1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h"
12 #include "base/logging.h"
13 #include "ui/gfx/geometry/rect.h"
14 #include "ui/ozone/platform/drm/gpu/crtc_controller.h"
15 #include "ui/ozone/platform/drm/gpu/drm_device.h"
16 #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
17 #include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
18 #include "ui/ozone/public/ozone_switches.h"
23 const float kFixedPointScaleValue
= 65536.0f
;
27 HardwareDisplayPlaneList::HardwareDisplayPlaneList() {
28 #if defined(USE_DRM_ATOMIC)
29 atomic_property_set
.reset(drmModePropertySetAlloc());
30 #endif // defined(USE_DRM_ATOMIC)
33 HardwareDisplayPlaneList::~HardwareDisplayPlaneList() {
34 for (auto* plane
: plane_list
) {
35 plane
->set_in_use(false);
36 plane
->set_owning_crtc(0);
38 for (auto* plane
: old_plane_list
) {
39 plane
->set_in_use(false);
40 plane
->set_owning_crtc(0);
44 HardwareDisplayPlaneList::PageFlipInfo::PageFlipInfo(uint32_t crtc_id
,
47 : crtc_id(crtc_id
), framebuffer(framebuffer
), crtc(crtc
) {
50 HardwareDisplayPlaneList::PageFlipInfo::~PageFlipInfo() {
53 HardwareDisplayPlaneList::PageFlipInfo::Plane::Plane(int plane
,
55 const gfx::Rect
& bounds
,
56 const gfx::Rect
& src_rect
)
58 framebuffer(framebuffer
),
63 HardwareDisplayPlaneList::PageFlipInfo::Plane::~Plane() {
66 HardwareDisplayPlaneManager::HardwareDisplayPlaneManager() : drm_(nullptr) {
69 HardwareDisplayPlaneManager::~HardwareDisplayPlaneManager() {
72 bool HardwareDisplayPlaneManager::Initialize(DrmDevice
* drm
) {
75 // Try to get all of the planes if possible, so we don't have to try to
76 // discover hidden primary planes.
77 bool has_universal_planes
= false;
78 #if defined(DRM_CLIENT_CAP_UNIVERSAL_PLANES)
79 has_universal_planes
= drm
->SetCapability(DRM_CLIENT_CAP_UNIVERSAL_PLANES
, 1);
80 #endif // defined(DRM_CLIENT_CAP_UNIVERSAL_PLANES)
82 ScopedDrmResourcesPtr
resources(drmModeGetResources(drm
->get_fd()));
84 PLOG(ERROR
) << "Failed to get resources";
88 ScopedDrmPlaneResPtr
plane_resources(drmModeGetPlaneResources(drm
->get_fd()));
89 if (!plane_resources
) {
90 PLOG(ERROR
) << "Failed to get plane resources";
95 for (int i
= 0; i
< resources
->count_crtcs
; ++i
) {
96 crtcs_
.push_back(resources
->crtcs
[i
]);
99 uint32_t num_planes
= plane_resources
->count_planes
;
100 std::set
<uint32_t> plane_ids
;
101 for (uint32_t i
= 0; i
< num_planes
; ++i
) {
102 ScopedDrmPlanePtr
drm_plane(
103 drmModeGetPlane(drm
->get_fd(), plane_resources
->planes
[i
]));
105 PLOG(ERROR
) << "Failed to get plane " << i
;
108 plane_ids
.insert(drm_plane
->plane_id
);
109 scoped_ptr
<HardwareDisplayPlane
> plane(
110 CreatePlane(drm_plane
->plane_id
, drm_plane
->possible_crtcs
));
111 if (plane
->Initialize(drm
))
112 planes_
.push_back(plane
.Pass());
115 // crbug.com/464085: if driver reports no primary planes for a crtc, create a
116 // dummy plane for which we can assign exactly one overlay.
117 // TODO(dnicoara): refactor this to simplify AssignOverlayPlanes and move
118 // this workaround into HardwareDisplayPlaneLegacy.
119 if (!has_universal_planes
) {
120 for (int i
= 0; i
< resources
->count_crtcs
; ++i
) {
121 if (plane_ids
.find(resources
->crtcs
[i
] - 1) == plane_ids
.end()) {
122 scoped_ptr
<HardwareDisplayPlane
> dummy_plane(
123 CreatePlane(resources
->crtcs
[i
] - 1, (1 << i
)));
124 dummy_plane
->set_is_dummy(true);
125 if (dummy_plane
->Initialize(drm
))
126 planes_
.push_back(dummy_plane
.Pass());
131 std::sort(planes_
.begin(), planes_
.end(),
132 [](HardwareDisplayPlane
* l
, HardwareDisplayPlane
* r
) {
133 return l
->plane_id() < r
->plane_id();
138 scoped_ptr
<HardwareDisplayPlane
> HardwareDisplayPlaneManager::CreatePlane(
140 uint32_t possible_crtcs
) {
141 return scoped_ptr
<HardwareDisplayPlane
>(
142 new HardwareDisplayPlane(plane_id
, possible_crtcs
));
145 HardwareDisplayPlane
* HardwareDisplayPlaneManager::FindNextUnusedPlane(
147 uint32_t crtc_index
) {
148 for (size_t i
= *index
; i
< planes_
.size(); ++i
) {
149 auto plane
= planes_
[i
];
150 if (!plane
->in_use() && plane
->CanUseForCrtc(crtc_index
)) {
158 int HardwareDisplayPlaneManager::LookupCrtcIndex(uint32_t crtc_id
) {
159 for (size_t i
= 0; i
< crtcs_
.size(); ++i
)
160 if (crtcs_
[i
] == crtc_id
)
165 void HardwareDisplayPlaneManager::BeginFrame(
166 HardwareDisplayPlaneList
* plane_list
) {
167 for (auto* plane
: plane_list
->old_plane_list
) {
168 plane
->set_in_use(false);
172 bool HardwareDisplayPlaneManager::AssignOverlayPlanes(
173 HardwareDisplayPlaneList
* plane_list
,
174 const OverlayPlaneList
& overlay_list
,
176 CrtcController
* crtc
) {
177 int crtc_index
= LookupCrtcIndex(crtc_id
);
178 if (crtc_index
< 0) {
179 LOG(ERROR
) << "Cannot find crtc " << crtc_id
;
183 size_t plane_idx
= 0;
184 for (const auto& plane
: overlay_list
) {
185 HardwareDisplayPlane
* hw_plane
=
186 FindNextUnusedPlane(&plane_idx
, crtc_index
);
188 LOG(ERROR
) << "Failed to find a free plane for crtc " << crtc_id
;
192 gfx::Rect fixed_point_rect
;
193 if (!hw_plane
->is_dummy()) {
194 const gfx::Size
& size
= plane
.buffer
->GetSize();
195 gfx::RectF crop_rect
= plane
.crop_rect
;
196 crop_rect
.Scale(size
.width(), size
.height());
198 // This returns a number in 16.16 fixed point, required by the DRM overlay
200 auto to_fixed_point
=
201 [](double v
) -> uint32_t { return v
* kFixedPointScaleValue
; };
202 fixed_point_rect
= gfx::Rect(to_fixed_point(crop_rect
.x()),
203 to_fixed_point(crop_rect
.y()),
204 to_fixed_point(crop_rect
.width()),
205 to_fixed_point(crop_rect
.height()));
208 plane_list
->plane_list
.push_back(hw_plane
);
209 hw_plane
->set_owning_crtc(crtc_id
);
210 if (SetPlaneData(plane_list
, hw_plane
, plane
, crtc_id
, fixed_point_rect
,
212 hw_plane
->set_in_use(true);
220 void HardwareDisplayPlaneManager::ResetPlanes(
221 HardwareDisplayPlaneList
* plane_list
,
223 std::vector
<HardwareDisplayPlane
*> planes
;
224 planes
.swap(plane_list
->old_plane_list
);
225 for (auto* plane
: planes
) {
226 if (plane
->owning_crtc() == crtc_id
) {
227 plane
->set_owning_crtc(0);
228 plane
->set_in_use(false);
230 plane_list
->old_plane_list
.push_back(plane
);