OSDN Git Service

26b01a3b593ebe2566bd965518671538c7d0af4e
[android-x86/external-IA-Hardware-Composer.git] / wsi / drm / drmdisplay.cpp
1 /*
2 // Copyright (c) 2016 Intel Corporation
3 //
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
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
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.
15 */
16
17 #include "drmdisplay.h"
18
19 #include <cmath>
20 #include <set>
21
22 #include <hwcdefs.h>
23 #include <hwclayer.h>
24 #include <hwctrace.h>
25
26 #include <algorithm>
27 #include <string>
28 #include <sstream>
29
30 #include "displayqueue.h"
31 #include "displayplanemanager.h"
32
33 namespace hwcomposer {
34
35 static const int32_t kUmPerInch = 25400;
36
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(&current_mode_, 0, sizeof(current_mode_));
40 }
41
42 DrmDisplay::~DrmDisplay() {
43   if (blob_id_)
44     drmModeDestroyPropertyBlob(gpu_fd_, blob_id_);
45
46   if (old_blob_id_)
47     drmModeDestroyPropertyBlob(gpu_fd_, old_blob_id_);
48
49   display_queue_->SetPowerMode(kOff);
50 }
51
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_);
60
61   return true;
62 }
63
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_) {
69     IHOTPLUGEVENTTRACE("Display is already connected to this connector.");
70     PhysicalDisplay::Connect();
71     return true;
72   }
73
74   IHOTPLUGEVENTTRACE("Display is being connected to a new connector.");
75   connector_ = connector->connector_id;
76   mmWidth_ = connector->mmWidth;
77   mmHeight_ = connector->mmHeight;
78   SetDisplayAttribute(mode_info);
79
80   ScopedDrmObjectPropertyPtr connector_props(drmModeObjectGetProperties(
81       gpu_fd_, connector_, DRM_MODE_OBJECT_CONNECTOR));
82   if (!connector_props) {
83     ETRACE("Unable to get connector properties.");
84     return false;
85   }
86
87   // GetDrmObjectProperty("DPMS", connector_props, &dpms_prop_);
88   GetDrmObjectProperty("CRTC_ID", connector_props, &crtc_prop_);
89   GetDrmObjectProperty("Broadcast RGB", connector_props, &broadcastrgb_id_);
90   GetDrmObjectProperty("DPMS", connector_props, &dpms_prop_);
91
92   PhysicalDisplay::Connect();
93
94   drmModePropertyPtr broadcastrgb_props =
95       drmModeGetProperty(gpu_fd_, broadcastrgb_id_);
96
97   SetPowerMode(power_mode_);
98
99   // This is a valid case on DSI panels.
100   if (!broadcastrgb_props)
101     return true;
102
103   if (!(broadcastrgb_props->flags & DRM_MODE_PROP_ENUM))
104     return false;
105
106   for (int i = 0; i < broadcastrgb_props->count_enums; i++) {
107     if (!strcmp(broadcastrgb_props->enums[i].name, "Full")) {
108       broadcastrgb_full_ = broadcastrgb_props->enums[i].value;
109     } else if (!strcmp(broadcastrgb_props->enums[i].name, "Automatic")) {
110       broadcastrgb_automatic_ = broadcastrgb_props->enums[i].value;
111     }
112   }
113
114   drmModeFreeProperty(broadcastrgb_props);
115
116   return true;
117 }
118
119 bool DrmDisplay::GetDisplayAttribute(uint32_t config /*config*/,
120                                      HWCDisplayAttribute attribute,
121                                      int32_t *value) {
122   display_lock_.lock();
123   float refresh;
124   bool status = true;
125   switch (attribute) {
126     case HWCDisplayAttribute::kWidth:
127       *value = modes_[config].hdisplay;
128       break;
129     case HWCDisplayAttribute::kHeight:
130       *value = modes_[config].vdisplay;
131       break;
132     case HWCDisplayAttribute::kRefreshRate:
133       refresh = (modes_[config].clock * 1000.0f) /
134                 (modes_[config].htotal * modes_[config].vtotal);
135
136       if (modes_[config].flags & DRM_MODE_FLAG_INTERLACE)
137         refresh *= 2;
138
139       if (modes_[config].flags & DRM_MODE_FLAG_DBLSCAN)
140         refresh /= 2;
141
142       if (modes_[config].vscan > 1)
143         refresh /= modes_[config].vscan;
144       // in nanoseconds
145       *value = 1e9 / refresh;
146       break;
147     case HWCDisplayAttribute::kDpiX:
148       // Dots per 1000 inches
149       *value =
150           mmWidth_ ? (modes_[config].hdisplay * kUmPerInch) / mmWidth_ : -1;
151       break;
152     case HWCDisplayAttribute::kDpiY:
153       // Dots per 1000 inches
154       *value =
155           mmHeight_ ? (modes_[config].vdisplay * kUmPerInch) / mmHeight_ : -1;
156       break;
157     default:
158       *value = -1;
159       status = false;
160   }
161
162   display_lock_.unlock();
163   return status;
164 }
165
166 bool DrmDisplay::GetDisplayConfigs(uint32_t *num_configs, uint32_t *configs) {
167   if (!configs) {
168     display_lock_.lock();
169     *num_configs = modes_.size();
170     display_lock_.unlock();
171     return true;
172   }
173
174   uint32_t size = *num_configs;
175   for (uint32_t i = 0; i < size; i++)
176     configs[i] = i;
177
178   return true;
179 }
180
181 bool DrmDisplay::GetDisplayName(uint32_t *size, char *name) {
182   std::ostringstream stream;
183   stream << "Display-" << connector_;
184   std::string string = stream.str();
185   size_t length = string.length();
186   if (!name) {
187     *size = length;
188     return true;
189   }
190
191   *size = std::min<uint32_t>(static_cast<uint32_t>(length - 1), *size);
192   strncpy(name, string.c_str(), *size);
193   return true;
194 }
195
196 void DrmDisplay::UpdateDisplayConfig() {
197   // update the activeConfig
198   display_lock_.lock();
199   flags_ |= DRM_MODE_ATOMIC_ALLOW_MODESET;
200   SetDisplayAttribute(modes_[config_]);
201   display_lock_.unlock();
202 }
203
204 void DrmDisplay::PowerOn() {
205   flags_ = 0;
206   flags_ |= DRM_MODE_ATOMIC_ALLOW_MODESET;
207   drmModeConnectorSetProperty(gpu_fd_, connector_, dpms_prop_,
208                               DRM_MODE_DPMS_ON);
209 }
210
211 bool DrmDisplay::SetBroadcastRGB(const char *range_property) {
212   int64_t p_value = -1;
213
214   if (!strcmp(range_property, "Full")) {
215     p_value = broadcastrgb_full_;
216   } else if (!strcmp(range_property, "Automatic")) {
217     p_value = broadcastrgb_automatic_;
218   } else {
219     ETRACE("Wrong Broadcast RGB value %s", range_property);
220     return false;
221   }
222
223   if (p_value < 0)
224     return false;
225
226   if (drmModeObjectSetProperty(gpu_fd_, connector_, DRM_MODE_OBJECT_CONNECTOR,
227                                broadcastrgb_id_, (uint64_t)p_value) != 0)
228     return false;
229
230   return true;
231 }
232
233 bool DrmDisplay::Commit(
234     const DisplayPlaneStateList &composition_planes,
235     const DisplayPlaneStateList &previous_composition_planes,
236     bool disable_explicit_fence, int32_t *commit_fence) {
237   // Do the actual commit.
238   ScopedDrmAtomicReqPtr pset(drmModeAtomicAlloc());
239
240   if (!pset) {
241     ETRACE("Failed to allocate property set %d", -ENOMEM);
242     return false;
243   }
244
245   if (display_state_ & kNeedsModeset) {
246     if (!ApplyPendingModeset(pset.get())) {
247       ETRACE("Failed to Modeset.");
248       return false;
249     }
250   } else if (!disable_explicit_fence && out_fence_ptr_prop_) {
251     GetFence(pset.get(), commit_fence);
252   }
253
254   if (!CommitFrame(composition_planes, previous_composition_planes, pset.get(),
255                    flags_)) {
256     ETRACE("Failed to Commit layers.");
257     return false;
258   }
259
260   if (display_state_ & kNeedsModeset) {
261     display_state_ &= ~kNeedsModeset;
262     if (!disable_explicit_fence) {
263       flags_ = 0;
264       flags_ |= DRM_MODE_ATOMIC_NONBLOCK;
265     }
266   }
267
268   return true;
269 }
270
271 bool DrmDisplay::CommitFrame(
272     const DisplayPlaneStateList &comp_planes,
273     const DisplayPlaneStateList &previous_composition_planes,
274     drmModeAtomicReqPtr pset, uint32_t flags) {
275   CTRACE();
276   if (!pset) {
277     ETRACE("Failed to allocate property set %d", -ENOMEM);
278     return false;
279   }
280
281   for (const DisplayPlaneState &comp_plane : previous_composition_planes) {
282     DrmPlane *plane = static_cast<DrmPlane *>(comp_plane.plane());
283     plane->SetEnabled(false);
284   }
285
286   for (const DisplayPlaneState &comp_plane : comp_planes) {
287     DrmPlane *plane = static_cast<DrmPlane *>(comp_plane.plane());
288     const OverlayLayer *layer = comp_plane.GetOverlayLayer();
289     int32_t fence = layer->GetAcquireFence();
290     if (fence > 0) {
291       plane->SetNativeFence(dup(fence));
292     } else {
293       plane->SetNativeFence(-1);
294     }
295     if (!plane->UpdateProperties(pset, crtc_id_, layer))
296       return false;
297
298     plane->SetEnabled(true);
299   }
300
301   for (const DisplayPlaneState &comp_plane : previous_composition_planes) {
302     DrmPlane *plane = static_cast<DrmPlane *>(comp_plane.plane());
303     if (plane->IsEnabled())
304       continue;
305
306     plane->Disable(pset);
307   }
308
309   int ret = drmModeAtomicCommit(gpu_fd_, pset, flags, NULL);
310   if (ret) {
311     ETRACE("Failed to commit pset ret=%s\n", PRINTERROR());
312     return false;
313   }
314
315   return true;
316 }
317
318 void DrmDisplay::SetDrmModeInfo(const std::vector<drmModeModeInfo> &mode_info) {
319   display_lock_.lock();
320   uint32_t size = mode_info.size();
321   for (uint32_t i = 0; i < size; ++i)
322     modes_.emplace_back(mode_info[i]);
323
324   display_lock_.unlock();
325 }
326
327 void DrmDisplay::SetDisplayAttribute(const drmModeModeInfo &mode_info) {
328   width_ = mode_info.hdisplay;
329   height_ = mode_info.vdisplay;
330   dpix_ = mmWidth_ ? (width_ * kUmPerInch) / mmWidth_ : -1;
331   dpiy_ = mmHeight_ ? (height_ * kUmPerInch) / mmHeight_ : -1;
332   current_mode_ = mode_info;
333 }
334
335 void DrmDisplay::GetDrmObjectProperty(const char *name,
336                                       const ScopedDrmObjectPropertyPtr &props,
337                                       uint32_t *id) const {
338   uint32_t count_props = props->count_props;
339   for (uint32_t i = 0; i < count_props; i++) {
340     ScopedDrmPropertyPtr property(drmModeGetProperty(gpu_fd_, props->props[i]));
341     if (property && !strcmp(property->name, name)) {
342       *id = property->prop_id;
343       break;
344     }
345   }
346   if (!(*id))
347     ETRACE("Could not find property %s", name);
348 }
349
350 void DrmDisplay::GetDrmObjectPropertyValue(
351     const char *name, const ScopedDrmObjectPropertyPtr &props,
352     uint64_t *value) const {
353   uint32_t count_props = props->count_props;
354   for (uint32_t i = 0; i < count_props; i++) {
355     ScopedDrmPropertyPtr property(drmModeGetProperty(gpu_fd_, props->props[i]));
356     if (property && !strcmp(property->name, name)) {
357       *value = props->prop_values[i];
358       break;
359     }
360   }
361   if (!(*value))
362     ETRACE("Could not find property value %s", name);
363 }
364
365 void DrmDisplay::ApplyPendingLUT(struct drm_color_lut *lut) const {
366   if (lut_id_prop_ == 0)
367     return;
368
369   uint32_t lut_blob_id = 0;
370
371   drmModeCreatePropertyBlob(
372       gpu_fd_, lut, sizeof(struct drm_color_lut) * lut_size_, &lut_blob_id);
373   if (lut_blob_id == 0) {
374     return;
375   }
376
377   drmModeObjectSetProperty(gpu_fd_, crtc_id_, DRM_MODE_OBJECT_CRTC,
378                            lut_id_prop_, lut_blob_id);
379   drmModeDestroyPropertyBlob(gpu_fd_, lut_blob_id);
380 }
381
382 float DrmDisplay::TransformContrastBrightness(float value, float brightness,
383                                               float contrast) const {
384   float result;
385   result = (value - 0.5) * contrast + 0.5 + brightness;
386
387   if (result < 0.0)
388     result = 0.0;
389   if (result > 1.0)
390     result = 1.0;
391   return result;
392 }
393
394 float DrmDisplay::TransformGamma(float value, float gamma) const {
395   float result;
396
397   result = pow(value, gamma);
398   if (result < 0.0)
399     result = 0.0;
400   if (result > 1.0)
401     result = 1.0;
402
403   return result;
404 }
405
406 void DrmDisplay::SetColorCorrection(struct gamma_colors gamma,
407                                     uint32_t contrast_c,
408                                     uint32_t brightness_c) const {
409   struct drm_color_lut *lut;
410   float brightness[3];
411   float contrast[3];
412   uint8_t temp[3];
413
414   /* reset lut when contrast and brightness are all 0 */
415   if (contrast_c == 0 && brightness_c == 0) {
416     lut = NULL;
417     ApplyPendingLUT(lut);
418     free(lut);
419     return;
420   }
421
422   lut =
423       (struct drm_color_lut *)malloc(sizeof(struct drm_color_lut) * lut_size_);
424   if (!lut) {
425     ETRACE("Cannot allocate LUT memory");
426     return;
427   }
428
429   /* Unpack brightness values for each channel */
430   temp[0] = (brightness_c >> 16) & 0xFF;
431   temp[1] = (brightness_c >> 8) & 0xFF;
432   temp[2] = (brightness_c)&0xFF;
433
434   /* Map brightness from -128 - 127 range into -0.5 - 0.5 range */
435   brightness[0] = (float)(temp[0]) / 255 - 0.5;
436   brightness[1] = (float)(temp[1]) / 255 - 0.5;
437   brightness[2] = (float)(temp[2]) / 255 - 0.5;
438
439   /* Unpack contrast values for each channel */
440   temp[0] = (contrast_c >> 16) & 0xFF;
441   temp[1] = (contrast_c >> 8) & 0xFF;
442   temp[2] = (contrast_c)&0xFF;
443
444   /* Map contrast from 0 - 255 range into 0.0 - 2.0 range */
445   contrast[0] = (float)(temp[0]) / 128;
446   contrast[1] = (float)(temp[1]) / 128;
447   contrast[2] = (float)(temp[2]) / 128;
448
449   for (uint64_t i = 0; i < lut_size_; i++) {
450     /* Set lut[0] as 0 always as the darkest color should has brightness 0 */
451     if (i == 0) {
452       lut[i].red = 0;
453       lut[i].green = 0;
454       lut[i].blue = 0;
455       continue;
456     }
457
458     lut[i].red = 0xFFFF * TransformGamma(TransformContrastBrightness(
459                                              (float)(i) / lut_size_,
460                                              brightness[0], contrast[0]),
461                                          gamma.red);
462     lut[i].green = 0xFFFF * TransformGamma(TransformContrastBrightness(
463                                                (float)(i) / lut_size_,
464                                                brightness[1], contrast[1]),
465                                            gamma.green);
466     lut[i].blue = 0xFFFF * TransformGamma(TransformContrastBrightness(
467                                               (float)(i) / lut_size_,
468                                               brightness[2], contrast[2]),
469                                           gamma.blue);
470   }
471
472   ApplyPendingLUT(lut);
473   free(lut);
474 }
475
476 bool DrmDisplay::ApplyPendingModeset(drmModeAtomicReqPtr property_set) {
477   if (old_blob_id_) {
478     drmModeDestroyPropertyBlob(gpu_fd_, old_blob_id_);
479     old_blob_id_ = 0;
480   }
481
482   drmModeCreatePropertyBlob(gpu_fd_, &current_mode_, sizeof(drmModeModeInfo),
483                             &blob_id_);
484   if (blob_id_ == 0)
485     return false;
486
487   bool active = true;
488
489   int ret = drmModeAtomicAddProperty(property_set, crtc_id_, mode_id_prop_,
490                                      blob_id_) < 0 ||
491             drmModeAtomicAddProperty(property_set, connector_, crtc_prop_,
492                                      crtc_id_) < 0 ||
493             drmModeAtomicAddProperty(property_set, crtc_id_, active_prop_,
494                                      active) < 0;
495   if (ret) {
496     ETRACE("Failed to add blob %d to pset", blob_id_);
497     return false;
498   }
499
500   old_blob_id_ = blob_id_;
501   blob_id_ = 0;
502
503   return true;
504 }
505
506 bool DrmDisplay::GetFence(drmModeAtomicReqPtr property_set,
507                           int32_t *out_fence) {
508   int ret = drmModeAtomicAddProperty(property_set, crtc_id_,
509                                      out_fence_ptr_prop_, (uintptr_t)out_fence);
510   if (ret < 0) {
511     ETRACE("Failed to add OUT_FENCE_PTR property to pset: %d", ret);
512     return false;
513   }
514
515   return true;
516 }
517
518 void DrmDisplay::Disable(const DisplayPlaneStateList &composition_planes) {
519   ScopedDrmAtomicReqPtr pset(drmModeAtomicAlloc());
520   if (pset) {
521     bool active = false;
522     int ret = drmModeAtomicAddProperty(pset.get(), crtc_id_, active_prop_,
523                                        active) < 0;
524     if (ret) {
525       ETRACE("Failed to set display to inactive");
526     }
527
528     for (const DisplayPlaneState &comp_plane : composition_planes) {
529       DrmPlane *plane = static_cast<DrmPlane *>(comp_plane.plane());
530       plane->SetEnabled(false);
531       plane->Disable(pset.get());
532     }
533
534     ret = drmModeAtomicCommit(gpu_fd_, pset.get(),
535                               DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
536     if (ret)
537       ETRACE("Failed to disable display:%s\n", PRINTERROR());
538   } else {
539     ETRACE("Failed to allocate property set %d", -ENOMEM);
540   }
541
542   drmModeConnectorSetProperty(gpu_fd_, connector_, dpms_prop_,
543                               DRM_MODE_DPMS_OFF);
544 }
545
546 bool DrmDisplay::PopulatePlanes(
547     std::unique_ptr<DisplayPlane> &primary_plane,
548     std::unique_ptr<DisplayPlane> &cursor_plane,
549     std::vector<std::unique_ptr<DisplayPlane>> &overlay_planes) {
550   ScopedDrmPlaneResPtr plane_resources(drmModeGetPlaneResources(gpu_fd_));
551   if (!plane_resources) {
552     ETRACE("Failed to get plane resources");
553     return false;
554   }
555
556   uint32_t num_planes = plane_resources->count_planes;
557   uint32_t pipe_bit = 1 << pipe_;
558   std::set<uint32_t> plane_ids;
559   for (uint32_t i = 0; i < num_planes; ++i) {
560     ScopedDrmPlanePtr drm_plane(
561         drmModeGetPlane(gpu_fd_, plane_resources->planes[i]));
562     if (!drm_plane) {
563       ETRACE("Failed to get plane ");
564       return false;
565     }
566
567     if (!(pipe_bit & drm_plane->possible_crtcs))
568       continue;
569
570     uint32_t formats_size = drm_plane->count_formats;
571     plane_ids.insert(drm_plane->plane_id);
572     std::unique_ptr<DrmPlane> plane(
573         CreatePlane(drm_plane->plane_id, drm_plane->possible_crtcs));
574     std::vector<uint32_t> supported_formats(formats_size);
575     for (uint32_t j = 0; j < formats_size; j++)
576       supported_formats[j] = drm_plane->formats[j];
577
578     if (plane->Initialize(gpu_fd_, supported_formats)) {
579       if (plane->type() == DRM_PLANE_TYPE_CURSOR) {
580         cursor_plane.reset(plane.release());
581       } else if (plane->type() == DRM_PLANE_TYPE_PRIMARY) {
582         plane->SetEnabled(true);
583         primary_plane.reset(plane.release());
584       } else if (plane->type() == DRM_PLANE_TYPE_OVERLAY) {
585         overlay_planes.emplace_back(plane.release());
586       }
587     }
588   }
589
590   if (!primary_plane) {
591     ETRACE("Failed to get primary plane for display %d", crtc_id_);
592     return false;
593   }
594
595   // We expect layers to be in ascending order.
596   std::sort(
597       overlay_planes.begin(), overlay_planes.end(),
598       [](const std::unique_ptr<DisplayPlane> &l,
599          const std::unique_ptr<DisplayPlane> &r) { return l->id() < r->id(); });
600
601   return true;
602 }
603
604 bool DrmDisplay::TestCommit(
605     const std::vector<OverlayPlane> &commit_planes) const {
606   ScopedDrmAtomicReqPtr pset(drmModeAtomicAlloc());
607   for (auto i = commit_planes.begin(); i != commit_planes.end(); i++) {
608     DrmPlane *plane = static_cast<DrmPlane *>(i->plane);
609     if (!(plane->UpdateProperties(pset.get(), crtc_id_, i->layer, true))) {
610       return false;
611     }
612   }
613
614   if (drmModeAtomicCommit(gpu_fd_, pset.get(), DRM_MODE_ATOMIC_TEST_ONLY,
615                           NULL)) {
616     IDISPLAYMANAGERTRACE("Test Commit Failed. %s ", PRINTERROR());
617     return false;
618   }
619
620   return true;
621 }
622
623 std::unique_ptr<DrmPlane> DrmDisplay::CreatePlane(uint32_t plane_id,
624                                                   uint32_t possible_crtcs) {
625   return std::unique_ptr<DrmPlane>(new DrmPlane(plane_id, possible_crtcs));
626 }
627
628 }  // namespace hwcomposer