• 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 "hwc-display"
18 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
19 
20 #include "HwcDisplay.h"
21 
22 #include "DrmHwcTwo.h"
23 #include "backend/Backend.h"
24 #include "backend/BackendManager.h"
25 #include "bufferinfo/BufferInfoGetter.h"
26 #include "utils/log.h"
27 #include "utils/properties.h"
28 
29 namespace android {
30 
DumpDelta(HwcDisplay::Stats delta)31 std::string HwcDisplay::DumpDelta(HwcDisplay::Stats delta) {
32   if (delta.total_pixops_ == 0)
33     return "No stats yet";
34   double ratio = 1.0 - double(delta.gpu_pixops_) / double(delta.total_pixops_);
35 
36   std::stringstream ss;
37   ss << " Total frames count: " << delta.total_frames_ << "\n"
38      << " Failed to test commit frames: " << delta.failed_kms_validate_ << "\n"
39      << " Failed to commit frames: " << delta.failed_kms_present_ << "\n"
40      << ((delta.failed_kms_present_ > 0)
41              ? " !!! Internal failure, FIX it please\n"
42              : "")
43      << " Flattened frames: " << delta.frames_flattened_ << "\n"
44      << " Pixel operations (free units)"
45      << " : [TOTAL: " << delta.total_pixops_ << " / GPU: " << delta.gpu_pixops_
46      << "]\n"
47      << " Composition efficiency: " << ratio;
48 
49   return ss.str();
50 }
51 
Dump()52 std::string HwcDisplay::Dump() {
53   std::string flattening_state_str;
54   switch (flattenning_state_) {
55     case ClientFlattenningState::Disabled:
56       flattening_state_str = "Disabled";
57       break;
58     case ClientFlattenningState::NotRequired:
59       flattening_state_str = "Not needed";
60       break;
61     case ClientFlattenningState::Flattened:
62       flattening_state_str = "Active";
63       break;
64     case ClientFlattenningState::ClientRefreshRequested:
65       flattening_state_str = "Refresh requested";
66       break;
67     default:
68       flattening_state_str = std::to_string(flattenning_state_) +
69                              " VSync remains";
70   }
71 
72   std::string connector_name = IsInHeadlessMode()
73                                    ? "NULL-DISPLAY"
74                                    : GetPipe().connector->Get()->GetName();
75 
76   std::stringstream ss;
77   ss << "- Display on: " << connector_name << "\n"
78      << "  Flattening state: " << flattening_state_str << "\n"
79      << "Statistics since system boot:\n"
80      << DumpDelta(total_stats_) << "\n\n"
81      << "Statistics since last dumpsys request:\n"
82      << DumpDelta(total_stats_.minus(prev_stats_)) << "\n\n";
83 
84   memcpy(&prev_stats_, &total_stats_, sizeof(Stats));
85   return ss.str();
86 }
87 
HwcDisplay(hwc2_display_t handle,HWC2::DisplayType type,DrmHwcTwo * hwc2)88 HwcDisplay::HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type,
89                        DrmHwcTwo *hwc2)
90     : hwc2_(hwc2),
91       handle_(handle),
92       type_(type),
93       color_transform_hint_(HAL_COLOR_TRANSFORM_IDENTITY) {
94   // clang-format off
95   color_transform_matrix_ = {1.0, 0.0, 0.0, 0.0,
96                              0.0, 1.0, 0.0, 0.0,
97                              0.0, 0.0, 1.0, 0.0,
98                              0.0, 0.0, 0.0, 1.0};
99   // clang-format on
100 }
101 
102 HwcDisplay::~HwcDisplay() = default;
103 
SetPipeline(DrmDisplayPipeline * pipeline)104 void HwcDisplay::SetPipeline(DrmDisplayPipeline *pipeline) {
105   pipeline_ = pipeline;
106 
107   if (pipeline != nullptr) {
108     ChosePreferredConfig();
109     Init();
110 
111     hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ true);
112   } else {
113     backend_.reset();
114     vsync_worker_.Init(nullptr, [](int64_t) {});
115     SetClientTarget(nullptr, -1, 0, {});
116     if (handle_ != kPrimaryDisplay) {
117       hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ false);
118     }
119   }
120 }
121 
Init()122 HWC2::Error HwcDisplay::Init() {
123   int ret = vsync_worker_.Init(pipeline_, [this](int64_t timestamp) {
124     const std::lock_guard<std::mutex> lock(hwc2_->GetResMan().GetMainLock());
125     if (vsync_event_en_) {
126       uint32_t period_ns{};
127       GetDisplayVsyncPeriod(&period_ns);
128       hwc2_->SendVsyncEventToClient(handle_, timestamp, period_ns);
129     }
130     if (vsync_flattening_en_) {
131       ProcessFlatenningVsyncInternal();
132     }
133     if (vsync_tracking_en_) {
134       last_vsync_ts_ = timestamp;
135     }
136     if (!vsync_event_en_ && !vsync_flattening_en_ && !vsync_tracking_en_) {
137       vsync_worker_.VSyncControl(false);
138     }
139   });
140   if (ret && ret != -EALREADY) {
141     ALOGE("Failed to create event worker for d=%d %d\n", int(handle_), ret);
142     return HWC2::Error::BadDisplay;
143   }
144 
145   if (!IsInHeadlessMode()) {
146     ret = BackendManager::GetInstance().SetBackendForDisplay(this);
147     if (ret) {
148       ALOGE("Failed to set backend for d=%d %d\n", int(handle_), ret);
149       return HWC2::Error::BadDisplay;
150     }
151   }
152 
153   client_layer_.SetLayerBlendMode(HWC2_BLEND_MODE_PREMULTIPLIED);
154 
155   return HWC2::Error::None;
156 }
157 
ChosePreferredConfig()158 HWC2::Error HwcDisplay::ChosePreferredConfig() {
159   HWC2::Error err{};
160   if (!IsInHeadlessMode()) {
161     err = configs_.Update(*pipeline_->connector->Get());
162   } else {
163     configs_.FillHeadless();
164   }
165   if (!IsInHeadlessMode() && err != HWC2::Error::None) {
166     return HWC2::Error::BadDisplay;
167   }
168 
169   return SetActiveConfig(configs_.preferred_config_id);
170 }
171 
AcceptDisplayChanges()172 HWC2::Error HwcDisplay::AcceptDisplayChanges() {
173   for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_)
174     l.second.AcceptTypeChange();
175   return HWC2::Error::None;
176 }
177 
CreateLayer(hwc2_layer_t * layer)178 HWC2::Error HwcDisplay::CreateLayer(hwc2_layer_t *layer) {
179   layers_.emplace(static_cast<hwc2_layer_t>(layer_idx_), HwcLayer());
180   *layer = static_cast<hwc2_layer_t>(layer_idx_);
181   ++layer_idx_;
182   return HWC2::Error::None;
183 }
184 
DestroyLayer(hwc2_layer_t layer)185 HWC2::Error HwcDisplay::DestroyLayer(hwc2_layer_t layer) {
186   if (!get_layer(layer)) {
187     return HWC2::Error::BadLayer;
188   }
189 
190   layers_.erase(layer);
191   return HWC2::Error::None;
192 }
193 
GetActiveConfig(hwc2_config_t * config) const194 HWC2::Error HwcDisplay::GetActiveConfig(hwc2_config_t *config) const {
195   if (configs_.hwc_configs.count(staged_mode_config_id_) == 0)
196     return HWC2::Error::BadConfig;
197 
198   *config = staged_mode_config_id_;
199   return HWC2::Error::None;
200 }
201 
GetChangedCompositionTypes(uint32_t * num_elements,hwc2_layer_t * layers,int32_t * types)202 HWC2::Error HwcDisplay::GetChangedCompositionTypes(uint32_t *num_elements,
203                                                    hwc2_layer_t *layers,
204                                                    int32_t *types) {
205   if (IsInHeadlessMode()) {
206     *num_elements = 0;
207     return HWC2::Error::None;
208   }
209 
210   uint32_t num_changes = 0;
211   for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) {
212     if (l.second.IsTypeChanged()) {
213       if (layers && num_changes < *num_elements)
214         layers[num_changes] = l.first;
215       if (types && num_changes < *num_elements)
216         types[num_changes] = static_cast<int32_t>(l.second.GetValidatedType());
217       ++num_changes;
218     }
219   }
220   if (!layers && !types)
221     *num_elements = num_changes;
222   return HWC2::Error::None;
223 }
224 
GetClientTargetSupport(uint32_t width,uint32_t height,int32_t,int32_t dataspace)225 HWC2::Error HwcDisplay::GetClientTargetSupport(uint32_t width, uint32_t height,
226                                                int32_t /*format*/,
227                                                int32_t dataspace) {
228   if (IsInHeadlessMode()) {
229     return HWC2::Error::None;
230   }
231 
232   std::pair<uint32_t, uint32_t> min = pipeline_->device->GetMinResolution();
233   std::pair<uint32_t, uint32_t> max = pipeline_->device->GetMaxResolution();
234 
235   if (width < min.first || height < min.second)
236     return HWC2::Error::Unsupported;
237 
238   if (width > max.first || height > max.second)
239     return HWC2::Error::Unsupported;
240 
241   if (dataspace != HAL_DATASPACE_UNKNOWN)
242     return HWC2::Error::Unsupported;
243 
244   // TODO(nobody): Validate format can be handled by either GL or planes
245   return HWC2::Error::None;
246 }
247 
GetColorModes(uint32_t * num_modes,int32_t * modes)248 HWC2::Error HwcDisplay::GetColorModes(uint32_t *num_modes, int32_t *modes) {
249   if (!modes)
250     *num_modes = 1;
251 
252   if (modes)
253     *modes = HAL_COLOR_MODE_NATIVE;
254 
255   return HWC2::Error::None;
256 }
257 
GetDisplayAttribute(hwc2_config_t config,int32_t attribute_in,int32_t * value)258 HWC2::Error HwcDisplay::GetDisplayAttribute(hwc2_config_t config,
259                                             int32_t attribute_in,
260                                             int32_t *value) {
261   int conf = static_cast<int>(config);
262 
263   if (configs_.hwc_configs.count(conf) == 0) {
264     ALOGE("Could not find mode #%d", conf);
265     return HWC2::Error::BadConfig;
266   }
267 
268   auto &hwc_config = configs_.hwc_configs[conf];
269 
270   static const int32_t kUmPerInch = 25400;
271   uint32_t mm_width = configs_.mm_width;
272   uint32_t mm_height = configs_.mm_height;
273   auto attribute = static_cast<HWC2::Attribute>(attribute_in);
274   switch (attribute) {
275     case HWC2::Attribute::Width:
276       *value = static_cast<int>(hwc_config.mode.h_display());
277       break;
278     case HWC2::Attribute::Height:
279       *value = static_cast<int>(hwc_config.mode.v_display());
280       break;
281     case HWC2::Attribute::VsyncPeriod:
282       // in nanoseconds
283       *value = static_cast<int>(1E9 / hwc_config.mode.v_refresh());
284       break;
285     case HWC2::Attribute::DpiX:
286       // Dots per 1000 inches
287       *value = mm_width ? static_cast<int>(hwc_config.mode.h_display() *
288                                            kUmPerInch / mm_width)
289                         : -1;
290       break;
291     case HWC2::Attribute::DpiY:
292       // Dots per 1000 inches
293       *value = mm_height ? static_cast<int>(hwc_config.mode.v_display() *
294                                             kUmPerInch / mm_height)
295                          : -1;
296       break;
297 #if PLATFORM_SDK_VERSION > 29
298     case HWC2::Attribute::ConfigGroup:
299       /* Dispite ConfigGroup is a part of HWC2.4 API, framework
300        * able to request it even if service @2.1 is used */
301       *value = int(hwc_config.group_id);
302       break;
303 #endif
304     default:
305       *value = -1;
306       return HWC2::Error::BadConfig;
307   }
308   return HWC2::Error::None;
309 }
310 
GetDisplayConfigs(uint32_t * num_configs,hwc2_config_t * configs)311 HWC2::Error HwcDisplay::GetDisplayConfigs(uint32_t *num_configs,
312                                           hwc2_config_t *configs) {
313   uint32_t idx = 0;
314   for (auto &hwc_config : configs_.hwc_configs) {
315     if (hwc_config.second.disabled) {
316       continue;
317     }
318 
319     if (configs != nullptr) {
320       if (idx >= *num_configs) {
321         break;
322       }
323       configs[idx] = hwc_config.second.id;
324     }
325 
326     idx++;
327   }
328   *num_configs = idx;
329   return HWC2::Error::None;
330 }
331 
GetDisplayName(uint32_t * size,char * name)332 HWC2::Error HwcDisplay::GetDisplayName(uint32_t *size, char *name) {
333   std::ostringstream stream;
334   if (IsInHeadlessMode()) {
335     stream << "null-display";
336   } else {
337     stream << "display-" << GetPipe().connector->Get()->GetId();
338   }
339   std::string string = stream.str();
340   size_t length = string.length();
341   if (!name) {
342     *size = length;
343     return HWC2::Error::None;
344   }
345 
346   *size = std::min<uint32_t>(static_cast<uint32_t>(length - 1), *size);
347   strncpy(name, string.c_str(), *size);
348   return HWC2::Error::None;
349 }
350 
GetDisplayRequests(int32_t *,uint32_t * num_elements,hwc2_layer_t *,int32_t *)351 HWC2::Error HwcDisplay::GetDisplayRequests(int32_t * /*display_requests*/,
352                                            uint32_t *num_elements,
353                                            hwc2_layer_t * /*layers*/,
354                                            int32_t * /*layer_requests*/) {
355   // TODO(nobody): I think virtual display should request
356   //      HWC2_DISPLAY_REQUEST_WRITE_CLIENT_TARGET_TO_OUTPUT here
357   *num_elements = 0;
358   return HWC2::Error::None;
359 }
360 
GetDisplayType(int32_t * type)361 HWC2::Error HwcDisplay::GetDisplayType(int32_t *type) {
362   *type = static_cast<int32_t>(type_);
363   return HWC2::Error::None;
364 }
365 
GetDozeSupport(int32_t * support)366 HWC2::Error HwcDisplay::GetDozeSupport(int32_t *support) {
367   *support = 0;
368   return HWC2::Error::None;
369 }
370 
GetHdrCapabilities(uint32_t * num_types,int32_t *,float *,float *,float *)371 HWC2::Error HwcDisplay::GetHdrCapabilities(uint32_t *num_types,
372                                            int32_t * /*types*/,
373                                            float * /*max_luminance*/,
374                                            float * /*max_average_luminance*/,
375                                            float * /*min_luminance*/) {
376   *num_types = 0;
377   return HWC2::Error::None;
378 }
379 
380 /* Find API details at:
381  * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1767
382  */
GetReleaseFences(uint32_t * num_elements,hwc2_layer_t * layers,int32_t * fences)383 HWC2::Error HwcDisplay::GetReleaseFences(uint32_t *num_elements,
384                                          hwc2_layer_t *layers,
385                                          int32_t *fences) {
386   if (IsInHeadlessMode()) {
387     *num_elements = 0;
388     return HWC2::Error::None;
389   }
390 
391   uint32_t num_layers = 0;
392 
393   for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) {
394     ++num_layers;
395     if (layers == nullptr || fences == nullptr)
396       continue;
397 
398     if (num_layers > *num_elements) {
399       ALOGW("Overflow num_elements %d/%d", num_layers, *num_elements);
400       return HWC2::Error::None;
401     }
402 
403     layers[num_layers - 1] = l.first;
404     fences[num_layers - 1] = l.second.GetReleaseFence().Release();
405   }
406   *num_elements = num_layers;
407   return HWC2::Error::None;
408 }
409 
CreateComposition(AtomicCommitArgs & a_args)410 HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
411   if (IsInHeadlessMode()) {
412     ALOGE("%s: Display is in headless mode, should never reach here", __func__);
413     return HWC2::Error::None;
414   }
415 
416   int PrevModeVsyncPeriodNs = static_cast<int>(
417       1E9 / GetPipe().connector->Get()->GetActiveMode().v_refresh());
418 
419   auto mode_update_commited_ = false;
420   if (staged_mode_ &&
421       staged_mode_change_time_ <= ResourceManager::GetTimeMonotonicNs()) {
422     client_layer_.SetLayerDisplayFrame(
423         (hwc_rect_t){.left = 0,
424                      .top = 0,
425                      .right = static_cast<int>(staged_mode_->h_display()),
426                      .bottom = static_cast<int>(staged_mode_->v_display())});
427 
428     configs_.active_config_id = staged_mode_config_id_;
429 
430     a_args.display_mode = *staged_mode_;
431     if (!a_args.test_only) {
432       mode_update_commited_ = true;
433     }
434   }
435 
436   // order the layers by z-order
437   bool use_client_layer = false;
438   uint32_t client_z_order = UINT32_MAX;
439   std::map<uint32_t, HwcLayer *> z_map;
440   for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) {
441     switch (l.second.GetValidatedType()) {
442       case HWC2::Composition::Device:
443         z_map.emplace(std::make_pair(l.second.GetZOrder(), &l.second));
444         break;
445       case HWC2::Composition::Client:
446         // Place it at the z_order of the lowest client layer
447         use_client_layer = true;
448         client_z_order = std::min(client_z_order, l.second.GetZOrder());
449         break;
450       default:
451         continue;
452     }
453   }
454   if (use_client_layer)
455     z_map.emplace(std::make_pair(client_z_order, &client_layer_));
456 
457   if (z_map.empty())
458     return HWC2::Error::BadLayer;
459 
460   std::vector<DrmHwcLayer> composition_layers;
461 
462   // now that they're ordered by z, add them to the composition
463   for (std::pair<const uint32_t, HwcLayer *> &l : z_map) {
464     DrmHwcLayer layer;
465     l.second->PopulateDrmLayer(&layer);
466     int ret = layer.ImportBuffer(GetPipe().device);
467     if (ret) {
468       ALOGE("Failed to import layer, ret=%d", ret);
469       return HWC2::Error::NoResources;
470     }
471     composition_layers.emplace_back(std::move(layer));
472   }
473 
474   /* Store plan to ensure shared planes won't be stolen by other display
475    * in between of ValidateDisplay() and PresentDisplay() calls
476    */
477   current_plan_ = DrmKmsPlan::CreateDrmKmsPlan(GetPipe(),
478                                                std::move(composition_layers));
479   if (!current_plan_) {
480     if (!a_args.test_only) {
481       ALOGE("Failed to create DrmKmsPlan");
482     }
483     return HWC2::Error::BadConfig;
484   }
485 
486   a_args.composition = current_plan_;
487 
488   int ret = GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
489 
490   if (ret) {
491     if (!a_args.test_only)
492       ALOGE("Failed to apply the frame composition ret=%d", ret);
493     return HWC2::Error::BadParameter;
494   }
495 
496   if (mode_update_commited_) {
497     staged_mode_.reset();
498     vsync_tracking_en_ = false;
499     if (last_vsync_ts_ != 0) {
500       hwc2_->SendVsyncPeriodTimingChangedEventToClient(
501           handle_, last_vsync_ts_ + PrevModeVsyncPeriodNs);
502     }
503   }
504 
505   return HWC2::Error::None;
506 }
507 
508 /* Find API details at:
509  * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1805
510  */
PresentDisplay(int32_t * present_fence)511 HWC2::Error HwcDisplay::PresentDisplay(int32_t *present_fence) {
512   if (IsInHeadlessMode()) {
513     *present_fence = -1;
514     return HWC2::Error::None;
515   }
516   HWC2::Error ret{};
517 
518   ++total_stats_.total_frames_;
519 
520   AtomicCommitArgs a_args{};
521   ret = CreateComposition(a_args);
522 
523   if (ret != HWC2::Error::None)
524     ++total_stats_.failed_kms_present_;
525 
526   if (ret == HWC2::Error::BadLayer) {
527     // Can we really have no client or device layers?
528     *present_fence = -1;
529     return HWC2::Error::None;
530   }
531   if (ret != HWC2::Error::None)
532     return ret;
533 
534   *present_fence = a_args.out_fence.Release();
535 
536   ++frame_no_;
537   return HWC2::Error::None;
538 }
539 
SetActiveConfigInternal(uint32_t config,int64_t change_time)540 HWC2::Error HwcDisplay::SetActiveConfigInternal(uint32_t config,
541                                                 int64_t change_time) {
542   if (configs_.hwc_configs.count(config) == 0) {
543     ALOGE("Could not find active mode for %u", config);
544     return HWC2::Error::BadConfig;
545   }
546 
547   staged_mode_ = configs_.hwc_configs[config].mode;
548   staged_mode_change_time_ = change_time;
549   staged_mode_config_id_ = config;
550 
551   return HWC2::Error::None;
552 }
553 
SetActiveConfig(hwc2_config_t config)554 HWC2::Error HwcDisplay::SetActiveConfig(hwc2_config_t config) {
555   return SetActiveConfigInternal(config, ResourceManager::GetTimeMonotonicNs());
556 }
557 
558 /* Find API details at:
559  * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1861
560  */
SetClientTarget(buffer_handle_t target,int32_t acquire_fence,int32_t dataspace,hwc_region_t)561 HWC2::Error HwcDisplay::SetClientTarget(buffer_handle_t target,
562                                         int32_t acquire_fence,
563                                         int32_t dataspace,
564                                         hwc_region_t /*damage*/) {
565   client_layer_.SetLayerBuffer(target, acquire_fence);
566   client_layer_.SetLayerDataspace(dataspace);
567 
568   /*
569    * target can be nullptr, this does mean the Composer Service is calling
570    * cleanDisplayResources() on after receiving HOTPLUG event. See more at:
571    * https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h;l=350;drc=944b68180b008456ed2eb4d4d329e33b19bd5166
572    */
573   if (target == nullptr) {
574     return HWC2::Error::None;
575   }
576 
577   /* TODO: Do not update source_crop every call.
578    * It makes sense to do it once after every hotplug event. */
579   HwcDrmBo bo{};
580   BufferInfoGetter::GetInstance()->ConvertBoInfo(target, &bo);
581 
582   hwc_frect_t source_crop = {.left = 0.0F,
583                              .top = 0.0F,
584                              .right = static_cast<float>(bo.width),
585                              .bottom = static_cast<float>(bo.height)};
586   client_layer_.SetLayerSourceCrop(source_crop);
587 
588   return HWC2::Error::None;
589 }
590 
SetColorMode(int32_t mode)591 HWC2::Error HwcDisplay::SetColorMode(int32_t mode) {
592   if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_BT2100_HLG)
593     return HWC2::Error::BadParameter;
594 
595   if (mode != HAL_COLOR_MODE_NATIVE)
596     return HWC2::Error::Unsupported;
597 
598   color_mode_ = mode;
599   return HWC2::Error::None;
600 }
601 
SetColorTransform(const float * matrix,int32_t hint)602 HWC2::Error HwcDisplay::SetColorTransform(const float *matrix, int32_t hint) {
603   if (hint < HAL_COLOR_TRANSFORM_IDENTITY ||
604       hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA)
605     return HWC2::Error::BadParameter;
606 
607   if (!matrix && hint == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX)
608     return HWC2::Error::BadParameter;
609 
610   color_transform_hint_ = static_cast<android_color_transform_t>(hint);
611   if (color_transform_hint_ == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX)
612     std::copy(matrix, matrix + MATRIX_SIZE, color_transform_matrix_.begin());
613 
614   return HWC2::Error::None;
615 }
616 
SetOutputBuffer(buffer_handle_t,int32_t)617 HWC2::Error HwcDisplay::SetOutputBuffer(buffer_handle_t /*buffer*/,
618                                         int32_t /*release_fence*/) {
619   // TODO(nobody): Need virtual display support
620   return HWC2::Error::Unsupported;
621 }
622 
SetPowerMode(int32_t mode_in)623 HWC2::Error HwcDisplay::SetPowerMode(int32_t mode_in) {
624   if (IsInHeadlessMode()) {
625     return HWC2::Error::None;
626   }
627 
628   auto mode = static_cast<HWC2::PowerMode>(mode_in);
629   AtomicCommitArgs a_args{};
630 
631   switch (mode) {
632     case HWC2::PowerMode::Off:
633       a_args.active = false;
634       break;
635     case HWC2::PowerMode::On:
636       /*
637        * Setting the display to active before we have a composition
638        * can break some drivers, so skip setting a_args.active to
639        * true, as the next composition frame will implicitly activate
640        * the display
641        */
642       return GetPipe().atomic_state_manager->ActivateDisplayUsingDPMS() == 0
643                  ? HWC2::Error::None
644                  : HWC2::Error::BadParameter;
645       break;
646     case HWC2::PowerMode::Doze:
647     case HWC2::PowerMode::DozeSuspend:
648       return HWC2::Error::Unsupported;
649     default:
650       ALOGI("Power mode %d is unsupported\n", mode);
651       return HWC2::Error::BadParameter;
652   };
653 
654   int err = GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
655   if (err) {
656     ALOGE("Failed to apply the dpms composition err=%d", err);
657     return HWC2::Error::BadParameter;
658   }
659   return HWC2::Error::None;
660 }
661 
SetVsyncEnabled(int32_t enabled)662 HWC2::Error HwcDisplay::SetVsyncEnabled(int32_t enabled) {
663   vsync_event_en_ = HWC2_VSYNC_ENABLE == enabled;
664   if (vsync_event_en_) {
665     vsync_worker_.VSyncControl(true);
666   }
667   return HWC2::Error::None;
668 }
669 
ValidateDisplay(uint32_t * num_types,uint32_t * num_requests)670 HWC2::Error HwcDisplay::ValidateDisplay(uint32_t *num_types,
671                                         uint32_t *num_requests) {
672   if (IsInHeadlessMode()) {
673     *num_types = *num_requests = 0;
674     return HWC2::Error::None;
675   }
676   return backend_->ValidateDisplay(this, num_types, num_requests);
677 }
678 
GetOrderLayersByZPos()679 std::vector<HwcLayer *> HwcDisplay::GetOrderLayersByZPos() {
680   std::vector<HwcLayer *> ordered_layers;
681   ordered_layers.reserve(layers_.size());
682 
683   for (auto &[handle, layer] : layers_) {
684     ordered_layers.emplace_back(&layer);
685   }
686 
687   std::sort(std::begin(ordered_layers), std::end(ordered_layers),
688             [](const HwcLayer *lhs, const HwcLayer *rhs) {
689               return lhs->GetZOrder() < rhs->GetZOrder();
690             });
691 
692   return ordered_layers;
693 }
694 
GetDisplayVsyncPeriod(uint32_t * outVsyncPeriod)695 HWC2::Error HwcDisplay::GetDisplayVsyncPeriod(
696     uint32_t *outVsyncPeriod /* ns */) {
697   return GetDisplayAttribute(configs_.active_config_id,
698                              HWC2_ATTRIBUTE_VSYNC_PERIOD,
699                              (int32_t *)(outVsyncPeriod));
700 }
701 
702 #if PLATFORM_SDK_VERSION > 29
GetDisplayConnectionType(uint32_t * outType)703 HWC2::Error HwcDisplay::GetDisplayConnectionType(uint32_t *outType) {
704   if (IsInHeadlessMode()) {
705     *outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::Internal);
706     return HWC2::Error::None;
707   }
708   /* Primary display should be always internal,
709    * otherwise SF will be unhappy and will crash
710    */
711   if (GetPipe().connector->Get()->IsInternal() || handle_ == kPrimaryDisplay)
712     *outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::Internal);
713   else if (GetPipe().connector->Get()->IsExternal())
714     *outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::External);
715   else
716     return HWC2::Error::BadConfig;
717 
718   return HWC2::Error::None;
719 }
720 
SetActiveConfigWithConstraints(hwc2_config_t config,hwc_vsync_period_change_constraints_t * vsyncPeriodChangeConstraints,hwc_vsync_period_change_timeline_t * outTimeline)721 HWC2::Error HwcDisplay::SetActiveConfigWithConstraints(
722     hwc2_config_t config,
723     hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints,
724     hwc_vsync_period_change_timeline_t *outTimeline) {
725   if (vsyncPeriodChangeConstraints == nullptr || outTimeline == nullptr) {
726     return HWC2::Error::BadParameter;
727   }
728 
729   uint32_t current_vsync_period{};
730   GetDisplayVsyncPeriod(&current_vsync_period);
731 
732   if (vsyncPeriodChangeConstraints->seamlessRequired) {
733     return HWC2::Error::SeamlessNotAllowed;
734   }
735 
736   outTimeline->refreshTimeNanos = vsyncPeriodChangeConstraints
737                                       ->desiredTimeNanos -
738                                   current_vsync_period;
739   auto ret = SetActiveConfigInternal(config, outTimeline->refreshTimeNanos);
740   if (ret != HWC2::Error::None) {
741     return ret;
742   }
743 
744   outTimeline->refreshRequired = true;
745   outTimeline->newVsyncAppliedTimeNanos = vsyncPeriodChangeConstraints
746                                               ->desiredTimeNanos;
747 
748   last_vsync_ts_ = 0;
749   vsync_tracking_en_ = true;
750   vsync_worker_.VSyncControl(true);
751 
752   return HWC2::Error::None;
753 }
754 
SetAutoLowLatencyMode(bool)755 HWC2::Error HwcDisplay::SetAutoLowLatencyMode(bool /*on*/) {
756   return HWC2::Error::Unsupported;
757 }
758 
GetSupportedContentTypes(uint32_t * outNumSupportedContentTypes,const uint32_t * outSupportedContentTypes)759 HWC2::Error HwcDisplay::GetSupportedContentTypes(
760     uint32_t *outNumSupportedContentTypes,
761     const uint32_t *outSupportedContentTypes) {
762   if (outSupportedContentTypes == nullptr)
763     *outNumSupportedContentTypes = 0;
764 
765   return HWC2::Error::None;
766 }
767 
SetContentType(int32_t contentType)768 HWC2::Error HwcDisplay::SetContentType(int32_t contentType) {
769   if (contentType != HWC2_CONTENT_TYPE_NONE)
770     return HWC2::Error::Unsupported;
771 
772   /* TODO: Map to the DRM Connector property:
773    * https://elixir.bootlin.com/linux/v5.4-rc5/source/drivers/gpu/drm/drm_connector.c#L809
774    */
775 
776   return HWC2::Error::None;
777 }
778 #endif
779 
780 #if PLATFORM_SDK_VERSION > 28
GetDisplayIdentificationData(uint8_t * outPort,uint32_t * outDataSize,uint8_t * outData)781 HWC2::Error HwcDisplay::GetDisplayIdentificationData(uint8_t *outPort,
782                                                      uint32_t *outDataSize,
783                                                      uint8_t *outData) {
784   if (IsInHeadlessMode()) {
785     return HWC2::Error::None;
786   }
787   auto blob = GetPipe().connector->Get()->GetEdidBlob();
788 
789   *outPort = handle_ - 1;
790 
791   if (!blob) {
792     if (outData == nullptr) {
793       *outDataSize = 0;
794     }
795     return HWC2::Error::None;
796   }
797 
798   if (outData) {
799     *outDataSize = std::min(*outDataSize, blob->length);
800     memcpy(outData, blob->data, *outDataSize);
801   } else {
802     *outDataSize = blob->length;
803   }
804 
805   return HWC2::Error::None;
806 }
807 
GetDisplayCapabilities(uint32_t * outNumCapabilities,uint32_t *)808 HWC2::Error HwcDisplay::GetDisplayCapabilities(uint32_t *outNumCapabilities,
809                                                uint32_t * /*outCapabilities*/) {
810   if (outNumCapabilities == nullptr) {
811     return HWC2::Error::BadParameter;
812   }
813 
814   *outNumCapabilities = 0;
815 
816   return HWC2::Error::None;
817 }
818 
GetDisplayBrightnessSupport(bool * supported)819 HWC2::Error HwcDisplay::GetDisplayBrightnessSupport(bool *supported) {
820   *supported = false;
821   return HWC2::Error::None;
822 }
823 
SetDisplayBrightness(float)824 HWC2::Error HwcDisplay::SetDisplayBrightness(float /* brightness */) {
825   return HWC2::Error::Unsupported;
826 }
827 
828 #endif /* PLATFORM_SDK_VERSION > 28 */
829 
830 #if PLATFORM_SDK_VERSION > 27
831 
GetRenderIntents(int32_t mode,uint32_t * outNumIntents,int32_t * outIntents)832 HWC2::Error HwcDisplay::GetRenderIntents(
833     int32_t mode, uint32_t *outNumIntents,
834     int32_t * /*android_render_intent_v1_1_t*/ outIntents) {
835   if (mode != HAL_COLOR_MODE_NATIVE) {
836     return HWC2::Error::BadParameter;
837   }
838 
839   if (outIntents == nullptr) {
840     *outNumIntents = 1;
841     return HWC2::Error::None;
842   }
843   *outNumIntents = 1;
844   outIntents[0] = HAL_RENDER_INTENT_COLORIMETRIC;
845   return HWC2::Error::None;
846 }
847 
SetColorModeWithIntent(int32_t mode,int32_t intent)848 HWC2::Error HwcDisplay::SetColorModeWithIntent(int32_t mode, int32_t intent) {
849   if (intent < HAL_RENDER_INTENT_COLORIMETRIC ||
850       intent > HAL_RENDER_INTENT_TONE_MAP_ENHANCE)
851     return HWC2::Error::BadParameter;
852 
853   if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_BT2100_HLG)
854     return HWC2::Error::BadParameter;
855 
856   if (mode != HAL_COLOR_MODE_NATIVE)
857     return HWC2::Error::Unsupported;
858 
859   if (intent != HAL_RENDER_INTENT_COLORIMETRIC)
860     return HWC2::Error::Unsupported;
861 
862   color_mode_ = mode;
863   return HWC2::Error::None;
864 }
865 
866 #endif /* PLATFORM_SDK_VERSION > 27 */
867 
backend() const868 const Backend *HwcDisplay::backend() const {
869   return backend_.get();
870 }
871 
set_backend(std::unique_ptr<Backend> backend)872 void HwcDisplay::set_backend(std::unique_ptr<Backend> backend) {
873   backend_ = std::move(backend);
874 }
875 
876 /* returns true if composition should be sent to client */
ProcessClientFlatteningState(bool skip)877 bool HwcDisplay::ProcessClientFlatteningState(bool skip) {
878   int flattenning_state = flattenning_state_;
879   if (flattenning_state == ClientFlattenningState::Disabled) {
880     return false;
881   }
882 
883   if (skip) {
884     flattenning_state_ = ClientFlattenningState::NotRequired;
885     return false;
886   }
887 
888   if (flattenning_state == ClientFlattenningState::ClientRefreshRequested) {
889     flattenning_state_ = ClientFlattenningState::Flattened;
890     return true;
891   }
892 
893   vsync_flattening_en_ = true;
894   vsync_worker_.VSyncControl(true);
895   flattenning_state_ = ClientFlattenningState::VsyncCountdownMax;
896   return false;
897 }
898 
ProcessFlatenningVsyncInternal()899 void HwcDisplay::ProcessFlatenningVsyncInternal() {
900   if (flattenning_state_ > ClientFlattenningState::ClientRefreshRequested &&
901       --flattenning_state_ == ClientFlattenningState::ClientRefreshRequested &&
902       hwc2_->refresh_callback_.first != nullptr &&
903       hwc2_->refresh_callback_.second != nullptr) {
904     hwc2_->refresh_callback_.first(hwc2_->refresh_callback_.second, handle_);
905     vsync_flattening_en_ = false;
906   }
907 }
908 
909 }  // namespace android
910