• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
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 #define LOG_TAG "drmhwc"
18 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
19 
20 #include "HwcDisplay.h"
21 
22 #include <cinttypes>
23 
24 #include <ui/ColorSpace.h>
25 
26 #include "backend/Backend.h"
27 #include "backend/BackendManager.h"
28 #include "bufferinfo/BufferInfoGetter.h"
29 #include "compositor/DisplayInfo.h"
30 #include "drm/DrmConnector.h"
31 #include "drm/DrmDisplayPipeline.h"
32 #include "drm/DrmHwc.h"
33 #include "utils/log.h"
34 #include "utils/properties.h"
35 
36 using ::android::DrmDisplayPipeline;
37 using ColorGamut = ::android::ColorSpace;
38 
39 namespace android {
40 
41 namespace {
42 
43 constexpr int kCtmRows = 3;
44 constexpr int kCtmCols = 3;
45 
46 constexpr std::array<float, 16> kIdentityMatrix = {
47     1.0F, 0.0F, 0.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F,
48     0.0F, 0.0F, 1.0F, 0.0F, 0.0F, 0.0F, 0.0F, 1.0F,
49 };
50 
float_equals(float a,float b)51 bool float_equals(float a, float b) {
52   const float epsilon = 0.001F;
53   return std::abs(a - b) < epsilon;
54 }
55 
To3132FixPt(float in)56 uint64_t To3132FixPt(float in) {
57   constexpr uint64_t kSignMask = (1ULL << 63);
58   constexpr uint64_t kValueMask = ~(1ULL << 63);
59   constexpr auto kValueScale = static_cast<float>(1ULL << 32);
60   if (in < 0)
61     return (static_cast<uint64_t>(-in * kValueScale) & kValueMask) | kSignMask;
62   return static_cast<uint64_t>(in * kValueScale) & kValueMask;
63 }
64 
TransformHasOffsetValue(const float * matrix)65 bool TransformHasOffsetValue(const float *matrix) {
66   for (int i = 12; i < 14; i++) {
67     if (!float_equals(matrix[i], 0.F)) {
68       ALOGW("DRM API does not support CTM with offsets.");
69       return true;
70     }
71   }
72   return false;
73 }
74 
ToColorTransform(const std::array<float,16> & color_transform_matrix)75 auto ToColorTransform(const std::array<float, 16> &color_transform_matrix) {
76   /* HAL provides a 4x4 float type matrix:
77    * | 0  1  2  3|
78    * | 4  5  6  7|
79    * | 8  9 10 11|
80    * |12 13 14 15|
81    *
82    * R_out = R*0 + G*4 + B*8 + 12
83    * G_out = R*1 + G*5 + B*9 + 13
84    * B_out = R*2 + G*6 + B*10 + 14
85    *
86    * DRM expects a 3x3 s31.32 fixed point matrix:
87    * out   matrix    in
88    * |R|   |0 1 2|   |R|
89    * |G| = |3 4 5| x |G|
90    * |B|   |6 7 8|   |B|
91    *
92    * R_out = R*0 + G*1 + B*2
93    * G_out = R*3 + G*4 + B*5
94    * B_out = R*6 + G*7 + B*8
95    */
96   auto color_matrix = std::make_shared<drm_color_ctm>();
97   for (int i = 0; i < kCtmCols; i++) {
98     for (int j = 0; j < kCtmRows; j++) {
99       constexpr int kInCtmRows = 4;
100       color_matrix->matrix[(i * kCtmRows) + j] = To3132FixPt(
101           color_transform_matrix[(j * kInCtmRows) + i]);
102     }
103   }
104   return color_matrix;
105 }
106 
107 }  // namespace
108 
DumpDelta(HwcDisplay::Stats delta)109 std::string HwcDisplay::DumpDelta(HwcDisplay::Stats delta) {
110   if (delta.total_pixops_ == 0)
111     return "No stats yet";
112   auto ratio = 1.0 - (double(delta.gpu_pixops_) / double(delta.total_pixops_));
113 
114   std::stringstream ss;
115   ss << " Total frames count: " << delta.total_frames_ << "\n"
116      << " Failed to test commit frames: " << delta.failed_kms_validate_ << "\n"
117      << " Failed to commit frames: " << delta.failed_kms_present_ << "\n"
118      << ((delta.failed_kms_present_ > 0)
119              ? " !!! Internal failure, FIX it please\n"
120              : "")
121      << " Flattened frames: " << delta.frames_flattened_ << "\n"
122      << " Pixel operations (free units)"
123      << " : [TOTAL: " << delta.total_pixops_ << " / GPU: " << delta.gpu_pixops_
124      << "]\n"
125      << " Composition efficiency: " << ratio;
126 
127   return ss.str();
128 }
129 
Dump()130 std::string HwcDisplay::Dump() {
131   auto connector_name = IsInHeadlessMode()
132                             ? std::string("NULL-DISPLAY")
133                             : GetPipe().connector->Get()->GetName();
134 
135   std::stringstream ss;
136   ss << "- Display on: " << connector_name << "\n"
137      << "Statistics since system boot:\n"
138      << DumpDelta(total_stats_) << "\n\n"
139      << "Statistics since last dumpsys request:\n"
140      << DumpDelta(total_stats_.minus(prev_stats_)) << "\n\n";
141 
142   memcpy(&prev_stats_, &total_stats_, sizeof(Stats));
143   return ss.str();
144 }
145 
HwcDisplay(hwc2_display_t handle,HWC2::DisplayType type,DrmHwc * hwc)146 HwcDisplay::HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type,
147                        DrmHwc *hwc)
148     : hwc_(hwc), handle_(handle), type_(type), client_layer_(this) {
149   if (type_ == HWC2::DisplayType::Virtual) {
150     writeback_layer_ = std::make_unique<HwcLayer>(this);
151   }
152 
153   identity_color_matrix_ = ToColorTransform(kIdentityMatrix);
154 }
155 
SetColorTransformMatrix(const std::array<float,16> & color_transform_matrix)156 void HwcDisplay::SetColorTransformMatrix(
157     const std::array<float, 16> &color_transform_matrix) {
158   const bool is_identity = std::equal(color_transform_matrix.begin(),
159                                       color_transform_matrix.end(),
160                                       kIdentityMatrix.begin(), float_equals);
161   color_transform_hint_ = is_identity ? HAL_COLOR_TRANSFORM_IDENTITY
162                                       : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
163   ctm_has_offset_ = false;
164 
165   if (color_transform_hint_ == is_identity) {
166     SetColorMatrixToIdentity();
167   } else {
168     if (TransformHasOffsetValue(color_transform_matrix.data()))
169       ctm_has_offset_ = true;
170 
171     color_matrix_ = ToColorTransform(color_transform_matrix);
172   }
173 }
174 
SetColorMatrixToIdentity()175 void HwcDisplay::SetColorMatrixToIdentity() {
176   color_matrix_ = identity_color_matrix_;
177   color_transform_hint_ = HAL_COLOR_TRANSFORM_IDENTITY;
178 }
179 
~HwcDisplay()180 HwcDisplay::~HwcDisplay() {
181   Deinit();
182 };
183 
GetConfig(hwc2_config_t config_id) const184 auto HwcDisplay::GetConfig(hwc2_config_t config_id) const
185     -> const HwcDisplayConfig * {
186   auto config_iter = configs_.hwc_configs.find(config_id);
187   if (config_iter == configs_.hwc_configs.end()) {
188     return nullptr;
189   }
190   return &config_iter->second;
191 }
192 
GetCurrentConfig() const193 auto HwcDisplay::GetCurrentConfig() const -> const HwcDisplayConfig * {
194   return GetConfig(configs_.active_config_id);
195 }
196 
GetLastRequestedConfig() const197 auto HwcDisplay::GetLastRequestedConfig() const -> const HwcDisplayConfig * {
198   return GetConfig(staged_mode_config_id_.value_or(configs_.active_config_id));
199 }
200 
SetOutputType(uint32_t hdr_output_type)201 HWC2::Error HwcDisplay::SetOutputType(uint32_t hdr_output_type) {
202   switch (hdr_output_type) {
203     case 3: { // HDR10
204       auto ret = SetHdrOutputMetadata(ui::Hdr::HDR10);
205       if (ret != HWC2::Error::None)
206         return ret;
207       min_bpc_ = 8;
208       colorspace_ = Colorspace::kBt2020Rgb;
209       break;
210     }
211     case 1: { // SYSTEM
212       std::vector<ui::Hdr> hdr_types;
213       GetEdid()->GetSupportedHdrTypes(hdr_types);
214       if (!hdr_types.empty()) {
215         auto ret = SetHdrOutputMetadata(hdr_types.front());
216         if (ret != HWC2::Error::None)
217           return ret;
218         min_bpc_ = 8;
219         colorspace_ = Colorspace::kBt2020Rgb;
220         break;
221       } else {
222         [[fallthrough]];
223       }
224     }
225     case 0:  // INVALID
226       [[fallthrough]];
227     case 2:  // SDR
228       [[fallthrough]];
229     default:
230       hdr_metadata_ = std::make_shared<hdr_output_metadata>();
231       min_bpc_ = 6;
232       colorspace_ = Colorspace::kDefault;
233   }
234 
235   return HWC2::Error::None;
236 }
237 
SetConfig(hwc2_config_t config)238 HwcDisplay::ConfigError HwcDisplay::SetConfig(hwc2_config_t config) {
239   const HwcDisplayConfig *new_config = GetConfig(config);
240   if (new_config == nullptr) {
241     ALOGE("Could not find active mode for %u", config);
242     return ConfigError::kBadConfig;
243   }
244 
245   const HwcDisplayConfig *current_config = GetCurrentConfig();
246 
247   const uint32_t width = new_config->mode.GetRawMode().hdisplay;
248   const uint32_t height = new_config->mode.GetRawMode().vdisplay;
249 
250   std::optional<LayerData> modeset_layer_data;
251   // If a client layer has already been provided, and its size matches the
252   // new config, use it for the modeset.
253   if (client_layer_.IsLayerUsableAsDevice() && current_config &&
254       current_config->mode.GetRawMode().hdisplay == width &&
255       current_config->mode.GetRawMode().vdisplay == height) {
256     ALOGV("Use existing client_layer for blocking config.");
257     modeset_layer_data = client_layer_.GetLayerData();
258   } else {
259     ALOGV("Allocate modeset buffer.");
260     auto modeset_buffer =  //
261         GetPipe().device->CreateBufferForModeset(width, height);
262     if (modeset_buffer) {
263       auto modeset_layer = std::make_unique<HwcLayer>(this);
264       HwcLayer::LayerProperties properties;
265       properties.slot_buffer = {
266           .slot_id = 0,
267           .bi = modeset_buffer,
268       };
269       properties.active_slot = {
270           .slot_id = 0,
271           .fence = {},
272       };
273       properties.blend_mode = BufferBlendMode::kNone;
274       modeset_layer->SetLayerProperties(properties);
275       modeset_layer->PopulateLayerData();
276       modeset_layer_data = modeset_layer->GetLayerData();
277     }
278   }
279 
280   ALOGV("Create modeset commit.");
281   SetOutputType(new_config->output_type);
282 
283   // Create atomic commit args for a blocking modeset. There's no need to do a
284   // separate test commit, since the commit does a test anyways.
285   AtomicCommitArgs commit_args = CreateModesetCommit(new_config,
286                                                      modeset_layer_data);
287   commit_args.blocking = true;
288   int ret = GetPipe().atomic_state_manager->ExecuteAtomicCommit(commit_args);
289 
290   if (ret) {
291     ALOGE("Blocking config failed: %d", ret);
292     return HwcDisplay::ConfigError::kConfigFailed;
293   }
294 
295   ALOGV("Blocking config succeeded.");
296   configs_.active_config_id = config;
297   staged_mode_config_id_.reset();
298   vsync_worker_->SetVsyncPeriodNs(new_config->mode.GetVSyncPeriodNs());
299   // set new vsync period
300   return ConfigError::kNone;
301 }
302 
QueueConfig(hwc2_config_t config,int64_t desired_time,bool seamless,QueuedConfigTiming * out_timing)303 auto HwcDisplay::QueueConfig(hwc2_config_t config, int64_t desired_time,
304                              bool seamless, QueuedConfigTiming *out_timing)
305     -> ConfigError {
306   if (configs_.hwc_configs.count(config) == 0) {
307     ALOGE("Could not find active mode for %u", config);
308     return ConfigError::kBadConfig;
309   }
310 
311   // TODO: Add support for seamless configuration changes.
312   if (seamless) {
313     return ConfigError::kSeamlessNotAllowed;
314   }
315 
316   // Request a refresh from the client one vsync period before the desired
317   // time, or simply at the desired time if there is no active configuration.
318   const HwcDisplayConfig *current_config = GetCurrentConfig();
319   out_timing->refresh_time_ns = desired_time -
320                                 (current_config
321                                      ? current_config->mode.GetVSyncPeriodNs()
322                                      : 0);
323   out_timing->new_vsync_time_ns = desired_time;
324 
325   // Queue the config change timing to be consistent with the requested
326   // refresh time.
327   staged_mode_change_time_ = out_timing->refresh_time_ns;
328   staged_mode_config_id_ = config;
329 
330   // Enable vsync events until the mode has been applied.
331   vsync_worker_->SetVsyncTimestampTracking(true);
332 
333   return ConfigError::kNone;
334 }
335 
ValidateStagedComposition()336 auto HwcDisplay::ValidateStagedComposition() -> std::vector<ChangedLayer> {
337   if (IsInHeadlessMode()) {
338     return {};
339   }
340 
341   /* In current drm_hwc design in case previous frame layer was not validated as
342    * a CLIENT, it is used by display controller (Front buffer). We have to store
343    * this state to provide the CLIENT with the release fences for such buffers.
344    */
345   for (auto &l : layers_) {
346     l.second.SetPriorBufferScanOutFlag(l.second.GetValidatedType() !=
347                                        HWC2::Composition::Client);
348   }
349 
350   // ValidateDisplay returns the number of layers that may be changed.
351   uint32_t num_types = 0;
352   uint32_t num_requests = 0;
353   backend_->ValidateDisplay(this, &num_types, &num_requests);
354 
355   if (num_types == 0) {
356     return {};
357   }
358 
359   // Iterate through the layers to find which layers actually changed.
360   std::vector<ChangedLayer> changed_layers;
361   for (auto &l : layers_) {
362     if (l.second.IsTypeChanged()) {
363       changed_layers.emplace_back(l.first, l.second.GetValidatedType());
364     }
365   }
366   return changed_layers;
367 }
368 
GetDisplayBoundsMm()369 auto HwcDisplay::GetDisplayBoundsMm() -> std::pair<int32_t, int32_t> {
370 
371   const auto bounds = GetEdid()->GetBoundsMm();
372   if (bounds.first > 0 || bounds.second > 0) {
373     return bounds;
374   }
375 
376   ALOGE("Failed to get display bounds for d=%d\n", int(handle_));
377   // mm_width and mm_height are unreliable. so only provide mm_width to avoid
378   // wrong dpi computations or other use of the values.
379   return {configs_.mm_width, -1};
380 }
381 
AcceptValidatedComposition()382 auto HwcDisplay::AcceptValidatedComposition() -> void {
383   for (auto &[_, layer] : layers_) {
384     layer.AcceptTypeChange();
385   }
386 }
387 
PresentStagedComposition(std::optional<int64_t> desired_present_time,SharedFd & out_present_fence,std::vector<ReleaseFence> & out_release_fences)388 auto HwcDisplay::PresentStagedComposition(
389     std::optional<int64_t> desired_present_time, SharedFd &out_present_fence,
390     std::vector<ReleaseFence> &out_release_fences) -> bool {
391   if (IsInHeadlessMode()) {
392     return true;
393   }
394   HWC2::Error ret{};
395 
396   ++total_stats_.total_frames_;
397 
398   uint32_t vperiod_ns = 0;
399   GetDisplayVsyncPeriod(&vperiod_ns);
400 
401   if (desired_present_time && vperiod_ns != 0) {
402     // DRM atomic uAPI does not support specifying that a commit should be
403     // applied to some future vsync. Until such uAPI is available, sleep in
404     // userspace until the next expected vsync time is consistent with the
405     // desired present time.
406     WaitForPresentTime(desired_present_time.value(), vperiod_ns);
407   }
408 
409   AtomicCommitArgs a_args{};
410   ret = CreateComposition(a_args);
411 
412   if (ret != HWC2::Error::None)
413     ++total_stats_.failed_kms_present_;
414 
415   if (ret == HWC2::Error::BadLayer) {
416     // Can we really have no client or device layers?
417     return true;
418   }
419   if (ret != HWC2::Error::None)
420     return false;
421 
422   out_present_fence = a_args.out_fence;
423 
424   // Reset the color matrix so we don't apply it over and over again.
425   color_matrix_ = {};
426 
427   ++frame_no_;
428 
429   if (!out_present_fence) {
430     return true;
431   }
432 
433   for (auto &l : layers_) {
434     if (l.second.GetPriorBufferScanOutFlag()) {
435       out_release_fences.emplace_back(l.first, out_present_fence);
436     }
437   }
438 
439   return true;
440 }
441 
SetPipeline(std::shared_ptr<DrmDisplayPipeline> pipeline)442 void HwcDisplay::SetPipeline(std::shared_ptr<DrmDisplayPipeline> pipeline) {
443   Deinit();
444 
445   pipeline_ = std::move(pipeline);
446 
447   if (pipeline_ != nullptr || handle_ == kPrimaryDisplay) {
448     Init();
449     hwc_->ScheduleHotplugEvent(handle_, DrmHwc::kConnected);
450   } else {
451     hwc_->ScheduleHotplugEvent(handle_, DrmHwc::kDisconnected);
452   }
453 }
454 
Deinit()455 void HwcDisplay::Deinit() {
456   if (pipeline_ != nullptr) {
457     AtomicCommitArgs a_args{};
458     a_args.composition = std::make_shared<DrmKmsPlan>();
459     GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
460     a_args.composition = {};
461     a_args.active = false;
462     GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
463 
464     current_plan_.reset();
465     backend_.reset();
466     if (flatcon_) {
467       flatcon_->StopThread();
468       flatcon_.reset();
469     }
470   }
471 
472   if (vsync_worker_) {
473     vsync_worker_->StopThread();
474     vsync_worker_ = {};
475   }
476 
477   client_layer_.ClearSlots();
478 }
479 
Init()480 HWC2::Error HwcDisplay::Init() {
481   ChosePreferredConfig();
482 
483   if (type_ != HWC2::DisplayType::Virtual) {
484     vsync_worker_ = VSyncWorker::CreateInstance(pipeline_);
485     if (!vsync_worker_) {
486       ALOGE("Failed to create event worker for d=%d\n", int(handle_));
487       return HWC2::Error::BadDisplay;
488     }
489   }
490 
491   if (!IsInHeadlessMode()) {
492     auto ret = BackendManager::GetInstance().SetBackendForDisplay(this);
493     if (ret) {
494       ALOGE("Failed to set backend for d=%d %d\n", int(handle_), ret);
495       return HWC2::Error::BadDisplay;
496     }
497     auto flatcbk = (struct FlatConCallbacks){
498         .trigger = [this]() { hwc_->SendRefreshEventToClient(handle_); }};
499     flatcon_ = FlatteningController::CreateInstance(flatcbk);
500   }
501 
502   HwcLayer::LayerProperties lp;
503   lp.blend_mode = BufferBlendMode::kPreMult;
504   client_layer_.SetLayerProperties(lp);
505 
506   SetColorMatrixToIdentity();
507 
508   return HWC2::Error::None;
509 }
510 
getDisplayPhysicalOrientation()511 std::optional<PanelOrientation> HwcDisplay::getDisplayPhysicalOrientation() {
512   if (IsInHeadlessMode()) {
513     // The pipeline can be nullptr in headless mode, so return the default
514     // "normal" mode.
515     return PanelOrientation::kModePanelOrientationNormal;
516   }
517 
518   DrmDisplayPipeline &pipeline = GetPipe();
519   if (pipeline.connector == nullptr || pipeline.connector->Get() == nullptr) {
520     ALOGW(
521         "No display pipeline present to query the panel orientation property.");
522     return {};
523   }
524 
525   return pipeline.connector->Get()->GetPanelOrientation();
526 }
527 
ChosePreferredConfig()528 HWC2::Error HwcDisplay::ChosePreferredConfig() {
529   HWC2::Error err{};
530   if (type_ == HWC2::DisplayType::Virtual) {
531     configs_.GenFakeMode(virtual_disp_width_, virtual_disp_height_);
532   } else if (!IsInHeadlessMode()) {
533     err = configs_.Update(*pipeline_->connector->Get());
534   } else {
535     configs_.GenFakeMode(0, 0);
536   }
537   if (!IsInHeadlessMode() && err != HWC2::Error::None) {
538     return HWC2::Error::BadDisplay;
539   }
540 
541   return SetActiveConfig(configs_.preferred_config_id);
542 }
543 
CreateLayer(ILayerId new_layer_id)544 auto HwcDisplay::CreateLayer(ILayerId new_layer_id) -> bool {
545   if (layers_.count(new_layer_id) > 0)
546     return false;
547 
548   layers_.emplace(new_layer_id, HwcLayer(this));
549 
550   return true;
551 }
552 
DestroyLayer(ILayerId layer_id)553 auto HwcDisplay::DestroyLayer(ILayerId layer_id) -> bool {
554   auto count = layers_.erase(layer_id);
555   return count != 0;
556 }
557 
GetActiveConfig(hwc2_config_t * config) const558 HWC2::Error HwcDisplay::GetActiveConfig(hwc2_config_t *config) const {
559   // If a config has been queued, it is considered the "active" config.
560   const HwcDisplayConfig *hwc_config = GetLastRequestedConfig();
561   if (hwc_config == nullptr)
562     return HWC2::Error::BadConfig;
563 
564   *config = hwc_config->id;
565   return HWC2::Error::None;
566 }
567 
GetColorModes(uint32_t * num_modes,int32_t * modes)568 HWC2::Error HwcDisplay::GetColorModes(uint32_t *num_modes, int32_t *modes) {
569   if (IsInHeadlessMode()) {
570     *num_modes = 1;
571     if (modes)
572       modes[0] = HAL_COLOR_MODE_NATIVE;
573     return HWC2::Error::None;
574   }
575 
576   if (!modes) {
577     std::vector<Colormode> temp_modes;
578     GetEdid()->GetColorModes(temp_modes);
579     *num_modes = temp_modes.size();
580     return HWC2::Error::None;
581   }
582 
583   std::vector<Colormode> temp_modes;
584   std::vector<int32_t> out_modes(modes, modes + *num_modes);
585   GetEdid()->GetColorModes(temp_modes);
586   if (temp_modes.empty()) {
587     out_modes.emplace_back(HAL_COLOR_MODE_NATIVE);
588     return HWC2::Error::None;
589   }
590 
591   for (auto &c : temp_modes)
592     out_modes.emplace_back(static_cast<int32_t>(c));
593 
594   return HWC2::Error::None;
595 }
596 
GetDisplayAttribute(hwc2_config_t config,int32_t attribute_in,int32_t * value)597 HWC2::Error HwcDisplay::GetDisplayAttribute(hwc2_config_t config,
598                                             int32_t attribute_in,
599                                             int32_t *value) {
600   int conf = static_cast<int>(config);
601 
602   if (configs_.hwc_configs.count(conf) == 0) {
603     ALOGE("Could not find mode #%d", conf);
604     return HWC2::Error::BadConfig;
605   }
606 
607   auto &hwc_config = configs_.hwc_configs[conf];
608 
609   static const int32_t kUmPerInch = 25400;
610   auto mm_width = configs_.mm_width;
611   auto attribute = static_cast<HWC2::Attribute>(attribute_in);
612   switch (attribute) {
613     case HWC2::Attribute::Width:
614       *value = static_cast<int>(hwc_config.mode.GetRawMode().hdisplay);
615       break;
616     case HWC2::Attribute::Height:
617       *value = static_cast<int>(hwc_config.mode.GetRawMode().vdisplay);
618       break;
619     case HWC2::Attribute::VsyncPeriod:
620       // in nanoseconds
621       *value = hwc_config.mode.GetVSyncPeriodNs();
622       break;
623     case HWC2::Attribute::DpiY:
624       *value = GetEdid()->GetDpiY();
625       if (*value < 0) {
626         // default to raw mode DpiX for both x and y when no good value
627         // can be provided from edid.
628         *value = mm_width ? int(hwc_config.mode.GetRawMode().hdisplay *
629                                 kUmPerInch / mm_width)
630                           : -1;
631       }
632       break;
633     case HWC2::Attribute::DpiX:
634       // Dots per 1000 inches
635       *value = GetEdid()->GetDpiX();
636       if (*value < 0) {
637         // default to raw mode DpiX for both x and y when no good value
638         // can be provided from edid.
639         *value = mm_width ? int(hwc_config.mode.GetRawMode().hdisplay *
640                                 kUmPerInch / mm_width)
641                           : -1;
642       }
643       break;
644 #if __ANDROID_API__ > 29
645     case HWC2::Attribute::ConfigGroup:
646       /* Dispite ConfigGroup is a part of HWC2.4 API, framework
647        * able to request it even if service @2.1 is used */
648       *value = int(hwc_config.group_id);
649       break;
650 #endif
651     default:
652       *value = -1;
653       return HWC2::Error::BadConfig;
654   }
655   return HWC2::Error::None;
656 }
657 
LegacyGetDisplayConfigs(uint32_t * num_configs,hwc2_config_t * configs)658 HWC2::Error HwcDisplay::LegacyGetDisplayConfigs(uint32_t *num_configs,
659                                                 hwc2_config_t *configs) {
660   uint32_t idx = 0;
661   for (auto &hwc_config : configs_.hwc_configs) {
662     if (hwc_config.second.disabled) {
663       continue;
664     }
665 
666     if (configs != nullptr) {
667       if (idx >= *num_configs) {
668         break;
669       }
670       configs[idx] = hwc_config.second.id;
671     }
672 
673     idx++;
674   }
675   *num_configs = idx;
676   return HWC2::Error::None;
677 }
678 
GetDisplayName(uint32_t * size,char * name)679 HWC2::Error HwcDisplay::GetDisplayName(uint32_t *size, char *name) {
680   std::ostringstream stream;
681   if (IsInHeadlessMode()) {
682     stream << "null-display";
683   } else {
684     stream << "display-" << GetPipe().connector->Get()->GetId();
685   }
686   auto string = stream.str();
687   auto length = string.length();
688   if (!name) {
689     *size = length;
690     return HWC2::Error::None;
691   }
692 
693   *size = std::min<uint32_t>(static_cast<uint32_t>(length - 1), *size);
694   strncpy(name, string.c_str(), *size);
695   return HWC2::Error::None;
696 }
697 
GetDisplayType(int32_t * type)698 HWC2::Error HwcDisplay::GetDisplayType(int32_t *type) {
699   *type = static_cast<int32_t>(type_);
700   return HWC2::Error::None;
701 }
702 
GetHdrCapabilities(uint32_t * num_types,int32_t * types,float * max_luminance,float * max_average_luminance,float * min_luminance)703 HWC2::Error HwcDisplay::GetHdrCapabilities(uint32_t *num_types, int32_t *types,
704                                            float *max_luminance,
705                                            float *max_average_luminance,
706                                            float *min_luminance) {
707   if (IsInHeadlessMode()) {
708     *num_types = 0;
709     return HWC2::Error::None;
710   }
711 
712   if (!types) {
713     std::vector<ui::Hdr> temp_types;
714     float lums[3] = {0.F};
715     GetEdid()->GetHdrCapabilities(temp_types, &lums[0], &lums[1], &lums[2]);
716     *num_types = temp_types.size();
717     return HWC2::Error::None;
718   }
719 
720   std::vector<ui::Hdr> temp_types;
721   std::vector<int32_t> out_types(types, types + *num_types);
722   GetEdid()->GetHdrCapabilities(temp_types, max_luminance,
723                                 max_average_luminance, min_luminance);
724   for (auto &t : temp_types) {
725     switch (t) {
726       case ui::Hdr::HDR10:
727         out_types.emplace_back(HAL_HDR_HDR10);
728         break;
729       case ui::Hdr::HLG:
730         out_types.emplace_back(HAL_HDR_HLG);
731         break;
732       default:
733         // Ignore any other HDR types
734         break;
735     }
736   }
737   return HWC2::Error::None;
738 }
739 
CreateModesetCommit(const HwcDisplayConfig * config,const std::optional<LayerData> & modeset_layer)740 AtomicCommitArgs HwcDisplay::CreateModesetCommit(
741     const HwcDisplayConfig *config,
742     const std::optional<LayerData> &modeset_layer) {
743   AtomicCommitArgs args{};
744 
745   args.color_matrix = color_matrix_;
746   args.content_type = content_type_;
747   args.colorspace = colorspace_;
748   args.hdr_metadata = hdr_metadata_;
749   args.min_bpc = min_bpc_;
750 
751   std::vector<LayerData> composition_layers;
752   if (modeset_layer) {
753     composition_layers.emplace_back(modeset_layer.value());
754   }
755 
756   if (composition_layers.empty()) {
757     ALOGW("Attempting to create a modeset commit without a layer.");
758   }
759 
760   args.display_mode = config->mode;
761   args.active = true;
762   args.composition = DrmKmsPlan::CreateDrmKmsPlan(GetPipe(),
763                                                   std::move(
764                                                       composition_layers));
765   ALOGW_IF(!args.composition, "No composition for blocking modeset");
766 
767   return args;
768 }
769 
WaitForPresentTime(int64_t present_time,uint32_t vsync_period_ns)770 void HwcDisplay::WaitForPresentTime(int64_t present_time,
771                                     uint32_t vsync_period_ns) {
772   const int64_t current_time = ResourceManager::GetTimeMonotonicNs();
773   int64_t next_vsync_time = vsync_worker_->GetNextVsyncTimestamp(current_time);
774 
775   int64_t vsync_after_present_time = vsync_worker_->GetNextVsyncTimestamp(
776       present_time);
777   int64_t vsync_before_present_time = vsync_after_present_time -
778                                       vsync_period_ns;
779 
780   // Check if |present_time| is closer to the expected vsync before or after.
781   int64_t desired_vsync = (vsync_after_present_time - present_time) <
782                                   (present_time - vsync_before_present_time)
783                               ? vsync_after_present_time
784                               : vsync_before_present_time;
785 
786   // Don't sleep if desired_vsync is before or nearly equal to vsync_period of
787   // the next expected vsync.
788   const int64_t quarter_vsync_period = vsync_period_ns / 4;
789   if ((desired_vsync - next_vsync_time) < quarter_vsync_period) {
790     return;
791   }
792 
793   // Sleep until 75% vsync_period before the desired_vsync.
794   int64_t sleep_until = desired_vsync - (quarter_vsync_period * 3);
795   struct timespec sleep_until_ts{};
796   constexpr int64_t kOneSecondNs = 1LL * 1000 * 1000 * 1000;
797   sleep_until_ts.tv_sec = int(sleep_until / kOneSecondNs);
798   sleep_until_ts.tv_nsec = int(sleep_until -
799                                (sleep_until_ts.tv_sec * kOneSecondNs));
800   clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &sleep_until_ts, nullptr);
801 }
802 
803 // NOLINTNEXTLINE(readability-function-cognitive-complexity)
CreateComposition(AtomicCommitArgs & a_args)804 HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
805   if (IsInHeadlessMode()) {
806     ALOGE("%s: Display is in headless mode, should never reach here", __func__);
807     return HWC2::Error::None;
808   }
809 
810   a_args.color_matrix = color_matrix_;
811   a_args.content_type = content_type_;
812   a_args.colorspace = colorspace_;
813   a_args.hdr_metadata = hdr_metadata_;
814   a_args.min_bpc = min_bpc_;
815 
816   uint32_t prev_vperiod_ns = 0;
817   GetDisplayVsyncPeriod(&prev_vperiod_ns);
818 
819   std::optional<uint32_t> new_vsync_period_ns;
820   if (staged_mode_config_id_ &&
821       staged_mode_change_time_ <= ResourceManager::GetTimeMonotonicNs()) {
822     const HwcDisplayConfig *staged_config = GetConfig(
823         staged_mode_config_id_.value());
824     if (staged_config == nullptr) {
825       return HWC2::Error::BadConfig;
826     }
827 
828     configs_.active_config_id = staged_mode_config_id_.value();
829     a_args.display_mode = staged_config->mode;
830     if (!a_args.test_only) {
831       new_vsync_period_ns = staged_config->mode.GetVSyncPeriodNs();
832     }
833   }
834 
835   // order the layers by z-order
836   size_t client_layer_count = 0;
837   bool use_client_layer = false;
838   uint32_t client_z_order = UINT32_MAX;
839   std::map<uint32_t, HwcLayer *> z_map;
840   std::optional<LayerData> cursor_layer = std::nullopt;
841   for (auto &[_, layer] : layers_) {
842     switch (layer.GetValidatedType()) {
843       case HWC2::Composition::Device:
844         z_map.emplace(layer.GetZOrder(), &layer);
845         break;
846       case HWC2::Composition::Cursor:
847         if (!cursor_layer.has_value()) {
848           layer.PopulateLayerData();
849           cursor_layer = layer.GetLayerData();
850         } else {
851           ALOGW("Detected multiple cursor layers");
852           z_map.emplace(layer.GetZOrder(), &layer);
853         }
854         break;
855       case HWC2::Composition::Client:
856         // Place it at the z_order of the lowest client layer
857         use_client_layer = true;
858         client_layer_count++;
859         client_z_order = std::min(client_z_order, layer.GetZOrder());
860         break;
861       default:
862         continue;
863     }
864   }
865 
866   // CTM will be applied by the client, don't apply DRM CTM
867   if (client_layer_count == layers_.size())
868    a_args.color_matrix = identity_color_matrix_;
869   else
870     a_args.color_matrix = color_matrix_;
871 
872   if (use_client_layer) {
873     z_map.emplace(client_z_order, &client_layer_);
874 
875     client_layer_.PopulateLayerData();
876     if (!client_layer_.IsLayerUsableAsDevice()) {
877       ALOGE_IF(!a_args.test_only,
878                "Client layer must be always usable by DRM/KMS");
879       /* This may be normally triggered on validation of the first frame
880        * containing CLIENT layer. At this moment client buffer is not yet
881        * provided by the CLIENT.
882        * This may be triggered once in HwcLayer lifecycle in case FB can't be
883        * imported. For example when non-contiguous buffer is imported into
884        * contiguous-only DRM/KMS driver.
885        */
886       return HWC2::Error::BadLayer;
887     }
888   }
889 
890   if (z_map.empty())
891     return HWC2::Error::BadLayer;
892 
893   std::vector<LayerData> composition_layers;
894 
895   /* Import & populate */
896   for (std::pair<const uint32_t, HwcLayer *> &l : z_map) {
897     l.second->PopulateLayerData();
898   }
899 
900   // now that they're ordered by z, add them to the composition
901   for (std::pair<const uint32_t, HwcLayer *> &l : z_map) {
902     if (!l.second->IsLayerUsableAsDevice()) {
903       return HWC2::Error::BadLayer;
904     }
905     composition_layers.emplace_back(l.second->GetLayerData());
906   }
907 
908   /* Store plan to ensure shared planes won't be stolen by other display
909    * in between of ValidateDisplay() and PresentDisplay() calls
910    */
911   current_plan_ = DrmKmsPlan::CreateDrmKmsPlan(GetPipe(),
912                                                std::move(composition_layers),
913                                                cursor_layer);
914 
915   if (type_ == HWC2::DisplayType::Virtual) {
916     writeback_layer_->PopulateLayerData();
917     if (!writeback_layer_->IsLayerUsableAsDevice()) {
918       ALOGE("Output layer must be always usable by DRM/KMS");
919       return HWC2::Error::BadLayer;
920     }
921     a_args.writeback_fb = writeback_layer_->GetLayerData().fb;
922     a_args.writeback_release_fence = writeback_layer_->GetLayerData()
923                                          .acquire_fence;
924   }
925 
926   if (!current_plan_) {
927     ALOGE_IF(!a_args.test_only, "Failed to create DrmKmsPlan");
928     return HWC2::Error::BadConfig;
929   }
930 
931   a_args.composition = current_plan_;
932 
933   auto ret = GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
934 
935   if (ret) {
936     ALOGE_IF(!a_args.test_only, "Failed to apply the frame composition ret=%d", ret);
937     return HWC2::Error::BadParameter;
938   }
939 
940   if (new_vsync_period_ns) {
941     staged_mode_config_id_.reset();
942 
943     vsync_worker_->SetVsyncTimestampTracking(false);
944     uint32_t last_vsync_ts = vsync_worker_->GetLastVsyncTimestamp();
945     if (last_vsync_ts != 0) {
946       hwc_->SendVsyncPeriodTimingChangedEventToClient(handle_,
947                                                       last_vsync_ts +
948                                                           prev_vperiod_ns);
949     }
950     vsync_worker_->SetVsyncPeriodNs(new_vsync_period_ns.value());
951   }
952 
953   return HWC2::Error::None;
954 }
955 
SetActiveConfigInternal(uint32_t config,int64_t change_time)956 HWC2::Error HwcDisplay::SetActiveConfigInternal(uint32_t config,
957                                                 int64_t change_time) {
958   if (configs_.hwc_configs.count(config) == 0) {
959     ALOGE("Could not find active mode for %u", config);
960     return HWC2::Error::BadConfig;
961   }
962 
963   staged_mode_change_time_ = change_time;
964   staged_mode_config_id_ = config;
965   if (const HwcDisplayConfig *new_config = GetConfig(config))
966     SetOutputType(new_config->output_type);
967 
968   return HWC2::Error::None;
969 }
970 
SetActiveConfig(hwc2_config_t config)971 HWC2::Error HwcDisplay::SetActiveConfig(hwc2_config_t config) {
972   return SetActiveConfigInternal(config, ResourceManager::GetTimeMonotonicNs());
973 }
974 
SetColorMode(int32_t mode)975 HWC2::Error HwcDisplay::SetColorMode(int32_t mode) {
976   /* Maps to the Colorspace DRM connector property:
977    * https://elixir.bootlin.com/linux/v6.11/source/include/drm/drm_connector.h#L538
978    */
979   if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_DISPLAY_BT2020)
980     return HWC2::Error::BadParameter;
981 
982   switch (mode) {
983     case HAL_COLOR_MODE_NATIVE:
984       colorspace_ = Colorspace::kDefault;
985       break;
986     case HAL_COLOR_MODE_STANDARD_BT601_625:
987     case HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED:
988     case HAL_COLOR_MODE_STANDARD_BT601_525:
989     case HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED:
990       // The DP spec does not say whether this is the 525 or the 625 line version.
991       colorspace_ = Colorspace::kBt601Ycc;
992       break;
993     case HAL_COLOR_MODE_STANDARD_BT709:
994     case HAL_COLOR_MODE_SRGB:
995       colorspace_ = Colorspace::kBt709Ycc;
996       break;
997     case HAL_COLOR_MODE_DCI_P3:
998     case HAL_COLOR_MODE_DISPLAY_P3:
999       colorspace_ = Colorspace::kDciP3RgbD65;
1000       break;
1001     case HAL_COLOR_MODE_DISPLAY_BT2020:
1002     case HAL_COLOR_MODE_ADOBE_RGB:
1003     case HAL_COLOR_MODE_BT2020:
1004     case HAL_COLOR_MODE_BT2100_PQ:
1005     case HAL_COLOR_MODE_BT2100_HLG:
1006     default:
1007       return HWC2::Error::Unsupported;
1008   }
1009 
1010   color_mode_ = mode;
1011   return HWC2::Error::None;
1012 }
1013 
SetColorTransform(const float * matrix,int32_t hint)1014 HWC2::Error HwcDisplay::SetColorTransform(const float *matrix, int32_t hint) {
1015   if (hint < HAL_COLOR_TRANSFORM_IDENTITY ||
1016       hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA)
1017     return HWC2::Error::BadParameter;
1018 
1019   if (!matrix && hint == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX)
1020     return HWC2::Error::BadParameter;
1021 
1022   color_transform_hint_ = static_cast<android_color_transform_t>(hint);
1023   ctm_has_offset_ = false;
1024 
1025   if (IsInHeadlessMode())
1026     return HWC2::Error::None;
1027 
1028   if (!GetPipe().crtc->Get()->GetCtmProperty())
1029     return HWC2::Error::None;
1030 
1031   switch (color_transform_hint_) {
1032     case HAL_COLOR_TRANSFORM_IDENTITY:
1033       SetColorMatrixToIdentity();
1034       break;
1035     case HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX:
1036       // Without HW support, we cannot correctly process matrices with an offset.
1037       {
1038         if (TransformHasOffsetValue(matrix))
1039           ctm_has_offset_ = true;
1040 
1041         std::array<float, 16> aidl_matrix = kIdentityMatrix;
1042         memcpy(aidl_matrix.data(), matrix, aidl_matrix.size() * sizeof(float));
1043         color_matrix_ = ToColorTransform(aidl_matrix);
1044       }
1045       break;
1046     default:
1047       return HWC2::Error::Unsupported;
1048   }
1049 
1050   return HWC2::Error::None;
1051 }
1052 
CtmByGpu()1053 bool HwcDisplay::CtmByGpu() {
1054   if (color_transform_hint_ == HAL_COLOR_TRANSFORM_IDENTITY)
1055     return false;
1056 
1057   if (GetPipe().crtc->Get()->GetCtmProperty() && !ctm_has_offset_)
1058     return false;
1059 
1060   if (GetHwc()->GetResMan().GetCtmHandling() == CtmHandling::kDrmOrIgnore)
1061     return false;
1062 
1063   return true;
1064 }
1065 
SetPowerMode(int32_t mode_in)1066 HWC2::Error HwcDisplay::SetPowerMode(int32_t mode_in) {
1067   auto mode = static_cast<HWC2::PowerMode>(mode_in);
1068 
1069   AtomicCommitArgs a_args{};
1070 
1071   switch (mode) {
1072     case HWC2::PowerMode::Off:
1073       a_args.active = false;
1074       break;
1075     case HWC2::PowerMode::On:
1076       a_args.active = true;
1077       break;
1078     case HWC2::PowerMode::Doze:
1079     case HWC2::PowerMode::DozeSuspend:
1080       return HWC2::Error::Unsupported;
1081     default:
1082       ALOGE("Incorrect power mode value (%d)\n", mode_in);
1083       return HWC2::Error::BadParameter;
1084   }
1085 
1086   if (IsInHeadlessMode()) {
1087     return HWC2::Error::None;
1088   }
1089 
1090   if (a_args.active && *a_args.active) {
1091     /*
1092      * Setting the display to active before we have a composition
1093      * can break some drivers, so skip setting a_args.active to
1094      * true, as the next composition frame will implicitly activate
1095      * the display
1096      */
1097     return GetPipe().atomic_state_manager->ActivateDisplayUsingDPMS() == 0
1098                ? HWC2::Error::None
1099                : HWC2::Error::BadParameter;
1100   };
1101 
1102   auto err = GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
1103   if (err) {
1104     ALOGE("Failed to apply the dpms composition err=%d", err);
1105     return HWC2::Error::BadParameter;
1106   }
1107   return HWC2::Error::None;
1108 }
1109 
SetVsyncEnabled(int32_t enabled)1110 HWC2::Error HwcDisplay::SetVsyncEnabled(int32_t enabled) {
1111   if (type_ == HWC2::DisplayType::Virtual) {
1112     return HWC2::Error::None;
1113   }
1114   if (!vsync_worker_) {
1115     return HWC2::Error::NoResources;
1116   }
1117 
1118   vsync_event_en_ = HWC2_VSYNC_ENABLE == enabled;
1119   std::optional<VSyncWorker::VsyncTimestampCallback> callback = std::nullopt;
1120   if (vsync_event_en_) {
1121     DrmHwc *hwc = hwc_;
1122     hwc2_display_t id = handle_;
1123     // Callback will be called from the vsync thread.
1124     callback = [hwc, id](int64_t timestamp, uint32_t period_ns) {
1125       hwc->SendVsyncEventToClient(id, timestamp, period_ns);
1126     };
1127   }
1128   vsync_worker_->SetTimestampCallback(std::move(callback));
1129   return HWC2::Error::None;
1130 }
1131 
GetOrderLayersByZPos()1132 std::vector<HwcLayer *> HwcDisplay::GetOrderLayersByZPos() {
1133   std::vector<HwcLayer *> ordered_layers;
1134   ordered_layers.reserve(layers_.size());
1135 
1136   for (auto &[handle, layer] : layers_) {
1137     ordered_layers.emplace_back(&layer);
1138   }
1139 
1140   std::sort(std::begin(ordered_layers), std::end(ordered_layers),
1141             [](const HwcLayer *lhs, const HwcLayer *rhs) {
1142               // Cursor layers should always have highest zpos.
1143               if ((lhs->GetSfType() == HWC2::Composition::Cursor) !=
1144                   (rhs->GetSfType() == HWC2::Composition::Cursor)) {
1145                 return rhs->GetSfType() == HWC2::Composition::Cursor;
1146               }
1147 
1148               return lhs->GetZOrder() < rhs->GetZOrder();
1149             });
1150 
1151   return ordered_layers;
1152 }
1153 
GetDisplayVsyncPeriod(uint32_t * outVsyncPeriod)1154 HWC2::Error HwcDisplay::GetDisplayVsyncPeriod(
1155     uint32_t *outVsyncPeriod /* ns */) {
1156   return GetDisplayAttribute(configs_.active_config_id,
1157                              HWC2_ATTRIBUTE_VSYNC_PERIOD,
1158                              (int32_t *)(outVsyncPeriod));
1159 }
1160 
1161 // Display primary values are coded as unsigned 16-bit values in units of
1162 // 0.00002, where 0x0000 represents zero and 0xC350 represents 1.0000.
ToU16ColorValue(float in)1163 static uint64_t ToU16ColorValue(float in) {
1164   constexpr float kPrimariesFixedPoint = 50000.F;
1165   return static_cast<uint64_t>(kPrimariesFixedPoint * in);
1166 }
1167 
SetHdrOutputMetadata(ui::Hdr type)1168 HWC2::Error HwcDisplay::SetHdrOutputMetadata(ui::Hdr type) {
1169   hdr_metadata_ = std::make_shared<hdr_output_metadata>();
1170   hdr_metadata_->metadata_type = 0;
1171   auto *m = &hdr_metadata_->hdmi_metadata_type1;
1172   m->metadata_type = 0;
1173 
1174   switch (type) {
1175     case ui::Hdr::HDR10:
1176       m->eotf = 2;  // PQ
1177       break;
1178     case ui::Hdr::HLG:
1179       m->eotf = 3;  // HLG
1180       break;
1181     default:
1182       return HWC2::Error::Unsupported;
1183   }
1184 
1185   // Most luminance values are coded as an unsigned 16-bit value in units of 1
1186   // cd/m2, where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2.
1187   std::vector<ui::Hdr> types;
1188   float hdr_luminance[3]{0.F, 0.F, 0.F};
1189   GetEdid()->GetHdrCapabilities(types, &hdr_luminance[0], &hdr_luminance[1],
1190                                 &hdr_luminance[2]);
1191   m->max_display_mastering_luminance = m->max_cll = static_cast<uint64_t>(
1192       hdr_luminance[0]);
1193   m->max_fall = static_cast<uint64_t>(hdr_luminance[1]);
1194   // The min luminance value is coded as an unsigned 16-bit value in units of
1195   // 0.0001 cd/m2, where 0x0001 represents 0.0001 cd/m2 and 0xFFFF
1196   // represents 6.5535 cd/m2.
1197   m->min_display_mastering_luminance = static_cast<uint64_t>(hdr_luminance[2] *
1198                                                              10000.F);
1199 
1200   auto gamut = ColorGamut::BT2020();
1201   auto primaries = gamut.getPrimaries();
1202   m->display_primaries[0].x = ToU16ColorValue(primaries[0].x);
1203   m->display_primaries[0].y = ToU16ColorValue(primaries[0].y);
1204   m->display_primaries[1].x = ToU16ColorValue(primaries[1].x);
1205   m->display_primaries[1].y = ToU16ColorValue(primaries[1].y);
1206   m->display_primaries[2].x = ToU16ColorValue(primaries[2].x);
1207   m->display_primaries[2].y = ToU16ColorValue(primaries[2].y);
1208 
1209   auto whitePoint = gamut.getWhitePoint();
1210   m->white_point.x = ToU16ColorValue(whitePoint.x);
1211   m->white_point.y = ToU16ColorValue(whitePoint.y);
1212 
1213   return HWC2::Error::None;
1214 }
1215 
1216 #if __ANDROID_API__ > 29
GetDisplayConnectionType(uint32_t * outType)1217 HWC2::Error HwcDisplay::GetDisplayConnectionType(uint32_t *outType) {
1218   if (IsInHeadlessMode()) {
1219     *outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::Internal);
1220     return HWC2::Error::None;
1221   }
1222   /* Primary display should be always internal,
1223    * otherwise SF will be unhappy and will crash
1224    */
1225   if (GetPipe().connector->Get()->IsInternal() || handle_ == kPrimaryDisplay)
1226     *outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::Internal);
1227   else if (GetPipe().connector->Get()->IsExternal())
1228     *outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::External);
1229   else
1230     return HWC2::Error::BadConfig;
1231 
1232   return HWC2::Error::None;
1233 }
1234 
SetActiveConfigWithConstraints(hwc2_config_t config,hwc_vsync_period_change_constraints_t * vsyncPeriodChangeConstraints,hwc_vsync_period_change_timeline_t * outTimeline)1235 HWC2::Error HwcDisplay::SetActiveConfigWithConstraints(
1236     hwc2_config_t config,
1237     hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints,
1238     hwc_vsync_period_change_timeline_t *outTimeline) {
1239   if (type_ == HWC2::DisplayType::Virtual) {
1240     return HWC2::Error::None;
1241   }
1242 
1243   if (vsyncPeriodChangeConstraints == nullptr || outTimeline == nullptr) {
1244     return HWC2::Error::BadParameter;
1245   }
1246 
1247   uint32_t current_vsync_period{};
1248   GetDisplayVsyncPeriod(&current_vsync_period);
1249 
1250   if (vsyncPeriodChangeConstraints->seamlessRequired) {
1251     return HWC2::Error::SeamlessNotAllowed;
1252   }
1253 
1254   outTimeline->refreshTimeNanos = vsyncPeriodChangeConstraints
1255                                       ->desiredTimeNanos -
1256                                   current_vsync_period;
1257   auto ret = SetActiveConfigInternal(config, outTimeline->refreshTimeNanos);
1258   if (ret != HWC2::Error::None) {
1259     return ret;
1260   }
1261 
1262   outTimeline->refreshRequired = true;
1263   outTimeline->newVsyncAppliedTimeNanos = vsyncPeriodChangeConstraints
1264                                               ->desiredTimeNanos;
1265 
1266   vsync_worker_->SetVsyncTimestampTracking(true);
1267 
1268   return HWC2::Error::None;
1269 }
1270 
SetContentType(int32_t contentType)1271 HWC2::Error HwcDisplay::SetContentType(int32_t contentType) {
1272   /* Maps exactly to the content_type DRM connector property:
1273    * https://elixir.bootlin.com/linux/v6.11/source/include/uapi/drm/drm_mode.h#L107
1274    */
1275   if (contentType < HWC2_CONTENT_TYPE_NONE || contentType > HWC2_CONTENT_TYPE_GAME)
1276     return HWC2::Error::BadParameter;
1277 
1278   content_type_ = contentType;
1279 
1280   return HWC2::Error::None;
1281 }
1282 #endif
1283 
1284 #if __ANDROID_API__ > 28
GetDisplayIdentificationData(uint8_t * outPort,uint32_t * outDataSize,uint8_t * outData)1285 HWC2::Error HwcDisplay::GetDisplayIdentificationData(uint8_t *outPort,
1286                                                      uint32_t *outDataSize,
1287                                                      uint8_t *outData) {
1288   if (IsInHeadlessMode()) {
1289     return HWC2::Error::Unsupported;
1290   }
1291 
1292   auto *connector = GetPipe().connector->Get();
1293   auto blob = connector->GetEdidBlob();
1294   if (!blob) {
1295     return HWC2::Error::Unsupported;
1296   }
1297 
1298   constexpr uint8_t kDrmDeviceBitShift = 5U;
1299   constexpr uint8_t kDrmDeviceBitMask = 0xE0;
1300   constexpr uint8_t kConnectorBitMask = 0x1F;
1301   const auto kDrmIdx = static_cast<uint8_t>(
1302       connector->GetDev().GetIndexInDevArray());
1303   const auto kConnectorIdx = static_cast<uint8_t>(
1304       connector->GetIndexInResArray());
1305   *outPort = (((kDrmIdx << kDrmDeviceBitShift) & kDrmDeviceBitMask) |
1306               (kConnectorIdx & kConnectorBitMask));
1307 
1308   if (outData) {
1309     *outDataSize = std::min(*outDataSize, blob->length);
1310     memcpy(outData, blob->data, *outDataSize);
1311   } else {
1312     *outDataSize = blob->length;
1313   }
1314 
1315   return HWC2::Error::None;
1316 }
1317 
GetDisplayCapabilities(uint32_t * outNumCapabilities,uint32_t * outCapabilities)1318 HWC2::Error HwcDisplay::GetDisplayCapabilities(uint32_t *outNumCapabilities,
1319                                                uint32_t *outCapabilities) {
1320   if (outNumCapabilities == nullptr) {
1321     return HWC2::Error::BadParameter;
1322   }
1323 
1324   bool skip_ctm = false;
1325 
1326   // Skip client CTM if user requested DRM_OR_IGNORE
1327   if (GetHwc()->GetResMan().GetCtmHandling() == CtmHandling::kDrmOrIgnore)
1328     skip_ctm = true;
1329 
1330   if (!skip_ctm) {
1331     *outNumCapabilities = 0;
1332     return HWC2::Error::None;
1333   }
1334 
1335   *outNumCapabilities = 1;
1336   if (outCapabilities) {
1337     outCapabilities[0] = HWC2_DISPLAY_CAPABILITY_SKIP_CLIENT_COLOR_TRANSFORM;
1338   }
1339 
1340   return HWC2::Error::None;
1341 }
1342 
1343 #endif /* __ANDROID_API__ > 28 */
1344 
1345 #if __ANDROID_API__ > 27
1346 
GetRenderIntents(int32_t mode,uint32_t * outNumIntents,int32_t * outIntents)1347 HWC2::Error HwcDisplay::GetRenderIntents(
1348     int32_t mode, uint32_t *outNumIntents,
1349     int32_t * /*android_render_intent_v1_1_t*/ outIntents) {
1350   if (mode != HAL_COLOR_MODE_NATIVE) {
1351     return HWC2::Error::BadParameter;
1352   }
1353 
1354   if (outIntents == nullptr) {
1355     *outNumIntents = 1;
1356     return HWC2::Error::None;
1357   }
1358   *outNumIntents = 1;
1359   outIntents[0] = HAL_RENDER_INTENT_COLORIMETRIC;
1360   return HWC2::Error::None;
1361 }
1362 
SetColorModeWithIntent(int32_t mode,int32_t intent)1363 HWC2::Error HwcDisplay::SetColorModeWithIntent(int32_t mode, int32_t intent) {
1364   if (intent < HAL_RENDER_INTENT_COLORIMETRIC ||
1365       intent > HAL_RENDER_INTENT_TONE_MAP_ENHANCE)
1366     return HWC2::Error::BadParameter;
1367 
1368   if (intent != HAL_RENDER_INTENT_COLORIMETRIC)
1369     return HWC2::Error::Unsupported;
1370 
1371   auto err = SetColorMode(mode);
1372   if (err != HWC2::Error::None) return err;
1373 
1374   return HWC2::Error::None;
1375 }
1376 
1377 #endif /* __ANDROID_API__ > 27 */
1378 
backend() const1379 const Backend *HwcDisplay::backend() const {
1380   return backend_.get();
1381 }
1382 
set_backend(std::unique_ptr<Backend> backend)1383 void HwcDisplay::set_backend(std::unique_ptr<Backend> backend) {
1384   backend_ = std::move(backend);
1385 }
1386 
NeedsClientLayerUpdate() const1387 bool HwcDisplay::NeedsClientLayerUpdate() const {
1388   return std::any_of(layers_.begin(), layers_.end(), [](const auto &pair) {
1389     const auto &layer = pair.second;
1390     return layer.GetSfType() == HWC2::Composition::Client ||
1391            layer.GetValidatedType() == HWC2::Composition::Client;
1392   });
1393 }
1394 
1395 }  // namespace android
1396