diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-05-17 17:24:03 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-06-22 07:51:41 +0000 |
commit | 774f54339e5db91f785733232d3950366db65d07 (patch) | |
tree | 068e1b47bd1af94d77094ed12b604a6b83d9c22a /chromium/ui/ozone | |
parent | f7eaed5286974984ba5f9e3189d8f49d03e99f81 (diff) | |
download | qtwebengine-chromium-774f54339e5db91f785733232d3950366db65d07.tar.gz |
BASELINE: Update Chromium to 102.0.5005.57
Change-Id: I885f714bb40ee724c28f94ca6bd8dbdb39915158
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/ui/ozone')
202 files changed, 3263 insertions, 2215 deletions
diff --git a/chromium/ui/ozone/BUILD.gn b/chromium/ui/ozone/BUILD.gn index d85d01f06f0..dc0b0ab02a9 100644 --- a/chromium/ui/ozone/BUILD.gn +++ b/chromium/ui/ozone/BUILD.gn @@ -62,8 +62,6 @@ if (ozone_platform_x11) { ozone_platforms += [ "x11" ] ozone_platform_deps += [ "platform/x11" ] ozone_platform_ui_test_support_deps += [ "platform/x11:test_support" ] - ozone_platform_interactive_ui_tests_sources += - [ "platform/x11:interactive_uitests" ] } if (ozone_platform_scenic) { @@ -89,6 +87,7 @@ component("ozone_base") { "public/gl_ozone.h", "public/gpu_platform_support_host.cc", "public/gpu_platform_support_host.h", + "public/hardware_capabilities.h", "public/input_controller.cc", "public/input_controller.h", "public/overlay_candidates_ozone.cc", @@ -183,7 +182,6 @@ source_set("platform") { "platform_selection.cc", "platform_selection.h", "public/client_native_pixmap_factory_ozone.cc", - "public/ozone_gpu_test_helper.cc", "public/ozone_platform.cc", constructor_list_cc_file, platform_list_cc_file, @@ -193,7 +191,6 @@ source_set("platform") { public = [ "platform_object.h", "public/client_native_pixmap_factory_ozone.h", - "public/ozone_gpu_test_helper.h", "public/ozone_platform.h", ] @@ -241,7 +238,10 @@ source_set("ozone_switches") { deps = [ "//base" ] - visibility += [ "//chrome/test:browser_tests_runner" ] + visibility += [ + "//chrome/test:browser_tests_runner", + "//content/public/browser:browser_sources", + ] } component("ozone") { @@ -306,7 +306,7 @@ static_library("ui_test_support") { source_set("ozone_interactive_ui_tests") { visibility = [] - visibility = [ "//chrome/test:interactive_ui_tests" ] + visibility = [ "//chrome/test:interactive_ui_tests${exec_target_suffix}" ] testonly = true @@ -345,6 +345,20 @@ action("generate_ozone_platform_list") { visibility += [ "//media:*" ] } +source_set("ozone_gpu_test_support") { + visibility = [] + visibility = [ "//components/viz/demo:viz_demo" ] + + sources = [ "public/ozone_gpu_test_helper.cc" ] + + public = [ "public/ozone_gpu_test_helper.h" ] + + public_deps = [ + ":platform", + "//base", + ] +} + action("generate_constructor_list") { script = "generate_constructor_list.py" diff --git a/chromium/ui/ozone/common/egl_util.cc b/chromium/ui/ozone/common/egl_util.cc index 08d42145b1d..9ebf5d4d121 100644 --- a/chromium/ui/ozone/common/egl_util.cc +++ b/chromium/ui/ozone/common/egl_util.cc @@ -46,25 +46,6 @@ const base::FilePath::CharType kAngleGlesSoname[] = FILE_PATH_LITERAL("libGLESv2.so"); #endif // BUILDFLAG(IS_WIN) -#if BUILDFLAG(ENABLE_SWIFTSHADER) -#if BUILDFLAG(IS_WIN) -const base::FilePath::CharType kGLESv2SwiftShaderLibraryName[] = - FILE_PATH_LITERAL("libGLESv2.dll"); -const base::FilePath::CharType kEGLSwiftShaderLibraryName[] = - FILE_PATH_LITERAL("libEGL.dll"); -#elif BUILDFLAG(IS_FUCHSIA) -const base::FilePath::CharType kGLESv2SwiftShaderLibraryName[] = - FILE_PATH_LITERAL("libswiftshader_libGLESv2.so"); -const base::FilePath::CharType kEGLSwiftShaderLibraryName[] = - FILE_PATH_LITERAL("libswiftshader_libEGL.so"); -#else -const base::FilePath::CharType kGLESv2SwiftShaderLibraryName[] = - FILE_PATH_LITERAL("libGLESv2.so"); -const base::FilePath::CharType kEGLSwiftShaderLibraryName[] = - FILE_PATH_LITERAL("libEGL.so"); -#endif -#endif // BUILDFLAG(ENABLE_SWIFTSHADER) - bool LoadEGLGLES2Bindings(const base::FilePath& egl_library_path, const base::FilePath& gles_library_path) { base::NativeLibraryLoadError error; @@ -154,21 +135,7 @@ bool LoadDefaultEGLGLES2Bindings( base::FilePath glesv2_path; base::FilePath egl_path; - if (implementation.gl == gl::kGLImplementationSwiftShaderGL) { -#if BUILDFLAG(ENABLE_SWIFTSHADER) - base::FilePath module_path; -#if !BUILDFLAG(IS_FUCHSIA) - if (!base::PathService::Get(base::DIR_MODULE, &module_path)) - return false; - module_path = module_path.Append(FILE_PATH_LITERAL("swiftshader/")); -#endif - - glesv2_path = module_path.Append(kGLESv2SwiftShaderLibraryName); - egl_path = module_path.Append(kEGLSwiftShaderLibraryName); -#else - return false; -#endif - } else if (implementation.gl == gl::kGLImplementationEGLANGLE) { + if (implementation.gl == gl::kGLImplementationEGLANGLE) { base::FilePath module_path; #if !BUILDFLAG(IS_FUCHSIA) if (!base::PathService::Get(base::DIR_MODULE, &module_path)) diff --git a/chromium/ui/ozone/common/gl_ozone_egl.cc b/chromium/ui/ozone/common/gl_ozone_egl.cc index 194d29f754d..2034d0ab74d 100644 --- a/chromium/ui/ozone/common/gl_ozone_egl.cc +++ b/chromium/ui/ozone/common/gl_ozone_egl.cc @@ -16,7 +16,8 @@ namespace ui { bool GLOzoneEGL::InitializeGLOneOffPlatform() { - if (!gl::GLSurfaceEGL::InitializeOneOff(GetNativeDisplay())) { + if (!gl::GLSurfaceEGL::InitializeOneOff(GetNativeDisplay(), + /*system_device_id=*/0)) { LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed."; return false; } diff --git a/chromium/ui/ozone/common/test/stub_ozone_ui_controls_test_helper.cc b/chromium/ui/ozone/common/test/stub_ozone_ui_controls_test_helper.cc index fd6026ae4f3..8990ef9fbf8 100644 --- a/chromium/ui/ozone/common/test/stub_ozone_ui_controls_test_helper.cc +++ b/chromium/ui/ozone/common/test/stub_ozone_ui_controls_test_helper.cc @@ -29,6 +29,10 @@ OzoneUIControlsTestHelper* CreateOzoneUIControlsTestHelperScenic() { return PrintErrorAndReturnNullptr(); } +OzoneUIControlsTestHelper* CreateOzoneUIControlsTestHelperFlatland() { + return PrintErrorAndReturnNullptr(); +} + OzoneUIControlsTestHelper* CreateOzoneUIControlsTestHelperHeadless() { return PrintErrorAndReturnNullptr(); } diff --git a/chromium/ui/ozone/common/test/stub_ozone_ui_controls_test_helper.h b/chromium/ui/ozone/common/test/stub_ozone_ui_controls_test_helper.h index 94fa715dc63..a8f4499e95e 100644 --- a/chromium/ui/ozone/common/test/stub_ozone_ui_controls_test_helper.h +++ b/chromium/ui/ozone/common/test/stub_ozone_ui_controls_test_helper.h @@ -12,6 +12,7 @@ class OzoneUIControlsTestHelper; OzoneUIControlsTestHelper* CreateOzoneUIControlsTestHelperWindows(); OzoneUIControlsTestHelper* CreateOzoneUIControlsTestHelperDrm(); OzoneUIControlsTestHelper* CreateOzoneUIControlsTestHelperScenic(); +OzoneUIControlsTestHelper* CreateOzoneUIControlsTestHelperFlatland(); OzoneUIControlsTestHelper* CreateOzoneUIControlsTestHelperHeadless(); OzoneUIControlsTestHelper* CreateOzoneUIControlsTestHelperCast(); diff --git a/chromium/ui/ozone/demo/simple_renderer_factory.cc b/chromium/ui/ozone/demo/simple_renderer_factory.cc index 98ac818d159..da580102fa3 100644 --- a/chromium/ui/ozone/demo/simple_renderer_factory.cc +++ b/chromium/ui/ozone/demo/simple_renderer_factory.cc @@ -65,7 +65,8 @@ bool SimpleRendererFactory::Initialize() { } } #endif - if (!command_line->HasSwitch(kDisableGpu) && gl::init::InitializeGLOneOff()) { + if (!command_line->HasSwitch(kDisableGpu) && + gl::init::InitializeGLOneOff(/*system_device_id=*/0)) { type_ = GL; } else { type_ = SOFTWARE; diff --git a/chromium/ui/ozone/demo/skia/skia_renderer_factory.cc b/chromium/ui/ozone/demo/skia/skia_renderer_factory.cc index 005c22488e3..bbad1dff348 100644 --- a/chromium/ui/ozone/demo/skia/skia_renderer_factory.cc +++ b/chromium/ui/ozone/demo/skia/skia_renderer_factory.cc @@ -38,7 +38,7 @@ SkiaRendererFactory::SkiaRendererFactory() {} SkiaRendererFactory::~SkiaRendererFactory() {} bool SkiaRendererFactory::Initialize() { - if (!gl::init::InitializeGLOneOff()) { + if (!gl::init::InitializeGLOneOff(/*system_device_id=*/0)) { LOG(FATAL) << "Failed to initialize GL"; } diff --git a/chromium/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc b/chromium/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc index 25bf025929d..9f41f94f991 100644 --- a/chromium/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc +++ b/chromium/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc @@ -5,13 +5,13 @@ #include "ui/ozone/demo/skia/skia_surfaceless_gl_renderer.h" #include <stddef.h> + #include <memory> #include <utility> #include "base/bind.h" #include "base/callback_helpers.h" #include "base/command_line.h" -#include "base/cxx17_backports.h" #include "base/trace_event/trace_event.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkDeferredDisplayListRecorder.h" @@ -178,7 +178,7 @@ bool SurfacelessSkiaGlRenderer::Initialize() { else primary_plane_rect_ = gfx::Rect(size_); - for (size_t i = 0; i < base::size(buffers_); ++i) { + for (size_t i = 0; i < std::size(buffers_); ++i) { buffers_[i] = std::make_unique<BufferWrapper>(); if (!buffers_[i]->Initialize(gr_context_.get(), widget_, primary_plane_rect_.size())) @@ -187,7 +187,7 @@ bool SurfacelessSkiaGlRenderer::Initialize() { if (command_line->HasSwitch(kEnableOverlay)) { gfx::Size overlay_size = gfx::Size(size_.width() / 8, size_.height() / 8); - for (size_t i = 0; i < base::size(overlay_buffer_); ++i) { + for (size_t i = 0; i < std::size(overlay_buffer_); ++i) { overlay_buffer_[i] = std::make_unique<BufferWrapper>(); overlay_buffer_[i]->Initialize(gr_context_.get(), gfx::kNullAcceleratedWidget, overlay_size); @@ -284,7 +284,7 @@ void SurfacelessSkiaGlRenderer::PostRenderFrameTask( gfx::SwapCompletionResult result) { switch (result.swap_result) { case gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS: - for (size_t i = 0; i < base::size(buffers_); ++i) { + for (size_t i = 0; i < std::size(buffers_); ++i) { buffers_[i] = std::make_unique<BufferWrapper>(); if (!buffers_[i]->Initialize(gr_context_.get(), widget_, primary_plane_rect_.size())) diff --git a/chromium/ui/ozone/demo/software_renderer.h b/chromium/ui/ozone/demo/software_renderer.h index 570f229626f..337b2b5e707 100644 --- a/chromium/ui/ozone/demo/software_renderer.h +++ b/chromium/ui/ozone/demo/software_renderer.h @@ -8,6 +8,7 @@ #include <memory> #include "base/memory/weak_ptr.h" +#include "base/time/time.h" #include "base/timer/timer.h" #include "ui/ozone/demo/renderer_base.h" diff --git a/chromium/ui/ozone/demo/surfaceless_gl_renderer.cc b/chromium/ui/ozone/demo/surfaceless_gl_renderer.cc index 4f033db976e..0c8db95634b 100644 --- a/chromium/ui/ozone/demo/surfaceless_gl_renderer.cc +++ b/chromium/ui/ozone/demo/surfaceless_gl_renderer.cc @@ -134,11 +134,11 @@ SurfacelessGlRenderer::~SurfacelessGlRenderer() { // Need to make current when deleting the framebuffer resources allocated in // the buffers. context_->MakeCurrent(gl_surface_.get()); - for (size_t i = 0; i < base::size(buffers_); ++i) + for (size_t i = 0; i < std::size(buffers_); ++i) buffers_[i].reset(); for (size_t i = 0; i < kMaxLayers; ++i) { - for (size_t j = 0; j < base::size(overlay_buffers_[i]); ++j) + for (size_t j = 0; j < std::size(overlay_buffers_[i]); ++j) overlay_buffers_[i][j].reset(); } } @@ -164,7 +164,7 @@ bool SurfacelessGlRenderer::Initialize() { else primary_plane_rect_ = gfx::Rect(size_); - for (size_t i = 0; i < base::size(buffers_); ++i) { + for (size_t i = 0; i < std::size(buffers_); ++i) { buffers_[i] = std::make_unique<BufferWrapper>(); if (!buffers_[i]->Initialize(widget_, primary_plane_rect_.size())) return false; @@ -180,7 +180,7 @@ bool SurfacelessGlRenderer::Initialize() { const gfx::Size overlay_size = gfx::Size(size_.width() / 8, size_.height() / 8); for (size_t i = 0; i < overlay_cnt_; ++i) { - for (size_t j = 0; j < base::size(overlay_buffers_[i]); ++j) { + for (size_t j = 0; j < std::size(overlay_buffers_[i]); ++j) { overlay_buffers_[i][j] = std::make_unique<BufferWrapper>(); overlay_buffers_[i][j]->Initialize(gfx::kNullAcceleratedWidget, overlay_size); @@ -302,7 +302,7 @@ void SurfacelessGlRenderer::PostRenderFrameTask( switch (result.swap_result) { case gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS: - for (size_t i = 0; i < base::size(buffers_); ++i) { + for (size_t i = 0; i < std::size(buffers_); ++i) { buffers_[i] = std::make_unique<BufferWrapper>(); if (!buffers_[i]->Initialize(widget_, primary_plane_rect_.size())) LOG(FATAL) << "Failed to recreate buffer"; diff --git a/chromium/ui/ozone/demo/vulkan_overlay_renderer.cc b/chromium/ui/ozone/demo/vulkan_overlay_renderer.cc index 4a648468de5..e32de9245a0 100644 --- a/chromium/ui/ozone/demo/vulkan_overlay_renderer.cc +++ b/chromium/ui/ozone/demo/vulkan_overlay_renderer.cc @@ -90,7 +90,7 @@ bool VulkanOverlayRenderer::Initialize() { /* .pipelineBindPoint = */ VK_PIPELINE_BIND_POINT_GRAPHICS, /* .inputAttachmentCount = */ 0, /* .pInputAttachments = */ nullptr, - /* .colorAttachmentCount = */ base::size(color_attachment_references), + /* .colorAttachmentCount = */ std::size(color_attachment_references), /* .pColorAttachments = */ color_attachment_references, /* .pResolveAttachments = */ nullptr, /* .pDepthStencilAttachment = */ nullptr, @@ -102,9 +102,9 @@ bool VulkanOverlayRenderer::Initialize() { /* .sType = */ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, /* .pNext = */ nullptr, /* .flags = */ 0, - /* .attachmentCount = */ base::size(render_pass_attachments), + /* .attachmentCount = */ std::size(render_pass_attachments), /* .pAttachments = */ render_pass_attachments, - /* .subpassCount = */ base::size(render_pass_subpasses), + /* .subpassCount = */ std::size(render_pass_subpasses), /* .pSubpasses = */ render_pass_subpasses, /* .dependencyCount = */ 0, /* .pDependencies = */ nullptr, @@ -173,9 +173,9 @@ void VulkanOverlayRenderer::RenderFrame() { const Buffer& buffer = *buffers_[next_buffer_]; next_buffer_++; - next_buffer_ %= base::size(buffers_); + next_buffer_ %= std::size(buffers_); ++in_use_buffers_; - DCHECK_LE(in_use_buffers_, base::size(buffers_)); + DCHECK_LE(in_use_buffers_, std::size(buffers_)); gpu::VulkanCommandBuffer& command_buffer = *buffer.command_buffer(); @@ -218,7 +218,7 @@ std::unique_ptr<gfx::GpuFence> VulkanOverlayRenderer::SubmitFence( VkFence fence) { VkResult result; VkFence fences[] = {fence}; - result = vkResetFences(device_queue_->GetVulkanDevice(), base::size(fences), + result = vkResetFences(device_queue_->GetVulkanDevice(), std::size(fences), fences); CHECK_EQ(result, VK_SUCCESS); diff --git a/chromium/ui/ozone/demo/vulkan_renderer.cc b/chromium/ui/ozone/demo/vulkan_renderer.cc index 8d2ea1659d1..20261982b12 100644 --- a/chromium/ui/ozone/demo/vulkan_renderer.cc +++ b/chromium/ui/ozone/demo/vulkan_renderer.cc @@ -144,7 +144,7 @@ bool VulkanRenderer::Initialize() { /* .pipelineBindPoint = */ VK_PIPELINE_BIND_POINT_GRAPHICS, /* .inputAttachmentCount = */ 0, /* .pInputAttachments = */ nullptr, - /* .colorAttachmentCount = */ base::size(color_attachment_references), + /* .colorAttachmentCount = */ std::size(color_attachment_references), /* .pColorAttachments = */ color_attachment_references, /* .pResolveAttachments = */ nullptr, /* .pDepthStencilAttachment = */ nullptr, @@ -156,9 +156,9 @@ bool VulkanRenderer::Initialize() { /* .sType = */ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, /* .pNext = */ nullptr, /* .flags = */ 0, - /* .attachmentCount = */ base::size(render_pass_attachments), + /* .attachmentCount = */ std::size(render_pass_attachments), /* .pAttachments = */ render_pass_attachments, - /* .subpassCount = */ base::size(render_pass_subpasses), + /* .subpassCount = */ std::size(render_pass_subpasses), /* .pSubpasses = */ render_pass_subpasses, /* .dependencyCount = */ 0, /* .pDependencies = */ nullptr, @@ -332,7 +332,8 @@ void VulkanRenderer::RenderFrame() { VkSemaphore end_semaphore = scoped_write.end_semaphore(); CHECK(command_buffer.Submit(1, &begin_semaphore, 1, &end_semaphore)); } - vulkan_surface_->SwapBuffers(); + vulkan_surface_->SwapBuffers( + base::DoNothingAs<void(const gfx::PresentationFeedback&)>()); PostRenderFrameTask(); } 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 0cd79d34583..0bd8223bbcc 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 @@ -89,7 +89,15 @@ using GLImageScanoutType = testing::Types< GLImageNativePixmapTestDelegate<gfx::BufferUsage::SCANOUT, gfx::BufferFormat::BGRA_8888>>; -INSTANTIATE_TYPED_TEST_SUITE_P(GLImageNativePixmapScanoutBGRA, +#if BUILDFLAG(IS_CHROMEOS) +// Disabled due to failures on ChromeOS MSan builder. +// TODO(crbug.com/1314304) Reenable the test. +#define MAYBE_GLImageNativePixmapScanoutBGRA \ + DISABLED_GLImageNativePixmapScanoutBGRA +#else +#define MAYBE_GLImageNativePixmapScanoutBGRA GLImageNativePixmapScanoutBGRA +#endif +INSTANTIATE_TYPED_TEST_SUITE_P(MAYBE_GLImageNativePixmapScanoutBGRA, GLImageTest, GLImageScanoutType); diff --git a/chromium/ui/ozone/platform/cast/gl_surface_cast.cc b/chromium/ui/ozone/platform/cast/gl_surface_cast.cc index 73457769c72..5057f342991 100644 --- a/chromium/ui/ozone/platform/cast/gl_surface_cast.cc +++ b/chromium/ui/ozone/platform/cast/gl_surface_cast.cc @@ -107,7 +107,7 @@ EGLConfig GLSurfaceCast::GetConfig() { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE}; - config_ = ChooseEGLConfig(GetDisplay(), config_attribs); + config_ = ChooseEGLConfig(GetEGLDisplay(), config_attribs); } return config_; } diff --git a/chromium/ui/ozone/platform/cast/surface_factory_cast.cc b/chromium/ui/ozone/platform/cast/surface_factory_cast.cc index 52d28595994..073671f166d 100644 --- a/chromium/ui/ozone/platform/cast/surface_factory_cast.cc +++ b/chromium/ui/ozone/platform/cast/surface_factory_cast.cc @@ -63,6 +63,11 @@ class CastPixmap : public gfx::NativePixmap { return gfx::BufferFormat::BGRA_8888; } size_t GetNumberOfPlanes() const override { return 1; } + bool SupportsZeroCopyWebGPUImport() const override { + // TODO(crbug.com/1258986): Figure out how to import multi-planar pixmap + // into WebGPU without copy. + return false; + } gfx::Size GetBufferSize() const override { return gfx::Size(); } uint32_t GetUniqueId() const override { return 0; } diff --git a/chromium/ui/ozone/platform/drm/BUILD.gn b/chromium/ui/ozone/platform/drm/BUILD.gn index b6c498e888f..a35a83a6f0b 100644 --- a/chromium/ui/ozone/platform/drm/BUILD.gn +++ b/chromium/ui/ozone/platform/drm/BUILD.gn @@ -202,9 +202,13 @@ source_set("gbm_unittests") { deps = [ ":gbm", "//base/test:test_support", - "//build/config/linux/libdrm", "//skia", "//testing/gtest", + + # We're using this instead of the config to ensure that our tests built for + # linux have a controllable dependency instead of relying on whatever is on + # the system. + "//third_party/libdrm", "//ui/base/ime", "//ui/gfx", "//ui/gfx/linux:drm", diff --git a/chromium/ui/ozone/platform/drm/common/drm_util.cc b/chromium/ui/ozone/platform/drm/common/drm_util.cc index 7f6f5ffd890..9bc3ecfbd79 100644 --- a/chromium/ui/ozone/platform/drm/common/drm_util.cc +++ b/chromium/ui/ozone/platform/drm/common/drm_util.cc @@ -25,6 +25,7 @@ #include "base/strings/string_piece.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" +#include "ui/base/ui_base_features.h" #include "ui/display/types/display_mode.h" #include "ui/display/util/display_util.h" #include "ui/display/util/edid_parser.h" @@ -136,12 +137,13 @@ display::DisplayConnectionType GetDisplayType(drmModeConnector* connector) { } } +template <typename T> int GetDrmProperty(int fd, - drmModeConnector* connector, + T* object, const std::string& name, ScopedDrmPropertyPtr* property) { - for (int i = 0; i < connector->count_props; ++i) { - ScopedDrmPropertyPtr tmp(drmModeGetProperty(fd, connector->props[i])); + for (uint32_t i = 0; i < static_cast<uint32_t>(object->count_props); ++i) { + ScopedDrmPropertyPtr tmp(drmModeGetProperty(fd, object->props[i])); if (!tmp) continue; @@ -245,6 +247,14 @@ display::PanelOrientation GetPanelOrientation(int fd, int index = GetDrmProperty(fd, connector, "panel orientation", &property); if (index < 0) return display::PanelOrientation::kNormal; + + // If the DRM driver doesn't provide panel orientation then this property + // will be DRM_MODE_PANEL_ORIENTATION_UNKNOWN (which is -1, except + // `prop_values` is unsigned, so compare against max uint64_t). Assume that + // panels with unknown orientation have normal orientation. + if (connector->prop_values[index] == std::numeric_limits<uint64_t>::max()) + return display::PanelOrientation::kNormal; + DCHECK_LE(connector->prop_values[index], display::PanelOrientation::kLast); return static_cast<display::PanelOrientation>(connector->prop_values[index]); } @@ -333,6 +343,30 @@ gfx::Size GetMaximumCursorSize(int fd) { return gfx::Size(width, height); } +bool IsVrrCapable(int fd, drmModeConnector* connector) { + if (!features::IsVariableRefreshRateEnabled()) { + return false; + } + + ScopedDrmPropertyPtr vrr_capable_property; + const int vrr_capable_index = GetDrmProperty( + fd, connector, kVrrCapablePropertyName, &vrr_capable_property); + return vrr_capable_index >= 0 && connector->prop_values[vrr_capable_index]; +} + +bool IsVrrEnabled(int fd, drmModeCrtc* crtc) { + if (!features::IsVariableRefreshRateEnabled()) { + return false; + } + + ScopedDrmObjectPropertyPtr crtc_props( + drmModeObjectGetProperties(fd, crtc->crtc_id, DRM_MODE_OBJECT_CRTC)); + ScopedDrmPropertyPtr vrr_enabled_property; + const int vrr_enabled_index = GetDrmProperty( + fd, crtc_props.get(), kVrrEnabledPropertyName, &vrr_enabled_property); + return vrr_enabled_index >= 0 && crtc_props->prop_values[vrr_enabled_index]; +} + HardwareDisplayControllerInfo::HardwareDisplayControllerInfo( ScopedDrmConnectorPtr connector, ScopedDrmCrtcPtr crtc, @@ -737,9 +771,10 @@ std::vector<const char*> GetPreferredDrmDrivers() { const auto sys_vendor = ReadFileAndTrim(dmi_dir.Append("sys_vendor")); const auto product_name = ReadFileAndTrim(dmi_dir.Append("product_name")); - // The iMac 12,1 has an integrated Intel GPU that isn't connected to - // any real outputs. Prefer the Radeon card instead. - if (sys_vendor == "Apple Inc." && product_name == "iMac12,1") + // The iMac 12.1 and 12.2 have an integrated Intel GPU that isn't connected + // to any real outputs. Prefer the Radeon card instead. + if (sys_vendor == "Apple Inc." && + (product_name == "iMac12,1" || product_name == "iMac12,2")) return {"radeon"}; // Default order. diff --git a/chromium/ui/ozone/platform/drm/common/drm_util.h b/chromium/ui/ozone/platform/drm/common/drm_util.h index f6baf97b8e4..90e749c40f1 100644 --- a/chromium/ui/ozone/platform/drm/common/drm_util.h +++ b/chromium/ui/ozone/platform/drm/common/drm_util.h @@ -49,6 +49,9 @@ constexpr char kPrivacyScreenPropertyNameLegacy[] = "privacy-screen"; constexpr char kPrivacyScreenHwStatePropertyName[] = "privacy-screen hw-state"; constexpr char kPrivacyScreenSwStatePropertyName[] = "privacy-screen sw-state"; +constexpr char kVrrCapablePropertyName[] = "vrr_capable"; +constexpr char kVrrEnabledPropertyName[] = "VRR_ENABLED"; + // DRM property enum to internal type mappings. template <typename InternalType> struct DrmPropertyEnumToInternalTypeMapping { @@ -156,6 +159,10 @@ float ModeRefreshRate(const drmModeModeInfo& mode); bool ModeIsInterlaced(const drmModeModeInfo& mode); +bool IsVrrCapable(int fd, drmModeConnector* connector); + +bool IsVrrEnabled(int fd, drmModeCrtc* crtc); + uint64_t GetEnumValueForName(int fd, int property_id, const char* str); std::vector<uint64_t> ParsePathBlob(const drmModePropertyBlobRes& path_blob); 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 7a40ed649fc..0edb8f69d18 100644 --- a/chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc +++ b/chromium/ui/ozone/platform/drm/common/drm_util_unittest.cc @@ -9,7 +9,6 @@ #include <map> -#include "skia/ext/skia_matrix_44.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkColorSpace.h" #include "ui/display/types/display_snapshot.h" 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 0a8a95331b6..c6eeb8a72d8 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 @@ -107,9 +107,9 @@ DrmGpuDisplayManager::DrmGpuDisplayManager(ScreenManager* screen_manager, DrmGpuDisplayManager::~DrmGpuDisplayManager() = default; -void DrmGpuDisplayManager::SetClearOverlayCacheCallback( +void DrmGpuDisplayManager::SetDisplaysConfiguredCallback( base::RepeatingClosure callback) { - clear_overlay_cache_callback_ = std::move(callback); + displays_configured_callback_ = std::move(callback); } MovableDisplaySnapshots DrmGpuDisplayManager::GetDisplays() { @@ -236,12 +236,13 @@ bool DrmGpuDisplayManager::ConfigureDisplays( controllers_to_configure.push_back(std::move(params)); } - if (clear_overlay_cache_callback_) - clear_overlay_cache_callback_.Run(); - bool config_success = screen_manager_->ConfigureDisplayControllers(controllers_to_configure); + if (displays_configured_callback_) { + displays_configured_callback_.Run(); + } + for (const auto& controller : controllers_to_configure) { if (config_success) { FindDisplay(controller.display_id)->SetOrigin(controller.origin); 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 0382fab55e5..009f0fb8ca8 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 @@ -43,8 +43,8 @@ class DrmGpuDisplayManager { ~DrmGpuDisplayManager(); // Sets a callback that will be notified when display configuration may have - // changed to clear the overlay configuration cache. - void SetClearOverlayCacheCallback(base::RepeatingClosure callback); + // changed, so we should update state for managing overlays. + void SetDisplaysConfiguredCallback(base::RepeatingClosure callback); // Returns a list of the connected displays. When this is called the list of // displays is refreshed. @@ -87,7 +87,7 @@ class DrmGpuDisplayManager { std::vector<std::unique_ptr<DrmDisplay>> displays_; - base::RepeatingClosure clear_overlay_cache_callback_; + base::RepeatingClosure displays_configured_callback_; }; } // namespace ui 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 b76943a8fa4..762024834bc 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_util.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_util.cc @@ -75,8 +75,8 @@ ScopedDrmColorCtmPtr CreateCTMBlob(const std::vector<float>& color_matrix) { ScopedDrmColorCtmPtr ctm( static_cast<drm_color_ctm*>(malloc(sizeof(drm_color_ctm)))); - DCHECK_EQ(color_matrix.size(), base::size(ctm->matrix)); - for (size_t i = 0; i < base::size(ctm->matrix); ++i) { + DCHECK_EQ(color_matrix.size(), std::size(ctm->matrix)); + for (size_t i = 0; i < std::size(ctm->matrix); ++i) { if (color_matrix[i] < 0) { ctm->matrix[i] = static_cast<uint64_t>(-color_matrix[i] * (1ull << 32)); ctm->matrix[i] |= static_cast<uint64_t>(1) << 63; diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_candidates.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_candidates.cc index 1ca27372af5..886e66cc8bc 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_candidates.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_candidates.cc @@ -16,6 +16,7 @@ DrmOverlayCandidates::DrmOverlayCandidates(DrmOverlayManager* manager, DrmOverlayCandidates::~DrmOverlayCandidates() { overlay_manager_->RegisterOverlayRequirement(widget_, false); + overlay_manager_->StopObservingHardwareCapabilities(widget_); } void DrmOverlayCandidates::CheckOverlaySupport( @@ -23,6 +24,12 @@ void DrmOverlayCandidates::CheckOverlaySupport( overlay_manager_->CheckOverlaySupport(candidates, widget_); } +void DrmOverlayCandidates::ObserveHardwareCapabilities( + HardwareCapabilitiesCallback receive_callback) { + overlay_manager_->StartObservingHardwareCapabilities( + widget_, std::move(receive_callback)); +} + void DrmOverlayCandidates::RegisterOverlayRequirement(bool requires_overlay) { #if !BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA) DCHECK(!requires_overlay); diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_candidates.h b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_candidates.h index cbbd6d7b27d..c1f9cc42f84 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_candidates.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_candidates.h @@ -8,6 +8,7 @@ #include <vector> #include "ui/gfx/native_widget_types.h" +#include "ui/ozone/public/hardware_capabilities.h" #include "ui/ozone/public/overlay_candidates_ozone.h" namespace ui { @@ -29,6 +30,8 @@ class DrmOverlayCandidates : public OverlayCandidatesOzone { // OverlayCandidatesOzone: void CheckOverlaySupport( std::vector<OverlaySurfaceCandidate>* candidates) override; + void ObserveHardwareCapabilities( + HardwareCapabilitiesCallback receive_callback) override; void RegisterOverlayRequirement(bool requires_overlay) override; private: diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc index 79227e5a59b..6f51baf3c8f 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.cc @@ -54,10 +54,26 @@ DrmOverlayManager::CreateOverlayCandidates(gfx::AcceleratedWidget widget) { return std::make_unique<DrmOverlayCandidates>(this, widget); } -void DrmOverlayManager::ResetCache() { - TRACE_EVENT0("hwoverlays", "DrmOverlayManager::ResetCache"); +void DrmOverlayManager::DisplaysConfigured() { + TRACE_EVENT0("hwoverlays", "DrmOverlayManager::DisplaysConfigured"); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); widget_cache_map_.clear(); + + for (auto& entry : hardware_capabilities_callbacks_) { + GetHardwareCapabilities(entry.first, entry.second); + } +} + +void DrmOverlayManager::StartObservingHardwareCapabilities( + gfx::AcceleratedWidget widget, + HardwareCapabilitiesCallback receive_callback) { + GetHardwareCapabilities(widget, receive_callback); + hardware_capabilities_callbacks_.emplace(widget, std::move(receive_callback)); +} + +void DrmOverlayManager::StopObservingHardwareCapabilities( + gfx::AcceleratedWidget widget) { + hardware_capabilities_callbacks_.erase(widget); } void DrmOverlayManager::CheckOverlaySupport( diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.h b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.h index c9927dd4953..28fa53038ed 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager.h @@ -12,6 +12,7 @@ #include "base/containers/lru_cache.h" #include "base/threading/thread_checker.h" #include "ui/gfx/native_widget_types.h" +#include "ui/ozone/public/hardware_capabilities.h" #include "ui/ozone/public/overlay_candidates_ozone.h" #include "ui/ozone/public/overlay_manager_ozone.h" @@ -35,15 +36,26 @@ class DrmOverlayManager : public OverlayManagerOzone { std::unique_ptr<OverlayCandidatesOzone> CreateOverlayCandidates( gfx::AcceleratedWidget w) override; + // Called when notified by the DRM thread of a display configuration change. // Resets the cache of OverlaySurfaceCandidates and if they can be displayed - // as an overlay. For use when display configuration changes. - void ResetCache(); + // as an overlay. Requests an updated HardwareCapabilities for any observing + // OverlayProcessors. + void DisplaysConfigured(); // Checks if overlay candidates can be displayed as overlays. Modifies // |candidates| to indicate if they can. void CheckOverlaySupport(std::vector<OverlaySurfaceCandidate>* candidates, gfx::AcceleratedWidget widget); + void StartObservingHardwareCapabilities( + gfx::AcceleratedWidget widget, + HardwareCapabilitiesCallback receive_callback); + void StopObservingHardwareCapabilities(gfx::AcceleratedWidget widget); + + virtual void GetHardwareCapabilities( + gfx::AcceleratedWidget widget, + HardwareCapabilitiesCallback& receive_callback) = 0; + // Should be called by the overlay processor to indicate if a widget has a // candidate that requires an overlay. This is to prioritize which display // gets the overlay in a multiple display environment. @@ -98,6 +110,9 @@ class DrmOverlayManager : public OverlayManagerOzone { base::flat_set<gfx::AcceleratedWidget> widgets_with_required_overlays_; + std::map<gfx::AcceleratedWidget, HardwareCapabilitiesCallback> + hardware_capabilities_callbacks_; + THREAD_CHECKER(thread_checker_); }; 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 13dc7cbbca6..803c45f278f 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 @@ -28,7 +28,7 @@ void DrmOverlayManagerGpu::SendOverlayValidationRequest( TRACE_EVENT_NESTABLE_ASYNC_BEGIN0( "hwoverlays", "DrmOverlayManagerGpu::SendOverlayValidationRequest", TRACE_ID_LOCAL(this)); - SetClearCacheCallbackIfNecessary(); + SetDisplaysConfiguredCallbackIfNecessary(); drm_thread_proxy_->CheckOverlayCapabilities( widget, candidates, base::BindOnce(&DrmOverlayManagerGpu::ReceiveOverlayValidationResponse, @@ -41,21 +41,30 @@ DrmOverlayManagerGpu::SendOverlayValidationRequestSync( gfx::AcceleratedWidget widget) { TRACE_EVENT0("hwoverlays", "DrmOverlayManagerGpu::SendOverlayValidationRequestSync"); - SetClearCacheCallbackIfNecessary(); + SetDisplaysConfiguredCallbackIfNecessary(); return drm_thread_proxy_->CheckOverlayCapabilitiesSync(widget, candidates); } -void DrmOverlayManagerGpu::SetClearCacheCallbackIfNecessary() { +void DrmOverlayManagerGpu::GetHardwareCapabilities( + gfx::AcceleratedWidget widget, + HardwareCapabilitiesCallback& receive_callback) { + TRACE_EVENT0("hwoverlays", + "DrmOverlayManagerGpu::SendMaxOverlaysRequestSync"); + SetDisplaysConfiguredCallbackIfNecessary(); + drm_thread_proxy_->GetHardwareCapabilities(widget, receive_callback); +} + +void DrmOverlayManagerGpu::SetDisplaysConfiguredCallbackIfNecessary() { // 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 - // DrmThread has been started by this point *and* we are on the thread the - // callback should run on. Those two conditions are not necessarily true in - // the constructor. - if (!has_set_clear_cache_callback_) { - has_set_clear_cache_callback_ = true; - drm_thread_proxy_->SetClearOverlayCacheCallback(base::BindRepeating( - &DrmOverlayManagerGpu::ResetCache, weak_ptr_factory_.GetWeakPtr())); + // configuration may have changed. + // This happens in SendOverlayValidationRequest() because the DrmThread has + // been started by this point *and* we are on the thread the callback should + // run on. Those two conditions are not necessarily true in the constructor. + if (!has_set_displays_configured_callback_) { + has_set_displays_configured_callback_ = true; + drm_thread_proxy_->SetDisplaysConfiguredCallback( + base::BindRepeating(&DrmOverlayManagerGpu::DisplaysConfigured, + weak_ptr_factory_.GetWeakPtr())); } } 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 93f77bb424e..1942d754538 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 @@ -35,7 +35,11 @@ class DrmOverlayManagerGpu : public DrmOverlayManager { const std::vector<OverlaySurfaceCandidate>& candidates, gfx::AcceleratedWidget widget) override; - void SetClearCacheCallbackIfNecessary(); + void GetHardwareCapabilities( + gfx::AcceleratedWidget widget, + HardwareCapabilitiesCallback& receive_callback) override; + + void SetDisplaysConfiguredCallbackIfNecessary(); void ReceiveOverlayValidationResponse( gfx::AcceleratedWidget widget, @@ -44,7 +48,7 @@ class DrmOverlayManagerGpu : public DrmOverlayManager { DrmThreadProxy* const drm_thread_proxy_; - bool has_set_clear_cache_callback_ = false; + bool has_set_displays_configured_callback_ = false; base::WeakPtrFactory<DrmOverlayManagerGpu> weak_ptr_factory_{this}; }; diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_unittest.cc index 24e93a07671..47784e5fe9b 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_unittest.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_manager_unittest.cc @@ -38,6 +38,16 @@ class TestDrmOverlayManager : public DrmOverlayManager { gfx::AcceleratedWidget widget) override { return {}; } + void GetHardwareCapabilities( + gfx::AcceleratedWidget widget, + ui::HardwareCapabilitiesCallback& receive_callback) override { + ui::HardwareCapabilities hardware_capabilities; + hardware_capabilities.num_overlay_capable_planes = num_planes_response_; + // Immediately respond to the callback. + receive_callback.Run(hardware_capabilities); + } + + int num_planes_response_ = 0; private: std::vector<std::vector<OverlaySurfaceCandidate>> requests_; @@ -308,4 +318,50 @@ TEST(DrmOverlayManagerTest, RequiredOverlayMultiDisplay) { EXPECT_EQ(manager.requests().size(), 1u); } +TEST(DrmOverlayManagerTest, ObservingHardwareCapabilities) { + TestDrmOverlayManager manager; + manager.num_planes_response_ = 2; + + int primary_calls = 0; + HardwareCapabilitiesCallback primary_callback = base::BindRepeating( + [](int* calls, HardwareCapabilities hc) { + (*calls)++; + EXPECT_EQ(hc.num_overlay_capable_planes, 2); + }, + &primary_calls); + manager.StartObservingHardwareCapabilities(kPrimaryWidget, primary_callback); + EXPECT_EQ(primary_calls, 1); + + manager.DisplaysConfigured(); + + EXPECT_EQ(primary_calls, 2); + + int secondary_calls = 0; + HardwareCapabilitiesCallback secondary_callback = base::BindRepeating( + [](int* calls, HardwareCapabilities hc) { + (*calls)++; + EXPECT_EQ(hc.num_overlay_capable_planes, 2); + }, + &secondary_calls); + manager.StartObservingHardwareCapabilities(kSecondaryWidget, + secondary_callback); + // Only the secondary callback should be called. + EXPECT_EQ(primary_calls, 2); + EXPECT_EQ(secondary_calls, 1); + + manager.DisplaysConfigured(); + + // Both callbacks are called. + EXPECT_EQ(primary_calls, 3); + EXPECT_EQ(secondary_calls, 2); + + manager.StopObservingHardwareCapabilities(kPrimaryWidget); + manager.DisplaysConfigured(); + manager.DisplaysConfigured(); + + // The primary callback won't be called anymore. + EXPECT_EQ(primary_calls, 3); + EXPECT_EQ(secondary_calls, 4); +} + } // namespace ui 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 6e339c7cb63..a94d256ee92 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc @@ -89,6 +89,19 @@ DrmOverlayValidator::DrmOverlayValidator(DrmWindow* window) : window_(window) {} DrmOverlayValidator::~DrmOverlayValidator() {} +DrmOverlayPlane DrmOverlayValidator::MakeOverlayPlane( + const OverlaySurfaceCandidate& param, + std::vector<scoped_refptr<DrmFramebuffer>>& reusable_buffers, + size_t& total_allocated_memory_size) { + scoped_refptr<DrmFramebuffer> buffer = GetBufferForPageFlipTest( + window_, param, &reusable_buffers, &total_allocated_memory_size); + + return DrmOverlayPlane(buffer, param.plane_z_order, param.transform, + gfx::ToNearestRect(param.display_rect), + param.crop_rect, !param.is_opaque, + /*gpu_fence=*/nullptr); +} + OverlayStatusList DrmOverlayValidator::TestPageFlip( const OverlaySurfaceCandidateList& params, const DrmOverlayPlaneList& last_used_planes) { @@ -96,8 +109,9 @@ OverlayStatusList DrmOverlayValidator::TestPageFlip( HardwareDisplayController* controller = window_->GetController(); if (!controller) { // The controller is not yet installed. - for (auto& param : returns) - param = OVERLAY_STATUS_NOT; + for (auto& status : returns) { + status = OVERLAY_STATUS_NOT; + } return returns; } @@ -106,55 +120,77 @@ OverlayStatusList DrmOverlayValidator::TestPageFlip( std::vector<scoped_refptr<DrmFramebuffer>> reusable_buffers; scoped_refptr<DrmDevice> drm = controller->GetDrmDevice(); - for (const auto& plane : last_used_planes) + for (const auto& plane : last_used_planes) { reusable_buffers.push_back(plane.buffer); + } size_t total_allocated_memory_size = 0; - int test_page_flip_count = 0; + std::vector<size_t> plane_indices; for (size_t i = 0; i < params.size(); ++i) { - if (!params[i].overlay_handled) { + auto& param = params[i]; + // Skip candidates that have already been disqualified. + if (!param.overlay_handled) { returns[i] = OVERLAY_STATUS_NOT; continue; } - scoped_refptr<DrmFramebuffer> buffer = GetBufferForPageFlipTest( - window_, params[i], &reusable_buffers, &total_allocated_memory_size); + DrmOverlayPlane plane = + MakeOverlayPlane(param, reusable_buffers, total_allocated_memory_size); + if (!plane.buffer) { + returns[i] = OVERLAY_STATUS_NOT; + continue; + } - DrmOverlayPlane plane(buffer, params[i].plane_z_order, params[i].transform, - gfx::ToNearestRect(params[i].display_rect), - params[i].crop_rect, !params[i].is_opaque, - /*gpu_fence=*/nullptr); test_list.push_back(std::move(plane)); + // We need to save the indices because we're skipping some planes. + plane_indices.push_back(i); + } - bool result = false; - if (buffer) { - test_page_flip_count++; - base::ElapsedTimer timer; - - result = controller->TestPageFlip(test_list); + int test_page_flip_count = 0; - auto time = timer.Elapsed(); - static constexpr base::TimeDelta kMinTime = base::Microseconds(1); - static constexpr base::TimeDelta kMaxTime = base::Milliseconds(10); - static constexpr int kTimeBuckets = 50; - UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( - "Compositing.Display.DrmOverlayManager.TestPageFlipUs", time, - kMinTime, kMaxTime, kTimeBuckets); + // Test the whole list, then gradually remove the last plane and retest until + // we have success, or no more planes to test. + while (!test_list.empty()) { + test_page_flip_count++; + base::ElapsedTimer timer; + + bool test_result = controller->TestPageFlip(test_list); + + auto time = timer.Elapsed(); + static constexpr base::TimeDelta kMinTime = base::Microseconds(1); + static constexpr base::TimeDelta kMaxTime = base::Milliseconds(10); + static constexpr int kTimeBuckets = 50; + UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( + "Compositing.Display.DrmOverlayManager.TestPageFlipUs", time, kMinTime, + kMaxTime, kTimeBuckets); + + if (test_page_flip_count == 1) { + UMA_HISTOGRAM_BOOLEAN( + "Compositing.Display.DrmOverlayManager.FirstTestPageFlipPassed", + test_result); } - if (result) { - returns[i] = OVERLAY_STATUS_ABLE; - } else { - // If test failed here, platform cannot support this configuration - // with current combination of layers. This is usually the case when this - // plane has requested post processing capability which needs additional - // hardware resources and they might be already in use by other planes. - // For example this plane has requested scaling capabilities and all - // available scalars are already in use by other planes. - returns[i] = OVERLAY_STATUS_NOT; - test_list.pop_back(); + if (test_result) { + break; } + + // If test failed here, platform cannot support this configuration + // with current combination of layers. This is usually the case when this + // plane has requested post processing capability which needs additional + // hardware resources and they might be already in use by other planes. + // For example this plane has requested scaling capabilities and all + // available scalars are already in use by other planes. + + // Drop the last plane from the test list and set it to OVERLAY_STATUS_NOT. + returns[plane_indices.back()] = OVERLAY_STATUS_NOT; + plane_indices.pop_back(); + test_list.pop_back(); + } + + // Set OVERLAY_STATUS_ABLE for all planes left in the test_list. + for (size_t index : plane_indices) { + returns[index] = OVERLAY_STATUS_ABLE; } UMA_HISTOGRAM_MEMORY_KB( diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.h b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.h index 5b410997879..b7ccb7e406c 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.h @@ -5,6 +5,8 @@ #ifndef UI_OZONE_PLATFORM_DRM_GPU_DRM_OVERLAY_VALIDATOR_H_ #define UI_OZONE_PLATFORM_DRM_GPU_DRM_OVERLAY_VALIDATOR_H_ +#include <vector> + #include "base/containers/lru_cache.h" #include "ui/ozone/platform/drm/gpu/drm_overlay_plane.h" #include "ui/ozone/public/overlay_surface_candidate.h" @@ -22,13 +24,23 @@ class DrmOverlayValidator { ~DrmOverlayValidator(); - // Tests if configurations |params| are compatible with |window_| and finds + // Tests if configurations of |params| are compatible with |window_| and finds // which of these configurations can be promoted to Overlay composition - // without failing the page flip. It expects |params| to be sorted by z_order. + // without failing the page flip. + // If the complete list of planes fails we will remove planes from the end of + // the test list one at a time. This means that |params| should always have + // the primary plane at the beginning of the list, and the rest should be + // sorted based on expected power gain, so less impactful planes are dropped + // first. OverlayStatusList TestPageFlip(const OverlaySurfaceCandidateList& params, const DrmOverlayPlaneList& last_used_planes); private: + DrmOverlayPlane MakeOverlayPlane( + const OverlaySurfaceCandidate& param, + std::vector<scoped_refptr<DrmFramebuffer>>& reusable_buffers, + size_t& total_allocated_memory_size); + DrmWindow* const window_; // Not owned. }; 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 a67ea0c5433..5a84f9565fe 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 @@ -27,6 +27,7 @@ #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/screen_manager.h" +#include "ui/ozone/public/overlay_surface_candidate.h" namespace { @@ -584,7 +585,7 @@ TEST_F(DrmOverlayValidatorTest, NonIntegerDisplayRect) { {.formats = {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}}}}; InitDrmStatesAndControllers(std::vector<CrtcState>(1, state)); - overlay_params_.back().display_rect.Inset(0.005f, 0.005f); + overlay_params_.back().display_rect.Inset(0.005f); plane_list_.pop_back(); AddPlane(overlay_params_.back()); @@ -594,3 +595,100 @@ TEST_F(DrmOverlayValidatorTest, NonIntegerDisplayRect) { for (const auto& param : returns) EXPECT_EQ(param, ui::OVERLAY_STATUS_ABLE); } + +class TestAtOnceDrmOverlayValidatorTest + : public DrmOverlayValidatorTest, + public testing::WithParamInterface<bool> {}; + +TEST_F(DrmOverlayValidatorTest, FourCandidates_OneCommit) { + // Four planes. + CrtcState crtc_state = {.planes = {{.formats = {DRM_FORMAT_XRGB8888}}, + {.formats = {DRM_FORMAT_XRGB8888}}, + {.formats = {DRM_FORMAT_XRGB8888}}, + {.formats = {DRM_FORMAT_XRGB8888}}}}; + InitDrmStatesAndControllers({crtc_state}); + int setup_commits = drm_->get_commit_count(); + + // Add two more overlay candidates. + auto param3 = overlay_params_.back(); + auto param4 = overlay_params_.back(); + overlay_params_.push_back(param3); + overlay_params_.push_back(param4); + + std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip( + overlay_params_, ui::DrmOverlayPlaneList()); + + // All planes promoted. + ASSERT_EQ(4u, returns.size()); + EXPECT_EQ(returns[0], ui::OVERLAY_STATUS_ABLE); + EXPECT_EQ(returns[1], ui::OVERLAY_STATUS_ABLE); + EXPECT_EQ(returns[2], ui::OVERLAY_STATUS_ABLE); + EXPECT_EQ(returns[3], ui::OVERLAY_STATUS_ABLE); + // Only 1 commit was necessary. + EXPECT_EQ(drm_->get_commit_count() - setup_commits, 1); +} + +TEST_F(DrmOverlayValidatorTest, FourCandidatesTwoPlanes_MoreThanOneCommit) { + // Only two planes. + CrtcState crtc_state = {.planes = {{.formats = {DRM_FORMAT_XRGB8888}}, + {.formats = {DRM_FORMAT_XRGB8888}}}}; + InitDrmStatesAndControllers({crtc_state}); + int setup_commits = drm_->get_commit_count(); + + // Add two more overlay candidates. + auto param3 = overlay_params_.back(); + auto param4 = overlay_params_.back(); + overlay_params_.push_back(param3); + overlay_params_.push_back(param4); + + std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip( + overlay_params_, ui::DrmOverlayPlaneList()); + + // All planes promoted. + ASSERT_EQ(4u, returns.size()); + EXPECT_EQ(returns[0], ui::OVERLAY_STATUS_ABLE); + EXPECT_EQ(returns[1], ui::OVERLAY_STATUS_ABLE); + EXPECT_EQ(returns[2], ui::OVERLAY_STATUS_NOT); + EXPECT_EQ(returns[3], ui::OVERLAY_STATUS_NOT); + // First attempted with all 4 planes, then 3, then 2. + EXPECT_EQ(drm_->get_commit_count() - setup_commits, 3); +} + +TEST_F(DrmOverlayValidatorTest, TwoOfSixIgnored_OneCommit) { + // Six planes. + CrtcState crtc_state = {.planes = {{.formats = {DRM_FORMAT_XRGB8888}}, + {.formats = {DRM_FORMAT_XRGB8888}}, + {.formats = {DRM_FORMAT_XRGB8888}}, + {.formats = {DRM_FORMAT_XRGB8888}}, + {.formats = {DRM_FORMAT_XRGB8888}}, + {.formats = {DRM_FORMAT_XRGB8888}}}}; + InitDrmStatesAndControllers({crtc_state}); + int setup_commits = drm_->get_commit_count(); + + auto param3 = overlay_params_.back(); + auto param4 = overlay_params_.back(); + auto param5 = overlay_params_.back(); + auto param6 = overlay_params_.back(); + // Candidate 3 and 5 are already disqualified. + param3.overlay_handled = false; + param5.overlay_handled = false; + overlay_params_.push_back(param3); + overlay_params_.push_back(param4); + overlay_params_.push_back(param5); + overlay_params_.push_back(param6); + + std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip( + overlay_params_, ui::DrmOverlayPlaneList()); + + ASSERT_EQ(6u, returns.size()); + // Third and Fifth candidate were ignored. + EXPECT_EQ(returns[0], ui::OVERLAY_STATUS_ABLE); + EXPECT_EQ(returns[1], ui::OVERLAY_STATUS_ABLE); + EXPECT_EQ(returns[2], ui::OVERLAY_STATUS_NOT); + EXPECT_EQ(returns[3], ui::OVERLAY_STATUS_ABLE); + EXPECT_EQ(returns[4], ui::OVERLAY_STATUS_NOT); + EXPECT_EQ(returns[5], ui::OVERLAY_STATUS_ABLE); + // Only 1 commit was needed because the two unpromoted candidates were + // excluded before testing. + EXPECT_EQ(drm_->get_commit_count() - setup_commits, 1); +} diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc b/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc index 805e82b8d50..02066666364 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc @@ -26,6 +26,7 @@ #include "ui/gfx/presentation_feedback.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" #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_dumb_buffer.h" @@ -214,8 +215,8 @@ void DrmThread::CreateBufferFromHandle( *out_framebuffer = std::move(framebuffer); } -void DrmThread::SetClearOverlayCacheCallback(base::RepeatingClosure callback) { - display_manager_->SetClearOverlayCacheCallback(std::move(callback)); +void DrmThread::SetDisplaysConfiguredCallback(base::RepeatingClosure callback) { + display_manager_->SetDisplaysConfiguredCallback(std::move(callback)); } void DrmThread::SchedulePageFlip( @@ -337,6 +338,41 @@ void DrmThread::CheckOverlayCapabilitiesSync( kMinTime, kMaxTime, kTimeBuckets); } +void DrmThread::GetHardwareCapabilities( + gfx::AcceleratedWidget widget, + ui::HardwareCapabilitiesCallback receive_callback) { + TRACE_EVENT0("drm,hwoverlays", "DrmThread::GetHardwareCapabilities"); + DCHECK(screen_manager_->GetWindow(widget)); + DCHECK(device_manager_->GetDrmDevice(widget)); + HardwareDisplayController* hdc = + screen_manager_->GetWindow(widget)->GetController(); + HardwareDisplayPlaneManager* plane_manager = + device_manager_->GetDrmDevice(widget)->plane_manager(); + + if (!hdc || !plane_manager) { + // Assume only the primary plane exists. + ui::HardwareCapabilities hardware_capabilities; + hardware_capabilities.num_overlay_capable_planes = 1; + std::move(receive_callback).Run(hardware_capabilities); + return; + } + + const auto& crtc_controllers = hdc->crtc_controllers(); + // We almost always expect only one CRTC. Multiple CRTCs for one widget was + // the old way mirror mode was supported. + if (crtc_controllers.size() == 1) { + std::move(receive_callback) + .Run(plane_manager->GetHardwareCapabilities( + crtc_controllers[0]->crtc())); + } else { + // If there are multiple CRTCs for this widget, we shouldn't rely on + // overlays working, so we'll say only the primary plane exists. + ui::HardwareCapabilities hardware_capabilities; + hardware_capabilities.num_overlay_capable_planes = 1; + std::move(receive_callback).Run(hardware_capabilities); + } +} + void DrmThread::GetDeviceCursor( mojo::PendingAssociatedReceiver<ozone::mojom::DeviceCursor> receiver) { cursor_receivers_.Add(this, std::move(receiver)); diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread.h b/chromium/ui/ozone/platform/drm/gpu/drm_thread.h index fa20e5b3515..0a1249e76af 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/platform/drm/mojom/device_cursor.mojom.h" #include "ui/ozone/platform/drm/mojom/drm_device.mojom.h" +#include "ui/ozone/public/hardware_capabilities.h" #include "ui/ozone/public/overlay_surface_candidate.h" #include "ui/ozone/public/swap_completion_callback.h" @@ -107,7 +108,7 @@ class DrmThread : public base::Thread, gfx::NativePixmapHandle handle, std::unique_ptr<GbmBuffer>* buffer, scoped_refptr<DrmFramebuffer>* framebuffer); - void SetClearOverlayCacheCallback(base::RepeatingClosure callback); + void SetDisplaysConfiguredCallback(base::RepeatingClosure callback); void AddDrmDeviceReceiver( mojo::PendingReceiver<ozone::mojom::DrmDevice> receiver); @@ -128,6 +129,11 @@ class DrmThread : public base::Thread, gfx::AcceleratedWidget widget, const std::vector<OverlaySurfaceCandidate>& candidates, std::vector<OverlayStatus>* result); + // Calls `receive_callback` with a `HardwareCapabilities` containing + // information about overlay support on the current hardware. + void GetHardwareCapabilities( + gfx::AcceleratedWidget widget, + ui::HardwareCapabilitiesCallback receive_callback); // DrmWindowProxy (on GPU thread) is the client for these methods. void SchedulePageFlip(gfx::AcceleratedWidget widget, 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 a785ee1eec7..078ee8a975a 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc @@ -130,13 +130,13 @@ void DrmThreadProxy::CreateBufferFromHandle( base::Unretained(&drm_thread_), std::move(task))); } -void DrmThreadProxy::SetClearOverlayCacheCallback( +void DrmThreadProxy::SetDisplaysConfiguredCallback( base::RepeatingClosure callback) { DCHECK(drm_thread_.task_runner()); drm_thread_.task_runner()->PostTask( FROM_HERE, - base::BindOnce(&DrmThread::SetClearOverlayCacheCallback, + base::BindOnce(&DrmThread::SetDisplaysConfiguredCallback, base::Unretained(&drm_thread_), CreateSafeRepeatingCallback(std::move(callback)))); } @@ -172,6 +172,20 @@ std::vector<OverlayStatus> DrmThreadProxy::CheckOverlayCapabilitiesSync( return result; } +void DrmThreadProxy::GetHardwareCapabilities( + gfx::AcceleratedWidget widget, + const HardwareCapabilitiesCallback& receive_callback) { + TRACE_EVENT0("drm", "DrmThreadProxy::GetHardwareCapabilities"); + DCHECK(drm_thread_.task_runner()); + base::RepeatingClosure task = base::BindRepeating( + &DrmThread::GetHardwareCapabilities, base::Unretained(&drm_thread_), + widget, CreateSafeRepeatingCallback(receive_callback)); + drm_thread_.task_runner()->PostTask( + FROM_HERE, + base::BindOnce(&DrmThread::RunTaskAfterDeviceReady, + base::Unretained(&drm_thread_), std::move(task), nullptr)); +} + 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 16204ce4089..f50c939a8df 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.h @@ -13,6 +13,7 @@ #include "mojo/public/cpp/bindings/pending_receiver.h" #include "ui/ozone/platform/drm/gpu/drm_thread.h" #include "ui/ozone/platform/drm/mojom/device_cursor.mojom.h" +#include "ui/ozone/public/hardware_capabilities.h" #include "ui/ozone/public/overlay_surface_candidate.h" namespace ui { @@ -66,9 +67,9 @@ class DrmThreadProxy { scoped_refptr<DrmFramebuffer>* framebuffer); // Sets a callback that will be notified when display configuration may have - // changed to clear the overlay configuration cache. |callback| will be run on - // origin thread. - void SetClearOverlayCacheCallback(base::RepeatingClosure reset_callback); + // changed, so we should update state for managing overlays. + // |callback| will be run on origin thread. + void SetDisplaysConfiguredCallback(base::RepeatingClosure callback); // Checks if overlay |candidates| can be displayed asynchronously and then // runs |callback|. Testing the overlay configuration requires posting a task @@ -83,6 +84,10 @@ class DrmThreadProxy { gfx::AcceleratedWidget widget, const std::vector<OverlaySurfaceCandidate>& candidates); + void GetHardwareCapabilities( + gfx::AcceleratedWidget widget, + const HardwareCapabilitiesCallback& receive_callback); + void AddDrmDeviceReceiver( mojo::PendingReceiver<ozone::mojom::DrmDevice> receiver); diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_pixmap.cc b/chromium/ui/ozone/platform/drm/gpu/gbm_pixmap.cc index 92b95778f88..fdff43be050 100644 --- a/chromium/ui/ozone/platform/drm/gpu/gbm_pixmap.cc +++ b/chromium/ui/ozone/platform/drm/gpu/gbm_pixmap.cc @@ -52,6 +52,10 @@ size_t GbmPixmap::GetNumberOfPlanes() const { return buffer_->GetNumPlanes(); } +bool GbmPixmap::SupportsZeroCopyWebGPUImport() const { + return buffer_->SupportsZeroCopyWebGPUImport(); +} + uint64_t GbmPixmap::GetBufferFormatModifier() const { return buffer_->GetFormatModifier(); } diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_pixmap.h b/chromium/ui/ozone/platform/drm/gpu/gbm_pixmap.h index a2192a3b2b0..c5abbdfde10 100644 --- a/chromium/ui/ozone/platform/drm/gpu/gbm_pixmap.h +++ b/chromium/ui/ozone/platform/drm/gpu/gbm_pixmap.h @@ -34,6 +34,7 @@ class GbmPixmap : public gfx::NativePixmap { size_t GetDmaBufOffset(size_t plane) const override; size_t GetDmaBufPlaneSize(size_t plane) const override; size_t GetNumberOfPlanes() const override; + bool SupportsZeroCopyWebGPUImport() const override; uint64_t GetBufferFormatModifier() const override; gfx::BufferFormat GetBufferFormat() const override; gfx::Size GetBufferSize() const override; 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 5e5b8493a1b..0c54d912c79 100644 --- a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc +++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc @@ -270,15 +270,13 @@ GbmSurfaceFactory::GetAllowedGLImplementations() { return std::vector<gl::GLImplementationParts>{ gl::GLImplementationParts(gl::kGLImplementationEGLGLES2), gl::GLImplementationParts(gl::kGLImplementationEGLANGLE), - gl::GLImplementationParts(gl::ANGLEImplementation::kSwiftShader), - gl::GLImplementationParts(gl::kGLImplementationSwiftShaderGL)}; + gl::GLImplementationParts(gl::ANGLEImplementation::kSwiftShader)}; } GLOzone* GbmSurfaceFactory::GetGLOzone( const gl::GLImplementationParts& implementation) { switch (implementation.gl) { case gl::kGLImplementationEGLGLES2: - case gl::kGLImplementationSwiftShaderGL: case gl::kGLImplementationEGLANGLE: return egl_implementation_.get(); default: diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc index 5279a9f9245..7cee75377b1 100644 --- a/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc +++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc @@ -10,7 +10,6 @@ #include "base/bind.h" #include "base/check_op.h" #include "base/notreached.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_handle.h" @@ -166,7 +165,7 @@ void GbmSurfaceless::SwapBuffersAsync( CHECK_NE(fence, EGL_NO_SYNC_KHR) << "eglCreateSyncKHR failed"; base::OnceClosure fence_wait_task = - base::BindOnce(&WaitForFence, GetDisplay(), fence); + base::BindOnce(&WaitForFence, GetEGLDisplay(), fence); base::OnceClosure fence_retired_callback = base::BindOnce( &GbmSurfaceless::FenceRetired, weak_factory_.GetWeakPtr(), frame); @@ -206,7 +205,7 @@ EGLConfig GbmSurfaceless::GetConfig() { EGL_SURFACE_TYPE, EGL_DONT_CARE, EGL_NONE}; - config_ = ChooseEGLConfig(GetDisplay(), config_attribs); + config_ = ChooseEGLConfig(GetEGLDisplay(), config_attribs); } return config_; } @@ -282,7 +281,7 @@ EGLSyncKHR GbmSurfaceless::InsertFence(bool implicit) { const EGLint attrib_list[] = {EGL_SYNC_CONDITION_KHR, EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM, EGL_NONE}; - return eglCreateSyncKHR(GetDisplay(), EGL_SYNC_FENCE_KHR, + return eglCreateSyncKHR(GetEGLDisplay(), EGL_SYNC_FENCE_KHR, implicit ? attrib_list : NULL); } 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 2809e5983e1..91b0861cbd4 100644 --- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc +++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc @@ -517,7 +517,7 @@ void HardwareDisplayController::AllocateCursorBuffers() { gfx::Size max_cursor_size = GetMaximumCursorSize(GetDrmDevice()->get_fd()); SkImageInfo info = SkImageInfo::MakeN32Premul(max_cursor_size.width(), max_cursor_size.height()); - for (size_t i = 0; i < base::size(cursor_buffers_); ++i) { + for (size_t i = 0; i < std::size(cursor_buffers_); ++i) { cursor_buffers_[i] = std::make_unique<DrmDumbBuffer>(GetDrmDevice()); // Don't register a framebuffer for cursors since they are special (they // aren't modesetting buffers and drivers may fail to register them due to @@ -531,7 +531,7 @@ void HardwareDisplayController::AllocateCursorBuffers() { DrmDumbBuffer* HardwareDisplayController::NextCursorBuffer() { ++cursor_frontbuffer_; - cursor_frontbuffer_ %= base::size(cursor_buffers_); + cursor_frontbuffer_ %= std::size(cursor_buffers_); return cursor_buffers_[cursor_frontbuffer_].get(); } 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 70bd00b8afc..689f636e634 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 @@ -520,4 +520,16 @@ void HardwareDisplayPlaneManager::ResetModesetStateForCrtc(uint32_t crtc_id) { crtc_state.modeset_framebuffers.clear(); } +ui::HardwareCapabilities HardwareDisplayPlaneManager::GetHardwareCapabilities( + uint32_t crtc_id) { + ui::HardwareCapabilities hc; + hc.num_overlay_capable_planes = std::count_if( + planes_.begin(), planes_.end(), + [crtc_id](const std::unique_ptr<HardwareDisplayPlane>& plane) { + return plane->type() != DRM_PLANE_TYPE_CURSOR && + plane->CanUseForCrtcId(crtc_id); + }); + return hc; +} + } // namespace ui diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h index b5761650e75..ba1ee1685eb 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 @@ -9,6 +9,7 @@ #include <stdint.h> #include <xf86drmMode.h> #include <cstdint> +#include <map> #include <memory> #include <vector> @@ -19,6 +20,7 @@ #include "ui/ozone/platform/drm/gpu/crtc_commit_request.h" #include "ui/ozone/platform/drm/gpu/drm_device.h" #include "ui/ozone/platform/drm/gpu/drm_overlay_plane.h" +#include "ui/ozone/public/hardware_capabilities.h" #include "ui/ozone/public/swap_completion_callback.h" namespace gfx { @@ -204,6 +206,11 @@ class HardwareDisplayPlaneManager { // caller. void ResetModesetStateForCrtc(uint32_t crtc_id); + // Gets `HardwareCapabilities` based on planes available to the specified + // CRTC. num_overlay_capable_planes counts both `DRM_PLANE_TYPE_PRIMARY` and + // `DRM_PLANE_TYPE_OVERLAY` planes. + ui::HardwareCapabilities GetHardwareCapabilities(uint32_t crtc_id); + protected: struct ConnectorProperties { uint32_t id; 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 3c8592f3259..4bd30ea831d 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,7 +12,6 @@ #include "base/bind.h" #include "base/logging.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" 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 8af1afef63c..2b129797f29 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 @@ -1180,6 +1180,51 @@ TEST_P(HardwareDisplayPlaneManagerTest, ForceOpaqueFormatsForAddFramebuffer) { } } +TEST_P(HardwareDisplayPlaneManagerTest, GetHardwareCapabilities) { + InitializeDrmState(/*crtc_count=*/4, /*planes_per_crtc=*/7); + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); + + for (int i = 0; i < 4; ++i) { + // Legacy doesn't support OVERLAY planes. + int expected_planes = use_atomic_ ? 7 : 1; + EXPECT_EQ(fake_drm_->plane_manager() + ->GetHardwareCapabilities(kCrtcIdBase + i) + .num_overlay_capable_planes, + expected_planes); + } + + { + // Change the last (CURSOR) plane into a PRIMARY plane that is available to + // only the first two CRTCs. + auto& last_props = plane_properties_[plane_properties_.size() - 1]; + last_props.crtc_mask = (1 << 0) | (1 << 1); + // Find the type property and change it to PRIMARY. + for (auto& property : last_props.properties) { + if (property.id == kTypePropId) { + property.value = DRM_PLANE_TYPE_PRIMARY; + break; + } + } + + fake_drm_->InitializeState(crtc_properties_, connector_properties_, + plane_properties_, property_names_, use_atomic_); + } + + for (int i = 0; i < 4; ++i) { + // Legacy doesn't support OVERLAY planes. + int expected_planes = use_atomic_ ? 7 : 1; + // First two CRTCs have the newly added plane available. + if (i == 0 || i == 1) { + expected_planes++; + } + EXPECT_EQ(fake_drm_->plane_manager() + ->GetHardwareCapabilities(kCrtcIdBase + i) + .num_overlay_capable_planes, + expected_planes); + } +} + INSTANTIATE_TEST_SUITE_P(All, HardwareDisplayPlaneManagerTest, testing::Values(false, true)); diff --git a/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc b/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc index 1ef0fe9f11f..6501e9a0906 100644 --- a/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc +++ b/chromium/ui/ozone/platform/drm/gpu/mock_drm_device.cc @@ -4,6 +4,7 @@ #include "ui/ozone/platform/drm/gpu/mock_drm_device.h" +#include <stdint.h> #include <xf86drm.h> #include <memory> #include <utility> @@ -24,6 +25,7 @@ struct drmModeAtomicReqItem { uint32_t object_id; uint32_t property_id; uint64_t value; + uint32_t cursor; }; typedef drmModeAtomicReqItem* drmModeAtomicReqItemPtr; diff --git a/chromium/ui/ozone/platform/drm/gpu/page_flip_request.h b/chromium/ui/ozone/platform/drm/gpu/page_flip_request.h index 40923002821..030b4922fc7 100644 --- a/chromium/ui/ozone/platform/drm/gpu/page_flip_request.h +++ b/chromium/ui/ozone/platform/drm/gpu/page_flip_request.h @@ -5,9 +5,9 @@ #ifndef UI_OZONE_PLATFORM_DRM_GPU_PAGE_FLIP_REQUEST_H_ #define UI_OZONE_PLATFORM_DRM_GPU_PAGE_FLIP_REQUEST_H_ - #include "base/atomic_ref_count.h" #include "base/callback.h" +#include "base/time/time.h" #include "ui/gfx/swap_result.h" #include "ui/ozone/public/swap_completion_callback.h" 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 b605816e01c..dc0c7ff05a4 100644 --- a/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc +++ b/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc @@ -986,7 +986,7 @@ TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithDifferentBounds) { new ui::DrmWindow(1, device_manager_.get(), screen_manager_.get())); window->Initialize(); gfx::Rect new_bounds = GetPrimaryBounds(); - new_bounds.Inset(0, 0, 1, 1); + new_bounds.Inset(gfx::Insets::TLBR(0, 0, 1, 1)); window->SetBounds(new_bounds); screen_manager_->AddWindow(1, std::move(window)); diff --git a/chromium/ui/ozone/platform/drm/host/drm_cursor.cc b/chromium/ui/ozone/platform/drm/host/drm_cursor.cc index 38b8e5ce65e..8695aafd157 100644 --- a/chromium/ui/ozone/platform/drm/host/drm_cursor.cc +++ b/chromium/ui/ozone/platform/drm/host/drm_cursor.cc @@ -8,6 +8,8 @@ #include <utility> #include "base/memory/scoped_refptr.h" +#include "base/task/current_thread.h" +#include "base/threading/thread_checker.h" #include "base/time/time.h" #include "base/trace_event/trace_event.h" #include "build/chromeos_buildflags.h" @@ -28,12 +30,12 @@ using mojom::CursorType; class NullProxy : public DrmCursorProxy { public: - NullProxy() {} + NullProxy() = default; NullProxy(const NullProxy&) = delete; NullProxy& operator=(const NullProxy&) = delete; - ~NullProxy() override {} + ~NullProxy() override = default; void CursorSet(gfx::AcceleratedWidget window, const std::vector<SkBitmap>& bitmaps, @@ -46,17 +48,18 @@ class NullProxy : public DrmCursorProxy { } // namespace DrmCursor::DrmCursor(DrmWindowHostManager* window_manager) - : window_(gfx::kNullAcceleratedWidget), + : ui_thread_(base::ThreadTaskRunnerHandle::Get()), + window_(gfx::kNullAcceleratedWidget), window_manager_(window_manager), proxy_(new NullProxy()) { - evdev_thread_checker_.DetachFromThread(); + DETACH_FROM_THREAD(evdev_thread_checker_); } -DrmCursor::~DrmCursor() {} +DrmCursor::~DrmCursor() = default; void DrmCursor::SetDrmCursorProxy(std::unique_ptr<DrmCursorProxy> proxy) { TRACE_EVENT0("drmcursor", "DrmCursor::SetDrmCursorProxy"); - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_); base::AutoLock lock(lock_); proxy_ = std::move(proxy); if (window_ != gfx::kNullAcceleratedWidget) @@ -65,21 +68,22 @@ void DrmCursor::SetDrmCursorProxy(std::unique_ptr<DrmCursorProxy> proxy) { void DrmCursor::ResetDrmCursorProxy() { TRACE_EVENT0("drmcursor", "DrmCursor::ResetDrmCursorProxy"); - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_); NullProxy* np = new NullProxy(); base::AutoLock lock(lock_); proxy_.reset(np); } -gfx::Point DrmCursor::GetBitmapLocationLocked() { +gfx::Point DrmCursor::GetBitmapLocationLocked() + EXCLUSIVE_LOCKS_REQUIRED(lock_) { return gfx::ToFlooredPoint(location_) - cursor_->hotspot().OffsetFromOrigin(); } void DrmCursor::SetCursor(gfx::AcceleratedWidget window, scoped_refptr<BitmapCursor> platform_cursor) { TRACE_EVENT0("drmcursor", "DrmCursor::SetCursor"); - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_); DCHECK_NE(window, gfx::kNullAcceleratedWidget); DCHECK(platform_cursor); @@ -97,7 +101,7 @@ void DrmCursor::OnWindowAdded(gfx::AcceleratedWidget window, const gfx::Rect& bounds_in_screen, const gfx::Rect& cursor_confined_bounds) { TRACE_EVENT0("drmcursor", "DrmCursor::OnWindowAdded"); - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_); base::AutoLock lock(lock_); if (window_ == gfx::kNullAcceleratedWidget) { @@ -111,7 +115,7 @@ void DrmCursor::OnWindowAdded(gfx::AcceleratedWidget window, void DrmCursor::OnWindowRemoved(gfx::AcceleratedWidget window) { TRACE_EVENT0("drmcursor", "DrmCursor::OnWindowRemoved"); - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_); base::AutoLock lock(lock_); if (window_ == window) { @@ -138,7 +142,7 @@ void DrmCursor::CommitBoundsChange( const gfx::Rect& new_display_bounds_in_screen, const gfx::Rect& new_confined_bounds) { TRACE_EVENT0("drmcursor", "DrmCursor::CommitBoundsChange"); - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_); base::AutoLock lock(lock_); if (window_ == window) { @@ -152,7 +156,7 @@ void DrmCursor::CommitBoundsChange( void DrmCursor::MoveCursorTo(gfx::AcceleratedWidget window, const gfx::PointF& location) { TRACE_EVENT0("drmcursor", "DrmCursor::MoveCursorTo (window)"); - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_); base::AutoLock lock(lock_); gfx::AcceleratedWidget old_window = window_; @@ -178,7 +182,31 @@ void DrmCursor::MoveCursorTo(gfx::AcceleratedWidget window, void DrmCursor::MoveCursorTo(const gfx::PointF& screen_location) { TRACE_EVENT0("drmcursor", "DrmCursor::MoveCursorTo"); - DCHECK(thread_checker_.CalledOnValidThread()); + if (ui_thread_->BelongsToCurrentThread()) + MoveCursorToOnUiThread(screen_location); + else + MoveCursorToOnEvdevThread(screen_location); +} + +void DrmCursor::MoveCursorToOnUiThread(const gfx::PointF& screen_location) { + DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_); + + const auto* window = + window_manager_->GetWindowAt(gfx::ToRoundedPoint(screen_location)); + if (!window) { + // See b/221758935#comment18 for why we need to silently ignore this error + // here. + return; + } + + auto location_in_window = + screen_location - window->GetBounds().OffsetFromOrigin(); + MoveCursorTo(window->GetAcceleratedWidget(), location_in_window); +} + +void DrmCursor::MoveCursorToOnEvdevThread(const gfx::PointF& screen_location) { + DCHECK_CALLED_ON_VALID_THREAD(evdev_thread_checker_); + base::AutoLock lock(lock_); // TODO(spang): Moving between windows doesn't work here, but @@ -190,7 +218,12 @@ void DrmCursor::MoveCursorTo(const gfx::PointF& screen_location) { } void DrmCursor::MoveCursor(const gfx::Vector2dF& delta) { - DCHECK(evdev_thread_checker_.CalledOnValidThread()); +#if DCHECK_IS_ON() + // We explicitly check for DCHECK_IS_ON() as |ui_thread_checker_| and + // |evdev_thread_checker_| do not exist on non-DCHECK builds. + DCHECK(evdev_thread_checker_.CalledOnValidThread() || + ui_thread_checker_.CalledOnValidThread()); +#endif TRACE_EVENT0("drmcursor", "DrmCursor::MoveCursor"); base::AutoLock lock(lock_); @@ -224,12 +257,13 @@ gfx::Rect DrmCursor::GetCursorConfinedBounds() { } void DrmCursor::InitializeOnEvdev() { - DCHECK(evdev_thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(evdev_thread_checker_); base::AutoLock lock(lock_); proxy_->InitializeOnEvdevIfNecessary(); } -void DrmCursor::SetCursorLocationLocked(const gfx::PointF& location) { +void DrmCursor::SetCursorLocationLocked(const gfx::PointF& location) + EXCLUSIVE_LOCKS_REQUIRED(lock_) { gfx::PointF clamped_location = location; clamped_location.SetToMax(gfx::PointF(confined_bounds_.origin())); // Right and bottom edges are exclusive. @@ -242,7 +276,7 @@ void DrmCursor::SetCursorLocationLocked(const gfx::PointF& location) { #endif } -void DrmCursor::SendCursorShowLocked() { +void DrmCursor::SendCursorShowLocked() EXCLUSIVE_LOCKS_REQUIRED(lock_) { if (!cursor_ || cursor_->type() == CursorType::kNone) { SendCursorHideLocked(); return; @@ -252,12 +286,12 @@ void DrmCursor::SendCursorShowLocked() { cursor_->frame_delay()); } -void DrmCursor::SendCursorHideLocked() { +void DrmCursor::SendCursorHideLocked() EXCLUSIVE_LOCKS_REQUIRED(lock_) { CursorSetLockTested(window_, std::vector<SkBitmap>(), gfx::Point(), base::TimeDelta()); } -void DrmCursor::SendCursorMoveLocked() { +void DrmCursor::SendCursorMoveLocked() EXCLUSIVE_LOCKS_REQUIRED(lock_) { if (!cursor_ || cursor_->type() == CursorType::kNone) return; @@ -279,5 +313,4 @@ void DrmCursor::MoveLockTested(gfx::AcceleratedWidget window, proxy_->Move(window, point); } - } // namespace ui diff --git a/chromium/ui/ozone/platform/drm/host/drm_cursor.h b/chromium/ui/ozone/platform/drm/host/drm_cursor.h index e0d2a65476b..b9e90735861 100644 --- a/chromium/ui/ozone/platform/drm/host/drm_cursor.h +++ b/chromium/ui/ozone/platform/drm/host/drm_cursor.h @@ -10,6 +10,7 @@ #include "base/memory/scoped_refptr.h" #include "base/synchronization/lock.h" +#include "base/task/single_thread_task_runner.h" #include "base/threading/thread_checker.h" #include "ui/events/ozone/evdev/cursor_delegate_evdev.h" #include "ui/gfx/geometry/rect.h" @@ -27,7 +28,7 @@ class DrmWindowHostManager; // processes. The proxy implementation must satisfy DrmCursorProxy. class DrmCursorProxy { public: - virtual ~DrmCursorProxy() {} + virtual ~DrmCursorProxy() = default; // Sets the cursor |bitmaps| on |window| at |point| with |frame_delay|. virtual void CursorSet(gfx::AcceleratedWidget window, @@ -88,6 +89,9 @@ class DrmCursor : public CursorDelegateEvdev { void SendCursorHideLocked(); void SendCursorMoveLocked(); + void MoveCursorToOnEvdevThread(const gfx::PointF& screen_location); + void MoveCursorToOnUiThread(const gfx::PointF& screen_location); + // Lock-testing helpers. void CursorSetLockTested(gfx::AcceleratedWidget window, const std::vector<SkBitmap>& bitmaps, @@ -99,30 +103,33 @@ class DrmCursor : public CursorDelegateEvdev { base::Lock lock_; // Enforce our threading constraints. - base::ThreadChecker thread_checker_; - base::ThreadChecker evdev_thread_checker_; + THREAD_CHECKER(ui_thread_checker_); + THREAD_CHECKER(evdev_thread_checker_); + + scoped_refptr<base::SingleThreadTaskRunner> ui_thread_; // The location of the bitmap (the cursor location is the hotspot location). gfx::Point GetBitmapLocationLocked(); // The current cursor bitmap (immutable). - scoped_refptr<BitmapCursor> cursor_; + scoped_refptr<BitmapCursor> cursor_ GUARDED_BY(lock_); // The window under the cursor. - gfx::AcceleratedWidget window_; + gfx::AcceleratedWidget window_ GUARDED_BY(lock_); // The location of the cursor within the window. - gfx::PointF location_; + gfx::PointF location_ GUARDED_BY(lock_); // The bounds of the display under the cursor. - gfx::Rect display_bounds_in_screen_; + gfx::Rect display_bounds_in_screen_ GUARDED_BY(lock_); // The bounds that the cursor is confined to in |window|. - gfx::Rect confined_bounds_; + gfx::Rect confined_bounds_ GUARDED_BY(lock_); - DrmWindowHostManager* const window_manager_; // Not owned. + DrmWindowHostManager* const window_manager_ + GUARDED_BY_CONTEXT(ui_thread_checker_); // Not owned. - std::unique_ptr<DrmCursorProxy> proxy_; + std::unique_ptr<DrmCursorProxy> proxy_ GUARDED_BY(lock_); }; } // namespace ui 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 6bda9fb2df7..f8cc4fce0cc 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 @@ -11,11 +11,11 @@ #include <utility> #include "base/bind.h" +#include "base/command_line.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/strings/string_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" @@ -27,6 +27,7 @@ #include "ui/ozone/platform/drm/host/drm_display_host.h" #include "ui/ozone/platform/drm/host/drm_native_display_delegate.h" #include "ui/ozone/platform/drm/host/gpu_thread_adapter.h" +#include "ui/ozone/public/ozone_switches.h" namespace ui { @@ -108,8 +109,12 @@ base::FilePath GetPrimaryDisplayCardPath() { for (int i = 0; /* end on first card# that does not exist */; i++) { std::string card_path = base::StringPrintf(kDefaultGraphicsCardPattern, i); - if (access(card_path.c_str(), F_OK) != 0) - break; + if (access(card_path.c_str(), F_OK) != 0) { + if (i == 0) /* card paths may start with 0 or 1 */ + continue; + else + break; + } base::ScopedFD fd(open(card_path.c_str(), O_RDWR | O_CLOEXEC)); if (!fd.is_valid()) { @@ -184,6 +189,15 @@ DrmDisplayHostManager::DrmDisplayHostManager( } host_properties->supports_overlays = primary_drm_device_handle_->has_atomic_capabilities(); + // TODO(b/192563524): The legacy video decoder wraps its frames with legacy + // mailboxes instead of SharedImages. The display compositor can composite + // these quads, but does not support promoting them to overlays. Thus, we + // disable overlays on platforms using the legacy video decoder. + auto* command_line = base::CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch( + switches::kPlatformDisallowsChromeOSDirectVideoDecoder)) { + host_properties->supports_overlays = false; + } drm_devices_[primary_graphics_card_path_] = primary_graphics_card_path_sysfs; } diff --git a/chromium/ui/ozone/platform/flatland/flatland_surface.h b/chromium/ui/ozone/platform/flatland/flatland_surface.h index fb344468c7a..e2fa3a7f98d 100644 --- a/chromium/ui/ozone/platform/flatland/flatland_surface.h +++ b/chromium/ui/ozone/platform/flatland/flatland_surface.h @@ -12,6 +12,7 @@ #include "base/containers/flat_map.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" +#include "base/time/time.h" #include "mojo/public/cpp/platform/platform_handle.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect_f.h" diff --git a/chromium/ui/ozone/platform/flatland/flatland_sysmem_buffer_collection.cc b/chromium/ui/ozone/platform/flatland/flatland_sysmem_buffer_collection.cc index 06b1c49e713..de5cfbdc782 100644 --- a/chromium/ui/ozone/platform/flatland/flatland_sysmem_buffer_collection.cc +++ b/chromium/ui/ozone/platform/flatland/flatland_sysmem_buffer_collection.cc @@ -648,8 +648,7 @@ void FlatlandSysmemBufferCollection::InitializeImageCreateInfo( vk_image_info->usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - if (usage_ == gfx::BufferUsage::SCANOUT || - usage_ == gfx::BufferUsage::SCANOUT_CPU_READ_WRITE) { + if (usage_ == gfx::BufferUsage::SCANOUT) { vk_image_info->usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; } diff --git a/chromium/ui/ozone/platform/flatland/flatland_sysmem_native_pixmap.cc b/chromium/ui/ozone/platform/flatland/flatland_sysmem_native_pixmap.cc index 54d79fa2fe6..0423510e873 100644 --- a/chromium/ui/ozone/platform/flatland/flatland_sysmem_native_pixmap.cc +++ b/chromium/ui/ozone/platform/flatland/flatland_sysmem_native_pixmap.cc @@ -46,6 +46,13 @@ size_t FlatlandSysmemNativePixmap::GetNumberOfPlanes() const { return 0; } +bool FlatlandSysmemNativePixmap::SupportsZeroCopyWebGPUImport() const { + NOTREACHED(); + // TODO(crbug.com/1304490): Figure out how to import multi-planar pixmap into + // WebGPU without copy. + return false; +} + uint64_t FlatlandSysmemNativePixmap::GetBufferFormatModifier() const { NOTREACHED(); return 0; diff --git a/chromium/ui/ozone/platform/flatland/flatland_sysmem_native_pixmap.h b/chromium/ui/ozone/platform/flatland/flatland_sysmem_native_pixmap.h index ad7d6a8f46c..a5d6d0d1c5e 100644 --- a/chromium/ui/ozone/platform/flatland/flatland_sysmem_native_pixmap.h +++ b/chromium/ui/ozone/platform/flatland/flatland_sysmem_native_pixmap.h @@ -27,6 +27,7 @@ class FlatlandSysmemNativePixmap : public gfx::NativePixmap { size_t GetDmaBufOffset(size_t plane) const override; size_t GetDmaBufPlaneSize(size_t plane) const override; size_t GetNumberOfPlanes() const override; + bool SupportsZeroCopyWebGPUImport() const override; uint64_t GetBufferFormatModifier() const override; gfx::BufferFormat GetBufferFormat() const override; gfx::Size GetBufferSize() const override; diff --git a/chromium/ui/ozone/platform/flatland/flatland_window.cc b/chromium/ui/ozone/platform/flatland/flatland_window.cc index c7663034038..5723c828001 100644 --- a/chromium/ui/ozone/platform/flatland/flatland_window.cc +++ b/chromium/ui/ozone/platform/flatland/flatland_window.cc @@ -213,7 +213,11 @@ PlatformWindowState FlatlandWindow::GetPlatformWindowState() const { return PlatformWindowState::kFullScreen; if (!is_view_attached_) return PlatformWindowState::kMinimized; - return PlatformWindowState::kNormal; + + // TODO(crbug.com/1241868): We cannot tell what portion of the screen is + // occupied by the View, so report is as maximized to reduce the space used + // by any browser chrome. + return PlatformWindowState::kMaximized; } void FlatlandWindow::Activate() { diff --git a/chromium/ui/ozone/platform/flatland/vulkan_implementation_flatland.cc b/chromium/ui/ozone/platform/flatland/vulkan_implementation_flatland.cc index 60da05573a4..1653d4ec37c 100644 --- a/chromium/ui/ozone/platform/flatland/vulkan_implementation_flatland.cc +++ b/chromium/ui/ozone/platform/flatland/vulkan_implementation_flatland.cc @@ -225,6 +225,7 @@ VulkanImplementationFlatland::CreateImageFromGpuMemoryHandle( return nullptr; } + image->set_queue_family_index(VK_QUEUE_FAMILY_EXTERNAL); image->set_native_pixmap(collection->CreateNativePixmap( gmb_handle.native_pixmap_handle.buffer_index)); return image; diff --git a/chromium/ui/ozone/platform/headless/BUILD.gn b/chromium/ui/ozone/platform/headless/BUILD.gn index 16209948a6d..20a2ef3fb0f 100644 --- a/chromium/ui/ozone/platform/headless/BUILD.gn +++ b/chromium/ui/ozone/platform/headless/BUILD.gn @@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//gpu/vulkan/features.gni") + visibility = [ "//ui/ozone/*" ] source_set("headless") { @@ -24,6 +26,9 @@ source_set("headless") { deps = [ "//base", + "//build:chromecast_buildflags", + "//build:chromeos_buildflags", + "//gpu/vulkan:buildflags", "//skia", "//ui/base", "//ui/base/cursor", @@ -41,4 +46,14 @@ source_set("headless") { if (is_fuchsia) { deps += [ "//ui/base/ime/fuchsia" ] } + + if (enable_vulkan && is_linux) { + sources += [ + "vulkan_implementation_headless.cc", + "vulkan_implementation_headless.h", + "vulkan_surface_headless.cc", + "vulkan_surface_headless.h", + ] + deps += [ "//gpu/vulkan" ] + } } diff --git a/chromium/ui/ozone/platform/headless/headless_surface_factory.cc b/chromium/ui/ozone/platform/headless/headless_surface_factory.cc index cad85b0856a..95ee659bd66 100644 --- a/chromium/ui/ozone/platform/headless/headless_surface_factory.cc +++ b/chromium/ui/ozone/platform/headless/headless_surface_factory.cc @@ -11,12 +11,16 @@ #include "base/location.h" #include "base/logging.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 "skia/ext/legacy_display_globals.h" +#include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkImageInfo.h" +#include "third_party/skia/include/core/SkPixmap.h" +#include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/core/SkSurface.h" +#include "third_party/skia/include/core/SkSurfaceProps.h" #include "ui/gfx/buffer_format_util.h" #include "ui/gfx/codec/png_codec.h" #include "ui/gfx/geometry/skia_conversions.h" @@ -30,6 +34,10 @@ #include "ui/ozone/platform/headless/headless_window_manager.h" #include "ui/ozone/public/surface_ozone_canvas.h" +#if BUILDFLAG(ENABLE_VULKAN) && BUILDFLAG(IS_LINUX) +#include "ui/ozone/platform/headless/vulkan_implementation_headless.h" +#endif + namespace ui { namespace { @@ -156,6 +164,7 @@ class TestPixmap : public gfx::NativePixmap { size_t GetNumberOfPlanes() const override { return gfx::NumberOfPlanesForLinearBufferFormat(format_); } + bool SupportsZeroCopyWebGPUImport() const override { return false; } gfx::Size GetBufferSize() const override { return gfx::Size(); } uint32_t GetUniqueId() const override { return 0; } bool ScheduleOverlayPlane( @@ -226,7 +235,6 @@ HeadlessSurfaceFactory::~HeadlessSurfaceFactory() = default; std::vector<gl::GLImplementationParts> HeadlessSurfaceFactory::GetAllowedGLImplementations() { return std::vector<gl::GLImplementationParts>{ - gl::GLImplementationParts(gl::kGLImplementationSwiftShaderGL), gl::GLImplementationParts(gl::kGLImplementationEGLGLES2), gl::GLImplementationParts(gl::ANGLEImplementation::kSwiftShader), gl::GLImplementationParts(gl::ANGLEImplementation::kDefault), @@ -237,7 +245,6 @@ GLOzone* HeadlessSurfaceFactory::GetGLOzone( const gl::GLImplementationParts& implementation) { switch (implementation.gl) { case gl::kGLImplementationEGLGLES2: - case gl::kGLImplementationSwiftShaderGL: case gl::kGLImplementationEGLANGLE: return swiftshader_implementation_.get(); @@ -273,4 +280,13 @@ void HeadlessSurfaceFactory::CheckBasePath() const { PLOG(FATAL) << "Unable to write to output location"; } +#if BUILDFLAG(ENABLE_VULKAN) && BUILDFLAG(IS_LINUX) +std::unique_ptr<gpu::VulkanImplementation> +HeadlessSurfaceFactory::CreateVulkanImplementation( + bool use_swiftshader, + bool allow_protected_memory) { + return std::make_unique<VulkanImplementationHeadless>(use_swiftshader); +} +#endif + } // namespace ui diff --git a/chromium/ui/ozone/platform/headless/headless_surface_factory.h b/chromium/ui/ozone/platform/headless/headless_surface_factory.h index bbd129fbbc0..bf58e12f346 100644 --- a/chromium/ui/ozone/platform/headless/headless_surface_factory.h +++ b/chromium/ui/ozone/platform/headless/headless_surface_factory.h @@ -26,6 +26,11 @@ class HeadlessSurfaceFactory : public SurfaceFactoryOzone { // SurfaceFactoryOzone: std::vector<gl::GLImplementationParts> GetAllowedGLImplementations() override; GLOzone* GetGLOzone(const gl::GLImplementationParts& implementation) override; +#if BUILDFLAG(ENABLE_VULKAN) && BUILDFLAG(IS_LINUX) + std::unique_ptr<gpu::VulkanImplementation> CreateVulkanImplementation( + bool use_swiftshader, + bool allow_protected_memory) override; +#endif std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget( gfx::AcceleratedWidget widget) override; scoped_refptr<gfx::NativePixmap> CreateNativePixmap( diff --git a/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc b/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc index 9f489c75089..011827af226 100644 --- a/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc +++ b/chromium/ui/ozone/platform/headless/ozone_platform_headless.cc @@ -8,7 +8,10 @@ #include "base/command_line.h" #include "base/files/file_path.h" +#include "base/no_destructor.h" #include "build/build_config.h" +#include "build/chromecast_buildflags.h" +#include "build/chromeos_buildflags.h" #include "ui/base/cursor/cursor_factory.h" #include "ui/base/ime/input_method_minimal.h" #include "ui/display/types/native_display_delegate.h" @@ -98,6 +101,20 @@ class OzonePlatformHeadless : public OzonePlatform { return std::make_unique<InputMethodMinimal>(delegate); } +// Desktop Linux, not ChromeOS. +#if BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS_ASH) && \ + !BUILDFLAG(IS_CHROMEOS_LACROS) && !BUILDFLAG(IS_CHROMECAST) + const PlatformProperties& GetPlatformProperties() override { + static base::NoDestructor<OzonePlatform::PlatformProperties> properties; + static bool initialized = false; + if (!initialized) { + properties->uses_external_vulkan_image_factory = true; + initialized = true; + } + return *properties; + } +#endif + bool InitializeUI(const InitParams& params) override { window_manager_ = std::make_unique<HeadlessWindowManager>(); surface_factory_ = std::make_unique<HeadlessSurfaceFactory>(file_path_); diff --git a/chromium/ui/ozone/platform/headless/vulkan_implementation_headless.cc b/chromium/ui/ozone/platform/headless/vulkan_implementation_headless.cc new file mode 100644 index 00000000000..e9c7feb22c6 --- /dev/null +++ b/chromium/ui/ozone/platform/headless/vulkan_implementation_headless.cc @@ -0,0 +1,157 @@ +// Copyright (c) 2022 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/headless/vulkan_implementation_headless.h" + +#include "base/base_paths.h" +#include "base/callback_helpers.h" +#include "base/files/file_path.h" +#include "base/notreached.h" +#include "base/path_service.h" +#include "base/scoped_environment_variable_override.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" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "ui/gfx/gpu_fence.h" +#include "ui/gfx/gpu_memory_buffer.h" +#include "ui/ozone/platform/headless/vulkan_surface_headless.h" + +namespace ui { + +VulkanImplementationHeadless::VulkanImplementationHeadless(bool use_swiftshader) + : gpu::VulkanImplementation(use_swiftshader) {} + +bool VulkanImplementationHeadless::InitializeVulkanInstance( + bool using_surface) { + using_surface_ = using_surface; + + std::vector<const char*> required_extensions = { + VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, + VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME}; + if (using_surface_) { + required_extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); + required_extensions.push_back(VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME); + } + + base::FilePath path; + if (use_swiftshader()) { + if (!base::PathService::Get(base::DIR_MODULE, &path)) + return false; + path = path.Append("libvk_swiftshader.so"); + } else { + path = base::FilePath("libvulkan.so.1"); + } + + return vulkan_instance_.Initialize(path, required_extensions, {}); +} + +gpu::VulkanInstance* VulkanImplementationHeadless::GetVulkanInstance() { + return &vulkan_instance_; +} + +std::unique_ptr<gpu::VulkanSurface> +VulkanImplementationHeadless::CreateViewSurface(gfx::AcceleratedWidget window) { + if (!using_surface_) + return nullptr; + return VulkanSurfaceHeadless::Create(vulkan_instance_.vk_instance(), window); +} + +bool VulkanImplementationHeadless::GetPhysicalDevicePresentationSupport( + VkPhysicalDevice device, + const std::vector<VkQueueFamilyProperties>& queue_family_properties, + uint32_t queue_family_index) { + // TODO(samans): Don't early out once Swiftshader supports this method. + // https://crbug.com/swiftshader/129 + if (use_swiftshader()) + return true; + // Should this be false? + return true; +} + +std::vector<const char*> +VulkanImplementationHeadless::GetRequiredDeviceExtensions() { + std::vector<const char*> extensions; + if (using_surface_) + extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); + return extensions; +} + +std::vector<const char*> +VulkanImplementationHeadless::GetOptionalDeviceExtensions() { + return { + VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, + VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, + VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME, + VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, + VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, + VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME, + }; +} + +VkFence VulkanImplementationHeadless::CreateVkFenceForGpuFence( + VkDevice vk_device) { + NOTREACHED(); + return VK_NULL_HANDLE; +} + +std::unique_ptr<gfx::GpuFence> +VulkanImplementationHeadless::ExportVkFenceToGpuFence(VkDevice vk_device, + VkFence vk_fence) { + NOTREACHED(); + return nullptr; +} + +VkSemaphore VulkanImplementationHeadless::CreateExternalSemaphore( + VkDevice vk_device) { + return gpu::CreateExternalVkSemaphore( + vk_device, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT); +} + +VkSemaphore VulkanImplementationHeadless::ImportSemaphoreHandle( + VkDevice vk_device, + gpu::SemaphoreHandle sync_handle) { + return ImportVkSemaphoreHandle(vk_device, std::move(sync_handle)); +} + +gpu::SemaphoreHandle VulkanImplementationHeadless::GetSemaphoreHandle( + VkDevice vk_device, + VkSemaphore vk_semaphore) { + return gpu::GetVkSemaphoreHandle( + vk_device, vk_semaphore, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT); +} + +VkExternalMemoryHandleTypeFlagBits +VulkanImplementationHeadless::GetExternalImageHandleType() { + return VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; +} + +bool VulkanImplementationHeadless::CanImportGpuMemoryBuffer( + gfx::GpuMemoryBufferType memory_buffer_type) { + if (memory_buffer_type == gfx::GpuMemoryBufferType::NATIVE_PIXMAP) + return true; + return false; +} + +std::unique_ptr<gpu::VulkanImage> +VulkanImplementationHeadless::CreateImageFromGpuMemoryHandle( + gpu::VulkanDeviceQueue* device_queue, + gfx::GpuMemoryBufferHandle gmb_handle, + gfx::Size size, + VkFormat vk_format) { + constexpr auto kUsage = + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + auto tiling = gmb_handle.native_pixmap_handle.modifier == + gfx::NativePixmapHandle::kNoModifier + ? VK_IMAGE_TILING_OPTIMAL + : VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; + return gpu::VulkanImage::CreateFromGpuMemoryBufferHandle( + device_queue, std::move(gmb_handle), size, vk_format, kUsage, /*flags=*/0, + tiling, VK_QUEUE_FAMILY_EXTERNAL); +} + +} // namespace ui diff --git a/chromium/ui/ozone/platform/headless/vulkan_implementation_headless.h b/chromium/ui/ozone/platform/headless/vulkan_implementation_headless.h new file mode 100644 index 00000000000..7d4912d9d51 --- /dev/null +++ b/chromium/ui/ozone/platform/headless/vulkan_implementation_headless.h @@ -0,0 +1,60 @@ +// Copyright (c) 2022 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_HEADLESS_VULKAN_IMPLEMENTATION_HEADLESS_H_ +#define UI_OZONE_PLATFORM_HEADLESS_VULKAN_IMPLEMENTATION_HEADLESS_H_ + +#include <memory> +#include <vector> + +#include "gpu/vulkan/vulkan_implementation.h" +#include "gpu/vulkan/vulkan_instance.h" + +namespace ui { + +class VulkanImplementationHeadless : public gpu::VulkanImplementation { + public: + explicit VulkanImplementationHeadless(bool use_swiftshader = false); + + VulkanImplementationHeadless(const VulkanImplementationHeadless&) = delete; + VulkanImplementationHeadless& operator=(const VulkanImplementationHeadless&) = + delete; + + // VulkanImplementation: + bool InitializeVulkanInstance(bool using_surface) override; + gpu::VulkanInstance* GetVulkanInstance() override; + std::unique_ptr<gpu::VulkanSurface> CreateViewSurface( + gfx::AcceleratedWidget window) override; + bool GetPhysicalDevicePresentationSupport( + VkPhysicalDevice device, + 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, + VkFence vk_fence) override; + VkSemaphore CreateExternalSemaphore(VkDevice vk_device) override; + VkSemaphore ImportSemaphoreHandle(VkDevice vk_device, + gpu::SemaphoreHandle handle) override; + gpu::SemaphoreHandle GetSemaphoreHandle(VkDevice vk_device, + VkSemaphore vk_semaphore) override; + VkExternalMemoryHandleTypeFlagBits GetExternalImageHandleType() override; + bool CanImportGpuMemoryBuffer( + gfx::GpuMemoryBufferType memory_buffer_type) override; + std::unique_ptr<gpu::VulkanImage> CreateImageFromGpuMemoryHandle( + gpu::VulkanDeviceQueue* device_queue, + gfx::GpuMemoryBufferHandle gmb_handle, + gfx::Size size, + VkFormat vk_formae) override; + + private: + bool using_surface_ = true; + gpu::VulkanInstance vulkan_instance_; +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_HEADLESS_VULKAN_IMPLEMENTATION_HEADLESS_H_ diff --git a/chromium/ui/ozone/platform/headless/vulkan_surface_headless.cc b/chromium/ui/ozone/platform/headless/vulkan_surface_headless.cc new file mode 100644 index 00000000000..e421a7e5f3a --- /dev/null +++ b/chromium/ui/ozone/platform/headless/vulkan_surface_headless.cc @@ -0,0 +1,38 @@ +// Copyright 2022 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/headless/vulkan_surface_headless.h" + +#include "base/logging.h" +#include "gpu/vulkan/vulkan_function_pointers.h" +#include "ui/gfx/native_widget_types.h" + +namespace ui { + +// static +std::unique_ptr<VulkanSurfaceHeadless> VulkanSurfaceHeadless::Create( + VkInstance vk_instance, + gfx::AcceleratedWidget widget) { + VkSurfaceKHR vk_surface; + const VkHeadlessSurfaceCreateInfoEXT surface_create_info = { + .sType = VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT, + .pNext = nullptr, + .flags = 0, + }; + VkResult result = vkCreateHeadlessSurfaceEXT( + vk_instance, &surface_create_info, nullptr, &vk_surface); + if (VK_SUCCESS != result) { + DLOG(ERROR) << "vkCreateHeadlessSurfaceEXT() failed: " << result; + return nullptr; + } + return std::make_unique<VulkanSurfaceHeadless>(vk_instance, vk_surface, + widget); +} + +VulkanSurfaceHeadless::VulkanSurfaceHeadless(VkInstance vk_instance, + VkSurfaceKHR vk_surface, + gfx::AcceleratedWidget widget) + : gpu::VulkanSurface(vk_instance, widget, vk_surface) {} + +} // namespace ui diff --git a/chromium/ui/ozone/platform/headless/vulkan_surface_headless.h b/chromium/ui/ozone/platform/headless/vulkan_surface_headless.h new file mode 100644 index 00000000000..fb9ded1823c --- /dev/null +++ b/chromium/ui/ozone/platform/headless/vulkan_surface_headless.h @@ -0,0 +1,30 @@ +// Copyright 2022 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_HEADLESS_VULKAN_SURFACE_HEADLESS_H_ +#define UI_OZONE_PLATFORM_HEADLESS_VULKAN_SURFACE_HEADLESS_H_ + +#include <vulkan/vulkan.h> +#include <memory> + +#include "gpu/vulkan/vulkan_surface.h" + +namespace ui { + +class VulkanSurfaceHeadless : public gpu::VulkanSurface { + public: + static std::unique_ptr<VulkanSurfaceHeadless> Create( + VkInstance vk_instance, + gfx::AcceleratedWidget widget); + VulkanSurfaceHeadless(VkInstance vk_instance, + VkSurfaceKHR vk_surface, + gfx::AcceleratedWidget widget); + + VulkanSurfaceHeadless(const VulkanSurfaceHeadless&) = delete; + VulkanSurfaceHeadless& operator=(const VulkanSurfaceHeadless&) = delete; +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_HEADLESS_VULKAN_SURFACE_HEADLESS_H_ diff --git a/chromium/ui/ozone/platform/scenic/scenic_surface.h b/chromium/ui/ozone/platform/scenic/scenic_surface.h index 485bae74328..e2a3344ae81 100644 --- a/chromium/ui/ozone/platform/scenic/scenic_surface.h +++ b/chromium/ui/ozone/platform/scenic/scenic_surface.h @@ -18,6 +18,7 @@ #include "base/containers/flat_map.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" +#include "base/time/time.h" #include "mojo/public/cpp/platform/platform_handle.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect_f.h" diff --git a/chromium/ui/ozone/platform/scenic/scenic_window.cc b/chromium/ui/ozone/platform/scenic/scenic_window.cc index 4a6589222e8..22b8fbab2ad 100644 --- a/chromium/ui/ozone/platform/scenic/scenic_window.cc +++ b/chromium/ui/ozone/platform/scenic/scenic_window.cc @@ -35,10 +35,11 @@ namespace { gfx::Insets ConvertInsets( float device_pixel_ratio, const fuchsia::ui::gfx::ViewProperties& view_properties) { - return gfx::Insets(device_pixel_ratio * view_properties.inset_from_min.y, - device_pixel_ratio * view_properties.inset_from_min.x, - device_pixel_ratio * view_properties.inset_from_max.y, - device_pixel_ratio * view_properties.inset_from_max.x); + return gfx::Insets::TLBR( + device_pixel_ratio * view_properties.inset_from_min.y, + device_pixel_ratio * view_properties.inset_from_min.x, + device_pixel_ratio * view_properties.inset_from_max.y, + device_pixel_ratio * view_properties.inset_from_max.x); } } // namespace @@ -206,7 +207,11 @@ PlatformWindowState ScenicWindow::GetPlatformWindowState() const { return PlatformWindowState::kFullScreen; if (!is_view_attached_) return PlatformWindowState::kMinimized; - return PlatformWindowState::kNormal; + + // TODO(crbug.com/1241868): We cannot tell what portion of the screen is + // occupied by the View, so report is as maximized to reduce the space used + // by any browser chrome. + return PlatformWindowState::kMaximized; } void ScenicWindow::Activate() { diff --git a/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc b/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc index fb585e20a71..4b86c0ce869 100644 --- a/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc +++ b/chromium/ui/ozone/platform/scenic/sysmem_buffer_collection.cc @@ -634,8 +634,7 @@ void SysmemBufferCollection::InitializeImageCreateInfo( vk_image_info->usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - if (usage_ == gfx::BufferUsage::SCANOUT || - usage_ == gfx::BufferUsage::SCANOUT_CPU_READ_WRITE) { + if (usage_ == gfx::BufferUsage::SCANOUT) { vk_image_info->usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; } diff --git a/chromium/ui/ozone/platform/scenic/sysmem_native_pixmap.cc b/chromium/ui/ozone/platform/scenic/sysmem_native_pixmap.cc index 0322f07e497..868120934d5 100644 --- a/chromium/ui/ozone/platform/scenic/sysmem_native_pixmap.cc +++ b/chromium/ui/ozone/platform/scenic/sysmem_native_pixmap.cc @@ -59,6 +59,11 @@ size_t SysmemNativePixmap::GetNumberOfPlanes() const { return 0; } +bool SysmemNativePixmap::SupportsZeroCopyWebGPUImport() const { + NOTREACHED(); + return false; +} + uint64_t SysmemNativePixmap::GetBufferFormatModifier() const { NOTREACHED(); return 0; diff --git a/chromium/ui/ozone/platform/scenic/sysmem_native_pixmap.h b/chromium/ui/ozone/platform/scenic/sysmem_native_pixmap.h index b54eca948a5..80b97dda569 100644 --- a/chromium/ui/ozone/platform/scenic/sysmem_native_pixmap.h +++ b/chromium/ui/ozone/platform/scenic/sysmem_native_pixmap.h @@ -27,6 +27,7 @@ class SysmemNativePixmap : public gfx::NativePixmap { size_t GetDmaBufOffset(size_t plane) const override; size_t GetDmaBufPlaneSize(size_t plane) const override; size_t GetNumberOfPlanes() const override; + bool SupportsZeroCopyWebGPUImport() const override; uint64_t GetBufferFormatModifier() const override; gfx::BufferFormat GetBufferFormat() const override; gfx::Size GetBufferSize() const override; diff --git a/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc b/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc index ed80cab4ce4..4ab374d9d26 100644 --- a/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc +++ b/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc @@ -284,6 +284,7 @@ VulkanImplementationScenic::CreateImageFromGpuMemoryHandle( return nullptr; } + image->set_queue_family_index(VK_QUEUE_FAMILY_EXTERNAL); image->set_native_pixmap(collection->CreateNativePixmap( gmb_handle.native_pixmap_handle.buffer_index)); return image; diff --git a/chromium/ui/ozone/platform/wayland/BUILD.gn b/chromium/ui/ozone/platform/wayland/BUILD.gn index aeaf7b8d94e..cb575394306 100644 --- a/chromium/ui/ozone/platform/wayland/BUILD.gn +++ b/chromium/ui/ozone/platform/wayland/BUILD.gn @@ -218,6 +218,7 @@ source_set("wayland") { "//mojo/public/cpp/system", "//skia", "//third_party/libsync", + "//third_party/re2", "//third_party/wayland:wayland_util", "//third_party/wayland-protocols:alpha_compositing_protocol", "//third_party/wayland-protocols:cursor_shapes_protocol", @@ -245,6 +246,7 @@ source_set("wayland") { "//ui/base", "//ui/base:buildflags", "//ui/base:data_exchange", + "//ui/base:features", "//ui/base/cursor", "//ui/base/cursor:theme_manager", "//ui/base/cursor/mojom:cursor_type", @@ -601,6 +603,7 @@ source_set("ui_test_support") { deps = [ ":wayland_proxy", "//base", + "//third_party/wayland:wayland_util", "//third_party/wayland-protocols:weston_test", "//ui/base:test_support", "//ui/events", diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_util.cc b/chromium/ui/ozone/platform/wayland/common/wayland_util.cc index 8823a541576..372e0e48dc4 100644 --- a/chromium/ui/ozone/platform/wayland/common/wayland_util.cc +++ b/chromium/ui/ozone/platform/wayland/common/wayland_util.cc @@ -190,6 +190,54 @@ wl_output_transform ToWaylandTransform(gfx::OverlayTransform transform) { return WL_OUTPUT_TRANSFORM_NORMAL; } +gfx::RectF ApplyWaylandTransform(const gfx::RectF& rect, + const gfx::SizeF& bounds, + wl_output_transform transform) { + gfx::RectF result = rect; + switch (transform) { + case WL_OUTPUT_TRANSFORM_NORMAL: + break; + case WL_OUTPUT_TRANSFORM_FLIPPED: + result.set_x(bounds.width() - rect.x() - rect.width()); + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + result.set_x(rect.y()); + result.set_y(rect.x()); + result.set_width(rect.height()); + result.set_height(rect.width()); + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_180: + result.set_y(bounds.height() - rect.y() - rect.height()); + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + result.set_x(bounds.height() - rect.y() - rect.height()); + result.set_y(bounds.width() - rect.x() - rect.width()); + result.set_width(rect.height()); + result.set_height(rect.width()); + break; + case WL_OUTPUT_TRANSFORM_90: + result.set_x(rect.y()); + result.set_y(bounds.width() - rect.x() - rect.width()); + result.set_width(rect.height()); + result.set_height(rect.width()); + break; + case WL_OUTPUT_TRANSFORM_180: + result.set_x(bounds.width() - rect.x() - rect.width()); + result.set_y(bounds.height() - rect.y() - rect.height()); + break; + case WL_OUTPUT_TRANSFORM_270: + result.set_x(bounds.height() - rect.y() - rect.height()); + result.set_y(rect.x()); + result.set_width(rect.height()); + result.set_height(rect.width()); + break; + default: + NOTREACHED(); + break; + } + return result; +} + gfx::Rect ApplyWaylandTransform(const gfx::Rect& rect, const gfx::Size& bounds, wl_output_transform transform) { @@ -301,7 +349,7 @@ SkPath ConvertPathToDIP(const SkPath& path_in_pixels, float scale) { gfx::Transform transform; transform.Scale(sk_scale, sk_scale); SkPath path_in_dips; - path_in_pixels.transform(SkMatrix(transform.matrix()), &path_in_dips); + path_in_pixels.transform(transform.matrix().asM33(), &path_in_dips); return path_in_dips; } diff --git a/chromium/ui/ozone/platform/wayland/common/wayland_util.h b/chromium/ui/ozone/platform/wayland/common/wayland_util.h index b8f298328ff..305dd91b123 100644 --- a/chromium/ui/ozone/platform/wayland/common/wayland_util.h +++ b/chromium/ui/ozone/platform/wayland/common/wayland_util.h @@ -73,6 +73,13 @@ gfx::Rect ApplyWaylandTransform(const gfx::Rect& rect, const gfx::Size& bounds, wl_output_transform transform); +// |bounds| contains |rect|. ApplyWaylandTransform() returns the resulted +// |rect| after transformation is applied to |bounds| containing |rect| as a +// whole. +gfx::RectF ApplyWaylandTransform(const gfx::RectF& rect, + const gfx::SizeF& bounds, + wl_output_transform transform); + // Applies transformation to |size|. gfx::SizeF ApplyWaylandTransform(const gfx::SizeF& size, wl_output_transform transform); 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 4a634386361..3d6d59d0b8a 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc +++ b/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc @@ -34,7 +34,7 @@ GbmPixmapWayland::GbmPixmapWayland(WaylandBufferManagerGpu* buffer_manager) GbmPixmapWayland::~GbmPixmapWayland() { if (gbm_bo_ && widget_ != gfx::kNullAcceleratedWidget) - buffer_manager_->DestroyBuffer(widget_, buffer_id_); + buffer_manager_->DestroyBuffer(buffer_id_); } bool GbmPixmapWayland::InitializeBuffer( @@ -141,6 +141,12 @@ size_t GbmPixmapWayland::GetNumberOfPlanes() const { return gbm_bo_->GetNumPlanes(); } +bool GbmPixmapWayland::SupportsZeroCopyWebGPUImport() const { + // TODO(crbug.com/1258986): Figure out how to import multi-planar pixmap into + // WebGPU without copy. + return false; +} + uint64_t GbmPixmapWayland::GetBufferFormatModifier() const { return gbm_bo_->GetFormatModifier(); } 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 e9b25a74528..49b038ba0dd 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.h +++ b/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.h @@ -57,6 +57,7 @@ class GbmPixmapWayland : public gfx::NativePixmap { size_t GetDmaBufOffset(size_t plane) const override; size_t GetDmaBufPlaneSize(size_t plane) const override; size_t GetNumberOfPlanes() const override; + bool SupportsZeroCopyWebGPUImport() const override; uint64_t GetBufferFormatModifier() const override; gfx::BufferFormat GetBufferFormat() const override; gfx::Size GetBufferSize() const override; 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 d3cd4021741..380c31fb067 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc +++ b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc @@ -6,10 +6,11 @@ #include <sync/sync.h> #include <cmath> +#include <cstdint> #include <memory> +#include <utility> #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" @@ -77,8 +78,7 @@ GbmSurfacelessWayland::SolidColorBufferHolder::GetOrCreateSolidColorBuffer( void GbmSurfacelessWayland::SolidColorBufferHolder::OnSubmission( BufferId buffer_id, - WaylandBufferManagerGpu* buffer_manager, - gfx::AcceleratedWidget widget) { + WaylandBufferManagerGpu* buffer_manager) { // Solid color buffers do not require on submission as skia doesn't track // them. Instead, they are tracked by GbmSurfacelessWayland. In the future, // when SharedImageFactory allows to create non-backed shared images, this @@ -96,7 +96,7 @@ void GbmSurfacelessWayland::SolidColorBufferHolder::OnSubmission( // ones until the maximum number of available solid color buffer. while (available_solid_color_buffers_.size() > kMaxSolidColorBuffers) { buffer_manager->DestroyBuffer( - widget, available_solid_color_buffers_.begin()->buffer_id); + available_solid_color_buffers_.begin()->buffer_id); available_solid_color_buffers_.erase( available_solid_color_buffers_.begin()); } @@ -104,10 +104,9 @@ void GbmSurfacelessWayland::SolidColorBufferHolder::OnSubmission( } void GbmSurfacelessWayland::SolidColorBufferHolder::EraseBuffers( - WaylandBufferManagerGpu* buffer_manager, - gfx::AcceleratedWidget widget) { + WaylandBufferManagerGpu* buffer_manager) { for (const auto& buffer : available_solid_color_buffers_) - buffer_manager->DestroyBuffer(widget, buffer.buffer_id); + buffer_manager->DestroyBuffer(buffer.buffer_id); available_solid_color_buffers_.clear(); } @@ -122,12 +121,13 @@ GbmSurfacelessWayland::GbmSurfacelessWayland( solid_color_buffers_holder_(std::make_unique<SolidColorBufferHolder>()), weak_factory_(this) { buffer_manager_->RegisterSurface(widget_, this); - unsubmitted_frames_.push_back(std::make_unique<PendingFrame>()); + unsubmitted_frames_.push_back( + std::make_unique<PendingFrame>(next_frame_id())); } void GbmSurfacelessWayland::QueueOverlayPlane(OverlayPlane plane, BufferId buffer_id) { - unsubmitted_frames_.back()->planes.emplace(buffer_id, std::move(plane)); + unsubmitted_frames_.back()->planes.emplace_back(buffer_id, std::move(plane)); } bool GbmSurfacelessWayland::ScheduleOverlayPlane( @@ -198,7 +198,8 @@ void GbmSurfacelessWayland::SwapBuffersAsync( frame->presentation_callback = std::move(presentation_callback); frame->ScheduleOverlayPlanes(this); - unsubmitted_frames_.push_back(std::make_unique<PendingFrame>()); + unsubmitted_frames_.push_back( + std::make_unique<PendingFrame>(next_frame_id())); // If Wayland server supports linux_explicit_synchronization_protocol, fences // should be shipped with buffers. Otherwise, we will wait for fences. @@ -255,7 +256,7 @@ EGLConfig GbmSurfacelessWayland::GetConfig() { EGL_SURFACE_TYPE, EGL_DONT_CARE, EGL_NONE}; - config_ = ChooseEGLConfig(GetDisplay(), config_attribs); + config_ = ChooseEGLConfig(GetEGLDisplay(), config_attribs); } return config_; } @@ -289,7 +290,7 @@ bool GbmSurfacelessWayland::Resize(const gfx::Size& size, surface_scale_factor_ = scale_factor; // Remove all the buffers. - solid_color_buffers_holder_->EraseBuffers(buffer_manager_, widget_); + solid_color_buffers_holder_->EraseBuffers(buffer_manager_); return gl::SurfacelessEGL::Resize(size, scale_factor, color_space, has_alpha); } @@ -298,7 +299,8 @@ GbmSurfacelessWayland::~GbmSurfacelessWayland() { buffer_manager_->UnregisterSurface(widget_); } -GbmSurfacelessWayland::PendingFrame::PendingFrame() = default; +GbmSurfacelessWayland::PendingFrame::PendingFrame(uint32_t frame_id) + : frame_id(frame_id) {} GbmSurfacelessWayland::PendingFrame::~PendingFrame() = default; @@ -368,14 +370,11 @@ void GbmSurfacelessWayland::MaybeSubmitFrames() { // The current scale factor of the surface, which is used to determine // the size in pixels of resources allocated by the GPU process. overlay_configs.back()->surface_scale_factor = surface_scale_factor_; -#if DCHECK_IS_ON() - if (plane.second.overlay_plane_data.z_order == INT32_MIN) - background_buffer_id_ = plane.first; -#endif plane.second.gpu_fence.reset(); } - buffer_manager_->CommitOverlays(widget_, std::move(overlay_configs)); + buffer_manager_->CommitOverlays(widget_, submitted_frame->frame_id, + std::move(overlay_configs)); submitted_frames_.push_back(std::move(submitted_frame)); } } @@ -384,7 +383,7 @@ EGLSyncKHR GbmSurfacelessWayland::InsertFence(bool implicit) { const EGLint attrib_list[] = {EGL_SYNC_CONDITION_KHR, EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM, EGL_NONE}; - return eglCreateSyncKHR(GetDisplay(), EGL_SYNC_FENCE_KHR, + return eglCreateSyncKHR(GetEGLDisplay(), EGL_SYNC_FENCE_KHR, implicit ? attrib_list : nullptr); } @@ -397,19 +396,21 @@ void GbmSurfacelessWayland::SetNoGLFlushForTests() { no_gl_flush_for_tests_ = true; } -void GbmSurfacelessWayland::OnSubmission(BufferId buffer_id, +void GbmSurfacelessWayland::OnSubmission(uint32_t frame_id, const gfx::SwapResult& swap_result, gfx::GpuFenceHandle release_fence) { - DCHECK(!submitted_frames_.empty()); - DCHECK(submitted_frames_.front()->planes.count(buffer_id) || - buffer_id == background_buffer_id_); + // If the frame_id is stale, the gpu process just recovered from a crash so + // this frame_id can be ignored. + if (submitted_frames_.empty() || + submitted_frames_.front()->frame_id != frame_id) { + return; + } auto submitted_frame = std::move(submitted_frames_.front()); submitted_frames_.erase(submitted_frames_.begin()); for (auto& plane : submitted_frame->planes) { // Let the holder mark this buffer as free to reuse. - solid_color_buffers_holder_->OnSubmission(plane.first, buffer_manager_, - widget_); + solid_color_buffers_holder_->OnSubmission(plane.first, buffer_manager_); } submitted_frame->planes.clear(); submitted_frame->overlays.clear(); @@ -417,7 +418,6 @@ void GbmSurfacelessWayland::OnSubmission(BufferId buffer_id, std::move(submitted_frame->completion_callback) .Run(gfx::SwapCompletionResult(swap_result, std::move(release_fence))); - submitted_frame->pending_presentation_buffer = buffer_id; pending_presentation_frames_.push_back(std::move(submitted_frame)); if (swap_result != gfx::SwapResult::SWAP_ACK) { @@ -429,11 +429,12 @@ void GbmSurfacelessWayland::OnSubmission(BufferId buffer_id, } void GbmSurfacelessWayland::OnPresentation( - BufferId buffer_id, + uint32_t frame_id, const gfx::PresentationFeedback& feedback) { - DCHECK(!pending_presentation_frames_.empty()); - DCHECK_EQ(pending_presentation_frames_.front()->pending_presentation_buffer, - buffer_id); + if (pending_presentation_frames_.empty() || + pending_presentation_frames_.front()->frame_id != frame_id) { + return; + } std::move(pending_presentation_frames_.front()->presentation_callback) .Run(feedback); 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 fd3911ee557..be8bc9c890e 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h +++ b/chromium/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.h @@ -5,10 +5,9 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_GPU_GBM_SURFACELESS_WAYLAND_H_ #define UI_OZONE_PLATFORM_WAYLAND_GPU_GBM_SURFACELESS_WAYLAND_H_ -#include <map> #include <memory> +#include <vector> -#include "base/containers/small_map.h" #include "base/gtest_prod_util.h" #include "base/memory/weak_ptr.h" #include "ui/gfx/native_widget_types.h" @@ -79,6 +78,8 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL, GbmSurfacelessWaylandCommitOverlaysCallbacksTest); FRIEND_TEST_ALL_PREFIXES(WaylandSurfaceFactoryTest, GbmSurfacelessWaylandGroupOnSubmissionCallbacksTest); + FRIEND_TEST_ALL_PREFIXES(WaylandSurfaceFactoryCompositorV3, + SurfaceDamageTest); // Holds solid color buffers. class SolidColorBufferHolder { @@ -91,10 +92,8 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL, WaylandBufferManagerGpu* buffer_manager); void OnSubmission(BufferId buffer_id, - WaylandBufferManagerGpu* buffer_manager, - gfx::AcceleratedWidget widget); - void EraseBuffers(WaylandBufferManagerGpu* buffer_manager, - gfx::AcceleratedWidget widget); + WaylandBufferManagerGpu* buffer_manager); + void EraseBuffers(WaylandBufferManagerGpu* buffer_manager); private: // Gpu-size holder for the solid color buffers. These are not backed by @@ -121,10 +120,10 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL, ~GbmSurfacelessWayland() override; // WaylandSurfaceGpu overrides: - void OnSubmission(BufferId buffer_id, + void OnSubmission(uint32_t frame_id, const gfx::SwapResult& swap_result, gfx::GpuFenceHandle release_fence) override; - void OnPresentation(BufferId buffer_id, + void OnPresentation(uint32_t frame_id, const gfx::PresentationFeedback& feedback) override; // PendingFrame here is a post-SkiaRenderer struct that contains overlays + @@ -132,13 +131,16 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL, // level. This information gets into browser process and overlays are // translated to be attached to WaylandSurfaces of the AcceleratedWidget. struct PendingFrame { - PendingFrame(); + explicit PendingFrame(uint32_t frame_id); ~PendingFrame(); // Queues overlay configs to |planes|. void ScheduleOverlayPlanes(GbmSurfacelessWayland* surfaceless); void Flush(); + // Unique identifier of the frame within this AcceleratedWidget. + uint32_t frame_id; + bool ready = false; // TODO(fangzhoug): This should be changed to support Vulkan. @@ -150,10 +152,9 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL, // fences for a particular OnSubmission. bool schedule_planes_succeeded = false; - // Maps |buffer_id| to one or more OverlayPlanes, used for committing - // overlays and wait for OnSubmission's. - std::multimap<BufferId, OverlayPlane> planes; - BufferId pending_presentation_buffer; + // Contains |buffer_id|s to OverlayPlanes, used for committing overlays and + // wait for OnSubmission's. + std::vector<std::pair<BufferId, OverlayPlane>> planes; }; void MaybeSubmitFrames(); @@ -166,12 +167,6 @@ class GbmSurfacelessWayland : public gl::SurfacelessEGL, WaylandBufferManagerGpu* const buffer_manager_; - // |background_buffer_id| is sent to WaylandBufferManagerHost once per - // background_buffer allocation. However WaylandBufferManagerHost may commit - // this buffer more often b/c buffers needs to be re-attached when wl_surface - // is reshown. - BufferId background_buffer_id_; - // The native surface. Deleting this is allowed to free the EGLNativeWindow. gfx::AcceleratedWidget widget_; 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 index 8df7730acd4..9e955388c5f 100644 --- 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 @@ -117,7 +117,8 @@ void GLSurfaceEglReadbackWayland::SwapBuffersAsync( ReadPixels(next_buffer->shm_mapping_.memory()); const auto bounds = gfx::Rect(GetSize()); - buffer_manager_->CommitBuffer(widget_, next_buffer->buffer_id_, bounds, + buffer_manager_->CommitBuffer(widget_, next_buffer->buffer_id_, + /*frame_id*/ next_buffer->buffer_id_, bounds, surface_scale_factor_, bounds); } @@ -132,7 +133,7 @@ GLSurfaceEglReadbackWayland::~GLSurfaceEglReadbackWayland() { } void GLSurfaceEglReadbackWayland::OnSubmission( - uint32_t buffer_id, + uint32_t frame_id, const gfx::SwapResult& swap_result, gfx::GpuFenceHandle release_fence) { DCHECK(release_fence.is_null()); @@ -142,7 +143,7 @@ void GLSurfaceEglReadbackWayland::OnSubmission( 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); + DCHECK_EQ(displayed_buffer_->buffer_id_, frame_id); } in_flight_pixel_buffers_.pop_front(); @@ -154,7 +155,7 @@ void GLSurfaceEglReadbackWayland::OnSubmission( } void GLSurfaceEglReadbackWayland::OnPresentation( - uint32_t buffer_id, + uint32_t frame_id, const gfx::PresentationFeedback& feedback) { DCHECK(!presentation_callbacks_.empty()); std::move(presentation_callbacks_.front()).Run(feedback); @@ -163,12 +164,12 @@ void GLSurfaceEglReadbackWayland::OnPresentation( void GLSurfaceEglReadbackWayland::DestroyBuffers() { for (const auto& pixel_buffer : available_buffers_) - buffer_manager_->DestroyBuffer(widget_, pixel_buffer->buffer_id_); + buffer_manager_->DestroyBuffer(pixel_buffer->buffer_id_); for (const auto& pixel_buffer : in_flight_pixel_buffers_) - buffer_manager_->DestroyBuffer(widget_, pixel_buffer->buffer_id_); + buffer_manager_->DestroyBuffer(pixel_buffer->buffer_id_); if (displayed_buffer_) - buffer_manager_->DestroyBuffer(widget_, displayed_buffer_->buffer_id_); + buffer_manager_->DestroyBuffer(displayed_buffer_->buffer_id_); available_buffers_.clear(); in_flight_pixel_buffers_.clear(); 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 index af65f174902..8d8f915307d 100644 --- 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 @@ -71,10 +71,10 @@ class GLSurfaceEglReadbackWayland : public GLSurfaceEglReadback, ~GLSurfaceEglReadbackWayland() override; // WaylandSurfaceGpu: - void OnSubmission(uint32_t buffer_id, + void OnSubmission(uint32_t frame_id, const gfx::SwapResult& swap_result, gfx::GpuFenceHandle release_fence) override; - void OnPresentation(uint32_t buffer_id, + void OnPresentation(uint32_t frame_id, const gfx::PresentationFeedback& feedback) override; void DestroyBuffers(); 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 b8993c995cd..d79ce4f3df5 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc +++ b/chromium/ui/ozone/platform/wayland/gpu/gl_surface_wayland.cc @@ -70,7 +70,7 @@ EGLConfig GLSurfaceWayland::GetConfig() { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE}; - config_ = ChooseEGLConfig(GetDisplay(), config_attribs); + config_ = ChooseEGLConfig(GetEGLDisplay(), config_attribs); } return config_; } 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 84c70912c3f..32ceabf355d 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 @@ -259,6 +259,7 @@ void WaylandBufferManagerGpu::CreateSolidColorBuffer(SkColor color, } void WaylandBufferManagerGpu::CommitBuffer(gfx::AcceleratedWidget widget, + uint32_t frame_id, uint32_t buffer_id, const gfx::Rect& bounds_rect, float surface_scale_factor, @@ -273,42 +274,42 @@ void WaylandBufferManagerGpu::CommitBuffer(gfx::AcceleratedWidget widget, 1.0f /*opacity*/, gfx::GpuFenceHandle(), gfx::OverlayPriorityHint::kNone, gfx::RRectF())); - CommitOverlays(widget, std::move(overlay_configs)); + CommitOverlays(widget, frame_id, std::move(overlay_configs)); } void WaylandBufferManagerGpu::CommitOverlays( gfx::AcceleratedWidget widget, + uint32_t frame_id, std::vector<ozone::mojom::WaylandOverlayConfigPtr> overlays) { DCHECK(gpu_thread_runner_); if (!gpu_thread_runner_->BelongsToCurrentThread()) { // Do the mojo call on the GpuMainThread. gpu_thread_runner_->PostTask( - FROM_HERE, - base::BindOnce(&WaylandBufferManagerGpu::CommitOverlays, - base::Unretained(this), widget, std::move(overlays))); + FROM_HERE, base::BindOnce(&WaylandBufferManagerGpu::CommitOverlays, + base::Unretained(this), widget, frame_id, + std::move(overlays))); return; } - base::OnceClosure task = - base::BindOnce(&WaylandBufferManagerGpu::CommitOverlaysTask, - base::Unretained(this), widget, std::move(overlays)); + base::OnceClosure task = base::BindOnce( + &WaylandBufferManagerGpu::CommitOverlaysTask, base::Unretained(this), + widget, frame_id, std::move(overlays)); RunOrQueueTask(std::move(task)); } -void WaylandBufferManagerGpu::DestroyBuffer(gfx::AcceleratedWidget widget, - uint32_t buffer_id) { +void WaylandBufferManagerGpu::DestroyBuffer(uint32_t buffer_id) { DCHECK(gpu_thread_runner_); if (!gpu_thread_runner_->BelongsToCurrentThread()) { // Do the mojo call on the GpuMainThread. gpu_thread_runner_->PostTask( FROM_HERE, base::BindOnce(&WaylandBufferManagerGpu::DestroyBuffer, - base::Unretained(this), widget, buffer_id)); + base::Unretained(this), buffer_id)); return; } base::OnceClosure task = base::BindOnce(&WaylandBufferManagerGpu::DestroyBufferTask, - base::Unretained(this), widget, buffer_id); + base::Unretained(this), buffer_id); RunOrQueueTask(std::move(task)); } @@ -398,26 +399,26 @@ void WaylandBufferManagerGpu::ForgetTaskRunnerForWidgetOnIOThread( void WaylandBufferManagerGpu::SubmitSwapResultOnOriginThread( gfx::AcceleratedWidget widget, - uint32_t buffer_id, + uint32_t frame_id, gfx::SwapResult swap_result, gfx::GpuFenceHandle release_fence) { DCHECK_NE(widget, gfx::kNullAcceleratedWidget); auto* surface = GetSurface(widget); // The surface might be destroyed by the time the swap result is provided. if (surface) - surface->OnSubmission(buffer_id, swap_result, std::move(release_fence)); + surface->OnSubmission(frame_id, swap_result, std::move(release_fence)); } void WaylandBufferManagerGpu::SubmitPresentationOnOriginThread( gfx::AcceleratedWidget widget, - uint32_t buffer_id, + uint32_t frame_id, const gfx::PresentationFeedback& feedback) { DCHECK_NE(widget, gfx::kNullAcceleratedWidget); auto* surface = GetSurface(widget); // The surface might be destroyed by the time the presentation feedback is // provided. if (surface) - surface->OnPresentation(buffer_id, feedback); + surface->OnPresentation(frame_id, feedback); } #if defined(WAYLAND_GBM) @@ -508,19 +509,19 @@ void WaylandBufferManagerGpu::CreateSolidColorBufferTask(SkColor color, void WaylandBufferManagerGpu::CommitOverlaysTask( gfx::AcceleratedWidget widget, + uint32_t frame_id, std::vector<ozone::mojom::WaylandOverlayConfigPtr> overlays) { DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_); DCHECK(remote_host_); - remote_host_->CommitOverlays(widget, std::move(overlays)); + remote_host_->CommitOverlays(widget, frame_id, std::move(overlays)); } -void WaylandBufferManagerGpu::DestroyBufferTask(gfx::AcceleratedWidget widget, - uint32_t buffer_id) { +void WaylandBufferManagerGpu::DestroyBufferTask(uint32_t buffer_id) { DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_); DCHECK(remote_host_); - remote_host_->DestroyBuffer(widget, buffer_id); + remote_host_->DestroyBuffer(buffer_id); } } // namespace ui 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 69dd6538053..662db319757 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 @@ -5,6 +5,7 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_GPU_WAYLAND_BUFFER_MANAGER_GPU_H_ #define UI_OZONE_PLATFORM_WAYLAND_GPU_WAYLAND_BUFFER_MANAGER_GPU_H_ +#include <cstdint> #include <map> #include <memory> @@ -63,13 +64,13 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu { // These two calls get the surface, which backs the |widget| and notifies it // about the submission and the presentation. After the surface receives the - // OnSubmission call, it can schedule a new buffer for swap. + // OnSubmission call, it can schedule a new frame for swap. void OnSubmission(gfx::AcceleratedWidget widget, - uint32_t buffer_id, + uint32_t frame_id, gfx::SwapResult swap_result, gfx::GpuFenceHandle release_fence_handle) override; void OnPresentation(gfx::AcceleratedWidget widget, - uint32_t buffer_id, + uint32_t frame_id, const gfx::PresentationFeedback& feedback) override; // If the client, which uses this manager and implements WaylandSurfaceGpu, @@ -122,6 +123,7 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu { // CommitBuffer() calls CommitOverlays() to commit only a primary plane // buffer. void CommitBuffer(gfx::AcceleratedWidget widget, + uint32_t frame_id, uint32_t buffer_id, const gfx::Rect& bounds_rect, float surface_scale_factor, @@ -130,10 +132,11 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu { // |widget|. void CommitOverlays( gfx::AcceleratedWidget widget, + uint32_t frame_id, std::vector<ozone::mojom::WaylandOverlayConfigPtr> overlays); // Asks Wayland to destroy a wl_buffer. - void DestroyBuffer(gfx::AcceleratedWidget widget, uint32_t buffer_id); + void DestroyBuffer(uint32_t buffer_id); #if defined(WAYLAND_GBM) // Returns a gbm_device based on a DRM render node. @@ -166,6 +169,8 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu { GbmSurfacelessWaylandCommitOverlaysCallbacksTest); FRIEND_TEST_ALL_PREFIXES(WaylandSurfaceFactoryTest, GbmSurfacelessWaylandGroupOnSubmissionCallbacksTest); + FRIEND_TEST_ALL_PREFIXES(WaylandSurfaceFactoryCompositorV3, + SurfaceDamageTest); FRIEND_TEST_ALL_PREFIXES(WaylandBufferManagerTest, ExecutesTasksAfterInitialization); FRIEND_TEST_ALL_PREFIXES(WaylandOverlayManagerTest, @@ -182,12 +187,12 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu { // Provides the WaylandSurfaceGpu, which backs the |widget|, with swap and // presentation results. void SubmitSwapResultOnOriginThread(gfx::AcceleratedWidget widget, - uint32_t buffer_id, + uint32_t frame_id, gfx::SwapResult swap_result, gfx::GpuFenceHandle release_fence); void SubmitPresentationOnOriginThread( gfx::AcceleratedWidget widget, - uint32_t buffer_id, + uint32_t frame_id, const gfx::PresentationFeedback& feedback); void OnHostDisconnected(); @@ -217,8 +222,9 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu { uint32_t buf_id); void CommitOverlaysTask( gfx::AcceleratedWidget widget, + uint32_t frame_id, std::vector<ozone::mojom::WaylandOverlayConfigPtr> overlays); - void DestroyBufferTask(gfx::AcceleratedWidget widget, uint32_t buffer_id); + void DestroyBufferTask(uint32_t buffer_id); #if defined(WAYLAND_GBM) // Finds drm render node, opens it and stores the handle into 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 a88a6161faf..a58e342a74f 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc +++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc @@ -45,7 +45,7 @@ class WaylandCanvasSurface::SharedMemoryBuffer { SharedMemoryBuffer(const SharedMemoryBuffer&) = delete; SharedMemoryBuffer& operator=(const SharedMemoryBuffer&) = delete; - ~SharedMemoryBuffer() { buffer_manager_->DestroyBuffer(widget_, buffer_id_); } + ~SharedMemoryBuffer() { buffer_manager_->DestroyBuffer(buffer_id_); } // Returns SkSurface, which the client can use to write to this buffer. sk_sp<SkSurface> sk_surface() const { return sk_surface_; } @@ -95,8 +95,8 @@ class WaylandCanvasSurface::SharedMemoryBuffer { } void CommitBuffer(const gfx::Rect& damage, float buffer_scale) { - buffer_manager_->CommitBuffer(widget_, buffer_id_, gfx::Rect(size_), - buffer_scale, damage); + buffer_manager_->CommitBuffer(widget_, buffer_id_, /*frame_id*/ buffer_id_, + gfx::Rect(size_), buffer_scale, damage); } void OnUse() { @@ -313,7 +313,7 @@ void WaylandCanvasSurface::ProcessUnsubmittedBuffers() { current_buffer_->CommitBuffer(damage, viewport_scale_); } -void WaylandCanvasSurface::OnSubmission(uint32_t buffer_id, +void WaylandCanvasSurface::OnSubmission(uint32_t frame_id, const gfx::SwapResult& swap_result, gfx::GpuFenceHandle release_fence) { DCHECK(release_fence.is_null()); @@ -323,15 +323,15 @@ void WaylandCanvasSurface::OnSubmission(uint32_t buffer_id, // 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|. + // so we will not know about |frame_id|. if (std::none_of(buffers_.begin(), buffers_.end(), - [buffer_id](const auto& buffer) { - return buffer->buffer_id() == buffer_id; + [frame_id](const auto& buffer) { + return buffer->buffer_id() == frame_id; })) return; DCHECK(current_buffer_); - DCHECK_EQ(current_buffer_->buffer_id(), buffer_id); + DCHECK_EQ(current_buffer_->buffer_id(), frame_id); if (previous_buffer_) previous_buffer_->OnRelease(); @@ -344,7 +344,7 @@ void WaylandCanvasSurface::OnSubmission(uint32_t buffer_id, } void WaylandCanvasSurface::OnPresentation( - uint32_t buffer_id, + uint32_t frame_id, const gfx::PresentationFeedback& feedback) { last_timestamp_ = feedback.timestamp; last_interval_ = feedback.interval; 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 a7f60c10928..cbf4414ee6d 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.h +++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.h @@ -9,6 +9,7 @@ #include <vector> #include "base/memory/weak_ptr.h" +#include "base/time/time.h" #include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/core/SkSurface.h" #include "ui/gfx/geometry/size.h" @@ -73,10 +74,10 @@ class WaylandCanvasSurface : public SurfaceOzoneCanvas, void ProcessUnsubmittedBuffers(); // WaylandSurfaceGpu overrides: - void OnSubmission(uint32_t buffer_id, + void OnSubmission(uint32_t frame_id, const gfx::SwapResult& swap_result, gfx::GpuFenceHandle release_fence) override; - void OnPresentation(uint32_t buffer_id, + void OnPresentation(uint32_t frame_id, const gfx::PresentationFeedback& feedback) override; sk_sp<SkSurface> GetNextSurface(); diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_overlay_manager.cc b/chromium/ui/ozone/platform/wayland/gpu/wayland_overlay_manager.cc index 1c44f05f722..e4cb8ec1dcf 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/wayland_overlay_manager.cc +++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_overlay_manager.cc @@ -80,6 +80,18 @@ bool WaylandOverlayManager::CanHandleCandidate( kAssumedMaxDeviceScaleFactor) == 0) return false; + // Passing an empty surface size through wayland will actually clear the size + // restriction and display the buffer at full size. The function + // 'set_destination_size' in augmenter will accept empty sizes without + // protocol error but interprets this as a clear. + // TODO(https://crbug.com/1306230) : Move and generalize this fix in wayland + // host. + if (wl_fixed_from_double(candidate.display_rect.width() / + kAssumedMaxDeviceScaleFactor) == 0 || + wl_fixed_from_double(candidate.display_rect.height() / + kAssumedMaxDeviceScaleFactor) == 0) + return false; + if (candidate.transform == gfx::OVERLAY_TRANSFORM_INVALID) return false; 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 df94127bc6e..73ac0a0a672 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 @@ -852,13 +852,143 @@ TEST_P(WaylandSurfaceFactoryTest, CreateSurfaceCheckGbm) { EXPECT_FALSE(gl_surface); } +class WaylandSurfaceFactoryCompositorV3 : public WaylandSurfaceFactoryTest {}; + +TEST_P(WaylandSurfaceFactoryCompositorV3, SurfaceDamageTest) { + // This tests multiple buffers per-frame and order of SwapCompletionCallbacks. + // Even when all OnSubmission from later frames are called, their + // SwapCompletionCallbacks should not run until previous frames' + // SwapCompletionCallbacks run. + gl::SetGLImplementation(gl::kGLImplementationEGLGLES2); + + buffer_manager_gpu_->use_fake_gbm_device_for_test_ = true; + buffer_manager_gpu_->gbm_device_ = std::make_unique<MockGbmDevice>(); + buffer_manager_gpu_->supports_dmabuf_ = true; + + auto* gl_ozone = surface_factory_->GetGLOzone( + gl::GLImplementationParts(gl::kGLImplementationEGLGLES2)); + auto gl_surface = gl_ozone->CreateSurfacelessViewGLSurface(widget_); + EXPECT_TRUE(gl_surface); + gl_surface->SetRelyOnImplicitSync(); + static_cast<ui::GbmSurfacelessWayland*>(gl_surface.get()) + ->SetNoGLFlushForTests(); + + // Expect to create 4 buffers. + EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(4); + + gfx::Size test_buffer_size = {300, 100}; + gfx::RectF test_buffer_dmg_uv = {0.2f, 0.3f, 0.6, 0.32f}; + gfx::Rect test_buffer_dmg = gfx::ToEnclosingRect(gfx::ScaleRect( + test_buffer_dmg_uv, test_buffer_size.width(), test_buffer_size.height())); + gfx::RectF crop_uv = {0.1f, 0.2f, 0.5, 0.5f}; + gfx::RectF expected_combined_uv = {0.2, 0.2, 0.8, 0.64}; + gfx::Rect expected_surface_dmg = gfx::ToEnclosingRect( + gfx::ScaleRect(expected_combined_uv, window_->GetBounds().width(), + window_->GetBounds().height())); + + // Create buffers and FakeGlImageNativePixmap. + std::vector<scoped_refptr<FakeGLImageNativePixmap>> fake_gl_image; + for (int i = 0; i < 4; ++i) { + auto native_pixmap = surface_factory_->CreateNativePixmap( + widget_, nullptr, test_buffer_size, gfx::BufferFormat::BGRA_8888, + gfx::BufferUsage::SCANOUT); + fake_gl_image.push_back(base::MakeRefCounted<FakeGLImageNativePixmap>( + native_pixmap, test_buffer_size)); + + Sync(); + + // Create one buffer at a time. + auto params_vector = server_.zwp_linux_dmabuf_v1()->buffer_params(); + DCHECK_EQ(params_vector.size(), 1u); + zwp_linux_buffer_params_v1_send_created( + params_vector.front()->resource(), + params_vector.front()->buffer_resource()); + + Sync(); + } + + auto* root_surface = server_.GetObject<wl::MockSurface>( + window_->root_surface()->GetSurfaceId()); + auto* mock_primary_surface = server_.GetObject<wl::MockSurface>( + window_->primary_subsurface()->wayland_surface()->GetSurfaceId()); + + CallbacksHelper cbs_helper; + // Submit a frame with an overlay and background. + { + // Associate each image with swap id so that we could track released + // buffers. + auto swap_id = cbs_helper.GetNextLocalSwapId(); + // Associate the image with the next swap id so that we can easily track if + // it became free to reuse. + fake_gl_image[0]->AssociateWithSwapId(swap_id); + // And set it to be busy... + fake_gl_image[0]->SetBusy(true); + + // Prepare background. + gl_surface->ScheduleOverlayPlane( + fake_gl_image[0].get(), nullptr, + gfx::OverlayPlaneData( + INT32_MIN, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE, + gfx::RectF(window_->GetBounds()), crop_uv, false, + gfx::Rect(test_buffer_dmg), 1.0f, gfx::OverlayPriorityHint::kNone, + gfx::RRectF(), gfx::ColorSpace::CreateSRGB(), absl::nullopt)); + + std::vector<scoped_refptr<FakeGLImageNativePixmap>> gl_images; + gl_images.push_back(fake_gl_image[0]); + + // And submit each image. They will be executed in FIFO manner. + gl_surface->SwapBuffersAsync( + base::BindOnce(&CallbacksHelper::FinishSwapBuffersAsync, + base::Unretained(&cbs_helper), swap_id, gl_images), + base::BindOnce(&CallbacksHelper::BufferPresented, + base::Unretained(&cbs_helper), swap_id)); + } + + // Let's sync so that 1) GbmSurfacelessWayland submits the buffer according to + // internal queue and fake server processes the request. + + // Wait until the mojo calls are done. + base::RunLoop().RunUntilIdle(); + + Expectation damage = + EXPECT_CALL(*surface_, Damage(expected_surface_dmg.origin().x(), + expected_surface_dmg.origin().y(), + expected_surface_dmg.width(), + expected_surface_dmg.height())); + wl_resource* buffer_resource = nullptr; + Expectation attach = EXPECT_CALL(*surface_, Attach(_, 0, 0)) + .WillOnce(SaveArg<0>(&buffer_resource)); + EXPECT_CALL(*surface_, Commit()).After(damage, attach); + + Sync(); + + testing::Mock::VerifyAndClearExpectations(mock_primary_surface); + testing::Mock::VerifyAndClearExpectations(root_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(); +} + INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest, WaylandSurfaceFactoryTest, Values(wl::ServerConfig{ .shell_version = wl::ShellVersion::kStable})); + INSTANTIATE_TEST_SUITE_P(XdgVersionV6Test, WaylandSurfaceFactoryTest, Values(wl::ServerConfig{ .shell_version = wl::ShellVersion::kV6})); +INSTANTIATE_TEST_SUITE_P( + CompositorVersionV3Test, + WaylandSurfaceFactoryCompositorV3, + Values(wl::ServerConfig{.compositor_version = wl::CompositorVersion::kV3})); + } // namespace ui 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 64f3aba5dec..e6b755c8674 100644 --- a/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h +++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h @@ -20,22 +20,28 @@ namespace ui { // the buffer. class WaylandSurfaceGpu { public: - virtual ~WaylandSurfaceGpu() {} - - // Tells the surface the result of the last swap of buffer with the - // |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, + virtual ~WaylandSurfaceGpu() = default; + + // Tells the surface the result of the last swap of frame with the |frame_id|. + // After this callback, the previously (before |frame_id|) submitted buffers + // may be reused. This is guaranteed to be called in the same order that + // frames were submitted. If not, there's been a GPU process crash and the + // stale |frame_id| can be ignored. + virtual void OnSubmission(uint32_t frame_id, const gfx::SwapResult& swap_result, gfx::GpuFenceHandle release_fence) = 0; // Tells the surface the result of the last presentation of buffer with the - // |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, + // |frame_id|. This is guaranteed to be called in the same order that frames + // were submitted, and is guaranteed to be called after the corresponding call + // to |OnSubmission| for this frame. + virtual void OnPresentation(uint32_t frame_id, const gfx::PresentationFeedback& feedback) = 0; + + uint32_t next_frame_id() { return ++frame_id_; } + + private: + uint32_t frame_id_ = 0u; }; } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/DEPS b/chromium/ui/ozone/platform/wayland/host/DEPS index 02595ff5fc8..bae43b4dd25 100644 --- a/chromium/ui/ozone/platform/wayland/host/DEPS +++ b/chromium/ui/ozone/platform/wayland/host/DEPS @@ -9,4 +9,5 @@ include_rules = [ "+components/crash/core/common", "+dbus", "+ui/base/linux", + "+third_party/re2", ] diff --git a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc b/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc index 59ac3767f7d..92bb004a390 100644 --- a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc +++ b/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.cc @@ -6,7 +6,6 @@ #include <gtk-primary-selection-client-protocol.h> -#include "base/logging.h" #include "ui/ozone/platform/wayland/host/gtk_primary_selection_offer.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" #include "ui/ozone/platform/wayland/host/wayland_data_source.h" @@ -27,15 +26,11 @@ GtkPrimarySelectionDevice::GtkPrimarySelectionDevice( GtkPrimarySelectionDevice::~GtkPrimarySelectionDevice() = default; void GtkPrimarySelectionDevice::SetSelectionSource( - GtkPrimarySelectionSource* source) { - auto serial = GetSerialForSelection(); - if (!serial.has_value()) { - LOG(ERROR) << "Failed to set selection. No serial found."; - return; - } + GtkPrimarySelectionSource* source, + uint32_t serial) { auto* data_source = source ? source->data_source() : nullptr; gtk_primary_selection_device_set_selection(data_device_.get(), data_source, - serial->value); + serial); connection()->ScheduleFlush(); } diff --git a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.h b/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.h index a9bcdb06623..219db517859 100644 --- a/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.h +++ b/chromium/ui/ozone/platform/wayland/host/gtk_primary_selection_device.h @@ -5,7 +5,8 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_PRIMARY_SELECTION_DEVICE_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_GTK_PRIMARY_SELECTION_DEVICE_H_ -#include "base/callback.h" +#include <cstdint> + #include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/host/wayland_data_device_base.h" #include "ui/ozone/platform/wayland/host/wayland_data_source.h" @@ -32,7 +33,7 @@ class GtkPrimarySelectionDevice : public WaylandDataDeviceBase { return data_device_.get(); } - void SetSelectionSource(GtkPrimarySelectionSource* source); + void SetSelectionSource(GtkPrimarySelectionSource* source, uint32_t serial); private: // gtk_primary_selection_device_listener callbacks diff --git a/chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h b/chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h index 7e67dc95085..35151f7e32e 100644 --- a/chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h +++ b/chromium/ui/ozone/platform/wayland/host/shell_toplevel_wrapper.h @@ -76,9 +76,14 @@ class ShellToplevelWrapper { // Tells if the surface has been AckConfigured at least once. virtual bool IsConfigured() = 0; - // Sets a desired window geometry once wayland requests client to do so. + // Sets a desired window geometry in surface local coordinates that specifies + // the content area of the surface. virtual void SetWindowGeometry(const gfx::Rect& bounds) = 0; + // Requests a desired window position and size in global screen coordinates. + // The compositor may or may not filfill the request. + virtual void RequestWindowBounds(const gfx::Rect& bounds) = 0; + // Sets the minimum size for the top level. virtual void SetMinSize(int32_t width, int32_t height) = 0; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_shm.cc b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_shm.cc index 19fbfac4222..43f7d2592ca 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_shm.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_buffer_backing_shm.cc @@ -4,6 +4,7 @@ #include "ui/ozone/platform/wayland/host/wayland_buffer_backing_shm.h" +#include "build/chromeos_buildflags.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" #include "ui/ozone/platform/wayland/host/wayland_shm.h" @@ -24,6 +25,7 @@ WaylandBufferBackingShm::~WaylandBufferBackingShm() = default; void WaylandBufferBackingShm::RequestBufferHandle( base::OnceCallback<void(wl::Object<wl_buffer>)> callback) { DCHECK(!callback.is_null()); + DCHECK(fd_.is_valid()); // Given that buffers for canvas surfaces are submitted with alpha disabled, // using a format with alpha channel results in popup surfaces that have black @@ -39,6 +41,8 @@ void WaylandBufferBackingShm::RequestBufferHandle( #endif std::move(callback).Run(connection_->shm()->CreateBuffer(fd_, length_, size(), with_alpha_channel)); + if (UseExplicitSyncRelease()) + auto close = std::move(fd_); } } // namespace ui 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 bdd437618e9..3e3dea901fd 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 @@ -256,6 +256,7 @@ WaylandBufferHandle* WaylandBufferManagerHost::GetBufferHandle( void WaylandBufferManagerHost::CommitOverlays( gfx::AcceleratedWidget widget, + uint32_t frame_id, std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlays) { DCHECK(base::CurrentUIThread::IsSet()); @@ -282,14 +283,10 @@ void WaylandBufferManagerHost::CommitOverlays( } } - window->CommitOverlays(overlays); + window->CommitOverlays(frame_id, overlays); } -void WaylandBufferManagerHost::DestroyBuffer( - [[maybe_unused]] gfx::AcceleratedWidget widget, - uint32_t buffer_id) { - // TODO(fangzhoug): Remove |widget| from the argument list of the mojo - // interface. +void WaylandBufferManagerHost::DestroyBuffer(uint32_t buffer_id) { DCHECK(base::CurrentUIThread::IsSet()); TRACE_EVENT1("wayland", "WaylandBufferManagerHost::DestroyBuffer", @@ -429,24 +426,24 @@ bool WaylandBufferManagerHost::ValidateOverlayData( } void WaylandBufferManagerHost::OnSubmission(gfx::AcceleratedWidget widget, - uint32_t buffer_id, + uint32_t frame_id, const gfx::SwapResult& swap_result, gfx::GpuFenceHandle release_fence) { DCHECK(base::CurrentUIThread::IsSet()); DCHECK(buffer_manager_gpu_associated_); - buffer_manager_gpu_associated_->OnSubmission(widget, buffer_id, swap_result, + buffer_manager_gpu_associated_->OnSubmission(widget, frame_id, swap_result, std::move(release_fence)); } void WaylandBufferManagerHost::OnPresentation( gfx::AcceleratedWidget widget, - uint32_t buffer_id, + uint32_t frame_id, const gfx::PresentationFeedback& feedback) { DCHECK(base::CurrentUIThread::IsSet()); DCHECK(buffer_manager_gpu_associated_); - buffer_manager_gpu_associated_->OnPresentation(widget, buffer_id, feedback); + buffer_manager_gpu_associated_->OnPresentation(widget, frame_id, feedback); } void WaylandBufferManagerHost::TerminateGpuProcess() { 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 e0862674f77..3e2e079f2ad 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 @@ -103,13 +103,13 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost { uint32_t buffer_id) override; // Called by the GPU to destroy the imported wl_buffer with a |buffer_id|. - void DestroyBuffer(gfx::AcceleratedWidget widget, - uint32_t buffer_id) override; + void DestroyBuffer(uint32_t buffer_id) override; // Called by the GPU and asks to configure the surface/subsurfaces and attach // wl_buffers to WaylandWindow with the specified |widget|. Calls OnSubmission // and OnPresentation on successful swap and pixels presented. void CommitOverlays( gfx::AcceleratedWidget widget, + uint32_t frame_id, std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlays) override; // Ensures a WaylandBufferHandle of |buffer_id| is created for the @@ -125,11 +125,11 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost { // Tells the |buffer_manager_gpu_ptr_| the result of a swap call and provides // it with the presentation feedback. void OnSubmission(gfx::AcceleratedWidget widget, - uint32_t buffer_id, + uint32_t frame_id, const gfx::SwapResult& swap_result, gfx::GpuFenceHandle release_fence); void OnPresentation(gfx::AcceleratedWidget widget, - uint32_t buffer_id, + uint32_t frame_id, const gfx::PresentationFeedback& feedback); private: diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc index 52a1af56d1f..b7fa2877766 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard.cc @@ -4,11 +4,13 @@ #include "ui/ozone/platform/wayland/host/wayland_clipboard.h" +#include <cstdint> #include <memory> #include <string> #include "base/bind.h" #include "base/check.h" +#include "base/logging.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "base/notreached.h" @@ -24,6 +26,7 @@ #include "ui/ozone/platform/wayland/host/wayland_data_device_manager.h" #include "ui/ozone/platform/wayland/host/wayland_data_offer_base.h" #include "ui/ozone/platform/wayland/host/wayland_data_source.h" +#include "ui/ozone/platform/wayland/host/wayland_serial_tracker.h" #include "ui/ozone/platform/wayland/host/zwp_primary_selection_device.h" #include "ui/ozone/platform/wayland/host/zwp_primary_selection_device_manager.h" #include "ui/ozone/public/platform_clipboard.h" @@ -69,8 +72,10 @@ template <typename Manager, typename DataDevice = typename Manager::DataDevice> class ClipboardImpl final : public Clipboard, public DataSource::Delegate { public: - explicit ClipboardImpl(Manager* manager, ui::ClipboardBuffer buffer) - : manager_(manager), buffer_(buffer) { + ClipboardImpl(Manager* manager, + ui::ClipboardBuffer buffer, + ui::WaylandConnection* connection) + : manager_(manager), buffer_(buffer), connection_(connection) { GetDevice()->set_selection_offer_callback(base::BindRepeating( &ClipboardImpl::HandleNewSelectionOffer, weak_factory_.GetWeakPtr())); } @@ -93,6 +98,10 @@ class ClipboardImpl final : public Clipboard, public DataSource::Delegate { // responsible for writing the clipboard contents into the supplied fd. This // client can only drop the clipboard contents when it receives a // wl_data_source::cancelled event. + // + // This is supposedly responding to an input event, i.e: there is a valid + // corresponding serial number (provided by wl::SerialTracker). Otherwise, + // this function will no-op. void Write(const ui::PlatformClipboard::DataMap* data) final { if (!data || data->empty()) { offered_data_.clear(); @@ -102,7 +111,21 @@ class ClipboardImpl final : public Clipboard, public DataSource::Delegate { source_ = manager_->CreateSource(this); source_->Offer(GetOfferedMimeTypes()); } - GetDevice()->SetSelectionSource(source_.get()); + + // TODO(nickdiego): This function should just no-op if no serial is found + // (ie: no recent input event has been processed yet), though several unit + // and browser tests do not satisfy this precondition so would fail [1]. + // Revisit this once those tests are fixed. + // + // [1] https://chromium-review.googlesource.com/c/chromium/src/+/3527605/2 + auto& serial_tracker = connection_->serial_tracker(); + auto serial = serial_tracker.GetSerial({wl::SerialType::kTouchPress, + wl::SerialType::kMousePress, + wl::SerialType::kKeyPress}); + if (serial.has_value()) + GetDevice()->SetSelectionSource(source_.get(), serial->value); + else + LOG(WARNING) << "No serial found for selection."; if (!clipboard_changed_callback_.is_null()) clipboard_changed_callback_.Run(buffer_); @@ -180,6 +203,8 @@ class ClipboardImpl final : public Clipboard, public DataSource::Delegate { // Notifies when clipboard data changes. Can be empty if not set. ClipboardDataChangedCallback clipboard_changed_callback_; + ui::WaylandConnection* const connection_; + base::WeakPtrFactory<ClipboardImpl> weak_factory_{this}; }; @@ -193,7 +218,8 @@ WaylandClipboard::WaylandClipboard(WaylandConnection* connection, copypaste_clipboard_( std::make_unique<wl::ClipboardImpl<WaylandDataDeviceManager>>( manager, - ClipboardBuffer::kCopyPaste)) { + ClipboardBuffer::kCopyPaste, + connection)) { DCHECK(manager); DCHECK(connection_); DCHECK(copypaste_clipboard_); @@ -257,7 +283,7 @@ wl::Clipboard* WaylandClipboard::GetClipboard(ClipboardBuffer buffer) { if (!primary_selection_clipboard_) { primary_selection_clipboard_ = std::make_unique< wl::ClipboardImpl<ZwpPrimarySelectionDeviceManager>>( - zwp_manager, ClipboardBuffer::kSelection); + zwp_manager, ClipboardBuffer::kSelection, connection_); } return primary_selection_clipboard_.get(); } @@ -266,7 +292,7 @@ wl::Clipboard* WaylandClipboard::GetClipboard(ClipboardBuffer buffer) { if (!primary_selection_clipboard_) { primary_selection_clipboard_ = std::make_unique< wl::ClipboardImpl<GtkPrimarySelectionDeviceManager>>( - gtk_manager, ClipboardBuffer::kSelection); + gtk_manager, ClipboardBuffer::kSelection, connection_); } return primary_selection_clipboard_.get(); } diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard_unittest.cc index 40be06ab34b..2b7955dc7b1 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_clipboard_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_clipboard_unittest.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <linux/input.h> #include <wayland-server.h> #include <cstring> @@ -10,6 +11,7 @@ #include <vector> #include "base/bind.h" +#include "base/callback_forward.h" #include "base/containers/flat_set.h" #include "base/location.h" #include "base/run_loop.h" @@ -22,14 +24,19 @@ #include "ui/base/clipboard/clipboard_buffer.h" #include "ui/base/clipboard/clipboard_constants.h" #include "ui/events/base_event_utils.h" +#include "ui/gfx/geometry/point.h" #include "ui/ozone/platform/wayland/host/wayland_clipboard.h" #include "ui/ozone/platform/wayland/host/wayland_connection_test_api.h" +#include "ui/ozone/platform/wayland/host/wayland_serial_tracker.h" +#include "ui/ozone/platform/wayland/test/mock_pointer.h" #include "ui/ozone/platform/wayland/test/mock_surface.h" #include "ui/ozone/platform/wayland/test/test_data_device.h" #include "ui/ozone/platform/wayland/test/test_data_device_manager.h" #include "ui/ozone/platform/wayland/test/test_data_offer.h" #include "ui/ozone/platform/wayland/test/test_data_source.h" +#include "ui/ozone/platform/wayland/test/test_keyboard.h" #include "ui/ozone/platform/wayland/test/test_selection_device_manager.h" +#include "ui/ozone/platform/wayland/test/test_touch.h" #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h" #include "ui/ozone/platform/wayland/test/wayland_test.h" #include "ui/ozone/public/platform_clipboard.h" @@ -61,6 +68,21 @@ class WaylandClipboardTestBase : public WaylandTest { void SetUp() override { WaylandTest::SetUp(); + wl_seat_send_capabilities(server_.seat()->resource(), + WL_SEAT_CAPABILITY_POINTER | + WL_SEAT_CAPABILITY_TOUCH | + WL_SEAT_CAPABILITY_KEYBOARD); + Sync(); + + pointer_ = server_.seat()->pointer(); + ASSERT_TRUE(pointer_); + + touch_ = server_.seat()->touch(); + ASSERT_TRUE(touch_); + + keyboard_ = server_.seat()->keyboard(); + ASSERT_TRUE(keyboard_); + // As of now, WaylandClipboard::RequestClipboardData is implemented in a // blocking way, which requires a roundtrip before attempting the data // from the selection fd. As Wayland events polling is single-threaded for @@ -94,7 +116,43 @@ class WaylandClipboardTestBase : public WaylandTest { base::RunLoop().RunUntilIdle(); } + void SentPointerButtonPress(const gfx::Point& location) { + wl_pointer_send_enter(pointer_->resource(), ++serial_, surface_->resource(), + location.x(), location.y()); + wl_pointer_send_button(pointer_->resource(), ++serial_, ++timestamp_, + BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED); + } + void SendTouchDown(const gfx::Point& location) { + wl_touch_send_down(touch_->resource(), ++serial_, ++timestamp_, + surface_->resource(), /*touch_id=*/0, + wl_fixed_from_int(location.x()), + wl_fixed_from_int(location.y())); + } + + void SendTouchUp() { + wl_touch_send_up(touch_->resource(), ++serial_, ++timestamp_, + /*touch_id=*/0); + } + + void SendKeyboardKey() { + struct wl_array empty; + wl_array_init(&empty); + wl_keyboard_send_enter(keyboard_->resource(), 1, surface_->resource(), + &empty); + wl_array_release(&empty); + wl_keyboard_send_key(keyboard_->resource(), 2, 0, 30 /* a */, + WL_KEYBOARD_KEY_STATE_PRESSED); + } + + /* Server objects */ + wl::MockPointer* pointer_; + wl::TestTouch* touch_; + wl::TestKeyboard* keyboard_; + WaylandClipboard* clipboard_ = nullptr; + + uint32_t serial_ = 0; + uint32_t timestamp_ = 0; }; class WaylandClipboardTest : public WaylandClipboardTestBase { @@ -145,6 +203,15 @@ class WaylandClipboardTest : public WaylandClipboardTestBase { : ClipboardBuffer::kCopyPaste; } + void ResetServerSelectionSource() { + if (GetParam().primary_selection_protocol != + wl::PrimarySelectionProtocol::kNone) { + server_.primary_selection_device_manager()->set_source(nullptr); + } else { + server_.data_device_manager()->set_data_source(nullptr); + } + } + // Fill the clipboard backing store with sample data. void OfferData(ClipboardBuffer buffer, const char* data, @@ -174,22 +241,66 @@ class CopyPasteOnlyClipboardTest : public WaylandClipboardTestBase { } }; +// Verifies that copy-to-clipboard works as expected. Actual Wayland input +// events are used in order to exercise all the components involved, e.g: +// Wayland{Pointer,Keyboard,Touch}, Serial tracker and WaylandClipboard. +// +// Regression test for https://crbug.com/1282220. TEST_P(WaylandClipboardTest, WriteToClipboard) { - // 1. Offer sample text as selection data. - OfferData(GetBuffer(), kSampleClipboardText, {kMimeTypeTextUtf8}); - Sync(); - - // 2. Emulate an external client requesting to read the offered data and make - // sure the appropriate string gets delivered. - std::string delivered_text; - base::MockCallback<wl::TestSelectionSource::ReadDataCallback> callback; - EXPECT_CALL(callback, Run(_)).WillOnce([&](std::vector<uint8_t>&& data) { - delivered_text = std::string(data.begin(), data.end()); - }); - GetServerSelectionSource()->ReadData(kMimeTypeTextUtf8, callback.Get()); + const base::RepeatingClosure send_input_event_closures[]{ + // Mouse button press + base::BindLambdaForTesting([&]() { + SentPointerButtonPress({10, 10}); + }), + // Key press + base::BindLambdaForTesting([&]() { SendKeyboardKey(); }), + // Touch down + base::BindLambdaForTesting([&]() { + SendTouchDown({200, 200}); + }), + // Touch tap (down > up) + base::BindLambdaForTesting([&]() { + SendTouchDown({300, 300}); + SendTouchUp(); + })}; + + auto* window_manager = connection_->wayland_window_manager(); + + // Triggering copy on touch-down event. + for (auto send_input_event : send_input_event_closures) { + ResetServerSelectionSource(); + + send_input_event.Run(); + Sync(); + auto client_selection_serial = connection_->serial_tracker().GetSerial( + {wl::SerialType::kTouchPress, wl::SerialType::kMousePress, + wl::SerialType::kKeyPress}); + ASSERT_TRUE(client_selection_serial.has_value()); - WaitForClipboardTasks(); - ASSERT_EQ(kSampleClipboardText, delivered_text); + // 1. Offer sample text as selection data. + OfferData(GetBuffer(), kSampleClipboardText, {kMimeTypeTextUtf8}); + Sync(); + ASSERT_TRUE(GetServerSelectionSource()); + + EXPECT_EQ(client_selection_serial->value, + GetServerSelectionDevice()->selection_serial()); + + // 2. Emulate an external client requesting to read the offered data and + // make sure the appropriate string gets delivered. + std::string delivered_text; + base::MockCallback<wl::TestSelectionSource::ReadDataCallback> callback; + EXPECT_CALL(callback, Run(_)).WillOnce([&](std::vector<uint8_t>&& data) { + delivered_text = std::string(data.begin(), data.end()); + }); + GetServerSelectionSource()->ReadData(kMimeTypeTextUtf8, callback.Get()); + + WaitForClipboardTasks(); + ASSERT_EQ(kSampleClipboardText, delivered_text); + + window_manager->SetPointerFocusedWindow(nullptr); + window_manager->SetTouchFocusedWindow(nullptr); + window_manager->SetKeyboardFocusedWindow(nullptr); + } } TEST_P(WaylandClipboardTest, ReadFromClipboard) { @@ -251,8 +362,11 @@ TEST_P(WaylandClipboardTest, ReadFromClipboardWithoutOffer) { } TEST_P(WaylandClipboardTest, IsSelectionOwner) { + connection_->serial_tracker().UpdateSerial(wl::SerialType::kMousePress, 1); + OfferData(GetBuffer(), kSampleClipboardText, {kMimeTypeTextUtf8}); Sync(); + ASSERT_TRUE(GetServerSelectionSource()); ASSERT_TRUE(clipboard_->IsSelectionOwner(GetBuffer())); // The compositor sends OnCancelled whenever another application on the system @@ -262,6 +376,7 @@ TEST_P(WaylandClipboardTest, IsSelectionOwner) { Sync(); ASSERT_FALSE(clipboard_->IsSelectionOwner(GetBuffer())); + connection_->serial_tracker().ResetSerial(wl::SerialType::kMousePress); } // Ensures WaylandClipboard correctly handles overlapping read requests for @@ -320,10 +435,13 @@ TEST_P(WaylandClipboardTest, ClipboardChangeNotifications) { EXPECT_FALSE(clipboard_->IsSelectionOwner(buffer)); // 2. For selection offered by Chromium. + connection_->serial_tracker().UpdateSerial(wl::SerialType::kMousePress, 1); EXPECT_CALL(clipboard_changed_callback, Run(buffer)).Times(1); OfferData(buffer, kSampleClipboardText, {kMimeTypeTextUtf8}); Sync(); + ASSERT_TRUE(GetServerSelectionSource()); EXPECT_TRUE(clipboard_->IsSelectionOwner(buffer)); + connection_->serial_tracker().ResetSerial(wl::SerialType::kMousePress); } // Verifies clipboard calls targeting primary selection buffer no-op and run diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_connection_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_connection_unittest.cc index 6ef944f632f..d67b664a994 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_connection_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_connection_unittest.cc @@ -20,7 +20,9 @@ TEST(WaylandConnectionTest, Ping) { base::test::SingleThreadTaskEnvironment task_environment( base::test::SingleThreadTaskEnvironment::MainThreadType::UI); wl::TestWaylandServerThread server; - ASSERT_TRUE(server.Start({.shell_version = wl::ShellVersion::kStable})); + constexpr uint32_t expected_compositor_version = 4; + ASSERT_TRUE(server.Start({.shell_version = wl::ShellVersion::kStable, + .compositor_version = wl::CompositorVersion::kV4})); WaylandConnection connection; ASSERT_TRUE(connection.Initialize()); connection.event_source()->StartProcessingEvents(); @@ -28,7 +30,7 @@ TEST(WaylandConnectionTest, Ping) { base::RunLoop().RunUntilIdle(); server.Pause(); - EXPECT_EQ(wl::TestCompositor::kVersion, + EXPECT_EQ(expected_compositor_version, wl::get_version_of_object(connection.compositor())); xdg_wm_base_send_ping(server.xdg_shell()->resource(), 1234); diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.cc b/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.cc index d9895e42592..d72ff37b737 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor_factory.cc @@ -6,7 +6,6 @@ #include <wayland-cursor.h> -#include "base/task/post_task.h" #include "base/task/task_runner_util.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_cursor_position.h b/chromium/ui/ozone/platform/wayland/host/wayland_cursor_position.h index f10bed74d7f..3bc75a27304 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_cursor_position.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_cursor_position.h @@ -9,8 +9,8 @@ namespace ui { -// Stores last known cursor pointer position in regards to top-level windows' -// coordinates and returns it on request. +// Stores last known cursor pointer position relative to 0,0 origin +// and returns it on request. class WaylandCursorPosition { public: WaylandCursorPosition(); @@ -22,8 +22,8 @@ class WaylandCursorPosition { void OnCursorPositionChanged(const gfx::Point& cursor_position); - // Returns last known cursor position in regards to top-level surface local - // coordinates. It is unknown what surface receives that cursor position. + // Returns last known cursor position relative to 0,0 origin. + // It is unknown what surface receives that cursor position. gfx::Point GetCursorSurfacePoint() const; private: 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 65c218342f2..6e798918525 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.cc @@ -73,14 +73,10 @@ void WaylandDataDevice::RequestData(WaylandDataOffer* offer, RegisterDeferredReadCallback(); } -void WaylandDataDevice::SetSelectionSource(WaylandDataSource* source) { - auto serial = GetSerialForSelection(); - if (!serial.has_value()) { - LOG(ERROR) << "Failed to set selection. No serial found."; - return; - } +void WaylandDataDevice::SetSelectionSource(WaylandDataSource* source, + uint32_t serial) { auto* data_source = source ? source->data_source() : nullptr; - wl_data_device_set_selection(data_device_.get(), data_source, serial->value); + wl_data_device_set_selection(data_device_.get(), data_source, serial); connection()->ScheduleFlush(); } @@ -92,6 +88,14 @@ void WaylandDataDevice::ReadDragDataFromFD(base::ScopedFD fd, base::RefCountedBytes::TakeVector(&contents))); } +void WaylandDataDevice::ResetDragDelegateIfNeeded() { + // When in an active drag-and-drop session initiated by an external Wayland + // client, |drag_delegate_| is set at OnEnter, and must be reset upon + // OnLeave/OnDrop in order to avoid potential memory corruption issues. + if (drag_delegate_ && !drag_delegate_->IsDragSource()) + ResetDragDelegate(); +} + // static void WaylandDataDevice::OnOffer(void* data, wl_data_device* data_device, @@ -155,6 +159,15 @@ void WaylandDataDevice::OnDrop(void* data, wl_data_device* data_device) { self->drag_delegate_->OnDragDrop(); self->connection()->ScheduleFlush(); } + + // There are buggy Exo versions, which send 'drop' event (even for + // unsuccessful drops) without a subsequent 'leave'. In order to mitigate + // potential leaks and/or UAFs, forcibly call corresponding delegate callback + // here, in Lacros. TODO(crbug.com/1293415): Remove once Exo bug is fixed. +#if BUILDFLAG(IS_CHROMEOS_LACROS) + self->drag_delegate_->OnDragLeave(); + self->ResetDragDelegateIfNeeded(); +#endif } void WaylandDataDevice::OnLeave(void* data, wl_data_device* data_device) { @@ -163,15 +176,7 @@ void WaylandDataDevice::OnLeave(void* data, wl_data_device* data_device) { self->drag_delegate_->OnDragLeave(); self->connection()->ScheduleFlush(); } - - // When in a DND session initiated by an external application, - // |drag_delegate_| is set at OnEnter, and must be reset here to avoid - // potential use-after-free. - // - // NOTE: Above call to OnDragLeave() may result in |drag_delegate_| being - // reset, so it must be checked here as well. - if (self->drag_delegate_ && !self->drag_delegate_->IsDragSource()) - self->ResetDragDelegate(); + self->ResetDragDelegateIfNeeded(); } void WaylandDataDevice::OnSelection(void* data, 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 218dd06b33b..9c0328ae994 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device.h @@ -77,19 +77,16 @@ class WaylandDataDevice : public WaylandDataDeviceBase { // wl_data_device::set_selection makes the corresponding wl_data_source the // target of future wl_data_device::data_offer events. In non-Wayland terms, - // this is equivalent to "writing" to the clipboard or DnD, although the - // actual transfer of data happens asynchronously, on-demand-only. - // - // The API relies on the assumption that the Wayland client is responding to a - // keyboard or mouse event with a serial number. This is cached in - // WaylandConnection. However, this may not exist or be set properly in tests, - // resulting in the Wayland server ignoring the set_selection() request. - void SetSelectionSource(WaylandDataSource* source); + // this is equivalent to "writing" to the clipboard, although the actual + // transfer of data happens asynchronously, on-demand-only. + void SetSelectionSource(WaylandDataSource* source, uint32_t serial); private: FRIEND_TEST_ALL_PREFIXES(WaylandDataDragControllerTest, StartDrag); + FRIEND_TEST_ALL_PREFIXES(WaylandDataDragControllerTest, ReceiveDrag); void ReadDragDataFromFD(base::ScopedFD fd, RequestDataCallback callback); + void ResetDragDelegateIfNeeded(); // wl_data_device_listener callbacks static void OnOffer(void* data, diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.cc index 43044c510e5..95965e5bc78 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.cc @@ -14,7 +14,6 @@ #include "ui/ozone/platform/wayland/host/wayland_connection.h" #include "ui/ozone/platform/wayland/host/wayland_data_offer_base.h" #include "ui/ozone/platform/wayland/host/wayland_serial_tracker.h" -#include "wayland-client-core.h" namespace ui { @@ -109,11 +108,4 @@ void WaylandDataDeviceBase::NotifySelectionOffer( selection_offer_callback_.Run(offer); } -absl::optional<wl::Serial> WaylandDataDeviceBase::GetSerialForSelection() - const { - return connection_->serial_tracker().GetSerial({wl::SerialType::kTouchPress, - wl::SerialType::kMousePress, - wl::SerialType::kKeyPress}); -} - } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.h b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.h index 99c74499169..eac004dc7c8 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_device_base.h @@ -8,17 +8,11 @@ #include <string> #include "base/callback.h" -#include "base/callback_forward.h" #include "base/files/scoped_file.h" -#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/host/wayland_data_offer_base.h" #include "ui/ozone/public/platform_clipboard.h" -namespace wl { -struct Serial; -} - namespace ui { class WaylandConnection; @@ -72,8 +66,6 @@ class WaylandDataDeviceBase { void NotifySelectionOffer(WaylandDataOfferBase* offer) const; - absl::optional<wl::Serial> GetSerialForSelection() const; - private: // wl_callback_listener callback static void DeferredReadCallback(void* data, diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc index 04f35c33ba9..d972fe438e4 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc @@ -188,22 +188,45 @@ bool WaylandDataDragController::IsDragSource() const { } void WaylandDataDragController::DrawIcon() { - if (!icon_bitmap_) + if (!icon_surface_ || !icon_bitmap_) + return; + + static const wl_callback_listener kFrameListener{ + .done = WaylandDataDragController::OnDragSurfaceFrame}; + + wl_surface* const surface = icon_surface_->surface(); + icon_frame_callback_.reset(wl_surface_frame(surface)); + wl_callback_add_listener(icon_frame_callback_.get(), &kFrameListener, this); + wl_surface_commit(surface); +} + +void WaylandDataDragController::OnDragSurfaceFrame(void* data, + struct wl_callback* callback, + uint32_t time) { + auto* self = static_cast<WaylandDataDragController*>(data); + DCHECK(self); + self->DrawIconInternal(); + self->icon_frame_callback_.reset(); + self->connection_->ScheduleFlush(); +} + +void WaylandDataDragController::DrawIconInternal() { + if (!icon_surface_ || !icon_bitmap_) return; DCHECK(!icon_bitmap_->empty()); gfx::Size size(icon_bitmap_->width(), icon_bitmap_->height()); - if (!shm_buffer_ || shm_buffer_->size() != size) { - shm_buffer_ = std::make_unique<WaylandShmBuffer>(connection_->shm(), size); - if (!shm_buffer_->IsValid()) { - LOG(ERROR) << "Failed to create drag icon buffer."; - return; - } + icon_buffer_ = std::make_unique<WaylandShmBuffer>(connection_->shm(), size); + if (!icon_buffer_->IsValid()) { + LOG(ERROR) << "Failed to create drag icon buffer."; + return; } - wl::DrawBitmap(*icon_bitmap_, shm_buffer_.get()); + + DVLOG(3) << "Drawing drag icon. size=" << size.ToString(); + wl::DrawBitmap(*icon_bitmap_, icon_buffer_.get()); auto* const surface = icon_surface_->surface(); - wl_surface_attach(surface, shm_buffer_->get(), icon_offset_.x(), + wl_surface_attach(surface, icon_buffer_->get(), icon_offset_.x(), icon_offset_.y()); wl_surface_damage(surface, 0, 0, size.width(), size.height()); wl_surface_commit(surface); @@ -332,6 +355,8 @@ void WaylandDataDragController::OnDataSourceFinish(bool completed) { window_manager_->RemoveObserver(this); data_source_.reset(); data_offer_.reset(); + icon_buffer_.reset(); + icon_frame_callback_.reset(); offered_exchange_data_provider_.reset(); data_device_->ResetDragDelegate(); state_ = State::kIdle; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h index df0cdbd952a..f8f8266eae2 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h @@ -171,6 +171,11 @@ class WaylandDataDragController : public WaylandDataDevice::DragDelegate, bool CanDispatchEvent(const PlatformEvent& event) override; uint32_t DispatchEvent(const PlatformEvent& event) override; + void DrawIconInternal(); + static void OnDragSurfaceFrame(void* data, + struct wl_callback* callback, + uint32_t time); + WaylandConnection* const connection_; WaylandDataDeviceManager* const data_device_manager_; WaylandDataDevice* const data_device_; @@ -217,9 +222,10 @@ class WaylandDataDragController : public WaylandDataDevice::DragDelegate, // Drag icon related variables. std::unique_ptr<WaylandSurface> icon_surface_; - std::unique_ptr<WaylandShmBuffer> shm_buffer_; + std::unique_ptr<WaylandShmBuffer> icon_buffer_; const SkBitmap* icon_bitmap_ = nullptr; gfx::Point icon_offset_; + wl::Object<wl_callback> icon_frame_callback_; // Keeps track of the window that holds the pointer grab, i.e. the window that // will receive the mouse release event from DispatchPointerRelease(). diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc index d759b57bfbe..f94209e8726 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc @@ -50,6 +50,7 @@ #include "url/gurl.h" using ::testing::_; +using ::testing::AtMost; using ::testing::Eq; using ::testing::Mock; using ::testing::Values; @@ -440,6 +441,7 @@ TEST_P(WaylandDataDragControllerTest, ReceiveDrag) { wl_fixed_from_int(entered_point.y()), data_offer); Sync(); + ASSERT_EQ(drag_controller(), data_device()->drag_delegate_); // In 2x window scale, we expect received coordinates to be multiplied. EXPECT_CALL(*drop_handler_, @@ -463,6 +465,8 @@ TEST_P(WaylandDataDragControllerTest, ReceiveDrag) { Sync(); data_device_manager_->data_device()->OnLeave(); + Sync(); + ASSERT_FALSE(data_device()->drag_delegate_); } TEST_P(WaylandDataDragControllerTest, ReceiveDragPixelSurface) { @@ -605,7 +609,7 @@ TEST_P(WaylandDataDragControllerTest, ValidateDroppedUriList) { EXPECT_EQ(kCase.expected_uris.count(filename.path.AsUTF8Unsafe()), 1U); } - EXPECT_CALL(*drop_handler_, OnDragLeave()).Times(1); + EXPECT_CALL(*drop_handler_, OnDragLeave()).Times(AtMost(1)); data_device_manager_->data_device()->OnLeave(); Sync(); Mock::VerifyAndClearExpectations(drop_handler_.get()); @@ -661,7 +665,7 @@ TEST_P(WaylandDataDragControllerTest, ValidateDroppedXMozUrl) { EXPECT_EQ(title, kCase.expected_title); } - EXPECT_CALL(*drop_handler_, OnDragLeave()).Times(1); + EXPECT_CALL(*drop_handler_, OnDragLeave()).Times(AtMost(1)); data_device_manager_->data_device()->OnLeave(); Sync(); Mock::VerifyAndClearExpectations(drop_handler_.get()); diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc index 0b2bd19561f..74bc3db6435 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_source.cc @@ -373,6 +373,19 @@ void WaylandEventSource::OnTouchReleaseEvent(base::TimeTicks timestamp, keyboard_modifiers_); DispatchEvent(&event); + // It is possible that an user interaction triggers nested loops + // in higher levels of the application stack in order to process a + // given touch down/up action. + // For instance, a modal dialog might block this execution point, + // and trigger thread to continue to process events. + // The auxiliary flow might clear entries in touch_points_. + // + // Hence, we check whether the TouchId is still being held. + if (touch_points_.find(id) == touch_points_.end()) { + LOG(WARNING) << "Touch has been released during processing."; + return; + } + HandleTouchFocusChange(touch_point->window, false, id); touch_points_.erase(it); } diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc b/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc index 9405055f6d0..ec764c34b44 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher.cc @@ -10,11 +10,22 @@ #include "base/logging.h" #include "base/strings/stringprintf.h" #include "components/crash/core/common/crash_key.h" +#include "third_party/re2/src/re2/re2.h" namespace ui { namespace { +// Formats the |message| by removing '@' char followed by any digits until the +// next char. Also removes new line, tab and carriage-return. +void FormatErrorMessage(std::string* message) { + const re2::RE2 kInvalidChars[] = {"\n", "\r", "\t", "[@]+[0-9]+"}; + if (message) { + for (const auto& pattern : kInvalidChars) + re2::RE2::Replace(message, pattern, ""); + } +} + // Wayland error log that will be stored if the client (Chromium) is // disconnected due to a protocol error. static std::string* g_error_log = nullptr; @@ -23,6 +34,9 @@ void wayland_log(const char* fmt, va_list argp) { DCHECK(!g_error_log); g_error_log = new std::string(base::StringPrintV(fmt, argp)); LOG(ERROR) << "libwayland: " << *g_error_log; + // Format the error message only after it's printed. Otherwise, object id will + // be lost and local development and debugging will be harder to do. + FormatErrorMessage(g_error_log); } std::string GetWaylandProtocolError(int err, wl_display* display) { @@ -36,17 +50,18 @@ std::string GetWaylandProtocolError(int err, wl_display* display) { "Fatal Wayland protocol error %u on interface %s (object %u). " "Shutting down..", ec, intf->name, id); - LOG(ERROR) << error_string; } else { error_string = base::StringPrintf( "Fatal Wayland protocol error %u. Shutting down..", ec); - LOG(ERROR) << error_string; } } else { - error_string = base::StringPrintf("Fatal Wayland communication error %s.", + error_string = base::StringPrintf("Fatal Wayland communication error: %s.", std::strerror(err)); - LOG(ERROR) << error_string; } + LOG(ERROR) << error_string; + // Format the error message only after it's printed. Otherwise, object id will + // be lost and local development and debugging will be harder to do. + FormatErrorMessage(&error_string); return error_string; } @@ -171,8 +186,9 @@ void WaylandEventWatcher::WlDisplayCheckForErrors() { // This can be null in tests. if (!shutdown_cb_.is_null()) { - // Force a crash so that a crash report is generated. - CHECK(false) << "Wayland protocol error."; + // If Wayland compositor died, it'll be shutdown gracefully. In all the + // other cases, force a crash so that a crash report is generated. + CHECK(err == EPIPE || err == ECONNRESET) << "Wayland protocol error."; std::move(shutdown_cb_).Run(); } StopProcessingEvents(); diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher_unittest.cc index 809e92b0d25..0c9f0c295c8 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_event_watcher_unittest.cc @@ -38,12 +38,11 @@ TEST_P(WaylandEventWatcherTest, CrashKeyResourceError) { auto* xdg_surface = mock_surface->xdg_surface(); // Prepare the expectation error string. - const std::string expected_error_code = base::StrCat( - {wl_resource_get_class(xdg_surface->resource()), "@", - NumberToString(wl_resource_get_id(xdg_surface->resource())), ": error ", - NumberToString( - static_cast<uint32_t>(XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER)), - ": ", kTestErrorString, "\n"}); + const std::string expected_error_code = + base::StrCat({wl_resource_get_class(xdg_surface->resource()), ": error ", + NumberToString(static_cast<uint32_t>( + XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER)), + ": ", kTestErrorString}); wl_resource_post_error(xdg_surface->resource(), XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER, "%s", @@ -62,9 +61,9 @@ TEST_P(WaylandEventWatcherTest, CrashKeyResourceNoMemory) { // Prepare the expectation error string. const std::string expected_error_code = base::StrCat( - {"wl_display@1: error ", + {"wl_display: error ", NumberToString(static_cast<uint32_t>(WL_DISPLAY_ERROR_NO_MEMORY)), - ": no memory\n"}); + ": no memory"}); wl_resource_post_no_memory(xdg_surface->resource()); @@ -76,9 +75,9 @@ TEST_P(WaylandEventWatcherTest, CrashKeyResourceNoMemory) { TEST_P(WaylandEventWatcherTest, CrashKeyClientNoMemoryError) { const std::string expected_error_code = base::StrCat( - {"wl_display@1: error ", + {"wl_display: error ", NumberToString(static_cast<uint32_t>(WL_DISPLAY_ERROR_NO_MEMORY)), - ": no memory\n"}); + ": no memory"}); wl_client_post_no_memory(server_.client()); @@ -91,9 +90,9 @@ TEST_P(WaylandEventWatcherTest, CrashKeyClientNoMemoryError) { TEST_P(WaylandEventWatcherTest, CrashKeyClientImplementationError) { const std::string kError = "A nice error."; const std::string expected_error_code = base::StrCat( - {"wl_display@1: error ", + {"wl_display: error ", NumberToString(static_cast<uint32_t>(WL_DISPLAY_ERROR_IMPLEMENTATION)), - ": ", kError, "\n"}); + ": ", kError}); wl_client_post_implementation_error(server_.client(), "%s", kError.c_str()); diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_exchange_data_provider_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_exchange_data_provider_unittest.cc index ddf5a365600..a852290685e 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_exchange_data_provider_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_exchange_data_provider_unittest.cc @@ -14,7 +14,7 @@ #include "ui/base/clipboard/clipboard_constants.h" #include "ui/base/clipboard/clipboard_format_type.h" #include "ui/base/data_transfer_policy/data_transfer_endpoint.h" -#include "url/origin.h" +#include "url/gurl.h" namespace ui { @@ -66,9 +66,9 @@ TEST(WaylandExchangeDataProviderTest, ExtractPickledData) { #if BUILDFLAG(IS_CHROMEOS_LACROS) TEST(WaylandExchangeDataProviderTest, AddAndExtractDataTransferEndpoint) { std::string kExpectedEncodedDte = - R"({"endpoint_type":"url","url_origin":"https://www.google.com"})"; - const DataTransferEndpoint expected_dte = ui::DataTransferEndpoint( - url::Origin::Create(GURL("https://www.google.com"))); + R"({"endpoint_type":"url","url":"https://www.google.com/","url_origin":"https://www.google.com"})"; + const DataTransferEndpoint expected_dte = + ui::DataTransferEndpoint(GURL("https://www.google.com")); WaylandExchangeDataProvider provider; std::string extracted; @@ -80,8 +80,7 @@ TEST(WaylandExchangeDataProviderTest, AddAndExtractDataTransferEndpoint) { provider.AddData(ToClipboardData(kExpectedEncodedDte), kMimeTypeDataTransferEndpoint); DataTransferEndpoint* actual_dte = provider.GetSource(); - EXPECT_TRUE( - expected_dte.GetOrigin()->IsSameOriginWith(*actual_dte->GetOrigin())); + EXPECT_TRUE(expected_dte.IsSameURLWith(*actual_dte)); std::vector<std::string> mime_types = provider.BuildMimeTypesList(); EXPECT_THAT(mime_types, ::testing::Contains(kMimeTypeDataTransferEndpoint)); diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_frame_manager.cc b/chromium/ui/ozone/platform/wayland/host/wayland_frame_manager.cc index 4cdeebdd8d6..f429cc59927 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_frame_manager.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_frame_manager.cc @@ -7,6 +7,7 @@ #include <presentation-time-client-protocol.h> #include <sync/sync.h> +#include "base/containers/adapters.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/size_conversions.h" #include "ui/ozone/platform/wayland/host/wayland_buffer_handle.h" @@ -40,18 +41,30 @@ uint32_t GetPresentationKindFlags(uint32_t flags) { } // namespace WaylandFrame::WaylandFrame( + uint32_t frame_id, WaylandSurface* root_surface, ui::ozone::mojom::WaylandOverlayConfigPtr root_config, base::circular_deque<std::pair<WaylandSubsurface*, ui::ozone::mojom::WaylandOverlayConfigPtr>> - subsurfaces_to_overlays, - bool expects_ack) + subsurfaces_to_overlays) + : frame_id(frame_id), + root_surface(root_surface), + root_config(std::move(root_config)), + subsurfaces_to_overlays(std::move(subsurfaces_to_overlays)), + submission_acked(false), + presentation_acked(false) {} + +WaylandFrame::WaylandFrame( + WaylandSurface* root_surface, + ui::ozone::mojom::WaylandOverlayConfigPtr root_config, + base::circular_deque<std::pair<WaylandSubsurface*, + ui::ozone::mojom::WaylandOverlayConfigPtr>> + subsurfaces_to_overlays) : root_surface(root_surface), root_config(std::move(root_config)), subsurfaces_to_overlays(std::move(subsurfaces_to_overlays)), - buffer_id(this->root_config ? this->root_config->buffer_id : 0), - submission_acked(!expects_ack), - presentation_acked(!expects_ack) {} + submission_acked(true), + presentation_acked(true) {} WaylandFrame::~WaylandFrame() = default; @@ -106,7 +119,6 @@ void WaylandFrameManager::MaybeProcessPendingFrame() { subsurface_to_overlay.second->buffer_id); // Buffer is gone while this frame is pending, remove this config. if (!handle) { - frame->buffer_id = subsurface_to_overlay.second->buffer_id; frame->buffer_lost = true; subsurface_to_overlay.second.reset(); } else if (!handle->wl_buffer() && !handle_pending_creation) { @@ -120,7 +132,6 @@ void WaylandFrameManager::MaybeProcessPendingFrame() { auto* handle = connection_->buffer_manager_host()->EnsureBufferHandle( frame->root_surface, frame->root_config->buffer_id); if (!handle) { - frame->buffer_id = frame->root_config->buffer_id; frame->buffer_lost = true; frame->root_config.reset(); } else if (!handle->wl_buffer() && !handle_pending_creation) { @@ -180,13 +191,11 @@ void WaylandFrameManager::PlayBackFrame(std::unique_ptr<WaylandFrame> frame) { // Configure subsurfaces. Traverse the deque backwards s.t. we can set // frame_callback and presentation_feedback on the top-most possible surface. - WaylandSurface* reference_above = nullptr; - for (auto r_iter = frame->subsurfaces_to_overlays.rbegin(); - r_iter != frame->subsurfaces_to_overlays.rend(); ++r_iter) { - auto* subsurface = r_iter->first; + WaylandSubsurface* reference_above = nullptr; + for (auto& [subsurface, config] : + base::Reversed(frame->subsurfaces_to_overlays)) { DCHECK(subsurface); auto* surface = subsurface->wayland_surface(); - auto& config = r_iter->second; if (empty_frame || config.is_null() || wl_fixed_from_double(config->opacity) == 0) { subsurface->Hide(); @@ -203,11 +212,12 @@ void WaylandFrameManager::PlayBackFrame(std::unique_ptr<WaylandFrame> frame) { } } } else { + subsurface->Show(); subsurface->ConfigureAndShowSurface( config->bounds_rect, root_config->bounds_rect, root_config->surface_scale_factor, nullptr, reference_above); ApplySurfaceConfigure(frame.get(), surface, config, true); - reference_above = surface; + reference_above = subsurface; surface->Commit(false); } } @@ -286,7 +296,6 @@ void WaylandFrameManager::ApplySurfaceConfigure( // new wl_buffer, which leads to graphics freeze. So only setup // frame_callback when we're attaching a different buffer. if (!frame->wl_frame_callback) { - frame->buffer_id = config->buffer_id; frame->wl_frame_callback.reset(wl_surface_frame(surface->surface())); wl_callback_add_listener(frame->wl_frame_callback.get(), &frame_listener, this); @@ -433,10 +442,9 @@ void WaylandFrameManager::VerifyNumberOfSubmittedFrames() { } } -void WaylandFrameManager::OnExplicitBufferRelease( - WaylandSurface* surface, - struct wl_buffer* wl_buffer, - absl::optional<int32_t> fence) { +void WaylandFrameManager::OnExplicitBufferRelease(WaylandSurface* surface, + struct wl_buffer* wl_buffer, + base::ScopedFD fence) { DCHECK(wl_buffer); // Releases may not necessarily come in order, so search the submitted @@ -449,14 +457,12 @@ void WaylandFrameManager::OnExplicitBufferRelease( // linux_explicit_synchronization is used. result->second->OnExplicitRelease(); - if (fence.has_value()) { - base::ScopedFD fd{fence.value()}; - // Accumulate release fences into a single fence. + if (fence.is_valid()) { if (frame->merged_release_fence_fd.is_valid()) { - frame->merged_release_fence_fd.reset( - sync_merge("", frame->merged_release_fence_fd.get(), fd.get())); + frame->merged_release_fence_fd.reset(sync_merge( + "", frame->merged_release_fence_fd.get(), fence.get())); } else { - frame->merged_release_fence_fd = std::move(fd); + frame->merged_release_fence_fd = std::move(fence); } DCHECK(frame->merged_release_fence_fd.is_valid()); } @@ -541,8 +547,7 @@ void WaylandFrameManager::MaybeProcessSubmittedFrames() { continue; frame->presentation_acked = true; connection_->buffer_manager_host()->OnPresentation( - window_->GetWidget(), /*buffer_id*/ frame->buffer_id, - frame->feedback.value()); + window_->GetWidget(), frame->frame_id, frame->feedback.value()); } // Clear frames that are fully released and has already called @@ -571,8 +576,8 @@ void WaylandFrameManager::ProcessOldSubmittedFrame( // release because SwapCompletionCallback indicates to the client that the // buffers in previous frame is available for reuse. connection_->buffer_manager_host()->OnSubmission( - window_->GetWidget(), /*buffer_id*/ frame->buffer_id, - gfx::SwapResult::SWAP_ACK, std::move(release_fence_handle)); + window_->GetWidget(), frame->frame_id, gfx::SwapResult::SWAP_ACK, + std::move(release_fence_handle)); // If presentation feedback is not supported, use a fake feedback. This // literally means there are no presentation feedback callbacks created. diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_frame_manager.h b/chromium/ui/ozone/platform/wayland/host/wayland_frame_manager.h index 2ccc2522b3e..789fc5ed25a 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_frame_manager.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_frame_manager.h @@ -32,13 +32,23 @@ class WaylandSubsurface; // presented and released. struct WaylandFrame { public: + // A frame originated from gpu process, and hence, requires acknowledgements. WaylandFrame( + uint32_t frame_id, WaylandSurface* root_surface, ui::ozone::mojom::WaylandOverlayConfigPtr root_config, base::circular_deque<std::pair<WaylandSubsurface*, ui::ozone::mojom::WaylandOverlayConfigPtr>> - subsurfaces_to_overlays = {}, - bool expects_ack = true); + subsurfaces_to_overlays = {}); + + // A frame that does not require acknowledgements. + WaylandFrame( + WaylandSurface* root_surface, + ui::ozone::mojom::WaylandOverlayConfigPtr root_config, + base::circular_deque<std::pair<WaylandSubsurface*, + ui::ozone::mojom::WaylandOverlayConfigPtr>> + subsurfaces_to_overlays = {}); + WaylandFrame() = delete; WaylandFrame(const WaylandFrame&) = delete; WaylandFrame& operator=(const WaylandFrame&) = delete; @@ -47,6 +57,7 @@ struct WaylandFrame { private: friend class WaylandFrameManager; + uint32_t frame_id; WaylandSurface* root_surface; ui::ozone::mojom::WaylandOverlayConfigPtr root_config; base::circular_deque< @@ -55,11 +66,6 @@ struct WaylandFrame { base::flat_map<WaylandSurface*, WaylandBufferHandle*> submitted_buffers; - // ID of one of the buffers that will be attached to the subsurfaces. If none - // of the buffers will be attached, this is |root_config->buffer_id|. - // Used to invoke buffer_manager_host OnSubmission and OnPrensentation calls. - uint32_t buffer_id; - // An indicator that there are buffers destrotyed before frame playback. This // frame should be skipped. bool buffer_lost = false; @@ -73,7 +79,7 @@ struct WaylandFrame { // for this frame. base::ScopedFD merged_release_fence_fd; // Whether this frame has had OnSubmission sent for it. - bool submission_acked = false; + bool submission_acked; // The wayland object identifying this feedback. wl::Object<struct wp_presentation_feedback> pending_feedback; @@ -81,7 +87,7 @@ struct WaylandFrame { // Wayland server has not arrived yet. absl::optional<gfx::PresentationFeedback> feedback = absl::nullopt; // Whether this frame has had OnPresentation sent for it. - bool presentation_acked = false; + bool presentation_acked; }; // This is the frame update manager that configures graphical window/surface @@ -129,7 +135,7 @@ class WaylandFrameManager { gfx::GpuFenceHandle release_fence_handle); void OnExplicitBufferRelease(WaylandSurface* surface, struct wl_buffer* wl_buffer, - absl::optional<int32_t> fence); + base::ScopedFD fence); void OnWlBufferRelease(WaylandSurface* surface, struct wl_buffer* wl_buffer); // wl_callback_listener 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 512a6153b26..ab716d20a64 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 @@ -388,12 +388,15 @@ void WaylandInputMethodContext::SetSurroundingText( } void WaylandInputMethodContext::SetContentType(TextInputType input_type, - int input_flags) { + int input_flags, + bool should_do_learning) { if (!text_input_) return; uint32_t content_purpose = InputTypeToContentPurpose(input_type); uint32_t content_hint = InputFlagsToContentHint(input_flags); + if (!should_do_learning) + content_hint |= ZWP_TEXT_INPUT_V1_CONTENT_HINT_SENSITIVE_DATA; text_input_->SetContentType(content_hint, content_purpose); } @@ -519,12 +522,32 @@ void WaylandInputMethodContext::OnDeleteSurroundingText(int32_t index, void WaylandInputMethodContext::OnKeysym(uint32_t keysym, uint32_t state, - uint32_t modifiers) { + uint32_t modifiers_bits) { #if BUILDFLAG(USE_XKBCOMMON) auto* layout_engine = KeyboardLayoutEngineManager::GetKeyboardLayoutEngine(); if (!layout_engine) return; + // TODO(crbug.com/1289236): This is for the backward compatibility with older + // ash-chrome (M101 and earlier). In that version of ash-chrome didn't send + // CapsLock so that we hit an issue on using it. + // Because newer ash-chrome always sends CapsLock modifier map, as short term + // workaround, check the condition to identify whether Lacros is running + // on top of enough newer ash-chrome. + // To avoid accident, we also check text_input_extension, which is available + // only on ash-chrome. + // We can remove this workaround check in M104 or later. + absl::optional<std::vector<base::StringPiece>> modifiers; + if (!connection_->text_input_extension_v1() || + base::Contains(modifiers_map_, XKB_MOD_NAME_CAPS)) { + std::vector<base::StringPiece> modifier_content; + for (size_t i = 0; i < modifiers_map_.size(); ++i) { + if (modifiers_bits & (1 << i)) + modifier_content.emplace_back(modifiers_map_[i]); + } + modifiers = std::move(modifier_content); + } + DomCode dom_code = static_cast<XkbKeyboardLayoutEngine*>(layout_engine) ->GetDomCodeByKeysym(keysym, modifiers); if (dom_code == DomCode::NONE) @@ -614,6 +637,11 @@ void WaylandInputMethodContext::OnInputPanelState(uint32_t state) { // region somehow. } +void WaylandInputMethodContext::OnModifiersMap( + std::vector<std::string> modifiers_map) { + modifiers_map_ = std::move(modifiers_map); +} + void WaylandInputMethodContext::OnKeyboardFocusedWindowChanged() { MaybeUpdateActivated(); } diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.h b/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.h index d2b7082de56..4d11108cc35 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_input_method_context.h @@ -8,7 +8,6 @@ #include <memory> #include <vector> -#include "base/observer_list.h" #include "base/strings/string_piece.h" #include "ui/base/ime/character_composer.h" #include "ui/base/ime/linux/linux_input_method_context.h" @@ -49,7 +48,9 @@ class WaylandInputMethodContext : public LinuxInputMethodContext, void SetCursorLocation(const gfx::Rect& rect) override; void SetSurroundingText(const std::u16string& text, const gfx::Range& selection_range) override; - void SetContentType(TextInputType input_type, int input_flags) override; + void SetContentType(TextInputType input_type, + int input_flags, + bool should_do_learning) override; void Reset() override; void Focus() override; void Blur() override; @@ -76,6 +77,7 @@ class WaylandInputMethodContext : public LinuxInputMethodContext, uint32_t length, const std::vector<SpanStyle>& spans) override; void OnInputPanelState(uint32_t state) override; + void OnModifiersMap(std::vector<std::string> modifiers_map) override; private: void UpdatePreeditText(const std::u16string& preedit_text); @@ -113,6 +115,9 @@ class WaylandInputMethodContext : public LinuxInputMethodContext, // Caches VirtualKeyboard visibility. bool virtual_keyboard_visible_ = false; + + // Keeps modifiers_map sent from the wayland compositor. + std::vector<std::string> modifiers_map_; }; } // namespace ui 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 70b566e2b67..e9e09d700b0 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 @@ -388,7 +388,21 @@ TEST_P(WaylandInputMethodContextTest, SetContentType) { ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_URL)) .Times(1); input_method_context_->SetContentType(TEXT_INPUT_TYPE_URL, - TEXT_INPUT_FLAG_AUTOCOMPLETE_ON); + TEXT_INPUT_FLAG_AUTOCOMPLETE_ON, + /*should_do_learning=*/true); + connection_->ScheduleFlush(); + Sync(); +} + +TEST_P(WaylandInputMethodContextTest, SetContentTypeWithoutLearning) { + EXPECT_CALL(*zwp_text_input_, + SetContentType(ZWP_TEXT_INPUT_V1_CONTENT_HINT_AUTO_COMPLETION | + ZWP_TEXT_INPUT_V1_CONTENT_HINT_SENSITIVE_DATA, + ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_URL)) + .Times(1); + input_method_context_->SetContentType(TEXT_INPUT_TYPE_URL, + TEXT_INPUT_FLAG_AUTOCOMPLETE_ON, + /*should_do_learning=*/false); connection_->ScheduleFlush(); Sync(); } diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_output.h b/chromium/ui/ozone/platform/wayland/host/wayland_output.h index 68bd62c85ca..c36c7c77763 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_output.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_output.h @@ -63,6 +63,8 @@ class WaylandOutput : public wl::GlobalObjectRegistrar<WaylandOutput> { // global compositor space. bool is_ready() const { return !rect_in_physical_pixels_.IsEmpty(); } + wl_output* get_output() { return output_.get(); } + private: static constexpr int32_t kDefaultScaleFactor = 1; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc b/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc index c4d8ca41bcf..25d1fce653f 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_popup.cc @@ -205,7 +205,7 @@ void WaylandPopup::ApplyPendingBounds() { return; base::AutoReset<bool> auto_reset(&wayland_sets_bounds_, true); - SetBoundsDip(pending_configures_.back().bounds_dip); + WaylandWindow::ApplyPendingBounds(); } void WaylandPopup::OnCloseRequest() { diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc b/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc index 3fde4d13c9b..241b037b5b3 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_screen.cc @@ -8,6 +8,7 @@ #include <vector> #include "base/containers/contains.h" +#include "base/observer_list.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" @@ -224,9 +225,9 @@ display::Display WaylandScreen::GetDisplayForAcceleratedWidget( } gfx::Point WaylandScreen::GetCursorScreenPoint() const { - // Wayland does not provide either location of surfaces in global space - // coordinate system or location of a pointer. Instead, only locations of - // mouse/touch events are known. Given that Chromium assumes top-level + // wl_shell/xdg-shell do not provide either location of surfaces in global + // space coordinate system or location of a pointer. Instead, only locations + // of mouse/touch events are known. Given that Chromium assumes top-level // windows are located at origin, always provide a cursor point in regards // to surfaces' location. // 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 f159a5b1dbc..6021298006f 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc @@ -764,12 +764,11 @@ TEST_P(WaylandScreenTest, SetWindowScale) { display::Display::ResetForceDeviceScaleFactorForTesting(); } -// Checks that transform is properly translated to Display orientation. The -// first one is counter-clockwise, and the second is clockwise. +// Checks that output transform is properly translated into Display orientation. +// The first one is counter-clockwise, while the latter is clockwise. TEST_P(WaylandScreenTest, Transform) { - constexpr std::array< - std::pair<wl_output_transform, display::Display::Rotation>, 8> - test_data = {{ + constexpr std::pair<wl_output_transform, display::Display::Rotation> + kTestData[] = { {WL_OUTPUT_TRANSFORM_NORMAL, display::Display::ROTATE_0}, {WL_OUTPUT_TRANSFORM_90, display::Display::ROTATE_270}, {WL_OUTPUT_TRANSFORM_180, display::Display::ROTATE_180}, @@ -779,16 +778,16 @@ TEST_P(WaylandScreenTest, Transform) { {WL_OUTPUT_TRANSFORM_FLIPPED_90, display::Display::ROTATE_0}, {WL_OUTPUT_TRANSFORM_FLIPPED_180, display::Display::ROTATE_0}, {WL_OUTPUT_TRANSFORM_FLIPPED_270, display::Display::ROTATE_0}, - }}; + }; - for (const auto& i : test_data) { - output_->SetTransform(i.first); + for (const auto& [transform, expected_rotation] : kTestData) { + output_->SetTransform(transform); output_->Flush(); Sync(); auto main_display = platform_screen_->GetPrimaryDisplay(); - EXPECT_EQ(main_display.rotation(), i.second); + EXPECT_EQ(main_display.rotation(), expected_rotation); } } diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_serial_tracker.h b/chromium/ui/ozone/platform/wayland/host/wayland_serial_tracker.h index 66de9a05e16..5230119838f 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_serial_tracker.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_serial_tracker.h @@ -18,6 +18,10 @@ namespace wl { // meta-data, received through Wayland protocol events. Each serial value is // associated with an event type, which is represented by a SerialType enum // entry. +// +// Note: SerialTracker must not be used to track related input object states, +// e.g: whether a pointer button is pressed, or whether there are active touch +// points. Instead, other specific APIs should be added/used for that. enum class SerialType { kMouseEnter, diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc b/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc index aa2f3dc483c..5f573173a23 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.cc @@ -62,6 +62,9 @@ void WaylandSubsurface::Hide() { if (!subsurface_) return; + // Remove it from the stack. + RemoveFromList(); + augmented_subsurface_.reset(); subsurface_.reset(); } @@ -76,6 +79,10 @@ void WaylandSubsurface::CreateSubsurface() { wl_subcompositor* subcompositor = connection_->subcompositor(); DCHECK(subcompositor); subsurface_ = wayland_surface()->CreateSubsurface(parent_->root_surface()); + position_dip_ = {0, 0}; + + // A new sub-surface is initially added as the top-most in the stack. + parent_->subsurface_stack_committed()->Append(this); DCHECK(subsurface_); wl_subsurface_set_sync(subsurface_.get()); @@ -99,8 +106,8 @@ void WaylandSubsurface::ConfigureAndShowSurface( const gfx::RectF& bounds_px, const gfx::RectF& parent_bounds_px, float buffer_scale, - const WaylandSurface* reference_below, - const WaylandSurface* reference_above) { + WaylandSubsurface* new_below, + WaylandSubsurface* new_above) { Show(); // Chromium positions quads in display::Display coordinates in physical @@ -110,26 +117,35 @@ void WaylandSubsurface::ConfigureAndShowSurface( bounds_px, parent_bounds_px, connection_->surface_submission_in_pixel_coordinates() ? 1.f : buffer_scale); - if (augmented_subsurface_) { - DCHECK( - connection_->surface_augmenter()->SupportsSubpixelAccuratePosition()); - augmented_sub_surface_set_position( - augmented_subsurface_.get(), - wl_fixed_from_double(bounds_dip_in_parent_surface.x()), - wl_fixed_from_double(bounds_dip_in_parent_surface.y())); - } else { - gfx::Rect enclosed_rect_in_parent = - gfx::ToEnclosedRect(bounds_dip_in_parent_surface); - wl_subsurface_set_position(subsurface_.get(), enclosed_rect_in_parent.x(), - enclosed_rect_in_parent.y()); + if (bounds_dip_in_parent_surface.origin() != position_dip_) { + position_dip_ = bounds_dip_in_parent_surface.origin(); + if (augmented_subsurface_) { + DCHECK( + connection_->surface_augmenter()->SupportsSubpixelAccuratePosition()); + augmented_sub_surface_set_position( + augmented_subsurface_.get(), + wl_fixed_from_double(bounds_dip_in_parent_surface.x()), + wl_fixed_from_double(bounds_dip_in_parent_surface.y())); + } else { + gfx::Rect enclosed_rect_in_parent = + gfx::ToEnclosedRect(bounds_dip_in_parent_surface); + wl_subsurface_set_position(subsurface_.get(), enclosed_rect_in_parent.x(), + enclosed_rect_in_parent.y()); + } } // Setup the stacking order of this subsurface. - DCHECK(!reference_above || !reference_below); - if (reference_below) { - wl_subsurface_place_above(subsurface_.get(), reference_below->surface()); - } else if (reference_above) { - wl_subsurface_place_below(subsurface_.get(), reference_above->surface()); + DCHECK(!new_above || !new_below); + if (new_below && new_below != previous()) { + DCHECK_EQ(parent_, new_below->parent_); + RemoveFromList(); + InsertAfter(new_below); + wl_subsurface_place_above(subsurface_.get(), new_below->surface()); + } else if (new_above && new_above != next()) { + DCHECK_EQ(parent_, new_above->parent_); + RemoveFromList(); + InsertBefore(new_above); + wl_subsurface_place_below(subsurface_.get(), new_above->surface()); } } diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.h b/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.h index cedfff72f5c..db2455a47b7 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_subsurface.h @@ -5,6 +5,7 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SUBSURFACE_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_SUBSURFACE_H_ +#include "base/containers/linked_list.h" #include "ui/gfx/native_widget_types.h" #include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/host/wayland_surface.h" @@ -15,7 +16,11 @@ class WaylandWindow; // Wraps a wl_surface with a wl_subsurface role assigned. It is used to submit a // buffer as a sub region of WaylandWindow. -class WaylandSubsurface { +// +// Inherits base::LinkNode<> s.t. it's location in the subsurface stack can be +// tracked and prevent us from sending excessive wl_subsurface.place_below/above +// requests. +class WaylandSubsurface : public base::LinkNode<WaylandSubsurface> { public: WaylandSubsurface(WaylandConnection* connection, WaylandWindow* parent); WaylandSubsurface(const WaylandSubsurface&) = delete; @@ -39,8 +44,8 @@ class WaylandSubsurface { void ConfigureAndShowSurface(const gfx::RectF& bounds_px, const gfx::RectF& parent_bounds_px, float buffer_scale, - const WaylandSurface* reference_below, - const WaylandSurface* reference_above); + WaylandSubsurface* reference_below, + WaylandSubsurface* reference_above); // Assigns wl_subsurface role to the wl_surface so it is visible when a // wl_buffer is attached. @@ -56,6 +61,7 @@ class WaylandSubsurface { WaylandSurface wayland_surface_; wl::Object<wl_subsurface> subsurface_; wl::Object<augmented_sub_surface> augmented_subsurface_; + gfx::PointF position_dip_; WaylandConnection* const connection_; // |parent_| refers to the WaylandWindow whose wl_surface is the parent to diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc b/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc index 3eca6cd8951..0ff844dda1d 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_surface.cc @@ -18,6 +18,7 @@ #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size_f.h" +#include "ui/gfx/geometry/transform.h" #include "ui/gfx/native_widget_types.h" #include "ui/ozone/platform/wayland/common/wayland_util.h" #include "ui/ozone/platform/wayland/host/overlay_prioritizer.h" @@ -74,7 +75,13 @@ WaylandSurface::WaylandSurface(WaylandConnection* connection, root_window_(root_window), surface_(connection->CreateSurface()) {} -WaylandSurface::~WaylandSurface() = default; +WaylandSurface::~WaylandSurface() { + if (explicit_release_callback_.is_null()) + return; + for (auto& release : linux_buffer_releases_) { + explicit_release_callback_.Run(release.second.buffer, base::ScopedFD()); + } +} uint32_t WaylandSurface::GetSurfaceId() const { if (!surface_) @@ -210,7 +217,13 @@ void WaylandSurface::SetSurfaceBufferScale(float scale) { void WaylandSurface::SetOpaqueRegion(const std::vector<gfx::Rect>* region_px) { pending_state_.opaque_region_px.clear(); - if (!root_window_ || !root_window_->IsOpaqueWindow()) + if (!root_window_) + return; + bool is_primary_or_root = + root_window_->root_surface() == this || + (root_window()->primary_subsurface() && + root_window()->primary_subsurface()->wayland_surface() == this); + if (is_primary_or_root && !root_window_->IsOpaqueWindow()) return; if (region_px) pending_state_.opaque_region_px = *region_px; @@ -229,8 +242,12 @@ void WaylandSurface::SetOpaqueRegion(const std::vector<gfx::Rect>* region_px) { void WaylandSurface::SetInputRegion(const gfx::Rect* region_px) { pending_state_.input_region_px.reset(); - if (!root_window_ || root_window_->ShouldUseNativeFrame()) + if (!root_window_) + return; + if (root_window_->root_surface() == this && + root_window_->ShouldUseNativeFrame()) { return; + } if (region_px) pending_state_.input_region_px = *region_px; @@ -483,7 +500,7 @@ void WaylandSurface::ApplyPendingState() { gfx::SizeF bounds = wl::ApplyWaylandTransform( gfx::SizeF(pending_state_.buffer_size_px), wl::ToWaylandTransform(pending_state_.buffer_transform)); - int32_t applying_surface_scale; + int32_t applying_surface_scale = surface_scale_set_; // When viewport_px is set, wp_viewport will scale the surface accordingly. // Thus, there is no need to downscale bounds as Wayland compositor @@ -495,35 +512,38 @@ void WaylandSurface::ApplyPendingState() { applying_surface_scale = pending_state_.buffer_scale; bounds = gfx::ScaleSize(bounds, 1.f / pending_state_.buffer_scale); } - if (!SurfaceSubmissionInPixelCoordinates()) + if (!SurfaceSubmissionInPixelCoordinates() && + surface_scale_set_ != applying_surface_scale) { wl_surface_set_buffer_scale(surface_.get(), applying_surface_scale); + surface_scale_set_ = applying_surface_scale; + } + DCHECK_GE(surface_scale_set_, 1); gfx::RectF viewport_src_dip; + wl_fixed_t src_to_set[4] = {wl_fixed_from_int(-1), wl_fixed_from_int(-1), + wl_fixed_from_int(-1), wl_fixed_from_int(-1)}; if (pending_state_.crop.IsEmpty()) { viewport_src_dip = gfx::RectF(bounds); - // Unset crop (wp_viewport.set_source). - if (viewport()) { - wp_viewport_set_source(viewport(), wl_fixed_from_int(-1), - wl_fixed_from_int(-1), wl_fixed_from_int(-1), - wl_fixed_from_int(-1)); - } } else { viewport_src_dip = gfx::ScaleRect(pending_state_.crop, bounds.width(), bounds.height()); - // Apply crop (wp_viewport.set_source). DCHECK(viewport()); if (wl_fixed_from_double(viewport_src_dip.width()) == 0 || wl_fixed_from_double(viewport_src_dip.height()) == 0) { LOG(ERROR) << "Sending viewport src with width/height zero will result " "in wayland disconnection"; } - if (viewport()) { - wp_viewport_set_source(viewport(), - wl_fixed_from_double(viewport_src_dip.x()), - wl_fixed_from_double(viewport_src_dip.y()), - wl_fixed_from_double(viewport_src_dip.width()), - wl_fixed_from_double(viewport_src_dip.height())); - } + src_to_set[0] = wl_fixed_from_double(viewport_src_dip.x()), + src_to_set[1] = wl_fixed_from_double(viewport_src_dip.y()); + src_to_set[2] = wl_fixed_from_double(viewport_src_dip.width()); + src_to_set[3] = wl_fixed_from_double(viewport_src_dip.height()); + } + // Apply crop (wp_viewport.set_source). + if (viewport() && !std::equal(std::begin(src_to_set), std::end(src_to_set), + std::begin(src_set_))) { + wp_viewport_set_source(viewport(), src_to_set[0], src_to_set[1], + src_to_set[2], src_to_set[3]); + memcpy(src_set_, src_to_set, 4 * sizeof(*src_to_set)); } gfx::SizeF viewport_dst_dip = @@ -531,10 +551,16 @@ void WaylandSurface::ApplyPendingState() { ? viewport_src_dip.size() : gfx::ScaleSize(pending_state_.viewport_px, 1.f / pending_state_.buffer_scale); + float dst_to_set[2] = {-1.f, -1.f}; if (viewport_dst_dip != viewport_src_dip.size()) { - // Apply viewport scale (wp_viewport.set_destination). + dst_to_set[0] = viewport_dst_dip.width(); + dst_to_set[1] = viewport_dst_dip.height(); + } + // Apply viewport scale (wp_viewport.set_destination). + if (!std::equal(std::begin(dst_to_set), std::end(dst_to_set), + std::begin(dst_set_))) { auto* augmented_surface = GetAugmentedSurface(); - if (augmented_surface && + if (dst_to_set[0] > 0.f && augmented_surface && connection_->surface_augmenter()->SupportsSubpixelAccuratePosition()) { // Subpixel accurate positioning is available since the surface augmenter // version 2. Since that version, the augmented surface also supports @@ -547,13 +573,14 @@ void WaylandSurface::ApplyPendingState() { augmented_surface, wl_fixed_from_double(viewport_dst_dip.width()), wl_fixed_from_double(viewport_dst_dip.height())); } else if (viewport()) { - wp_viewport_set_destination(viewport(), - base::ClampCeil(viewport_dst_dip.width()), - base::ClampCeil(viewport_dst_dip.height())); + wp_viewport_set_destination( + viewport(), + dst_to_set[0] > 0.f ? base::ClampCeil(viewport_dst_dip.width()) + : static_cast<int>(dst_to_set[0]), + dst_to_set[1] > 0.f ? base::ClampCeil(viewport_dst_dip.height()) + : static_cast<int>(dst_to_set[1])); } - } else if (viewport()) { - // Unset viewport scale (wp_viewport.set_destination). - wp_viewport_set_destination(viewport(), -1, -1); + memcpy(dst_set_, dst_to_set, 2 * sizeof(*dst_to_set)); } DCHECK_LE(pending_state_.damage_px.size(), 1u); @@ -577,28 +604,28 @@ void WaylandSurface::ApplyPendingState() { pending_state_.damage_px.back().width(), pending_state_.damage_px.back().height()); } else { - // Calculate the damage region in surface coordinates. - // The calculation for damage region relies on the assumption: The buffer is - // always attached at surface location (0, 0). - // It's possible to write logic that accounts for attaching buffer at other - // locations, but it's currently unnecessary. - - // Apply buffer_transform (wl_surface.set_buffer_transform). - gfx::Rect damage = wl::ApplyWaylandTransform( - pending_state_.damage_px.back(), pending_state_.buffer_size_px, - wl::ToWaylandTransform(pending_state_.buffer_transform)); - // Apply buffer_scale (wl_surface.set_buffer_scale). - damage = gfx::ScaleToEnclosingRect(damage, 1.f / applying_surface_scale); - // Adjust coordinates to |viewport_src| (wp_viewport.set_source). - damage = wl::TranslateBoundsToParentCoordinates( - damage, gfx::ToEnclosingRect(viewport_src_dip)); - // Apply viewport scale (wp_viewport.set_destination). - if (viewport_dst_dip != viewport_src_dip.size()) { - damage = gfx::ScaleToEnclosingRect( - damage, viewport_dst_dip.width() / viewport_src_dip.width(), - viewport_dst_dip.height() / viewport_src_dip.height()); + gfx::RectF damage_uv = + gfx::ScaleRect(gfx::RectF(pending_state_.damage_px.back()), + 1.0f / pending_state_.buffer_size_px.width(), + 1.0f / pending_state_.buffer_size_px.height()); + + if (!pending_state_.crop.IsEmpty()) { + damage_uv.Offset(-pending_state_.crop.OffsetFromOrigin()); + damage_uv.Scale(1.0f / pending_state_.crop.width(), + 1.0f / pending_state_.crop.height()); } + damage_uv.Intersect(gfx::RectF(1, 1)); + + gfx::RectF damage_uv_transformed = wl::ApplyWaylandTransform( + damage_uv, gfx::SizeF(1, 1), + wl::ToWaylandTransform(pending_state_.buffer_transform)); + gfx::RectF damage_float = + gfx::ScaleRect(damage_uv_transformed, viewport_dst_dip.width(), + viewport_dst_dip.height()); + constexpr float kAcceptableSubDipDamageError = 0.001f; + gfx::Rect damage = gfx::ToEnclosingRectIgnoringError( + damage_float, kAcceptableSubDipDamageError); wl_surface_damage(surface_.get(), damage.x(), damage.y(), damage.width(), damage.height()); } @@ -613,12 +640,12 @@ void WaylandSurface::SetApplyStateImmediately() { void WaylandSurface::ExplicitRelease( struct zwp_linux_buffer_release_v1* linux_buffer_release, - absl::optional<int32_t> fence) { + base::ScopedFD fence) { auto iter = linux_buffer_releases_.find(linux_buffer_release); DCHECK(iter != linux_buffer_releases_.end()); DCHECK(iter->second.buffer); if (!explicit_release_callback_.is_null()) - explicit_release_callback_.Run(iter->second.buffer, fence); + explicit_release_callback_.Run(iter->second.buffer, std::move(fence)); linux_buffer_releases_.erase(iter); } @@ -717,8 +744,9 @@ void WaylandSurface::FencedRelease( void* data, struct zwp_linux_buffer_release_v1* linux_buffer_release, int32_t fence) { + auto fd = base::ScopedFD(fence); static_cast<WaylandSurface*>(data)->ExplicitRelease(linux_buffer_release, - fence); + std::move(fd)); } // static @@ -726,7 +754,7 @@ void WaylandSurface::ImmediateRelease( void* data, struct zwp_linux_buffer_release_v1* linux_buffer_release) { static_cast<WaylandSurface*>(data)->ExplicitRelease(linux_buffer_release, - absl::nullopt); + base::ScopedFD()); } } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_surface.h b/chromium/ui/ozone/platform/wayland/host/wayland_surface.h index 1e78c3ddeb1..e6b4e2f07f1 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_surface.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_surface.h @@ -10,6 +10,7 @@ #include "base/callback.h" #include "base/containers/flat_map.h" +#include "base/files/scoped_file.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect_f.h" @@ -34,7 +35,7 @@ class WaylandBufferHandle; class WaylandSurface { public: using ExplicitReleaseCallback = - base::RepeatingCallback<void(wl_buffer*, absl::optional<int32_t>)>; + base::RepeatingCallback<void(wl_buffer*, base::ScopedFD)>; WaylandSurface(WaylandConnection* connection, WaylandWindow* ro_window); WaylandSurface(const WaylandSurface&) = delete; @@ -238,6 +239,14 @@ class WaylandSurface { gfx::OverlayPriorityHint priority_hint = gfx::OverlayPriorityHint::kRegular; }; + // Tracks the last sent src and dst values across wayland protocol s.t. we + // skip resending them when possible. + wl_fixed_t src_set_[4] = {wl_fixed_from_int(-1), wl_fixed_from_int(-1), + wl_fixed_from_int(-1), wl_fixed_from_int(-1)}; + float dst_set_[2] = {-1.f, -1.f}; + // Tracks the last sent surface_scale value s.t. we skip resending. + int32_t surface_scale_set_ = 1; + wl::Object<wl_region> CreateAndAddRegion( const std::vector<gfx::Rect>& region_px, int32_t buffer_scale); @@ -281,7 +290,7 @@ class WaylandSurface { std::vector<uint32_t> entered_outputs_; void ExplicitRelease(struct zwp_linux_buffer_release_v1* linux_buffer_release, - absl::optional<int32_t> fence); + base::ScopedFD fence); // wl_surface_listener static void Enter(void* data, diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc index 215cbc9d915..c0843b39d4f 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc @@ -14,6 +14,7 @@ #include "build/chromeos_buildflags.h" #include "third_party/skia/include/core/SkPath.h" #include "ui/base/hit_test.h" +#include "ui/base/ui_base_features.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/native_widget_types.h" #include "ui/ozone/platform/wayland/host/gtk_shell1.h" @@ -45,7 +46,9 @@ constexpr int kVisibleOnAllWorkspaces = -1; WaylandToplevelWindow::WaylandToplevelWindow(PlatformWindowDelegate* delegate, WaylandConnection* connection) : WaylandWindow(delegate, connection), - state_(PlatformWindowState::kNormal) { + state_(PlatformWindowState::kNormal), + screen_coordinates_enabled_( + features::IsWaylandScreenCoordinatesEnabled()) { // Set a class property key, which allows |this| to be used for interactive // events, e.g. move or resize. SetWmMoveResizeHandler(this, AsWmMoveResizeHandler()); @@ -76,6 +79,10 @@ bool WaylandToplevelWindow::CreateShellToplevel() { TriggerStateChanges(); SetUpShellIntegration(); OnDecorationModeChanged(); + + if (screen_coordinates_enabled_) + SetBounds(GetBounds()); + // This could be the proper time to update window mask using // NonClientView::GetWindowMask, since |non_client_view| is not created yet // during the call to WaylandWindow::Initialize(). @@ -89,7 +96,7 @@ void WaylandToplevelWindow::ApplyPendingBounds() { return; DCHECK(shell_toplevel_); - SetBoundsDip(pending_configures_.back().bounds_dip); + WaylandWindow::ApplyPendingBounds(); } void WaylandToplevelWindow::DispatchHostWindowDragMovement( @@ -319,6 +326,17 @@ void WaylandToplevelWindow::HandleToplevelConfigure(int32_t width_dip, bool is_maximized, bool is_fullscreen, bool is_activated) { + HandleAuraToplevelConfigure(0, 0, width_dip, height_dip, is_maximized, + is_fullscreen, is_activated); +} + +void WaylandToplevelWindow::HandleAuraToplevelConfigure(int32_t x, + int32_t y, + int32_t width_dip, + int32_t height_dip, + 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_; @@ -359,11 +377,11 @@ void WaylandToplevelWindow::HandleToplevelConfigure(int32_t width_dip, // explicitly set the bounds to the current desired ones or the previous // bounds. if (width_dip > 1 && height_dip > 1) { - pending_bounds_dip_ = gfx::Rect(0, 0, width_dip, height_dip); + pending_bounds_dip_ = gfx::Rect(x, y, width_dip, height_dip); if (is_normal && frame_insets_px()) { pending_bounds_dip_.Inset( -gfx::ScaleToRoundedInsets(*frame_insets_px(), 1.f / window_scale())); - pending_bounds_dip_.set_origin({0, 0}); + pending_bounds_dip_.set_origin({x, y}); } } else if (is_normal) { pending_bounds_dip_.set_size( @@ -373,6 +391,11 @@ void WaylandToplevelWindow::HandleToplevelConfigure(int32_t width_dip, 1.0 / window_scale())); } + pending_bounds_dip_ = gfx::ScaleToRoundedRect( + AdjustBoundsToConstraintsPx( + gfx::ScaleToRoundedRect(pending_bounds_dip_, window_scale())), + 1 / window_scale()); + // Store the restored bounds if 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. @@ -389,6 +412,22 @@ void WaylandToplevelWindow::HandleToplevelConfigure(int32_t width_dip, state_change_in_transit_ = false; } +void WaylandToplevelWindow::SetBounds(const gfx::Rect& bounds) { + if (!shell_toplevel_ || !screen_coordinates_enabled_) { + WaylandWindow::SetBounds(bounds); + return; + } + gfx::Rect bounds_in_dip = + gfx::ScaleToEnclosingRect(bounds, 1.f / window_scale()); + shell_toplevel_->RequestWindowBounds(bounds_in_dip); +} + +void WaylandToplevelWindow::SetOrigin(const gfx::Point& origin) { + gfx::Point origin_px = + gfx::ScaleToFlooredPoint(origin, window_scale(), window_scale()); + WaylandWindow::SetBounds(gfx::Rect(origin_px, GetBounds().size())); +} + void WaylandToplevelWindow::HandleSurfaceConfigure(uint32_t serial) { ProcessPendingBoundsDip(serial); pending_bounds_dip_ = gfx::Rect(); @@ -454,11 +493,13 @@ void WaylandToplevelWindow::SetWindowGeometry(gfx::Rect bounds_dip) { if (!shell_toplevel_) return; + gfx::Rect geometry_dip(bounds_dip.size()); + if (state_ == PlatformWindowState::kNormal && frame_insets_px()) { - bounds_dip.Inset( + geometry_dip.Inset( gfx::ScaleToRoundedInsets(*frame_insets_px(), 1.f / window_scale())); } - shell_toplevel_->SetWindowGeometry(bounds_dip); + shell_toplevel_->SetWindowGeometry(geometry_dip); } void WaylandToplevelWindow::AckConfigure(uint32_t serial) { diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h index 928f5ad52b1..f1887b3f2e7 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_toplevel_window.h @@ -69,10 +69,18 @@ class WaylandToplevelWindow : public WaylandWindow, void SetOpaqueRegion(const std::vector<gfx::Rect>* region_px) override; void SetInputRegion(const gfx::Rect* region_px) override; void SetAspectRatio(const gfx::SizeF& aspect_ratio) override; + void SetBounds(const gfx::Rect& bounds) override; + + // Sets the window's origin. + void SetOrigin(const gfx::Point& origin); // WaylandWindow overrides: absl::optional<std::vector<gfx::Rect>> GetWindowShape() const override; + bool screen_coordinates_enabled() const { + return screen_coordinates_enabled_; + } + // Client-side decorations on Wayland take some portion of the window surface, // and when they are turned on or off, the window geometry is changed. That // happens only once at the moment of switching the decoration mode, and has @@ -89,6 +97,13 @@ class WaylandToplevelWindow : public WaylandWindow, bool is_maximized, bool is_fullscreen, bool is_activated) override; + void HandleAuraToplevelConfigure(int32_t x, + int32_t y, + int32_t width, + int32_t height, + bool is_maximized, + bool is_fullscreen, + bool is_activated) override; void HandleSurfaceConfigure(uint32_t serial) override; void UpdateVisualSize(const gfx::Size& size_px, float scale_factor) override; bool OnInitialize(PlatformWindowInitProperties properties) override; @@ -273,6 +288,9 @@ class WaylandToplevelWindow : public WaylandWindow, // If |workspace_| is -1, window is visible on all workspaces. absl::optional<int> workspace_ = absl::nullopt; + // True when screen coordinates is enabled. + bool screen_coordinates_enabled_; + WorkspaceExtensionDelegate* workspace_extension_delegate_ = nullptr; }; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc b/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc index 77629d7c52f..8b5c21639be 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_touch.cc @@ -62,12 +62,6 @@ void WaylandTouch::Up(void* data, base::TimeTicks timestamp = base::TimeTicks() + base::Milliseconds(time); touch->delegate_->OnTouchReleaseEvent(timestamp, id); - - // Reset kTouchPress serial only after dispatching touch-up event, so popups - // may detect if they were triggered by a tap gesture, and avoid grab in such - // case, which, per the spec, is illegal and may lead to instant popup - // dismissal by the compositor. - touch->connection_->serial_tracker().ResetSerial(wl::SerialType::kTouchPress); } void WaylandTouch::Motion(void* data, diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window.cc index 7a707aee4fd..273f4b514ad 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_window.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_window.cc @@ -13,6 +13,7 @@ #include "base/bind.h" #include "base/memory/scoped_refptr.h" #include "base/run_loop.h" +#include "base/threading/thread_task_runner_handle.h" #include "build/chromeos_buildflags.h" #include "ui/base/cursor/cursor.h" #include "ui/base/cursor/mojom/cursor_type.mojom.h" @@ -93,6 +94,9 @@ WaylandWindow::~WaylandWindow() { // Thus, the parent will have another child window. Do not reset it. if (parent_window_ && parent_window_->child_window() == this) parent_window_->set_child_window(nullptr); + + if (child_window_) + child_window_->set_parent_window(nullptr); } void WaylandWindow::OnWindowLostCapture() { @@ -252,8 +256,7 @@ void WaylandWindow::OnChannelDestroyed() { subsurfaces_to_overlays.emplace_back(subsurface.get(), nullptr); frame_manager_->RecordFrame(std::make_unique<WaylandFrame>( - root_surface(), nullptr, std::move(subsurfaces_to_overlays), - /*expects_ack=*/false)); + root_surface(), nullptr, std::move(subsurfaces_to_overlays))); } void WaylandWindow::Close() { @@ -271,23 +274,7 @@ void WaylandWindow::PrepareForShutdown() { } void WaylandWindow::SetBounds(const gfx::Rect& bounds_px) { - gfx::Rect adjusted_bounds_px = bounds_px; - - if (const auto min_size = delegate_->GetMinimumSizeForWindow()) { - if (min_size->width() > 0 && adjusted_bounds_px.width() < min_size->width()) - adjusted_bounds_px.set_width(min_size->width()); - if (min_size->height() > 0 && - adjusted_bounds_px.height() < min_size->height()) - adjusted_bounds_px.set_height(min_size->height()); - } - if (const auto max_size = delegate_->GetMaximumSizeForWindow()) { - if (max_size->width() > 0 && adjusted_bounds_px.width() > max_size->width()) - adjusted_bounds_px.set_width(max_size->width()); - if (max_size->height() > 0 && - adjusted_bounds_px.height() > max_size->height()) - adjusted_bounds_px.set_height(max_size->height()); - } - + gfx::Rect adjusted_bounds_px = AdjustBoundsToConstraintsPx(bounds_px); if (bounds_px_ == adjusted_bounds_px) return; bounds_px_ = adjusted_bounds_px; @@ -496,6 +483,17 @@ void WaylandWindow::HandleToplevelConfigure(int32_t widht, << "Only shell toplevels must receive HandleToplevelConfigure calls."; } +void WaylandWindow::HandleAuraToplevelConfigure(int32_t x, + int32_t y, + int32_t width, + int32_t height, + bool is_maximized, + bool is_fullscreen, + bool is_activated) { + NOTREACHED() + << "Only shell toplevels must receive HandleAuraToplevelConfigure calls."; +} + void WaylandWindow::HandlePopupConfigure(const gfx::Rect& bounds_dip) { NOTREACHED() << "Only shell popups must receive HandlePopupConfigure calls."; } @@ -576,7 +574,10 @@ void WaylandWindow::OnDragSessionClose(DragOperation operation) { } void WaylandWindow::SetBoundsDip(const gfx::Rect& bounds_dip) { - SetBounds(gfx::ScaleToRoundedRect(bounds_dip, window_scale())); + // This method is used to update the content size, and this method is calling + // WindowWindow's SetBounds to avoid calling into + // WaylandToplevelWindow::SetBounds which sends a request to a compostior. + WaylandWindow::SetBounds(gfx::ScaleToRoundedRect(bounds_dip, window_scale())); } bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) { @@ -663,11 +664,11 @@ void WaylandWindow::UpdateCursorPositionFromEvent( // // Basically, this method must translate coordinates of all events // in regards to top-level windows' coordinates as it's always located at - // origin (0,0) from Chromium point of view (remember that Wayland doesn't - // provide global coordinates to its clients). And it's totally fine to use it - // as the target. Thus, the location of the |event| is always converted using - // the top-level window's bounds as the target excluding cases, when the - // mouse/touch is over a top-level window. + // origin (0,0) from Chromium point of view (remember that wl_shell/xdg_shell + // doesn't provide global coordinates to its clients). And it's totally fine + // to use it as the target. Thus, the location of the |event| is always + // converted using the top-level window's bounds as the target excluding + // cases, when the mouse/touch is over a top-level window. auto* toplevel_window = GetRootParentWindow(); if (toplevel_window != this) { ConvertEventLocationToTargetWindowLocation( @@ -677,7 +678,8 @@ void WaylandWindow::UpdateCursorPositionFromEvent( auto* cursor_position = connection_->wayland_cursor_position(); if (cursor_position) { cursor_position->OnCursorPositionChanged( - event->AsLocatedEvent()->location()); + event->AsLocatedEvent()->location() + + toplevel_window->GetBoundsInDIP().origin().OffsetFromOrigin()); } } @@ -704,7 +706,8 @@ gfx::PointF WaylandWindow::ToRootWindowPixel(const gfx::PointF& location_dp) { if (!connection_->surface_submission_in_pixel_coordinates()) location_px.Scale(window_scale()); - return location_px; + auto* root_window = GetRootParentWindow(); + return location_px + root_window->GetBounds().origin().OffsetFromOrigin(); } WaylandWindow* WaylandWindow::GetTopMostChildWindow() { @@ -783,6 +786,7 @@ bool WaylandWindow::ArrangeSubsurfaceStack(size_t above, size_t below) { } bool WaylandWindow::CommitOverlays( + uint32_t frame_id, std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr>& overlays) { if (overlays.empty()) return true; @@ -795,7 +799,7 @@ bool WaylandWindow::CommitOverlays( ozone::mojom::WaylandOverlayConfig::New(); auto split = std::lower_bound(overlays.begin(), overlays.end(), value, OverlayStackOrderCompare); - CHECK(split == overlays.end() || (*split)->z_order >= 0); + DCHECK(split == overlays.end() || (*split)->z_order >= 0); size_t num_primary_planes = (split != overlays.end() && (*split)->z_order == 0) ? 1 : 0; size_t num_background_planes = @@ -809,18 +813,14 @@ bool WaylandWindow::CommitOverlays( if (!ArrangeSubsurfaceStack(above, below)) return false; - auto main_overlay = split; - if (split == overlays.end() && overlays.front()->z_order == INT32_MIN) - main_overlay = overlays.begin(); - - gfx::SizeF visual_size = (*main_overlay)->bounds_rect.size(); - float buffer_scale = (*main_overlay)->surface_scale_factor; - auto& rounded_clip_bounds = (*main_overlay)->rounded_clip_bounds; + gfx::SizeF visual_size = (*overlays.begin())->bounds_rect.size(); + float buffer_scale = (*overlays.begin())->surface_scale_factor; + auto& rounded_clip_bounds = (*overlays.begin())->rounded_clip_bounds; if (!wayland_overlay_delegation_enabled_) { DCHECK_EQ(overlays.size(), 1u); frame_manager_->RecordFrame(std::make_unique<WaylandFrame>( - root_surface(), std::move(*main_overlay))); + frame_id, root_surface(), std::move(*overlays.begin()))); return true; } @@ -831,10 +831,8 @@ bool WaylandWindow::CommitOverlays( std::max(overlays.size() - num_background_planes, wayland_subsurfaces_.size() + 1)); - if (num_primary_planes) { - subsurfaces_to_overlays.emplace_back(primary_subsurface(), - std::move(*split)); - } + subsurfaces_to_overlays.emplace_back( + primary_subsurface(), num_primary_planes ? std::move(*split) : nullptr); { // Iterate through |subsurface_stack_below_|, setup subsurfaces and place @@ -873,21 +871,17 @@ bool WaylandWindow::CommitOverlays( if (num_background_planes) { root_config = std::move(overlays.front()); } else { - root_config = ui::ozone::mojom::WaylandOverlayConfig::New(); - root_config->z_order = INT32_MIN; - root_config->transform = gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE; - root_config->buffer_id = root_surface()->buffer_id(); - root_config->enable_blend = root_surface()->use_blending(); - root_config->opacity = root_surface()->opacity(); - root_config->priority_hint = gfx::OverlayPriorityHint::kNone; + root_config = ui::ozone::mojom::WaylandOverlayConfig::New( + INT32_MIN, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE, + root_surface()->buffer_id(), buffer_scale, gfx::RectF(visual_size), + gfx::RectF(), gfx::Rect(), root_surface()->use_blending(), + root_surface()->opacity(), gfx::GpuFenceHandle(), + gfx::OverlayPriorityHint::kNone, rounded_clip_bounds); } - root_config->bounds_rect.set_size(visual_size); - root_config->surface_scale_factor = buffer_scale; - root_config->rounded_clip_bounds = rounded_clip_bounds; - frame_manager_->RecordFrame( - std::make_unique<WaylandFrame>(root_surface(), std::move(root_config), - std::move(subsurfaces_to_overlays))); + frame_manager_->RecordFrame(std::make_unique<WaylandFrame>( + frame_id, root_surface(), std::move(root_config), + std::move(subsurfaces_to_overlays))); return true; } @@ -981,18 +975,47 @@ void WaylandWindow::ProcessPendingBoundsDip(uint32_t serial) { } } +gfx::Rect WaylandWindow::AdjustBoundsToConstraintsPx( + const gfx::Rect& bounds_px) { + gfx::Rect adjusted_bounds_px = bounds_px; + if (const auto min_size = delegate_->GetMinimumSizeForWindow()) { + if (min_size->width() > 0 && adjusted_bounds_px.width() < min_size->width()) + adjusted_bounds_px.set_width(min_size->width()); + if (min_size->height() > 0 && + adjusted_bounds_px.height() < min_size->height()) + adjusted_bounds_px.set_height(min_size->height()); + } + if (const auto max_size = delegate_->GetMaximumSizeForWindow()) { + if (max_size->width() > 0 && adjusted_bounds_px.width() > max_size->width()) + adjusted_bounds_px.set_width(max_size->width()); + if (max_size->height() > 0 && + adjusted_bounds_px.height() > max_size->height()) + adjusted_bounds_px.set_height(max_size->height()); + } + return adjusted_bounds_px; +} + bool WaylandWindow::ProcessVisualSizeUpdate(const gfx::Size& size_px, float scale_factor) { + // TODO(crbug.com/1307501): Optimize this to be less expensive. Maybe + // precompute in pixels for configure events. pending_configures_ can have 10s + // of elements in it for several frames under some conditions. auto result = std::find_if( pending_configures_.begin(), pending_configures_.end(), - [&size_px, &scale_factor](auto& configure) { - return gfx::ScaleToRoundedRect(configure.bounds_dip, scale_factor) - .size() == size_px; + [this, &size_px, &scale_factor](auto& configure) { + // Since size_px comes from SetBounds via UpdateVisualSize in + // WaylandTopLevelWindow, we also need to adjust it for bounds to see if + // we match. + return AdjustBoundsToConstraintsPx( + gfx::ScaleToRoundedRect(configure.bounds_dip, scale_factor)) + .size() == size_px && + configure.set; }); if (result != pending_configures_.end()) { + auto serial = result->serial; SetWindowGeometry(result->bounds_dip); - AckConfigure(result->serial); + AckConfigure(serial); connection()->ScheduleFlush(); pending_configures_.erase(pending_configures_.begin(), ++result); return true; @@ -1000,4 +1023,11 @@ bool WaylandWindow::ProcessVisualSizeUpdate(const gfx::Size& size_px, return false; } +void WaylandWindow::ApplyPendingBounds() { + DCHECK(!pending_configures_.empty()); + for (auto& configure : pending_configures_) + configure.set = true; + SetBoundsDip(pending_configures_.back().bounds_dip); +} + } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window.h b/chromium/ui/ozone/platform/wayland/host/wayland_window.h index 8015c35c5e7..52472f360ae 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_window.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_window.h @@ -13,6 +13,7 @@ #include "base/callback.h" #include "base/containers/circular_deque.h" #include "base/containers/flat_set.h" +#include "base/containers/linked_list.h" #include "base/gtest_prod_util.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" @@ -78,6 +79,10 @@ class WaylandWindow : public PlatformWindow, return wayland_subsurfaces_; } + base::LinkedList<WaylandSubsurface>* subsurface_stack_committed() { + return &subsurface_stack_committed_; + } + void set_parent_window(WaylandWindow* parent_window) { parent_window_ = parent_window; } @@ -93,6 +98,7 @@ class WaylandWindow : public PlatformWindow, // subsurface_stack_below_.size() >= below. bool ArrangeSubsurfaceStack(size_t above, size_t below); bool CommitOverlays( + uint32_t frame_id, std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr>& overlays); // Set whether this window has pointer focus and should dispatch mouse events. @@ -202,11 +208,18 @@ class WaylandWindow : public PlatformWindow, // The width and height come in DIP of the output that the surface is // currently bound to. virtual void HandleSurfaceConfigure(uint32_t serial); - virtual void HandleToplevelConfigure(int32_t widht, + virtual void HandleToplevelConfigure(int32_t width, int32_t height, bool is_maximized, bool is_fullscreen, bool is_activated); + virtual void HandleAuraToplevelConfigure(int32_t x, + int32_t y, + int32_t width, + int32_t height, + bool is_maximized, + bool is_fullscreen, + bool is_activated); virtual void HandlePopupConfigure(const gfx::Rect& bounds); // The final size of the Wayland surface is determined by the buffer size in // px * scale that the Chromium compositor renders at. If the window changes a @@ -318,12 +331,16 @@ class WaylandWindow : public PlatformWindow, // Processes the pending bounds in dip. void ProcessPendingBoundsDip(uint32_t serial); + // If the given |bounds_px| violate size constraints set for this window, + // fixes them so they wouldn't. + gfx::Rect AdjustBoundsToConstraintsPx(const gfx::Rect& bounds_px); + // Processes the size information form visual size update and returns true if // any pending configure is fulfilled. bool ProcessVisualSizeUpdate(const gfx::Size& size_px, float scale_factor); // Applies pending bounds. - virtual void ApplyPendingBounds() = 0; + virtual void ApplyPendingBounds(); // These bounds attributes below have suffixes that indicate units used. // Wayland operates in DIP but the platform operates in physical pixels so @@ -342,11 +359,14 @@ class WaylandWindow : public PlatformWindow, struct PendingConfigure { gfx::Rect bounds_dip; uint32_t serial; + // True if this configure has been passed to the compositor for rendering. + bool set = false; }; base::circular_deque<PendingConfigure> pending_configures_; private: friend class WaylandBufferManagerViewportTest; + friend class BlockableWaylandToplevelWindow; FRIEND_TEST_ALL_PREFIXES(WaylandScreenTest, SetWindowScale); FRIEND_TEST_ALL_PREFIXES(WaylandBufferManagerTest, CanSubmitOverlayPriority); @@ -404,11 +424,15 @@ class WaylandWindow : public PlatformWindow, // The stack of sub-surfaces to take effect when Commit() is called. // |subsurface_stack_above_| refers to subsurfaces that are stacked above the - // primary. + // primary. These include the subsurfaces to be hidden as well. // Subsurface at the front of the list is the closest to the primary. std::list<WaylandSubsurface*> subsurface_stack_above_; std::list<WaylandSubsurface*> subsurface_stack_below_; + // The stack of sub-surfaces currently committed. This list is altered when + // the subsurface arrangement are played back by WaylandFrameManager. + base::LinkedList<WaylandSubsurface> subsurface_stack_committed_; + // The current cursor bitmap (immutable). scoped_refptr<BitmapCursor> cursor_; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc index e993f399190..84ac475378b 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc @@ -14,6 +14,7 @@ #include "base/callback.h" #include "base/check.h" +#include "base/containers/contains.h" #include "base/logging.h" #include "base/memory/weak_ptr.h" #include "base/notreached.h" @@ -108,12 +109,6 @@ bool WaylandWindowDragController::StartDragSession() { if (state_ != State::kIdle) return true; - origin_window_ = window_manager_->GetCurrentPointerOrTouchFocusedWindow(); - if (!origin_window_) { - LOG(ERROR) << "Failed to get origin window."; - return false; - } - auto serial = connection_->serial_tracker().GetSerial( {wl::SerialType::kTouchPress, wl::SerialType::kMousePress}); if (!serial.has_value()) { @@ -127,6 +122,14 @@ bool WaylandWindowDragController::StartDragSession() { ? DragSource::kTouch : DragSource::kMouse; + origin_window_ = *drag_source_ == DragSource::kMouse + ? window_manager_->GetCurrentPointerFocusedWindow() + : window_manager_->GetCurrentTouchFocusedWindow(); + if (!origin_window_) { + LOG(ERROR) << "Failed to get origin window."; + return false; + } + DCHECK(!data_source_); data_source_ = data_device_manager_->CreateSource(this); data_source_->Offer({kMimeTypeChromiumWindow}); @@ -186,7 +189,6 @@ void WaylandWindowDragController::StopDragging() { state_ = State::kAttaching; pointer_grab_owner_ = window_manager_->GetCurrentPointerOrTouchFocusedWindow(); - DCHECK(pointer_grab_owner_); QuitLoop(); } @@ -232,12 +234,10 @@ void WaylandWindowDragController::OnDragEnter(WaylandWindow* window, // TODO(crbug.com/1102946): Exo does not support custom mime types. In this // case, |data_offer_| will hold an empty mime_types list and, at this point, // it's safe just to skip the offer checks and requests here. - if (data_offer_->mime_types().empty()) + if (!base::Contains(data_offer_->mime_types(), kMimeTypeChromiumWindow)) { + DVLOG(1) << "OnEnter. No valid mime type found."; return; - - // Ensure this is a valid "window drag" offer. - DCHECK_EQ(data_offer_->mime_types().size(), 1u); - DCHECK_EQ(data_offer_->mime_types().front(), kMimeTypeChromiumWindow); + } // Accept the offer and set the dnd action. data_offer_->SetDndActions(kDndActionWindowDrag); @@ -360,7 +360,7 @@ void WaylandWindowDragController::OnDataSourceFinish(bool completed) { pointer_delegate_->OnPointerFocusChanged(dragged_window_, pointer_location_); } else { - touch_delegate_->OnTouchFocusChanged(nullptr); + touch_delegate_->OnTouchFocusChanged(dragged_window_); } } dragged_window_ = nullptr; @@ -421,7 +421,6 @@ void WaylandWindowDragController::OnToplevelWindowCreated( void WaylandWindowDragController::OnWindowRemoved(WaylandWindow* window) { DCHECK_NE(state_, State::kIdle); - DCHECK_NE(window, dragged_window_); DVLOG(1) << "Window being destroyed. widget=" << window->GetWidget(); if (window == pointer_grab_owner_) @@ -429,29 +428,34 @@ void WaylandWindowDragController::OnWindowRemoved(WaylandWindow* window) { if (window == origin_window_) origin_surface_ = origin_window_->TakeWaylandSurface(); + + if (window == dragged_window_) + SetDraggedWindow(nullptr, {}); } void WaylandWindowDragController::HandleMotionEvent(LocatedEvent* event) { DCHECK_EQ(state_, State::kDetached); - DCHECK(dragged_window_); DCHECK(event); if (!should_process_drag_event_) return; - // Update current cursor position, so it can be retrieved later on through + // Update current cursor position relative to the event source + // (pointer_grab_owner_) so it can be retrieved later on through // |Screen::GetCursorScreenPoint| API. - connection_->wayland_cursor_position()->OnCursorPositionChanged( - event->location()); + if (pointer_grab_owner_) + pointer_grab_owner_->UpdateCursorPositionFromEvent(Event::Clone(*event)); // Notify listeners about window bounds change (i.e: re-positioning) event. // To do so, set the new bounds as per the motion event location and the drag // offset. Note that setting a new location (i.e: bounds.origin()) for a // surface has no visual effect in ozone/wayland backend. Actual window // re-positioning during dragging session is done through the drag icon. - gfx::Point new_location = event->location() - drag_offset_; - gfx::Size size = dragged_window_->GetBounds().size(); - dragged_window_->SetBounds({new_location, size}); + if (dragged_window_) { + gfx::Point new_location = event->location() - drag_offset_; + gfx::Size size = dragged_window_->GetBounds().size(); + dragged_window_->SetBounds({new_location, size}); + } should_process_drag_event_ = false; } diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h index 0d3f9fbe21e..152b2de28fb 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h +++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h @@ -88,11 +88,13 @@ class WaylandWindowDragController : public WaylandDataDevice::DragDelegate, set_extended_drag_available_for_testing_ = true; } + WaylandWindow* origin_window_for_testing() { return origin_window_; } + private: class ExtendedDragSource; FRIEND_TEST_ALL_PREFIXES(WaylandWindowDragControllerTest, - HandleDraggedWindowDestruction); + HandleDraggedWindowDestructionAfterMoveLoop); // WaylandDataDevice::DragDelegate: bool IsDragSource() const override; diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc index db03b4b9326..3ea8233f99c 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc @@ -20,6 +20,7 @@ #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/native_widget_types.h" +#include "ui/ozone/platform/wayland/host/wayland_cursor_position.h" #include "ui/ozone/platform/wayland/host/wayland_data_device.h" #include "ui/ozone/platform/wayland/host/wayland_screen.h" #include "ui/ozone/platform/wayland/host/wayland_window.h" @@ -189,15 +190,17 @@ TEST_P(WaylandWindowDragControllerTest, DragInsideWindowAndDrop) { SendDndMotion({20, 20}); test_step = kDragging; break; - case kDropping: + case kDropping: { EXPECT_EQ(ET_MOUSE_RELEASED, event->type()); EXPECT_EQ(State::kDropped, drag_controller()->state()); // Ensure PlatformScreen keeps consistent. - EXPECT_EQ(gfx::Point(20, 20), screen_->GetCursorScreenPoint()); + gfx::Point expected_point{20, 20}; + expected_point += window_->GetBoundsInDIP().origin().OffsetFromOrigin(); EXPECT_EQ(window_->GetWidget(), screen_->GetLocalProcessWidgetAtPoint({20, 20}, {})); test_step = kDone; break; + } case kDone: EXPECT_EQ(ET_MOUSE_EXITED, event->type()); EXPECT_EQ(window_->GetWidget(), @@ -280,7 +283,9 @@ TEST_P(WaylandWindowDragControllerTest, DragInsideWindowAndDrop_TOUCH) { EXPECT_EQ(ET_TOUCH_RELEASED, event->type()); EXPECT_EQ(State::kDropped, drag_controller()->state()); // Ensure PlatformScreen keeps consistent. - EXPECT_EQ(gfx::Point(20, 20), screen_->GetCursorScreenPoint()); + gfx::Point expected_point{20, 20}; + expected_point += window_->GetBoundsInDIP().origin().OffsetFromOrigin(); + EXPECT_EQ(expected_point, screen_->GetCursorScreenPoint()); EXPECT_EQ(window_->GetWidget(), screen_->GetLocalProcessWidgetAtPoint({20, 20}, {})); test_step = kDone; @@ -320,6 +325,60 @@ TEST_P(WaylandWindowDragControllerTest, DragInsideWindowAndDrop_TOUCH) { } // Check the following flow works as expected: +// 1. With two windows open, +// 2. Touch down and start drag a window, +// 3. Emulate the compositor sending an unexpected `pointer enter` event +// to another window, when the drag is ongoing. +// +// NOTE: This bug isn't noticed on DUT, but seems to be frequent on ash/chrome +// linux desktop builds (with ozone/x11 underneath). +TEST_P(WaylandWindowDragControllerTest, + DragAndDropWithExtraneousPointerEnterEvent_TOUCH) { + // Init and open |target_window|. + PlatformWindowInitProperties properties{gfx::Rect{80, 80}}; + properties.type = PlatformWindowType::kWindow; + EXPECT_CALL(delegate_, OnAcceleratedWidgetAvailable(_)).Times(1); + auto window_2 = WaylandWindow::Create(&delegate_, connection_.get(), + std::move(properties)); + ASSERT_NE(gfx::kNullAcceleratedWidget, window_2->GetWidget()); + Sync(); + + // Ensure there is no window currently focused + EXPECT_FALSE(window_manager()->GetCurrentPointerOrTouchFocusedWindow()); + EXPECT_EQ(gfx::kNullAcceleratedWidget, + screen_->GetLocalProcessWidgetAtPoint({10, 10}, {})); + + ASSERT_TRUE(GetWmMoveLoopHandler(*window_2)); + ASSERT_TRUE(GetWaylandExtension(*window_2)); + + // Start triggering a drag operation. + SendTouchDown(window_2.get(), &delegate_, 0 /*point id*/, + {0, 0} /*location*/); + + // This operation simulates bogus Wayland compositor that might send out + // unexpected pointer enter events. + SendPointerEnter(window_.get(), &delegate_); + Sync(); + EXPECT_EQ(window_.get(), + window_manager()->GetCurrentPointerOrTouchFocusedWindow()); + EXPECT_EQ(window_.get(), window_manager()->GetCurrentPointerFocusedWindow()); + EXPECT_EQ(window_2.get(), window_manager()->GetCurrentTouchFocusedWindow()); + + // Set up an "interaction flow", start the drag session, run move loop + // and verify the window effectively being dragged. + GetWaylandExtension(*window_2)->StartWindowDraggingSessionIfNeeded( + /*allow_system_drag=*/false); + + Sync(); + // Verify that the proper window is being dragged. + EXPECT_EQ(window_2.get(), drag_controller()->origin_window_for_testing()); + Mock::VerifyAndClearExpectations(&delegate_); + + SendTouchUp(0 /*touch id*/); + Sync(); +} + +// Check the following flow works as expected: // 1. With only 1 window open; // 2. Move pointer into it, press left button, move cursor a bit (drag); // 3. Run move loop, @@ -364,15 +423,17 @@ TEST_P(WaylandWindowDragControllerTest, DragExitWindowAndDrop) { SendDndMotion({20, 20}); test_step = kDragging; break; - case kExitedDropping: + case kExitedDropping: { EXPECT_EQ(ET_MOUSE_RELEASED, event->type()); EXPECT_EQ(State::kDropped, drag_controller()->state()); // Ensure PlatformScreen keeps consistent. - EXPECT_EQ(gfx::Point(20, 20), screen_->GetCursorScreenPoint()); + gfx::Point expected_point{20, 20}; + expected_point += window_->GetBoundsInDIP().origin().OffsetFromOrigin(); + EXPECT_EQ(expected_point, screen_->GetCursorScreenPoint()); EXPECT_EQ(window_->GetWidget(), screen_->GetLocalProcessWidgetAtPoint({20, 20}, {})); test_step = kDone; - break; + } break; case kDone: EXPECT_EQ(ET_MOUSE_EXITED, event->type()); break; @@ -876,7 +937,7 @@ TEST_P(WaylandWindowDragControllerTest, IgnorePointerEventsUntilDrop) { SendDndMotion({100, 100}); test_step = kDragging; break; - case kDropping: + case kDropping: { EXPECT_EQ(ET_MOUSE_RELEASED, event->type()); EXPECT_EQ(State::kDropped, drag_controller()->state()); @@ -888,9 +949,11 @@ TEST_P(WaylandWindowDragControllerTest, IgnorePointerEventsUntilDrop) { screen_->GetLocalProcessWidgetAtPoint({100, 100}, {})); // Rather, only PlatformScreen's cursor position is updated accordingly. - EXPECT_EQ(gfx::Point(20, 20), screen_->GetCursorScreenPoint()); + gfx::Point expected_point{20, 20}; + expected_point += window_->GetBoundsInDIP().origin().OffsetFromOrigin(); + EXPECT_EQ(expected_point, screen_->GetCursorScreenPoint()); test_step = kDone; - break; + } break; case kDone: EXPECT_EQ(ET_MOUSE_EXITED, event->type()); EXPECT_EQ(window_->GetWidget(), @@ -1044,16 +1107,20 @@ TEST_P(WaylandWindowDragControllerTest, CursorPositionIsUpdatedOnMotion) { WmMoveLoopHandler* move_loop_handler, bool in_pixel_coordinates) { for (auto* output : *outputs) { - // Resetting cursor to the initial position. gfx::Point p0{10, 10}; - self->SendDndMotion(p0); - self->Sync(); + // Compute the expected point first as drag operation will move the + // window. gfx::Point expected_point = in_pixel_coordinates ? gfx::ScaleToRoundedPoint(p0, 1.0f / window->window_scale()) : p0; + expected_point += window->GetBoundsInDIP().origin().OffsetFromOrigin(); EXPECT_EQ(expected_point, screen->GetCursorScreenPoint()); + // Resetting cursor to the initial position. + self->SendDndMotion(p0); + self->Sync(); + // Send the window to |output|. wl::MockSurface* surface = server->GetObject<wl::MockSurface>( window->root_surface()->GetSurfaceId()); @@ -1063,13 +1130,15 @@ TEST_P(WaylandWindowDragControllerTest, CursorPositionIsUpdatedOnMotion) { EXPECT_EQ(output->GetScale(), window->window_scale()); gfx::Point p1{20, 20}; + expected_point = + (in_pixel_coordinates + ? gfx::ScaleToRoundedPoint(p1, 1.0f / window->window_scale()) + : p1); + expected_point += window->GetBoundsInDIP().origin().OffsetFromOrigin(); + self->SendDndMotion(p1); self->Sync(); - expected_point = - in_pixel_coordinates - ? gfx::ScaleToRoundedPoint(p1, 1.0f / window->window_scale()) - : p1; EXPECT_EQ(expected_point, screen->GetCursorScreenPoint()); wl_surface_send_leave(surface->resource(), output->resource()); } @@ -1090,7 +1159,8 @@ TEST_P(WaylandWindowDragControllerTest, CursorPositionIsUpdatedOnMotion) { // after quitting the move loop. Regression test for crbug.com/1267791 and // should be caught in both regular and ASAN builds, where more details about // the actual memory issue is provided. -TEST_P(WaylandWindowDragControllerTest, HandleDraggedWindowDestruction) { +TEST_P(WaylandWindowDragControllerTest, + HandleDraggedWindowDestructionAfterMoveLoop) { // 1. Ensure there is no window currently focused EXPECT_FALSE(window_manager()->GetCurrentPointerOrTouchFocusedWindow()); SendPointerEnter(window_.get(), &delegate_); @@ -1135,6 +1205,95 @@ TEST_P(WaylandWindowDragControllerTest, HandleDraggedWindowDestruction) { screen_->GetLocalProcessWidgetAtPoint({20, 20}, {})); } +// Ensure no memory issues happen when the dragged and/or events grabber windows +// get destroyed while the move loop is running. +TEST_P(WaylandWindowDragControllerTest, + HandleWindowsDestructionDuringMoveLoop) { + // 1. Send some initial pointer events to |window_|. + ASSERT_FALSE(window_manager()->GetCurrentPointerOrTouchFocusedWindow()); + SendPointerEnter(window_.get(), &delegate_); + SendPointerPress(window_.get(), &delegate_, BTN_LEFT); + SendPointerMotion(window_.get(), &delegate_, {10, 10}); + Mock::VerifyAndClearExpectations(&delegate_); + + // 2. Start the window drag session. + auto* wayland_extension = GetWaylandExtension(*window_); + wayland_extension->StartWindowDraggingSessionIfNeeded( + /*allow_system_drag=*/false); + EXPECT_EQ(State::kAttached, drag_controller()->state()); + + // 3. Spawns a new toplevel |window_2| out of the origin |window_|. Similarly + // to when a tab is detached in a Chrome's tab drag session. + PlatformWindowInitProperties properties{gfx::Rect{80, 80}}; + properties.type = PlatformWindowType::kWindow; + MockPlatformWindowDelegate delegate_2; + EXPECT_CALL(delegate_2, OnAcceleratedWidgetAvailable(_)).Times(1); + auto window_2 = WaylandWindow::Create(&delegate_2, connection_.get(), + std::move(properties)); + ASSERT_NE(gfx::kNullAcceleratedWidget, window_2->GetWidget()); + Sync(); + + // Spin the nested move loop and schedule a sequence of test steps to be + // pefomed while it is running. + ScheduleTestTask(base::BindLambdaForTesting([&]() { + auto* cursor_tracker = connection_->wayland_cursor_position(); + ASSERT_TRUE(cursor_tracker); + + // Send a motion event and verify it is correctly propagated. + EXPECT_CALL(delegate_2, OnBoundsChanged(_)).Times(1); + SendDndMotion({11, 10}); + Sync(); + EXPECT_EQ(gfx::Point(11, 10), cursor_tracker->GetCursorSurfacePoint()); + Mock::VerifyAndClearExpectations(&delegate_2); + + // Destroy the window being currently dragged. + window_2.reset(); + Sync(); + + // Verifies that motion events are no longer propagated, as the dragged + // window was just destroyed. + EXPECT_CALL(delegate_2, OnBoundsChanged(_)).Times(0); + SendDndMotion({12, 10}); + Sync(); + EXPECT_EQ(gfx::Point(12, 10), cursor_tracker->GetCursorSurfacePoint()); + Mock::VerifyAndClearExpectations(&delegate_2); + + // Destroy the current drag controler's pointer events grabber. + window_.reset(); + Sync(); + + // And verifies neither motion events are propagated nor internal "last + // cursor position" gets updated. + EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0); + SendDndMotion({13, 10}); + Sync(); + EXPECT_EQ(gfx::Point(12, 10), cursor_tracker->GetCursorSurfacePoint()); + Mock::VerifyAndClearExpectations(&delegate_); + + drag_controller()->StopDragging(); + })); + + ASSERT_TRUE(GetWmMoveLoopHandler(*window_2)); + GetWmMoveLoopHandler(*window_2)->RunMoveLoop({}); + Sync(); + + EXPECT_EQ(State::kAttached, drag_controller()->state()); + + // 5. Ensure no events are dispatched for drop. Which indirectly means that + // drop handling code at window drag controller does not call into the above + // destroyed dragged window. + EXPECT_CALL(delegate_2, DispatchEvent(_)).Times(0); + SendDndDrop(); + Sync(); + Mock::VerifyAndClearExpectations(&delegate_); + + // 6. Verifies that related state is correctly reset after drop. + EXPECT_EQ(State::kIdle, drag_controller()->state()); + EXPECT_FALSE(window_manager()->GetCurrentPointerOrTouchFocusedWindow()); + EXPECT_EQ(gfx::kNullAcceleratedWidget, + screen_->GetLocalProcessWidgetAtPoint({20, 20}, {})); +} + INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest, WaylandWindowDragControllerTest, Values(wl::ServerConfig{ diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.cc b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.cc index 52f17a55f6f..e92e4cb5bf5 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_manager.cc @@ -4,6 +4,7 @@ #include "ui/ozone/platform/wayland/host/wayland_window_manager.h" +#include "base/observer_list.h" #include "ui/ozone/platform/wayland/host/wayland_window.h" namespace ui { 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 e8d7cda5074..d83449063e3 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_window_unittest.cc @@ -4,8 +4,10 @@ #include "ui/ozone/platform/wayland/host/wayland_window.h" +#include <cstddef> #include <memory> #include <utility> +#include <vector> #include <cursor-shapes-unstable-v1-client-protocol.h> #include <linux/input.h> @@ -19,6 +21,7 @@ #include "base/nix/xdg_util.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/bind.h" #include "base/test/scoped_command_line.h" #include "build/chromeos_buildflags.h" #include "testing/gmock/include/gmock/gmock.h" @@ -44,6 +47,7 @@ #include "ui/ozone/platform/wayland/host/wayland_output_manager.h" #include "ui/ozone/platform/wayland/host/wayland_seat.h" #include "ui/ozone/platform/wayland/host/wayland_subsurface.h" +#include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h" #include "ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.h" #include "ui/ozone/platform/wayland/mojom/wayland_overlay_config.mojom.h" #include "ui/ozone/platform/wayland/test/mock_pointer.h" @@ -387,7 +391,7 @@ TEST_P(WaylandWindowTest, SetDecorationInsets) { Sync(); // Set insets for normal DPI. - const gfx::Insets kDecorationInsets = {24, 28, 32, 28}; + const auto kDecorationInsets = gfx::Insets::TLBR(24, 28, 32, 28); auto bounds_with_insets = kNormalBounds; bounds_with_insets.Inset(kDecorationInsets); EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0); @@ -424,7 +428,7 @@ TEST_P(WaylandWindowTest, SetDecorationInsets) { window_->root_surface()->SetSurfaceBufferScale(kHiDpiScale); // Set new insets so that rounding does not result in integer. - const gfx::Insets kDecorationInsets_2x = {48, 55, 63, 55}; + const auto kDecorationInsets_2x = gfx::Insets::TLBR(48, 55, 63, 55); EXPECT_CALL(*xdg_surface_, SetWindowGeometry(bounds_with_insets.x(), bounds_with_insets.y(), bounds_with_insets.width(), @@ -451,7 +455,7 @@ TEST_P(WaylandWindowTest, SetDecorationInsets) { } } -TEST_P(WaylandWindowTest, ShuffledUpdateVisualSizeOrder) { +TEST_P(WaylandWindowTest, DisregardUnpassedWindowConfigure) { const auto kNormalBounds1 = gfx::Rect{0, 0, 500, 300}; const auto kNormalBounds2 = gfx::Rect{0, 0, 800, 600}; const auto kNormalBounds3 = gfx::Rect{0, 0, 700, 400}; @@ -459,15 +463,17 @@ TEST_P(WaylandWindowTest, ShuffledUpdateVisualSizeOrder) { window_->set_update_visual_size_immediately(false); - // Send 3 configures and only ack the second one, the first pending configure - // is cleared. The second can still be ack'ed. + // Send 3 configures, and call UpdateVisualSize out of order. The out-of-order + // UpdateVisualSize(kNormalBounds2) should disregarded b/c kNormalBounds2 + // never reached UI Compositor when UpdateVisualSize(kNormalBounds2) is + // called. EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds1.width(), - kNormalBounds1.height())) - .Times(0); - EXPECT_CALL(*xdg_surface_, AckConfigure(2)).Times(0); + kNormalBounds1.height())); + EXPECT_CALL(*xdg_surface_, AckConfigure(2)); EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds2.width(), - kNormalBounds2.height())); - EXPECT_CALL(*xdg_surface_, AckConfigure(3)); + kNormalBounds2.height())) + .Times(0); + EXPECT_CALL(*xdg_surface_, AckConfigure(3)).Times(0); EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds3.width(), kNormalBounds3.height())); EXPECT_CALL(*xdg_surface_, AckConfigure(4)); @@ -528,8 +534,10 @@ TEST_P(WaylandWindowTest, UpdateVisualSizeClearsPreviousUnackedConfigures) { window_->set_update_visual_size_immediately(false); - // Send 3 configures and only ack the second one, the first pending configure - // is cleared. The second can still be ack'ed. + // Send 3 configures. Calling UpdateVisualSize(kNormalBounds3) will cause the + // kNormalBounds3 to be passed onto UI compositor. Hence, kNormalBounds1/2/3 + // configs will be acknowledgeable. The next UpdateVisualSize(kNormalBounds3) + // wiil ack kNormalBounds3 and skip kNormalBounds1/2. EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds1.width(), kNormalBounds1.height())) .Times(0); @@ -539,8 +547,9 @@ TEST_P(WaylandWindowTest, UpdateVisualSizeClearsPreviousUnackedConfigures) { Sync(); EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds2.width(), - kNormalBounds2.height())); - EXPECT_CALL(*xdg_surface_, AckConfigure(3)); + kNormalBounds2.height())) + .Times(0); + EXPECT_CALL(*xdg_surface_, AckConfigure(3)).Times(0); state = InitializeWlArrayWithActivatedState(); SendConfigureEvent(xdg_surface_, kNormalBounds2.width(), kNormalBounds2.height(), ++serial, state.get()); @@ -554,8 +563,7 @@ TEST_P(WaylandWindowTest, UpdateVisualSizeClearsPreviousUnackedConfigures) { kNormalBounds3.height(), ++serial, state.get()); Sync(); - window_->UpdateVisualSize(kNormalBounds2.size(), 1.0f); - window_->UpdateVisualSize(kNormalBounds1.size(), 1.0f); + window_->UpdateVisualSize(kNormalBounds3.size(), 1.0f); window_->UpdateVisualSize(kNormalBounds3.size(), 1.0f); } @@ -807,7 +815,7 @@ TEST_P(WaylandWindowTest, StartMaximized) { TEST_P(WaylandWindowTest, CompositorSideStateChanges) { // Real insets used by default on HiDPI. - const auto kInsets = gfx::Insets{38, 44, 55, 44}; + const auto kInsets = gfx::Insets::TLBR(38, 44, 55, 44); const auto kNormalBounds = window_->GetBounds(); EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal); @@ -2523,6 +2531,87 @@ TEST_P(WaylandWindowTest, WaylandPopupNestedParent) { } } +// Tests that size constraints returned by the `ui::PlatformWindowDelegate` are +// obeyed by the window when its bounds are set internally via its SetBounds() +// implementation. +TEST_P(WaylandWindowTest, SizeConstraintsInternal) { + const gfx::Rect kMinBounds{0, 0, 100, 100}; + const gfx::Rect kMaxBounds{0, 0, 300, 300}; + + window_->SetBounds({0, 0, 200, 200}); + Sync(); + + auto even_smaller_bounds = kMinBounds; + even_smaller_bounds.Inset(10); + even_smaller_bounds.set_origin({0, 0}); + + EXPECT_CALL(delegate_, GetMinimumSizeForWindow()) + .WillOnce(Return(kMinBounds.size())); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kMinBounds))); + + window_->SetBounds(even_smaller_bounds); + Sync(); + + VerifyAndClearExpectations(); + + auto even_greater_bounds = kMaxBounds; + even_greater_bounds.Outset(10); + even_greater_bounds.set_origin({0, 0}); + + EXPECT_CALL(delegate_, GetMaximumSizeForWindow()) + .WillOnce(Return(kMaxBounds.size())); + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kMaxBounds))); + + window_->SetBounds(even_greater_bounds); + Sync(); +} + +// Tests that size constraints returned by the `ui::PlatformWindowDelegate` are +// obeyed by the window when its bounds are set externally via the configure +// event sent by the compositor. +TEST_P(WaylandWindowTest, SizeConstraintsExternal) { + const gfx::Rect kMinBounds{0, 0, 100, 100}; + const gfx::Rect kMaxBounds{0, 0, 300, 300}; + + EXPECT_CALL(delegate_, GetMinimumSizeForWindow()) + .WillRepeatedly(Return(kMinBounds.size())); + EXPECT_CALL(delegate_, GetMaximumSizeForWindow()) + .WillRepeatedly(Return(kMaxBounds.size())); + + window_->SetBounds({0, 0, 200, 200}); + Sync(); + + uint32_t serial = 0; + auto state = InitializeWlArrayWithActivatedState(); + + auto even_smaller_bounds = kMinBounds; + even_smaller_bounds.Inset(10); + even_smaller_bounds.set_origin({0, 0}); + + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kMinBounds))); + + SendConfigureEvent(xdg_surface_, even_smaller_bounds.width(), + even_smaller_bounds.height(), ++serial, state.get()); + Sync(); + + VerifyAndClearExpectations(); + + EXPECT_CALL(delegate_, GetMinimumSizeForWindow()) + .WillRepeatedly(Return(kMinBounds.size())); + EXPECT_CALL(delegate_, GetMaximumSizeForWindow()) + .WillRepeatedly(Return(kMaxBounds.size())); + + auto even_greater_bounds = kMaxBounds; + even_greater_bounds.Outset(10); + even_greater_bounds.set_origin({0, 0}); + + EXPECT_CALL(delegate_, OnBoundsChanged(Eq(kMaxBounds))); + + SendConfigureEvent(xdg_surface_, even_greater_bounds.width(), + even_greater_bounds.height(), ++serial, state.get()); + Sync(); +} + TEST_P(WaylandWindowTest, OnSizeConstraintsChanged) { const bool kBooleans[] = {false, true}; for (bool has_min_size : kBooleans) { @@ -2661,7 +2750,8 @@ TEST_P(WaylandWindowTest, ReattachesBackgroundOnShow) { background->surface_scale_factor = 1; background->opacity = 1.f; overlays.push_back(std::move(background)); - buffer_manager_gpu_->CommitOverlays(window->GetWidget(), std::move(overlays)); + buffer_manager_gpu_->CommitOverlays(window->GetWidget(), 1u, + std::move(overlays)); mock_surface->SendFrameCallback(); Sync(); @@ -2693,7 +2783,8 @@ TEST_P(WaylandWindowTest, ReattachesBackgroundOnShow) { primary->surface_scale_factor = 1; primary->opacity = 1.f; overlays.push_back(std::move(primary)); - buffer_manager_gpu_->CommitOverlays(window->GetWidget(), std::move(overlays)); + buffer_manager_gpu_->CommitOverlays(window->GetWidget(), 2u, + std::move(overlays)); Sync(); @@ -2878,10 +2969,11 @@ TEST_P(WaylandWindowTest, CreatesPopupOnTouchDownSerial) { auto* test_popup = GetTestXdgPopupByWindow(popup.get()); ASSERT_TRUE(test_popup); - // Touch events are the exception. We can't use the serial that was sent - // before the "up" event. Otherwise, some compositors may dismiss popups. - // Thus, no serial must be used. - EXPECT_EQ(test_popup->grab_serial(), 0U); + // Unless the use-wayland-explicit-grab switch is set, touch events are the + // exception, i.e: the serial sent before the "up" event (latest) cannot be + // used, otherwise, some compositors may dismiss popups. + if (!use_explicit_grab) + EXPECT_EQ(test_popup->grab_serial(), 0U); popup->Hide(); @@ -3085,6 +3177,19 @@ class WaylandSubsurfaceTest : public WaylandWindowTest { EXPECT_EQ(test_subsurface->position(), expected_position); EXPECT_TRUE(test_subsurface->sync()); } + + std::vector<WaylandSubsurface*> RequestWaylandSubsurface(uint32_t n) { + VerifyAndClearExpectations(); + std::vector<WaylandSubsurface*> res = + std::vector<WaylandSubsurface*>{window_->primary_subsurface()}; + for (uint32_t i = 0; i < n - 1; ++i) { + window_->RequestSubsurface(); + } + for (auto& subsurface : window_->wayland_subsurfaces()) { + res.push_back(subsurface.get()); + } + return res; + } }; } // namespace @@ -3127,6 +3232,144 @@ TEST_P(WaylandSubsurfaceTest, OneWaylandSubsurfaceNonInteger) { } } +TEST_P(WaylandSubsurfaceTest, NoDuplicateSubsurfaceRequests) { + auto subsurfaces = RequestWaylandSubsurface(3); + for (auto* subsurface : subsurfaces) { + subsurface->ConfigureAndShowSurface(gfx::RectF(1.f, 2.f, 10.f, 20.f), + gfx::RectF(0.f, 0.f, 800.f, 600.f), 1.f, + nullptr, nullptr); + } + connection_->ScheduleFlush(); + + Sync(); + + // From top to bottom: subsurfaces[2], subsurfaces[1], subsurfaces[0]. + wl::TestSubSurface* test_subs[3] = { + server_ + .GetObject<wl::MockSurface>( + subsurfaces[0]->wayland_surface()->GetSurfaceId()) + ->sub_surface(), + server_ + .GetObject<wl::MockSurface>( + subsurfaces[1]->wayland_surface()->GetSurfaceId()) + ->sub_surface(), + server_ + .GetObject<wl::MockSurface>( + subsurfaces[2]->wayland_surface()->GetSurfaceId()) + ->sub_surface()}; + + EXPECT_CALL(*test_subs[0], PlaceAbove(_)).Times(1); + EXPECT_CALL(*test_subs[0], PlaceBelow(_)).Times(0); + EXPECT_CALL(*test_subs[0], SetPosition(_, _)).Times(1); + EXPECT_CALL(*test_subs[1], PlaceAbove(_)).Times(0); + EXPECT_CALL(*test_subs[1], PlaceBelow(_)).Times(0); + EXPECT_CALL(*test_subs[1], SetPosition(_, _)).Times(0); + EXPECT_CALL(*test_subs[2], PlaceAbove(_)).Times(0); + EXPECT_CALL(*test_subs[2], PlaceBelow(_)).Times(0); + EXPECT_CALL(*test_subs[2], SetPosition(_, _)).Times(0); + + // Stack subsurfaces[0] to be from bottom to top, and change its position. + subsurfaces[0]->ConfigureAndShowSurface(gfx::RectF(0.f, 0.f, 10.f, 20.f), + gfx::RectF(0.f, 0.f, 800.f, 600.f), + 1.f, subsurfaces[2], nullptr); + subsurfaces[1]->ConfigureAndShowSurface(gfx::RectF(1.f, 2.f, 10.f, 20.f), + gfx::RectF(0.f, 0.f, 800.f, 600.f), + 1.f, nullptr, subsurfaces[2]); + subsurfaces[2]->ConfigureAndShowSurface(gfx::RectF(1.f, 2.f, 10.f, 20.f), + gfx::RectF(0.f, 0.f, 800.f, 600.f), + 1.f, nullptr, subsurfaces[0]); + connection_->ScheduleFlush(); + + Sync(); + VerifyAndClearExpectations(); +} + +TEST_P(WaylandWindowTest, NoDuplicateViewporterRequests) { + EXPECT_TRUE(connection_->buffer_manager_host()); + + auto interface_ptr = connection_->buffer_manager_host()->BindInterface(); + buffer_manager_gpu_->Initialize( + std::move(interface_ptr), {}, false, true, false, + /*supports_non_backed_solid_color_buffers*/ false, + /*supports_subpixel_accurate_position*/ false); + + // Setup wl_buffers. + constexpr uint32_t buffer_id = 1; + gfx::Size buffer_size(1024, 768); + auto length = 1024 * 768 * 4; + buffer_manager_gpu_->CreateShmBasedBuffer(MakeFD(), length, buffer_size, + buffer_id); + Sync(); + + auto* surface = window_->root_surface(); + auto* test_viewport = + server_.GetObject<wl::MockSurface>(surface->GetSurfaceId())->viewport(); + + // Set viewport src and dst. + EXPECT_CALL(*test_viewport, SetSource(512, 384, 512, 384)).Times(1); + EXPECT_CALL(*test_viewport, SetDestination(800, 600)).Times(1); + + surface->AttachBuffer(connection_->buffer_manager_host()->EnsureBufferHandle( + surface, buffer_id)); + + surface->SetViewportSource({0.5, 0.5, 0.5, 0.5}); + surface->SetViewportDestination({800, 600}); + surface->ApplyPendingState(); + surface->Commit(); + connection_->ScheduleFlush(); + + Sync(); + VerifyAndClearExpectations(); + + // Duplicate viewport requests are not sent. + EXPECT_CALL(*test_viewport, SetSource(_, _, _, _)).Times(0); + EXPECT_CALL(*test_viewport, SetDestination(_, _)).Times(0); + + surface->AttachBuffer(connection_->buffer_manager_host()->EnsureBufferHandle( + surface, buffer_id)); + + surface->SetViewportSource({0.5, 0.5, 0.5, 0.5}); + surface->SetViewportDestination({800, 600}); + surface->ApplyPendingState(); + surface->Commit(); + connection_->ScheduleFlush(); + + Sync(); + VerifyAndClearExpectations(); + + // Unset viewport src and dst. + EXPECT_CALL(*test_viewport, SetSource(-1, -1, -1, -1)).Times(1); + EXPECT_CALL(*test_viewport, SetDestination(-1, -1)).Times(1); + + surface->AttachBuffer(connection_->buffer_manager_host()->EnsureBufferHandle( + surface, buffer_id)); + + surface->SetViewportSource({0., 0., 1., 1.}); + surface->SetViewportDestination({1024, 768}); + surface->ApplyPendingState(); + surface->Commit(); + connection_->ScheduleFlush(); + + Sync(); + VerifyAndClearExpectations(); + + // Duplicate viewport requests are not sent. + EXPECT_CALL(*test_viewport, SetSource(_, _, _, _)).Times(0); + EXPECT_CALL(*test_viewport, SetDestination(_, _)).Times(0); + + surface->AttachBuffer(connection_->buffer_manager_host()->EnsureBufferHandle( + surface, buffer_id)); + + surface->SetViewportSource({0., 0., 1., 1.}); + surface->SetViewportDestination({1024, 768}); + surface->ApplyPendingState(); + surface->Commit(); + connection_->ScheduleFlush(); + + Sync(); + VerifyAndClearExpectations(); +} + // Tests that WaylandPopups can be repositioned. TEST_P(WaylandWindowTest, RepositionPopups) { VerifyAndClearExpectations(); @@ -3227,6 +3470,112 @@ TEST_P(WaylandWindowTest, StartWithMinimized) { Sync(); } +class BlockableWaylandToplevelWindow : public WaylandToplevelWindow { + public: + BlockableWaylandToplevelWindow(MockPlatformWindowDelegate* delegate, + WaylandConnection* connection) + : WaylandToplevelWindow(delegate, connection) {} + + static std::unique_ptr<BlockableWaylandToplevelWindow> Create( + const gfx::Rect bounds, + WaylandConnection* connection, + MockPlatformWindowDelegate* delegate) { + auto window = + std::make_unique<BlockableWaylandToplevelWindow>(delegate, connection); + window->set_update_visual_size_immediately(/*update_immediately=*/true); + window->set_apply_pending_state_on_update_visual_size( + /*apply_immediately=*/true); + + PlatformWindowInitProperties properties; + properties.bounds = bounds; + properties.type = PlatformWindowType::kWindow; + properties.parent_widget = gfx::kNullAcceleratedWidget; + window->Initialize(std::move(properties)); + window->Show(false); + return window; + } + + // WaylandToplevelWindow overrides: + uint32_t DispatchEvent(const PlatformEvent& platform_event) override { + ui::Event* event(platform_event); + if (event->type() == ET_TOUCH_RELEASED && !blocked_) { + base::RunLoop run_loop{base::RunLoop::Type::kNestableTasksAllowed}; + blocked_ = true; + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(std::move(async_task_), run_loop.QuitClosure())); + run_loop.Run(); + blocked_ = false; + } + + return WaylandToplevelWindow::DispatchEvent(platform_event); + } + + void SetAsyncTask( + base::RepeatingCallback<void(base::OnceClosure)> async_task) { + async_task_ = std::move(async_task); + } + + private: + bool blocked_ = false; + base::RepeatingCallback<void(base::OnceClosure)> async_task_; +}; + +// This test ensures that Ozone/Wayland does not crash while handling a +// sequence of two or more touch down/up actions, where the first one blocks +// unfinished before the second pair comes in. +// +// This mimics the behavior of a modal dialog that comes up as a result of +// the first touch down/up action, and blocks the original flow, before it gets +// handled completely. +// The test is flaky. https://crbug.com/1305272. +TEST_P(WaylandWindowTest, DISABLED_BlockingTouchDownUp_NoCrash) { + window_.reset(); + + MockPlatformWindowDelegate delegate; + auto window = BlockableWaylandToplevelWindow::Create( + gfx::Rect(0, 0, 800, 600), connection_.get(), &delegate); + + wl_seat_send_capabilities( + server_.seat()->resource(), + WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_TOUCH); + Sync(); + ASSERT_TRUE(connection_->seat()->pointer()); + ASSERT_TRUE(connection_->seat()->touch()); + window->set_touch_focus(true); + + uint32_t serial = 0; + + // Test that CanDispatchEvent is set correctly. + wl::MockSurface* toplevel_surface = server_.GetObject<wl::MockSurface>( + window->root_surface()->GetSurfaceId()); + Sync(); + VerifyCanDispatchTouchEvents({window.get()}, {}); + + // Steps to be executed after the handling of the first touch down/up + // pair blocks. + auto async_task = base::BindLambdaForTesting([&](base::OnceClosure closure) { + wl_touch_send_down(server_.seat()->touch()->resource(), ++serial, 0, + toplevel_surface->resource(), 0 /* id */, + wl_fixed_from_int(100), wl_fixed_from_int(100)); + wl_touch_send_up(server_.seat()->touch()->resource(), ++serial, 2000, + 0 /* id */); + Sync(); + + std::move(closure).Run(); + }); + window->SetAsyncTask(std::move(async_task)); + + // Start executing the first touch down/up pair. + wl_touch_send_down(server_.seat()->touch()->resource(), ++serial, 0, + toplevel_surface->resource(), 0 /* id */, + wl_fixed_from_int(50), wl_fixed_from_int(50)); + wl_touch_send_up(server_.seat()->touch()->resource(), ++serial, 1000, + 0 /* id */); + Sync(); +} + INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest, WaylandWindowTest, Values(wl::ServerConfig{ diff --git a/chromium/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.cc b/chromium/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.cc index f1b492fc5e1..a0d9ec7ba07 100644 --- a/chromium/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.cc +++ b/chromium/ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.cc @@ -8,6 +8,7 @@ #include <wayland-util.h> #include "base/logging.h" +#include "build/chromeos_buildflags.h" #include "ui/gfx/geometry/vector2d_f.h" #include "ui/ozone/platform/wayland/common/wayland_util.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" 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 3116311fb6f..32c9079069f 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 @@ -70,8 +70,15 @@ void XDGSurfaceWrapperImpl::Configure(void* data, auto* surface = static_cast<XDGSurfaceWrapperImpl*>(data); DCHECK(surface); - surface->wayland_window_->HandleSurfaceConfigure(serial); - surface->wayland_window_->OnSurfaceConfigureEvent(); + // Calls to HandleSurfaceConfigure() might end up hiding the enclosing + // toplevel window, and deleting this object. + auto weak_window = surface->wayland_window_->AsWeakPtr(); + weak_window->HandleSurfaceConfigure(serial); + + if (!weak_window) + return; + + weak_window->OnSurfaceConfigureEvent(); } xdg_surface* XDGSurfaceWrapperImpl::xdg_surface() const { 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 2571aac25d5..a44a5d82d0e 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 @@ -35,14 +35,14 @@ class XDGSurfaceWrapperImpl : public ShellSurfaceWrapper { bool IsConfigured() override; void SetWindowGeometry(const gfx::Rect& bounds) override; + struct xdg_surface* xdg_surface() const; + + private: // xdg_surface_listener static void Configure(void* data, struct xdg_surface* xdg_surface, uint32_t serial); - struct xdg_surface* xdg_surface() const; - - private: // Non-owing WaylandWindow that uses this surface wrapper. WaylandWindow* const wayland_window_; WaylandConnection* const connection_; diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc b/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc index c2f1a62cf81..caec9df233a 100644 --- a/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc +++ b/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.cc @@ -13,12 +13,16 @@ #include "base/strings/utf_string_conversions.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/base/hit_test.h" +#include "ui/base/ui_base_features.h" #include "ui/ozone/common/features.h" #include "ui/ozone/platform/wayland/common/wayland_util.h" #include "ui/ozone/platform/wayland/host/shell_surface_wrapper.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" +#include "ui/ozone/platform/wayland/host/wayland_output.h" +#include "ui/ozone/platform/wayland/host/wayland_output_manager.h" #include "ui/ozone/platform/wayland/host/wayland_seat.h" #include "ui/ozone/platform/wayland/host/wayland_serial_tracker.h" +#include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h" #include "ui/ozone/platform/wayland/host/wayland_window.h" #include "ui/ozone/platform/wayland/host/wayland_zaura_shell.h" #include "ui/ozone/platform/wayland/host/xdg_surface_wrapper_impl.h" @@ -99,11 +103,25 @@ bool XDGToplevelWrapperImpl::Initialize() { ZAURA_SHELL_GET_AURA_TOPLEVEL_FOR_XDG_TOPLEVEL_SINCE_VERSION) { aura_toplevel_.reset(zaura_shell_get_aura_toplevel_for_xdg_toplevel( connection_->zaura_shell()->wl_object(), xdg_toplevel_.get())); - if (IsWaylandSurfaceSubmissionInPixelCoordinatesEnabled() && + if (ui::IsWaylandSurfaceSubmissionInPixelCoordinatesEnabled() && version >= - ZAURA_TOPLEVEL_SURFACE_SUBMISSION_IN_PIXEL_COORDINATES_SINCE_VERSION) + ZAURA_TOPLEVEL_SURFACE_SUBMISSION_IN_PIXEL_COORDINATES_SINCE_VERSION) { zaura_toplevel_surface_submission_in_pixel_coordinates( aura_toplevel_.get()); + } + + if (features::IsWaylandScreenCoordinatesEnabled()) { + DCHECK(ProtocolSupportsScreenCoordinates()); + zaura_toplevel_set_supports_screen_coordinates(aura_toplevel_.get()); + + static constexpr zaura_toplevel_listener aura_toplevel_listener = { + &ConfigureAuraTopLevel, + &OnOriginChange, + }; + + zaura_toplevel_add_listener(aura_toplevel_.get(), + &aura_toplevel_listener, this); + } } } @@ -230,6 +248,42 @@ void XDGToplevelWrapperImpl::ConfigureTopLevel( } // static +void XDGToplevelWrapperImpl::ConfigureAuraTopLevel( + void* data, + struct zaura_toplevel* zaura_toplevel, + int32_t x, + int32_t y, + int32_t width, + int32_t height, + struct wl_array* states) { + auto* surface = static_cast<XDGToplevelWrapperImpl*>(data); + DCHECK(surface); + + bool is_maximized = + CheckIfWlArrayHasValue(states, XDG_TOPLEVEL_STATE_MAXIMIZED); + bool is_fullscreen = + CheckIfWlArrayHasValue(states, XDG_TOPLEVEL_STATE_FULLSCREEN); + bool is_activated = + CheckIfWlArrayHasValue(states, XDG_TOPLEVEL_STATE_ACTIVATED); + + surface->wayland_window_->HandleAuraToplevelConfigure( + x, y, width, height, is_maximized, is_fullscreen, is_activated); +} + +// static +void XDGToplevelWrapperImpl::OnOriginChange( + void* data, + struct zaura_toplevel* zaura_toplevel, + int32_t x, + int32_t y) { + auto* surface = static_cast<XDGToplevelWrapperImpl*>(data); + DCHECK(surface); + auto* wayland_toplevel_window = + static_cast<WaylandToplevelWindow*>(surface->wayland_window_); + wayland_toplevel_window->SetOrigin(gfx::Point(x, y)); +} + +// static void XDGToplevelWrapperImpl::CloseTopLevel(void* data, struct xdg_toplevel* xdg_toplevel) { auto* surface = static_cast<XDGToplevelWrapperImpl*>(data); @@ -315,4 +369,25 @@ void XDGToplevelWrapperImpl::Unlock() { } } +void XDGToplevelWrapperImpl::RequestWindowBounds(const gfx::Rect& bounds) { + DCHECK(ProtocolSupportsScreenCoordinates()); + uint32_t id = wayland_window_->GetPreferredEnteredOutputId(); + auto* output = connection_->wayland_output_manager()->GetOutput(id); + if (!output) { + // output can be null when the surfae is just created. output should + // probably be inferred in that case. + LOG(WARNING) << "Output Not found for id=" << id; + output = connection_->wayland_output_manager()->GetPrimaryOutput(); + } + zaura_toplevel_set_window_bounds(aura_toplevel_.get(), bounds.x(), bounds.y(), + bounds.width(), bounds.height(), + output->get_output()); +} + +bool XDGToplevelWrapperImpl::ProtocolSupportsScreenCoordinates() { + return aura_toplevel_ && + zaura_toplevel_get_version(aura_toplevel_.get()) >= + ZAURA_TOPLEVEL_SET_SUPPORTS_SCREEN_COORDINATES_SINCE_VERSION; +} + } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h b/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h index c8a58680faf..77706b7b372 100644 --- a/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h +++ b/chromium/ui/ozone/platform/wayland/host/xdg_toplevel_wrapper_impl.h @@ -44,10 +44,13 @@ class XDGToplevelWrapperImpl : public ShellToplevelWrapper { void SetDecoration(DecorationMode decoration) override; void Lock(WaylandOrientationLockType lock_type) override; void Unlock() override; + void RequestWindowBounds(const gfx::Rect& bounds) override; XDGSurfaceWrapperImpl* xdg_surface_wrapper() const; private: + bool ProtocolSupportsScreenCoordinates(); + // xdg_toplevel_listener static void ConfigureTopLevel(void* data, struct xdg_toplevel* xdg_toplevel, @@ -62,6 +65,20 @@ class XDGToplevelWrapperImpl : public ShellToplevelWrapper { struct zxdg_toplevel_decoration_v1* decoration, uint32_t mode); + // aura_toplevel_listener + static void ConfigureAuraTopLevel(void* data, + struct zaura_toplevel* zaura_toplevel, + int32_t x, + int32_t y, + int32_t width, + int32_t height, + struct wl_array* states); + + static void OnOriginChange(void* data, + struct zaura_toplevel* zaura_toplevel, + int32_t x, + int32_t y); + // Send request to wayland compositor to enable a requested decoration mode. void SetTopLevelDecorationMode(DecorationMode requested_mode); diff --git a/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.cc b/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.cc index b052dab80b4..28f3e8c3c35 100644 --- a/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.cc +++ b/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.cc @@ -6,7 +6,6 @@ #include <primary-selection-unstable-v1-client-protocol.h> -#include "base/logging.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" #include "ui/ozone/platform/wayland/host/wayland_data_source.h" #include "ui/ozone/platform/wayland/host/zwp_primary_selection_offer.h" @@ -27,15 +26,11 @@ ZwpPrimarySelectionDevice::ZwpPrimarySelectionDevice( ZwpPrimarySelectionDevice::~ZwpPrimarySelectionDevice() = default; void ZwpPrimarySelectionDevice::SetSelectionSource( - ZwpPrimarySelectionSource* source) { - auto serial = GetSerialForSelection(); - if (!serial.has_value()) { - LOG(ERROR) << "Failed to set selection. No serial found."; - return; - } + ZwpPrimarySelectionSource* source, + uint32_t serial) { auto* data_source = source ? source->data_source() : nullptr; zwp_primary_selection_device_v1_set_selection(data_device_.get(), data_source, - serial->value); + serial); connection()->ScheduleFlush(); } diff --git a/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.h b/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.h index 764d8bae45f..a1196a0da96 100644 --- a/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.h +++ b/chromium/ui/ozone/platform/wayland/host/zwp_primary_selection_device.h @@ -5,6 +5,8 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_ZWP_PRIMARY_SELECTION_DEVICE_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_ZWP_PRIMARY_SELECTION_DEVICE_H_ +#include <cstdint> + #include "ui/ozone/platform/wayland/common/wayland_object.h" #include "ui/ozone/platform/wayland/host/wayland_data_device_base.h" #include "ui/ozone/platform/wayland/host/wayland_data_source.h" @@ -31,7 +33,7 @@ class ZwpPrimarySelectionDevice : public WaylandDataDeviceBase { return data_device_.get(); } - void SetSelectionSource(ZwpPrimarySelectionSource* source); + void SetSelectionSource(ZwpPrimarySelectionSource* source, uint32_t serial); private: // primary_selection_device_listener callbacks diff --git a/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper.h b/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper.h index 4bd183397c4..18ad5e60748 100644 --- a/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper.h +++ b/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper.h @@ -73,6 +73,13 @@ class ZWPTextInputWrapperClient { // (visible=1/invisible=0), and ignore other bits for future compatibility. // This behavior must be consistent with components/exo. virtual void OnInputPanelState(uint32_t state) = 0; + + // Called when the modifiers map is updated. + // Each element holds the XKB name represents a modifier, such as "Shift". + // The position of the element represents the bit position of modifiers + // on OnKeysym. E.g., if LSB of modifiers is set, modifiers_map[0] is + // set, if (1 << 1) of modifiers is set, modifiers_map[1] is set, and so on. + virtual void OnModifiersMap(std::vector<std::string> modifiers_map) = 0; }; // A wrapper around different versions of wayland text input protocols. diff --git a/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc b/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc index 09245d9b217..834e43dd907 100644 --- a/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc +++ b/chromium/ui/ozone/platform/wayland/host/zwp_text_input_wrapper_v1.cc @@ -7,12 +7,29 @@ #include <string> #include <utility> +#include "base/strings/string_piece.h" +#include "base/strings/string_split.h" #include "ui/gfx/range/range.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h" #include "ui/ozone/platform/wayland/host/wayland_seat.h" #include "ui/ozone/platform/wayland/host/wayland_window.h" namespace ui { +namespace { + +// Parses the content of |array|, and creates a map of modifiers. +// The content of array is just a concat of modifier names in c-style string +// (i.e., '\0' terminated string), thus this splits the whole byte array by +// '\0' character. +std::vector<std::string> ParseModifiersMap(wl_array* array) { + return base::SplitString( + base::StringPiece(static_cast<char*>(array->data), + array->size - 1), // exclude trailing '\0'. + base::StringPiece("\0", 1), // '\0' as a delimiter. + base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); +} + +} // namespace ZWPTextInputWrapperV1::ZWPTextInputWrapperV1( WaylandConnection* connection, @@ -126,7 +143,8 @@ void ZWPTextInputWrapperV1::OnLeave(void* data, void ZWPTextInputWrapperV1::OnModifiersMap(void* data, struct zwp_text_input_v1* text_input, struct wl_array* map) { - NOTIMPLEMENTED_LOG_ONCE(); + auto* self = static_cast<ZWPTextInputWrapperV1*>(data); + self->client_->OnModifiersMap(ParseModifiersMap(map)); } // static diff --git a/chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.cc b/chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.cc index 18b35a2d95b..20138f2e255 100644 --- a/chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.cc +++ b/chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.cc @@ -193,4 +193,8 @@ void ZXDGToplevelV6WrapperImpl::Lock(WaylandOrientationLockType lock_type) {} void ZXDGToplevelV6WrapperImpl::Unlock() {} +void ZXDGToplevelV6WrapperImpl::RequestWindowBounds(const gfx::Rect& bounds) { + NOTREACHED(); +} + } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.h b/chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.h index d55a373b881..caf4cc90a02 100644 --- a/chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.h +++ b/chromium/ui/ozone/platform/wayland/host/zxdg_toplevel_v6_wrapper_impl.h @@ -45,6 +45,7 @@ class ZXDGToplevelV6WrapperImpl : public ShellToplevelWrapper { void SetDecoration(DecorationMode decoration) override; void Lock(WaylandOrientationLockType lock_type) override; void Unlock() override; + void RequestWindowBounds(const gfx::Rect& geometry) override; ZXDGSurfaceV6WrapperImpl* zxdg_surface_v6_wrapper() const; diff --git a/chromium/ui/ozone/platform/wayland/mojom/wayland_buffer_manager.mojom b/chromium/ui/ozone/platform/wayland/mojom/wayland_buffer_manager.mojom index 36461071a82..73f211f1c28 100644 --- a/chromium/ui/ozone/platform/wayland/mojom/wayland_buffer_manager.mojom +++ b/chromium/ui/ozone/platform/wayland/mojom/wayland_buffer_manager.mojom @@ -73,18 +73,16 @@ interface WaylandBufferManagerHost { // These two methods are independent from the type of rendering. // - // Destroys a wl_buffer created by WaylandConnection based on the |buffer_id| - // for the WaylandWindow, which has the following |widget|. The |buffer_id| - // is the unique id of the buffer objects being destroyed on the browser - // process side. If the buffer with |buffer_id| has never been assigned to an - // AcceleratedWidget, it can be destroyed by passing a null widget - // with a correct buffer id. Providing wrong pair of the |widget| and the - // |buffer_id| will result in the termination of the GPU process. - DestroyBuffer(gfx.mojom.AcceleratedWidget widget, uint32 buffer_id); + // Destroys a wl_buffer created by WaylandConnection based on the |buffer_id|. + // The |buffer_id| is the unique id of the buffer objects being destroyed on + // the browser process side. Providing wrong |buffer_id| will result in the + // termination of the GPU process. + DestroyBuffer(uint32 buffer_id); // Send overlay configurations for a frame to a WaylandWindow with the - // following |widget|. + // following |widget| and |frame_id|. CommitOverlays(gfx.mojom.AcceleratedWidget widget, + uint32 frame_id, array<WaylandOverlayConfig> overlays); }; @@ -123,12 +121,12 @@ interface WaylandBufferManagerGpu { // Signals about swap completion. OnSubmission(gfx.mojom.AcceleratedWidget widget, - uint32 buffer_id, + uint32 frame_id, gfx.mojom.SwapResult swap_result, gfx.mojom.GpuFenceHandle? release_fence_handle); // Signals about presentation. OnPresentation(gfx.mojom.AcceleratedWidget widget, - uint32 buffer_id, + uint32 frame_id, gfx.mojom.PresentationFeedback feedback); }; diff --git a/chromium/ui/ozone/platform/wayland/test/test_augmented_subsurface.cc b/chromium/ui/ozone/platform/wayland/test/test_augmented_subsurface.cc index 23b8916308b..8df4c6adfa7 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_augmented_subsurface.cc +++ b/chromium/ui/ozone/platform/wayland/test/test_augmented_subsurface.cc @@ -25,7 +25,8 @@ void SetPosition(struct wl_client* client, auto* test_subsurface = GetUserDataAs<TestSubSurface>(test_augmented_subsurface->sub_surface()); DCHECK(test_subsurface); - test_subsurface->SetPosition(wl_fixed_to_double(x), wl_fixed_to_double(y)); + test_subsurface->SetPositionImpl(wl_fixed_to_double(x), + wl_fixed_to_double(y)); } } // namespace diff --git a/chromium/ui/ozone/platform/wayland/test/test_augmented_surface.cc b/chromium/ui/ozone/platform/wayland/test/test_augmented_surface.cc index 5e570026c8a..0220f5ba150 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_augmented_surface.cc +++ b/chromium/ui/ozone/platform/wayland/test/test_augmented_surface.cc @@ -33,8 +33,8 @@ void SetDestinationSize(struct wl_client* client, auto* viewport = mock_surface->viewport(); DCHECK(viewport); - viewport->SetDestination(wl_fixed_to_double(width), - wl_fixed_to_double(height)); + viewport->SetDestinationImpl(wl_fixed_to_double(width), + wl_fixed_to_double(height)); } void SetRoundedClipBounds(struct wl_client* client, diff --git a/chromium/ui/ozone/platform/wayland/test/test_compositor.cc b/chromium/ui/ozone/platform/wayland/test/test_compositor.cc index 80fab9ab4bb..e02e57f37d2 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_compositor.cc +++ b/chromium/ui/ozone/platform/wayland/test/test_compositor.cc @@ -12,8 +12,6 @@ namespace wl { -constexpr uint32_t TestCompositor::kVersion; - namespace { void CreateSurface(wl_client* client, @@ -41,8 +39,11 @@ const struct wl_compositor_interface kTestCompositorImpl = { CreateRegion, // create_region }; -TestCompositor::TestCompositor() - : GlobalObject(&wl_compositor_interface, &kTestCompositorImpl, kVersion) {} +TestCompositor::TestCompositor(uint32_t intended_version) + : GlobalObject(&wl_compositor_interface, + &kTestCompositorImpl, + intended_version), + version_(intended_version) {} TestCompositor::~TestCompositor() = default; diff --git a/chromium/ui/ozone/platform/wayland/test/test_compositor.h b/chromium/ui/ozone/platform/wayland/test/test_compositor.h index ca7c32200d1..1b268d20f62 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_compositor.h +++ b/chromium/ui/ozone/platform/wayland/test/test_compositor.h @@ -16,9 +16,7 @@ class MockSurface; // Manage wl_compositor object. class TestCompositor : public GlobalObject { public: - static constexpr uint32_t kVersion = 4; - - TestCompositor(); + explicit TestCompositor(uint32_t intended_version); TestCompositor(const TestCompositor&) = delete; TestCompositor& operator=(const TestCompositor&) = delete; @@ -26,8 +24,10 @@ class TestCompositor : public GlobalObject { ~TestCompositor() override; void AddSurface(MockSurface* surface); + uint32_t GetVersion() { return version_; } private: + uint32_t version_; std::vector<MockSurface*> surfaces_; }; diff --git a/chromium/ui/ozone/platform/wayland/test/test_data_device.cc b/chromium/ui/ozone/platform/wayland/test/test_data_device.cc index e2a8a8bc9bc..ee3fc397545 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_data_device.cc +++ b/chromium/ui/ozone/platform/wayland/test/test_data_device.cc @@ -11,6 +11,7 @@ #include "base/notreached.h" #include "ui/ozone/platform/wayland/test/mock_surface.h" #include "ui/ozone/platform/wayland/test/server_object.h" +#include "ui/ozone/platform/wayland/test/test_data_device_manager.h" #include "ui/ozone/platform/wayland/test/test_data_offer.h" #include "ui/ozone/platform/wayland/test/test_data_source.h" #include "ui/ozone/platform/wayland/test/test_selection_device_manager.h" @@ -75,15 +76,19 @@ const struct wl_data_device_interface kTestDataDeviceImpl = { &DataDeviceStartDrag, &TestSelectionDevice::SetSelection, &DataDeviceRelease}; -TestDataDevice::TestDataDevice(wl_resource* resource, wl_client* client) +TestDataDevice::TestDataDevice(wl_resource* resource, + wl_client* client, + TestDataDeviceManager* manager) : TestSelectionDevice(resource, new WlDataDeviceImpl(this)), - client_(client) {} + client_(client), + manager_(manager) {} TestDataDevice::~TestDataDevice() = default; void TestDataDevice::SetSelection(TestDataSource* data_source, uint32_t serial) { - NOTIMPLEMENTED(); + CHECK(manager_); + manager_->set_data_source(data_source); } TestDataOffer* TestDataDevice::CreateAndSendDataOffer() { @@ -95,6 +100,10 @@ void TestDataDevice::StartDrag(TestDataSource* source, uint32_t serial) { DCHECK(source); DCHECK(origin); + + CHECK(manager_); + manager_->set_data_source(source); + if (drag_delegate_) drag_delegate_->StartDrag(source, origin, serial); wl_client_flush(client_); diff --git a/chromium/ui/ozone/platform/wayland/test/test_data_device.h b/chromium/ui/ozone/platform/wayland/test/test_data_device.h index ba2b2c4d183..16242fb49ca 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_data_device.h +++ b/chromium/ui/ozone/platform/wayland/test/test_data_device.h @@ -21,6 +21,7 @@ extern const struct wl_data_device_interface kTestDataDeviceImpl; class TestDataOffer; class TestDataSource; +class TestDataDeviceManager; class TestDataDevice : public TestSelectionDevice { public: @@ -30,7 +31,9 @@ class TestDataDevice : public TestSelectionDevice { uint32_t serial) = 0; }; - TestDataDevice(wl_resource* resource, wl_client* client); + TestDataDevice(wl_resource* resource, + wl_client* client, + TestDataDeviceManager* manager); TestDataDevice(const TestDataDevice&) = delete; TestDataDevice& operator=(const TestDataDevice&) = delete; @@ -59,6 +62,8 @@ class TestDataDevice : public TestSelectionDevice { private: wl_client* client_ = nullptr; DragDelegate* drag_delegate_ = nullptr; + + TestDataDeviceManager* const manager_; }; } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/test_data_device_manager.cc b/chromium/ui/ozone/platform/wayland/test/test_data_device_manager.cc index e54efbf8aea..5e774db05aa 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_data_device_manager.cc +++ b/chromium/ui/ozone/platform/wayland/test/test_data_device_manager.cc @@ -8,6 +8,7 @@ #include "ui/ozone/platform/wayland/test/test_data_device.h" #include "ui/ozone/platform/wayland/test/test_data_source.h" +#include "ui/ozone/platform/wayland/test/test_selection_device_manager.h" namespace wl { @@ -16,23 +17,25 @@ namespace { constexpr uint32_t kDataDeviceManagerVersion = 3; void CreateDataSource(wl_client* client, wl_resource* resource, uint32_t id) { - wl_resource* data_source_resource = CreateResourceWithImpl<TestDataSource>( - client, &wl_data_source_interface, wl_resource_get_version(resource), - &kTestDataSourceImpl, id); - GetUserDataAs<TestDataDeviceManager>(resource)->set_data_source( - GetUserDataAs<TestDataSource>(data_source_resource)); + CreateResourceWithImpl<TestDataSource>(client, &wl_data_source_interface, + wl_resource_get_version(resource), + &kTestDataSourceImpl, id); } void GetDataDevice(wl_client* client, - wl_resource* data_device_manager_resource, + wl_resource* manager_resource, uint32_t id, wl_resource* seat_resource) { + auto* manager = GetUserDataAs<TestDataDeviceManager>(manager_resource); + CHECK(manager); + wl_resource* resource = CreateResourceWithImpl<TestDataDevice>( client, &wl_data_device_interface, - wl_resource_get_version(data_device_manager_resource), - &kTestDataDeviceImpl, id, client); - GetUserDataAs<TestDataDeviceManager>(data_device_manager_resource) - ->set_data_device(GetUserDataAs<TestDataDevice>(resource)); + wl_resource_get_version(manager_resource), &kTestDataDeviceImpl, id, + client, manager); + + CHECK(GetUserDataAs<TestDataDevice>(resource)); + manager->set_data_device(GetUserDataAs<TestDataDevice>(resource)); } } // namespace diff --git a/chromium/ui/ozone/platform/wayland/test/test_gtk_primary_selection.cc b/chromium/ui/ozone/platform/wayland/test/test_gtk_primary_selection.cc index a027fdaee04..7d9e2290498 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_gtk_primary_selection.cc +++ b/chromium/ui/ozone/platform/wayland/test/test_gtk_primary_selection.cc @@ -37,7 +37,7 @@ struct GtkPrimarySelectionOffer final : public TestSelectionOffer::Delegate { struct GtkPrimarySelectionDevice final : public TestSelectionDevice::Delegate { TestSelectionOffer* CreateAndSendOffer() override { - const struct gtk_primary_selection_offer_interface kOfferImpl = { + static const struct gtk_primary_selection_offer_interface kOfferImpl = { &TestSelectionOffer::Receive, &Destroy}; wl_resource* device_resource = device->resource(); const int version = wl_resource_get_version(device_resource); @@ -98,7 +98,7 @@ struct GtkPrimarySelectionDeviceManager ~GtkPrimarySelectionDeviceManager() override = default; TestSelectionDevice* CreateDevice(wl_client* client, uint32_t id) override { - const struct gtk_primary_selection_device_interface + static const struct gtk_primary_selection_device_interface kTestSelectionDeviceImpl = {&TestSelectionDevice::SetSelection, &Destroy}; auto* delegate = new GtkPrimarySelectionDevice; @@ -110,7 +110,7 @@ struct GtkPrimarySelectionDeviceManager } TestSelectionSource* CreateSource(wl_client* client, uint32_t id) override { - const struct gtk_primary_selection_source_interface + static const struct gtk_primary_selection_source_interface kTestSelectionSourceImpl = {&TestSelectionSource::Offer, &Destroy}; auto* delegate = new GtkPrimarySelectionSource; wl_resource* resource = CreateResourceWithImpl<TestSelectionSource>( @@ -130,7 +130,7 @@ struct GtkPrimarySelectionDeviceManager TestSelectionDeviceManager* CreateTestSelectionManagerGtk() { constexpr uint32_t kVersion = 1; - const struct gtk_primary_selection_device_manager_interface + static const struct gtk_primary_selection_device_manager_interface kTestSelectionManagerImpl = {&TestSelectionDeviceManager::CreateSource, &TestSelectionDeviceManager::GetDevice, &Destroy}; diff --git a/chromium/ui/ozone/platform/wayland/test/test_selection_device_manager.cc b/chromium/ui/ozone/platform/wayland/test/test_selection_device_manager.cc index b9747902e1a..ec2626d0f42 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_selection_device_manager.cc +++ b/chromium/ui/ozone/platform/wayland/test/test_selection_device_manager.cc @@ -15,7 +15,6 @@ #include "base/files/scoped_file.h" #include "base/logging.h" #include "base/notreached.h" -#include "base/task/post_task.h" #include "base/task/sequenced_task_runner.h" #include "base/task/task_runner_util.h" #include "base/task/task_traits.h" @@ -153,7 +152,10 @@ void TestSelectionDevice::SetSelection(struct wl_client* client, CHECK(GetUserDataAs<TestSelectionDevice>(resource)); auto* self = GetUserDataAs<TestSelectionDevice>(resource); auto* src = source ? GetUserDataAs<TestSelectionSource>(source) : nullptr; + self->selection_serial_ = serial; self->delegate_->HandleSetSelection(src, serial); + if (self->manager_) + self->manager_->set_source(src); } TestSelectionDeviceManager::TestSelectionDeviceManager( @@ -171,7 +173,7 @@ void TestSelectionDeviceManager::CreateSource(wl_client* client, uint32_t id) { CHECK(GetUserDataAs<TestSelectionDeviceManager>(manager_resource)); auto* manager = GetUserDataAs<TestSelectionDeviceManager>(manager_resource); - manager->source_ = manager->delegate_->CreateSource(client, id); + manager->delegate_->CreateSource(client, id); } void TestSelectionDeviceManager::GetDevice(wl_client* client, @@ -180,7 +182,9 @@ void TestSelectionDeviceManager::GetDevice(wl_client* client, wl_resource* seat_resource) { CHECK(GetUserDataAs<TestSelectionDeviceManager>(manager_resource)); auto* manager = GetUserDataAs<TestSelectionDeviceManager>(manager_resource); - manager->device_ = manager->delegate_->CreateDevice(client, id); + auto* new_device = manager->delegate_->CreateDevice(client, id); + new_device->set_manager(manager); + manager->device_ = new_device; } } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/test_selection_device_manager.h b/chromium/ui/ozone/platform/wayland/test/test_selection_device_manager.h index 0d542d65a35..bf4c9578f00 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_selection_device_manager.h +++ b/chromium/ui/ozone/platform/wayland/test/test_selection_device_manager.h @@ -60,6 +60,8 @@ class TestSelectionDeviceManager : public GlobalObject { TestSelectionDevice* device() { return device_; } TestSelectionSource* source() { return source_; } + void set_source(TestSelectionSource* source) { source_ = source; } + // Protocol object requests: static void CreateSource(wl_client* client, wl_resource* manager_resource, @@ -165,14 +167,22 @@ class TestSelectionDevice : public ServerObject { TestSelectionOffer* OnDataOffer(); void OnSelection(TestSelectionOffer* offer); + void set_manager(TestSelectionDeviceManager* manager) { manager_ = manager; } + // Protocol object requests: static void SetSelection(struct wl_client* client, struct wl_resource* resource, struct wl_resource* source, uint32_t serial); + uint32_t selection_serial() const { return selection_serial_; } + private: Delegate* const delegate_; + + uint32_t selection_serial_ = 0; + + TestSelectionDeviceManager* manager_ = nullptr; }; } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/test_subsurface.cc b/chromium/ui/ozone/platform/wayland/test/test_subsurface.cc index 90ba375ba6a..49d946453da 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_subsurface.cc +++ b/chromium/ui/ozone/platform/wayland/test/test_subsurface.cc @@ -15,19 +15,19 @@ void SetPosition(wl_client* client, wl_resource* resource, int32_t x, int32_t y) { - GetUserDataAs<TestSubSurface>(resource)->SetPosition(x, y); + GetUserDataAs<TestSubSurface>(resource)->SetPositionImpl(x, y); } void PlaceAbove(wl_client* client, wl_resource* resource, wl_resource* reference_resource) { - NOTIMPLEMENTED_LOG_ONCE(); + GetUserDataAs<TestSubSurface>(resource)->PlaceAbove(reference_resource); } void PlaceBelow(wl_client* client, wl_resource* resource, wl_resource* sibling_resource) { - NOTIMPLEMENTED_LOG_ONCE(); + GetUserDataAs<TestSubSurface>(resource)->PlaceBelow(sibling_resource); } void SetSync(wl_client* client, wl_resource* resource) { @@ -61,8 +61,9 @@ TestSubSurface::~TestSubSurface() { wl_resource_destroy(augmented_subsurface_->resource()); } -void TestSubSurface::SetPosition(float x, float y) { +void TestSubSurface::SetPositionImpl(float x, float y) { position_ = gfx::PointF(x, y); + SetPosition(x, y); } } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/test_subsurface.h b/chromium/ui/ozone/platform/wayland/test/test_subsurface.h index eb4f1678781..833248e4d4a 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_subsurface.h +++ b/chromium/ui/ozone/platform/wayland/test/test_subsurface.h @@ -29,7 +29,11 @@ class TestSubSurface : public ServerObject { TestSubSurface(const TestSubSurface& rhs) = delete; TestSubSurface& operator=(const TestSubSurface& rhs) = delete; - void SetPosition(float x, float y); + MOCK_METHOD1(PlaceAbove, void(wl_resource* reference_resource)); + MOCK_METHOD1(PlaceBelow, void(wl_resource* sibling_resource)); + MOCK_METHOD2(SetPosition, void(float x, float y)); + + void SetPositionImpl(float x, float y); gfx::PointF position() const { return position_; } void set_sync(bool sync) { sync_ = sync; } diff --git a/chromium/ui/ozone/platform/wayland/test/test_viewport.cc b/chromium/ui/ozone/platform/wayland/test/test_viewport.cc index 04b2ea2c391..8d6cd572d9c 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_viewport.cc +++ b/chromium/ui/ozone/platform/wayland/test/test_viewport.cc @@ -17,7 +17,10 @@ void SetSource(wl_client* client, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height) { - NOTIMPLEMENTED_LOG_ONCE(); + auto* test_vp = GetUserDataAs<TestViewport>(resource); + DCHECK(test_vp); + test_vp->SetSource(wl_fixed_to_double(x), wl_fixed_to_double(y), + wl_fixed_to_double(width), wl_fixed_to_double(height)); } void SetDestination(wl_client* client, @@ -26,7 +29,7 @@ void SetDestination(wl_client* client, int32_t height) { auto* test_vp = GetUserDataAs<TestViewport>(resource); DCHECK(test_vp); - test_vp->SetDestination(width, height); + test_vp->SetDestinationImpl(width, height); } } // namespace @@ -48,8 +51,9 @@ TestViewport::~TestViewport() { mock_surface->set_viewport(nullptr); } -void TestViewport::SetDestination(float width, float height) { +void TestViewport::SetDestinationImpl(float width, float height) { destination_size_ = gfx::SizeF(width, height); + SetDestination(width, height); } } // namespace wl diff --git a/chromium/ui/ozone/platform/wayland/test/test_viewport.h b/chromium/ui/ozone/platform/wayland/test/test_viewport.h index 7be156bbe40..4ac792a0c24 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_viewport.h +++ b/chromium/ui/ozone/platform/wayland/test/test_viewport.h @@ -7,6 +7,7 @@ #include <viewporter-server-protocol.h> +#include "testing/gmock/include/gmock/gmock.h" #include "ui/gfx/geometry/size_f.h" #include "ui/ozone/platform/wayland/test/server_object.h" @@ -23,8 +24,11 @@ class TestViewport : public ServerObject { TestViewport(const TestViewport& rhs) = delete; TestViewport& operator=(const TestViewport& rhs) = delete; + MOCK_METHOD2(SetDestination, void(float x, float y)); + MOCK_METHOD4(SetSource, void(float x, float y, float width, float height)); + gfx::SizeF destination_size() const { return destination_size_; } - void SetDestination(float x, float y); + void SetDestinationImpl(float x, float y); private: // Surface resource that is the ground for this Viewport. diff --git a/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc b/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc index 686c350a99e..964d1445f61 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc +++ b/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.cc @@ -32,6 +32,8 @@ TestWaylandServerThread::TestWaylandServerThread() base::WaitableEvent::InitialState::NOT_SIGNALED), resume_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC, base::WaitableEvent::InitialState::NOT_SIGNALED), + compositor_v4_(4), + compositor_v3_(3), controller_(FROM_HERE) {} TestWaylandServerThread::~TestWaylandServerThread() { @@ -60,8 +62,13 @@ bool TestWaylandServerThread::Start(const ServerConfig& config) { if (wl_display_init_shm(display_.get()) < 0) return false; - if (!compositor_.Initialize(display_.get())) - return false; + if (config.compositor_version == CompositorVersion::kV3) { + if (!compositor_v3_.Initialize(display_.get())) + return false; + } else { + if (!compositor_v4_.Initialize(display_.get())) + return false; + } if (!sub_compositor_.Initialize(display_.get())) return false; if (!viewporter_.Initialize(display_.get())) diff --git a/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.h b/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.h index 4dfe8a53668..2c40b46b4f6 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.h +++ b/chromium/ui/ozone/platform/wayland/test/test_wayland_server_thread.h @@ -46,9 +46,11 @@ struct DisplayDeleter { // Server configuration related enums and structs. enum class ShellVersion { kV6, kStable }; enum class PrimarySelectionProtocol { kNone, kGtk, kZwp }; +enum class CompositorVersion { kV3, kV4 }; struct ServerConfig { ShellVersion shell_version = ShellVersion::kStable; + CompositorVersion compositor_version = CompositorVersion::kV4; PrimarySelectionProtocol primary_selection_protocol = PrimarySelectionProtocol::kNone; }; @@ -151,7 +153,12 @@ class TestWaylandServerThread : public base::Thread, base::WaitableEvent resume_event_; // Represent Wayland global objects - TestCompositor compositor_; + // Compositor version is selected dynamically by server config but version is + // actually set on construction thus both compositor version objects appear + // here. + // TODO(crbug.com/1315587): Refactor this pattern when required. + TestCompositor compositor_v4_; + TestCompositor compositor_v3_; TestSubCompositor sub_compositor_; TestViewporter viewporter_; TestAlphaCompositing alpha_compositing_; diff --git a/chromium/ui/ozone/platform/wayland/test/test_zwp_primary_selection.cc b/chromium/ui/ozone/platform/wayland/test/test_zwp_primary_selection.cc index 6e22a3a4388..447fa6e3568 100644 --- a/chromium/ui/ozone/platform/wayland/test/test_zwp_primary_selection.cc +++ b/chromium/ui/ozone/platform/wayland/test/test_zwp_primary_selection.cc @@ -37,7 +37,7 @@ struct ZwpPrimarySelectionOffer final : public TestSelectionOffer::Delegate { struct ZwpPrimarySelectionDevice final : public TestSelectionDevice::Delegate { TestSelectionOffer* CreateAndSendOffer() override { - const struct zwp_primary_selection_offer_v1_interface kOfferImpl = { + static const struct zwp_primary_selection_offer_v1_interface kOfferImpl = { &TestSelectionOffer::Receive, &Destroy}; wl_resource* device_resource = device->resource(); const int version = wl_resource_get_version(device_resource); @@ -98,7 +98,7 @@ struct ZwpPrimarySelectionDeviceManager ~ZwpPrimarySelectionDeviceManager() override = default; TestSelectionDevice* CreateDevice(wl_client* client, uint32_t id) override { - const struct zwp_primary_selection_device_v1_interface + static const struct zwp_primary_selection_device_v1_interface kTestSelectionDeviceImpl = {&TestSelectionDevice::SetSelection, &Destroy}; auto* delegate = new ZwpPrimarySelectionDevice; @@ -110,7 +110,7 @@ struct ZwpPrimarySelectionDeviceManager } TestSelectionSource* CreateSource(wl_client* client, uint32_t id) override { - const struct zwp_primary_selection_source_v1_interface + static const struct zwp_primary_selection_source_v1_interface kTestSelectionSourceImpl = {&TestSelectionSource::Offer, &Destroy}; auto* delegate = new ZwpPrimarySelectionSource; wl_resource* resource = CreateResourceWithImpl<TestSelectionSource>( @@ -130,7 +130,7 @@ struct ZwpPrimarySelectionDeviceManager TestSelectionDeviceManager* CreateTestSelectionManagerZwp() { constexpr uint32_t kVersion = 1; - const struct zwp_primary_selection_device_manager_v1_interface + static const struct zwp_primary_selection_device_manager_v1_interface kTestSelectionManagerImpl = {&TestSelectionDeviceManager::CreateSource, &TestSelectionDeviceManager::GetDevice, &Destroy}; 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 87d7814b43a..ef4c9720cd9 100644 --- a/chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/wayland_buffer_manager_unittest.cc @@ -16,6 +16,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/geometry/rounded_corners_f.h" #include "ui/gfx/geometry/rrect_f.h" +#include "ui/gfx/geometry/transform.h" #include "ui/gfx/gpu_fence_handle.h" #include "ui/gfx/linux/drm_util_linux.h" #include "ui/gfx/overlay_priority_hint.h" @@ -198,12 +199,10 @@ class WaylandBufferManagerTest : public WaylandTest { Sync(); } - void DestroyBufferAndSetTerminateExpectation(gfx::AcceleratedWidget widget, - uint32_t buffer_id, - bool fail) { + void DestroyBufferAndSetTerminateExpectation(uint32_t buffer_id, bool fail) { SetTerminateCallbackExpectationAndDestroyChannel(&callback_, fail); - buffer_manager_gpu_->DestroyBuffer(widget, buffer_id); + buffer_manager_gpu_->DestroyBuffer(buffer_id); Sync(); } @@ -255,8 +254,7 @@ TEST_P(WaylandBufferManagerTest, CreateDmabufBasedBuffers) { CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kDmabufBufferId); - DestroyBufferAndSetTerminateExpectation(gfx::kNullAcceleratedWidget, - kDmabufBufferId, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kDmabufBufferId, false /*fail*/); } TEST_P(WaylandBufferManagerTest, VerifyModifiers) { @@ -306,8 +304,7 @@ TEST_P(WaylandBufferManagerTest, VerifyModifiers) { EXPECT_EQ(params_vector[0]->modifier_lo_, kFormatModiferLinear & UINT32_MAX); // Clean up. - DestroyBufferAndSetTerminateExpectation(gfx::kNullAcceleratedWidget, - kDmabufBufferId, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kDmabufBufferId, false /*fail*/); } TEST_P(WaylandBufferManagerTest, CreateShmBasedBuffers) { @@ -315,8 +312,7 @@ TEST_P(WaylandBufferManagerTest, CreateShmBasedBuffers) { CreateShmBasedBufferAndSetTerminateExpecation(false /*fail*/, kShmBufferId); - DestroyBufferAndSetTerminateExpectation(gfx::kNullAcceleratedWidget, - kShmBufferId, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kShmBufferId, false /*fail*/); } TEST_P(WaylandBufferManagerTest, ValidateDataFromGpu) { @@ -377,8 +373,9 @@ TEST_P(WaylandBufferManagerTest, CreateAndDestroyBuffer) { CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId1); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, window_->GetBounds(), - kDefaultScale, window_->GetBounds()); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, + window_->GetBounds(), kDefaultScale, + window_->GetBounds()); CreateDmabufBasedBufferAndSetTerminateExpectation(true /*fail*/, kBufferId1); @@ -387,11 +384,10 @@ TEST_P(WaylandBufferManagerTest, CreateAndDestroyBuffer) { // ... impossible to destroy non-existing buffer. { // Either it is attached... - DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, true /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId1, true /*fail*/); // Or not attached. - DestroyBufferAndSetTerminateExpectation(gfx::kNullAcceleratedWidget, - kBufferId1, true /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId1, true /*fail*/); } // Can destroy the buffer without specifying the widget. @@ -400,11 +396,11 @@ TEST_P(WaylandBufferManagerTest, CreateAndDestroyBuffer) { CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId1); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, window_->GetBounds(), - kDefaultScale, window_->GetBounds()); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, + window_->GetBounds(), kDefaultScale, + window_->GetBounds()); - DestroyBufferAndSetTerminateExpectation(gfx::kNullAcceleratedWidget, - kBufferId1, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId1, false /*fail*/); } // Still can destroy the buffer even if it has not been attached to any @@ -413,7 +409,7 @@ TEST_P(WaylandBufferManagerTest, CreateAndDestroyBuffer) { EXPECT_CALL(*server_.zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(1); CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId1); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId1, false /*fail*/); } // ... impossible to destroy buffers twice. @@ -422,30 +418,28 @@ TEST_P(WaylandBufferManagerTest, CreateAndDestroyBuffer) { CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId1); // Attach to a surface. - buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, window_->GetBounds(), - kDefaultScale, window_->GetBounds()); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, + window_->GetBounds(), kDefaultScale, + window_->GetBounds()); // Created non-attached buffer as well. CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId2); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId1, false /*fail*/); // Can't destroy the buffer with non-existing id (the manager cleared the // state after the previous failure). - DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, true /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId1, true /*fail*/); // Non-attached buffer must have been also destroyed (we can't destroy it // twice) if there was a failure. - DestroyBufferAndSetTerminateExpectation(gfx::kNullAcceleratedWidget, - kBufferId2, true /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId2, true /*fail*/); // Create and destroy non-attached buffer twice. CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId2); - DestroyBufferAndSetTerminateExpectation(gfx::kNullAcceleratedWidget, - kBufferId2, false /*fail*/); - DestroyBufferAndSetTerminateExpectation(gfx::kNullAcceleratedWidget, - kBufferId2, true /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId2, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId2, true /*fail*/); } } @@ -455,7 +449,7 @@ TEST_P(WaylandBufferManagerTest, CommitBufferNonExistingBufferId) { // Can't commit for non-existing buffer id. SetTerminateCallbackExpectationAndDestroyChannel(&callback_, true /*fail*/); - buffer_manager_gpu_->CommitBuffer(window_->GetWidget(), 5u, + buffer_manager_gpu_->CommitBuffer(window_->GetWidget(), 1u, 5u, window_->GetBounds(), kDefaultScale, window_->GetBounds()); @@ -483,7 +477,7 @@ TEST_P(WaylandBufferManagerTest, CommitOverlaysNonExistingBufferId) { false, 1.0f, gfx::GpuFenceHandle(), gfx::OverlayPriorityHint::kNone, gfx::RRectF())); - buffer_manager_gpu_->CommitOverlays(window_->GetWidget(), + buffer_manager_gpu_->CommitOverlays(window_->GetWidget(), 1u, std::move(overlay_configs)); Sync(); @@ -508,7 +502,7 @@ TEST_P(WaylandBufferManagerTest, CommitOverlaysWithSameBufferId) { false, 1.0f, gfx::GpuFenceHandle(), gfx::OverlayPriorityHint::kNone, gfx::RRectF())); - buffer_manager_gpu_->CommitOverlays(window_->GetWidget(), + buffer_manager_gpu_->CommitOverlays(window_->GetWidget(), 1u, std::move(overlay_configs)); Sync(); @@ -516,10 +510,9 @@ TEST_P(WaylandBufferManagerTest, CommitOverlaysWithSameBufferId) { false /* fail */); // Destroying the buffer causes all wl_buffer objects to be destroyed. - DestroyBufferAndSetTerminateExpectation(window_->GetWidget(), 1u, - false /*fail*/); + DestroyBufferAndSetTerminateExpectation(1u, false /*fail*/); SetTerminateCallbackExpectationAndDestroyChannel(&callback_, true /*fail*/); - buffer_manager_gpu_->CommitBuffer(window_->GetWidget(), 1u, + buffer_manager_gpu_->CommitBuffer(window_->GetWidget(), 1u, 1u, window_->GetBounds(), kDefaultScale, window_->GetBounds()); Sync(); @@ -532,7 +525,7 @@ TEST_P(WaylandBufferManagerTest, CommitBufferNullWidget) { // Can't commit for non-existing widget. SetTerminateCallbackExpectationAndDestroyChannel(&callback_, true /*fail*/); - buffer_manager_gpu_->CommitBuffer(gfx::kNullAcceleratedWidget, kBufferId, + buffer_manager_gpu_->CommitBuffer(gfx::kNullAcceleratedWidget, 1u, kBufferId, window_->GetBounds(), kDefaultScale, window_->GetBounds()); @@ -564,7 +557,7 @@ TEST_P(WaylandBufferManagerTest, CommitOverlaysNonsensicalBoundsRect) { bounds_rect, gfx::RectF(), window_->GetBounds(), false, 1.0f, gfx::GpuFenceHandle(), gfx::OverlayPriorityHint::kNone, gfx::RRectF())); - buffer_manager_gpu_->CommitOverlays(window_->GetWidget(), + buffer_manager_gpu_->CommitOverlays(window_->GetWidget(), 1u, std::move(overlay_configs)); Sync(); @@ -612,8 +605,8 @@ TEST_P(WaylandBufferManagerTest, EnsureCorrectOrderOfCallbacks) { ASSERT_TRUE(!connection_->presentation()); EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, + kDefaultScale, bounds); Sync(); @@ -624,8 +617,8 @@ TEST_P(WaylandBufferManagerTest, EnsureCorrectOrderOfCallbacks) { Sync(); // Commit second buffer now. - buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, + kDefaultScale, bounds); Sync(); @@ -654,8 +647,8 @@ TEST_P(WaylandBufferManagerTest, EnsureCorrectOrderOfCallbacks) { .Times(1); // Commit second buffer now. - buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, + kDefaultScale, bounds); Sync(); @@ -680,8 +673,8 @@ TEST_P(WaylandBufferManagerTest, EnsureCorrectOrderOfCallbacks) { Sync(); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId2, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId1, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId2, false /*fail*/); } TEST_P(WaylandBufferManagerTest, @@ -732,8 +725,8 @@ TEST_P(WaylandBufferManagerTest, EXPECT_CALL(mock_surface_gpu, OnSubmission(kBufferId1, gfx::SwapResult::SWAP_ACK, _)) .Times(1); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, + kDefaultScale, bounds); mock_surface->SendFrameCallback(); Sync(); @@ -742,8 +735,8 @@ TEST_P(WaylandBufferManagerTest, mock_wp_presentation->set_presentation_callback(nullptr); // Commit second buffer now. - buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, + kDefaultScale, bounds); mock_surface->SendFrameCallback(); Sync(); @@ -752,7 +745,7 @@ TEST_P(WaylandBufferManagerTest, EXPECT_CALL(mock_surface_gpu, OnSubmission(kBufferId2, gfx::SwapResult::SWAP_ACK, _)) .Times(1); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, /*fail=*/false); + DestroyBufferAndSetTerminateExpectation(kBufferId1, /*fail=*/false); mock_surface->DestroyPrevAttachedBuffer(); mock_surface->SendFrameCallback(); Sync(); @@ -764,8 +757,8 @@ TEST_P(WaylandBufferManagerTest, // 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, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, kBufferId3, bounds, + kDefaultScale, bounds); mock_surface->SendFrameCallback(); mock_wp_presentation->SendPresentationCallback(); Sync(); @@ -792,13 +785,13 @@ TEST_P(WaylandBufferManagerTest, ::testing::Eq(gfx::PresentationFeedback::Flags::kFailure)))) .Times(1); EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId3, _)).Times(1); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId2, /*fail=*/false); + DestroyBufferAndSetTerminateExpectation(kBufferId2, /*fail=*/false); mock_surface->DestroyPrevAttachedBuffer(); mock_surface->SendFrameCallback(); mock_wp_presentation->SendPresentationCallback(); Sync(); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId3, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId3, false /*fail*/); } // This test ensures that a discarded presentation feedback sent prior receiving @@ -847,8 +840,8 @@ TEST_P(WaylandBufferManagerTest, EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0); // Commit first buffer - buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, + kDefaultScale, bounds); Sync(); @@ -866,8 +859,8 @@ TEST_P(WaylandBufferManagerTest, EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0); // Commit second buffer - buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, + kDefaultScale, bounds); Sync(); @@ -887,8 +880,8 @@ TEST_P(WaylandBufferManagerTest, EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0); // Commit third buffer - buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, kBufferId3, bounds, + kDefaultScale, bounds); Sync(); @@ -944,9 +937,9 @@ TEST_P(WaylandBufferManagerTest, Sync(); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId2, false /*fail*/); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId3, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId1, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId2, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId3, false /*fail*/); } TEST_P(WaylandBufferManagerTest, TestCommitBufferConditions) { @@ -972,7 +965,7 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditions) { EXPECT_CALL(*mock_surface, Frame(_)).Times(0); EXPECT_CALL(*mock_surface, Commit()).Times(0); - buffer_manager_gpu_->CommitBuffer(widget, kDmabufBufferId, + buffer_manager_gpu_->CommitBuffer(widget, kDmabufBufferId, kDmabufBufferId, window_->GetBounds(), kDefaultScale, window_->GetBounds()); Sync(); @@ -1006,7 +999,7 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditions) { EXPECT_CALL(*mock_surface, Frame(_)).Times(0); EXPECT_CALL(*mock_surface, Commit()).Times(0); - buffer_manager_gpu_->CommitBuffer(widget, kDmabufBufferId2, + buffer_manager_gpu_->CommitBuffer(widget, kDmabufBufferId2, kDmabufBufferId2, window_->GetBounds(), kDefaultScale, window_->GetBounds()); @@ -1021,10 +1014,8 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditions) { Sync(); - DestroyBufferAndSetTerminateExpectation(widget, kDmabufBufferId, - false /*fail*/); - DestroyBufferAndSetTerminateExpectation(widget, kDmabufBufferId2, - false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kDmabufBufferId, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kDmabufBufferId2, false /*fail*/); } // Tests the surface does not have buffers attached until it's configured at @@ -1069,7 +1060,7 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditionsAckConfigured) { EXPECT_CALL(*mock_surface, Frame(_)).Times(0); EXPECT_CALL(*mock_surface, Commit()).Times(0); - buffer_manager_gpu_->CommitBuffer(widget, kDmabufBufferId, + buffer_manager_gpu_->CommitBuffer(widget, kDmabufBufferId, kDmabufBufferId, window_->GetBounds(), kDefaultScale, window_->GetBounds()); Sync(); @@ -1085,8 +1076,7 @@ TEST_P(WaylandBufferManagerTest, TestCommitBufferConditionsAckConfigured) { window_->SetPointerFocus(false); temp_window.reset(); - DestroyBufferAndSetTerminateExpectation(widget, kDmabufBufferId, - false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kDmabufBufferId, false /*fail*/); Sync(); } @@ -1132,8 +1122,8 @@ TEST_P(WaylandBufferManagerTest, AnonymousBufferAttachedAndReleased) { EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1); // Commit second buffer now. - buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, + kDefaultScale, bounds); Sync(); @@ -1157,8 +1147,8 @@ TEST_P(WaylandBufferManagerTest, AnonymousBufferAttachedAndReleased) { EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId2, _)).Times(1); // Commit second buffer now. - buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, + kDefaultScale, bounds); Sync(); @@ -1182,8 +1172,8 @@ TEST_P(WaylandBufferManagerTest, AnonymousBufferAttachedAndReleased) { .Times(0); EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId3, _)).Times(0); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, kBufferId3, bounds, + kDefaultScale, bounds); Sync(); @@ -1203,9 +1193,9 @@ TEST_P(WaylandBufferManagerTest, AnonymousBufferAttachedAndReleased) { Sync(); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId2, false /*fail*/); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId3, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId1, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId2, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId3, false /*fail*/); } TEST_P(WaylandBufferManagerTest, DestroyBufferForDestroyedWindow) { @@ -1219,13 +1209,14 @@ TEST_P(WaylandBufferManagerTest, DestroyBufferForDestroyedWindow) { Sync(); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId, temp_window->GetBounds(), - kDefaultScale, temp_window->GetBounds()); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId, kBufferId, + temp_window->GetBounds(), kDefaultScale, + temp_window->GetBounds()); Sync(); temp_window.reset(); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId, false /*fail*/); } TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionSingleBuffer) { @@ -1252,12 +1243,12 @@ TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionSingleBuffer) { temp_window.reset(); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId, kBufferId, bounds, + kDefaultScale, bounds); Sync(); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId, false /*fail*/); } TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionMultipleBuffers) { @@ -1294,8 +1285,8 @@ TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionMultipleBuffers) { EXPECT_CALL(mock_surface_gpu, OnSubmission(_, _, _)).Times(1); EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(1); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, + kDefaultScale, bounds); Sync(); @@ -1315,8 +1306,8 @@ TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionMultipleBuffers) { .Times(1); EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId2, _)).Times(1); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, + kDefaultScale, bounds); Sync(); @@ -1328,13 +1319,13 @@ TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionMultipleBuffers) { EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0); temp_window.reset(); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, + kDefaultScale, bounds); Sync(); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId2, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId1, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId2, false /*fail*/); } // Tests that OnSubmission and OnPresentation are properly triggered if a buffer @@ -1365,8 +1356,8 @@ TEST_P(WaylandBufferManagerTest, DestroyBufferCommittedTwiceInARow) { .Times(1); EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, + kDefaultScale, bounds); mock_surface->SendFrameCallback(); Sync(); testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); @@ -1375,20 +1366,20 @@ TEST_P(WaylandBufferManagerTest, DestroyBufferCommittedTwiceInARow) { EXPECT_CALL(mock_surface_gpu, OnSubmission(_, _, _)).Times(0); EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, + kDefaultScale, bounds); mock_surface->SendFrameCallback(); Sync(); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, + kDefaultScale, bounds); mock_surface->SendFrameCallback(); Sync(); testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); // Destroying buffer2 should do nothing yet. - DestroyBufferAndSetTerminateExpectation(widget, kBufferId2, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId2, false /*fail*/); Sync(); testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); @@ -1398,7 +1389,7 @@ TEST_P(WaylandBufferManagerTest, DestroyBufferCommittedTwiceInARow) { OnSubmission(kBufferId2, gfx::SwapResult::SWAP_ACK, _)) .Times(2); EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId2, _)).Times(2); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId1, false /*fail*/); Sync(); testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); @@ -1432,8 +1423,8 @@ TEST_P(WaylandBufferManagerTest, ReleaseBufferCommittedTwiceInARow) { .Times(1); EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, + kDefaultScale, bounds); mock_surface->SendFrameCallback(); Sync(); testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); @@ -1443,13 +1434,13 @@ TEST_P(WaylandBufferManagerTest, ReleaseBufferCommittedTwiceInARow) { EXPECT_CALL(mock_surface_gpu, OnSubmission(_, _, _)).Times(0); EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, + kDefaultScale, bounds); mock_surface->SendFrameCallback(); Sync(); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, + kDefaultScale, bounds); mock_surface->SendFrameCallback(); Sync(); @@ -1465,8 +1456,8 @@ TEST_P(WaylandBufferManagerTest, ReleaseBufferCommittedTwiceInARow) { testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId2, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId1, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId2, false /*fail*/); } // Tests that OnSubmission and OnPresentation callbacks are properly called @@ -1500,8 +1491,8 @@ TEST_P(WaylandBufferManagerTest, ReleaseOrderDifferentToCommitOrder) { EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1); EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(1); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, + kDefaultScale, bounds); mock_surface->SendFrameCallback(); Sync(); testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); @@ -1512,14 +1503,14 @@ TEST_P(WaylandBufferManagerTest, ReleaseOrderDifferentToCommitOrder) { EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0); EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(2); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, + kDefaultScale, bounds); mock_surface->SendFrameCallback(); Sync(); auto* wl_buffer2 = mock_surface->attached_buffer(); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, kBufferId3, bounds, + kDefaultScale, bounds); mock_surface->SendFrameCallback(); Sync(); @@ -1547,9 +1538,9 @@ TEST_P(WaylandBufferManagerTest, ReleaseOrderDifferentToCommitOrder) { testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId2, false /*fail*/); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId3, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId1, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId2, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId3, false /*fail*/); } // This test verifies that submitting the buffer more than once results in @@ -1589,8 +1580,8 @@ TEST_P(WaylandBufferManagerTest, .Times(1); EXPECT_CALL(*mock_surface, Commit()).Times(1); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, + kDefaultScale, bounds); Sync(); @@ -1612,8 +1603,8 @@ TEST_P(WaylandBufferManagerTest, EXPECT_CALL(*mock_surface, Commit()).Times(1); // Commit second buffer now. - buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, + kDefaultScale, bounds); Sync(); @@ -1654,8 +1645,8 @@ TEST_P(WaylandBufferManagerTest, EXPECT_CALL(*mock_surface, Commit()).Times(1); // Commit second buffer now. - buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, + kDefaultScale, bounds); Sync(); @@ -1689,8 +1680,8 @@ TEST_P(WaylandBufferManagerTest, .Times(1); EXPECT_CALL(*mock_surface, Commit()).Times(1); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, + kDefaultScale, bounds); Sync(); @@ -1710,8 +1701,8 @@ TEST_P(WaylandBufferManagerTest, testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId2, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId1, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId2, false /*fail*/); } // Tests that submitting a single buffer only receives an OnSubmission. This is @@ -1739,11 +1730,11 @@ TEST_P(WaylandBufferManagerTest, OnSubmissionCalledForSingleBuffer) { .Times(1); EXPECT_CALL(mock_surface_gpu, OnPresentation(kBufferId1, _)).Times(1); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, + kDefaultScale, bounds); Sync(); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId1, false /*fail*/); } // Tests that when CommitOverlays(), root_surface can only be committed once all @@ -1796,7 +1787,7 @@ TEST_P(WaylandBufferManagerTest, RootSurfaceIsCommittedLast) { 1, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE, kBufferId3, kDefaultScale, gfx::RectF(bounds), gfx::RectF(), bounds, false, 1.0f, gfx::GpuFenceHandle(), gfx::OverlayPriorityHint::kNone, gfx::RRectF())); - buffer_manager_gpu_->CommitOverlays(window_->GetWidget(), + buffer_manager_gpu_->CommitOverlays(window_->GetWidget(), 1u, std::move(overlay_configs)); Sync(); testing::Mock::VerifyAndClearExpectations(mock_surface); @@ -1854,14 +1845,14 @@ TEST_P(WaylandBufferManagerTest, FencedRelease) { OnSubmission(kBufferId1, gfx::SwapResult::SWAP_ACK, Truly([](const auto& fence) { return fence.is_null(); }))) .Times(1); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, + kDefaultScale, bounds); mock_surface->SendFrameCallback(); Sync(); // Commit the second buffer now. - buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId2, kBufferId2, bounds, + kDefaultScale, bounds); mock_surface->SendFrameCallback(); Sync(); @@ -1881,8 +1872,8 @@ TEST_P(WaylandBufferManagerTest, FencedRelease) { Sync(); // Commit the third buffer now. - buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId3, kBufferId3, bounds, + kDefaultScale, bounds); mock_surface->SendFrameCallback(); Sync(); @@ -1899,9 +1890,9 @@ TEST_P(WaylandBufferManagerTest, FencedRelease) { Sync(); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId2, false /*fail*/); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId3, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId1, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId2, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId3, false /*fail*/); } // Tests that destroying a channel doesn't result in resetting surface state @@ -1937,8 +1928,8 @@ TEST_P(WaylandBufferManagerTest, .Times(1); EXPECT_CALL(*mock_surface_gpu.get(), OnPresentation(kBufferId1, _)).Times(1); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, + kDefaultScale, bounds); Sync(); // The root surface shouldn't get null buffer attached. @@ -1989,11 +1980,11 @@ TEST_P(WaylandBufferManagerTest, .Times(1); EXPECT_CALL(*mock_surface_gpu.get(), OnPresentation(kBufferId1, _)).Times(1); - buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, bounds, kDefaultScale, - bounds); + buffer_manager_gpu_->CommitBuffer(widget, kBufferId1, kBufferId1, bounds, + kDefaultScale, bounds); Sync(); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId1, false /*fail*/); } // Tests that destroying a channel results in attaching null buffers to the root @@ -2035,7 +2026,7 @@ TEST_P(WaylandBufferManagerTest, HidesSubsurfacesOnChannelDestroyed) { 1, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE, kBufferId3, kDefaultScale, gfx::RectF(bounds), gfx::RectF(), bounds, false, 1.0f, gfx::GpuFenceHandle(), gfx::OverlayPriorityHint::kNone, gfx::RRectF())); - buffer_manager_gpu_->CommitOverlays(window_->GetWidget(), + buffer_manager_gpu_->CommitOverlays(window_->GetWidget(), 1u, std::move(overlay_configs)); Sync(); @@ -2097,7 +2088,7 @@ TEST_P(WaylandBufferManagerTest, HidesSubsurfacesOnChannelDestroyed) { kDefaultScale, gfx::RectF(bounds), gfx::RectF(), bounds, false, 1.0f, gfx::GpuFenceHandle(), gfx::OverlayPriorityHint::kNone, gfx::RRectF())); - buffer_manager_gpu_->CommitOverlays(window_->GetWidget(), + buffer_manager_gpu_->CommitOverlays(window_->GetWidget(), 2u, std::move(overlay_configs2)); Sync(); @@ -2170,6 +2161,7 @@ TEST_P(WaylandBufferManagerTest, CanSubmitOverlayPriority) { {gfx::OverlayPriorityHint::kHardwareProtection, OVERLAY_PRIORITIZED_SURFACE_OVERLAY_PRIORITY_REQUIRED_HARDWARE_PROTECTION}}; + uint32_t frame_id = 0u; for (const auto& priority : priorities) { std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlay_configs; for (auto id : kBufferIds) { @@ -2180,7 +2172,7 @@ TEST_P(WaylandBufferManagerTest, CanSubmitOverlayPriority) { false, 1.0f, gfx::GpuFenceHandle(), priority.first, gfx::RRectF())); } - buffer_manager_gpu_->CommitOverlays(window_->GetWidget(), + buffer_manager_gpu_->CommitOverlays(window_->GetWidget(), ++frame_id, std::move(overlay_configs)); Sync(); @@ -2246,6 +2238,7 @@ TEST_P(WaylandBufferManagerTest, CanSetRoundedCorners) { // Exo may allow to submit values in px. std::vector<bool> in_pixels = {true, false}; + uint32_t frame_id = 0u; for (auto is_in_px : in_pixels) { connection_->set_surface_submission_in_pixel_coordinates(is_in_px); for (auto scale_factor : scale_factors) { @@ -2260,7 +2253,7 @@ TEST_P(WaylandBufferManagerTest, CanSetRoundedCorners) { gfx::OverlayPriorityHint::kNone, rounded_corners)); } - buffer_manager_gpu_->CommitOverlays(window_->GetWidget(), + buffer_manager_gpu_->CommitOverlays(window_->GetWidget(), ++frame_id, std::move(overlay_configs)); Sync(); @@ -2367,7 +2360,8 @@ TEST_P(WaylandBufferManagerTest, FeedbacksAreDiscardedIfClientMisbehaves) { EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0); } - buffer_manager_gpu_->CommitBuffer(widget, next_buffer_id_commit, bounds, + buffer_manager_gpu_->CommitBuffer(widget, next_buffer_id_commit, + next_buffer_id_commit, bounds, kDefaultScale, bounds); Sync(); @@ -2384,8 +2378,8 @@ TEST_P(WaylandBufferManagerTest, FeedbacksAreDiscardedIfClientMisbehaves) { testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); } - DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/); - DestroyBufferAndSetTerminateExpectation(widget, kBufferId2, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId1, false /*fail*/); + DestroyBufferAndSetTerminateExpectation(kBufferId2, false /*fail*/); } TEST_P(WaylandBufferManagerTest, ExecutesTasksAfterInitialization) { @@ -2401,10 +2395,9 @@ TEST_P(WaylandBufferManagerTest, ExecutesTasksAfterInitialization) { CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kDmabufBufferId); buffer_manager_gpu_->CommitBuffer(window_->GetWidget(), kDmabufBufferId, - window_->GetBounds(), kDefaultScale, - window_->GetBounds()); - DestroyBufferAndSetTerminateExpectation(gfx::kNullAcceleratedWidget, - kDmabufBufferId, false /*fail*/); + kDmabufBufferId, window_->GetBounds(), + kDefaultScale, window_->GetBounds()); + DestroyBufferAndSetTerminateExpectation(kDmabufBufferId, false /*fail*/); base::RunLoop().RunUntilIdle(); @@ -2478,7 +2471,7 @@ class WaylandBufferManagerViewportTest : public WaylandBufferManagerTest { bounds_rect, gfx::RectF(), temp_window->GetBounds(), false, 1.0f, gfx::GpuFenceHandle(), gfx::OverlayPriorityHint::kNone, gfx::RRectF())); - buffer_manager_gpu_->CommitOverlays(temp_window->GetWidget(), + buffer_manager_gpu_->CommitOverlays(temp_window->GetWidget(), 1u, std::move(overlay_configs)); Sync(); @@ -2513,10 +2506,8 @@ class WaylandBufferManagerViewportTest : public WaylandBufferManagerTest { mock_surface_of_subsurface->SendFrameCallback(); mock_surface->SendFrameCallback(); - DestroyBufferAndSetTerminateExpectation(gfx::kNullAcceleratedWidget, - kBufferId1, false); - DestroyBufferAndSetTerminateExpectation(gfx::kNullAcceleratedWidget, - kBufferId2, false); + DestroyBufferAndSetTerminateExpectation(kBufferId1, false); + DestroyBufferAndSetTerminateExpectation(kBufferId2, false); } }; diff --git a/chromium/ui/ozone/platform/windows/BUILD.gn b/chromium/ui/ozone/platform/windows/BUILD.gn deleted file mode 100644 index f5f44c2d3a3..00000000000 --- a/chromium/ui/ozone/platform/windows/BUILD.gn +++ /dev/null @@ -1,39 +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. - -visibility = [ "//ui/ozone/*" ] - -source_set("windows") { - sources = [ - "client_native_pixmap_factory_windows.cc", - "client_native_pixmap_factory_windows.h", - "ozone_platform_windows.cc", - "ozone_platform_windows.h", - "windows_surface_factory.cc", - "windows_surface_factory.h", - "windows_window.cc", - "windows_window.h", - "windows_window_manager.cc", - "windows_window_manager.h", - ] - - defines = [ "OZONE_IMPLEMENTATION" ] - - deps = [ - "//base", - "//skia", - "//ui/base", - "//ui/base/cursor", - "//ui/display/fake", - "//ui/events", - "//ui/events/ozone/layout", - "//ui/events/platform", - "//ui/gfx/geometry", - "//ui/gl", - "//ui/ozone:ozone_base", - "//ui/ozone/common", - "//ui/platform_window", - "//ui/platform_window/win", - ] -} diff --git a/chromium/ui/ozone/platform/windows/DEPS b/chromium/ui/ozone/platform/windows/DEPS deleted file mode 100644 index c73fab35723..00000000000 --- a/chromium/ui/ozone/platform/windows/DEPS +++ /dev/null @@ -1,3 +0,0 @@ -include_rules = [ - "+ui/base/win", -] diff --git a/chromium/ui/ozone/platform/windows/client_native_pixmap_factory_windows.cc b/chromium/ui/ozone/platform/windows/client_native_pixmap_factory_windows.cc deleted file mode 100644 index 30187da1ea6..00000000000 --- a/chromium/ui/ozone/platform/windows/client_native_pixmap_factory_windows.cc +++ /dev/null @@ -1,16 +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/windows/client_native_pixmap_factory_windows.h" - -#include "ui/ozone/common/stub_client_native_pixmap_factory.h" - -namespace ui { - -gfx::ClientNativePixmapFactory* CreateClientNativePixmapFactoryWindows() { - // TODO(camurcu): Implement the better (more performant) way. - return CreateStubClientNativePixmapFactory(); -} - -} // namespace ui diff --git a/chromium/ui/ozone/platform/windows/client_native_pixmap_factory_windows.h b/chromium/ui/ozone/platform/windows/client_native_pixmap_factory_windows.h deleted file mode 100644 index 542e448d042..00000000000 --- a/chromium/ui/ozone/platform/windows/client_native_pixmap_factory_windows.h +++ /dev/null @@ -1,19 +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_WINDOWS_CLIENT_NATIVE_PIXMAP_FACTORY_WINDOWS_H_ -#define UI_OZONE_PLATFORM_WINDOWS_CLIENT_NATIVE_PIXMAP_FACTORY_WINDOWS_H_ - -namespace gfx { -class ClientNativePixmapFactory; -} - -namespace ui { - -// Constructor hook for use in constructor_list.cc -gfx::ClientNativePixmapFactory* CreateClientNativePixmapFactoryWindows(); - -} // namespace ui - -#endif // UI_OZONE_PLATFORM_WINDOWS_CLIENT_NATIVE_PIXMAP_FACTORY_WINDOWS_H_ diff --git a/chromium/ui/ozone/platform/windows/ozone_platform_windows.cc b/chromium/ui/ozone/platform/windows/ozone_platform_windows.cc deleted file mode 100644 index 2e37a740197..00000000000 --- a/chromium/ui/ozone/platform/windows/ozone_platform_windows.cc +++ /dev/null @@ -1,129 +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/windows/ozone_platform_windows.h" - -#include <memory> - -#include "base/command_line.h" -#include "base/files/file_path.h" -#include "base/memory/ptr_util.h" -#include "ui/base/cursor/cursor_factory.h" -#include "ui/base/win/win_cursor_factory.h" -#include "ui/display/fake/fake_display_delegate.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/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" -#include "ui/ozone/platform/windows/windows_window_manager.h" -#include "ui/ozone/public/gpu_platform_support_host.h" -#include "ui/ozone/public/input_controller.h" -#include "ui/ozone/public/ozone_platform.h" -#include "ui/ozone/public/ozone_switches.h" -#include "ui/ozone/public/system_input_injector.h" -#include "ui/platform_window/platform_window_init_properties.h" - -namespace ui { - -namespace { - -// dummy class -class WindowsPlatformEventSource : public ui::PlatformEventSource { - public: - WindowsPlatformEventSource() = default; - - WindowsPlatformEventSource(const WindowsPlatformEventSource&) = delete; - WindowsPlatformEventSource& operator=(const WindowsPlatformEventSource&) = - delete; - - ~WindowsPlatformEventSource() override = default; -}; - -// OzonePlatform for Windows -class OzonePlatformWindows : public OzonePlatform { - public: - OzonePlatformWindows() {} - - OzonePlatformWindows(const OzonePlatformWindows&) = delete; - OzonePlatformWindows& operator=(const OzonePlatformWindows&) = delete; - - ~OzonePlatformWindows() override {} - - // OzonePlatform: - ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() override { - return surface_factory_.get(); - } - OverlayManagerOzone* GetOverlayManager() override { - return overlay_manager_.get(); - } - CursorFactory* GetCursorFactory() override { return cursor_factory_.get(); } - InputController* GetInputController() override { - return input_controller_.get(); - } - GpuPlatformSupportHost* GetGpuPlatformSupportHost() override { - return gpu_platform_support_host_.get(); - } - std::unique_ptr<SystemInputInjector> CreateSystemInputInjector() override { - return nullptr; // no input injection support. - } - std::unique_ptr<PlatformWindow> CreatePlatformWindow( - PlatformWindowDelegate* delegate, - PlatformWindowInitProperties properties) override { - return std::make_unique<WindowsWindow>(delegate, properties.bounds); - } - std::unique_ptr<display::NativeDisplayDelegate> CreateNativeDisplayDelegate() - override { - return std::make_unique<display::FakeDisplayDelegate>(); - } - std::unique_ptr<InputMethod> CreateInputMethod( - internal::InputMethodDelegate* delegate, - gfx::AcceleratedWidget) override { - NOTREACHED(); - return nullptr; - } - - bool InitializeUI(const InitParams& params) override { - window_manager_ = std::make_unique<WindowsWindowManager>(); - surface_factory_ = std::make_unique<WindowsSurfaceFactory>(); - // This unbreaks tests that create their own. - if (!PlatformEventSource::GetInstance()) - platform_event_source_ = std::make_unique<WindowsPlatformEventSource>(); - keyboard_layout_engine_ = std::make_unique<StubKeyboardLayoutEngine>(); - KeyboardLayoutEngineManager::SetKeyboardLayoutEngine( - keyboard_layout_engine_.get()); - - overlay_manager_ = std::make_unique<StubOverlayManager>(); - input_controller_ = CreateStubInputController(); - cursor_factory_ = std::make_unique<WinCursorFactory>(); - gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost()); - - return true; - } - - void InitializeGPU(const InitParams& params) override { - if (!surface_factory_) - surface_factory_ = std::make_unique<WindowsSurfaceFactory>(); - } - - private: - std::unique_ptr<KeyboardLayoutEngine> keyboard_layout_engine_; - std::unique_ptr<WindowsWindowManager> window_manager_; - std::unique_ptr<WindowsSurfaceFactory> surface_factory_; - std::unique_ptr<PlatformEventSource> platform_event_source_; - std::unique_ptr<CursorFactory> cursor_factory_; - std::unique_ptr<InputController> input_controller_; - std::unique_ptr<GpuPlatformSupportHost> gpu_platform_support_host_; - std::unique_ptr<OverlayManagerOzone> overlay_manager_; -}; - -} // namespace - -OzonePlatform* CreateOzonePlatformWindows() { - return new OzonePlatformWindows; -} - -} // namespace ui diff --git a/chromium/ui/ozone/platform/windows/ozone_platform_windows.h b/chromium/ui/ozone/platform/windows/ozone_platform_windows.h deleted file mode 100644 index 07169e74690..00000000000 --- a/chromium/ui/ozone/platform/windows/ozone_platform_windows.h +++ /dev/null @@ -1,17 +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_WINDOWS_OZONE_PLATFORM_WINDOWS_H_ -#define UI_OZONE_PLATFORM_WINDOWS_OZONE_PLATFORM_WINDOWS_H_ - -namespace ui { - -class OzonePlatform; - -// Constructor hook for use in ozone_platform_list.cc -OzonePlatform* CreateOzonePlatformWindows(); - -} // namespace ui - -#endif // UI_OZONE_PLATFORM_WINDOWS_OZONE_PLATFORM_WINDOWS_H_ diff --git a/chromium/ui/ozone/platform/windows/windows_surface_factory.cc b/chromium/ui/ozone/platform/windows/windows_surface_factory.cc deleted file mode 100644 index 5d525bd5ae4..00000000000 --- a/chromium/ui/ozone/platform/windows/windows_surface_factory.cc +++ /dev/null @@ -1,88 +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/windows/windows_surface_factory.h" - -#include "base/bind.h" -#include "base/files/file_util.h" -#include "base/location.h" -#include "base/memory/ptr_util.h" -#include "base/strings/string_number_conversions.h" -#include "base/task/post_task.h" -#include "build/build_config.h" -#include "ui/gfx/codec/png_codec.h" -#include "ui/gfx/geometry/skia_conversions.h" -#include "ui/gfx/vsync_provider.h" -#include "ui/gl/gl_surface_egl.h" -#include "ui/gl/vsync_provider_win.h" -#include "ui/ozone/common/egl_util.h" -#include "ui/ozone/common/gl_ozone_egl.h" -#include "ui/ozone/platform/windows/windows_window.h" -#include "ui/ozone/platform/windows/windows_window_manager.h" - -namespace ui { - -namespace { - -class GLOzoneEGLWindows : public GLOzoneEGL { - public: - GLOzoneEGLWindows() = default; - - GLOzoneEGLWindows(const GLOzoneEGLWindows&) = delete; - GLOzoneEGLWindows& operator=(const GLOzoneEGLWindows&) = delete; - - ~GLOzoneEGLWindows() override = default; - - // GLOzone: - scoped_refptr<gl::GLSurface> CreateViewGLSurface( - gfx::AcceleratedWidget window) override { - return InitializeGLSurface(base::MakeRefCounted<gl::NativeViewGLSurfaceEGL>( - window, std::make_unique<gl::VSyncProviderWin>(window))); - } - - scoped_refptr<gl::GLSurface> CreateOffscreenGLSurface( - const gfx::Size& size) override { - return gl::InitializeGLSurface( - base::MakeRefCounted<gl::PbufferGLSurfaceEGL>(size)); - } - - protected: - // GLOzoneEGL: - gl::EGLDisplayPlatform GetNativeDisplay() override { - return gl::EGLDisplayPlatform(GetWindowDC(nullptr)); - } - - bool LoadGLES2Bindings( - const gl::GLImplementationParts& implementation) override { - return LoadDefaultEGLGLES2Bindings(implementation); - } -}; - -} // namespace - -WindowsSurfaceFactory::WindowsSurfaceFactory() - : egl_implementation_(std::make_unique<GLOzoneEGLWindows>()) {} - -WindowsSurfaceFactory::~WindowsSurfaceFactory() = default; - -std::vector<gl::GLImplementationParts> -WindowsSurfaceFactory::GetAllowedGLImplementations() { - return std::vector<gl::GLImplementationParts>{ - gl::GLImplementationParts(gl::kGLImplementationEGLGLES2), - gl::GLImplementationParts(gl::ANGLEImplementation::kSwiftShader), - gl::GLImplementationParts(gl::kGLImplementationEGLANGLE)}; -} - -GLOzone* WindowsSurfaceFactory::GetGLOzone( - const gl::GLImplementationParts& implementation) { - switch (implementation.gl) { - case gl::kGLImplementationEGLGLES2: - case gl::kGLImplementationEGLANGLE: - return egl_implementation_.get(); - default: - return nullptr; - } -} - -} // namespace ui diff --git a/chromium/ui/ozone/platform/windows/windows_surface_factory.h b/chromium/ui/ozone/platform/windows/windows_surface_factory.h deleted file mode 100644 index 9e146e8f8e4..00000000000 --- a/chromium/ui/ozone/platform/windows/windows_surface_factory.h +++ /dev/null @@ -1,36 +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_WINDOWS_WINDOWS_SURFACE_FACTORY_H_ -#define UI_OZONE_PLATFORM_WINDOWS_WINDOWS_SURFACE_FACTORY_H_ - -#include <memory> -#include <vector> - -#include "ui/ozone/public/gl_ozone.h" -#include "ui/ozone/public/surface_factory_ozone.h" - -namespace ui { - -// Handles GL initialization and surface/context creation for Windows -class WindowsSurfaceFactory : public SurfaceFactoryOzone { - public: - WindowsSurfaceFactory(); - - WindowsSurfaceFactory(const WindowsSurfaceFactory&) = delete; - WindowsSurfaceFactory& operator=(const WindowsSurfaceFactory&) = delete; - - ~WindowsSurfaceFactory() override; - - // SurfaceFactoryOzone: - std::vector<gl::GLImplementationParts> GetAllowedGLImplementations() override; - GLOzone* GetGLOzone(const gl::GLImplementationParts& implementation) override; - - private: - std::unique_ptr<GLOzone> egl_implementation_; -}; - -} // namespace ui - -#endif // UI_OZONE_PLATFORM_WINDOWS_WINDOWS_SURFACE_FACTORY_H_ diff --git a/chromium/ui/ozone/platform/windows/windows_window.cc b/chromium/ui/ozone/platform/windows/windows_window.cc deleted file mode 100644 index 1e0ecdc03e5..00000000000 --- a/chromium/ui/ozone/platform/windows/windows_window.cc +++ /dev/null @@ -1,21 +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/windows/windows_window.h" - -#include <string> - -#include "build/build_config.h" -#include "ui/events/platform/platform_event_source.h" -#include "ui/ozone/platform/windows/windows_window_manager.h" - -namespace ui { - -WindowsWindow::WindowsWindow(PlatformWindowDelegate* delegate, - const gfx::Rect& bounds) - : WinWindow(delegate, bounds) {} - -WindowsWindow::~WindowsWindow() {} - -} // namespace ui diff --git a/chromium/ui/ozone/platform/windows/windows_window.h b/chromium/ui/ozone/platform/windows/windows_window.h deleted file mode 100644 index 0641d7fbf2e..00000000000 --- a/chromium/ui/ozone/platform/windows/windows_window.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_OZONE_PLATFORM_WINDOWS_WINDOWS_WINDOW_H_ -#define UI_OZONE_PLATFORM_WINDOWS_WINDOWS_WINDOW_H_ - -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/platform_window/platform_window_delegate.h" -#include "ui/platform_window/win/win_window.h" - -namespace ui { - -class WindowsWindow : public WinWindow { - public: - WindowsWindow(PlatformWindowDelegate* delegate, const gfx::Rect& bounds); - - WindowsWindow(const WindowsWindow&) = delete; - WindowsWindow& operator=(const WindowsWindow&) = delete; - - ~WindowsWindow() override; -}; - -} // namespace ui - -#endif // UI_OZONE_PLATFORM_WINDOWS_WINDOWS_WINDOW_H_ diff --git a/chromium/ui/ozone/platform/windows/windows_window_manager.cc b/chromium/ui/ozone/platform/windows/windows_window_manager.cc deleted file mode 100644 index c9a4858feee..00000000000 --- a/chromium/ui/ozone/platform/windows/windows_window_manager.cc +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/ozone/platform/windows/windows_window_manager.h" - -namespace ui { - -WindowsWindowManager::WindowsWindowManager() = default; - -WindowsWindowManager::~WindowsWindowManager() {} - -int32_t WindowsWindowManager::AddWindow(WindowsWindow* window) { - return windows_.Add(window); -} - -void WindowsWindowManager::RemoveWindow(int32_t window_id, - WindowsWindow* window) { - DCHECK_EQ(window, windows_.Lookup(window_id)); - windows_.Remove(window_id); -} - -WindowsWindow* WindowsWindowManager::GetWindow(int32_t window_id) { - return windows_.Lookup(window_id); -} - -} // namespace ui diff --git a/chromium/ui/ozone/platform/windows/windows_window_manager.h b/chromium/ui/ozone/platform/windows/windows_window_manager.h deleted file mode 100644 index 9f516fbcb1f..00000000000 --- a/chromium/ui/ozone/platform/windows/windows_window_manager.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_WINDOWS_WINDOWS_WINDOW_MANAGER_H_ -#define UI_OZONE_PLATFORM_WINDOWS_WINDOWS_WINDOW_MANAGER_H_ - -#include <stdint.h> - -#include "base/containers/id_map.h" -#include "base/threading/thread_checker.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/ozone/public/surface_factory_ozone.h" - -namespace ui { - -class WindowsWindow; - -class WindowsWindowManager { - public: - WindowsWindowManager(); - - WindowsWindowManager(const WindowsWindowManager&) = delete; - WindowsWindowManager& operator=(const WindowsWindowManager&) = delete; - - ~WindowsWindowManager(); - - // Register a new window. Returns the window id. - int32_t AddWindow(WindowsWindow* window); - - // Remove a window. - void RemoveWindow(int32_t window_id, WindowsWindow* window); - - // Find a window object by id; - WindowsWindow* GetWindow(int32_t window_id); - - private: - base::IDMap<WindowsWindow*> windows_; -}; - -} // namespace ui - -#endif // UI_OZONE_PLATFORM_WINDOWS_WINDOWS_WINDOW_MANAGER_H_ diff --git a/chromium/ui/ozone/platform/x11/BUILD.gn b/chromium/ui/ozone/platform/x11/BUILD.gn index dd65850ec13..b1180a85530 100644 --- a/chromium/ui/ozone/platform/x11/BUILD.gn +++ b/chromium/ui/ozone/platform/x11/BUILD.gn @@ -42,8 +42,6 @@ source_set("x11") { "x11_screen_ozone.h", "x11_surface_factory.cc", "x11_surface_factory.h", - "x11_topmost_window_finder.cc", - "x11_topmost_window_finder.h", "x11_user_input_monitor.cc", "x11_user_input_monitor.h", "x11_utils.cc", @@ -165,7 +163,7 @@ source_set("x11_unittests") { "//ui/ozone/common", ] - if (!is_chromeos && !is_chromeos_ash && !is_chromeos_lacros) { + if (!is_chromeos && !is_chromeos) { sources += [ "test/os_exchange_data_provider_x11_unittest.cc" ] deps += [ "//ui/base/clipboard:clipboard_types" ] @@ -193,24 +191,3 @@ source_set("test_support") { "//ui/base/x:test_support", ] } - -source_set("interactive_uitests") { - testonly = true - sources = [ "x11_topmost_window_finder_interactive_uitest.cc" ] - - deps = [ - ":x11", - "//base", - "//base/test:test_support", - "//testing/gmock", - "//testing/gtest", - "//ui/base/x", - "//ui/base/x:test_support", - "//ui/events/platform/x11", - "//ui/gfx", - "//ui/gfx/x", - "//ui/ozone", - "//ui/ozone:platform", - "//ui/platform_window", - ] -} diff --git a/chromium/ui/ozone/platform/x11/test/events_x_unittest.cc b/chromium/ui/ozone/platform/x11/test/events_x_unittest.cc index 86964207bbc..125ecac8d64 100644 --- a/chromium/ui/ozone/platform/x11/test/events_x_unittest.cc +++ b/chromium/ui/ozone/platform/x11/test/events_x_unittest.cc @@ -783,17 +783,14 @@ TEST_F(EventsXTest, EventLatencyOSTouchHistograms) { scoped_xevent.InitTouchEvent(0, x11::Input::DeviceEvent::TouchBegin, 5, gfx::Point(10, 10), {}); auto touch_begin = ui::BuildTouchEventFromXEvent(*scoped_xevent); - histogram_tester.ExpectTotalCount("Event.Latency.OS.TOUCH_PRESSED", 1); histogram_tester.ExpectTotalCount("Event.Latency.OS2.TOUCH_PRESSED", 1); scoped_xevent.InitTouchEvent(0, x11::Input::DeviceEvent::TouchUpdate, 5, gfx::Point(20, 20), {}); auto touch_update = ui::BuildTouchEventFromXEvent(*scoped_xevent); - histogram_tester.ExpectTotalCount("Event.Latency.OS.TOUCH_MOVED", 1); histogram_tester.ExpectTotalCount("Event.Latency.OS2.TOUCH_MOVED", 1); scoped_xevent.InitTouchEvent(0, x11::Input::DeviceEvent::TouchEnd, 5, gfx::Point(30, 30), {}); auto touch_end = ui::BuildTouchEventFromXEvent(*scoped_xevent); - histogram_tester.ExpectTotalCount("Event.Latency.OS.TOUCH_RELEASED", 1); histogram_tester.ExpectTotalCount("Event.Latency.OS2.TOUCH_RELEASED", 1); } @@ -809,7 +806,6 @@ TEST_F(EventsXTest, EventLatencyOSMouseWheelHistogram) { .detail = static_cast<x11::Button>(4), }); auto mouse_ev = ui::BuildMouseWheelEventFromXEvent(native_event); - histogram_tester.ExpectTotalCount("Event.Latency.OS.MOUSE_WHEEL", 1); histogram_tester.ExpectTotalCount("Event.Latency.OS2.MOUSE_WHEEL", 1); } diff --git a/chromium/ui/ozone/platform/x11/test/x11_drag_drop_client_unittest.cc b/chromium/ui/ozone/platform/x11/test/x11_drag_drop_client_unittest.cc index e4e915b8e50..e4f8670646a 100644 --- a/chromium/ui/ozone/platform/x11/test/x11_drag_drop_client_unittest.cc +++ b/chromium/ui/ozone/platform/x11/test/x11_drag_drop_client_unittest.cc @@ -19,6 +19,8 @@ #include "base/test/task_environment.h" #include "base/threading/thread_task_runner_handle.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkPath.h" #include "ui/base/dragdrop/drag_drop_types.h" #include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h" #include "ui/base/dragdrop/os_exchange_data.h" @@ -128,7 +130,7 @@ class SimpleTestDragDropClient : public XDragDropClient, private: // XDragDropClient::Delegate: - std::unique_ptr<XTopmostWindowFinder> CreateWindowFinder() override; + absl::optional<gfx::AcceleratedWidget> GetDragWidget() override; int UpdateDrag(const gfx::Point& screen_point) override; void UpdateCursor(DragOperation negotiated_operation) override; void OnBeginForeignDrag(x11::Window window) override; @@ -314,14 +316,15 @@ DragOperation SimpleTestDragDropClient::StartDragAndDrop( return resulting_operation; } +absl::optional<gfx::AcceleratedWidget> +SimpleTestDragDropClient::GetDragWidget() { + return absl::nullopt; +} + int SimpleTestDragDropClient::UpdateDrag(const gfx::Point& screen_point) { return 0; } -std::unique_ptr<XTopmostWindowFinder> -SimpleTestDragDropClient::CreateWindowFinder() { - return {}; -} void SimpleTestDragDropClient::UpdateCursor( DragOperation negotiated_operation) {} void SimpleTestDragDropClient::OnBeginForeignDrag(x11::Window window) {} diff --git a/chromium/ui/ozone/platform/x11/test/x11_window_unittest.cc b/chromium/ui/ozone/platform/x11/test/x11_window_unittest.cc index f6e41d42bd7..b4fc4d623a7 100644 --- a/chromium/ui/ozone/platform/x11/test/x11_window_unittest.cc +++ b/chromium/ui/ozone/platform/x11/test/x11_window_unittest.cc @@ -169,7 +169,7 @@ class TestScreen : public display::ScreenBase { display.SetScaleAndBounds(scale, bounds_in_pixels); ProcessDisplayChanged(display, true); } -}; // namespace +}; // Returns the list of rectangles which describe |window|'s bounding region via // the X shape extension. diff --git a/chromium/ui/ozone/platform/x11/vulkan_surface_x11.cc b/chromium/ui/ozone/platform/x11/vulkan_surface_x11.cc index 5a94e513688..7f7a6ca796b 100644 --- a/chromium/ui/ozone/platform/x11/vulkan_surface_x11.cc +++ b/chromium/ui/ozone/platform/x11/vulkan_surface_x11.cc @@ -7,6 +7,7 @@ #include "base/logging.h" #include "gpu/vulkan/vulkan_function_pointers.h" #include "ui/base/x/x11_util.h" +#include "ui/base/x/x11_xrandr_interval_only_vsync_provider.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/x/connection.h" #include "ui/gfx/x/x11_window_event_manager.h" @@ -39,9 +40,6 @@ std::unique_ptr<VulkanSurfaceX11> VulkanSurfaceX11::Create( LOG(ERROR) << "Failed to create or map window."; return nullptr; } - // Flush the connection, otherwise other Vulkan WSI calls may fail with some - // drivers. - connection->Flush(); VkSurfaceKHR vk_surface; const VkXcbSurfaceCreateInfoKHR surface_create_info = { @@ -72,11 +70,13 @@ VulkanSurfaceX11::VulkanSurfaceX11(VkInstance vk_instance, VkSurfaceKHR vk_surface, x11::Window parent_window, x11::Window window) - : gpu::VulkanSurface(vk_instance, - static_cast<gfx::AcceleratedWidget>(window), - vk_surface, - base::Time::kNanosecondsPerSecond * - 2 /* acquire_next_image_timeout_ns */), + : gpu::VulkanSurface( + vk_instance, + static_cast<gfx::AcceleratedWidget>(window), + vk_surface, + /*acquire_next_image_timeout_ns=*/base::Time::kNanosecondsPerSecond * + 2, + std::make_unique<ui::XrandrIntervalOnlyVSyncProvider>()), parent_window_(parent_window), window_(window), event_selector_(std::make_unique<x11::XScopedEventSelector>( diff --git a/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc b/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc index f69a5443e5b..9a7240a1eac 100644 --- a/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc +++ b/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc @@ -4,6 +4,7 @@ #include "ui/ozone/platform/x11/x11_screen_ozone.h" +#include "base/containers/flat_set.h" #include "ui/base/linux/linux_desktop.h" #include "ui/base/x/x11_idle_query.h" #include "ui/base/x/x11_screensaver.h" @@ -16,27 +17,28 @@ #include "ui/gfx/geometry/point_conversions.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/native_widget_types.h" -#include "ui/ozone/platform/x11/x11_topmost_window_finder.h" +#include "ui/gfx/x/window_cache.h" #include "ui/ozone/platform/x11/x11_window.h" #include "ui/ozone/platform/x11/x11_window_manager.h" namespace ui { X11ScreenOzone::X11ScreenOzone() - : window_manager_(X11WindowManager::GetInstance()), + : connection_(x11::Connection::Get()), + window_manager_(X11WindowManager::GetInstance()), x11_display_manager_(std::make_unique<XDisplayManager>(this)) { DCHECK(window_manager_); } X11ScreenOzone::~X11ScreenOzone() { if (x11_display_manager_->IsXrandrAvailable()) - x11::Connection::Get()->RemoveEventObserver(this); + connection_->RemoveEventObserver(this); } void X11ScreenOzone::Init() { initialized_ = true; if (x11_display_manager_->IsXrandrAvailable()) - x11::Connection::Get()->AddEventObserver(this); + connection_->AddEventObserver(this); x11_display_manager_->Init(); } @@ -79,23 +81,41 @@ gfx::Point X11ScreenOzone::GetCursorScreenPoint() const { gfx::ConvertPointToDips(*point_in_pixels, GetXDisplayScaleFactor())); } +bool X11ScreenOzone::IsAcceleratedWidgetUnderCursor( + gfx::AcceleratedWidget widget) const { + // Only ask the X11Window for its pointer state when some other window does + // not have mouse capture because capture disrupts pointer event tracking. + if (!window_manager_->located_events_grabber()) { + if (X11Window* window = window_manager_->GetWindow(widget)) + return window->has_pointer(); + } + return GetAcceleratedWidgetAtScreenPoint(GetCursorScreenPoint()) == widget; +} + gfx::AcceleratedWidget X11ScreenOzone::GetAcceleratedWidgetAtScreenPoint( const gfx::Point& point) const { gfx::Point point_in_pixels = gfx::ToFlooredPoint( gfx::ConvertPointToPixels(point, GetXDisplayScaleFactor())); - X11TopmostWindowFinder finder({}); return static_cast<gfx::AcceleratedWidget>( - finder.FindWindowAt(point_in_pixels)); + x11::GetWindowAtPoint(point_in_pixels)); } gfx::AcceleratedWidget X11ScreenOzone::GetLocalProcessWidgetAtPoint( const gfx::Point& point, const std::set<gfx::AcceleratedWidget>& ignore) const { - gfx::Point point_in_pixels = gfx::ToFlooredPoint( - gfx::ConvertPointToPixels(point, GetXDisplayScaleFactor())); - X11TopmostWindowFinder finder(ignore); - return static_cast<gfx::AcceleratedWidget>( - finder.FindLocalProcessWindowAt(point_in_pixels)); + gfx::AcceleratedWidget widget{}; + if (ignore.empty()) { + widget = GetAcceleratedWidgetAtScreenPoint(point); + } else { + gfx::Point point_in_pixels = gfx::ToFlooredPoint( + gfx::ConvertPointToPixels(point, GetXDisplayScaleFactor())); + base::flat_set<x11::Window> ignore_windows; + for (auto widget : ignore) + ignore_windows.insert(static_cast<x11::Window>(widget)); + widget = static_cast<gfx::AcceleratedWidget>( + x11::GetWindowAtPoint(point_in_pixels, &ignore_windows)); + } + return window_manager_->GetWindow(widget) ? widget : gfx::AcceleratedWidget{}; } display::Display X11ScreenOzone::GetDisplayNearestPoint( diff --git a/chromium/ui/ozone/platform/x11/x11_screen_ozone.h b/chromium/ui/ozone/platform/x11/x11_screen_ozone.h index c197be1f59b..d86acae9aa9 100644 --- a/chromium/ui/ozone/platform/x11/x11_screen_ozone.h +++ b/chromium/ui/ozone/platform/x11/x11_screen_ozone.h @@ -39,6 +39,8 @@ class X11ScreenOzone : public PlatformScreen, display::Display GetDisplayForAcceleratedWidget( gfx::AcceleratedWidget widget) const override; gfx::Point GetCursorScreenPoint() const override; + bool IsAcceleratedWidgetUnderCursor( + gfx::AcceleratedWidget widget) const override; gfx::AcceleratedWidget GetAcceleratedWidgetAtScreenPoint( const gfx::Point& point) const override; gfx::AcceleratedWidget GetLocalProcessWidgetAtPoint( @@ -70,6 +72,7 @@ class X11ScreenOzone : public PlatformScreen, gfx::Point GetCursorLocation() const; + x11::Connection* const connection_; X11WindowManager* const window_manager_; std::unique_ptr<ui::XDisplayManager> x11_display_manager_; diff --git a/chromium/ui/ozone/platform/x11/x11_surface_factory.cc b/chromium/ui/ozone/platform/x11/x11_surface_factory.cc index c915c87be7f..67c8073143f 100644 --- a/chromium/ui/ozone/platform/x11/x11_surface_factory.cc +++ b/chromium/ui/ozone/platform/x11/x11_surface_factory.cc @@ -107,8 +107,7 @@ X11SurfaceFactory::GetAllowedGLImplementations() { gl::GLImplementationParts(gl::kGLImplementationDesktopGL), gl::GLImplementationParts(gl::kGLImplementationEGLGLES2), gl::GLImplementationParts(gl::kGLImplementationEGLANGLE), - gl::GLImplementationParts(gl::ANGLEImplementation::kSwiftShader), - gl::GLImplementationParts(gl::kGLImplementationSwiftShaderGL)}; + gl::GLImplementationParts(gl::ANGLEImplementation::kSwiftShader)}; } GLOzone* X11SurfaceFactory::GetGLOzone( @@ -118,7 +117,6 @@ GLOzone* X11SurfaceFactory::GetGLOzone( return glx_implementation_.get(); case gl::kGLImplementationEGLGLES2: case gl::kGLImplementationEGLANGLE: - case gl::kGLImplementationSwiftShaderGL: return egl_implementation_.get(); default: return nullptr; diff --git a/chromium/ui/ozone/platform/x11/x11_topmost_window_finder.cc b/chromium/ui/ozone/platform/x11/x11_topmost_window_finder.cc deleted file mode 100644 index e5e051c0f63..00000000000 --- a/chromium/ui/ozone/platform/x11/x11_topmost_window_finder.cc +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2014 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/x11/x11_topmost_window_finder.h" - -#include <stddef.h> - -#include <vector> - -#include "base/bind.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/gfx/x/x11_atom_cache.h" -#include "ui/gfx/x/xproto_util.h" -#include "ui/ozone/platform/x11/x11_window.h" -#include "ui/ozone/platform/x11/x11_window_manager.h" - -namespace ui { - -namespace { - -using ShouldStopIteratingCallback = base::RepeatingCallback<bool(x11::Window)>; - -// Returns true if |window| is a named window. -bool IsWindowNamed(x11::Window window) { - return PropertyExists(window, x11::Atom::WM_NAME); -} - -bool EnumerateChildren(ShouldStopIteratingCallback should_stop_iterating, - x11::Window window, - const int max_depth, - int depth) { - if (depth > max_depth) - return false; - - auto query_tree = x11::Connection::Get()->QueryTree({window}).Sync(); - if (!query_tree) - return false; - std::vector<x11::Window> windows = std::move(query_tree->children); - - // XQueryTree returns the children of |window| in bottom-to-top order, so - // reverse-iterate the list to check the windows from top-to-bottom. - std::vector<x11::Window>::reverse_iterator iter; - for (iter = windows.rbegin(); iter != windows.rend(); iter++) { - if (depth < max_depth) { - if (EnumerateChildren(should_stop_iterating, *iter, max_depth, depth + 1)) - return true; - } - if (IsWindowNamed(*iter) && should_stop_iterating.Run(*iter)) - return true; - } - - return false; -} - -bool EnumerateAllWindows(ShouldStopIteratingCallback should_stop_iterating, - int max_depth) { - x11::Window root = GetX11RootWindow(); - return EnumerateChildren(should_stop_iterating, root, max_depth, 0); -} - -void EnumerateTopLevelWindows( - ui::ShouldStopIteratingCallback should_stop_iterating) { - // WMs may reparent toplevel windows inside their own containers, so extend - // the search to all grandchildren of all toplevel windows. - const int kMaxSearchDepth = 2; - ui::EnumerateAllWindows(should_stop_iterating, kMaxSearchDepth); -} - -} // namespace - -X11TopmostWindowFinder::X11TopmostWindowFinder( - const std::set<gfx::AcceleratedWidget>& ignore) - : ignore_(ignore) {} - -X11TopmostWindowFinder::~X11TopmostWindowFinder() = default; - -x11::Window X11TopmostWindowFinder::FindLocalProcessWindowAt( - const gfx::Point& screen_loc_in_pixels) { - screen_loc_in_pixels_ = screen_loc_in_pixels; - - std::vector<X11Window*> local_process_windows = - X11WindowManager::GetInstance()->GetAllOpenWindows(); - if (std::none_of(local_process_windows.cbegin(), local_process_windows.cend(), - [this](auto* window) { - return ShouldStopIteratingAtLocalProcessWindow(window); - })) { - return x11::Window::None; - } - - EnumerateTopLevelWindows(base::BindRepeating( - &X11TopmostWindowFinder::ShouldStopIterating, base::Unretained(this))); - return toplevel_; -} - -x11::Window X11TopmostWindowFinder::FindWindowAt( - const gfx::Point& screen_loc_in_pixels) { - screen_loc_in_pixels_ = screen_loc_in_pixels; - EnumerateTopLevelWindows(base::BindRepeating( - &X11TopmostWindowFinder::ShouldStopIterating, base::Unretained(this))); - return toplevel_; -} - -bool X11TopmostWindowFinder::ShouldStopIterating(x11::Window xwindow) { - if (!IsWindowVisible(xwindow)) - return false; - - auto* window = X11WindowManager::GetInstance()->GetWindow( - static_cast<gfx::AcceleratedWidget>(xwindow)); - if (window) { - if (ShouldStopIteratingAtLocalProcessWindow(window)) { - toplevel_ = xwindow; - return true; - } - return false; - } - - if (WindowContainsPoint(xwindow, screen_loc_in_pixels_)) { - toplevel_ = xwindow; - return true; - } - return false; -} - -bool X11TopmostWindowFinder::ShouldStopIteratingAtLocalProcessWindow( - X11Window* window) { - if (ignore_.find(window->GetWidget()) != ignore_.end()) - return false; - - // Currently |window|->IsVisible() always returns true. - // TODO(pkotwicz): Fix this. crbug.com/353038 - if (!window->IsVisible()) - return false; - - gfx::Rect window_bounds = window->GetOuterBounds(); - if (!window_bounds.Contains(screen_loc_in_pixels_)) - return false; - - gfx::Point window_point(screen_loc_in_pixels_); - window_point.Offset(-window_bounds.origin().x(), -window_bounds.origin().y()); - return window->ContainsPointInXRegion(window_point); -} - -} // namespace ui diff --git a/chromium/ui/ozone/platform/x11/x11_topmost_window_finder.h b/chromium/ui/ozone/platform/x11/x11_topmost_window_finder.h deleted file mode 100644 index 934045c6e72..00000000000 --- a/chromium/ui/ozone/platform/x11/x11_topmost_window_finder.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2014 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_X11_X11_TOPMOST_WINDOW_FINDER_H_ -#define UI_OZONE_PLATFORM_X11_X11_TOPMOST_WINDOW_FINDER_H_ - -#include <set> - -#include "ui/base/x/x11_topmost_window_finder.h" -#include "ui/base/x/x11_util.h" -#include "ui/gfx/geometry/point.h" -#include "ui/gfx/native_widget_types.h" - -namespace ui { - -class X11Window; - -// Utility class for finding the topmost window at a given screen position. -class X11TopmostWindowFinder : public ui::XTopmostWindowFinder { - public: - // Create finder, specifying a set of windows to |ignore|. - explicit X11TopmostWindowFinder( - const std::set<gfx::AcceleratedWidget>& ignore); - - X11TopmostWindowFinder(const X11TopmostWindowFinder&) = delete; - X11TopmostWindowFinder& operator=(const X11TopmostWindowFinder&) = delete; - - ~X11TopmostWindowFinder() override; - - // Returns the topmost window at |screen_loc_in_pixels|. Returns null widget - // if the topmost window at |screen_loc_in_pixels| does not belong to Chrome. - x11::Window FindLocalProcessWindowAt(const gfx::Point& screen_loc_in_pixels); - - // Returns the topmost window at |screen_loc_in_pixels|. - x11::Window FindWindowAt(const gfx::Point& screen_loc_in_pixels) override; - - private: - bool ShouldStopIterating(x11::Window window); - - // Returns true if |window| does not not belong to |ignore|, is visible and - // contains |screen_loc_|. - bool ShouldStopIteratingAtLocalProcessWindow(ui::X11Window* window); - - gfx::Point screen_loc_in_pixels_; - std::set<gfx::AcceleratedWidget> ignore_; - x11::Window toplevel_ = x11::Window::None; -}; - -} // namespace ui - -#endif // UI_OZONE_PLATFORM_X11_X11_TOPMOST_WINDOW_FINDER_H_ diff --git a/chromium/ui/ozone/platform/x11/x11_topmost_window_finder_interactive_uitest.cc b/chromium/ui/ozone/platform/x11/x11_topmost_window_finder_interactive_uitest.cc deleted file mode 100644 index 346a45ef8c5..00000000000 --- a/chromium/ui/ozone/platform/x11/x11_topmost_window_finder_interactive_uitest.cc +++ /dev/null @@ -1,504 +0,0 @@ -// Copyright 2014 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/x11/x11_topmost_window_finder.h" - -#include <stddef.h> - -#include <algorithm> -#include <memory> -#include <vector> - -#include "base/containers/contains.h" -#include "base/test/task_environment.h" -#include "build/build_config.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/skia/include/core/SkRect.h" -#include "third_party/skia/include/core/SkRegion.h" -#include "ui/base/x/test/x11_property_change_waiter.h" -#include "ui/base/x/x11_util.h" -#include "ui/events/platform/x11/x11_event_source.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/gfx/x/connection.h" -#include "ui/gfx/x/event.h" -#include "ui/gfx/x/shape.h" -#include "ui/gfx/x/x11_atom_cache.h" -#include "ui/gfx/x/x11_path.h" -#include "ui/gfx/x/xproto.h" -#include "ui/gfx/x/xproto_util.h" -#include "ui/ozone/platform/x11/x11_window.h" -#include "ui/ozone/platform/x11/x11_window_manager.h" -#include "ui/ozone/public/ozone_platform.h" -#include "ui/platform_window/platform_window_init_properties.h" - -namespace ui { - -namespace { - -// Waits until the |x11_window| is mapped and becomes viewable. -class X11VisibilityWaiter : public x11::EventObserver { - public: - X11VisibilityWaiter() = default; - X11VisibilityWaiter(const X11VisibilityWaiter&) = delete; - X11VisibilityWaiter& operator=(const X11VisibilityWaiter&) = delete; - ~X11VisibilityWaiter() override = default; - - void WaitUntilWindowIsVisible(x11::Window x11_window) { - if (IsWindowVisible(x11_window)) - return; - - event_selector_ = std::make_unique<x11::XScopedEventSelector>( - x11_window, - x11::EventMask::StructureNotify | x11::EventMask::SubstructureNotify); - x11_window_ = x11_window; - - x11::Connection::Get()->AddEventObserver(this); - - base::RunLoop run_loop; - quit_closure_ = run_loop.QuitClosure(); - run_loop.Run(); - DCHECK(IsWindowVisible(x11_window)); - } - - private: - // x11::EventObserver: - void OnEvent(const x11::Event& event) override { - auto* map = event.As<x11::MapNotifyEvent>(); - if (map && map->window == x11_window_) { - DCHECK(!quit_closure_.is_null()); - std::move(quit_closure_).Run(); - x11::Connection::Get()->RemoveEventObserver(this); - } - } - - x11::Window x11_window_; - std::unique_ptr<x11::XScopedEventSelector> event_selector_; - // Ends the run loop. - base::OnceClosure quit_closure_; -}; - -class TestPlatformWindowDelegate : public PlatformWindowDelegate { - public: - TestPlatformWindowDelegate() = default; - TestPlatformWindowDelegate(const TestPlatformWindowDelegate&) = delete; - TestPlatformWindowDelegate& operator=(const TestPlatformWindowDelegate&) = - delete; - ~TestPlatformWindowDelegate() override = default; - - PlatformWindowState state() { return state_; } - - // PlatformWindowDelegate: - void OnBoundsChanged(const BoundsChange& change) override {} - void OnDamageRect(const gfx::Rect& damaged_region) override {} - void DispatchEvent(Event* event) override {} - void OnCloseRequest() override {} - void OnClosed() override {} - void OnWindowStateChanged(PlatformWindowState old_state, - PlatformWindowState new_state) override { - state_ = new_state; - } - void OnLostCapture() override {} - void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget) override { - widget_ = widget; - } - void OnWillDestroyAcceleratedWidget() override {} - void OnAcceleratedWidgetDestroyed() override { - widget_ = gfx::kNullAcceleratedWidget; - } - void OnActivationChanged(bool active) override {} - void OnMouseEnter() override {} - - private: - gfx::AcceleratedWidget widget_ = gfx::kNullAcceleratedWidget; - PlatformWindowState state_ = PlatformWindowState::kUnknown; -}; - -// Waits till |window| is minimized. -class MinimizeWaiter : public X11PropertyChangeWaiter { - public: - explicit MinimizeWaiter(x11::Window window) - : X11PropertyChangeWaiter(window, "_NET_WM_STATE") {} - - MinimizeWaiter(const MinimizeWaiter&) = delete; - MinimizeWaiter& operator=(const MinimizeWaiter&) = delete; - - ~MinimizeWaiter() override = default; - - private: - // X11PropertyChangeWaiter: - bool ShouldKeepOnWaiting() override { - std::vector<x11::Atom> wm_states; - if (GetArrayProperty(xwindow(), x11::GetAtom("_NET_WM_STATE"), - &wm_states)) { - return !base::Contains(wm_states, x11::GetAtom("_NET_WM_STATE_HIDDEN")); - } - return true; - } -}; - -void IconifyWindow(x11::Connection* connection, x11::Window window) { - SendClientMessage(window, GetX11RootWindow(), x11::GetAtom("WM_CHANGE_STATE"), - {WM_STATE_ICONIC, 0, 0, 0, 0}); -} - -} // namespace - -class X11TopmostWindowFinderTest : public testing::Test { - public: - X11TopmostWindowFinderTest() - : task_env_(base::test::TaskEnvironment::MainThreadType::UI) {} - - X11TopmostWindowFinderTest(const X11TopmostWindowFinderTest&) = delete; - X11TopmostWindowFinderTest& operator=(const X11TopmostWindowFinderTest&) = - delete; - - ~X11TopmostWindowFinderTest() override = default; - - // testing::Test: - void SetUp() override { - // Run tests only for X11. - if (OzonePlatform::GetPlatformNameForTest() != "x11") - GTEST_SKIP(); - - auto* connection = x11::Connection::Get(); - // Not initialized when runs on CrOS builds. - if (!X11EventSource::GetInstance()) - event_source_ = std::make_unique<X11EventSource>(connection); - // Make X11 synchronous for our display connection. This does not force the - // window manager to behave synchronously. - connection->SynchronizeForTest(true); - testing::Test::SetUp(); - } - - void TearDown() override { - if (!IsSkipped()) - connection()->SynchronizeForTest(false); - } - - // Creates and shows an X11Window with |bounds|. The caller takes ownership of - // the returned window. - std::unique_ptr<X11Window> CreateAndShowX11Window( - PlatformWindowDelegate* delegate, - const gfx::Rect& bounds) { - PlatformWindowInitProperties init_params(bounds); - init_params.type = PlatformWindowType::kWindow; - init_params.remove_standard_frame = true; - auto window = std::make_unique<X11Window>(delegate); - window->Initialize(std::move(init_params)); - window->Show(true); - // The window must have a title. Otherwise, the X11TopmostWindowFinder - // refuses to use this window. - window->SetTitle(u"X11FinderTest"); - - // Wait until the window becomes visible so that window finder doesn't skip - // these windows (it's required to wait because mapping and searching for - // toplevel window is a subject to races). - X11VisibilityWaiter waiter; - waiter.WaitUntilWindowIsVisible( - static_cast<x11::Window>(window->GetWidget())); - return window; - } - - // Creates and shows an X window with |bounds|. - x11::Window CreateAndShowXWindow(const gfx::Rect& bounds) { - x11::Window root = GetX11RootWindow(); - auto window = connection()->GenerateId<x11::Window>(); - connection()->CreateWindow({ - .wid = window, - .parent = root, - .width = 1, - .height = 1, - }); - - // This is necessary because X11TopmostWindowFinder skips over unnamed - // windows. - SetStringProperty(window, x11::Atom::WM_NAME, x11::Atom::STRING, ""); - - SetUseOSWindowFrame(window, false); - ShowAndSetXWindowBounds(window, bounds); - - // Wait until the window becomes visible so that window finder doesn't skip - // these windows (it's required to wait because mapping and searching for - // toplevel window is a subject to races). - X11VisibilityWaiter waiter; - waiter.WaitUntilWindowIsVisible(static_cast<x11::Window>(window)); - return window; - } - - // Shows |window| and sets its bounds. - void ShowAndSetXWindowBounds(x11::Window window, const gfx::Rect& bounds) { - connection()->MapWindow({window}); - - connection()->ConfigureWindow({ - .window = window, - .x = bounds.x(), - .y = bounds.y(), - .width = bounds.width(), - .height = bounds.height(), - }); - } - - x11::Connection* connection() { return x11::Connection::Get(); } - - // Returns the topmost X window at the passed in screen position. - x11::Window FindTopmostXWindowAt(int screen_x, int screen_y) { - X11TopmostWindowFinder finder({}); - return finder.FindWindowAt(gfx::Point(screen_x, screen_y)); - } - - // Returns the topmost X window at the passed in screen position ignoring - // |ignore_window|. - x11::Window FindTopmostXWindowWithIgnore(int screen_x, - int screen_y, - x11::Window ignore_window) { - std::set<gfx::AcceleratedWidget> ignore; - ignore.insert(static_cast<gfx::AcceleratedWidget>(ignore_window)); - X11TopmostWindowFinder finder(ignore); - return finder.FindWindowAt(gfx::Point(screen_x, screen_y)); - } - - // Returns the topmost X11Window at the passed in screen position. Returns - // nullptr if the topmost window does not have an associated X11Window. - X11Window* FindTopmostLocalProcessWindowAt(int screen_x, int screen_y) { - X11TopmostWindowFinder finder({}); - auto x11_window = - finder.FindLocalProcessWindowAt(gfx::Point(screen_x, screen_y)); - return x11_window == x11::Window::None - ? nullptr - : X11WindowManager::GetInstance()->GetWindow( - static_cast<gfx::AcceleratedWidget>(x11_window)); - } - - // Returns the topmost X11Window at the passed in screen position ignoring - // |ignore_window|. Returns nullptr if the topmost window does not have an - // associated X11Window. - X11Window* FindTopmostLocalProcessWindowWithIgnore( - int screen_x, - int screen_y, - x11::Window ignore_window) { - std::set<gfx::AcceleratedWidget> ignore; - ignore.insert(static_cast<gfx::AcceleratedWidget>(ignore_window)); - X11TopmostWindowFinder finder(ignore); - auto x11_window = - finder.FindLocalProcessWindowAt(gfx::Point(screen_x, screen_y)); - return x11_window == x11::Window::None - ? nullptr - : X11WindowManager::GetInstance()->GetWindow( - static_cast<gfx::AcceleratedWidget>(x11_window)); - } - - private: - base::test::TaskEnvironment task_env_; - std::unique_ptr<X11EventSource> event_source_; -}; - -TEST_F(X11TopmostWindowFinderTest, Basic) { - // Avoid positioning test windows at 0x0 because window managers often have a - // panel/launcher along one of the screen edges and do not allow windows to - // position themselves to overlap the panel/launcher. - TestPlatformWindowDelegate delegate; - auto window1 = CreateAndShowX11Window(&delegate, {100, 100, 200, 100}); - auto x11_window1 = static_cast<x11::Window>(window1->GetWidget()); - - x11::Window x11_window2 = CreateAndShowXWindow(gfx::Rect(200, 100, 100, 200)); - - TestPlatformWindowDelegate delegate2; - auto window3 = CreateAndShowX11Window(&delegate2, {100, 190, 200, 110}); - auto x11_window3 = static_cast<x11::Window>(window3->GetWidget()); - - connection()->DispatchAll(); - - EXPECT_EQ(x11_window1, FindTopmostXWindowAt(150, 150)); - EXPECT_EQ(window1.get(), FindTopmostLocalProcessWindowAt(150, 150)); - - EXPECT_EQ(x11_window2, FindTopmostXWindowAt(250, 150)); - EXPECT_FALSE(FindTopmostLocalProcessWindowAt(250, 150)); - - EXPECT_EQ(x11_window3, FindTopmostXWindowAt(250, 250)); - EXPECT_EQ(window3.get(), FindTopmostLocalProcessWindowAt(250, 250)); - - EXPECT_EQ(x11_window3, FindTopmostXWindowAt(150, 250)); - EXPECT_EQ(window3.get(), FindTopmostLocalProcessWindowAt(150, 250)); - - EXPECT_EQ(x11_window3, FindTopmostXWindowAt(150, 195)); - EXPECT_EQ(window3.get(), FindTopmostLocalProcessWindowAt(150, 195)); - - EXPECT_NE(x11_window1, FindTopmostXWindowAt(1000, 1000)); - EXPECT_NE(x11_window2, FindTopmostXWindowAt(1000, 1000)); - EXPECT_NE(x11_window3, FindTopmostXWindowAt(1000, 1000)); - EXPECT_FALSE(FindTopmostLocalProcessWindowAt(1000, 1000)); - - EXPECT_EQ(x11_window1, FindTopmostXWindowWithIgnore(150, 150, x11_window3)); - EXPECT_EQ(window1.get(), - FindTopmostLocalProcessWindowWithIgnore(150, 150, x11_window3)); - EXPECT_EQ(x11_window2, FindTopmostXWindowWithIgnore(250, 250, x11_window3)); - EXPECT_FALSE(FindTopmostLocalProcessWindowWithIgnore(250, 250, x11_window3)); - EXPECT_EQ(x11::Window::None, - FindTopmostXWindowWithIgnore(150, 250, x11_window3)); - EXPECT_FALSE(FindTopmostLocalProcessWindowWithIgnore(150, 250, x11_window3)); - EXPECT_EQ(x11_window1, FindTopmostXWindowWithIgnore(150, 195, x11_window3)); - EXPECT_EQ(window1.get(), - FindTopmostLocalProcessWindowWithIgnore(150, 195, x11_window3)); - - connection()->DestroyWindow({x11_window2}); -} - -// Test that the minimized state is properly handled. -// The test is flaky (https://crbug.com/955316) -TEST_F(X11TopmostWindowFinderTest, DISABLED_Minimized) { - TestPlatformWindowDelegate delegate; - auto window1 = CreateAndShowX11Window(&delegate, {100, 100, 100, 100}); - auto x11_window1 = static_cast<x11::Window>(window1->GetWidget()); - x11::Window x11_window2 = CreateAndShowXWindow(gfx::Rect(300, 100, 100, 100)); - - connection()->DispatchAll(); - - EXPECT_EQ(x11_window1, FindTopmostXWindowAt(150, 150)); - { - MinimizeWaiter minimize_waiter(x11_window1); - IconifyWindow(connection(), x11_window1); - minimize_waiter.Wait(); - } - EXPECT_NE(x11_window1, FindTopmostXWindowAt(150, 150)); - EXPECT_NE(x11_window2, FindTopmostXWindowAt(150, 150)); - - // Repeat test for an X window which does not belong to a views::Widget - // because the code path is different. - EXPECT_EQ(x11_window2, FindTopmostXWindowAt(350, 150)); - { - MinimizeWaiter minimize_waiter(x11_window2); - IconifyWindow(connection(), x11_window2); - minimize_waiter.Wait(); - } - EXPECT_NE(x11_window1, FindTopmostXWindowAt(350, 150)); - EXPECT_NE(x11_window2, FindTopmostXWindowAt(350, 150)); - - connection()->DestroyWindow({x11_window2}); -} - -// Test that non-rectangular windows are properly handled. -TEST_F(X11TopmostWindowFinderTest, NonRectangular) { - if (!IsShapeExtensionAvailable()) - return; - - TestPlatformWindowDelegate delegate; - auto x11_window1 = CreateAndShowX11Window(&delegate, {100, 100, 100, 100}); - auto window1 = static_cast<x11::Window>(x11_window1->GetWidget()); - auto shape1 = std::make_unique<std::vector<gfx::Rect>>(); - shape1->emplace_back(0, 10, 10, 90); - shape1->emplace_back(10, 0, 90, 100); - gfx::Transform transform; - transform.Scale(1.0f, 1.0f); - x11_window1->SetShape(std::move(shape1), transform); - - SkRegion skregion2; - skregion2.op(SkIRect::MakeXYWH(0, 10, 10, 90), SkRegion::kUnion_Op); - skregion2.op(SkIRect::MakeXYWH(10, 0, 90, 100), SkRegion::kUnion_Op); - x11::Window window2 = CreateAndShowXWindow(gfx::Rect(300, 100, 100, 100)); - auto region2 = x11::CreateRegionFromSkRegion(skregion2); - x11::Connection::Get()->shape().Rectangles({ - .operation = x11::Shape::So::Set, - .destination_kind = x11::Shape::Sk::Bounding, - .ordering = x11::ClipOrdering::YXBanded, - .destination_window = window2, - .rectangles = *region2, - }); - connection()->DispatchAll(); - - EXPECT_EQ(window1, FindTopmostXWindowAt(105, 120)); - EXPECT_NE(window1, FindTopmostXWindowAt(105, 105)); - EXPECT_NE(window2, FindTopmostXWindowAt(105, 105)); - - // Repeat test for an X window which does not belong to a views::Widget - // because the code path is different. - EXPECT_EQ(window2, FindTopmostXWindowAt(305, 120)); - EXPECT_NE(window1, FindTopmostXWindowAt(305, 105)); - EXPECT_NE(window2, FindTopmostXWindowAt(305, 105)); - - connection()->DestroyWindow({window2}); -} - -// Test that a window with an empty shape are properly handled. -TEST_F(X11TopmostWindowFinderTest, NonRectangularEmptyShape) { - if (!IsShapeExtensionAvailable()) - return; - - TestPlatformWindowDelegate delegate; - auto x11_window1 = CreateAndShowX11Window(&delegate, {100, 100, 100, 100}); - auto window1 = static_cast<x11::Window>(x11_window1->GetWidget()); - - auto shape1 = std::make_unique<std::vector<gfx::Rect>>(); - shape1->emplace_back(); - gfx::Transform transform; - transform.Scale(1.0f, 1.0f); - x11_window1->SetShape(std::move(shape1), transform); - - connection()->DispatchAll(); - - EXPECT_NE(window1, FindTopmostXWindowAt(105, 105)); -} - -// Test that setting a Null shape removes the shape. -// crbug.com/955316: flaky on Linux -#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) -#define MAYBE_NonRectangularNullShape DISABLED_NonRectangularNullShape -#else -#define MAYBE_NonRectangularNullShape NonRectangularNullShape -#endif -TEST_F(X11TopmostWindowFinderTest, MAYBE_NonRectangularNullShape) { - if (!IsShapeExtensionAvailable()) - return; - - TestPlatformWindowDelegate delegate; - auto x11_window1 = CreateAndShowX11Window(&delegate, {100, 100, 100, 100}); - auto window1 = static_cast<x11::Window>(x11_window1->GetWidget()); - - auto shape1 = std::make_unique<std::vector<gfx::Rect>>(); - shape1->emplace_back(); - gfx::Transform transform; - transform.Scale(1.0f, 1.0f); - x11_window1->SetShape(std::move(shape1), transform); - - // Remove the shape - this is now just a normal window. - x11_window1->SetShape(nullptr, transform); - - connection()->DispatchAll(); - - EXPECT_EQ(window1, FindTopmostXWindowAt(105, 105)); -} - -// Test that the TopmostWindowFinder finds windows which belong to menus -// (which may or may not belong to Chrome). -// -// Flakes (https://crbug.com/955316) -TEST_F(X11TopmostWindowFinderTest, DISABLED_Menu) { - x11::Window window = CreateAndShowXWindow(gfx::Rect(100, 100, 100, 100)); - - x11::Window root = GetX11RootWindow(); - auto menu_window = connection()->GenerateId<x11::Window>(); - connection()->CreateWindow({ - .wid = menu_window, - .parent = root, - .width = 1, - .height = 1, - .c_class = x11::WindowClass::CopyFromParent, - .override_redirect = x11::Bool32(true), - }); - - SetProperty(menu_window, x11::GetAtom("_NET_WM_WINDOW_TYPE"), x11::Atom::ATOM, - x11::GetAtom("_NET_WM_WINDOW_TYPE_MENU")); - - SetUseOSWindowFrame(menu_window, false); - ShowAndSetXWindowBounds(menu_window, gfx::Rect(140, 110, 100, 100)); - connection()->DispatchAll(); - - EXPECT_EQ(window, FindTopmostXWindowAt(110, 110)); - EXPECT_EQ(menu_window, FindTopmostXWindowAt(150, 120)); - EXPECT_EQ(menu_window, FindTopmostXWindowAt(210, 120)); - - connection()->DestroyWindow({window}); - connection()->DestroyWindow({menu_window}); -} - -} // namespace ui diff --git a/chromium/ui/ozone/platform/x11/x11_window.cc b/chromium/ui/ozone/platform/x11/x11_window.cc index 15b5f6ff21d..3f696838ee7 100644 --- a/chromium/ui/ozone/platform/x11/x11_window.cc +++ b/chromium/ui/ozone/platform/x11/x11_window.cc @@ -22,7 +22,6 @@ #include "ui/base/x/x11_cursor.h" #include "ui/base/x/x11_os_exchange_data_provider.h" #include "ui/base/x/x11_pointer_grab.h" -#include "ui/base/x/x11_topmost_window_finder.h" #include "ui/base/x/x11_util.h" #include "ui/display/screen.h" #include "ui/events/devices/x11/touch_factory_x11.h" @@ -34,13 +33,13 @@ #include "ui/events/x/events_x_utils.h" #include "ui/events/x/x11_event_translation.h" #include "ui/gfx/geometry/skia_conversions.h" +#include "ui/gfx/image/image_skia_rep.h" #include "ui/gfx/x/x11_atom_cache.h" #include "ui/gfx/x/x11_path.h" #include "ui/gfx/x/x11_window_event_manager.h" #include "ui/gfx/x/xproto.h" #include "ui/gfx/x/xproto_util.h" #include "ui/ozone/platform/x11/hit_test_x11.h" -#include "ui/ozone/platform/x11/x11_topmost_window_finder.h" #include "ui/ozone/platform/x11/x11_window_manager.h" #include "ui/platform_window/common/platform_window_defaults.h" #include "ui/platform_window/extensions/workspace_extension_delegate.h" @@ -925,7 +924,7 @@ void X11Window::SetShape(std::unique_ptr<ShapeRects> native_shape, SkPath path_in_dip; if (native_region.getBoundaryPath(&path_in_dip)) { SkPath path_in_pixels; - path_in_dip.transform(SkMatrix(transform.matrix()), &path_in_pixels); + path_in_dip.transform(transform.matrix().asM33(), &path_in_pixels); xregion = x11::CreateRegionFromSkPath(path_in_pixels); } else { xregion = std::make_unique<std::vector<x11::Rectangle>>(); @@ -1153,17 +1152,6 @@ gfx::Rect X11Window::GetXRootWindowOuterBounds() const { return GetOuterBounds(); } -bool X11Window::ContainsPointInXRegion(const gfx::Point& point) const { - if (!shape()) - return true; - - for (const auto& rect : *shape()) { - if (gfx::Rect(rect.x, rect.y, rect.width, rect.height).Contains(point)) - return true; - } - return false; -} - void X11Window::LowerXWindow() { ui::LowerWindow(xwindow_); } @@ -1468,13 +1456,9 @@ void X11Window::CancelDrag() { QuitDragLoop(); } -std::unique_ptr<XTopmostWindowFinder> X11Window::CreateWindowFinder() { +absl::optional<gfx::AcceleratedWidget> X11Window::GetDragWidget() { DCHECK(drag_handler_delegate_); - std::set<gfx::AcceleratedWidget> ignore; - auto drag_widget = drag_handler_delegate_->GetDragWidget(); - if (drag_widget) - ignore.insert(*drag_widget); - return std::make_unique<X11TopmostWindowFinder>(ignore); + return drag_handler_delegate_->GetDragWidget(); } int X11Window::UpdateDrag(const gfx::Point& screen_point) { @@ -2184,9 +2168,14 @@ void X11Window::OnWindowMapped() { void X11Window::OnConfigureEvent(const x11::ConfigureNotifyEvent& configure, bool send_event) { - DCHECK_EQ(xwindow_, configure.window); DCHECK_EQ(xwindow_, configure.event); + // ConfigureNotifyEvent could be received for child windows. Ignore events for + // child windows. + if (xwindow_ != configure.window) { + return; + } + if (pending_counter_value_) { DCHECK(!configure_counter_value_); configure_counter_value_ = pending_counter_value_; @@ -2290,7 +2279,7 @@ void X11Window::OnFrameExtentsUpdated() { insets.size() == 4) { // |insets| are returned in the order: [left, right, top, bottom]. native_window_frame_borders_in_pixels_ = - gfx::Insets(insets[2], insets[0], insets[3], insets[1]); + gfx::Insets::TLBR(insets[2], insets[0], insets[3], insets[1]); } else { native_window_frame_borders_in_pixels_ = gfx::Insets(); } diff --git a/chromium/ui/ozone/platform/x11/x11_window.h b/chromium/ui/ozone/platform/x11/x11_window.h index 0b4ccfed941..81d42ae3167 100644 --- a/chromium/ui/ozone/platform/x11/x11_window.h +++ b/chromium/ui/ozone/platform/x11/x11_window.h @@ -11,6 +11,7 @@ #include <vector> #include "base/cancelable_callback.h" +#include "base/containers/flat_set.h" #include "base/gtest_prod_util.h" #include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h" #include "ui/base/x/x11_desktop_window_move_client.h" @@ -62,7 +63,6 @@ class X11Window : public PlatformWindow, virtual void Initialize(PlatformWindowInitProperties properties); // X11WindowManager calls this. - // XWindow override: void OnXWindowLostCapture(); void OnMouseEnter(); @@ -71,6 +71,8 @@ class X11Window : public PlatformWindow, gfx::Rect GetOuterBounds() const; void SetTransientWindow(x11::Window window); + bool has_pointer() const { return has_pointer_; } + // PlatformWindow: void Show(bool inactive) override; void Hide() override; @@ -128,7 +130,6 @@ class X11Window : public PlatformWindow, bool IsWmTiling() const override; void OnCompleteSwapAfterResize() override; gfx::Rect GetXRootWindowOuterBounds() const override; - bool ContainsPointInXRegion(const gfx::Point& point) const override; void LowerXWindow() override; void SetOverrideRedirect(bool override_redirect) override; bool CanResetOverrideRedirect() const override; @@ -186,7 +187,7 @@ class X11Window : public PlatformWindow, void CancelDrag() override; // XDragDropClient::Delegate - std::unique_ptr<XTopmostWindowFinder> CreateWindowFinder() override; + absl::optional<gfx::AcceleratedWidget> GetDragWidget() override; int UpdateDrag(const gfx::Point& screen_point) override; void UpdateCursor(mojom::DragOperation negotiated_operation) override; void OnBeginForeignDrag(x11::Window window) override; diff --git a/chromium/ui/ozone/platform/x11/x11_window_manager.cc b/chromium/ui/ozone/platform/x11/x11_window_manager.cc index eaa7c5803c6..2db427e0fcd 100644 --- a/chromium/ui/ozone/platform/x11/x11_window_manager.cc +++ b/chromium/ui/ozone/platform/x11/x11_window_manager.cc @@ -87,7 +87,6 @@ void X11WindowManager::RemoveWindow(X11Window* window) { } X11Window* X11WindowManager::GetWindow(gfx::AcceleratedWidget widget) const { - DCHECK_NE(gfx::kNullAcceleratedWidget, widget); auto it = windows_.find(widget); return it != windows_.end() ? it->second : nullptr; } @@ -100,11 +99,4 @@ void X11WindowManager::MouseOnWindow(X11Window* window) { window->OnMouseEnter(); } -std::vector<X11Window*> X11WindowManager::GetAllOpenWindows() const { - std::vector<X11Window*> all_windows; - for (const auto& item : windows_) - all_windows.push_back(item.second); - return all_windows; -} - } // namespace ui diff --git a/chromium/ui/ozone/platform/x11/x11_window_manager.h b/chromium/ui/ozone/platform/x11/x11_window_manager.h index 80e05108aee..0ca496cb4a5 100644 --- a/chromium/ui/ozone/platform/x11/x11_window_manager.h +++ b/chromium/ui/ozone/platform/x11/x11_window_manager.h @@ -47,8 +47,6 @@ class X11WindowManager { return window_mouse_currently_on_; } - std::vector<X11Window*> GetAllOpenWindows() const; - private: X11Window* located_events_grabber_ = nullptr; X11Window* window_mouse_currently_on_ = nullptr; 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 2d02e1ef523..f130507c508 100644 --- a/chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc +++ b/chromium/ui/ozone/platform/x11/x11_window_ozone_unittest.cc @@ -60,7 +60,7 @@ class TestScreen : public display::ScreenBase { display.SetScaleAndBounds(scale, bounds_in_pixels); ProcessDisplayChanged(display, true); } -}; // namespace +}; } // namespace diff --git a/chromium/ui/ozone/public/hardware_capabilities.h b/chromium/ui/ozone/public/hardware_capabilities.h new file mode 100644 index 00000000000..16bebaf0545 --- /dev/null +++ b/chromium/ui/ozone/public/hardware_capabilities.h @@ -0,0 +1,23 @@ +// Copyright 2022 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_HARDWARE_CAPABILITIES_H_ +#define UI_OZONE_PUBLIC_HARDWARE_CAPABILITIES_H_ + +#include "base/callback.h" + +namespace ui { + +struct HardwareCapabilities { + // Number of planes available to the current CRTC(s). + // This is specifically the count of non-CURSOR planes, because some boards + // may have extra PRIMARY planes that could be used for overlays. + int num_overlay_capable_planes = 0; +}; +using HardwareCapabilitiesCallback = + base::RepeatingCallback<void(HardwareCapabilities)>; + +} // namespace ui + +#endif // UI_OZONE_PUBLIC_HARDWARE_CAPABILITIES_H_ diff --git a/chromium/ui/ozone/public/overlay_candidates_ozone.cc b/chromium/ui/ozone/public/overlay_candidates_ozone.cc index 29730279999..36be2a38f7b 100644 --- a/chromium/ui/ozone/public/overlay_candidates_ozone.cc +++ b/chromium/ui/ozone/public/overlay_candidates_ozone.cc @@ -13,6 +13,9 @@ void OverlayCandidatesOzone::CheckOverlaySupport( NOTREACHED(); } -OverlayCandidatesOzone::~OverlayCandidatesOzone() {} +void OverlayCandidatesOzone::ObserveHardwareCapabilities( + ui::HardwareCapabilitiesCallback receive_callback) {} + +OverlayCandidatesOzone::~OverlayCandidatesOzone() = default; } // namespace ui diff --git a/chromium/ui/ozone/public/overlay_candidates_ozone.h b/chromium/ui/ozone/public/overlay_candidates_ozone.h index 27e32a9abcf..f6d2db2eb98 100644 --- a/chromium/ui/ozone/public/overlay_candidates_ozone.h +++ b/chromium/ui/ozone/public/overlay_candidates_ozone.h @@ -8,6 +8,7 @@ #include <vector> #include "base/component_export.h" +#include "ui/ozone/public/hardware_capabilities.h" #include "ui/ozone/public/overlay_surface_candidate.h" namespace ui { @@ -27,6 +28,14 @@ class COMPONENT_EXPORT(OZONE_BASE) OverlayCandidatesOzone { // if necessary. virtual void CheckOverlaySupport(OverlaySurfaceCandidateList* surfaces); + // Register `receive_callback` to be called with the latest + // HardwareCapbalitites, whenever displays are configured. + // `receive_callback` may be called once after OverlayCandidatesOzone is + // destroyed if there is an in-flight callback, so it should be bound with a + // WeakPtr. + virtual void ObserveHardwareCapabilities( + ui::HardwareCapabilitiesCallback receive_callback); + // This should be invoked during overlay processing to indicate if there are // any candidates for this processor that have an overlay requirement. virtual void RegisterOverlayRequirement(bool requires_overlay) {} diff --git a/chromium/ui/ozone/public/ozone_switches.cc b/chromium/ui/ozone/public/ozone_switches.cc index 60ff1cd4763..1f6ccc48ff3 100644 --- a/chromium/ui/ozone/public/ozone_switches.cc +++ b/chromium/ui/ozone/public/ozone_switches.cc @@ -26,11 +26,6 @@ const char kDisableWaylandIme[] = "disable-wayland-ime"; // See https://crbug.com/1220274 const char kUseWaylandExplicitGrab[] = "use-wayland-explicit-grab"; -// Use normal priority (ThreadPriority::NORMAL) for Wayland event watcher -// thread ("wayland-fd"). See https://crbug.com/1262133 -const char kUseWaylandNormalThreadPriority[] = - "use-wayland-normal-thread-priority"; - // Disable explicit DMA-fences const char kDisableExplicitDmaFences[] = "disable-explicit-dma-fences"; @@ -44,4 +39,10 @@ const char kDisableBufferBWCompression[] = "disable-buffer-bw-compression"; // Specifies ozone screen size. const char kOzoneOverrideScreenSize[] = "ozone-override-screen-size"; +// ChromeOS uses one of two VideoDecoder implementations based on SoC/board +// specific configurations that are signalled via this command line flag. +// TODO(b/159825227): remove when the "old" video decoder is fully launched. +const char kPlatformDisallowsChromeOSDirectVideoDecoder[] = + "platform-disallows-chromeos-direct-video-decoder"; + } // namespace switches diff --git a/chromium/ui/ozone/public/ozone_switches.h b/chromium/ui/ozone/public/ozone_switches.h index 3a56b500e21..ca63b0d2626 100644 --- a/chromium/ui/ozone/public/ozone_switches.h +++ b/chromium/ui/ozone/public/ozone_switches.h @@ -23,9 +23,6 @@ COMPONENT_EXPORT(OZONE_SWITCHES) extern const char kDisableWaylandIme[]; COMPONENT_EXPORT(OZONE_SWITCHES) extern const char kUseWaylandExplicitGrab[]; -COMPONENT_EXPORT(OZONE_SWITCHES) -extern const char kUseWaylandNormalThreadPriority[]; - COMPONENT_EXPORT(OZONE_SWITCHES) extern const char kDisableExplicitDmaFences[]; COMPONENT_EXPORT(OZONE_SWITCHES) @@ -36,6 +33,9 @@ extern const char kDisableBufferBWCompression[]; COMPONENT_EXPORT(OZONE_SWITCHES) extern const char kOzoneOverrideScreenSize[]; +COMPONENT_EXPORT(OZONE_SWITCHES) +extern const char kPlatformDisallowsChromeOSDirectVideoDecoder[]; + } // namespace switches #endif // UI_OZONE_PUBLIC_OZONE_SWITCHES_H_ diff --git a/chromium/ui/ozone/public/platform_screen.cc b/chromium/ui/ozone/public/platform_screen.cc index bc517733f58..98f599aa41d 100644 --- a/chromium/ui/ozone/public/platform_screen.cc +++ b/chromium/ui/ozone/public/platform_screen.cc @@ -6,6 +6,7 @@ #include "base/notreached.h" #include "base/time/time.h" +#include "ui/gfx/geometry/point.h" namespace ui { @@ -19,6 +20,11 @@ gfx::AcceleratedWidget PlatformScreen::GetLocalProcessWidgetAtPoint( return gfx::kNullAcceleratedWidget; } +bool PlatformScreen::IsAcceleratedWidgetUnderCursor( + gfx::AcceleratedWidget widget) const { + return GetAcceleratedWidgetAtScreenPoint(GetCursorScreenPoint()) == widget; +} + std::string PlatformScreen::GetCurrentWorkspace() { NOTIMPLEMENTED_LOG_ONCE(); return {}; diff --git a/chromium/ui/ozone/public/platform_screen.h b/chromium/ui/ozone/public/platform_screen.h index 43dc9984bd8..091220a99f7 100644 --- a/chromium/ui/ozone/public/platform_screen.h +++ b/chromium/ui/ozone/public/platform_screen.h @@ -68,6 +68,9 @@ class COMPONENT_EXPORT(OZONE_BASE) PlatformScreen { // TODO(rjkroege): Verify these semantics. virtual gfx::Point GetCursorScreenPoint() const = 0; + virtual bool IsAcceleratedWidgetUnderCursor( + gfx::AcceleratedWidget widget) const; + virtual gfx::AcceleratedWidget GetAcceleratedWidgetAtScreenPoint( const gfx::Point& point) const = 0; diff --git a/chromium/ui/ozone/public/surface_ozone_canvas.cc b/chromium/ui/ozone/public/surface_ozone_canvas.cc index eb506f97f02..d3de60cafd0 100644 --- a/chromium/ui/ozone/public/surface_ozone_canvas.cc +++ b/chromium/ui/ozone/public/surface_ozone_canvas.cc @@ -6,6 +6,8 @@ #include "base/notreached.h" +#include <ostream> + namespace ui { SurfaceOzoneCanvas::~SurfaceOzoneCanvas() = default; diff --git a/chromium/ui/ozone/public/system_input_injector.h b/chromium/ui/ozone/public/system_input_injector.h index d69d128e261..68acb1b8850 100644 --- a/chromium/ui/ozone/public/system_input_injector.h +++ b/chromium/ui/ozone/public/system_input_injector.h @@ -19,12 +19,16 @@ namespace ui { // native events. class COMPONENT_EXPORT(OZONE) SystemInputInjector { public: - SystemInputInjector() {} + SystemInputInjector() = default; SystemInputInjector(const SystemInputInjector&) = delete; SystemInputInjector& operator=(const SystemInputInjector&) = delete; - virtual ~SystemInputInjector() {} + virtual ~SystemInputInjector() = default; + + // Set the device id that will be used for all the generated events. + // The device id is set to |ui::ED_UNKNOWN_DEVICE| by default. + virtual void SetDeviceId(int device_id) = 0; // Moves the cursor on the screen and generates the corresponding MouseMove or // MouseDragged event. |location| is in physical screen coordinates, |