summaryrefslogtreecommitdiff
path: root/chromium/ui/ozone/platform/drm/test/vkms_tests.cc
blob: d0faea472e1231307d8f13b7496901bce9632ae6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// 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 <vector>

#include "base/logging.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/types/display_configuration_params.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/gpu_fence.h"
#include "ui/gfx/gpu_fence_handle.h"
#include "ui/gfx/linux/gbm_buffer.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/presentation_feedback.h"
#include "ui/gfx/swap_result.h"
#include "ui/ozone/platform/drm/common/display_types.h"
#include "ui/ozone/platform/drm/gpu/drm_framebuffer.h"
#include "ui/ozone/platform/drm/gpu/drm_overlay_plane.h"
#include "ui/ozone/platform/drm/gpu/drm_thread_proxy.h"
#include "ui/ozone/platform/drm/gpu/drm_window_proxy.h"
#include "ui/ozone/platform/drm/test/integration_test_helpers.h"

class VKMSTest : public testing::Test {
 public:
  VKMSTest() = default;

  void SetUp() override {
    base::RunLoop run_loop;
    drm_thread_proxy_ = std::make_unique<ui::DrmThreadProxy>();
    drm_thread_proxy_->StartDrmThread(run_loop.QuitClosure());
    drm_thread_proxy_->WaitUntilDrmThreadStarted();
    drm_thread_proxy_->AddDrmDeviceReceiver(
        drm_device_.BindNewPipeAndPassReceiver());
    run_loop.Run();

    auto [path, file] = ui::test::FindDrmDriverOrDie("vkms");
    drm_device_->AddGraphicsDevice(path, std::move(file));
  }

 protected:
  ui::MovableDisplaySnapshots RefreshDisplays() {
    ui::MovableDisplaySnapshots output;

    base::RunLoop run_loop;
    auto callback =
        base::BindLambdaForTesting([&](ui::MovableDisplaySnapshots snapshots) {
          output = std::move(snapshots);
          run_loop.Quit();
        });
    drm_device_->RefreshNativeDisplays(callback);
    run_loop.Run();

    return output;
  }

  ui::MovableDisplaySnapshots SetupDisplaysHorizontally() {
    auto displays = RefreshDisplays();
    std::vector<display::DisplayConfigurationParams> params;
    uint32_t x = 0;
    for (auto& display : displays) {
      const auto* mode = display->modes()[0].get();
      params.emplace_back(display->display_id(), gfx::Point(x, 0), mode);
      x += mode->size().width();
    }

    base::RunLoop run_loop;
    auto callback = base::BindLambdaForTesting([&run_loop](bool success) {
      EXPECT_TRUE(success) << "Unable to set up displays.";
      run_loop.Quit();
    });
    drm_device_->ConfigureNativeDisplays(
        params, display::kTestModeset | display::kCommitModeset, callback);
    run_loop.Run();

    return RefreshDisplays();
  }

  void FlipExpectingRecreateBuffers(
      const std::unique_ptr<ui::DrmWindowProxy>& window_proxy) {
    base::RunLoop run_loop;
    auto submission_callback =
        base::BindOnce([](gfx::SwapResult result, gfx::GpuFenceHandle handle) {
          EXPECT_EQ(result, gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS);
        });
    auto presentation_callback = base::BindLambdaForTesting(
        [&run_loop](const gfx::PresentationFeedback& feedback) {
          EXPECT_TRUE(feedback.failed());
          run_loop.Quit();
        });
    auto planes = std::vector<ui::DrmOverlayPlane>();
    window_proxy->SchedulePageFlip(std::move(planes),
                                   std::move(submission_callback),
                                   std::move(presentation_callback));
    run_loop.Run();
  }

  // This should be first, so that it is destructed last. The DRM thread
  // interacts with current IO thread when it is destructed.
  base::test::TaskEnvironment task_environment_{
      base::test::TaskEnvironment::MainThreadType::IO};

  std::unique_ptr<ui::DrmThreadProxy> drm_thread_proxy_ = nullptr;
  mojo::Remote<ui::ozone::mojom::DrmDevice> drm_device_;
};

TEST_F(VKMSTest, DisplaysAreAvailable) {
  auto snapshots = RefreshDisplays();
  EXPECT_GT(snapshots.size(), 0ul);
}

TEST_F(VKMSTest, SinglePlanePageFlip) {
  auto displays = SetupDisplaysHorizontally();

  constexpr gfx::AcceleratedWidget kWidget = 1;
  const auto kWindowRect =
      gfx::Rect(displays[0]->origin(), displays[0]->current_mode()->size());

  drm_device_->CreateWindow(kWidget, kWindowRect);
  auto window_proxy = drm_thread_proxy_->CreateDrmWindowProxy(kWidget);
  FlipExpectingRecreateBuffers(window_proxy);

  // Note that as of 2022/04, the only vkms-supported buffers are RGB. Note that
  // the BufferFormat order is flipped from DRM. See here for our conversions:
  // ui/gfx/linux/drm_util_linux.cc
  std::unique_ptr<ui::GbmBuffer> buffer;
  scoped_refptr<ui::DrmFramebuffer> framebuffer;
  drm_thread_proxy_->CreateBuffer(
      kWidget, kWindowRect.size(), kWindowRect.size(),
      gfx::BufferFormat::BGRX_8888, gfx::BufferUsage::SCANOUT_CPU_READ_WRITE,
      /*flags=*/0, &buffer, &framebuffer);

  auto planes = std::vector<ui::DrmOverlayPlane>();
  planes.emplace_back(framebuffer,
                      std::make_unique<gfx::GpuFence>(gfx::GpuFenceHandle()));

  base::RunLoop run_loop;
  auto submission_callback =
      base::BindOnce([](gfx::SwapResult result, gfx::GpuFenceHandle handle) {
        EXPECT_EQ(result, gfx::SwapResult::SWAP_ACK);
      });
  auto presentation_callback = base::BindLambdaForTesting(
      [&](const gfx::PresentationFeedback& feedback) {
        EXPECT_FALSE(feedback.failed());
        run_loop.Quit();
      });
  window_proxy->SchedulePageFlip(std::move(planes),
                                 std::move(submission_callback),
                                 std::move(presentation_callback));
  run_loop.Run();

  drm_device_->DestroyWindow(kWidget);
}