Commit 12dc8ef2 authored by Daniel Nicoara's avatar Daniel Nicoara Committed by Commit Bot

Reland "[Ozone-DRM] Refactor plane management and add tests"

This is a reland of ce767464

Original change's description:
> [Ozone-DRM] Refactor plane management and add tests
>
> * We use plane properties on legacy DRM to get some details (plane
> type, in_formats). Read the properties in HardwareDisplayPlane and
> check that the required properties are available in DRM atomic.
> * Split dummy plane into its own class to clean up code.
> * Remove test plane since we can now create the real objects via
> injected state in DrmDevice.
> * Cleanup plane initialization.
> * Remove MockHardwareDisplayPlaneManager and rely on MockDrmDevice to
> inject the necessary state.
>
> BUG=839487
> TEST=Ran unittests
>
> Change-Id: I03c91620557dcf7426629cf97bb989d8d7e83c68
> Reviewed-on: https://chromium-review.googlesource.com/1048585
> Commit-Queue: Daniel Nicoara <dnicoara@chromium.org>
> Reviewed-by: Daniele Castagna <dcastagna@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#561616}

Bug: 839487
Change-Id: Ifb74647dfe1f05ef3339261dd1f7c51c0c371622
Reviewed-on: https://chromium-review.googlesource.com/1073487Reviewed-by: default avatarDaniele Castagna <dcastagna@chromium.org>
Commit-Queue: Daniel Nicoara <dnicoara@chromium.org>
Cr-Commit-Position: refs/heads/master@{#561949}
parent 6a25833c
...@@ -64,6 +64,8 @@ source_set("gbm") { ...@@ -64,6 +64,8 @@ source_set("gbm") {
"gpu/hardware_display_plane.h", "gpu/hardware_display_plane.h",
"gpu/hardware_display_plane_atomic.cc", "gpu/hardware_display_plane_atomic.cc",
"gpu/hardware_display_plane_atomic.h", "gpu/hardware_display_plane_atomic.h",
"gpu/hardware_display_plane_dummy.cc",
"gpu/hardware_display_plane_dummy.h",
"gpu/hardware_display_plane_manager.cc", "gpu/hardware_display_plane_manager.cc",
"gpu/hardware_display_plane_manager.h", "gpu/hardware_display_plane_manager.h",
"gpu/hardware_display_plane_manager_atomic.cc", "gpu/hardware_display_plane_manager_atomic.cc",
...@@ -161,8 +163,6 @@ source_set("gbm_unittests") { ...@@ -161,8 +163,6 @@ source_set("gbm_unittests") {
"gpu/mock_drm_device.h", "gpu/mock_drm_device.h",
"gpu/mock_dumb_buffer_generator.cc", "gpu/mock_dumb_buffer_generator.cc",
"gpu/mock_dumb_buffer_generator.h", "gpu/mock_dumb_buffer_generator.h",
"gpu/mock_hardware_display_plane_manager.cc",
"gpu/mock_hardware_display_plane_manager.h",
"gpu/mock_scanout_buffer.cc", "gpu/mock_scanout_buffer.cc",
"gpu/mock_scanout_buffer.h", "gpu/mock_scanout_buffer.h",
"gpu/mock_scanout_buffer_generator.cc", "gpu/mock_scanout_buffer_generator.cc",
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/time/time.h" #include "base/time/time.h"
#include "ui/gfx/presentation_feedback.h" #include "ui/gfx/presentation_feedback.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h" #include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_plane.h"
#include "ui/ozone/platform/drm/gpu/page_flip_request.h" #include "ui/ozone/platform/drm/gpu/page_flip_request.h"
#include "ui/ozone/platform/drm/gpu/scanout_buffer.h" #include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
......
...@@ -393,6 +393,17 @@ ScopedDrmFramebufferPtr DrmDevice::GetFramebuffer(uint32_t framebuffer) { ...@@ -393,6 +393,17 @@ ScopedDrmFramebufferPtr DrmDevice::GetFramebuffer(uint32_t framebuffer) {
drmModeGetFB(file_.GetPlatformFile(), framebuffer)); drmModeGetFB(file_.GetPlatformFile(), framebuffer));
} }
ScopedDrmPlanePtr DrmDevice::GetPlane(uint32_t plane_id) {
DCHECK(file_.IsValid());
return ScopedDrmPlanePtr(drmModeGetPlane(file_.GetPlatformFile(), plane_id));
}
ScopedDrmPlaneResPtr DrmDevice::GetPlaneResources() {
DCHECK(file_.IsValid());
return ScopedDrmPlaneResPtr(
drmModeGetPlaneResources(file_.GetPlatformFile()));
}
ScopedDrmPropertyPtr DrmDevice::GetProperty(drmModeConnector* connector, ScopedDrmPropertyPtr DrmDevice::GetProperty(drmModeConnector* connector,
const char* name) { const char* name) {
TRACE_EVENT2("drm", "DrmDevice::GetProperty", "connector", TRACE_EVENT2("drm", "DrmDevice::GetProperty", "connector",
...@@ -427,6 +438,12 @@ bool DrmDevice::GetCapability(uint64_t capability, uint64_t* value) { ...@@ -427,6 +438,12 @@ bool DrmDevice::GetCapability(uint64_t capability, uint64_t* value) {
return !drmGetCap(file_.GetPlatformFile(), capability, value); return !drmGetCap(file_.GetPlatformFile(), capability, value);
} }
ScopedDrmPropertyBlobPtr DrmDevice::GetPropertyBlob(uint32_t property_id) {
DCHECK(file_.IsValid());
return ScopedDrmPropertyBlobPtr(
drmModeGetPropertyBlob(file_.GetPlatformFile(), property_id));
}
ScopedDrmPropertyBlobPtr DrmDevice::GetPropertyBlob(drmModeConnector* connector, ScopedDrmPropertyBlobPtr DrmDevice::GetPropertyBlob(drmModeConnector* connector,
const char* name) { const char* name) {
DCHECK(file_.IsValid()); DCHECK(file_.IsValid());
......
...@@ -131,6 +131,12 @@ class DrmDevice : public base::RefCountedThreadSafe<DrmDevice> { ...@@ -131,6 +131,12 @@ class DrmDevice : public base::RefCountedThreadSafe<DrmDevice> {
const gfx::Rect& source, const gfx::Rect& source,
int overlay_plane); int overlay_plane);
// Returns the list of all planes available on this DRM device.
virtual ScopedDrmPlaneResPtr GetPlaneResources();
// Returns the properties associated with plane with id |plane_id|.
virtual ScopedDrmPlanePtr GetPlane(uint32_t plane_id);
// Returns the property with name |name| associated with |connector|. Returns // Returns the property with name |name| associated with |connector|. Returns
// NULL if property not found. If the returned value is valid, it must be // NULL if property not found. If the returned value is valid, it must be
// released using FreeProperty(). // released using FreeProperty().
...@@ -145,17 +151,21 @@ class DrmDevice : public base::RefCountedThreadSafe<DrmDevice> { ...@@ -145,17 +151,21 @@ class DrmDevice : public base::RefCountedThreadSafe<DrmDevice> {
uint32_t property_id, uint32_t property_id,
uint64_t value); uint64_t value);
// Can be used to query device/driver |capability|. Sets the value of // Returns a binary blob associated with |property_id|. May be nullptr if the
// |capability to |value|. Returns true in case of a succesful query. // property couldn't be found.
virtual bool GetCapability(uint64_t capability, uint64_t* value); virtual ScopedDrmPropertyBlobPtr GetPropertyBlob(uint32_t property_id);
// Return a binary blob associated with |connector|. The binary blob is // Returns a binary blob associated with |connector|. The binary blob is
// associated with the property with name |name|. Return NULL if the property // associated with the property with name |name|. Return NULL if the property
// could not be found or if the property does not have a binary blob. If valid // could not be found or if the property does not have a binary blob. If valid
// the returned object must be freed using FreePropertyBlob(). // the returned object must be freed using FreePropertyBlob().
virtual ScopedDrmPropertyBlobPtr GetPropertyBlob(drmModeConnector* connector, virtual ScopedDrmPropertyBlobPtr GetPropertyBlob(drmModeConnector* connector,
const char* name); const char* name);
// Can be used to query device/driver |capability|. Sets the value of
// |capability| to |value|. Returns true in case of a succesful query.
virtual bool GetCapability(uint64_t capability, uint64_t* value);
// Set the cursor to be displayed in CRTC |crtc_id|. (width, height) is the // Set the cursor to be displayed in CRTC |crtc_id|. (width, height) is the
// cursor size pointed by |handle|. // cursor size pointed by |handle|.
virtual bool SetCursor(uint32_t crtc_id, virtual bool SetCursor(uint32_t crtc_id,
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
#include "ui/ozone/platform/drm/gpu/fake_plane_info.h" #include "ui/ozone/platform/drm/gpu/fake_plane_info.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h" #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
#include "ui/ozone/platform/drm/gpu/mock_drm_device.h" #include "ui/ozone/platform/drm/gpu/mock_drm_device.h"
#include "ui/ozone/platform/drm/gpu/mock_hardware_display_plane_manager.h"
#include "ui/ozone/platform/drm/gpu/mock_scanout_buffer.h" #include "ui/ozone/platform/drm/gpu/mock_scanout_buffer.h"
#include "ui/ozone/platform/drm/gpu/mock_scanout_buffer_generator.h" #include "ui/ozone/platform/drm/gpu/mock_scanout_buffer_generator.h"
#include "ui/ozone/platform/drm/gpu/screen_manager.h" #include "ui/ozone/platform/drm/gpu/screen_manager.h"
...@@ -33,11 +32,13 @@ const drmModeModeInfo kDefaultMode = ...@@ -33,11 +32,13 @@ const drmModeModeInfo kDefaultMode =
{0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}}; {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}};
const gfx::AcceleratedWidget kDefaultWidgetHandle = 1; const gfx::AcceleratedWidget kDefaultWidgetHandle = 1;
const uint32_t kDefaultCrtc = 1; constexpr uint32_t kCrtcIdBase = 1;
const uint32_t kDefaultConnector = 2; constexpr uint32_t kConnectorIdBase = 100;
const uint32_t kSecondaryCrtc = 3; constexpr uint32_t kPlaneIdBase = 200;
const uint32_t kSecondaryConnector = 4; constexpr uint32_t kInFormatsBlobPropIdBase = 400;
const size_t kPlanesPerCrtc = 1;
constexpr uint32_t kTypePropId = 300;
constexpr uint32_t kInFormatsPropId = 301;
} // namespace } // namespace
...@@ -61,12 +62,21 @@ class DrmOverlayValidatorTest : public testing::Test { ...@@ -61,12 +62,21 @@ class DrmOverlayValidatorTest : public testing::Test {
void AddPlane(const ui::OverlayCheck_Params& params); void AddPlane(const ui::OverlayCheck_Params& params);
protected: protected:
struct PlaneState {
std::vector<uint32_t> formats;
};
struct CrtcState {
std::vector<PlaneState> planes;
};
void InitializeDrmState(const std::vector<CrtcState>& crtc_states);
std::unique_ptr<base::MessageLoop> message_loop_; std::unique_ptr<base::MessageLoop> message_loop_;
scoped_refptr<ui::MockDrmDevice> drm_; scoped_refptr<ui::MockDrmDevice> drm_;
std::unique_ptr<ui::MockScanoutBufferGenerator> buffer_generator_; std::unique_ptr<ui::MockScanoutBufferGenerator> buffer_generator_;
std::unique_ptr<ui::ScreenManager> screen_manager_; std::unique_ptr<ui::ScreenManager> screen_manager_;
std::unique_ptr<ui::DrmDeviceManager> drm_device_manager_; std::unique_ptr<ui::DrmDeviceManager> drm_device_manager_;
ui::MockHardwareDisplayPlaneManager* plane_manager_;
ui::DrmWindow* window_; ui::DrmWindow* window_;
std::unique_ptr<ui::DrmOverlayValidator> overlay_validator_; std::unique_ptr<ui::DrmOverlayValidator> overlay_validator_;
std::vector<ui::OverlayCheck_Params> overlay_params_; std::vector<ui::OverlayCheck_Params> overlay_params_;
...@@ -86,14 +96,18 @@ void DrmOverlayValidatorTest::SetUp() { ...@@ -86,14 +96,18 @@ void DrmOverlayValidatorTest::SetUp() {
last_swap_buffers_result_ = gfx::SwapResult::SWAP_FAILED; last_swap_buffers_result_ = gfx::SwapResult::SWAP_FAILED;
message_loop_.reset(new base::MessageLoopForUI); message_loop_.reset(new base::MessageLoopForUI);
std::vector<uint32_t> crtcs; drm_ = new ui::MockDrmDevice(false);
crtcs.push_back(kDefaultCrtc);
drm_ = new ui::MockDrmDevice(false, crtcs, kPlanesPerCrtc); CrtcState crtc_state = {.planes = {
{.formats = {DRM_FORMAT_XRGB8888}},
}};
InitializeDrmState({crtc_state});
buffer_generator_.reset(new ui::MockScanoutBufferGenerator()); buffer_generator_.reset(new ui::MockScanoutBufferGenerator());
screen_manager_.reset(new ui::ScreenManager(buffer_generator_.get())); screen_manager_.reset(new ui::ScreenManager(buffer_generator_.get()));
screen_manager_->AddDisplayController(drm_, kDefaultCrtc, kDefaultConnector); screen_manager_->AddDisplayController(drm_, kCrtcIdBase, kConnectorIdBase);
screen_manager_->ConfigureDisplayController( screen_manager_->ConfigureDisplayController(
drm_, kDefaultCrtc, kDefaultConnector, gfx::Point(), kDefaultMode); drm_, kCrtcIdBase, kConnectorIdBase, gfx::Point(), kDefaultMode);
drm_device_manager_.reset(new ui::DrmDeviceManager(nullptr)); drm_device_manager_.reset(new ui::DrmDeviceManager(nullptr));
...@@ -103,8 +117,6 @@ void DrmOverlayValidatorTest::SetUp() { ...@@ -103,8 +117,6 @@ void DrmOverlayValidatorTest::SetUp() {
window->SetBounds( window->SetBounds(
gfx::Rect(gfx::Size(kDefaultMode.hdisplay, kDefaultMode.vdisplay))); gfx::Rect(gfx::Size(kDefaultMode.hdisplay, kDefaultMode.vdisplay)));
screen_manager_->AddWindow(kDefaultWidgetHandle, std::move(window)); screen_manager_->AddWindow(kDefaultWidgetHandle, std::move(window));
plane_manager_ =
static_cast<ui::MockHardwareDisplayPlaneManager*>(drm_->plane_manager());
window_ = screen_manager_->GetWindow(kDefaultWidgetHandle); window_ = screen_manager_->GetWindow(kDefaultWidgetHandle);
overlay_validator_.reset( overlay_validator_.reset(
new ui::DrmOverlayValidator(window_, buffer_generator_.get())); new ui::DrmOverlayValidator(window_, buffer_generator_.get()));
...@@ -130,6 +142,49 @@ void DrmOverlayValidatorTest::SetUp() { ...@@ -130,6 +142,49 @@ void DrmOverlayValidatorTest::SetUp() {
AddPlane(overlay_candidate); AddPlane(overlay_candidate);
} }
void DrmOverlayValidatorTest::InitializeDrmState(
const std::vector<CrtcState>& crtc_states) {
std::vector<ui::MockDrmDevice::CrtcProperties> crtc_properties(
crtc_states.size());
std::vector<ui::MockDrmDevice::PlaneProperties> plane_properties;
std::map<uint32_t, std::string> property_names = {
{kTypePropId, "type"}, {kInFormatsPropId, "IN_FORMATS"},
};
uint32_t plane_id = kPlaneIdBase;
uint32_t property_id = kInFormatsBlobPropIdBase;
for (size_t crtc_idx = 0; crtc_idx < crtc_states.size(); ++crtc_idx) {
crtc_properties[crtc_idx].id = kCrtcIdBase + crtc_idx;
std::vector<ui::MockDrmDevice::PlaneProperties> crtc_plane_properties(
crtc_states[crtc_idx].planes.size());
for (size_t plane_idx = 0; plane_idx < crtc_states[crtc_idx].planes.size();
++plane_idx) {
crtc_plane_properties[plane_idx].id = plane_id++;
crtc_plane_properties[plane_idx].crtc_mask = 1 << crtc_idx;
crtc_plane_properties[plane_idx].properties = {
{.id = kTypePropId,
.value = plane_idx == 0 ? DRM_PLANE_TYPE_PRIMARY
: DRM_PLANE_TYPE_OVERLAY},
{.id = kInFormatsPropId, .value = property_id++},
};
drm_->SetPropertyBlob(ui::MockDrmDevice::AllocateInFormatsBlob(
crtc_plane_properties[plane_idx].properties[1].value,
crtc_states[crtc_idx].planes[plane_idx].formats,
std::vector<drm_format_modifier>()));
}
plane_properties.insert(plane_properties.end(),
crtc_plane_properties.begin(),
crtc_plane_properties.end());
}
drm_->InitializeState(crtc_properties, plane_properties, property_names,
/* use_atomic= */ false);
}
void DrmOverlayValidatorTest::AddPlane(const ui::OverlayCheck_Params& params) { void DrmOverlayValidatorTest::AddPlane(const ui::OverlayCheck_Params& params) {
scoped_refptr<ui::DrmDevice> drm = scoped_refptr<ui::DrmDevice> drm =
window_->GetController()->GetAllocationDrmDevice(); window_->GetController()->GetAllocationDrmDevice();
...@@ -183,32 +238,29 @@ TEST_F(DrmOverlayValidatorTest, DontCollapseOverlayToPrimaryInFullScreen) { ...@@ -183,32 +238,29 @@ TEST_F(DrmOverlayValidatorTest, DontCollapseOverlayToPrimaryInFullScreen) {
} }
TEST_F(DrmOverlayValidatorTest, OverlayFormat_XRGB) { TEST_F(DrmOverlayValidatorTest, OverlayFormat_XRGB) {
plane_manager_->ResetPlaneCount();
// This test checks for optimal format in case of non full screen video case. // This test checks for optimal format in case of non full screen video case.
// This should be XRGB when overlay doesn't support YUV. // This should be XRGB when overlay doesn't support YUV.
overlay_params_.back().buffer_size = overlay_rect_.size(); overlay_params_.back().buffer_size = overlay_rect_.size();
overlay_params_.back().display_rect = overlay_rect_; overlay_params_.back().display_rect = overlay_rect_;
plane_list_.back().display_bounds = overlay_rect_; plane_list_.back().display_bounds = overlay_rect_;
std::vector<uint32_t> xrgb_yuv_packed_formats = {DRM_FORMAT_XRGB8888, CrtcState state = {
DRM_FORMAT_UYVY}; .planes =
ui::FakePlaneInfo primary_plane_info(100, 1 << 0, xrgb_yuv_packed_formats); {
ui::FakePlaneInfo overlay_info(101, 1 << 0, {.formats = {DRM_FORMAT_XRGB8888, DRM_FORMAT_UYVY}},
std::vector<uint32_t>(1, DRM_FORMAT_XRGB8888)); {.formats = {DRM_FORMAT_XRGB8888}},
std::vector<ui::FakePlaneInfo> planes_info{primary_plane_info, overlay_info}; },
plane_manager_->SetPlaneProperties(planes_info); };
InitializeDrmState(std::vector<CrtcState>(1, state));
std::vector<ui::OverlayCheckReturn_Params> returns = std::vector<ui::OverlayCheckReturn_Params> returns =
overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList()); overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList());
EXPECT_EQ(3, plane_manager_->plane_count()); EXPECT_EQ(2u, returns.size());
for (const auto& param : returns) for (const auto& param : returns)
EXPECT_EQ(param.status, ui::OVERLAY_STATUS_ABLE); EXPECT_EQ(param.status, ui::OVERLAY_STATUS_ABLE);
EXPECT_EQ(3, plane_manager_->plane_count());
} }
TEST_F(DrmOverlayValidatorTest, OverlayFormat_YUV) { TEST_F(DrmOverlayValidatorTest, OverlayFormat_YUV) {
plane_manager_->ResetPlaneCount();
// This test checks for optimal format in case of non full screen video case. // This test checks for optimal format in case of non full screen video case.
// Prefer YUV as optimal format when Overlay supports it and scaling is // Prefer YUV as optimal format when Overlay supports it and scaling is
// needed. // needed.
...@@ -220,25 +272,23 @@ TEST_F(DrmOverlayValidatorTest, OverlayFormat_YUV) { ...@@ -220,25 +272,23 @@ TEST_F(DrmOverlayValidatorTest, OverlayFormat_YUV) {
plane_list_.pop_back(); plane_list_.pop_back();
AddPlane(overlay_params_.back()); AddPlane(overlay_params_.back());
std::vector<uint32_t> xrgb_yuv_packed_formats = {DRM_FORMAT_XRGB8888, CrtcState state = {
DRM_FORMAT_UYVY}; .planes =
ui::FakePlaneInfo primary_plane_info( {
100, 1 << 0, std::vector<uint32_t>(1, DRM_FORMAT_XRGB8888)); {.formats = {DRM_FORMAT_XRGB8888}},
ui::FakePlaneInfo overlay_info(101, 1 << 0, xrgb_yuv_packed_formats); {.formats = {DRM_FORMAT_XRGB8888, DRM_FORMAT_UYVY}},
std::vector<ui::FakePlaneInfo> planes_info{primary_plane_info, overlay_info}; },
plane_manager_->SetPlaneProperties(planes_info); };
InitializeDrmState(std::vector<CrtcState>(1, state));
std::vector<ui::OverlayCheckReturn_Params> returns = std::vector<ui::OverlayCheckReturn_Params> returns =
overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList()); overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList());
EXPECT_EQ(2u, returns.size());
for (const auto& param : returns) for (const auto& param : returns)
EXPECT_EQ(param.status, ui::OVERLAY_STATUS_ABLE); EXPECT_EQ(param.status, ui::OVERLAY_STATUS_ABLE);
EXPECT_EQ(3, plane_manager_->plane_count());
} }
TEST_F(DrmOverlayValidatorTest, RejectYUVBuffersIfNotSupported) { TEST_F(DrmOverlayValidatorTest, RejectYUVBuffersIfNotSupported) {
plane_manager_->ResetPlaneCount();
// Check case where buffer storage format is already UYVY but planes dont // Check case where buffer storage format is already UYVY but planes dont
// support it. // support it.
overlay_params_.back().buffer_size = overlay_rect_.size(); overlay_params_.back().buffer_size = overlay_rect_.size();
...@@ -247,33 +297,47 @@ TEST_F(DrmOverlayValidatorTest, RejectYUVBuffersIfNotSupported) { ...@@ -247,33 +297,47 @@ TEST_F(DrmOverlayValidatorTest, RejectYUVBuffersIfNotSupported) {
plane_list_.pop_back(); plane_list_.pop_back();
AddPlane(overlay_params_.back()); AddPlane(overlay_params_.back());
ui::FakePlaneInfo primary_plane_info( CrtcState state = {
100, 1 << 0, std::vector<uint32_t>(1, DRM_FORMAT_XRGB8888)); .planes =
ui::FakePlaneInfo overlay_info(101, 1 << 0, {
std::vector<uint32_t>(1, DRM_FORMAT_XRGB8888)); {.formats = {DRM_FORMAT_XRGB8888}},
std::vector<ui::FakePlaneInfo> planes_info{primary_plane_info, overlay_info}; {.formats = {DRM_FORMAT_XRGB8888}},
plane_manager_->SetPlaneProperties(planes_info); },
};
InitializeDrmState(std::vector<CrtcState>(1, state));
std::vector<ui::OverlayCheck_Params> validated_params = overlay_params_; std::vector<ui::OverlayCheck_Params> validated_params = overlay_params_;
plane_manager_->ResetPlaneCount();
std::vector<ui::OverlayCheckReturn_Params> returns = std::vector<ui::OverlayCheckReturn_Params> returns =
overlay_validator_->TestPageFlip(validated_params, overlay_validator_->TestPageFlip(validated_params,
ui::OverlayPlaneList()); ui::OverlayPlaneList());
EXPECT_EQ(2u, returns.size());
EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_NOT); EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_NOT);
} }
TEST_F(DrmOverlayValidatorTest, TEST_F(DrmOverlayValidatorTest,
RejectYUVBuffersIfNotSupported_MirroredControllers) { RejectYUVBuffersIfNotSupported_MirroredControllers) {
std::vector<uint32_t> crtcs{kDefaultCrtc, kSecondaryCrtc}; std::vector<CrtcState> crtc_states = {
plane_manager_->SetCrtcInfo(crtcs); {
.planes =
{
{.formats = {DRM_FORMAT_XRGB8888}},
{.formats = {DRM_FORMAT_XRGB8888, DRM_FORMAT_UYVY}},
},
},
{
.planes =
{
{.formats = {DRM_FORMAT_XRGB8888}},
{.formats = {DRM_FORMAT_XRGB8888, DRM_FORMAT_UYVY}},
},
},
};
InitializeDrmState(crtc_states);
std::vector<uint32_t> only_rgb_format{DRM_FORMAT_XRGB8888};
std::vector<uint32_t> xrgb_yuv_packed_formats{DRM_FORMAT_XRGB8888,
DRM_FORMAT_UYVY};
ui::HardwareDisplayController* controller = window_->GetController(); ui::HardwareDisplayController* controller = window_->GetController();
controller->AddCrtc(std::unique_ptr<ui::CrtcController>( controller->AddCrtc(
new ui::CrtcController(drm_.get(), kSecondaryCrtc, kSecondaryConnector))); std::unique_ptr<ui::CrtcController>(new ui::CrtcController(
drm_.get(), kCrtcIdBase + 1, kConnectorIdBase + 1)));
ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>( ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>(
new ui::MockScanoutBuffer(primary_rect_.size())), new ui::MockScanoutBuffer(primary_rect_.size())),
nullptr); nullptr);
...@@ -286,56 +350,62 @@ TEST_F(DrmOverlayValidatorTest, ...@@ -286,56 +350,62 @@ TEST_F(DrmOverlayValidatorTest,
plane_list_.back().display_bounds = overlay_rect_; plane_list_.back().display_bounds = overlay_rect_;
plane_list_.back().crop_rect = crop_rect; plane_list_.back().crop_rect = crop_rect;
ui::FakePlaneInfo primary_crtc_primary_plane(100, 1 << 0, only_rgb_format);
ui::FakePlaneInfo primary_crtc_overlay(101, 1 << 0, xrgb_yuv_packed_formats);
ui::FakePlaneInfo secondary_crtc_primary_plane(102, 1 << 1, only_rgb_format);
ui::FakePlaneInfo secondary_crtc_overlay(103, 1 << 1,
xrgb_yuv_packed_formats);
std::vector<ui::FakePlaneInfo> planes_info{
primary_crtc_primary_plane, primary_crtc_overlay,
secondary_crtc_primary_plane, secondary_crtc_overlay};
plane_manager_->SetPlaneProperties(planes_info);
std::vector<ui::OverlayCheck_Params> validated_params = overlay_params_; std::vector<ui::OverlayCheck_Params> validated_params = overlay_params_;
validated_params.back().format = gfx::BufferFormat::UYVY_422; validated_params.back().format = gfx::BufferFormat::UYVY_422;
plane_manager_->ResetPlaneCount();
std::vector<ui::OverlayCheckReturn_Params> returns = std::vector<ui::OverlayCheckReturn_Params> returns =
overlay_validator_->TestPageFlip(validated_params, overlay_validator_->TestPageFlip(validated_params,
ui::OverlayPlaneList()); ui::OverlayPlaneList());
EXPECT_EQ(2u, returns.size());
EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_ABLE); EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_ABLE);
// This configuration should not be promoted to Overlay when either of the // This configuration should not be promoted to Overlay when either of the
// controllers dont support UYVY format. // controllers dont support UYVY format.
// Check case where we dont have support for packed formats in Mirrored CRTC. // Check case where we dont have support for packed formats in Mirrored CRTC.
planes_info.back().allowed_formats = only_rgb_format; crtc_states[1].planes[1].formats = {DRM_FORMAT_XRGB8888};
plane_manager_->SetPlaneProperties(planes_info); InitializeDrmState(crtc_states);
returns = overlay_validator_->TestPageFlip(validated_params, returns = overlay_validator_->TestPageFlip(validated_params,
ui::OverlayPlaneList()); ui::OverlayPlaneList());
EXPECT_EQ(2u, returns.size());
EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_NOT); EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_NOT);
// Check case where we dont have support for packed formats in primary // Check case where we dont have support for packed formats in primary
// display. // display.
planes_info.back().allowed_formats = xrgb_yuv_packed_formats; crtc_states[0].planes[1].formats = {DRM_FORMAT_XRGB8888};
planes_info[1].allowed_formats = only_rgb_format; crtc_states[1].planes[1].formats = {DRM_FORMAT_XRGB8888, DRM_FORMAT_UYVY};
plane_manager_->SetPlaneProperties(planes_info); InitializeDrmState(crtc_states);
returns = overlay_validator_->TestPageFlip(validated_params, returns = overlay_validator_->TestPageFlip(validated_params,
ui::OverlayPlaneList()); ui::OverlayPlaneList());
EXPECT_EQ(2u, returns.size());
EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_NOT); EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_NOT);
controller->RemoveCrtc(drm_, kSecondaryCrtc); controller->RemoveCrtc(drm_, kCrtcIdBase + 1);
} }
TEST_F(DrmOverlayValidatorTest, OptimalFormatYUV_MirroredControllers) { TEST_F(DrmOverlayValidatorTest, OptimalFormatXRGB_MirroredControllers) {
std::vector<uint32_t> crtcs{kDefaultCrtc, kSecondaryCrtc}; std::vector<CrtcState> crtc_states = {
plane_manager_->SetCrtcInfo(crtcs); {
.planes =
{
{.formats = {DRM_FORMAT_XRGB8888}},
{.formats = {DRM_FORMAT_XRGB8888, DRM_FORMAT_UYVY}},
},
},
{
.planes =
{
{.formats = {DRM_FORMAT_XRGB8888}},
{.formats = {DRM_FORMAT_XRGB8888, DRM_FORMAT_UYVY}},
},
},
};
InitializeDrmState(crtc_states);
ui::HardwareDisplayController* controller = window_->GetController(); ui::HardwareDisplayController* controller = window_->GetController();
controller->AddCrtc(std::unique_ptr<ui::CrtcController>( controller->AddCrtc(
new ui::CrtcController(drm_.get(), kSecondaryCrtc, kSecondaryConnector))); std::unique_ptr<ui::CrtcController>(new ui::CrtcController(
drm_.get(), kCrtcIdBase + 1, kConnectorIdBase + 1)));
ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>( ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>(
new ui::MockScanoutBuffer(primary_rect_.size())), new ui::MockScanoutBuffer(primary_rect_.size())),
nullptr); nullptr);
...@@ -344,30 +414,15 @@ TEST_F(DrmOverlayValidatorTest, OptimalFormatYUV_MirroredControllers) { ...@@ -344,30 +414,15 @@ TEST_F(DrmOverlayValidatorTest, OptimalFormatYUV_MirroredControllers) {
overlay_params_.back().buffer_size = overlay_rect_.size(); overlay_params_.back().buffer_size = overlay_rect_.size();
overlay_params_.back().display_rect = overlay_rect_; overlay_params_.back().display_rect = overlay_rect_;
plane_list_.back().display_bounds = overlay_rect_; plane_list_.back().display_bounds = overlay_rect_;
std::vector<uint32_t> only_rgb_format = {DRM_FORMAT_XRGB8888};
std::vector<uint32_t> xrgb_yuv_packed_formats = {DRM_FORMAT_XRGB8888,
DRM_FORMAT_UYVY};
ui::FakePlaneInfo primary_crtc_primary_plane(100, 1 << 0, only_rgb_format);
ui::FakePlaneInfo primary_crtc_overlay(101, 1 << 0, xrgb_yuv_packed_formats);
ui::FakePlaneInfo secondary_crtc_primary_plane(102, 1 << 1, only_rgb_format);
ui::FakePlaneInfo secondary_crtc_overlay(103, 1 << 1,
xrgb_yuv_packed_formats);
std::vector<ui::FakePlaneInfo> planes_info{
primary_crtc_primary_plane, primary_crtc_overlay,
secondary_crtc_primary_plane, secondary_crtc_overlay};
plane_manager_->SetPlaneProperties(planes_info);
plane_manager_->ResetPlaneCount();
std::vector<ui::OverlayCheckReturn_Params> returns = std::vector<ui::OverlayCheckReturn_Params> returns =
overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList()); overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList());
EXPECT_EQ(2u, returns.size());
EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_ABLE); EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_ABLE);
// Check case where we dont have support for packed formats in Mirrored CRTC. // Check case where we dont have support for packed formats in Mirrored CRTC.
planes_info.back().allowed_formats = only_rgb_format; crtc_states[1].planes[1].formats = {DRM_FORMAT_XRGB8888};
plane_manager_->SetPlaneProperties(planes_info); InitializeDrmState(crtc_states);
returns = returns =
overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList()); overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList());
...@@ -375,15 +430,16 @@ TEST_F(DrmOverlayValidatorTest, OptimalFormatYUV_MirroredControllers) { ...@@ -375,15 +430,16 @@ TEST_F(DrmOverlayValidatorTest, OptimalFormatYUV_MirroredControllers) {
// Check case where we dont have support for packed formats in primary // Check case where we dont have support for packed formats in primary
// display. // display.
planes_info.back().allowed_formats = xrgb_yuv_packed_formats; crtc_states[0].planes[1].formats = {DRM_FORMAT_XRGB8888};
planes_info[1].allowed_formats = only_rgb_format; crtc_states[1].planes[1].formats = {DRM_FORMAT_XRGB8888, DRM_FORMAT_UYVY};
plane_manager_->SetPlaneProperties(planes_info); InitializeDrmState(crtc_states);
returns = returns =
overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList()); overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList());
EXPECT_EQ(2u, returns.size());
EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_ABLE); EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_ABLE);
controller->RemoveCrtc(drm_, kSecondaryCrtc); controller->RemoveCrtc(drm_, kCrtcIdBase + 1);
} }
TEST_F(DrmOverlayValidatorTest, RejectBufferAllocationFail) { TEST_F(DrmOverlayValidatorTest, RejectBufferAllocationFail) {
...@@ -393,5 +449,6 @@ TEST_F(DrmOverlayValidatorTest, RejectBufferAllocationFail) { ...@@ -393,5 +449,6 @@ TEST_F(DrmOverlayValidatorTest, RejectBufferAllocationFail) {
std::vector<ui::OverlayCheckReturn_Params> returns = std::vector<ui::OverlayCheckReturn_Params> returns =
overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList()); overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList());
EXPECT_EQ(2u, returns.size());
EXPECT_EQ(returns.front().status, ui::OVERLAY_STATUS_NOT); EXPECT_EQ(returns.front().status, ui::OVERLAY_STATUS_NOT);
} }
...@@ -97,7 +97,7 @@ void DrmWindowTest::SetUp() { ...@@ -97,7 +97,7 @@ void DrmWindowTest::SetUp() {
last_swap_buffers_result_ = gfx::SwapResult::SWAP_FAILED; last_swap_buffers_result_ = gfx::SwapResult::SWAP_FAILED;
message_loop_.reset(new base::MessageLoopForUI); message_loop_.reset(new base::MessageLoopForUI);
drm_ = new ui::MockDrmDevice(); drm_ = new ui::MockDrmDevice(false);
buffer_generator_.reset(new ui::MockDumbBufferGenerator()); buffer_generator_.reset(new ui::MockDumbBufferGenerator());
screen_manager_.reset(new ui::ScreenManager(buffer_generator_.get())); screen_manager_.reset(new ui::ScreenManager(buffer_generator_.get()));
screen_manager_->AddDisplayController(drm_, kDefaultCrtc, kDefaultConnector); screen_manager_->AddDisplayController(drm_, kDefaultCrtc, kDefaultConnector);
...@@ -154,7 +154,7 @@ TEST_F(DrmWindowTest, CheckCursorSurfaceAfterChangingDevice) { ...@@ -154,7 +154,7 @@ TEST_F(DrmWindowTest, CheckCursorSurfaceAfterChangingDevice) {
gfx::Point(4, 2), 0); gfx::Point(4, 2), 0);
// Add another device. // Add another device.
scoped_refptr<ui::MockDrmDevice> drm = new ui::MockDrmDevice(); scoped_refptr<ui::MockDrmDevice> drm = new ui::MockDrmDevice(false);
screen_manager_->AddDisplayController(drm, kDefaultCrtc, kDefaultConnector); screen_manager_->AddDisplayController(drm, kDefaultCrtc, kDefaultConnector);
screen_manager_->ConfigureDisplayController( screen_manager_->ConfigureDisplayController(
drm, kDefaultCrtc, kDefaultConnector, drm, kDefaultCrtc, kDefaultConnector,
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "ui/ozone/platform/drm/gpu/crtc_controller.h" #include "ui/ozone/platform/drm/gpu/crtc_controller.h"
#include "ui/ozone/platform/drm/gpu/drm_buffer.h" #include "ui/ozone/platform/drm/gpu/drm_buffer.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h" #include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_plane.h"
#include "ui/ozone/platform/drm/gpu/page_flip_request.h" #include "ui/ozone/platform/drm/gpu/page_flip_request.h"
namespace ui { namespace ui {
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "ui/gfx/presentation_feedback.h" #include "ui/gfx/presentation_feedback.h"
#include "ui/ozone/platform/drm/gpu/crtc_controller.h" #include "ui/ozone/platform/drm/gpu/crtc_controller.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h" #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_plane.h"
#include "ui/ozone/platform/drm/gpu/mock_drm_device.h" #include "ui/ozone/platform/drm/gpu/mock_drm_device.h"
#include "ui/ozone/platform/drm/gpu/mock_scanout_buffer.h" #include "ui/ozone/platform/drm/gpu/mock_scanout_buffer.h"
...@@ -22,11 +23,11 @@ namespace { ...@@ -22,11 +23,11 @@ namespace {
const drmModeModeInfo kDefaultMode = const drmModeModeInfo kDefaultMode =
{0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}}; {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}};
const uint32_t kPrimaryCrtc = 1; constexpr uint32_t kCrtcIdBase = 1;
const uint32_t kPrimaryConnector = 2; constexpr uint32_t kPrimaryCrtc = kCrtcIdBase;
const uint32_t kSecondaryCrtc = 3; constexpr uint32_t kSecondaryCrtc = kCrtcIdBase + 1;
const uint32_t kSecondaryConnector = 4; constexpr uint32_t kPrimaryConnector = 10;
const size_t kPlanesPerCrtc = 2; constexpr uint32_t kSecondaryConnector = 11;
const gfx::Size kDefaultModeSize(kDefaultMode.hdisplay, kDefaultMode.vdisplay); const gfx::Size kDefaultModeSize(kDefaultMode.hdisplay, kDefaultMode.vdisplay);
const gfx::Size kOverlaySize(kDefaultMode.hdisplay / 2, const gfx::Size kOverlaySize(kDefaultMode.hdisplay / 2,
...@@ -43,6 +44,7 @@ class HardwareDisplayControllerTest : public testing::Test { ...@@ -43,6 +44,7 @@ class HardwareDisplayControllerTest : public testing::Test {
void SetUp() override; void SetUp() override;
void TearDown() override; void TearDown() override;
void InitializeDrmDevice(bool use_atomic);
void PageFlipCallback(gfx::SwapResult result, void PageFlipCallback(gfx::SwapResult result,
const gfx::PresentationFeedback& feedback); const gfx::PresentationFeedback& feedback);
...@@ -62,10 +64,9 @@ void HardwareDisplayControllerTest::SetUp() { ...@@ -62,10 +64,9 @@ void HardwareDisplayControllerTest::SetUp() {
page_flips_ = 0; page_flips_ = 0;
last_swap_result_ = gfx::SwapResult::SWAP_FAILED; last_swap_result_ = gfx::SwapResult::SWAP_FAILED;
std::vector<uint32_t> crtcs; drm_ = new ui::MockDrmDevice(false);
crtcs.push_back(kPrimaryCrtc); InitializeDrmDevice(/* use_atomic= */ false);
crtcs.push_back(kSecondaryCrtc);
drm_ = new ui::MockDrmDevice(false, crtcs, kPlanesPerCrtc);
controller_.reset(new ui::HardwareDisplayController( controller_.reset(new ui::HardwareDisplayController(
std::unique_ptr<ui::CrtcController>( std::unique_ptr<ui::CrtcController>(
new ui::CrtcController(drm_.get(), kPrimaryCrtc, kPrimaryConnector)), new ui::CrtcController(drm_.get(), kPrimaryCrtc, kPrimaryConnector)),
...@@ -77,6 +78,60 @@ void HardwareDisplayControllerTest::TearDown() { ...@@ -77,6 +78,60 @@ void HardwareDisplayControllerTest::TearDown() {
drm_ = nullptr; drm_ = nullptr;
} }
void HardwareDisplayControllerTest::InitializeDrmDevice(bool use_atomic) {
constexpr uint32_t kTypePropId = 300;
constexpr uint32_t kInFormatsPropId = 301;
constexpr uint32_t kInFormatsBlobPropId = 400;
std::vector<ui::MockDrmDevice::CrtcProperties> crtc_properties(2);
std::vector<ui::MockDrmDevice::PlaneProperties> plane_properties;
std::map<uint32_t, std::string> property_names = {
// Add all required properties.
{200, "CRTC_ID"},
{201, "CRTC_X"},
{202, "CRTC_Y"},
{203, "CRTC_W"},
{204, "CRTC_H"},
{205, "FB_ID"},
{206, "SRC_X"},
{207, "SRC_Y"},
{208, "SRC_W"},
{209, "SRC_H"},
// Add some optional properties we use for convenience.
{kTypePropId, "type"},
{kInFormatsPropId, "IN_FORMATS"},
};
for (size_t i = 0; i < crtc_properties.size(); ++i) {
crtc_properties[i].id = kCrtcIdBase + i;
for (size_t j = 0; j < 2; ++j) {
const uint32_t offset = plane_properties.size();
ui::MockDrmDevice::PlaneProperties plane;
plane.id = 100 + offset;
plane.crtc_mask = 1 << i;
for (const auto& pair : property_names) {
uint32_t value = 0;
if (pair.first == kTypePropId)
value = j == 0 ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
else if (pair.first == kInFormatsPropId)
value = kInFormatsBlobPropId;
plane.properties.push_back({.id = pair.first, .value = value});
};
drm_->SetPropertyBlob(ui::MockDrmDevice::AllocateInFormatsBlob(
kInFormatsBlobPropId, {DRM_FORMAT_XRGB8888}, {}));
plane_properties.emplace_back(std::move(plane));
}
}
drm_->InitializeState(crtc_properties, plane_properties, property_names,
use_atomic);
}
void HardwareDisplayControllerTest::PageFlipCallback( void HardwareDisplayControllerTest::PageFlipCallback(
gfx::SwapResult result, gfx::SwapResult result,
const gfx::PresentationFeedback& feedback) { const gfx::PresentationFeedback& feedback) {
...@@ -480,6 +535,9 @@ TEST_F(HardwareDisplayControllerTest, RemoveCrtcMidPageFlip) { ...@@ -480,6 +535,9 @@ TEST_F(HardwareDisplayControllerTest, RemoveCrtcMidPageFlip) {
} }
TEST_F(HardwareDisplayControllerTest, Disable) { TEST_F(HardwareDisplayControllerTest, Disable) {
// Page flipping overlays is only supported on atomic configurations.
InitializeDrmDevice(/* use_atomic= */ true);
ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>( ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>(
new ui::MockScanoutBuffer(kDefaultModeSize)), new ui::MockScanoutBuffer(kDefaultModeSize)),
nullptr); nullptr);
...@@ -497,7 +555,6 @@ TEST_F(HardwareDisplayControllerTest, Disable) { ...@@ -497,7 +555,6 @@ TEST_F(HardwareDisplayControllerTest, Disable) {
base::Unretained(this))); base::Unretained(this)));
drm_->RunCallbacks(); drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_); EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(1, page_flips_);
controller_->Disable(); controller_->Disable();
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h" #include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/drm_gpu_util.h"
#ifndef DRM_PLANE_TYPE_OVERLAY #ifndef DRM_PLANE_TYPE_OVERLAY
#define DRM_PLANE_TYPE_OVERLAY 0 #define DRM_PLANE_TYPE_OVERLAY 0
...@@ -26,7 +27,6 @@ namespace ui { ...@@ -26,7 +27,6 @@ namespace ui {
namespace { namespace {
const char* kTypePropName = "type";
HardwareDisplayPlane::Type GetPlaneType(int value) { HardwareDisplayPlane::Type GetPlaneType(int value) {
switch (value) { switch (value) {
case DRM_PLANE_TYPE_CURSOR: case DRM_PLANE_TYPE_CURSOR:
...@@ -41,57 +41,63 @@ HardwareDisplayPlane::Type GetPlaneType(int value) { ...@@ -41,57 +41,63 @@ HardwareDisplayPlane::Type GetPlaneType(int value) {
} }
} }
void ParseSupportedFormatsAndModifiers(
drmModePropertyBlobPtr blob,
std::vector<uint32_t>* supported_formats,
std::vector<drm_format_modifier>* supported_format_modifiers) {
auto* data = static_cast<const uint8_t*>(blob->data);
auto* header = reinterpret_cast<const drm_format_modifier_blob*>(data);
auto* formats =
reinterpret_cast<const uint32_t*>(data + header->formats_offset);
auto* modifiers = reinterpret_cast<const drm_format_modifier*>(
data + header->modifiers_offset);
for (uint32_t k = 0; k < header->count_formats; k++)
supported_formats->push_back(formats[k]);
for (uint32_t k = 0; k < header->count_modifiers; k++)
supported_format_modifiers->push_back(modifiers[k]);
}
} // namespace } // namespace
HardwareDisplayPlane::HardwareDisplayPlane(uint32_t plane_id, HardwareDisplayPlane::HardwareDisplayPlane(uint32_t id) : id_(id) {}
uint32_t possible_crtcs)
: plane_id_(plane_id), possible_crtcs_(possible_crtcs) {
}
HardwareDisplayPlane::~HardwareDisplayPlane() { HardwareDisplayPlane::~HardwareDisplayPlane() {}
}
bool HardwareDisplayPlane::CanUseForCrtc(uint32_t crtc_index) { bool HardwareDisplayPlane::CanUseForCrtc(uint32_t crtc_index) {
return possible_crtcs_ & (1 << crtc_index); return crtc_mask_ & (1 << crtc_index);
} }
bool HardwareDisplayPlane::Initialize( bool HardwareDisplayPlane::Initialize(DrmDevice* drm) {
DrmDevice* drm, InitializeProperties(drm);
const std::vector<uint32_t>& formats,
const std::vector<drm_format_modifier>& format_modifiers,
bool is_dummy,
bool test_only) {
supported_formats_ = formats;
supported_format_modifiers_ = format_modifiers;
if (test_only) ScopedDrmPlanePtr drm_plane(drm->GetPlane(id_));
return true; DCHECK(drm_plane);
if (is_dummy) { crtc_mask_ = drm_plane->possible_crtcs;
type_ = kDummy; if (properties_.in_formats.id) {
supported_formats_.push_back(DRM_FORMAT_XRGB8888); ScopedDrmPropertyBlobPtr blob(
supported_formats_.push_back(DRM_FORMAT_XBGR8888); drm->GetPropertyBlob(properties_.in_formats.value));
return true; DCHECK(blob);
ParseSupportedFormatsAndModifiers(blob.get(), &supported_formats_,
&supported_format_modifiers_);
} }
ScopedDrmObjectPropertyPtr plane_props(drmModeObjectGetProperties( if (supported_formats_.empty()) {
drm->get_fd(), plane_id_, DRM_MODE_OBJECT_PLANE)); for (uint32_t i = 0; i < drm_plane->count_formats; ++i)
if (!plane_props) { supported_formats_.push_back(drm_plane->formats[i]);
PLOG(ERROR) << "Unable to get plane properties.";
return false;
} }
uint32_t count_props = plane_props->count_props; if (properties_.type.id)
for (uint32_t i = 0; i < count_props; i++) { type_ = GetPlaneType(properties_.type.value);
ScopedDrmPropertyPtr property(
drmModeGetProperty(drm->get_fd(), plane_props->props[i]));
if (property && !strcmp(property->name, kTypePropName)) {
type_ = GetPlaneType(plane_props->prop_values[i]);
break;
}
}
return InitializeProperties(drm, plane_props); VLOG(3) << "Initialized plane=" << id_ << " crtc_mask=" << std::hex << "0x"
<< crtc_mask_ << std::dec
<< " supported_formats_count=" << supported_formats_.size()
<< " supported_modifiers_count="
<< supported_format_modifiers_.size();
return true;
} }
bool HardwareDisplayPlane::IsSupportedFormat(uint32_t format) { bool HardwareDisplayPlane::IsSupportedFormat(uint32_t format) {
...@@ -141,10 +147,25 @@ std::vector<uint64_t> HardwareDisplayPlane::ModifiersForFormat( ...@@ -141,10 +147,25 @@ std::vector<uint64_t> HardwareDisplayPlane::ModifiersForFormat(
return modifiers; return modifiers;
} }
bool HardwareDisplayPlane::InitializeProperties( void HardwareDisplayPlane::InitializeProperties(DrmDevice* drm) {
DrmDevice* drm, ScopedDrmObjectPropertyPtr props =
const ScopedDrmObjectPropertyPtr& plane_props) { drm->GetObjectProperties(id_, DRM_MODE_OBJECT_PLANE);
return true; GetDrmPropertyForName(drm, props.get(), "CRTC_ID", &properties_.crtc_id);
GetDrmPropertyForName(drm, props.get(), "CRTC_X", &properties_.crtc_x);
GetDrmPropertyForName(drm, props.get(), "CRTC_Y", &properties_.crtc_y);
GetDrmPropertyForName(drm, props.get(), "CRTC_W", &properties_.crtc_w);
GetDrmPropertyForName(drm, props.get(), "CRTC_H", &properties_.crtc_h);
GetDrmPropertyForName(drm, props.get(), "FB_ID", &properties_.fb_id);
GetDrmPropertyForName(drm, props.get(), "SRC_X", &properties_.src_x);
GetDrmPropertyForName(drm, props.get(), "SRC_Y", &properties_.src_y);
GetDrmPropertyForName(drm, props.get(), "SRC_W", &properties_.src_w);
GetDrmPropertyForName(drm, props.get(), "SRC_H", &properties_.src_h);
GetDrmPropertyForName(drm, props.get(), "type", &properties_.type);
GetDrmPropertyForName(drm, props.get(), "rotation", &properties_.rotation);
GetDrmPropertyForName(drm, props.get(), "IN_FORMATS",
&properties_.in_formats);
GetDrmPropertyForName(drm, props.get(), "IN_FENCE_FD",
&properties_.in_fence_fd);
} }
} // namespace ui } // namespace ui
...@@ -14,24 +14,19 @@ ...@@ -14,24 +14,19 @@
#include "base/macros.h" #include "base/macros.h"
#include "ui/ozone/platform/drm/common/scoped_drm_types.h" #include "ui/ozone/platform/drm/common/scoped_drm_types.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
namespace ui { namespace ui {
class DrmDevice;
class HardwareDisplayPlane { class HardwareDisplayPlane {
public: public:
enum Type { kDummy, kPrimary, kOverlay, kCursor }; enum Type { kDummy, kPrimary, kOverlay, kCursor };
HardwareDisplayPlane(uint32_t plane_id, uint32_t possible_crtcs); HardwareDisplayPlane(uint32_t id);
virtual ~HardwareDisplayPlane(); virtual ~HardwareDisplayPlane();
bool Initialize(DrmDevice* drm, virtual bool Initialize(DrmDevice* drm);
const std::vector<uint32_t>& formats,
const std::vector<drm_format_modifier>& format_info,
bool is_dummy,
bool test_only);
bool IsSupportedFormat(uint32_t format); bool IsSupportedFormat(uint32_t format);
...@@ -42,7 +37,7 @@ class HardwareDisplayPlane { ...@@ -42,7 +37,7 @@ class HardwareDisplayPlane {
bool in_use() const { return in_use_; } bool in_use() const { return in_use_; }
void set_in_use(bool in_use) { in_use_ = in_use; } void set_in_use(bool in_use) { in_use_ = in_use; }
uint32_t plane_id() const { return plane_id_; } uint32_t id() const { return id_; }
Type type() const { return type_; } Type type() const { return type_; }
void set_type(const Type type) { type_ = type; } void set_type(const Type type) { type_ = type; }
...@@ -53,12 +48,32 @@ class HardwareDisplayPlane { ...@@ -53,12 +48,32 @@ class HardwareDisplayPlane {
const std::vector<uint32_t>& supported_formats() const; const std::vector<uint32_t>& supported_formats() const;
protected: protected:
virtual bool InitializeProperties( struct Properties {
DrmDevice* drm, // These properties are mandatory on DRM atomic. On legacy they may or may
const ScopedDrmObjectPropertyPtr& plane_props); // not be present.
DrmDevice::Property crtc_id;
DrmDevice::Property crtc_x;
DrmDevice::Property crtc_y;
DrmDevice::Property crtc_w;
DrmDevice::Property crtc_h;
DrmDevice::Property fb_id;
DrmDevice::Property src_x;
DrmDevice::Property src_y;
DrmDevice::Property src_w;
DrmDevice::Property src_h;
DrmDevice::Property type;
// Optional properties.
DrmDevice::Property rotation;
DrmDevice::Property in_formats;
DrmDevice::Property in_fence_fd;
};
uint32_t id_;
uint32_t crtc_mask_ = 0;
Properties properties_ = {};
uint32_t plane_id_ = 0;
uint32_t possible_crtcs_ = 0;
uint32_t owning_crtc_ = 0; uint32_t owning_crtc_ = 0;
uint32_t last_used_format_ = 0; uint32_t last_used_format_ = 0;
bool in_use_ = false; bool in_use_ = false;
...@@ -66,6 +81,9 @@ class HardwareDisplayPlane { ...@@ -66,6 +81,9 @@ class HardwareDisplayPlane {
std::vector<uint32_t> supported_formats_; std::vector<uint32_t> supported_formats_;
std::vector<drm_format_modifier> supported_format_modifiers_; std::vector<drm_format_modifier> supported_format_modifiers_;
private:
void InitializeProperties(DrmDevice* drm);
DISALLOW_COPY_AND_ASSIGN(HardwareDisplayPlane); DISALLOW_COPY_AND_ASSIGN(HardwareDisplayPlane);
}; };
......
...@@ -9,19 +9,6 @@ ...@@ -9,19 +9,6 @@
namespace ui { namespace ui {
namespace { namespace {
const char* kCrtcPropName = "CRTC_ID";
const char* kFbPropName = "FB_ID";
const char* kCrtcXPropName = "CRTC_X";
const char* kCrtcYPropName = "CRTC_Y";
const char* kCrtcWPropName = "CRTC_W";
const char* kCrtcHPropName = "CRTC_H";
const char* kSrcXPropName = "SRC_X";
const char* kSrcYPropName = "SRC_Y";
const char* kSrcWPropName = "SRC_W";
const char* kSrcHPropName = "SRC_H";
const char* kRotationPropName = "rotation";
const char* kInFenceFdPropName = "IN_FENCE_FD";
// TODO(dcastagna): Remove the following defines once they're in libdrm headers. // TODO(dcastagna): Remove the following defines once they're in libdrm headers.
#if !defined(DRM_ROTATE_0) #if !defined(DRM_ROTATE_0)
#define BIT(n) (1 << (n)) #define BIT(n) (1 << (n))
...@@ -54,31 +41,41 @@ uint32_t OverlayTransformToDrmRotationPropertyValue( ...@@ -54,31 +41,41 @@ uint32_t OverlayTransformToDrmRotationPropertyValue(
return 0; return 0;
} }
} // namespace bool AddProperty(drmModeAtomicReqPtr property_set,
uint32_t object_id,
const DrmDevice::Property& property) {
int ret = drmModeAtomicAddProperty(property_set, object_id, property.id,
property.value);
if (ret < 0) {
LOG(ERROR) << "Failed to set property object_id=" << object_id
<< " property_id=" << property.id
<< " property_value=" << property.value << " error=" << -ret;
return false;
}
HardwareDisplayPlaneAtomic::Property::Property() { return true;
} }
bool HardwareDisplayPlaneAtomic::Property::Initialize( } // namespace
DrmDevice* drm,
const char* name,
const ScopedDrmObjectPropertyPtr& plane_props) {
for (uint32_t i = 0; i < plane_props->count_props; i++) {
ScopedDrmPropertyPtr property(
drmModeGetProperty(drm->get_fd(), plane_props->props[i]));
if (property && !strcmp(property->name, name)) {
id = property->prop_id;
break;
}
}
return !!id;
}
HardwareDisplayPlaneAtomic::HardwareDisplayPlaneAtomic(uint32_t plane_id, HardwareDisplayPlaneAtomic::HardwareDisplayPlaneAtomic(uint32_t id)
uint32_t possible_crtcs) : HardwareDisplayPlane(id) {}
: HardwareDisplayPlane(plane_id, possible_crtcs) {
} HardwareDisplayPlaneAtomic::~HardwareDisplayPlaneAtomic() {}
HardwareDisplayPlaneAtomic::~HardwareDisplayPlaneAtomic() {
bool HardwareDisplayPlaneAtomic::Initialize(DrmDevice* drm) {
if (!HardwareDisplayPlane::Initialize(drm))
return false;
// Check that all the required properties have been found.
bool ret = properties_.crtc_id.id && properties_.crtc_x.id &&
properties_.crtc_y.id && properties_.crtc_w.id &&
properties_.crtc_h.id && properties_.fb_id.id &&
properties_.src_x.id && properties_.src_y.id &&
properties_.src_w.id && properties_.src_h.id;
LOG_IF(ERROR, !ret) << "Failed to find all required properties for plane="
<< id_;
return ret;
} }
bool HardwareDisplayPlaneAtomic::SetPlaneData( bool HardwareDisplayPlaneAtomic::SetPlaneData(
...@@ -89,72 +86,51 @@ bool HardwareDisplayPlaneAtomic::SetPlaneData( ...@@ -89,72 +86,51 @@ bool HardwareDisplayPlaneAtomic::SetPlaneData(
const gfx::Rect& src_rect, const gfx::Rect& src_rect,
const gfx::OverlayTransform transform, const gfx::OverlayTransform transform,
int in_fence_fd) { int in_fence_fd) {
if (transform != gfx::OVERLAY_TRANSFORM_NONE && !rotation_prop_.id) if (transform != gfx::OVERLAY_TRANSFORM_NONE && !properties_.rotation.id)
return false; return false;
int plane_set_succeeded = properties_.crtc_id.value = crtc_id;
drmModeAtomicAddProperty(property_set, plane_id_, crtc_prop_.id, properties_.crtc_x.value = crtc_rect.x();
crtc_id) && properties_.crtc_y.value = crtc_rect.y();
drmModeAtomicAddProperty(property_set, plane_id_, fb_prop_.id, properties_.crtc_w.value = crtc_rect.width();
framebuffer) && properties_.crtc_h.value = crtc_rect.height();
drmModeAtomicAddProperty(property_set, plane_id_, crtc_x_prop_.id, properties_.fb_id.value = framebuffer;
crtc_rect.x()) && properties_.src_x.value = src_rect.x();
drmModeAtomicAddProperty(property_set, plane_id_, crtc_y_prop_.id, properties_.src_y.value = src_rect.y();
crtc_rect.y()) && properties_.src_w.value = src_rect.width();
drmModeAtomicAddProperty(property_set, plane_id_, crtc_w_prop_.id, properties_.src_h.value = src_rect.height();
crtc_rect.width()) &&
drmModeAtomicAddProperty(property_set, plane_id_, crtc_h_prop_.id, bool plane_set_succeeded =
crtc_rect.height()) && AddProperty(property_set, id_, properties_.crtc_id) &&
drmModeAtomicAddProperty(property_set, plane_id_, src_x_prop_.id, AddProperty(property_set, id_, properties_.crtc_x) &&
src_rect.x()) && AddProperty(property_set, id_, properties_.crtc_y) &&
drmModeAtomicAddProperty(property_set, plane_id_, src_y_prop_.id, AddProperty(property_set, id_, properties_.crtc_w) &&
src_rect.y()) && AddProperty(property_set, id_, properties_.crtc_h) &&
drmModeAtomicAddProperty(property_set, plane_id_, src_w_prop_.id, AddProperty(property_set, id_, properties_.fb_id) &&
src_rect.width()) && AddProperty(property_set, id_, properties_.src_x) &&
drmModeAtomicAddProperty(property_set, plane_id_, src_h_prop_.id, AddProperty(property_set, id_, properties_.src_y) &&
src_rect.height()); AddProperty(property_set, id_, properties_.src_w) &&
AddProperty(property_set, id_, properties_.src_h);
if (rotation_prop_.id) {
plane_set_succeeded = if (properties_.rotation.id) {
plane_set_succeeded && properties_.rotation.value =
drmModeAtomicAddProperty( OverlayTransformToDrmRotationPropertyValue(transform);
property_set, plane_id_, rotation_prop_.id, plane_set_succeeded = plane_set_succeeded &&
OverlayTransformToDrmRotationPropertyValue(transform)); AddProperty(property_set, id_, properties_.rotation);
} }
if (in_fence_fd_prop_.id && in_fence_fd >= 0) {
if (properties_.in_fence_fd.id && in_fence_fd >= 0) {
properties_.in_fence_fd.value = in_fence_fd;
plane_set_succeeded = plane_set_succeeded =
plane_set_succeeded && plane_set_succeeded &&
drmModeAtomicAddProperty(property_set, plane_id_, in_fence_fd_prop_.id, AddProperty(property_set, id_, properties_.in_fence_fd);
in_fence_fd);
} }
if (!plane_set_succeeded) { if (!plane_set_succeeded) {
PLOG(ERROR) << "Failed to set plane data"; LOG(ERROR) << "Failed to set plane data";
return false; return false;
} }
return true;
}
bool HardwareDisplayPlaneAtomic::InitializeProperties(
DrmDevice* drm,
const ScopedDrmObjectPropertyPtr& plane_props) {
bool props_init = crtc_prop_.Initialize(drm, kCrtcPropName, plane_props) &&
fb_prop_.Initialize(drm, kFbPropName, plane_props) &&
crtc_x_prop_.Initialize(drm, kCrtcXPropName, plane_props) &&
crtc_y_prop_.Initialize(drm, kCrtcYPropName, plane_props) &&
crtc_w_prop_.Initialize(drm, kCrtcWPropName, plane_props) &&
crtc_h_prop_.Initialize(drm, kCrtcHPropName, plane_props) &&
src_x_prop_.Initialize(drm, kSrcXPropName, plane_props) &&
src_y_prop_.Initialize(drm, kSrcYPropName, plane_props) &&
src_w_prop_.Initialize(drm, kSrcWPropName, plane_props) &&
src_h_prop_.Initialize(drm, kSrcHPropName, plane_props);
if (!props_init) {
LOG(ERROR) << "Unable to get plane properties.";
return false;
}
// The following properties are optional.
rotation_prop_.Initialize(drm, kRotationPropName, plane_props);
in_fence_fd_prop_.Initialize(drm, kInFenceFdPropName, plane_props);
return true; return true;
} }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_ATOMIC_H_ #define UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_ATOMIC_H_
#include "ui/gfx/overlay_transform.h" #include "ui/gfx/overlay_transform.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_plane.h" #include "ui/ozone/platform/drm/gpu/hardware_display_plane.h"
#include <stdint.h> #include <stdint.h>
...@@ -18,13 +19,14 @@ class Rect; ...@@ -18,13 +19,14 @@ class Rect;
namespace ui { namespace ui {
class CrtcController; class CrtcController;
class DrmDevice;
class HardwareDisplayPlaneAtomic : public HardwareDisplayPlane { class HardwareDisplayPlaneAtomic : public HardwareDisplayPlane {
public: public:
HardwareDisplayPlaneAtomic(uint32_t plane_id, uint32_t possible_crtcs); HardwareDisplayPlaneAtomic(uint32_t id);
~HardwareDisplayPlaneAtomic() override; ~HardwareDisplayPlaneAtomic() override;
bool Initialize(DrmDevice* drm) override;
virtual bool SetPlaneData(drmModeAtomicReq* property_set, virtual bool SetPlaneData(drmModeAtomicReq* property_set,
uint32_t crtc_id, uint32_t crtc_id,
uint32_t framebuffer, uint32_t framebuffer,
...@@ -37,32 +39,9 @@ class HardwareDisplayPlaneAtomic : public HardwareDisplayPlane { ...@@ -37,32 +39,9 @@ class HardwareDisplayPlaneAtomic : public HardwareDisplayPlane {
CrtcController* crtc() const { return crtc_; } CrtcController* crtc() const { return crtc_; }
private: private:
bool InitializeProperties(
DrmDevice* drm,
const ScopedDrmObjectPropertyPtr& plane_props) override;
// TODO(dnicoara): Merge this with DrmDevice::Property.
struct Property {
Property();
bool Initialize(DrmDevice* drm,
const char* name,
const ScopedDrmObjectPropertyPtr& plane_properties);
uint32_t id = 0;
};
Property crtc_prop_;
Property fb_prop_;
Property crtc_x_prop_;
Property crtc_y_prop_;
Property crtc_w_prop_;
Property crtc_h_prop_;
Property src_x_prop_;
Property src_y_prop_;
Property src_w_prop_;
Property src_h_prop_;
Property rotation_prop_;
Property in_fence_fd_prop_;
CrtcController* crtc_ = nullptr; CrtcController* crtc_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(HardwareDisplayPlaneAtomic);
}; };
} // namespace ui } // namespace ui
......
// Copyright 2018 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/hardware_display_plane_dummy.h"
#include <drm_fourcc.h>
namespace ui {
HardwareDisplayPlaneDummy::HardwareDisplayPlaneDummy(uint32_t id,
uint32_t crtc_mask)
: HardwareDisplayPlane(id) {
crtc_mask_ = crtc_mask;
}
HardwareDisplayPlaneDummy::~HardwareDisplayPlaneDummy() {}
bool HardwareDisplayPlaneDummy::Initialize(DrmDevice* drm) {
type_ = kDummy;
supported_formats_.push_back(DRM_FORMAT_XRGB8888);
supported_formats_.push_back(DRM_FORMAT_XBGR8888);
return true;
}
} // namespace ui
// Copyright 2018 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.
#ifndef UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_DUMMY_H_
#define UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_DUMMY_H_
#include "ui/ozone/platform/drm/gpu/hardware_display_plane.h"
namespace ui {
// Fake plane used with DRM legacy when universal planes are not supported and
// the kernel doesn't report the primary plane.
class HardwareDisplayPlaneDummy : public HardwareDisplayPlane {
public:
HardwareDisplayPlaneDummy(uint32_t id, uint32_t crtc_mask);
~HardwareDisplayPlaneDummy() override;
bool Initialize(DrmDevice* drm) override;
private:
DISALLOW_COPY_AND_ASSIGN(HardwareDisplayPlaneDummy);
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_DRM_GPU_HARDWARE_DISPLAY_PLANE_DUMMY_H_
...@@ -16,12 +16,14 @@ ...@@ -16,12 +16,14 @@
#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h" #include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/drm_gpu_util.h" #include "ui/ozone/platform/drm/gpu/drm_gpu_util.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_plane.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_plane_dummy.h"
#include "ui/ozone/platform/drm/gpu/scanout_buffer.h" #include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
namespace ui { namespace ui {
namespace { namespace {
const float kFixedPointScaleValue = 65536.0f; constexpr float kFixedPointScaleValue = 1 << 16;
ScopedDrmColorLutPtr CreateLutBlob( ScopedDrmColorLutPtr CreateLutBlob(
const std::vector<display::GammaRampRGBEntry>& source) { const std::vector<display::GammaRampRGBEntry>& source) {
...@@ -169,82 +171,34 @@ HardwareDisplayPlaneManager::~HardwareDisplayPlaneManager() { ...@@ -169,82 +171,34 @@ HardwareDisplayPlaneManager::~HardwareDisplayPlaneManager() {
bool HardwareDisplayPlaneManager::Initialize(DrmDevice* drm) { bool HardwareDisplayPlaneManager::Initialize(DrmDevice* drm) {
drm_ = drm; drm_ = drm;
// Try to get all of the planes if possible, so we don't have to try to
// discover hidden primary planes.
bool has_universal_planes = false; bool has_universal_planes = false;
// Try to get all of the planes if possible, so we don't have to try to
// discover hidden primary planes.
#if defined(DRM_CLIENT_CAP_UNIVERSAL_PLANES) #if defined(DRM_CLIENT_CAP_UNIVERSAL_PLANES)
has_universal_planes = drm->SetCapability(DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); has_universal_planes =
#endif // defined(DRM_CLIENT_CAP_UNIVERSAL_PLANES) drm_->SetCapability(DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
#endif
if (!InitializeCrtcProperties(drm)) if (!InitializeCrtcProperties(drm))
return false; return false;
ScopedDrmPlaneResPtr plane_resources(drmModeGetPlaneResources(drm->get_fd())); ScopedDrmPlaneResPtr plane_resources = drm->GetPlaneResources();
if (!plane_resources) { if (!plane_resources) {
PLOG(ERROR) << "Failed to get plane resources"; PLOG(ERROR) << "Failed to get plane resources.";
return false; return false;
} }
uint32_t num_planes = plane_resources->count_planes;
std::set<uint32_t> plane_ids; std::set<uint32_t> plane_ids;
for (uint32_t i = 0; i < num_planes; ++i) { for (uint32_t i = 0; i < plane_resources->count_planes; ++i) {
// TODO(hoegsberg) crbug.com/763760: We've rolled back the plane_ids.insert(plane_resources->planes[i]);
// downstream, incompatible drmModeGetPlane2 ioctl for now while
// we update libdrm to the upstream per-plane IN_FORMATS property
// API. This drops support for compressed and tiled framebuffers
// in the interim, but once the buildroots and SDKs have pulled in
// the new libdrm we'll add it back by reading the property.
ScopedDrmPlanePtr drm_plane(
drmModeGetPlane(drm->get_fd(), plane_resources->planes[i]));
if (!drm_plane) {
PLOG(ERROR) << "Failed to get plane " << i;
return false;
}
ScopedDrmObjectPropertyPtr drm_plane_properties(drmModeObjectGetProperties(
drm->get_fd(), plane_resources->planes[i], DRM_MODE_OBJECT_PLANE));
std::vector<uint32_t> supported_formats;
std::vector<drm_format_modifier> supported_format_modifiers;
if (drm_plane_properties) {
for (uint32_t j = 0; j < drm_plane_properties->count_props; j++) {
ScopedDrmPropertyPtr property(
drmModeGetProperty(drm->get_fd(), drm_plane_properties->props[j]));
if (strcmp(property->name, "IN_FORMATS") == 0) {
ScopedDrmPropertyBlobPtr blob(drmModeGetPropertyBlob(
drm->get_fd(), drm_plane_properties->prop_values[j]));
auto* data = static_cast<const uint8_t*>(blob->data);
auto* header = reinterpret_cast<const drm_format_modifier_blob*>(data);
auto* formats =
reinterpret_cast<const uint32_t*>(data + header->formats_offset);
auto* modifiers = reinterpret_cast<const drm_format_modifier*>(
data + header->modifiers_offset);
for (uint32_t k = 0; k < header->count_formats; k++)
supported_formats.push_back(formats[k]);
for (uint32_t k = 0; k < header->count_modifiers; k++)
supported_format_modifiers.push_back(modifiers[k]);
}
}
}
if (supported_formats.empty()) {
uint32_t formats_size = drm_plane->count_formats;
for (uint32_t j = 0; j < formats_size; j++)
supported_formats.push_back(drm_plane->formats[j]);
}
plane_ids.insert(drm_plane->plane_id);
std::unique_ptr<HardwareDisplayPlane> plane( std::unique_ptr<HardwareDisplayPlane> plane(
CreatePlane(drm_plane->plane_id, drm_plane->possible_crtcs)); CreatePlane(plane_resources->planes[i]));
if (plane->Initialize(drm, supported_formats, supported_format_modifiers, if (plane->Initialize(drm)) {
false, false)) { // CRTC controllers always assume they have a cursor plane and the
// CRTC controllers always assume they have a cursor plane and the cursor // cursor plane is updated via cursor specific DRM API. Hence, we don't
// plane is updated via cursor specific DRM API. Hence, we dont keep // keep track of cursor plane here to avoid re-using it for any other
// track of Cursor plane here to avoid re-using it for any other purpose. // purpose.
if (plane->type() != HardwareDisplayPlane::kCursor) if (plane->type() != HardwareDisplayPlane::kCursor)
planes_.push_back(std::move(plane)); planes_.push_back(std::move(plane));
} }
...@@ -258,10 +212,8 @@ bool HardwareDisplayPlaneManager::Initialize(DrmDevice* drm) { ...@@ -258,10 +212,8 @@ bool HardwareDisplayPlaneManager::Initialize(DrmDevice* drm) {
for (size_t i = 0; i < crtc_properties_.size(); ++i) { for (size_t i = 0; i < crtc_properties_.size(); ++i) {
if (plane_ids.find(crtc_properties_[i].id - 1) == plane_ids.end()) { if (plane_ids.find(crtc_properties_[i].id - 1) == plane_ids.end()) {
std::unique_ptr<HardwareDisplayPlane> dummy_plane( std::unique_ptr<HardwareDisplayPlane> dummy_plane(
CreatePlane(crtc_properties_[i].id - 1, (1 << i))); new HardwareDisplayPlaneDummy(crtc_properties_[i].id - 1, 1 << i));
if (dummy_plane->Initialize(drm, std::vector<uint32_t>(), if (dummy_plane->Initialize(drm)) {
std::vector<drm_format_modifier>(), true,
false)) {
planes_.push_back(std::move(dummy_plane)); planes_.push_back(std::move(dummy_plane));
} }
} }
...@@ -271,7 +223,7 @@ bool HardwareDisplayPlaneManager::Initialize(DrmDevice* drm) { ...@@ -271,7 +223,7 @@ bool HardwareDisplayPlaneManager::Initialize(DrmDevice* drm) {
std::sort(planes_.begin(), planes_.end(), std::sort(planes_.begin(), planes_.end(),
[](const std::unique_ptr<HardwareDisplayPlane>& l, [](const std::unique_ptr<HardwareDisplayPlane>& l,
const std::unique_ptr<HardwareDisplayPlane>& r) { const std::unique_ptr<HardwareDisplayPlane>& r) {
return l->plane_id() < r->plane_id(); return l->id() < r->id();
}); });
PopulateSupportedFormats(); PopulateSupportedFormats();
...@@ -279,10 +231,8 @@ bool HardwareDisplayPlaneManager::Initialize(DrmDevice* drm) { ...@@ -279,10 +231,8 @@ bool HardwareDisplayPlaneManager::Initialize(DrmDevice* drm) {
} }
std::unique_ptr<HardwareDisplayPlane> HardwareDisplayPlaneManager::CreatePlane( std::unique_ptr<HardwareDisplayPlane> HardwareDisplayPlaneManager::CreatePlane(
uint32_t plane_id, uint32_t id) {
uint32_t possible_crtcs) { return std::make_unique<HardwareDisplayPlane>(id);
return std::unique_ptr<HardwareDisplayPlane>(
new HardwareDisplayPlane(plane_id, possible_crtcs));
} }
HardwareDisplayPlane* HardwareDisplayPlaneManager::FindNextUnusedPlane( HardwareDisplayPlane* HardwareDisplayPlaneManager::FindNextUnusedPlane(
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include "ui/display/types/gamma_ramp_rgb_entry.h" #include "ui/display/types/gamma_ramp_rgb_entry.h"
#include "ui/ozone/platform/drm/common/scoped_drm_types.h" #include "ui/ozone/platform/drm/common/scoped_drm_types.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h" #include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_plane.h"
#include "ui/ozone/platform/drm/gpu/overlay_plane.h" #include "ui/ozone/platform/drm/gpu/overlay_plane.h"
namespace gfx { namespace gfx {
...@@ -24,6 +23,7 @@ class Rect; ...@@ -24,6 +23,7 @@ class Rect;
namespace ui { namespace ui {
class CrtcController; class CrtcController;
class HardwareDisplayPlane;
// This contains the list of planes controlled by one HDC on a given DRM fd. // This contains the list of planes controlled by one HDC on a given DRM fd.
// It is owned by the HDC and filled by the CrtcController. // It is owned by the HDC and filled by the CrtcController.
...@@ -150,9 +150,7 @@ class HardwareDisplayPlaneManager { ...@@ -150,9 +150,7 @@ class HardwareDisplayPlaneManager {
const gfx::Rect& src_rect, const gfx::Rect& src_rect,
CrtcController* crtc) = 0; CrtcController* crtc) = 0;
virtual std::unique_ptr<HardwareDisplayPlane> CreatePlane( virtual std::unique_ptr<HardwareDisplayPlane> CreatePlane(uint32_t plane_id);
uint32_t plane_id,
uint32_t possible_crtcs);
// Finds the plane located at or after |*index| that is not in use and can // Finds the plane located at or after |*index| that is not in use and can
// be used with |crtc_index|. // be used with |crtc_index|.
......
...@@ -219,10 +219,8 @@ bool HardwareDisplayPlaneManagerAtomic::SetPlaneData( ...@@ -219,10 +219,8 @@ bool HardwareDisplayPlaneManagerAtomic::SetPlaneData(
} }
std::unique_ptr<HardwareDisplayPlane> std::unique_ptr<HardwareDisplayPlane>
HardwareDisplayPlaneManagerAtomic::CreatePlane(uint32_t plane_id, HardwareDisplayPlaneManagerAtomic::CreatePlane(uint32_t plane_id) {
uint32_t possible_crtcs) { return std::make_unique<HardwareDisplayPlaneAtomic>(plane_id);
return std::unique_ptr<HardwareDisplayPlane>(
new HardwareDisplayPlaneAtomic(plane_id, possible_crtcs));
} }
} // namespace ui } // namespace ui
...@@ -39,9 +39,7 @@ class HardwareDisplayPlaneManagerAtomic : public HardwareDisplayPlaneManager { ...@@ -39,9 +39,7 @@ class HardwareDisplayPlaneManagerAtomic : public HardwareDisplayPlaneManager {
CrtcController* crtc) override; CrtcController* crtc) override;
private: private:
std::unique_ptr<HardwareDisplayPlane> CreatePlane( std::unique_ptr<HardwareDisplayPlane> CreatePlane(uint32_t plane_id) override;
uint32_t plane_id,
uint32_t possible_crtcs) override;
DISALLOW_COPY_AND_ASSIGN(HardwareDisplayPlaneManagerAtomic); DISALLOW_COPY_AND_ASSIGN(HardwareDisplayPlaneManagerAtomic);
}; };
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "ui/gfx/presentation_feedback.h" #include "ui/gfx/presentation_feedback.h"
#include "ui/ozone/platform/drm/gpu/crtc_controller.h" #include "ui/ozone/platform/drm/gpu/crtc_controller.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h" #include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_plane.h"
#include "ui/ozone/platform/drm/gpu/scanout_buffer.h" #include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
namespace ui { namespace ui {
...@@ -99,9 +100,9 @@ bool HardwareDisplayPlaneManagerLegacy::Commit( ...@@ -99,9 +100,9 @@ bool HardwareDisplayPlaneManagerLegacy::Commit(
if (!plane->in_use() && (plane->type() != HardwareDisplayPlane::kDummy)) { if (!plane->in_use() && (plane->type() != HardwareDisplayPlane::kDummy)) {
// This plane is being released, so we need to zero it. // This plane is being released, so we need to zero it.
if (!drm_->PageFlipOverlay(plane->owning_crtc(), 0, gfx::Rect(), if (!drm_->PageFlipOverlay(plane->owning_crtc(), 0, gfx::Rect(),
gfx::Rect(), plane->plane_id())) { gfx::Rect(), plane->id())) {
PLOG(ERROR) << "Cannot free overlay: crtc=" << plane->owning_crtc() PLOG(ERROR) << "Cannot free overlay: crtc=" << plane->owning_crtc()
<< " plane=" << plane->plane_id(); << " plane=" << plane->id();
ret = false; ret = false;
break; break;
} }
...@@ -174,7 +175,7 @@ bool HardwareDisplayPlaneManagerLegacy::SetPlaneData( ...@@ -174,7 +175,7 @@ bool HardwareDisplayPlaneManagerLegacy::SetPlaneData(
} else { } else {
plane_list->legacy_page_flips.back().planes.push_back( plane_list->legacy_page_flips.back().planes.push_back(
HardwareDisplayPlaneList::PageFlipInfo::Plane( HardwareDisplayPlaneList::PageFlipInfo::Plane(
hw_plane->plane_id(), overlay.buffer->GetOpaqueFramebufferId(), hw_plane->id(), overlay.buffer->GetOpaqueFramebufferId(),
overlay.display_bounds, src_rect)); overlay.display_bounds, src_rect));
} }
return true; return true;
......
...@@ -21,19 +21,14 @@ ...@@ -21,19 +21,14 @@
#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h" #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h" #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h"
#include "ui/ozone/platform/drm/gpu/mock_drm_device.h" #include "ui/ozone/platform/drm/gpu/mock_drm_device.h"
#include "ui/ozone/platform/drm/gpu/mock_hardware_display_plane_manager.h"
#include "ui/ozone/platform/drm/gpu/mock_scanout_buffer.h" #include "ui/ozone/platform/drm/gpu/mock_scanout_buffer.h"
namespace { namespace {
const ui::FakePlaneInfo kOnePlanePerCrtc[] = {{10, 1}, {20, 2}}; constexpr uint32_t kTypePropId = 200;
const ui::FakePlaneInfo kTwoPlanesPerCrtc[] = {{10, 1}, constexpr uint32_t kInFormatsPropId = 201;
{11, 1}, constexpr uint32_t kInFormatsBlobPropId = 300;
{20, 2},
{21, 2}};
const ui::FakePlaneInfo kOnePlanePerCrtcWithShared[] = {{10, 1},
{20, 2},
{50, 3}};
const uint32_t kDummyFormat = 0; const uint32_t kDummyFormat = 0;
const gfx::Size kDefaultBufferSize(2, 2); const gfx::Size kDefaultBufferSize(2, 2);
...@@ -41,129 +36,178 @@ class HardwareDisplayPlaneManagerTest : public testing::Test { ...@@ -41,129 +36,178 @@ class HardwareDisplayPlaneManagerTest : public testing::Test {
public: public:
HardwareDisplayPlaneManagerTest() {} HardwareDisplayPlaneManagerTest() {}
void InitializeDrmState(size_t crtc_count, size_t planes_per_crtc);
void SetUp() override; void SetUp() override;
protected: protected:
std::unique_ptr<ui::MockHardwareDisplayPlaneManager> plane_manager_;
ui::HardwareDisplayPlaneList state_; ui::HardwareDisplayPlaneList state_;
std::vector<uint32_t> default_crtcs_;
scoped_refptr<ui::ScanoutBuffer> fake_buffer_; scoped_refptr<ui::ScanoutBuffer> fake_buffer_;
scoped_refptr<ui::MockDrmDevice> fake_drm_; scoped_refptr<ui::MockDrmDevice> fake_drm_;
std::vector<ui::MockDrmDevice::CrtcProperties> crtc_properties_;
std::vector<ui::MockDrmDevice::PlaneProperties> plane_properties_;
std::map<uint32_t, std::string> property_names_;
private: private:
DISALLOW_COPY_AND_ASSIGN(HardwareDisplayPlaneManagerTest); DISALLOW_COPY_AND_ASSIGN(HardwareDisplayPlaneManagerTest);
}; };
void HardwareDisplayPlaneManagerTest::SetUp() { void HardwareDisplayPlaneManagerTest::SetUp() {
fake_buffer_ = new ui::MockScanoutBuffer(kDefaultBufferSize); fake_buffer_ = new ui::MockScanoutBuffer(kDefaultBufferSize);
default_crtcs_.push_back(100);
default_crtcs_.push_back(200);
fake_drm_ = new ui::MockDrmDevice(false, default_crtcs_, 2); fake_drm_ = new ui::MockDrmDevice(false);
plane_manager_.reset( fake_drm_->SetPropertyBlob(ui::MockDrmDevice::AllocateInFormatsBlob(
new ui::MockHardwareDisplayPlaneManager(fake_drm_.get())); kInFormatsBlobPropId, {DRM_FORMAT_XRGB8888}, {}));
}
void HardwareDisplayPlaneManagerTest::InitializeDrmState(
size_t crtc_count,
size_t planes_per_crtc) {
property_names_.insert({kTypePropId, "type"});
property_names_.insert({kInFormatsPropId, "IN_FORMATS"});
for (size_t i = 0; i < crtc_count; ++i) {
ui::MockDrmDevice::CrtcProperties crtc_prop;
crtc_prop.id = i + 1;
// Start ID at 1 cause 0 is an invalid ID.
crtc_properties_.emplace_back(std::move(crtc_prop));
for (size_t j = 0; j < planes_per_crtc; ++j) {
ui::MockDrmDevice::PlaneProperties plane_prop;
plane_prop.id = 100 + i * planes_per_crtc + j;
plane_prop.crtc_mask = 1 << i;
plane_prop.properties = {
{.id = kTypePropId,
.value = j == 0 ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY},
{.id = kInFormatsPropId, .value = kInFormatsBlobPropId},
};
plane_properties_.emplace_back(std::move(plane_prop));
}
}
} }
TEST_F(HardwareDisplayPlaneManagerTest, SinglePlaneAssignment) { TEST_F(HardwareDisplayPlaneManagerTest, SinglePlaneAssignment) {
ui::OverlayPlaneList assigns; ui::OverlayPlaneList assigns;
assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr)); assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr));
plane_manager_->InitForTest(kOnePlanePerCrtc, arraysize(kOnePlanePerCrtc),
default_crtcs_); InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/1);
EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns, fake_drm_->InitializeState(crtc_properties_, plane_properties_,
default_crtcs_[0], nullptr)); property_names_, /* use_atomic= */ false);
EXPECT_EQ(1, plane_manager_->plane_count());
EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
&state_, assigns, crtc_properties_[0].id, nullptr));
EXPECT_EQ(1u, state_.plane_list.size());
} }
TEST_F(HardwareDisplayPlaneManagerTest, BadCrtc) { TEST_F(HardwareDisplayPlaneManagerTest, BadCrtc) {
ui::OverlayPlaneList assigns; ui::OverlayPlaneList assigns;
assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr)); assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr));
plane_manager_->InitForTest(kOnePlanePerCrtc, arraysize(kOnePlanePerCrtc),
default_crtcs_); InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/1);
EXPECT_FALSE( fake_drm_->InitializeState(crtc_properties_, plane_properties_,
plane_manager_->AssignOverlayPlanes(&state_, assigns, 1, nullptr)); property_names_, /* use_atomic= */ false);
EXPECT_FALSE(fake_drm_->plane_manager()->AssignOverlayPlanes(&state_, assigns,
0, nullptr));
} }
TEST_F(HardwareDisplayPlaneManagerTest, MultiplePlaneAssignment) { TEST_F(HardwareDisplayPlaneManagerTest, MultiplePlaneAssignment) {
ui::OverlayPlaneList assigns; ui::OverlayPlaneList assigns;
assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr)); assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr));
assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr)); assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr));
plane_manager_->InitForTest(kTwoPlanesPerCrtc, arraysize(kTwoPlanesPerCrtc),
default_crtcs_); InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/2);
EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns, fake_drm_->InitializeState(crtc_properties_, plane_properties_,
default_crtcs_[0], nullptr)); property_names_, /* use_atomic= */ false);
EXPECT_EQ(2, plane_manager_->plane_count());
EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
&state_, assigns, crtc_properties_[0].id, nullptr));
EXPECT_EQ(2u, state_.plane_list.size());
} }
TEST_F(HardwareDisplayPlaneManagerTest, NotEnoughPlanes) { TEST_F(HardwareDisplayPlaneManagerTest, NotEnoughPlanes) {
ui::OverlayPlaneList assigns; ui::OverlayPlaneList assigns;
assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr)); assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr));
assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr)); assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr));
plane_manager_->InitForTest(kOnePlanePerCrtc, arraysize(kOnePlanePerCrtc),
default_crtcs_);
EXPECT_FALSE(plane_manager_->AssignOverlayPlanes(&state_, assigns, InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/1);
default_crtcs_[0], nullptr)); fake_drm_->InitializeState(crtc_properties_, plane_properties_,
property_names_, /* use_atomic= */ false);
EXPECT_FALSE(fake_drm_->plane_manager()->AssignOverlayPlanes(
&state_, assigns, crtc_properties_[0].id, nullptr));
} }
TEST_F(HardwareDisplayPlaneManagerTest, MultipleCrtcs) { TEST_F(HardwareDisplayPlaneManagerTest, MultipleCrtcs) {
ui::OverlayPlaneList assigns; ui::OverlayPlaneList assigns;
assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr)); assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr));
plane_manager_->InitForTest(kOnePlanePerCrtc, arraysize(kOnePlanePerCrtc),
default_crtcs_); InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/1);
fake_drm_->InitializeState(crtc_properties_, plane_properties_,
EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns, property_names_, /* use_atomic= */ false);
default_crtcs_[0], nullptr));
EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns, EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
default_crtcs_[1], nullptr)); &state_, assigns, crtc_properties_[0].id, nullptr));
EXPECT_EQ(2, plane_manager_->plane_count()); EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
&state_, assigns, crtc_properties_[1].id, nullptr));
EXPECT_EQ(2u, state_.plane_list.size());
} }
TEST_F(HardwareDisplayPlaneManagerTest, MultiplePlanesAndCrtcs) { TEST_F(HardwareDisplayPlaneManagerTest, MultiplePlanesAndCrtcs) {
ui::OverlayPlaneList assigns; ui::OverlayPlaneList assigns;
assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr)); assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr));
assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr)); assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr));
plane_manager_->InitForTest(kTwoPlanesPerCrtc, arraysize(kTwoPlanesPerCrtc),
default_crtcs_); InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/2);
EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns, fake_drm_->InitializeState(crtc_properties_, plane_properties_,
default_crtcs_[0], nullptr)); property_names_, /* use_atomic= */ false);
EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns,
default_crtcs_[1], nullptr)); EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
EXPECT_EQ(4, plane_manager_->plane_count()); &state_, assigns, crtc_properties_[0].id, nullptr));
EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
&state_, assigns, crtc_properties_[1].id, nullptr));
EXPECT_EQ(4u, state_.plane_list.size());
} }
TEST_F(HardwareDisplayPlaneManagerTest, MultipleFrames) { TEST_F(HardwareDisplayPlaneManagerTest, MultipleFrames) {
ui::OverlayPlaneList assigns; ui::OverlayPlaneList assigns;
assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr)); assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr));
plane_manager_->InitForTest(kTwoPlanesPerCrtc, arraysize(kTwoPlanesPerCrtc),
default_crtcs_);
EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns, InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/2);
default_crtcs_[0], nullptr)); fake_drm_->InitializeState(crtc_properties_, plane_properties_,
EXPECT_EQ(1, plane_manager_->plane_count()); property_names_, /* use_atomic= */ false);
EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
&state_, assigns, crtc_properties_[0].id, nullptr));
EXPECT_EQ(1u, state_.plane_list.size());
// Pretend we committed the frame. // Pretend we committed the frame.
state_.plane_list.swap(state_.old_plane_list); state_.plane_list.swap(state_.old_plane_list);
plane_manager_->BeginFrame(&state_); fake_drm_->plane_manager()->BeginFrame(&state_);
ui::HardwareDisplayPlane* old_plane = state_.old_plane_list[0]; ui::HardwareDisplayPlane* old_plane = state_.old_plane_list[0];
// The same plane should be used. // The same plane should be used.
EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns, EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
default_crtcs_[0], nullptr)); &state_, assigns, crtc_properties_[0].id, nullptr));
EXPECT_EQ(2, plane_manager_->plane_count()); EXPECT_EQ(1u, state_.plane_list.size());
EXPECT_EQ(state_.plane_list[0], old_plane); EXPECT_EQ(state_.plane_list[0], old_plane);
} }
TEST_F(HardwareDisplayPlaneManagerTest, MultipleFramesDifferentPlanes) { TEST_F(HardwareDisplayPlaneManagerTest, MultipleFramesDifferentPlanes) {
ui::OverlayPlaneList assigns; ui::OverlayPlaneList assigns;
assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr)); assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr));
plane_manager_->InitForTest(kTwoPlanesPerCrtc, arraysize(kTwoPlanesPerCrtc),
default_crtcs_);
EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns, InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/2);
default_crtcs_[0], nullptr)); fake_drm_->InitializeState(crtc_properties_, plane_properties_,
EXPECT_EQ(1, plane_manager_->plane_count()); property_names_, /* use_atomic= */ false);
EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
&state_, assigns, crtc_properties_[0].id, nullptr));
EXPECT_EQ(1u, state_.plane_list.size());
// The other plane should be used. // The other plane should be used.
EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns, EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
default_crtcs_[0], nullptr)); &state_, assigns, crtc_properties_[0].id, nullptr));
EXPECT_EQ(2, plane_manager_->plane_count()); EXPECT_EQ(2u, state_.plane_list.size());
EXPECT_NE(state_.plane_list[0], state_.plane_list[1]); EXPECT_NE(state_.plane_list[0], state_.plane_list[1]);
} }
...@@ -174,16 +218,25 @@ TEST_F(HardwareDisplayPlaneManagerTest, SharedPlanes) { ...@@ -174,16 +218,25 @@ TEST_F(HardwareDisplayPlaneManagerTest, SharedPlanes) {
assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr)); assigns.push_back(ui::OverlayPlane(fake_buffer_, nullptr));
assigns.push_back(ui::OverlayPlane(buffer, nullptr)); assigns.push_back(ui::OverlayPlane(buffer, nullptr));
plane_manager_->InitForTest(kOnePlanePerCrtcWithShared,
arraysize(kOnePlanePerCrtcWithShared),
default_crtcs_);
EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns, InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/1);
default_crtcs_[1], nullptr)); ui::MockDrmDevice::PlaneProperties plane_prop;
EXPECT_EQ(2, plane_manager_->plane_count()); plane_prop.id = 102;
plane_prop.crtc_mask = (1 << 0) | (1 << 1);
plane_prop.properties = {
{.id = kTypePropId, .value = DRM_PLANE_TYPE_OVERLAY},
{.id = kInFormatsPropId, .value = kInFormatsBlobPropId},
};
plane_properties_.emplace_back(std::move(plane_prop));
fake_drm_->InitializeState(crtc_properties_, plane_properties_,
property_names_, /* use_atomic= */ false);
EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
&state_, assigns, crtc_properties_[1].id, nullptr));
EXPECT_EQ(2u, state_.plane_list.size());
// The shared plane is now unavailable for use by the other CRTC. // The shared plane is now unavailable for use by the other CRTC.
EXPECT_FALSE(plane_manager_->AssignOverlayPlanes(&state_, assigns, EXPECT_FALSE(fake_drm_->plane_manager()->AssignOverlayPlanes(
default_crtcs_[0], nullptr)); &state_, assigns, crtc_properties_[0].id, nullptr));
} }
TEST_F(HardwareDisplayPlaneManagerTest, CheckFramebufferFormatMatch) { TEST_F(HardwareDisplayPlaneManagerTest, CheckFramebufferFormatMatch) {
...@@ -191,30 +244,33 @@ TEST_F(HardwareDisplayPlaneManagerTest, CheckFramebufferFormatMatch) { ...@@ -191,30 +244,33 @@ TEST_F(HardwareDisplayPlaneManagerTest, CheckFramebufferFormatMatch) {
scoped_refptr<ui::MockScanoutBuffer> buffer = scoped_refptr<ui::MockScanoutBuffer> buffer =
new ui::MockScanoutBuffer(kDefaultBufferSize, kDummyFormat); new ui::MockScanoutBuffer(kDefaultBufferSize, kDummyFormat);
assigns.push_back(ui::OverlayPlane(buffer, nullptr)); assigns.push_back(ui::OverlayPlane(buffer, nullptr));
plane_manager_->InitForTest(kOnePlanePerCrtc, arraysize(kOnePlanePerCrtc),
default_crtcs_); InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/1);
plane_manager_->BeginFrame(&state_); fake_drm_->InitializeState(crtc_properties_, plane_properties_,
property_names_, /* use_atomic= */ false);
fake_drm_->plane_manager()->BeginFrame(&state_);
// This should return false as plane manager creates planes which support // This should return false as plane manager creates planes which support
// DRM_FORMAT_XRGB8888 while buffer returns kDummyFormat as its pixelFormat. // DRM_FORMAT_XRGB8888 while buffer returns kDummyFormat as its pixelFormat.
EXPECT_FALSE(plane_manager_->AssignOverlayPlanes(&state_, assigns, EXPECT_FALSE(fake_drm_->plane_manager()->AssignOverlayPlanes(
default_crtcs_[0], nullptr)); &state_, assigns, crtc_properties_[0].id, nullptr));
assigns.clear(); assigns.clear();
scoped_refptr<ui::MockScanoutBuffer> xrgb_buffer = scoped_refptr<ui::MockScanoutBuffer> xrgb_buffer =
new ui::MockScanoutBuffer(kDefaultBufferSize); new ui::MockScanoutBuffer(kDefaultBufferSize);
assigns.push_back(ui::OverlayPlane(xrgb_buffer, nullptr)); assigns.push_back(ui::OverlayPlane(xrgb_buffer, nullptr));
plane_manager_->BeginFrame(&state_); fake_drm_->plane_manager()->BeginFrame(&state_);
EXPECT_TRUE(plane_manager_->AssignOverlayPlanes(&state_, assigns, EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
default_crtcs_[0], nullptr)); &state_, assigns, crtc_properties_[0].id, nullptr));
plane_manager_->BeginFrame(&state_); fake_drm_->plane_manager()->BeginFrame(&state_);
EXPECT_FALSE(plane_manager_->AssignOverlayPlanes(&state_, assigns, EXPECT_FALSE(fake_drm_->plane_manager()->AssignOverlayPlanes(
default_crtcs_[0], nullptr)); &state_, assigns, crtc_properties_[0].id, nullptr));
} }
TEST(HardwareDisplayPlaneManagerLegacyTest, UnusedPlanesAreReleased) { TEST_F(HardwareDisplayPlaneManagerTest, UnusedPlanesAreReleased) {
std::vector<uint32_t> crtcs; InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/2);
crtcs.push_back(100); fake_drm_->InitializeState(crtc_properties_, plane_properties_,
property_names_, /* use_atomic= */ false);
scoped_refptr<ui::MockDrmDevice> drm = new ui::MockDrmDevice(false, crtcs, 2);
ui::OverlayPlaneList assigns; ui::OverlayPlaneList assigns;
scoped_refptr<ui::MockScanoutBuffer> primary_buffer = scoped_refptr<ui::MockScanoutBuffer> primary_buffer =
new ui::MockScanoutBuffer(kDefaultBufferSize); new ui::MockScanoutBuffer(kDefaultBufferSize);
...@@ -223,19 +279,19 @@ TEST(HardwareDisplayPlaneManagerLegacyTest, UnusedPlanesAreReleased) { ...@@ -223,19 +279,19 @@ TEST(HardwareDisplayPlaneManagerLegacyTest, UnusedPlanesAreReleased) {
assigns.push_back(ui::OverlayPlane(primary_buffer, nullptr)); assigns.push_back(ui::OverlayPlane(primary_buffer, nullptr));
assigns.push_back(ui::OverlayPlane(overlay_buffer, nullptr)); assigns.push_back(ui::OverlayPlane(overlay_buffer, nullptr));
ui::HardwareDisplayPlaneList hdpl; ui::HardwareDisplayPlaneList hdpl;
ui::CrtcController crtc(drm, crtcs[0], 0); ui::CrtcController crtc(fake_drm_, crtc_properties_[0].id, 0);
drm->plane_manager()->BeginFrame(&hdpl); fake_drm_->plane_manager()->BeginFrame(&hdpl);
EXPECT_TRUE(drm->plane_manager()->AssignOverlayPlanes(&hdpl, assigns, EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
crtcs[0], &crtc)); &hdpl, assigns, crtc_properties_[0].id, &crtc));
EXPECT_TRUE(drm->plane_manager()->Commit(&hdpl, false)); EXPECT_TRUE(fake_drm_->plane_manager()->Commit(&hdpl, false));
assigns.clear(); assigns.clear();
assigns.push_back(ui::OverlayPlane(primary_buffer, nullptr)); assigns.push_back(ui::OverlayPlane(primary_buffer, nullptr));
drm->plane_manager()->BeginFrame(&hdpl); fake_drm_->plane_manager()->BeginFrame(&hdpl);
EXPECT_TRUE(drm->plane_manager()->AssignOverlayPlanes(&hdpl, assigns, EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
crtcs[0], &crtc)); &hdpl, assigns, crtc_properties_[0].id, &crtc));
EXPECT_EQ(0, drm->get_overlay_clear_call_count()); EXPECT_EQ(0, fake_drm_->get_overlay_clear_call_count());
EXPECT_TRUE(drm->plane_manager()->Commit(&hdpl, false)); EXPECT_TRUE(fake_drm_->plane_manager()->Commit(&hdpl, false));
EXPECT_EQ(1, drm->get_overlay_clear_call_count()); EXPECT_EQ(1, fake_drm_->get_overlay_clear_call_count());
} }
class FakeFenceFD { class FakeFenceFD {
...@@ -371,7 +427,7 @@ TEST_F(HardwareDisplayPlaneManagerPlanesReadyTest, ...@@ -371,7 +427,7 @@ TEST_F(HardwareDisplayPlaneManagerPlanesReadyTest,
class HardwareDisplayPlaneAtomicMock : public ui::HardwareDisplayPlaneAtomic { class HardwareDisplayPlaneAtomicMock : public ui::HardwareDisplayPlaneAtomic {
public: public:
HardwareDisplayPlaneAtomicMock() : ui::HardwareDisplayPlaneAtomic(0, ~0) {} HardwareDisplayPlaneAtomicMock() : ui::HardwareDisplayPlaneAtomic(1) {}
~HardwareDisplayPlaneAtomicMock() override {} ~HardwareDisplayPlaneAtomicMock() override {}
bool SetPlaneData(drmModeAtomicReq* property_set, bool SetPlaneData(drmModeAtomicReq* property_set,
......
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
#include "base/logging.h" #include "base/logging.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkCanvas.h"
#include "ui/ozone/platform/drm/gpu/mock_hardware_display_plane_manager.h" #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h"
namespace ui { namespace ui {
...@@ -20,9 +21,35 @@ Object* DrmAllocator() { ...@@ -20,9 +21,35 @@ Object* DrmAllocator() {
return static_cast<Object*>(drmMalloc(sizeof(Object))); return static_cast<Object*>(drmMalloc(sizeof(Object)));
} }
ScopedDrmObjectPropertyPtr CreatePropertyObject(
const std::vector<DrmDevice::Property>& properties) {
ScopedDrmObjectPropertyPtr drm_properties(
DrmAllocator<drmModeObjectProperties>());
drm_properties->count_props = properties.size();
drm_properties->props = static_cast<uint32_t*>(
drmMalloc(sizeof(uint32_t) * drm_properties->count_props));
drm_properties->prop_values = static_cast<uint64_t*>(
drmMalloc(sizeof(uint64_t) * drm_properties->count_props));
for (size_t i = 0; i < properties.size(); ++i) {
drm_properties->props[i] = properties[i].id;
drm_properties->prop_values[i] = properties[i].value;
}
return drm_properties;
}
} // namespace } // namespace
MockDrmDevice::MockDrmDevice() MockDrmDevice::CrtcProperties::CrtcProperties() = default;
MockDrmDevice::CrtcProperties::CrtcProperties(const CrtcProperties&) = default;
MockDrmDevice::CrtcProperties::~CrtcProperties() = default;
MockDrmDevice::PlaneProperties::PlaneProperties() = default;
MockDrmDevice::PlaneProperties::PlaneProperties(const PlaneProperties&) =
default;
MockDrmDevice::PlaneProperties::~PlaneProperties() = default;
MockDrmDevice::MockDrmDevice(bool use_sync_flips)
: DrmDevice(base::FilePath(), base::File(), true /* is_primary_device */), : DrmDevice(base::FilePath(), base::File(), true /* is_primary_device */),
get_crtc_call_count_(0), get_crtc_call_count_(0),
set_crtc_call_count_(0), set_crtc_call_count_(0),
...@@ -37,44 +64,102 @@ MockDrmDevice::MockDrmDevice() ...@@ -37,44 +64,102 @@ MockDrmDevice::MockDrmDevice()
add_framebuffer_expectation_(true), add_framebuffer_expectation_(true),
page_flip_expectation_(true), page_flip_expectation_(true),
create_dumb_buffer_expectation_(true), create_dumb_buffer_expectation_(true),
use_sync_flips_(false), use_sync_flips_(use_sync_flips),
current_framebuffer_(0) { current_framebuffer_(0) {
plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy()); plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy());
} }
MockDrmDevice::MockDrmDevice(bool use_sync_flips, // static
std::vector<uint32_t> crtcs, ScopedDrmPropertyBlobPtr MockDrmDevice::AllocateInFormatsBlob(
size_t planes_per_crtc) uint32_t id,
: DrmDevice(base::FilePath(), base::File(), true /* is_primary_device */), const std::vector<uint32_t>& supported_formats,
get_crtc_call_count_(0), const std::vector<drm_format_modifier>& supported_format_modifiers) {
set_crtc_call_count_(0), drm_format_modifier_blob header;
restore_crtc_call_count_(0), header.count_formats = supported_formats.size();
add_framebuffer_call_count_(0), header.formats_offset = sizeof(header);
remove_framebuffer_call_count_(0), header.count_modifiers = supported_format_modifiers.size();
page_flip_call_count_(0), header.modifiers_offset =
overlay_flip_call_count_(0), header.formats_offset + sizeof(uint32_t) * header.count_formats;
overlay_clear_call_count_(0),
allocate_buffer_count_(0), ScopedDrmPropertyBlobPtr blob(DrmAllocator<drmModePropertyBlobRes>());
set_crtc_expectation_(true), blob->id = id;
add_framebuffer_expectation_(true), blob->length = header.modifiers_offset +
page_flip_expectation_(true), sizeof(drm_format_modifier) * header.count_modifiers;
create_dumb_buffer_expectation_(true), blob->data = drmMalloc(blob->length);
use_sync_flips_(use_sync_flips),
current_framebuffer_(0) { memcpy(blob->data, &header, sizeof(header));
plane_manager_.reset( memcpy(static_cast<uint8_t*>(blob->data) + header.formats_offset,
new MockHardwareDisplayPlaneManager(this, crtcs, planes_per_crtc)); supported_formats.data(), sizeof(uint32_t) * header.count_formats);
memcpy(static_cast<uint8_t*>(blob->data) + header.modifiers_offset,
supported_format_modifiers.data(),
sizeof(drm_format_modifier) * header.count_modifiers);
return blob;
}
void MockDrmDevice::InitializeState(
const std::vector<CrtcProperties>& crtc_properties,
const std::vector<PlaneProperties>& plane_properties,
const std::map<uint32_t, std::string>& property_names,
bool use_atomic) {
crtc_properties_ = crtc_properties;
plane_properties_ = plane_properties;
property_names_ = property_names;
if (use_atomic) {
plane_manager_.reset(new HardwareDisplayPlaneManagerAtomic());
} else {
plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy());
}
CHECK(plane_manager_->Initialize(this));
} }
MockDrmDevice::~MockDrmDevice() {} MockDrmDevice::~MockDrmDevice() {}
ScopedDrmResourcesPtr MockDrmDevice::GetResources() { ScopedDrmResourcesPtr MockDrmDevice::GetResources() {
return ScopedDrmResourcesPtr(DrmAllocator<drmModeRes>()); ScopedDrmResourcesPtr resources(DrmAllocator<drmModeRes>());
resources->count_crtcs = crtc_properties_.size();
resources->crtcs = static_cast<uint32_t*>(
drmMalloc(sizeof(uint32_t) * resources->count_crtcs));
for (size_t i = 0; i < crtc_properties_.size(); ++i)
resources->crtcs[i] = crtc_properties_[i].id;
return resources;
}
ScopedDrmPlaneResPtr MockDrmDevice::GetPlaneResources() {
ScopedDrmPlaneResPtr resources(DrmAllocator<drmModePlaneRes>());
resources->count_planes = plane_properties_.size();
resources->planes = static_cast<uint32_t*>(
drmMalloc(sizeof(uint32_t) * resources->count_planes));
for (size_t i = 0; i < plane_properties_.size(); ++i)
resources->planes[i] = plane_properties_[i].id;
return resources;
} }
ScopedDrmObjectPropertyPtr MockDrmDevice::GetObjectProperties( ScopedDrmObjectPropertyPtr MockDrmDevice::GetObjectProperties(
uint32_t object_id, uint32_t object_id,
uint32_t object_type) { uint32_t object_type) {
return ScopedDrmObjectPropertyPtr(DrmAllocator<drmModeObjectProperties>()); if (object_type == DRM_MODE_OBJECT_PLANE) {
auto it = std::find_if(
plane_properties_.begin(), plane_properties_.end(),
[object_id](const PlaneProperties& p) { return p.id == object_id; });
if (it == plane_properties_.end())
return nullptr;
return CreatePropertyObject(it->properties);
} else if (object_type == DRM_MODE_OBJECT_CRTC) {
auto it = std::find_if(
crtc_properties_.begin(), crtc_properties_.end(),
[object_id](const CrtcProperties& p) { return p.id == object_id; });
if (it == crtc_properties_.end())
return nullptr;
return CreatePropertyObject(it->properties);
}
return nullptr;
} }
ScopedDrmCrtcPtr MockDrmDevice::GetCrtc(uint32_t crtc_id) { ScopedDrmCrtcPtr MockDrmDevice::GetCrtc(uint32_t crtc_id) {
...@@ -155,13 +240,33 @@ bool MockDrmDevice::PageFlipOverlay(uint32_t crtc_id, ...@@ -155,13 +240,33 @@ bool MockDrmDevice::PageFlipOverlay(uint32_t crtc_id,
return true; return true;
} }
ScopedDrmPlanePtr MockDrmDevice::GetPlane(uint32_t plane_id) {
auto it = std::find_if(plane_properties_.begin(), plane_properties_.end(),
[plane_id](const PlaneProperties& plane) {
return plane.id == plane_id;
});
if (it == plane_properties_.end())
return nullptr;
ScopedDrmPlanePtr plane(DrmAllocator<drmModePlane>());
plane->possible_crtcs = it->crtc_mask;
return plane;
}
ScopedDrmPropertyPtr MockDrmDevice::GetProperty(drmModeConnector* connector, ScopedDrmPropertyPtr MockDrmDevice::GetProperty(drmModeConnector* connector,
const char* name) { const char* name) {
return ScopedDrmPropertyPtr(DrmAllocator<drmModePropertyRes>()); return ScopedDrmPropertyPtr(DrmAllocator<drmModePropertyRes>());
} }
ScopedDrmPropertyPtr MockDrmDevice::GetProperty(uint32_t id) { ScopedDrmPropertyPtr MockDrmDevice::GetProperty(uint32_t id) {
return ScopedDrmPropertyPtr(DrmAllocator<drmModePropertyRes>()); auto it = property_names_.find(id);
if (it == property_names_.end())
return nullptr;
ScopedDrmPropertyPtr property(DrmAllocator<drmModePropertyRes>());
property->prop_id = id;
strcpy(property->name, it->second.c_str());
return property;
} }
bool MockDrmDevice::SetProperty(uint32_t connector_id, bool MockDrmDevice::SetProperty(uint32_t connector_id,
...@@ -174,6 +279,20 @@ bool MockDrmDevice::GetCapability(uint64_t capability, uint64_t* value) { ...@@ -174,6 +279,20 @@ bool MockDrmDevice::GetCapability(uint64_t capability, uint64_t* value) {
return true; return true;
} }
ScopedDrmPropertyBlobPtr MockDrmDevice::GetPropertyBlob(uint32_t property_id) {
auto it = blob_property_map_.find(property_id);
if (it == blob_property_map_.end())
return nullptr;
ScopedDrmPropertyBlobPtr blob(DrmAllocator<drmModePropertyBlobRes>());
blob->id = property_id;
blob->length = it->second->length;
blob->data = drmMalloc(blob->length);
memcpy(blob->data, it->second->data, blob->length);
return blob;
}
ScopedDrmPropertyBlobPtr MockDrmDevice::GetPropertyBlob( ScopedDrmPropertyBlobPtr MockDrmDevice::GetPropertyBlob(
drmModeConnector* connector, drmModeConnector* connector,
const char* name) { const char* name) {
...@@ -236,7 +355,11 @@ bool MockDrmDevice::CommitProperties(drmModeAtomicReq* properties, ...@@ -236,7 +355,11 @@ bool MockDrmDevice::CommitProperties(drmModeAtomicReq* properties,
uint32_t flags, uint32_t flags,
uint32_t crtc_count, uint32_t crtc_count,
PageFlipCallback callback) { PageFlipCallback callback) {
return false; if (use_sync_flips_)
std::move(callback).Run(0, base::TimeTicks());
else
callbacks_.push(std::move(callback));
return true;
} }
bool MockDrmDevice::SetGammaRamp( bool MockDrmDevice::SetGammaRamp(
...@@ -246,7 +369,7 @@ bool MockDrmDevice::SetGammaRamp( ...@@ -246,7 +369,7 @@ bool MockDrmDevice::SetGammaRamp(
} }
bool MockDrmDevice::SetCapability(uint64_t capability, uint64_t value) { bool MockDrmDevice::SetCapability(uint64_t capability, uint64_t value) {
return false; return true;
} }
void MockDrmDevice::RunCallbacks() { void MockDrmDevice::RunCallbacks() {
...@@ -257,4 +380,8 @@ void MockDrmDevice::RunCallbacks() { ...@@ -257,4 +380,8 @@ void MockDrmDevice::RunCallbacks() {
} }
} }
void MockDrmDevice::SetPropertyBlob(ScopedDrmPropertyBlobPtr blob) {
blob_property_map_[blob->id] = std::move(blob);
}
} // namespace ui } // namespace ui
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef UI_OZONE_PLATFORM_DRM_GPU_MOCK_DRM_DEVICE_H_ #ifndef UI_OZONE_PLATFORM_DRM_GPU_MOCK_DRM_DEVICE_H_
#define UI_OZONE_PLATFORM_DRM_GPU_MOCK_DRM_DEVICE_H_ #define UI_OZONE_PLATFORM_DRM_GPU_MOCK_DRM_DEVICE_H_
#include <drm_mode.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
...@@ -22,10 +23,32 @@ namespace ui { ...@@ -22,10 +23,32 @@ namespace ui {
// The real DrmDevice makes actual DRM calls which we can't use in unit tests. // The real DrmDevice makes actual DRM calls which we can't use in unit tests.
class MockDrmDevice : public DrmDevice { class MockDrmDevice : public DrmDevice {
public: public:
MockDrmDevice(); struct CrtcProperties {
MockDrmDevice(bool use_sync_flips, CrtcProperties();
std::vector<uint32_t> crtcs, CrtcProperties(const CrtcProperties&);
size_t planes_per_crtc); ~CrtcProperties();
uint32_t id;
std::vector<DrmDevice::Property> properties;
};
struct PlaneProperties {
PlaneProperties();
PlaneProperties(const PlaneProperties&);
~PlaneProperties();
uint32_t id;
uint32_t crtc_mask;
std::vector<DrmDevice::Property> properties;
};
explicit MockDrmDevice(bool use_sync_flips);
static ScopedDrmPropertyBlobPtr AllocateInFormatsBlob(
uint32_t id,
const std::vector<uint32_t>& supported_formats,
const std::vector<drm_format_modifier>& supported_format_modifiers);
int get_get_crtc_call_count() const { return get_crtc_call_count_; } int get_get_crtc_call_count() const { return get_crtc_call_count_; }
int get_set_crtc_call_count() const { return set_crtc_call_count_; } int get_set_crtc_call_count() const { return set_crtc_call_count_; }
...@@ -57,10 +80,18 @@ class MockDrmDevice : public DrmDevice { ...@@ -57,10 +80,18 @@ class MockDrmDevice : public DrmDevice {
return it != crtc_cursor_map_.end() ? it->second : 0; return it != crtc_cursor_map_.end() ? it->second : 0;
} }
void InitializeState(const std::vector<CrtcProperties>& crtc_properties,
const std::vector<PlaneProperties>& plane_properties,
const std::map<uint32_t, std::string>& property_names,
bool use_atomic);
void RunCallbacks(); void RunCallbacks();
void SetPropertyBlob(ScopedDrmPropertyBlobPtr blob);
// DrmDevice: // DrmDevice:
ScopedDrmResourcesPtr GetResources() override; ScopedDrmResourcesPtr GetResources() override;
ScopedDrmPlaneResPtr GetPlaneResources() override;
ScopedDrmObjectPropertyPtr GetObjectProperties(uint32_t object_id, ScopedDrmObjectPropertyPtr GetObjectProperties(uint32_t object_id,
uint32_t object_type) override; uint32_t object_type) override;
ScopedDrmCrtcPtr GetCrtc(uint32_t crtc_id) override; ScopedDrmCrtcPtr GetCrtc(uint32_t crtc_id) override;
...@@ -90,6 +121,7 @@ class MockDrmDevice : public DrmDevice { ...@@ -90,6 +121,7 @@ class MockDrmDevice : public DrmDevice {
const gfx::Rect& location, const gfx::Rect& location,
const gfx::Rect& source, const gfx::Rect& source,
int overlay_plane) override; int overlay_plane) override;
ScopedDrmPlanePtr GetPlane(uint32_t plane_id) override;
ScopedDrmPropertyPtr GetProperty(drmModeConnector* connector, ScopedDrmPropertyPtr GetProperty(drmModeConnector* connector,
const char* name) override; const char* name) override;
ScopedDrmPropertyPtr GetProperty(uint32_t id) override; ScopedDrmPropertyPtr GetProperty(uint32_t id) override;
...@@ -97,6 +129,7 @@ class MockDrmDevice : public DrmDevice { ...@@ -97,6 +129,7 @@ class MockDrmDevice : public DrmDevice {
uint32_t property_id, uint32_t property_id,
uint64_t value) override; uint64_t value) override;
bool GetCapability(uint64_t capability, uint64_t* value) override; bool GetCapability(uint64_t capability, uint64_t* value) override;
ScopedDrmPropertyBlobPtr GetPropertyBlob(uint32_t property_id) override;
ScopedDrmPropertyBlobPtr GetPropertyBlob(drmModeConnector* connector, ScopedDrmPropertyBlobPtr GetPropertyBlob(drmModeConnector* connector,
const char* name) override; const char* name) override;
bool SetCursor(uint32_t crtc_id, bool SetCursor(uint32_t crtc_id,
...@@ -145,8 +178,16 @@ class MockDrmDevice : public DrmDevice { ...@@ -145,8 +178,16 @@ class MockDrmDevice : public DrmDevice {
std::map<uint32_t, uint32_t> crtc_cursor_map_; std::map<uint32_t, uint32_t> crtc_cursor_map_;
std::map<uint32_t, ScopedDrmPropertyBlobPtr> blob_property_map_;
base::queue<PageFlipCallback> callbacks_; base::queue<PageFlipCallback> callbacks_;
std::vector<CrtcProperties> crtc_properties_;
std::vector<PlaneProperties> plane_properties_;
std::map<uint32_t, std::string> property_names_;
DISALLOW_COPY_AND_ASSIGN(MockDrmDevice); DISALLOW_COPY_AND_ASSIGN(MockDrmDevice);
}; };
......
// Copyright 2015 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/mock_hardware_display_plane_manager.h"
#include <drm_fourcc.h>
#include <utility>
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/ozone/platform/drm/gpu/fake_plane_info.h"
#include "ui/ozone/platform/drm/gpu/mock_scanout_buffer.h"
namespace ui {
MockHardwareDisplayPlaneManager::MockHardwareDisplayPlaneManager(
DrmDevice* drm,
const std::vector<uint32_t>& crtcs,
uint32_t planes_per_crtc) {
const int kPlaneBaseId = 50;
const struct drm_format_modifier linear_modifier { 0x1, DRM_FORMAT_MOD_NONE };
drm_ = drm;
for (size_t i = 0; i < crtcs.size(); ++i)
crtc_properties_.push_back({.id = crtcs[i]});
for (size_t crtc_idx = 0; crtc_idx < crtc_properties_.size(); crtc_idx++) {
for (size_t i = 0; i < planes_per_crtc; i++) {
std::unique_ptr<HardwareDisplayPlane> plane(
new HardwareDisplayPlane(kPlaneBaseId + i, 1 << crtc_idx));
plane->Initialize(drm, std::vector<uint32_t>(1, DRM_FORMAT_XRGB8888),
std::vector<drm_format_modifier>(1, linear_modifier),
false, true);
plane->set_type(i ? HardwareDisplayPlane::kOverlay
: HardwareDisplayPlane::kPrimary);
planes_.push_back(std::move(plane));
}
}
// The real HDPM uses sorted planes, so sort them for consistency.
std::sort(planes_.begin(), planes_.end(),
[](const std::unique_ptr<HardwareDisplayPlane>& l,
const std::unique_ptr<HardwareDisplayPlane>& r) {
return l->plane_id() < r->plane_id();
});
}
MockHardwareDisplayPlaneManager::MockHardwareDisplayPlaneManager(
DrmDevice* drm) {
drm_ = drm;
}
MockHardwareDisplayPlaneManager::~MockHardwareDisplayPlaneManager() {}
void MockHardwareDisplayPlaneManager::InitForTest(
const FakePlaneInfo* planes,
size_t count,
const std::vector<uint32_t>& crtcs) {
crtc_properties_.clear();
for (size_t i = 0; i < crtcs.size(); ++i)
crtc_properties_.push_back({.id = crtcs[i]});
planes_.clear();
for (size_t i = 0; i < count; i++) {
std::unique_ptr<HardwareDisplayPlane> plane(
new HardwareDisplayPlane(planes[i].id, planes[i].allowed_crtc_mask));
plane->Initialize(drm_, planes[i].allowed_formats,
std::vector<drm_format_modifier>(), // modifiers
false, true);
planes_.push_back(std::move(plane));
}
// The real HDPM uses sorted planes, so sort them for consistency.
std::sort(planes_.begin(), planes_.end(),
[](const std::unique_ptr<HardwareDisplayPlane>& l,
const std::unique_ptr<HardwareDisplayPlane>& r) {
return l->plane_id() < r->plane_id();
});
}
void MockHardwareDisplayPlaneManager::SetPlaneProperties(
const std::vector<FakePlaneInfo>& planes) {
planes_.clear();
uint32_t count = planes.size();
for (size_t i = 0; i < count; i++) {
std::unique_ptr<HardwareDisplayPlane> plane(
new HardwareDisplayPlane(planes[i].id, planes[i].allowed_crtc_mask));
plane->Initialize(drm_, planes[i].allowed_formats,
std::vector<drm_format_modifier>(), // modifiers
false, true);
planes_.push_back(std::move(plane));
}
// The real HDPM uses sorted planes, so sort them for consistency.
std::sort(planes_.begin(), planes_.end(),
[](const std::unique_ptr<HardwareDisplayPlane>& l,
const std::unique_ptr<HardwareDisplayPlane>& r) {
return l->plane_id() < r->plane_id();
});
ResetPlaneCount();
}
void MockHardwareDisplayPlaneManager::SetCrtcInfo(
const std::vector<uint32_t>& crtcs) {
crtc_properties_.clear();
for (size_t i = 0; i < crtcs.size(); ++i)
crtc_properties_.push_back({.id = crtcs[i]});
planes_.clear();
ResetPlaneCount();
}
bool MockHardwareDisplayPlaneManager::DisableOverlayPlanes(
HardwareDisplayPlaneList* plane_list) {
for (HardwareDisplayPlane* plane : plane_list->old_plane_list) {
if (plane->type() != HardwareDisplayPlane::kOverlay)
continue;
plane->set_in_use(false);
plane->set_owning_crtc(0);
}
return true;
}
bool MockHardwareDisplayPlaneManager::SetPlaneData(
HardwareDisplayPlaneList* plane_list,
HardwareDisplayPlane* hw_plane,
const OverlayPlane& overlay,
uint32_t crtc_id,
const gfx::Rect& src_rect,
CrtcController* crtc) {
// Check that the chosen plane is a legal choice for the crtc.
EXPECT_NE(-1, LookupCrtcIndex(crtc_id));
EXPECT_TRUE(hw_plane->CanUseForCrtc(LookupCrtcIndex(crtc_id)));
EXPECT_FALSE(hw_plane->in_use());
plane_count_++;
return HardwareDisplayPlaneManagerLegacy::SetPlaneData(
plane_list, hw_plane, overlay, crtc_id, src_rect, crtc);
}
int MockHardwareDisplayPlaneManager::plane_count() const {
return plane_count_;
}
void MockHardwareDisplayPlaneManager::ResetPlaneCount() {
plane_count_ = 0;
}
} // namespace ui
// Copyright 2015 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.
#ifndef UI_OZONE_PLATFORM_DRM_GPU_MOCK_HARDWARE_DISPLAY_PLANE_MANAGER_H_
#define UI_OZONE_PLATFORM_DRM_GPU_MOCK_HARDWARE_DISPLAY_PLANE_MANAGER_H_
#include <stddef.h>
#include <stdint.h>
#include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h"
namespace ui {
struct FakePlaneInfo;
class MockHardwareDisplayPlaneManager
: public HardwareDisplayPlaneManagerLegacy {
public:
MockHardwareDisplayPlaneManager(DrmDevice* drm,
const std::vector<uint32_t>& crtcs,
uint32_t planes_per_crtc);
explicit MockHardwareDisplayPlaneManager(DrmDevice* drm);
~MockHardwareDisplayPlaneManager() override;
// Normally we'd use DRM to figure out the controller configuration. But we
// can't use DRM in unit tests, so we just create a fake configuration.
void InitForTest(const FakePlaneInfo* planes,
size_t count,
const std::vector<uint32_t>& crtcs);
void SetPlaneProperties(const std::vector<FakePlaneInfo>& planes);
void SetCrtcInfo(const std::vector<uint32_t>& crtcs);
bool DisableOverlayPlanes(HardwareDisplayPlaneList* plane_list) override;
bool SetPlaneData(HardwareDisplayPlaneList* plane_list,
HardwareDisplayPlane* hw_plane,
const OverlayPlane& overlay,
uint32_t crtc_id,
const gfx::Rect& src_rect,
CrtcController* crtc) override;
int plane_count() const;
void ResetPlaneCount();
private:
int plane_count_ = 0;
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_DRM_GPU_MOCK_HARDWARE_DISPLAY_PLANE_MANAGER_H_
...@@ -49,8 +49,7 @@ class ScreenManagerTest : public testing::Test { ...@@ -49,8 +49,7 @@ class ScreenManagerTest : public testing::Test {
} }
void SetUp() override { void SetUp() override {
drm_ = new ui::MockDrmDevice(false, std::vector<uint32_t>(1, kPrimaryCrtc), drm_ = new ui::MockDrmDevice(false);
4 /* planes per crtc */);
device_manager_.reset(new ui::DrmDeviceManager(nullptr)); device_manager_.reset(new ui::DrmDeviceManager(nullptr));
buffer_generator_.reset(new ui::MockScanoutBufferGenerator()); buffer_generator_.reset(new ui::MockScanoutBufferGenerator());
screen_manager_.reset(new ui::ScreenManager(buffer_generator_.get())); screen_manager_.reset(new ui::ScreenManager(buffer_generator_.get()));
...@@ -354,7 +353,7 @@ TEST_F(ScreenManagerTest, CheckMirrorModeAfterBeginReEnabled) { ...@@ -354,7 +353,7 @@ TEST_F(ScreenManagerTest, CheckMirrorModeAfterBeginReEnabled) {
TEST_F(ScreenManagerTest, TEST_F(ScreenManagerTest,
CheckProperConfigurationWithDifferentDeviceAndSameCrtc) { CheckProperConfigurationWithDifferentDeviceAndSameCrtc) {
scoped_refptr<ui::MockDrmDevice> drm2 = new ui::MockDrmDevice(); scoped_refptr<ui::MockDrmDevice> drm2 = new ui::MockDrmDevice(false);
screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
screen_manager_->AddDisplayController(drm2, kPrimaryCrtc, kPrimaryConnector); screen_manager_->AddDisplayController(drm2, kPrimaryCrtc, kPrimaryConnector);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment