blob: d49fed0317d5f205728ce8936283562b7f7727bf [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/drm/gpu/drm_overlay_manager.h"
#include "base/bind.h"
#include "base/callback.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/ozone/public/overlay_surface_candidate.h"
namespace ui {
namespace {
constexpr gfx::AcceleratedWidget kPrimaryWidget = 1;
constexpr gfx::AcceleratedWidget kSecondaryWidget = 2;
class TestDrmOverlayManager : public DrmOverlayManager {
public:
TestDrmOverlayManager() : DrmOverlayManager(false) {}
~TestDrmOverlayManager() override = default;
using DrmOverlayManager::UpdateCacheForOverlayCandidates;
std::vector<std::vector<OverlaySurfaceCandidate>>& requests() {
return requests_;
}
// DrmOverlayManager:
void SendOverlayValidationRequest(
const std::vector<OverlaySurfaceCandidate>& candidates,
gfx::AcceleratedWidget widget) override {
requests_.push_back(candidates);
}
std::vector<OverlayStatus> SendOverlayValidationRequestSync(
const std::vector<OverlaySurfaceCandidate>& candidates,
gfx::AcceleratedWidget widget) override {
return {};
}
private:
std::vector<std::vector<OverlaySurfaceCandidate>> requests_;
};
OverlaySurfaceCandidate CreateCandidate(const gfx::Rect& rect,
int plane_z_order) {
ui::OverlaySurfaceCandidate candidate;
candidate.transform = gfx::OVERLAY_TRANSFORM_NONE;
candidate.format = gfx::BufferFormat::YUV_420_BIPLANAR;
candidate.plane_z_order = plane_z_order;
candidate.buffer_size = rect.size();
candidate.display_rect = gfx::RectF(rect);
candidate.crop_rect = gfx::RectF(rect);
return candidate;
}
} // namespace
TEST(DrmOverlayManagerTest, CacheLogic) {
TestDrmOverlayManager manager;
// Candidates for output surface and single-on-top quad.
std::vector<OverlaySurfaceCandidate> candidates = {
CreateCandidate(gfx::Rect(0, 0, 100, 100), 0),
CreateCandidate(gfx::Rect(10, 10, 20, 20), 1)};
// The first three times that CheckOverlaySupport() is called for an overlay
// configuration it won't send a validation request.
for (int i = 0; i < 3; ++i) {
manager.CheckOverlaySupport(&candidates, kPrimaryWidget);
EXPECT_FALSE(candidates[0].overlay_handled);
EXPECT_FALSE(candidates[1].overlay_handled);
EXPECT_EQ(manager.requests().size(), 0u);
}
// The fourth call with the same overlay configuration should trigger a
// request to validate the configuration. Still assume the overlay
// configuration won't work until we get a response.
manager.CheckOverlaySupport(&candidates, kPrimaryWidget);
EXPECT_FALSE(candidates[0].overlay_handled);
EXPECT_FALSE(candidates[1].overlay_handled);
EXPECT_EQ(manager.requests().size(), 1u);
// While waiting for a response we shouldn't send the same request.
manager.CheckOverlaySupport(&candidates, kPrimaryWidget);
EXPECT_FALSE(candidates[0].overlay_handled);
EXPECT_FALSE(candidates[1].overlay_handled);
ASSERT_EQ(manager.requests().size(), 1u);
// Receive response that the overlay configuration will work.
manager.UpdateCacheForOverlayCandidates(
manager.requests().front(), kPrimaryWidget,
std::vector<OverlayStatus>(candidates.size(), OVERLAY_STATUS_ABLE));
manager.requests().clear();
// CheckOverlaySupport() should now indicate the overlay configuration will
// work.
manager.CheckOverlaySupport(&candidates, kPrimaryWidget);
EXPECT_TRUE(candidates[0].overlay_handled);
EXPECT_TRUE(candidates[1].overlay_handled);
EXPECT_EQ(manager.requests().size(), 0u);
}
// Tests that the crop rect changing will make a new request.
TEST(DrmOverlayManagerTest, CropRectCacheLogic) {
TestDrmOverlayManager manager;
// Candidates fo single-on-top quad.
std::vector<OverlaySurfaceCandidate> candidates = {
CreateCandidate(gfx::Rect(0, 0, 100, 100), 0)};
// The first three times won't send a validation request. The fourth will send
// a request.
for (int i = 0; i < 3; ++i) {
manager.CheckOverlaySupport(&candidates, kPrimaryWidget);
EXPECT_FALSE(candidates.back().overlay_handled);
EXPECT_EQ(manager.requests().size(), 0u);
}
manager.CheckOverlaySupport(&candidates, kPrimaryWidget);
EXPECT_EQ(manager.requests().size(), 1u);
// Receive response that the overlay configuration will work.
manager.UpdateCacheForOverlayCandidates(
manager.requests().front(), kPrimaryWidget,
std::vector<OverlayStatus>(candidates.size(), OVERLAY_STATUS_ABLE));
manager.requests().clear();
// Overlay configuration should work.
manager.CheckOverlaySupport(&candidates, kPrimaryWidget);
EXPECT_TRUE(candidates.back().overlay_handled);
// Now, adjust the crop rect.
candidates.back().overlay_handled = false;
candidates.back().crop_rect = gfx::RectF(0, 0, 0.5f, 0.5f);
// The first three times won't send a validation request. The fourth will send
// a request.
for (int i = 0; i < 3; ++i) {
manager.CheckOverlaySupport(&candidates, kPrimaryWidget);
EXPECT_FALSE(candidates.back().overlay_handled);
EXPECT_EQ(manager.requests().size(), 0u);
}
manager.CheckOverlaySupport(&candidates, kPrimaryWidget);
EXPECT_EQ(manager.requests().size(), 1u);
// Receive response that the overlay configuration won't work.
manager.UpdateCacheForOverlayCandidates(
manager.requests().front(), kPrimaryWidget,
std::vector<OverlayStatus>(candidates.size(), OVERLAY_STATUS_NOT));
manager.requests().clear();
// Overlay configuration should not work.
manager.CheckOverlaySupport(&candidates, kPrimaryWidget);
EXPECT_FALSE(candidates.back().overlay_handled);
}
TEST(DrmOverlayManagerTest, DifferentWidgetCache) {
TestDrmOverlayManager manager;
// Candidates for output surface and single-on-top quad.
std::vector<OverlaySurfaceCandidate> candidates = {
CreateCandidate(gfx::Rect(0, 0, 100, 100), 0),
CreateCandidate(gfx::Rect(10, 10, 20, 20), 1)};
// Call 4 Times to go beyond the Throttle Request Size
ASSERT_EQ(manager.requests().size(), 0u);
for (int i = 0; i < 4; ++i) {
manager.CheckOverlaySupport(&candidates, kPrimaryWidget);
EXPECT_FALSE(candidates[0].overlay_handled);
EXPECT_FALSE(candidates[1].overlay_handled);
}
ASSERT_EQ(manager.requests().size(), 1u);
// Receive response that the overlay configuration on kPrimaryWidget will
// work.
manager.UpdateCacheForOverlayCandidates(
manager.requests().front(), kPrimaryWidget,
std::vector<OverlayStatus>(candidates.size(), OVERLAY_STATUS_ABLE));
manager.requests().clear();
// Overlay should not be handled when using a different widget
manager.CheckOverlaySupport(&candidates, kSecondaryWidget);
EXPECT_FALSE(candidates[0].overlay_handled);
EXPECT_FALSE(candidates[1].overlay_handled);
EXPECT_EQ(manager.requests().size(), 0u);
}
TEST(DrmOverlayManagerTest, MultipleWidgetCacheSupport) {
TestDrmOverlayManager manager;
// Candidates for output surface and single-on-top quad.
std::vector<OverlaySurfaceCandidate> candidates = {
CreateCandidate(gfx::Rect(0, 0, 100, 100), 0),
CreateCandidate(gfx::Rect(10, 10, 20, 20), 1)};
// Call 4 Times to go beyond the Throttle Request Size
ASSERT_EQ(manager.requests().size(), 0u);
for (int i = 0; i < 4; ++i) {
manager.CheckOverlaySupport(&candidates, kPrimaryWidget);
EXPECT_FALSE(candidates[0].overlay_handled);
EXPECT_FALSE(candidates[1].overlay_handled);
manager.CheckOverlaySupport(&candidates, kSecondaryWidget);
EXPECT_FALSE(candidates[0].overlay_handled);
EXPECT_FALSE(candidates[1].overlay_handled);
}
EXPECT_EQ(manager.requests().size(), 2u);
// Receive response that the overlay configuration on kPrimaryWidget will
// work.
manager.UpdateCacheForOverlayCandidates(
manager.requests().front(), kPrimaryWidget,
std::vector<OverlayStatus>(candidates.size(), OVERLAY_STATUS_ABLE));
manager.CheckOverlaySupport(&candidates, kPrimaryWidget);
EXPECT_TRUE(candidates[0].overlay_handled);
EXPECT_TRUE(candidates[1].overlay_handled);
// Receive response that the overlay configuration on kSecondaryWidget will
// work.
manager.UpdateCacheForOverlayCandidates(
manager.requests().front(), kSecondaryWidget,
std::vector<OverlayStatus>(candidates.size(), OVERLAY_STATUS_ABLE));
manager.requests().clear();
// Both Widgets should be handled
manager.CheckOverlaySupport(&candidates, kPrimaryWidget);
EXPECT_TRUE(candidates[0].overlay_handled);
EXPECT_TRUE(candidates[1].overlay_handled);
manager.CheckOverlaySupport(&candidates, kSecondaryWidget);
EXPECT_TRUE(candidates[0].overlay_handled);
EXPECT_TRUE(candidates[1].overlay_handled);
EXPECT_EQ(manager.requests().size(), 0u);
}
TEST(DrmOverlayManagerTest, DifferentWidgetsSameCandidatesAreDistinct) {
TestDrmOverlayManager manager;
// Candidates for output surface and single-on-top quad.
std::vector<OverlaySurfaceCandidate> candidates = {
CreateCandidate(gfx::Rect(0, 0, 100, 100), 0),
CreateCandidate(gfx::Rect(10, 10, 20, 20), 1)};
// Looping 4 times, but each widget is only checked twice, below the Throttle
// Request Size (3).
for (int i = 0; i < 4; ++i) {
manager.CheckOverlaySupport(&candidates,
i % 2 ? kPrimaryWidget : kSecondaryWidget);
}
EXPECT_EQ(manager.requests().size(), 0u);
}
TEST(DrmOverlayManagerTest, NonIntegerDisplayRect) {
TestDrmOverlayManager manager;
// Candidates for output surface and single-on-top quad.
std::vector<OverlaySurfaceCandidate> candidates = {
CreateCandidate(gfx::Rect(0, 0, 100, 100), 0),
CreateCandidate(gfx::Rect(10, 10, 20, 20), 1)};
// Submit a set of candidates that could potentially be displayed in an
// overlay so they are stored in the cache. This ensures a comparison gets
// made adding the next value to the cache.
manager.CheckOverlaySupport(&candidates, kPrimaryWidget);
// Modify the display_rect for the second candidate so it's non-integer. We
// will never try to promote this to an overlay but something will get stored
// in the cache. This verifies we don't try to convert the non-integer RectF
// into a Rect which DCHECKs.
candidates[1].display_rect = gfx::RectF(9.4, 10.43, 20.11, 20.99);
manager.CheckOverlaySupport(&candidates, kPrimaryWidget);
}
} // namespace ui