[go: nahoru, domu]

blob: f03679a1ccdcd44bc356f52f7d56640cf27b48e8 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// 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_display.h"
#include <utility>
#include "base/test/task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/manager/test/fake_display_snapshot.h"
#include "ui/display/types/display_color_management.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/linux/test/mock_gbm_device.h"
#include "ui/ozone/platform/drm/common/drm_util.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_plane.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h"
#include "ui/ozone/platform/drm/gpu/mock_drm_device.h"
using ::testing::_;
using ::testing::Return;
using ::testing::SizeIs;
namespace ui {
namespace {
constexpr gfx::Size kNativeDisplaySize(1920, 1080);
std::unique_ptr<HardwareDisplayControllerInfo> GetDisplayInfo(
uint8_t index = 0) {
// Initialize a list of display modes.
constexpr size_t kNumModes = 5;
drmModeModeInfo modes[kNumModes] = {
{.hdisplay = 640, .vdisplay = 400},
{.hdisplay = 640, .vdisplay = 480},
{.hdisplay = 800, .vdisplay = 600},
{.hdisplay = 1024, .vdisplay = 768},
// Last mode, which should be the largest, is the native mode.
{.hdisplay = kNativeDisplaySize.width(),
.vdisplay = kNativeDisplaySize.height()}};
// Initialize a connector.
ScopedDrmConnectorPtr connector(DrmAllocator<drmModeConnector>());
connector->connector_id = 123;
connector->connection = DRM_MODE_CONNECTED;
connector->count_props = 0;
connector->count_modes = kNumModes;
connector->modes = DrmAllocator<drmModeModeInfo>(kNumModes);
std::memcpy(connector->modes, &modes[0], kNumModes * sizeof(drmModeModeInfo));
// Initialize a CRTC.
ScopedDrmCrtcPtr crtc(DrmAllocator<drmModeCrtc>());
crtc->crtc_id = 456;
crtc->mode_valid = 1;
crtc->mode = connector->modes[kNumModes - 1];
return std::make_unique<HardwareDisplayControllerInfo>(
std::move(connector), std::move(crtc), index);
}
// Verifies that the argument goes from 0 to the maximum uint16_t times |scale|
// following a power function with |exponent|.
MATCHER_P2(MatchesPowerFunction, scale, exponent, "") {
EXPECT_FALSE(arg.IsDefaultIdentity());
const uint16_t kMaxValue = std::numeric_limits<uint16_t>::max() * scale;
const uint16_t kEpsilon = std::numeric_limits<uint16_t>::max() * 0.02f;
const size_t kSize = 10;
for (size_t i = 0; i < kSize; ++i) {
float x = i / (kSize - 1.f);
uint16_t r, g, b;
arg.Evaluate(x, r, g, b);
const uint16_t expected_value = kMaxValue * pow(x, exponent);
EXPECT_NEAR(r, expected_value, kEpsilon);
EXPECT_NEAR(g, expected_value, kEpsilon);
EXPECT_NEAR(b, expected_value, kEpsilon);
}
return true;
}
MATCHER(IsDefaultIdentity, "") {
EXPECT_TRUE(arg.IsDefaultIdentity());
return true;
}
class MockHardwareDisplayPlaneManager : public HardwareDisplayPlaneManager {
public:
explicit MockHardwareDisplayPlaneManager(DrmDevice* drm)
: HardwareDisplayPlaneManager(drm) {}
~MockHardwareDisplayPlaneManager() override = default;
MOCK_METHOD(bool,
SetGammaCorrection,
(uint32_t crtc_id,
const display::GammaCurve& degamma,
const display::GammaCurve& gamma),
(override));
bool Commit(CommitRequest commit_request, uint32_t flags) override {
return false;
}
bool Commit(HardwareDisplayPlaneList* plane_list,
scoped_refptr<PageFlipRequest> page_flip_request,
gfx::GpuFenceHandle* release_fence) override {
return false;
}
bool DisableOverlayPlanes(HardwareDisplayPlaneList* plane_list) override {
return false;
}
bool SetColorCorrectionOnAllCrtcPlanes(
uint32_t crtc_id,
ScopedDrmColorCtmPtr ctm_blob_data) override {
return false;
}
bool ValidatePrimarySize(const DrmOverlayPlane& primary,
const drmModeModeInfo& mode) override {
return false;
}
void RequestPlanesReadyCallback(
DrmOverlayPlaneList planes,
base::OnceCallback<void(DrmOverlayPlaneList planes)> callback) override {
return;
}
bool InitializePlanes() override { return false; }
bool SetPlaneData(HardwareDisplayPlaneList* plane_list,
HardwareDisplayPlane* hw_plane,
const DrmOverlayPlane& overlay,
uint32_t crtc_id,
const gfx::Rect& src_rect) override {
return false;
}
std::unique_ptr<HardwareDisplayPlane> CreatePlane(
uint32_t plane_id) override {
return nullptr;
}
bool IsCompatible(HardwareDisplayPlane* plane,
const DrmOverlayPlane& overlay,
uint32_t crtc_index) const override {
return false;
}
bool CommitColorMatrix(const CrtcProperties& crtc_props) override {
return false;
}
bool CommitGammaCorrection(const CrtcProperties& crtc_props) override {
return false;
}
};
} // namespace
class DrmDisplayTest : public testing::Test {
protected:
DrmDisplayTest()
: mock_drm_device_(base::MakeRefCounted<MockDrmDevice>(
std::make_unique<MockGbmDevice>())) {
auto info = GetDisplayInfo();
auto snapshot = display::FakeDisplaySnapshot::Builder()
.SetId(123456)
.SetBaseConnectorId(info->connector()->connector_id)
.SetNativeMode(kNativeDisplaySize)
.SetCurrentMode(kNativeDisplaySize)
.SetColorSpace(gfx::ColorSpace::CreateSRGB())
.Build();
drm_display_ =
std::make_unique<DrmDisplay>(mock_drm_device_, info.get(), *snapshot);
}
MockHardwareDisplayPlaneManager* AddMockHardwareDisplayPlaneManager() {
auto mock_hardware_display_plane_manager =
std::make_unique<MockHardwareDisplayPlaneManager>(
mock_drm_device_.get());
MockHardwareDisplayPlaneManager* pointer =
mock_hardware_display_plane_manager.get();
mock_drm_device_->plane_manager_ =
std::move(mock_hardware_display_plane_manager);
return pointer;
}
base::test::TaskEnvironment env_;
scoped_refptr<DrmDevice> mock_drm_device_;
std::unique_ptr<DrmDisplay> drm_display_;
};
TEST_F(DrmDisplayTest, SetColorSpace) {
drm_display_->set_is_hdr_capable_for_testing(true);
MockHardwareDisplayPlaneManager* plane_manager =
AddMockHardwareDisplayPlaneManager();
ON_CALL(*plane_manager, SetGammaCorrection(_, IsDefaultIdentity(), _))
.WillByDefault(::testing::Return(true));
const auto kHDRColorSpace = gfx::ColorSpace::CreateHDR10();
EXPECT_CALL(*plane_manager,
SetGammaCorrection(_, IsDefaultIdentity(), IsDefaultIdentity()));
drm_display_->SetColorSpace(kHDRColorSpace);
const auto kSDRColorSpace = gfx::ColorSpace::CreateREC709();
constexpr float kSDRLevel = 0.85;
constexpr float kExponent = 1.2;
EXPECT_CALL(*plane_manager,
SetGammaCorrection(_, IsDefaultIdentity(),
MatchesPowerFunction(kSDRLevel, kExponent)));
drm_display_->SetColorSpace(kSDRColorSpace);
}
TEST_F(DrmDisplayTest, SetEmptyGammaCorrectionNonHDRDisplay) {
MockHardwareDisplayPlaneManager* plane_manager =
AddMockHardwareDisplayPlaneManager();
ON_CALL(*plane_manager, SetGammaCorrection(_, _, _))
.WillByDefault(::testing::Return(true));
EXPECT_CALL(*plane_manager,
SetGammaCorrection(_, IsDefaultIdentity(), IsDefaultIdentity()));
drm_display_->SetGammaCorrection({}, {});
}
TEST_F(DrmDisplayTest, SetEmptyGammaCorrectionHDRDisplay) {
drm_display_->set_is_hdr_capable_for_testing(true);
MockHardwareDisplayPlaneManager* plane_manager =
AddMockHardwareDisplayPlaneManager();
ON_CALL(*plane_manager, SetGammaCorrection(_, _, _))
.WillByDefault(Return(true));
constexpr float kSDRLevel = 0.85;
constexpr float kExponent = 1.2;
EXPECT_CALL(*plane_manager,
SetGammaCorrection(_, IsDefaultIdentity(),
MatchesPowerFunction(kSDRLevel, kExponent)));
drm_display_->SetGammaCorrection({}, {});
}
} // namespace ui