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 157 158 159 160 161
|
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <vector>
#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, fd] = ui::test::FindDrmDriverOrDie("vkms");
drm_device_->AddGraphicsDevice(path, mojo::PlatformHandle(std::move(fd)));
}
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](const std::vector<display::DisplayConfigurationParams>&
request_results,
bool success) {
EXPECT_TRUE(success) << "Unable to set up displays.";
run_loop.Quit();
});
drm_device_->ConfigureNativeDisplays(params,
{display::ModesetFlag::kTestModeset,
display::ModesetFlag::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.push_back(ui::DrmOverlayPlane::TestPlane(
framebuffer, gfx::ColorSpace::CreateSRGB(),
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);
}
|