2 // Copyright (c) 2016 Intel Corporation
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
17 #include "drmdisplay.h"
30 #include "displayqueue.h"
31 #include "displayplanemanager.h"
33 namespace hwcomposer {
35 static const int32_t kUmPerInch = 25400;
37 DrmDisplay::DrmDisplay(uint32_t gpu_fd, uint32_t pipe_id, uint32_t crtc_id)
38 : PhysicalDisplay(gpu_fd, pipe_id), crtc_id_(crtc_id), connector_(0) {
39 memset(¤t_mode_, 0, sizeof(current_mode_));
42 DrmDisplay::~DrmDisplay() {
44 drmModeDestroyPropertyBlob(gpu_fd_, blob_id_);
47 drmModeDestroyPropertyBlob(gpu_fd_, old_blob_id_);
49 display_queue_->SetPowerMode(kOff);
52 bool DrmDisplay::InitializeDisplay() {
53 ScopedDrmObjectPropertyPtr crtc_props(
54 drmModeObjectGetProperties(gpu_fd_, crtc_id_, DRM_MODE_OBJECT_CRTC));
55 GetDrmObjectProperty("ACTIVE", crtc_props, &active_prop_);
56 GetDrmObjectProperty("MODE_ID", crtc_props, &mode_id_prop_);
57 GetDrmObjectProperty("GAMMA_LUT", crtc_props, &lut_id_prop_);
58 GetDrmObjectPropertyValue("GAMMA_LUT_SIZE", crtc_props, &lut_size_);
59 GetDrmObjectProperty("OUT_FENCE_PTR", crtc_props, &out_fence_ptr_prop_);
64 bool DrmDisplay::ConnectDisplay(const drmModeModeInfo &mode_info,
65 const drmModeConnector *connector) {
66 IHOTPLUGEVENTTRACE("DrmDisplay::Connect recieved.");
67 // TODO(kalyan): Add support for multi monitor case.
68 if (connector_ && connector->connector_id == connector_) {
70 "Display is already connected to this connector. %d %d %p \n",
71 connector->connector_id, connector_, this);
72 PhysicalDisplay::Connect();
77 "Display is being connected to a new connector.%d %d %p \n",
78 connector->connector_id, connector_, this);
79 connector_ = connector->connector_id;
80 mmWidth_ = connector->mmWidth;
81 mmHeight_ = connector->mmHeight;
82 SetDisplayAttribute(mode_info);
84 ScopedDrmObjectPropertyPtr connector_props(drmModeObjectGetProperties(
85 gpu_fd_, connector_, DRM_MODE_OBJECT_CONNECTOR));
86 if (!connector_props) {
87 ETRACE("Unable to get connector properties.");
91 // GetDrmObjectProperty("DPMS", connector_props, &dpms_prop_);
92 GetDrmObjectProperty("CRTC_ID", connector_props, &crtc_prop_);
93 GetDrmObjectProperty("Broadcast RGB", connector_props, &broadcastrgb_id_);
94 GetDrmObjectProperty("DPMS", connector_props, &dpms_prop_);
96 PhysicalDisplay::Connect();
98 drmModePropertyPtr broadcastrgb_props =
99 drmModeGetProperty(gpu_fd_, broadcastrgb_id_);
101 SetPowerMode(power_mode_);
103 // This is a valid case on DSI panels.
104 if (!broadcastrgb_props)
107 if (!(broadcastrgb_props->flags & DRM_MODE_PROP_ENUM))
110 for (int i = 0; i < broadcastrgb_props->count_enums; i++) {
111 if (!strcmp(broadcastrgb_props->enums[i].name, "Full")) {
112 broadcastrgb_full_ = broadcastrgb_props->enums[i].value;
113 } else if (!strcmp(broadcastrgb_props->enums[i].name, "Automatic")) {
114 broadcastrgb_automatic_ = broadcastrgb_props->enums[i].value;
118 drmModeFreeProperty(broadcastrgb_props);
123 bool DrmDisplay::GetDisplayAttribute(uint32_t config /*config*/,
124 HWCDisplayAttribute attribute,
126 display_lock_.lock();
130 case HWCDisplayAttribute::kWidth:
131 *value = modes_[config].hdisplay;
133 case HWCDisplayAttribute::kHeight:
134 *value = modes_[config].vdisplay;
136 case HWCDisplayAttribute::kRefreshRate:
137 refresh = (modes_[config].clock * 1000.0f) /
138 (modes_[config].htotal * modes_[config].vtotal);
140 if (modes_[config].flags & DRM_MODE_FLAG_INTERLACE)
143 if (modes_[config].flags & DRM_MODE_FLAG_DBLSCAN)
146 if (modes_[config].vscan > 1)
147 refresh /= modes_[config].vscan;
149 *value = 1e9 / refresh;
151 case HWCDisplayAttribute::kDpiX:
152 // Dots per 1000 inches
154 mmWidth_ ? (modes_[config].hdisplay * kUmPerInch) / mmWidth_ : -1;
156 case HWCDisplayAttribute::kDpiY:
157 // Dots per 1000 inches
159 mmHeight_ ? (modes_[config].vdisplay * kUmPerInch) / mmHeight_ : -1;
166 display_lock_.unlock();
170 bool DrmDisplay::GetDisplayConfigs(uint32_t *num_configs, uint32_t *configs) {
172 display_lock_.lock();
173 *num_configs = modes_.size();
174 display_lock_.unlock();
178 uint32_t size = *num_configs;
179 for (uint32_t i = 0; i < size; i++)
185 bool DrmDisplay::GetDisplayName(uint32_t *size, char *name) {
186 std::ostringstream stream;
187 stream << "Display-" << connector_;
188 std::string string = stream.str();
189 size_t length = string.length();
195 *size = std::min<uint32_t>(static_cast<uint32_t>(length - 1), *size);
196 strncpy(name, string.c_str(), *size);
200 void DrmDisplay::UpdateDisplayConfig() {
201 // update the activeConfig
202 display_lock_.lock();
203 flags_ |= DRM_MODE_ATOMIC_ALLOW_MODESET;
204 SetDisplayAttribute(modes_[config_]);
205 display_lock_.unlock();
208 void DrmDisplay::PowerOn() {
210 flags_ |= DRM_MODE_ATOMIC_ALLOW_MODESET;
211 drmModeConnectorSetProperty(gpu_fd_, connector_, dpms_prop_,
215 bool DrmDisplay::SetBroadcastRGB(const char *range_property) {
216 int64_t p_value = -1;
218 if (!strcmp(range_property, "Full")) {
219 p_value = broadcastrgb_full_;
220 } else if (!strcmp(range_property, "Automatic")) {
221 p_value = broadcastrgb_automatic_;
223 ETRACE("Wrong Broadcast RGB value %s", range_property);
230 if (drmModeObjectSetProperty(gpu_fd_, connector_, DRM_MODE_OBJECT_CONNECTOR,
231 broadcastrgb_id_, (uint64_t)p_value) != 0)
237 bool DrmDisplay::Commit(
238 const DisplayPlaneStateList &composition_planes,
239 const DisplayPlaneStateList &previous_composition_planes,
240 bool disable_explicit_fence, int32_t *commit_fence) {
241 // Do the actual commit.
242 ScopedDrmAtomicReqPtr pset(drmModeAtomicAlloc());
245 ETRACE("Failed to allocate property set %d", -ENOMEM);
249 if (display_state_ & kNeedsModeset) {
250 if (!ApplyPendingModeset(pset.get())) {
251 ETRACE("Failed to Modeset.");
254 } else if (!disable_explicit_fence && out_fence_ptr_prop_) {
255 GetFence(pset.get(), commit_fence);
258 if (!CommitFrame(composition_planes, previous_composition_planes, pset.get(),
260 ETRACE("Failed to Commit layers.");
264 if (display_state_ & kNeedsModeset) {
265 display_state_ &= ~kNeedsModeset;
266 if (!disable_explicit_fence) {
268 flags_ |= DRM_MODE_ATOMIC_NONBLOCK;
275 bool DrmDisplay::CommitFrame(
276 const DisplayPlaneStateList &comp_planes,
277 const DisplayPlaneStateList &previous_composition_planes,
278 drmModeAtomicReqPtr pset, uint32_t flags) {
281 ETRACE("Failed to allocate property set %d", -ENOMEM);
285 for (const DisplayPlaneState &comp_plane : previous_composition_planes) {
286 DrmPlane *plane = static_cast<DrmPlane *>(comp_plane.plane());
287 plane->SetEnabled(false);
290 for (const DisplayPlaneState &comp_plane : comp_planes) {
291 DrmPlane *plane = static_cast<DrmPlane *>(comp_plane.plane());
292 const OverlayLayer *layer = comp_plane.GetOverlayLayer();
293 int32_t fence = layer->GetAcquireFence();
295 plane->SetNativeFence(dup(fence));
297 plane->SetNativeFence(-1);
299 if (!plane->UpdateProperties(pset, crtc_id_, layer))
302 plane->SetEnabled(true);
305 for (const DisplayPlaneState &comp_plane : previous_composition_planes) {
306 DrmPlane *plane = static_cast<DrmPlane *>(comp_plane.plane());
307 if (plane->IsEnabled())
310 plane->Disable(pset);
313 int ret = drmModeAtomicCommit(gpu_fd_, pset, flags, NULL);
315 ETRACE("Failed to commit pset ret=%s\n", PRINTERROR());
322 void DrmDisplay::SetDrmModeInfo(const std::vector<drmModeModeInfo> &mode_info) {
323 display_lock_.lock();
324 uint32_t size = mode_info.size();
325 std::vector<drmModeModeInfo>().swap(modes_);
326 for (uint32_t i = 0; i < size; ++i) {
327 modes_.emplace_back(mode_info[i]);
330 display_lock_.unlock();
333 void DrmDisplay::SetDisplayAttribute(const drmModeModeInfo &mode_info) {
334 width_ = mode_info.hdisplay;
335 height_ = mode_info.vdisplay;
336 dpix_ = mmWidth_ ? (width_ * kUmPerInch) / mmWidth_ : -1;
337 dpiy_ = mmHeight_ ? (height_ * kUmPerInch) / mmHeight_ : -1;
338 current_mode_ = mode_info;
341 void DrmDisplay::GetDrmObjectProperty(const char *name,
342 const ScopedDrmObjectPropertyPtr &props,
343 uint32_t *id) const {
344 uint32_t count_props = props->count_props;
345 for (uint32_t i = 0; i < count_props; i++) {
346 ScopedDrmPropertyPtr property(drmModeGetProperty(gpu_fd_, props->props[i]));
347 if (property && !strcmp(property->name, name)) {
348 *id = property->prop_id;
353 ETRACE("Could not find property %s", name);
356 void DrmDisplay::GetDrmObjectPropertyValue(
357 const char *name, const ScopedDrmObjectPropertyPtr &props,
358 uint64_t *value) const {
359 uint32_t count_props = props->count_props;
360 for (uint32_t i = 0; i < count_props; i++) {
361 ScopedDrmPropertyPtr property(drmModeGetProperty(gpu_fd_, props->props[i]));
362 if (property && !strcmp(property->name, name)) {
363 *value = props->prop_values[i];
368 ETRACE("Could not find property value %s", name);
371 void DrmDisplay::ApplyPendingLUT(struct drm_color_lut *lut) const {
372 if (lut_id_prop_ == 0)
375 uint32_t lut_blob_id = 0;
377 drmModeCreatePropertyBlob(
378 gpu_fd_, lut, sizeof(struct drm_color_lut) * lut_size_, &lut_blob_id);
379 if (lut_blob_id == 0) {
383 drmModeObjectSetProperty(gpu_fd_, crtc_id_, DRM_MODE_OBJECT_CRTC,
384 lut_id_prop_, lut_blob_id);
385 drmModeDestroyPropertyBlob(gpu_fd_, lut_blob_id);
388 float DrmDisplay::TransformContrastBrightness(float value, float brightness,
389 float contrast) const {
391 result = (value - 0.5) * contrast + 0.5 + brightness;
400 float DrmDisplay::TransformGamma(float value, float gamma) const {
403 result = pow(value, gamma);
412 void DrmDisplay::SetColorCorrection(struct gamma_colors gamma,
414 uint32_t brightness_c) const {
415 struct drm_color_lut *lut;
420 /* reset lut when contrast and brightness are all 0 */
421 if (contrast_c == 0 && brightness_c == 0) {
423 ApplyPendingLUT(lut);
429 (struct drm_color_lut *)malloc(sizeof(struct drm_color_lut) * lut_size_);
431 ETRACE("Cannot allocate LUT memory");
435 /* Unpack brightness values for each channel */
436 temp[0] = (brightness_c >> 16) & 0xFF;
437 temp[1] = (brightness_c >> 8) & 0xFF;
438 temp[2] = (brightness_c)&0xFF;
440 /* Map brightness from -128 - 127 range into -0.5 - 0.5 range */
441 brightness[0] = (float)(temp[0]) / 255 - 0.5;
442 brightness[1] = (float)(temp[1]) / 255 - 0.5;
443 brightness[2] = (float)(temp[2]) / 255 - 0.5;
445 /* Unpack contrast values for each channel */
446 temp[0] = (contrast_c >> 16) & 0xFF;
447 temp[1] = (contrast_c >> 8) & 0xFF;
448 temp[2] = (contrast_c)&0xFF;
450 /* Map contrast from 0 - 255 range into 0.0 - 2.0 range */
451 contrast[0] = (float)(temp[0]) / 128;
452 contrast[1] = (float)(temp[1]) / 128;
453 contrast[2] = (float)(temp[2]) / 128;
455 for (uint64_t i = 0; i < lut_size_; i++) {
456 /* Set lut[0] as 0 always as the darkest color should has brightness 0 */
464 lut[i].red = 0xFFFF * TransformGamma(TransformContrastBrightness(
465 (float)(i) / lut_size_,
466 brightness[0], contrast[0]),
468 lut[i].green = 0xFFFF * TransformGamma(TransformContrastBrightness(
469 (float)(i) / lut_size_,
470 brightness[1], contrast[1]),
472 lut[i].blue = 0xFFFF * TransformGamma(TransformContrastBrightness(
473 (float)(i) / lut_size_,
474 brightness[2], contrast[2]),
478 ApplyPendingLUT(lut);
482 bool DrmDisplay::ApplyPendingModeset(drmModeAtomicReqPtr property_set) {
484 drmModeDestroyPropertyBlob(gpu_fd_, old_blob_id_);
488 drmModeCreatePropertyBlob(gpu_fd_, ¤t_mode_, sizeof(drmModeModeInfo),
495 int ret = drmModeAtomicAddProperty(property_set, crtc_id_, mode_id_prop_,
497 drmModeAtomicAddProperty(property_set, connector_, crtc_prop_,
499 drmModeAtomicAddProperty(property_set, crtc_id_, active_prop_,
502 ETRACE("Failed to add blob %d to pset", blob_id_);
506 old_blob_id_ = blob_id_;
512 bool DrmDisplay::GetFence(drmModeAtomicReqPtr property_set,
513 int32_t *out_fence) {
514 int ret = drmModeAtomicAddProperty(property_set, crtc_id_,
515 out_fence_ptr_prop_, (uintptr_t)out_fence);
517 ETRACE("Failed to add OUT_FENCE_PTR property to pset: %d", ret);
524 void DrmDisplay::Disable(const DisplayPlaneStateList &composition_planes) {
525 ScopedDrmAtomicReqPtr pset(drmModeAtomicAlloc());
528 int ret = drmModeAtomicAddProperty(pset.get(), crtc_id_, active_prop_,
531 ETRACE("Failed to set display to inactive");
534 for (const DisplayPlaneState &comp_plane : composition_planes) {
535 DrmPlane *plane = static_cast<DrmPlane *>(comp_plane.plane());
536 plane->SetEnabled(false);
537 plane->Disable(pset.get());
540 ret = drmModeAtomicCommit(gpu_fd_, pset.get(),
541 DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
543 ETRACE("Failed to disable display:%s\n", PRINTERROR());
545 ETRACE("Failed to allocate property set %d", -ENOMEM);
548 drmModeConnectorSetProperty(gpu_fd_, connector_, dpms_prop_,
552 bool DrmDisplay::PopulatePlanes(
553 std::unique_ptr<DisplayPlane> &primary_plane,
554 std::unique_ptr<DisplayPlane> &cursor_plane,
555 std::vector<std::unique_ptr<DisplayPlane>> &overlay_planes) {
556 ScopedDrmPlaneResPtr plane_resources(drmModeGetPlaneResources(gpu_fd_));
557 if (!plane_resources) {
558 ETRACE("Failed to get plane resources");
562 uint32_t num_planes = plane_resources->count_planes;
563 uint32_t pipe_bit = 1 << pipe_;
564 std::set<uint32_t> plane_ids;
565 for (uint32_t i = 0; i < num_planes; ++i) {
566 ScopedDrmPlanePtr drm_plane(
567 drmModeGetPlane(gpu_fd_, plane_resources->planes[i]));
569 ETRACE("Failed to get plane ");
573 if (!(pipe_bit & drm_plane->possible_crtcs))
576 uint32_t formats_size = drm_plane->count_formats;
577 plane_ids.insert(drm_plane->plane_id);
578 std::unique_ptr<DrmPlane> plane(
579 CreatePlane(drm_plane->plane_id, drm_plane->possible_crtcs));
580 std::vector<uint32_t> supported_formats(formats_size);
581 for (uint32_t j = 0; j < formats_size; j++)
582 supported_formats[j] = drm_plane->formats[j];
584 if (plane->Initialize(gpu_fd_, supported_formats)) {
585 if (plane->type() == DRM_PLANE_TYPE_CURSOR) {
586 cursor_plane.reset(plane.release());
587 } else if (plane->type() == DRM_PLANE_TYPE_PRIMARY) {
588 plane->SetEnabled(true);
589 primary_plane.reset(plane.release());
590 } else if (plane->type() == DRM_PLANE_TYPE_OVERLAY) {
591 overlay_planes.emplace_back(plane.release());
596 if (!primary_plane) {
597 ETRACE("Failed to get primary plane for display %d", crtc_id_);
601 // We expect layers to be in ascending order.
603 overlay_planes.begin(), overlay_planes.end(),
604 [](const std::unique_ptr<DisplayPlane> &l,
605 const std::unique_ptr<DisplayPlane> &r) { return l->id() < r->id(); });
610 bool DrmDisplay::TestCommit(
611 const std::vector<OverlayPlane> &commit_planes) const {
612 ScopedDrmAtomicReqPtr pset(drmModeAtomicAlloc());
613 for (auto i = commit_planes.begin(); i != commit_planes.end(); i++) {
614 DrmPlane *plane = static_cast<DrmPlane *>(i->plane);
615 if (!(plane->UpdateProperties(pset.get(), crtc_id_, i->layer, true))) {
620 if (drmModeAtomicCommit(gpu_fd_, pset.get(), DRM_MODE_ATOMIC_TEST_ONLY,
622 IDISPLAYMANAGERTRACE("Test Commit Failed. %s ", PRINTERROR());
629 std::unique_ptr<DrmPlane> DrmDisplay::CreatePlane(uint32_t plane_id,
630 uint32_t possible_crtcs) {
631 return std::unique_ptr<DrmPlane>(new DrmPlane(plane_id, possible_crtcs));
634 } // namespace hwcomposer