1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/ozone/platform/drm/gpu/drm_overlay_validator.h"
6
7 #include <drm_fourcc.h>
8 #include <xf86drm.h>
9
10 #include <memory>
11 #include <utility>
12
13 #include "base/files/platform_file.h"
14 #include "base/test/task_environment.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "ui/gfx/geometry/rect_conversions.h"
17 #include "ui/gfx/gpu_fence.h"
18 #include "ui/gfx/linux/drm_util_linux.h"
19 #include "ui/gfx/linux/gbm_buffer.h"
20 #include "ui/gfx/linux/test/mock_gbm_device.h"
21 #include "ui/ozone/platform/drm/common/drm_util.h"
22 #include "ui/ozone/platform/drm/gpu/crtc_controller.h"
23 #include "ui/ozone/platform/drm/gpu/drm_device_generator.h"
24 #include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
25 #include "ui/ozone/platform/drm/gpu/drm_framebuffer.h"
26 #include "ui/ozone/platform/drm/gpu/drm_window.h"
27 #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
28 #include "ui/ozone/platform/drm/gpu/mock_drm_device.h"
29 #include "ui/ozone/platform/drm/gpu/screen_manager.h"
30
31 namespace {
32
33 // Mode of size 12x8.
34 const drmModeModeInfo kDefaultMode = {0, 12, 0, 0, 0, 0, 8, 0,
35 0, 0, 0, 0, 0, 0, {'\0'}};
36
37 const gfx::AcceleratedWidget kDefaultWidgetHandle = 1;
38 constexpr uint32_t kCrtcIdBase = 1;
39 constexpr uint32_t kConnectorIdBase = 100;
40 constexpr uint32_t kPlaneIdBase = 200;
41 constexpr uint32_t kInFormatsBlobPropIdBase = 400;
42
43 constexpr uint32_t kTypePropId = 3010;
44 constexpr uint32_t kInFormatsPropId = 3011;
45
46 } // namespace
47
48 class DrmOverlayValidatorTest : public testing::Test {
49 public:
50 DrmOverlayValidatorTest() = default;
51
52 void SetUp() override;
53 void TearDown() override;
54
OnSwapBuffers(gfx::SwapResult result)55 void OnSwapBuffers(gfx::SwapResult result) {
56 on_swap_buffers_count_++;
57 last_swap_buffers_result_ = result;
58 }
59
ReturnNullBuffer(const gfx::Size & size,uint32_t format)60 scoped_refptr<ui::DrmFramebuffer> ReturnNullBuffer(const gfx::Size& size,
61 uint32_t format) {
62 return nullptr;
63 }
64
65 void AddPlane(const ui::OverlaySurfaceCandidate& params);
66
CreateBuffer()67 scoped_refptr<ui::DrmFramebuffer> CreateBuffer() {
68 auto gbm_buffer = drm_->gbm_device()->CreateBuffer(
69 DRM_FORMAT_XRGB8888, primary_rect_.size(), GBM_BO_USE_SCANOUT);
70 return ui::DrmFramebuffer::AddFramebuffer(drm_, gbm_buffer.get(),
71 primary_rect_.size());
72 }
73
CreateOverlayBuffer(uint32_t format,const gfx::Size & size)74 scoped_refptr<ui::DrmFramebuffer> CreateOverlayBuffer(uint32_t format,
75 const gfx::Size& size) {
76 auto gbm_buffer =
77 drm_->gbm_device()->CreateBuffer(format, size, GBM_BO_USE_SCANOUT);
78 return ui::DrmFramebuffer::AddFramebuffer(drm_, gbm_buffer.get(), size);
79 }
80
ModesetController(ui::HardwareDisplayController * controller)81 bool ModesetController(ui::HardwareDisplayController* controller) {
82 ui::CommitRequest commit_request;
83
84 ui::DrmOverlayPlane plane(CreateBuffer(), nullptr);
85
86 controller->GetModesetProps(&commit_request, plane, kDefaultMode);
87 ui::CommitRequest request_for_update = commit_request;
88 bool status = drm_->plane_manager()->Commit(std::move(commit_request),
89 DRM_MODE_ATOMIC_ALLOW_MODESET);
90 controller->UpdateState(
91 /*enable_requested=*/true,
92 ui::DrmOverlayPlane::GetPrimaryPlane(request_for_update[0].overlays()));
93
94 return status;
95 }
96
97 protected:
98 struct PlaneState {
99 std::vector<uint32_t> formats;
100 };
101
102 struct CrtcState {
103 std::vector<PlaneState> planes;
104 };
105
106 void InitDrmStatesAndControllers(const std::vector<CrtcState>& crtc_states);
107
108 base::test::SingleThreadTaskEnvironment task_environment_{
109 base::test::SingleThreadTaskEnvironment::MainThreadType::UI};
110 scoped_refptr<ui::MockDrmDevice> drm_;
111 ui::MockGbmDevice* gbm_ = nullptr;
112 std::unique_ptr<ui::ScreenManager> screen_manager_;
113 std::unique_ptr<ui::DrmDeviceManager> drm_device_manager_;
114 ui::DrmWindow* window_;
115 std::unique_ptr<ui::DrmOverlayValidator> overlay_validator_;
116 std::vector<ui::OverlaySurfaceCandidate> overlay_params_;
117 ui::DrmOverlayPlaneList plane_list_;
118
119 int on_swap_buffers_count_;
120 gfx::SwapResult last_swap_buffers_result_;
121 gfx::Rect overlay_rect_;
122 gfx::Rect primary_rect_;
123
124 private:
125 void SetupControllers();
126
127 DISALLOW_COPY_AND_ASSIGN(DrmOverlayValidatorTest);
128 };
129
SetUp()130 void DrmOverlayValidatorTest::SetUp() {
131 on_swap_buffers_count_ = 0;
132 last_swap_buffers_result_ = gfx::SwapResult::SWAP_FAILED;
133
134 auto gbm = std::make_unique<ui::MockGbmDevice>();
135 gbm_ = gbm.get();
136 drm_ = new ui::MockDrmDevice(std::move(gbm));
137 }
138
InitDrmStatesAndControllers(const std::vector<CrtcState> & crtc_states)139 void DrmOverlayValidatorTest::InitDrmStatesAndControllers(
140 const std::vector<CrtcState>& crtc_states) {
141 std::vector<ui::MockDrmDevice::CrtcProperties> crtc_properties(
142 crtc_states.size());
143 std::map<uint32_t, std::string> crtc_property_names = {
144 {1000, "ACTIVE"},
145 {1001, "MODE_ID"},
146 };
147
148 std::vector<ui::MockDrmDevice::ConnectorProperties> connector_properties(2);
149 std::map<uint32_t, std::string> connector_property_names = {
150 {2000, "CRTC_ID"},
151 };
152 for (size_t i = 0; i < connector_properties.size(); ++i) {
153 connector_properties[i].id = kConnectorIdBase + i;
154 for (const auto& pair : connector_property_names) {
155 connector_properties[i].properties.push_back(
156 {/* .id = */ pair.first, /* .value = */ 0});
157 }
158 }
159
160 std::vector<ui::MockDrmDevice::PlaneProperties> plane_properties;
161 std::map<uint32_t, std::string> plane_property_names = {
162 // Add all required properties.
163 {3000, "CRTC_ID"},
164 {3001, "CRTC_X"},
165 {3002, "CRTC_Y"},
166 {3003, "CRTC_W"},
167 {3004, "CRTC_H"},
168 {3005, "FB_ID"},
169 {3006, "SRC_X"},
170 {3007, "SRC_Y"},
171 {3008, "SRC_W"},
172 {3009, "SRC_H"},
173 // Defines some optional properties we use for convenience.
174 {kTypePropId, "type"},
175 {kInFormatsPropId, "IN_FORMATS"},
176 };
177
178 uint32_t plane_id = kPlaneIdBase;
179 uint32_t property_id = kInFormatsBlobPropIdBase;
180
181 for (size_t crtc_idx = 0; crtc_idx < crtc_states.size(); ++crtc_idx) {
182 crtc_properties[crtc_idx].id = kCrtcIdBase + crtc_idx;
183 for (const auto& pair : crtc_property_names) {
184 crtc_properties[crtc_idx].properties.push_back(
185 {/* .id = */ pair.first, /* .value = */ 0});
186 }
187
188 std::vector<ui::MockDrmDevice::PlaneProperties> crtc_plane_properties(
189 crtc_states[crtc_idx].planes.size());
190 for (size_t plane_idx = 0; plane_idx < crtc_states[crtc_idx].planes.size();
191 ++plane_idx) {
192 crtc_plane_properties[plane_idx].id = plane_id++;
193 crtc_plane_properties[plane_idx].crtc_mask = 1 << crtc_idx;
194
195 for (const auto& pair : plane_property_names) {
196 uint64_t value = 0;
197 if (pair.first == kTypePropId) {
198 value =
199 plane_idx == 0 ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
200 } else if (pair.first == kInFormatsPropId) {
201 value = property_id++;
202 drm_->SetPropertyBlob(ui::MockDrmDevice::AllocateInFormatsBlob(
203 value, crtc_states[crtc_idx].planes[plane_idx].formats,
204 std::vector<drm_format_modifier>()));
205 }
206
207 crtc_plane_properties[plane_idx].properties.push_back(
208 {/* .id = */ pair.first, /* .value = */ value});
209 }
210 }
211
212 plane_properties.insert(plane_properties.end(),
213 crtc_plane_properties.begin(),
214 crtc_plane_properties.end());
215 }
216
217 std::map<uint32_t, std::string> property_names;
218 property_names.insert(crtc_property_names.begin(), crtc_property_names.end());
219 property_names.insert(connector_property_names.begin(),
220 connector_property_names.end());
221 property_names.insert(plane_property_names.begin(),
222 plane_property_names.end());
223 drm_->InitializeState(crtc_properties, connector_properties, plane_properties,
224 property_names,
225 /* use_atomic= */ true);
226
227 SetupControllers();
228 }
229
SetupControllers()230 void DrmOverlayValidatorTest::SetupControllers() {
231 screen_manager_ = std::make_unique<ui::ScreenManager>();
232 screen_manager_->AddDisplayController(drm_, kCrtcIdBase, kConnectorIdBase);
233 std::vector<ui::ScreenManager::ControllerConfigParams> controllers_to_enable;
234 controllers_to_enable.emplace_back(
235 1 /*display_id*/, drm_, kCrtcIdBase, kConnectorIdBase, gfx::Point(),
236 std::make_unique<drmModeModeInfo>(kDefaultMode));
237 screen_manager_->ConfigureDisplayControllers(controllers_to_enable);
238
239 drm_device_manager_ = std::make_unique<ui::DrmDeviceManager>(nullptr);
240
241 std::unique_ptr<ui::DrmWindow> window(new ui::DrmWindow(
242 kDefaultWidgetHandle, drm_device_manager_.get(), screen_manager_.get()));
243 window->Initialize();
244 window->SetBounds(
245 gfx::Rect(gfx::Size(kDefaultMode.hdisplay, kDefaultMode.vdisplay)));
246 screen_manager_->AddWindow(kDefaultWidgetHandle, std::move(window));
247 window_ = screen_manager_->GetWindow(kDefaultWidgetHandle);
248 overlay_validator_ = std::make_unique<ui::DrmOverlayValidator>(window_);
249
250 overlay_rect_ =
251 gfx::Rect(0, 0, kDefaultMode.hdisplay / 2, kDefaultMode.vdisplay / 2);
252
253 primary_rect_ = gfx::Rect(0, 0, kDefaultMode.hdisplay, kDefaultMode.vdisplay);
254
255 ui::OverlaySurfaceCandidate primary_candidate;
256 primary_candidate.buffer_size = primary_rect_.size();
257 primary_candidate.display_rect = gfx::RectF(primary_rect_);
258 primary_candidate.is_opaque = true;
259 primary_candidate.format = gfx::BufferFormat::BGRX_8888;
260 primary_candidate.overlay_handled = true;
261 overlay_params_.push_back(primary_candidate);
262 AddPlane(primary_candidate);
263
264 ui::OverlaySurfaceCandidate overlay_candidate;
265 overlay_candidate.buffer_size = overlay_rect_.size();
266 overlay_candidate.display_rect = gfx::RectF(overlay_rect_);
267 overlay_candidate.plane_z_order = 1;
268 primary_candidate.is_opaque = true;
269 overlay_candidate.format = gfx::BufferFormat::BGRX_8888;
270 overlay_candidate.overlay_handled = true;
271 overlay_params_.push_back(overlay_candidate);
272 AddPlane(overlay_candidate);
273 }
274
AddPlane(const ui::OverlaySurfaceCandidate & params)275 void DrmOverlayValidatorTest::AddPlane(
276 const ui::OverlaySurfaceCandidate& params) {
277 scoped_refptr<ui::DrmDevice> drm = window_->GetController()->GetDrmDevice();
278
279 scoped_refptr<ui::DrmFramebuffer> drm_framebuffer = CreateOverlayBuffer(
280 ui::GetFourCCFormatFromBufferFormat(params.format), params.buffer_size);
281 plane_list_.push_back(ui::DrmOverlayPlane(
282 std::move(drm_framebuffer), params.plane_z_order, params.transform,
283 gfx::ToNearestRect(params.display_rect), params.crop_rect, true,
284 nullptr));
285 }
286
TearDown()287 void DrmOverlayValidatorTest::TearDown() {
288 std::unique_ptr<ui::DrmWindow> window =
289 screen_manager_->RemoveWindow(kDefaultWidgetHandle);
290 window->Shutdown();
291 }
292
TEST_F(DrmOverlayValidatorTest,WindowWithNoController)293 TEST_F(DrmOverlayValidatorTest, WindowWithNoController) {
294 CrtcState crtc_state = {/* .planes = */ {
295 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
296 }};
297 InitDrmStatesAndControllers({crtc_state});
298
299 // We should never promote layers to overlay when controller is not
300 // present.
301 ui::HardwareDisplayController* controller = window_->GetController();
302 window_->SetController(nullptr);
303 std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip(
304 overlay_params_, ui::DrmOverlayPlaneList());
305 EXPECT_EQ(returns.front(), ui::OVERLAY_STATUS_NOT);
306 EXPECT_EQ(returns.back(), ui::OVERLAY_STATUS_NOT);
307 window_->SetController(controller);
308 }
309
TEST_F(DrmOverlayValidatorTest,DontPromoteMoreLayersThanAvailablePlanes)310 TEST_F(DrmOverlayValidatorTest, DontPromoteMoreLayersThanAvailablePlanes) {
311 CrtcState crtc_state = {/* .planes = */ {
312 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
313 }};
314 InitDrmStatesAndControllers({crtc_state});
315
316 std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip(
317 overlay_params_, ui::DrmOverlayPlaneList());
318 EXPECT_EQ(returns.front(), ui::OVERLAY_STATUS_ABLE);
319 EXPECT_EQ(returns.back(), ui::OVERLAY_STATUS_NOT);
320 }
321
TEST_F(DrmOverlayValidatorTest,DontCollapseOverlayToPrimaryInFullScreen)322 TEST_F(DrmOverlayValidatorTest, DontCollapseOverlayToPrimaryInFullScreen) {
323 CrtcState crtc_state = {/* .planes = */ {
324 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
325 }};
326 InitDrmStatesAndControllers({crtc_state});
327
328 // Overlay Validator should not collapse planes during validation.
329 overlay_params_.back().buffer_size = primary_rect_.size();
330 overlay_params_.back().display_rect = gfx::RectF(primary_rect_);
331 plane_list_.back().display_bounds = primary_rect_;
332
333 std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip(
334 overlay_params_, ui::DrmOverlayPlaneList());
335 // Second candidate should be marked as Invalid as we have only one plane
336 // per CRTC.
337 EXPECT_EQ(returns.front(), ui::OVERLAY_STATUS_ABLE);
338 EXPECT_EQ(returns.back(), ui::OVERLAY_STATUS_NOT);
339 }
340
TEST_F(DrmOverlayValidatorTest,OverlayFormat_XRGB)341 TEST_F(DrmOverlayValidatorTest, OverlayFormat_XRGB) {
342 // This test checks for optimal format in case of non full screen video case.
343 // This should be XRGB when overlay doesn't support YUV.
344 CrtcState state = {
345 /* .planes = */
346 {
347 {/* .formats = */ {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}},
348 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
349 },
350 };
351 InitDrmStatesAndControllers(std::vector<CrtcState>(1, state));
352
353 overlay_params_.back().buffer_size = overlay_rect_.size();
354 overlay_params_.back().display_rect = gfx::RectF(overlay_rect_);
355 plane_list_.back().display_bounds = overlay_rect_;
356
357 std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip(
358 overlay_params_, ui::DrmOverlayPlaneList());
359 EXPECT_EQ(2u, returns.size());
360 for (const auto& param : returns)
361 EXPECT_EQ(param, ui::OVERLAY_STATUS_ABLE);
362 }
363
TEST_F(DrmOverlayValidatorTest,OverlayFormat_YUV)364 TEST_F(DrmOverlayValidatorTest, OverlayFormat_YUV) {
365 // This test checks for optimal format in case of non full screen video case.
366 // Prefer YUV as optimal format when Overlay supports it and scaling is
367 // needed.
368 CrtcState state = {
369 /* .planes = */
370 {
371 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
372 {/* .formats = */ {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}},
373 },
374 };
375 InitDrmStatesAndControllers(std::vector<CrtcState>(1, state));
376
377 gfx::RectF crop_rect = gfx::RectF(0, 0, 0.5, 0.5);
378 overlay_params_.back().buffer_size = overlay_rect_.size();
379 overlay_params_.back().display_rect = gfx::RectF(overlay_rect_);
380 overlay_params_.back().crop_rect = crop_rect;
381 overlay_params_.back().is_opaque = false;
382 overlay_params_.back().format = gfx::BufferFormat::YUV_420_BIPLANAR;
383 plane_list_.pop_back();
384 AddPlane(overlay_params_.back());
385
386 std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip(
387 overlay_params_, ui::DrmOverlayPlaneList());
388 EXPECT_EQ(2u, returns.size());
389 for (const auto& param : returns)
390 EXPECT_EQ(param, ui::OVERLAY_STATUS_ABLE);
391 }
392
TEST_F(DrmOverlayValidatorTest,RejectYUVBuffersIfNotSupported)393 TEST_F(DrmOverlayValidatorTest, RejectYUVBuffersIfNotSupported) {
394 // Check case where buffer storage format is already YUV 420 but planes don't
395 // support it.
396 CrtcState state = {
397 /* .planes = */
398 {
399 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
400 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
401 },
402 };
403 InitDrmStatesAndControllers(std::vector<CrtcState>(1, state));
404
405 overlay_params_.back().buffer_size = overlay_rect_.size();
406 overlay_params_.back().display_rect = gfx::RectF(overlay_rect_);
407 overlay_params_.back().format = gfx::BufferFormat::YUV_420_BIPLANAR;
408 plane_list_.pop_back();
409 AddPlane(overlay_params_.back());
410
411 std::vector<ui::OverlaySurfaceCandidate> validated_params = overlay_params_;
412 std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip(
413 validated_params, ui::DrmOverlayPlaneList());
414 EXPECT_EQ(2u, returns.size());
415 EXPECT_EQ(returns.back(), ui::OVERLAY_STATUS_NOT);
416 }
417
TEST_F(DrmOverlayValidatorTest,RejectYUVBuffersIfNotSupported_MirroredControllers)418 TEST_F(DrmOverlayValidatorTest,
419 RejectYUVBuffersIfNotSupported_MirroredControllers) {
420 std::vector<CrtcState> crtc_states = {
421 {
422 /* .planes = */
423 {
424 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
425 {/* .formats = */ {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}},
426 },
427 },
428 {
429 /* .planes = */
430 {
431 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
432 {/* .formats = */ {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}},
433 },
434 },
435 };
436 InitDrmStatesAndControllers(crtc_states);
437
438 ui::HardwareDisplayController* controller = window_->GetController();
439 controller->AddCrtc(std::make_unique<ui::CrtcController>(
440 drm_.get(), kCrtcIdBase + 1, kConnectorIdBase + 1));
441 EXPECT_TRUE(ModesetController(controller));
442
443 gfx::RectF crop_rect = gfx::RectF(0, 0, 0.5, 0.5);
444 overlay_params_.back().buffer_size = overlay_rect_.size();
445 overlay_params_.back().display_rect = gfx::RectF(overlay_rect_);
446 overlay_params_.back().crop_rect = crop_rect;
447 plane_list_.back().display_bounds = overlay_rect_;
448 plane_list_.back().crop_rect = crop_rect;
449
450 std::vector<ui::OverlaySurfaceCandidate> validated_params = overlay_params_;
451 validated_params.back().format = gfx::BufferFormat::YUV_420_BIPLANAR;
452 std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip(
453 validated_params, ui::DrmOverlayPlaneList());
454 EXPECT_EQ(2u, returns.size());
455 EXPECT_EQ(returns.back(), ui::OVERLAY_STATUS_ABLE);
456 }
457
TEST_F(DrmOverlayValidatorTest,RejectYUVBuffersIfNotSupported_NoPackedFormatsInMirroredCrtc)458 TEST_F(DrmOverlayValidatorTest,
459 RejectYUVBuffersIfNotSupported_NoPackedFormatsInMirroredCrtc) {
460 // This configuration should not be promoted to Overlay when either of the
461 // controllers don't support YUV 420 format.
462
463 std::vector<CrtcState> crtc_states = {
464 {
465 /* .planes = */
466 {
467 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
468 {/* .formats = */ {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}},
469 },
470 },
471 {
472 /* .planes = */
473 {
474 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
475 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
476 },
477 },
478 };
479 InitDrmStatesAndControllers(crtc_states);
480
481 ui::HardwareDisplayController* controller = window_->GetController();
482 controller->AddCrtc(std::make_unique<ui::CrtcController>(
483 drm_.get(), kCrtcIdBase + 1, kConnectorIdBase + 1));
484 EXPECT_TRUE(ModesetController(controller));
485
486 gfx::RectF crop_rect = gfx::RectF(0, 0, 0.5, 0.5);
487 overlay_params_.back().buffer_size = overlay_rect_.size();
488 overlay_params_.back().display_rect = gfx::RectF(overlay_rect_);
489 overlay_params_.back().crop_rect = crop_rect;
490 plane_list_.back().display_bounds = overlay_rect_;
491 plane_list_.back().crop_rect = crop_rect;
492
493 std::vector<ui::OverlaySurfaceCandidate> validated_params = overlay_params_;
494 validated_params.back().format = gfx::BufferFormat::YUV_420_BIPLANAR;
495 std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip(
496 validated_params, ui::DrmOverlayPlaneList());
497 EXPECT_EQ(2u, returns.size());
498 EXPECT_EQ(returns.back(), ui::OVERLAY_STATUS_NOT);
499 }
500
TEST_F(DrmOverlayValidatorTest,RejectYUVBuffersIfNotSupported_NoPackedFormatsInPrimaryDisplay)501 TEST_F(DrmOverlayValidatorTest,
502 RejectYUVBuffersIfNotSupported_NoPackedFormatsInPrimaryDisplay) {
503 std::vector<CrtcState> crtc_states = {
504 {
505 /* .planes = */
506 {
507 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
508 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
509 },
510 },
511 {
512 /* .planes = */
513 {
514 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
515 {/* .formats = */ {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}},
516 },
517 },
518 };
519 InitDrmStatesAndControllers(crtc_states);
520
521 ui::HardwareDisplayController* controller = window_->GetController();
522 controller->AddCrtc(std::make_unique<ui::CrtcController>(
523 drm_.get(), kCrtcIdBase + 1, kConnectorIdBase + 1));
524 EXPECT_TRUE(ModesetController(controller));
525
526 gfx::RectF crop_rect = gfx::RectF(0, 0, 0.5, 0.5);
527 overlay_params_.back().buffer_size = overlay_rect_.size();
528 overlay_params_.back().display_rect = gfx::RectF(overlay_rect_);
529 overlay_params_.back().crop_rect = crop_rect;
530 plane_list_.back().display_bounds = overlay_rect_;
531 plane_list_.back().crop_rect = crop_rect;
532
533 std::vector<ui::OverlaySurfaceCandidate> validated_params = overlay_params_;
534 validated_params.back().format = gfx::BufferFormat::YUV_420_BIPLANAR;
535
536 std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip(
537 validated_params, ui::DrmOverlayPlaneList());
538 EXPECT_EQ(2u, returns.size());
539 EXPECT_EQ(returns.back(), ui::OVERLAY_STATUS_NOT);
540 }
541
TEST_F(DrmOverlayValidatorTest,OptimalFormatXRGB_MirroredControllers)542 TEST_F(DrmOverlayValidatorTest, OptimalFormatXRGB_MirroredControllers) {
543 std::vector<CrtcState> crtc_states = {
544 {
545 /* .planes = */
546 {
547 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
548 {/* .formats = */ {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}},
549 },
550 },
551 {
552 /* .planes = */
553 {
554 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
555 {/* .formats = */ {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}},
556 },
557 },
558 };
559 InitDrmStatesAndControllers(crtc_states);
560
561 ui::HardwareDisplayController* controller = window_->GetController();
562 controller->AddCrtc(std::make_unique<ui::CrtcController>(
563 drm_.get(), kCrtcIdBase + 1, kConnectorIdBase + 1));
564 EXPECT_TRUE(ModesetController(controller));
565
566 overlay_params_.back().buffer_size = overlay_rect_.size();
567 overlay_params_.back().display_rect = gfx::RectF(overlay_rect_);
568 plane_list_.back().display_bounds = overlay_rect_;
569
570 std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip(
571 overlay_params_, ui::DrmOverlayPlaneList());
572 EXPECT_EQ(2u, returns.size());
573 EXPECT_EQ(returns.back(), ui::OVERLAY_STATUS_ABLE);
574 }
575
TEST_F(DrmOverlayValidatorTest,OptimalFormatXRGB_NoPackedFormatInMirroredCrtc)576 TEST_F(DrmOverlayValidatorTest,
577 OptimalFormatXRGB_NoPackedFormatInMirroredCrtc) {
578 std::vector<CrtcState> crtc_states = {
579 {
580 /* .planes = */
581 {
582 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
583 {/* .formats = */ {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}},
584 },
585 },
586 {
587 /* .planes = */
588 {
589 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
590 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
591 },
592 },
593 };
594 InitDrmStatesAndControllers(crtc_states);
595
596 ui::HardwareDisplayController* controller = window_->GetController();
597 controller->AddCrtc(std::make_unique<ui::CrtcController>(
598 drm_.get(), kCrtcIdBase + 1, kConnectorIdBase + 1));
599 EXPECT_TRUE(ModesetController(controller));
600
601 overlay_params_.back().buffer_size = overlay_rect_.size();
602 overlay_params_.back().display_rect = gfx::RectF(overlay_rect_);
603 plane_list_.back().display_bounds = overlay_rect_;
604
605 std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip(
606 overlay_params_, ui::DrmOverlayPlaneList());
607 EXPECT_EQ(returns.back(), ui::OVERLAY_STATUS_ABLE);
608 }
609
TEST_F(DrmOverlayValidatorTest,OptimalFormatXRGB_NoPackedFormatInPrimaryDisplay)610 TEST_F(DrmOverlayValidatorTest,
611 OptimalFormatXRGB_NoPackedFormatInPrimaryDisplay) {
612 std::vector<CrtcState> crtc_states = {
613 {
614 /* .planes = */
615 {
616 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
617 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
618 },
619 },
620 {
621 /* .planes = */
622 {
623 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
624 {/* .formats = */ {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}},
625 },
626 },
627 };
628 InitDrmStatesAndControllers(crtc_states);
629
630 ui::HardwareDisplayController* controller = window_->GetController();
631 controller->AddCrtc(std::make_unique<ui::CrtcController>(
632 drm_.get(), kCrtcIdBase + 1, kConnectorIdBase + 1));
633 EXPECT_TRUE(ModesetController(controller));
634
635 overlay_params_.back().buffer_size = overlay_rect_.size();
636 overlay_params_.back().display_rect = gfx::RectF(overlay_rect_);
637 plane_list_.back().display_bounds = overlay_rect_;
638
639 std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip(
640 overlay_params_, ui::DrmOverlayPlaneList());
641 EXPECT_EQ(2u, returns.size());
642 EXPECT_EQ(returns.back(), ui::OVERLAY_STATUS_ABLE);
643 }
644
TEST_F(DrmOverlayValidatorTest,RejectBufferAllocationFail)645 TEST_F(DrmOverlayValidatorTest, RejectBufferAllocationFail) {
646 CrtcState crtc_state = {/* .planes = */ {
647 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
648 }};
649 InitDrmStatesAndControllers({crtc_state});
650
651 // Buffer allocation for scanout might fail.
652 // In that case we should reject the overlay candidate.
653 gbm_->set_allocation_failure(true);
654
655 std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip(
656 overlay_params_, ui::DrmOverlayPlaneList());
657 EXPECT_EQ(2u, returns.size());
658 EXPECT_EQ(returns.front(), ui::OVERLAY_STATUS_NOT);
659 }
660
661 // This test verifies that the Ozone/DRM implementation does not reject overlay
662 // candidates purely on the basis of having non-integer bounds. Instead, they
663 // should be rounded to the nearest integer.
TEST_F(DrmOverlayValidatorTest,NonIntegerDisplayRect)664 TEST_F(DrmOverlayValidatorTest, NonIntegerDisplayRect) {
665 CrtcState state = {
666 /* .planes = */
667 {
668 {/* .formats = */ {DRM_FORMAT_XRGB8888}},
669 {/* .formats = */ {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}},
670 },
671 };
672 InitDrmStatesAndControllers(std::vector<CrtcState>(1, state));
673
674 overlay_params_.back().display_rect.Inset(0.005f, 0.005f);
675 plane_list_.pop_back();
676 AddPlane(overlay_params_.back());
677
678 std::vector<ui::OverlayStatus> returns = overlay_validator_->TestPageFlip(
679 overlay_params_, ui::DrmOverlayPlaneList());
680 EXPECT_EQ(2u, returns.size());
681 for (const auto& param : returns)
682 EXPECT_EQ(param, ui::OVERLAY_STATUS_ABLE);
683 }
684