blob: 76fecf953e2b0483d2f6f2372139fa2ae56563d0 [file] [log] [blame]
Sean Pauled2ec4b2016-03-10 15:35:40 -05001/*
2 * Copyright (C) 2016 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 ATRACE_TAG ATRACE_TAG_GRAPHICS
18#define LOG_TAG "hwc-drm-two"
19
Roman Stratiienko13cc3662020-08-29 21:35:39 +030020#include "DrmHwcTwo.h"
Sean Pauled2ec4b2016-03-10 15:35:40 -050021
Roman Stratiienko0fade372021-02-20 13:59:55 +020022#include <fcntl.h>
Sean Paulac874152016-03-10 16:00:26 -050023#include <hardware/hardware.h>
Sean Pauled2ec4b2016-03-10 15:35:40 -050024#include <hardware/hwcomposer2.h>
Roman Stratiienko74774712021-02-05 16:32:47 +020025#include <sync/sync.h>
Roman Stratiienko0fade372021-02-20 13:59:55 +020026#include <unistd.h>
Sean Pauled2ec4b2016-03-10 15:35:40 -050027
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +020028#include <cinttypes>
Roman Stratiienkod21071f2021-03-09 21:56:50 +020029#include <iostream>
30#include <sstream>
Roman Stratiienkoaa3cd542020-08-29 11:26:16 +030031#include <string>
32
Roman Stratiienko13cc3662020-08-29 21:35:39 +030033#include "backend/BackendManager.h"
Roman Stratiienko33365c22020-10-10 23:06:36 +030034#include "bufferinfo/BufferInfoGetter.h"
Roman Stratiienko13cc3662020-08-29 21:35:39 +030035#include "compositor/DrmDisplayComposition.h"
Roman Stratiienkod21071f2021-03-09 21:56:50 +020036#include "utils/log.h"
37#include "utils/properties.h"
Roman Stratiienkoaa3cd542020-08-29 11:26:16 +030038
Sean Pauled2ec4b2016-03-10 15:35:40 -050039namespace android {
40
Roman Stratiienko26fd2b22022-01-04 12:59:29 +020041DrmHwcTwo::DrmHwcTwo() = default;
Sean Pauled2ec4b2016-03-10 15:35:40 -050042
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +030043HWC2::Error DrmHwcTwo::CreateDisplay(hwc2_display_t displ,
44 HWC2::DisplayType type) {
Roman Stratiienkod26619b2021-08-04 19:55:37 +030045 DrmDevice *drm = resource_manager_.GetDrmDevice(static_cast<int>(displ));
Roman Stratiienko8666dc92021-02-09 17:49:55 +020046 if (!drm) {
47 ALOGE("Failed to get a valid drmresource");
Sean Paulac874152016-03-10 16:00:26 -050048 return HWC2::Error::NoResources;
49 }
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +030050 displays_.emplace(std::piecewise_construct, std::forward_as_tuple(displ),
Roman Stratiienko863a3c22021-09-29 13:00:29 +030051 std::forward_as_tuple(&resource_manager_, drm, displ, type,
52 this));
Sean Paulac874152016-03-10 16:00:26 -050053
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +030054 DrmCrtc *crtc = drm->GetCrtcForDisplay(static_cast<int>(displ));
Sean Paulac874152016-03-10 16:00:26 -050055 if (!crtc) {
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +030056 ALOGE("Failed to get crtc for display %d", static_cast<int>(displ));
Sean Paulac874152016-03-10 16:00:26 -050057 return HWC2::Error::BadDisplay;
58 }
Roman Stratiienkod21071f2021-03-09 21:56:50 +020059 auto display_planes = std::vector<DrmPlane *>();
60 for (const auto &plane : drm->planes()) {
Sean Paulac874152016-03-10 16:00:26 -050061 if (plane->GetCrtcSupported(*crtc))
62 display_planes.push_back(plane.get());
63 }
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +030064 displays_.at(displ).Init(&display_planes);
Sean Paulac874152016-03-10 16:00:26 -050065 return HWC2::Error::None;
66}
67
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +030068HWC2::Error DrmHwcTwo::Init() {
69 int rv = resource_manager_.Init();
70 if (rv) {
71 ALOGE("Can't initialize the resource manager %d", rv);
72 return HWC2::Error::NoResources;
73 }
74
75 HWC2::Error ret = HWC2::Error::None;
Roman Stratiienkofc014f52021-12-23 19:04:29 +020076 for (int i = 0; i < resource_manager_.GetDisplayCount(); i++) {
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +030077 ret = CreateDisplay(i, HWC2::DisplayType::Physical);
78 if (ret != HWC2::Error::None) {
79 ALOGE("Failed to create display %d with error %d", i, ret);
80 return ret;
81 }
82 }
83
Roman Stratiienko1e053b42021-10-25 22:54:20 +030084 resource_manager_.GetUEventListener()->RegisterHotplugHandler(
85 [this] { HandleHotplugUEvent(); });
86
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +030087 return ret;
88}
89
Roman Stratiienko7f576ec2021-12-22 17:34:18 +020090HWC2::Error DrmHwcTwo::CreateVirtualDisplay(uint32_t /*width*/,
91 uint32_t /*height*/,
92 int32_t * /*format*/,
93 hwc2_display_t * /*display*/) {
94 // TODO(nobody): Implement virtual display
Sean Pauled2ec4b2016-03-10 15:35:40 -050095 return HWC2::Error::Unsupported;
96}
97
Roman Stratiienko7f576ec2021-12-22 17:34:18 +020098HWC2::Error DrmHwcTwo::DestroyVirtualDisplay(hwc2_display_t /*display*/) {
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +020099 // TODO(nobody): Implement virtual display
Roman Stratiienko7f576ec2021-12-22 17:34:18 +0200100 return HWC2::Error::Unsupported;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500101}
102
Roman Stratiienko0d1a2cd2019-11-28 17:51:16 +0200103std::string DrmHwcTwo::HwcDisplay::DumpDelta(
104 DrmHwcTwo::HwcDisplay::Stats delta) {
105 if (delta.total_pixops_ == 0)
106 return "No stats yet";
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200107 double ratio = 1.0 - double(delta.gpu_pixops_) / double(delta.total_pixops_);
Roman Stratiienko0d1a2cd2019-11-28 17:51:16 +0200108
Roman Stratiienkod21071f2021-03-09 21:56:50 +0200109 std::stringstream ss;
110 ss << " Total frames count: " << delta.total_frames_ << "\n"
111 << " Failed to test commit frames: " << delta.failed_kms_validate_ << "\n"
112 << " Failed to commit frames: " << delta.failed_kms_present_ << "\n"
113 << ((delta.failed_kms_present_ > 0)
114 ? " !!! Internal failure, FIX it please\n"
115 : "")
116 << " Flattened frames: " << delta.frames_flattened_ << "\n"
117 << " Pixel operations (free units)"
118 << " : [TOTAL: " << delta.total_pixops_ << " / GPU: " << delta.gpu_pixops_
119 << "]\n"
120 << " Composition efficiency: " << ratio;
121
122 return ss.str();
Roman Stratiienko0d1a2cd2019-11-28 17:51:16 +0200123}
124
125std::string DrmHwcTwo::HwcDisplay::Dump() {
Roman Stratiienkoe8c06792021-09-30 10:09:31 +0300126 std::string flattening_state_str;
127 switch (flattenning_state_) {
128 case ClientFlattenningState::Disabled:
129 flattening_state_str = "Disabled";
130 break;
131 case ClientFlattenningState::NotRequired:
132 flattening_state_str = "Not needed";
133 break;
134 case ClientFlattenningState::Flattened:
135 flattening_state_str = "Active";
136 break;
137 case ClientFlattenningState::ClientRefreshRequested:
138 flattening_state_str = "Refresh requested";
139 break;
140 default:
141 flattening_state_str = std::to_string(flattenning_state_) +
142 " VSync remains";
143 }
144
Roman Stratiienkod21071f2021-03-09 21:56:50 +0200145 std::stringstream ss;
146 ss << "- Display on: " << connector_->name() << "\n"
Roman Stratiienkoe8c06792021-09-30 10:09:31 +0300147 << " Flattening state: " << flattening_state_str << "\n"
Roman Stratiienkod21071f2021-03-09 21:56:50 +0200148 << "Statistics since system boot:\n"
149 << DumpDelta(total_stats_) << "\n\n"
150 << "Statistics since last dumpsys request:\n"
151 << DumpDelta(total_stats_.minus(prev_stats_)) << "\n\n";
Roman Stratiienko0d1a2cd2019-11-28 17:51:16 +0200152
153 memcpy(&prev_stats_, &total_stats_, sizeof(Stats));
Roman Stratiienkod21071f2021-03-09 21:56:50 +0200154 return ss.str();
Roman Stratiienko0d1a2cd2019-11-28 17:51:16 +0200155}
156
157void DrmHwcTwo::Dump(uint32_t *outSize, char *outBuffer) {
Roman Stratiienko0d1a2cd2019-11-28 17:51:16 +0200158 if (outBuffer != nullptr) {
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200159 auto copied_bytes = mDumpString.copy(outBuffer, *outSize);
160 *outSize = static_cast<uint32_t>(copied_bytes);
Roman Stratiienko0d1a2cd2019-11-28 17:51:16 +0200161 return;
162 }
163
164 std::stringstream output;
165
166 output << "-- drm_hwcomposer --\n\n";
167
168 for (std::pair<const hwc2_display_t, DrmHwcTwo::HwcDisplay> &dp : displays_)
169 output << dp.second.Dump();
170
171 mDumpString = output.str();
172 *outSize = static_cast<uint32_t>(mDumpString.size());
Sean Pauled2ec4b2016-03-10 15:35:40 -0500173}
174
175uint32_t DrmHwcTwo::GetMaxVirtualDisplayCount() {
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200176 // TODO(nobody): Implement virtual display
Sean Pauled2ec4b2016-03-10 15:35:40 -0500177 return 0;
178}
179
180HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
Sean Paulac874152016-03-10 16:00:26 -0500181 hwc2_callback_data_t data,
182 hwc2_function_pointer_t function) {
Roman Stratiienko863a3c22021-09-29 13:00:29 +0300183 std::unique_lock<std::mutex> lock(callback_lock_);
184
Roman Stratiienko23701092020-09-26 02:08:41 +0300185 switch (static_cast<HWC2::Callback>(descriptor)) {
Sean Paulac874152016-03-10 16:00:26 -0500186 case HWC2::Callback::Hotplug: {
Roman Stratiienko863a3c22021-09-29 13:00:29 +0300187 hotplug_callback_ = std::make_pair(HWC2_PFN_HOTPLUG(function), data);
188 lock.unlock();
Roman Stratiienkofc014f52021-12-23 19:04:29 +0200189 const auto &drm_devices = resource_manager_.GetDrmDevices();
Roman Stratiienkod21071f2021-03-09 21:56:50 +0200190 for (const auto &device : drm_devices)
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +0300191 HandleInitialHotplugState(device.get());
Sean Paulac874152016-03-10 16:00:26 -0500192 break;
193 }
Roman Kovalivskyi8fae1562020-01-30 20:20:47 +0200194 case HWC2::Callback::Refresh: {
Roman Stratiienko863a3c22021-09-29 13:00:29 +0300195 refresh_callback_ = std::make_pair(HWC2_PFN_REFRESH(function), data);
Roman Kovalivskyi8fae1562020-01-30 20:20:47 +0200196 break;
197 }
Sean Paulac874152016-03-10 16:00:26 -0500198 case HWC2::Callback::Vsync: {
Roman Stratiienko863a3c22021-09-29 13:00:29 +0300199 vsync_callback_ = std::make_pair(HWC2_PFN_VSYNC(function), data);
Sean Paulac874152016-03-10 16:00:26 -0500200 break;
201 }
Roman Stratiienko11ef8c52021-09-29 13:01:39 +0300202#if PLATFORM_SDK_VERSION > 29
203 case HWC2::Callback::Vsync_2_4: {
204 vsync_2_4_callback_ = std::make_pair(HWC2_PFN_VSYNC_2_4(function), data);
205 break;
206 }
207#endif
Sean Paulac874152016-03-10 16:00:26 -0500208 default:
209 break;
210 }
211 return HWC2::Error::None;
212}
213
Alexandru Gheorghe6f0030f2018-05-01 17:25:48 +0100214DrmHwcTwo::HwcDisplay::HwcDisplay(ResourceManager *resource_manager,
Roman Stratiienko8666dc92021-02-09 17:49:55 +0200215 DrmDevice *drm, hwc2_display_t handle,
Roman Stratiienko863a3c22021-09-29 13:00:29 +0300216 HWC2::DisplayType type, DrmHwcTwo *hwc2)
217 : hwc2_(hwc2),
218 resource_manager_(resource_manager),
Alexandru Gheorghe6f0030f2018-05-01 17:25:48 +0100219 drm_(drm),
Alexandru Gheorghe6f0030f2018-05-01 17:25:48 +0100220 handle_(handle),
Roman Kovalivskyi12b91a32019-12-11 19:09:51 +0200221 type_(type),
222 color_transform_hint_(HAL_COLOR_TRANSFORM_IDENTITY) {
Roman Kovalivskyi12b91a32019-12-11 19:09:51 +0200223 // clang-format off
224 color_transform_matrix_ = {1.0, 0.0, 0.0, 0.0,
225 0.0, 1.0, 0.0, 0.0,
226 0.0, 0.0, 1.0, 0.0,
227 0.0, 0.0, 0.0, 1.0};
228 // clang-format on
Sean Paulac874152016-03-10 16:00:26 -0500229}
230
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +0300231void DrmHwcTwo::HwcDisplay::ClearDisplay() {
Roman Stratiienkodccc6fb2021-10-23 17:35:44 +0300232 AtomicCommitArgs a_args = {.clear_active_composition = true};
233 compositor_.ExecuteAtomicCommit(a_args);
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +0300234}
235
Sean Paulac874152016-03-10 16:00:26 -0500236HWC2::Error DrmHwcTwo::HwcDisplay::Init(std::vector<DrmPlane *> *planes) {
Sean Paulac874152016-03-10 16:00:26 -0500237 int display = static_cast<int>(handle_);
Roman Stratiienkoe8c06792021-09-30 10:09:31 +0300238 int ret = compositor_.Init(resource_manager_, display);
Sean Paulac874152016-03-10 16:00:26 -0500239 if (ret) {
240 ALOGE("Failed display compositor init for display %d (%d)", display, ret);
241 return HWC2::Error::NoResources;
242 }
243
244 // Split up the given display planes into primary and overlay to properly
245 // interface with the composition
246 char use_overlay_planes_prop[PROPERTY_VALUE_MAX];
Jason Macnakf1af9572020-08-20 11:49:51 -0700247 property_get("vendor.hwc.drm.use_overlay_planes", use_overlay_planes_prop,
248 "1");
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200249 bool use_overlay_planes = strtol(use_overlay_planes_prop, nullptr, 10);
Sean Paulac874152016-03-10 16:00:26 -0500250 for (auto &plane : *planes) {
Roman Stratiienkofc014f52021-12-23 19:04:29 +0200251 if (plane->GetType() == DRM_PLANE_TYPE_PRIMARY)
Sean Paulac874152016-03-10 16:00:26 -0500252 primary_planes_.push_back(plane);
Roman Stratiienkofc014f52021-12-23 19:04:29 +0200253 else if (use_overlay_planes && (plane)->GetType() == DRM_PLANE_TYPE_OVERLAY)
Sean Paulac874152016-03-10 16:00:26 -0500254 overlay_planes_.push_back(plane);
255 }
256
257 crtc_ = drm_->GetCrtcForDisplay(display);
258 if (!crtc_) {
259 ALOGE("Failed to get crtc for display %d", display);
260 return HWC2::Error::BadDisplay;
261 }
262
263 connector_ = drm_->GetConnectorForDisplay(display);
264 if (!connector_) {
265 ALOGE("Failed to get connector for display %d", display);
266 return HWC2::Error::BadDisplay;
267 }
268
Roman Stratiienko863a3c22021-09-29 13:00:29 +0300269 ret = vsync_worker_.Init(drm_, display, [this](int64_t timestamp) {
Roman Stratiienko863a3c22021-09-29 13:00:29 +0300270 const std::lock_guard<std::mutex> lock(hwc2_->callback_lock_);
Roman Stratiienko11ef8c52021-09-29 13:01:39 +0300271 /* vsync callback */
272#if PLATFORM_SDK_VERSION > 29
273 if (hwc2_->vsync_2_4_callback_.first != nullptr &&
274 hwc2_->vsync_2_4_callback_.second != nullptr) {
275 hwc2_vsync_period_t period_ns{};
276 GetDisplayVsyncPeriod(&period_ns);
277 hwc2_->vsync_2_4_callback_.first(hwc2_->vsync_2_4_callback_.second,
278 handle_, timestamp, period_ns);
279 } else
280#endif
281 if (hwc2_->vsync_callback_.first != nullptr &&
282 hwc2_->vsync_callback_.second != nullptr) {
Roman Stratiienko863a3c22021-09-29 13:00:29 +0300283 hwc2_->vsync_callback_.first(hwc2_->vsync_callback_.second, handle_,
284 timestamp);
285 }
286 });
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +0300287 if (ret) {
288 ALOGE("Failed to create event worker for d=%d %d\n", display, ret);
289 return HWC2::Error::BadDisplay;
290 }
291
Roman Stratiienkoe8c06792021-09-30 10:09:31 +0300292 ret = flattening_vsync_worker_.Init(drm_, display, [this](int64_t /*timestamp*/) {
293 const std::lock_guard<std::mutex> lock(hwc2_->callback_lock_);
294 /* Frontend flattening */
295 if (flattenning_state_ > ClientFlattenningState::ClientRefreshRequested &&
296 --flattenning_state_ ==
297 ClientFlattenningState::ClientRefreshRequested &&
298 hwc2_->refresh_callback_.first != nullptr &&
299 hwc2_->refresh_callback_.second != nullptr) {
300 hwc2_->refresh_callback_.first(hwc2_->refresh_callback_.second, handle_);
301 flattening_vsync_worker_.VSyncControl(false);
302 }
303 });
304 if (ret) {
305 ALOGE("Failed to create event worker for d=%d %d\n", display, ret);
306 return HWC2::Error::BadDisplay;
307 }
308
Matvii Zorinef3c7972020-08-11 15:15:44 +0300309 ret = BackendManager::GetInstance().SetBackendForDisplay(this);
310 if (ret) {
311 ALOGE("Failed to set backend for d=%d %d\n", display, ret);
312 return HWC2::Error::BadDisplay;
313 }
314
Roman Stratiienko720f6522021-12-06 14:56:14 +0200315 client_layer_.SetLayerBlendMode(HWC2_BLEND_MODE_PREMULTIPLIED);
316
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +0300317 return ChosePreferredConfig();
318}
319
320HWC2::Error DrmHwcTwo::HwcDisplay::ChosePreferredConfig() {
Sean Paulac874152016-03-10 16:00:26 -0500321 // Fetch the number of modes from the display
Roman Stratiienkob3b5c1e2021-02-15 13:44:19 +0200322 uint32_t num_configs = 0;
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200323 HWC2::Error err = GetDisplayConfigs(&num_configs, nullptr);
Sean Paulac874152016-03-10 16:00:26 -0500324 if (err != HWC2::Error::None || !num_configs)
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200325 return HWC2::Error::BadDisplay;
Sean Paulac874152016-03-10 16:00:26 -0500326
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200327 return SetActiveConfig(preferred_config_id_);
Sean Paulac874152016-03-10 16:00:26 -0500328}
329
Sean Pauled2ec4b2016-03-10 15:35:40 -0500330HWC2::Error DrmHwcTwo::HwcDisplay::AcceptDisplayChanges() {
Roman Stratiienko03fd35c2022-01-04 14:30:37 +0200331 for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_)
332 l.second.AcceptTypeChange();
Sean Paulac874152016-03-10 16:00:26 -0500333 return HWC2::Error::None;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500334}
335
336HWC2::Error DrmHwcTwo::HwcDisplay::CreateLayer(hwc2_layer_t *layer) {
Sean Paulac874152016-03-10 16:00:26 -0500337 layers_.emplace(static_cast<hwc2_layer_t>(layer_idx_), HwcLayer());
338 *layer = static_cast<hwc2_layer_t>(layer_idx_);
339 ++layer_idx_;
340 return HWC2::Error::None;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500341}
342
343HWC2::Error DrmHwcTwo::HwcDisplay::DestroyLayer(hwc2_layer_t layer) {
Vincent Donnefort9abec032019-10-09 15:43:43 +0100344 if (!get_layer(layer))
345 return HWC2::Error::BadLayer;
346
Sean Paulac874152016-03-10 16:00:26 -0500347 layers_.erase(layer);
348 return HWC2::Error::None;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500349}
350
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200351HWC2::Error DrmHwcTwo::HwcDisplay::GetActiveConfig(
352 hwc2_config_t *config) const {
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200353 if (hwc_configs_.count(active_config_id_) == 0)
Sean Paulac874152016-03-10 16:00:26 -0500354 return HWC2::Error::BadConfig;
355
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200356 *config = active_config_id_;
Sean Paulac874152016-03-10 16:00:26 -0500357 return HWC2::Error::None;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500358}
359
360HWC2::Error DrmHwcTwo::HwcDisplay::GetChangedCompositionTypes(
361 uint32_t *num_elements, hwc2_layer_t *layers, int32_t *types) {
Sean Paulac874152016-03-10 16:00:26 -0500362 uint32_t num_changes = 0;
Roman Stratiienko03fd35c2022-01-04 14:30:37 +0200363 for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) {
364 if (l.second.IsTypeChanged()) {
Sean Paulac874152016-03-10 16:00:26 -0500365 if (layers && num_changes < *num_elements)
366 layers[num_changes] = l.first;
367 if (types && num_changes < *num_elements)
Roman Stratiienko03fd35c2022-01-04 14:30:37 +0200368 types[num_changes] = static_cast<int32_t>(l.second.GetValidatedType());
Sean Paulac874152016-03-10 16:00:26 -0500369 ++num_changes;
370 }
371 }
372 if (!layers && !types)
373 *num_elements = num_changes;
374 return HWC2::Error::None;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500375}
376
377HWC2::Error DrmHwcTwo::HwcDisplay::GetClientTargetSupport(uint32_t width,
Sean Paulac874152016-03-10 16:00:26 -0500378 uint32_t height,
379 int32_t /*format*/,
380 int32_t dataspace) {
Sean Paulac874152016-03-10 16:00:26 -0500381 std::pair<uint32_t, uint32_t> min = drm_->min_resolution();
382 std::pair<uint32_t, uint32_t> max = drm_->max_resolution();
383
384 if (width < min.first || height < min.second)
385 return HWC2::Error::Unsupported;
386
387 if (width > max.first || height > max.second)
388 return HWC2::Error::Unsupported;
389
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200390 if (dataspace != HAL_DATASPACE_UNKNOWN)
Sean Paulac874152016-03-10 16:00:26 -0500391 return HWC2::Error::Unsupported;
392
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200393 // TODO(nobody): Validate format can be handled by either GL or planes
Sean Paulac874152016-03-10 16:00:26 -0500394 return HWC2::Error::None;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500395}
396
397HWC2::Error DrmHwcTwo::HwcDisplay::GetColorModes(uint32_t *num_modes,
Sean Paulac874152016-03-10 16:00:26 -0500398 int32_t *modes) {
Kalyan Kondapallyda5839c2016-11-10 10:59:50 -0800399 if (!modes)
400 *num_modes = 1;
401
402 if (modes)
403 *modes = HAL_COLOR_MODE_NATIVE;
404
405 return HWC2::Error::None;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500406}
407
408HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayAttribute(hwc2_config_t config,
Sean Paulac874152016-03-10 16:00:26 -0500409 int32_t attribute_in,
410 int32_t *value) {
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200411 int conf = static_cast<int>(config);
412
413 if (hwc_configs_.count(conf) == 0) {
414 ALOGE("Could not find active mode for %d", conf);
Sean Paulac874152016-03-10 16:00:26 -0500415 return HWC2::Error::BadConfig;
416 }
417
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200418 auto &hwc_config = hwc_configs_[conf];
419
Sean Paulac874152016-03-10 16:00:26 -0500420 static const int32_t kUmPerInch = 25400;
421 uint32_t mm_width = connector_->mm_width();
422 uint32_t mm_height = connector_->mm_height();
423 auto attribute = static_cast<HWC2::Attribute>(attribute_in);
424 switch (attribute) {
425 case HWC2::Attribute::Width:
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200426 *value = static_cast<int>(hwc_config.mode.h_display());
Sean Paulac874152016-03-10 16:00:26 -0500427 break;
428 case HWC2::Attribute::Height:
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200429 *value = static_cast<int>(hwc_config.mode.v_display());
Sean Paulac874152016-03-10 16:00:26 -0500430 break;
431 case HWC2::Attribute::VsyncPeriod:
432 // in nanoseconds
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200433 *value = static_cast<int>(1E9 / hwc_config.mode.v_refresh());
Sean Paulac874152016-03-10 16:00:26 -0500434 break;
435 case HWC2::Attribute::DpiX:
436 // Dots per 1000 inches
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200437 *value = mm_width ? static_cast<int>(hwc_config.mode.h_display() *
438 kUmPerInch / mm_width)
439 : -1;
Sean Paulac874152016-03-10 16:00:26 -0500440 break;
441 case HWC2::Attribute::DpiY:
442 // Dots per 1000 inches
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200443 *value = mm_height ? static_cast<int>(hwc_config.mode.v_display() *
444 kUmPerInch / mm_height)
Roman Stratiienkod26619b2021-08-04 19:55:37 +0300445 : -1;
Sean Paulac874152016-03-10 16:00:26 -0500446 break;
Roman Stratiienko6f5df172020-09-27 22:48:08 +0300447#if PLATFORM_SDK_VERSION > 29
448 case HWC2::Attribute::ConfigGroup:
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200449 /* Dispite ConfigGroup is a part of HWC2.4 API, framework
450 * able to request it even if service @2.1 is used */
451 *value = hwc_config.group_id;
Roman Stratiienko6f5df172020-09-27 22:48:08 +0300452 break;
453#endif
Sean Paulac874152016-03-10 16:00:26 -0500454 default:
455 *value = -1;
456 return HWC2::Error::BadConfig;
457 }
458 return HWC2::Error::None;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500459}
460
Roman Stratiienko5f2f3ce2021-12-22 11:46:03 +0200461// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
Sean Pauled2ec4b2016-03-10 15:35:40 -0500462HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayConfigs(uint32_t *num_configs,
463 hwc2_config_t *configs) {
Sean Paulac874152016-03-10 16:00:26 -0500464 // Since this callback is normally invoked twice (once to get the count, and
465 // once to populate configs), we don't really want to read the edid
466 // redundantly. Instead, only update the modes on the first invocation. While
467 // it's possible this will result in stale modes, it'll all come out in the
468 // wash when we try to set the active config later.
469 if (!configs) {
470 int ret = connector_->UpdateModes();
471 if (ret) {
472 ALOGE("Failed to update display modes %d", ret);
473 return HWC2::Error::BadDisplay;
474 }
Sean Paulac874152016-03-10 16:00:26 -0500475
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200476 hwc_configs_.clear();
477 preferred_config_id_ = 0;
478 int preferred_config_group_id_ = 0;
Neil Armstrongb67d0492019-06-20 09:00:21 +0000479
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200480 if (connector_->modes().empty()) {
481 ALOGE("No modes reported by KMS");
482 return HWC2::Error::BadDisplay;
Neil Armstrong4c027a72019-06-04 14:48:02 +0000483 }
Neil Armstrongb67d0492019-06-20 09:00:21 +0000484
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200485 int last_config_id = 1;
486 int last_group_id = 1;
Neil Armstrongb67d0492019-06-20 09:00:21 +0000487
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200488 /* Group modes */
489 for (const auto &mode : connector_->modes()) {
490 /* Find group for the new mode or create new group */
491 int group_found = 0;
492 for (auto &hwc_config : hwc_configs_) {
493 if (mode.h_display() == hwc_config.second.mode.h_display() &&
494 mode.v_display() == hwc_config.second.mode.v_display()) {
495 group_found = hwc_config.second.group_id;
496 }
497 }
498 if (group_found == 0) {
499 group_found = last_group_id++;
500 }
501
502 bool disabled = false;
503 if (mode.flags() & DRM_MODE_FLAG_3D_MASK) {
504 ALOGI("Disabling display mode %s (Modes with 3D flag aren't supported)",
505 mode.name().c_str());
506 disabled = true;
507 }
508
509 /* Add config */
510 hwc_configs_[last_config_id] = {
511 .id = last_config_id,
512 .group_id = group_found,
513 .mode = mode,
514 .disabled = disabled,
515 };
516
517 /* Chwck if the mode is preferred */
518 if ((mode.type() & DRM_MODE_TYPE_PREFERRED) != 0 &&
519 preferred_config_id_ == 0) {
520 preferred_config_id_ = last_config_id;
521 preferred_config_group_id_ = group_found;
522 }
523
524 last_config_id++;
525 }
526
527 /* We must have preferred mode. Set first mode as preferred
528 * in case KMS haven't reported anything. */
529 if (preferred_config_id_ == 0) {
530 preferred_config_id_ = 1;
531 preferred_config_group_id_ = 1;
532 }
533
534 for (int group = 1; group < last_group_id; group++) {
535 bool has_interlaced = false;
536 bool has_progressive = false;
537 for (auto &hwc_config : hwc_configs_) {
538 if (hwc_config.second.group_id != group || hwc_config.second.disabled) {
539 continue;
540 }
541
542 if (hwc_config.second.IsInterlaced()) {
543 has_interlaced = true;
544 } else {
545 has_progressive = true;
546 }
547 }
548
549 bool has_both = has_interlaced && has_progressive;
550 if (!has_both) {
551 continue;
552 }
553
554 bool group_contains_preferred_interlaced = false;
555 if (group == preferred_config_group_id_ &&
556 hwc_configs_[preferred_config_id_].IsInterlaced()) {
557 group_contains_preferred_interlaced = true;
558 }
559
560 for (auto &hwc_config : hwc_configs_) {
561 if (hwc_config.second.group_id != group || hwc_config.second.disabled) {
562 continue;
563 }
564
565 bool disable = group_contains_preferred_interlaced
566 ? !hwc_config.second.IsInterlaced()
567 : hwc_config.second.IsInterlaced();
568
569 if (disable) {
570 ALOGI(
571 "Group %i: Disabling display mode %s (This group should consist "
572 "of %s modes)",
573 group, hwc_config.second.mode.name().c_str(),
574 group_contains_preferred_interlaced ? "interlaced"
575 : "progressive");
576
577 hwc_config.second.disabled = true;
578 }
579 }
580 }
581
582 /* Group should not contain 2 modes with FPS delta less than ~1HZ
583 * otherwise android.graphics.cts.SetFrameRateTest CTS will fail
584 */
585 for (int m1 = 1; m1 < last_config_id; m1++) {
586 for (int m2 = 1; m2 < last_config_id; m2++) {
587 if (m1 != m2 &&
588 hwc_configs_[m1].group_id == hwc_configs_[m2].group_id &&
589 !hwc_configs_[m1].disabled && !hwc_configs_[m2].disabled &&
590 fabsf(hwc_configs_[m1].mode.v_refresh() -
591 hwc_configs_[m2].mode.v_refresh()) < 1.0) {
592 ALOGI(
593 "Group %i: Disabling display mode %s (Refresh rate value is "
594 "too close to existing mode %s)",
595 hwc_configs_[m2].group_id, hwc_configs_[m2].mode.name().c_str(),
596 hwc_configs_[m1].mode.name().c_str());
597
598 hwc_configs_[m2].disabled = true;
599 }
600 }
601 }
Neil Armstrongb67d0492019-06-20 09:00:21 +0000602 }
603
604 uint32_t idx = 0;
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200605 for (auto &hwc_config : hwc_configs_) {
606 if (hwc_config.second.disabled) {
607 continue;
608 }
609
610 if (configs != nullptr) {
611 if (idx >= *num_configs) {
612 break;
613 }
614 configs[idx] = hwc_config.second.id;
615 }
616
617 idx++;
Sean Paulac874152016-03-10 16:00:26 -0500618 }
619 *num_configs = idx;
620 return HWC2::Error::None;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500621}
622
623HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayName(uint32_t *size, char *name) {
Sean Paulac874152016-03-10 16:00:26 -0500624 std::ostringstream stream;
625 stream << "display-" << connector_->id();
626 std::string string = stream.str();
627 size_t length = string.length();
628 if (!name) {
629 *size = length;
630 return HWC2::Error::None;
631 }
632
633 *size = std::min<uint32_t>(static_cast<uint32_t>(length - 1), *size);
634 strncpy(name, string.c_str(), *size);
635 return HWC2::Error::None;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500636}
637
Roman Stratiienko7f576ec2021-12-22 17:34:18 +0200638HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayRequests(
639 int32_t * /*display_requests*/, uint32_t *num_elements,
640 hwc2_layer_t * /*layers*/, int32_t * /*layer_requests*/) {
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200641 // TODO(nobody): I think virtual display should request
Sean Paulac874152016-03-10 16:00:26 -0500642 // HWC2_DISPLAY_REQUEST_WRITE_CLIENT_TARGET_TO_OUTPUT here
Sean Paulac874152016-03-10 16:00:26 -0500643 *num_elements = 0;
644 return HWC2::Error::None;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500645}
646
647HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayType(int32_t *type) {
Sean Paulac874152016-03-10 16:00:26 -0500648 *type = static_cast<int32_t>(type_);
649 return HWC2::Error::None;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500650}
651
652HWC2::Error DrmHwcTwo::HwcDisplay::GetDozeSupport(int32_t *support) {
Sean Paulac874152016-03-10 16:00:26 -0500653 *support = 0;
654 return HWC2::Error::None;
655}
656
657HWC2::Error DrmHwcTwo::HwcDisplay::GetHdrCapabilities(
Sean Paulf72cccd2018-08-27 13:59:08 -0400658 uint32_t *num_types, int32_t * /*types*/, float * /*max_luminance*/,
659 float * /*max_average_luminance*/, float * /*min_luminance*/) {
Sean Paulac874152016-03-10 16:00:26 -0500660 *num_types = 0;
661 return HWC2::Error::None;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500662}
663
Roman Stratiienko3e2f9e72021-05-21 14:33:28 +0300664/* Find API details at:
665 * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1767
666 */
Sean Pauled2ec4b2016-03-10 15:35:40 -0500667HWC2::Error DrmHwcTwo::HwcDisplay::GetReleaseFences(uint32_t *num_elements,
Sean Paulac874152016-03-10 16:00:26 -0500668 hwc2_layer_t *layers,
669 int32_t *fences) {
Sean Paulac874152016-03-10 16:00:26 -0500670 uint32_t num_layers = 0;
671
Roman Stratiienko03fd35c2022-01-04 14:30:37 +0200672 for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) {
Sean Paulac874152016-03-10 16:00:26 -0500673 ++num_layers;
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200674 if (layers == nullptr || fences == nullptr)
Sean Paulac874152016-03-10 16:00:26 -0500675 continue;
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200676
677 if (num_layers > *num_elements) {
Sean Paulac874152016-03-10 16:00:26 -0500678 ALOGW("Overflow num_elements %d/%d", num_layers, *num_elements);
679 return HWC2::Error::None;
680 }
681
682 layers[num_layers - 1] = l.first;
Roman Stratiienko03fd35c2022-01-04 14:30:37 +0200683 fences[num_layers - 1] = l.second.GetReleaseFence().Release();
Sean Paulac874152016-03-10 16:00:26 -0500684 }
685 *num_elements = num_layers;
686 return HWC2::Error::None;
687}
688
Roman Stratiienko2a1f1ae2021-10-23 17:47:35 +0300689HWC2::Error DrmHwcTwo::HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
Sean Paulac874152016-03-10 16:00:26 -0500690 // order the layers by z-order
691 bool use_client_layer = false;
Alexandru Gheorghe1542d292018-06-13 16:46:36 +0100692 uint32_t client_z_order = UINT32_MAX;
Roman Stratiienko03fd35c2022-01-04 14:30:37 +0200693 std::map<uint32_t, HwcLayer *> z_map;
694 for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) {
695 switch (l.second.GetValidatedType()) {
Sean Paulac874152016-03-10 16:00:26 -0500696 case HWC2::Composition::Device:
Roman Stratiienko03fd35c2022-01-04 14:30:37 +0200697 z_map.emplace(std::make_pair(l.second.GetZOrder(), &l.second));
Sean Paulac874152016-03-10 16:00:26 -0500698 break;
699 case HWC2::Composition::Client:
Alexandru Gheorghe1542d292018-06-13 16:46:36 +0100700 // Place it at the z_order of the lowest client layer
Sean Paulac874152016-03-10 16:00:26 -0500701 use_client_layer = true;
Roman Stratiienko03fd35c2022-01-04 14:30:37 +0200702 client_z_order = std::min(client_z_order, l.second.GetZOrder());
Sean Paulac874152016-03-10 16:00:26 -0500703 break;
704 default:
705 continue;
706 }
707 }
708 if (use_client_layer)
709 z_map.emplace(std::make_pair(client_z_order, &client_layer_));
710
Rob Herring4f6c62e2018-05-17 14:33:02 -0500711 if (z_map.empty())
712 return HWC2::Error::BadLayer;
713
Matvii Zorin5368b732021-01-12 10:53:08 +0200714 std::vector<DrmHwcLayer> composition_layers;
715
Sean Paulac874152016-03-10 16:00:26 -0500716 // now that they're ordered by z, add them to the composition
Roman Stratiienko03fd35c2022-01-04 14:30:37 +0200717 for (std::pair<const uint32_t, HwcLayer *> &l : z_map) {
Sean Paulac874152016-03-10 16:00:26 -0500718 DrmHwcLayer layer;
719 l.second->PopulateDrmLayer(&layer);
Roman Stratiienko8666dc92021-02-09 17:49:55 +0200720 int ret = layer.ImportBuffer(drm_);
Sean Paulac874152016-03-10 16:00:26 -0500721 if (ret) {
722 ALOGE("Failed to import layer, ret=%d", ret);
723 return HWC2::Error::NoResources;
724 }
Matvii Zorin5368b732021-01-12 10:53:08 +0200725 composition_layers.emplace_back(std::move(layer));
Sean Paulac874152016-03-10 16:00:26 -0500726 }
Sean Paulac874152016-03-10 16:00:26 -0500727
Roman Stratiienko753d1072021-12-30 18:05:27 +0200728 auto composition = std::make_shared<DrmDisplayComposition>(crtc_);
Sean Paulac874152016-03-10 16:00:26 -0500729
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200730 // TODO(nobody): Don't always assume geometry changed
Matvii Zorin5368b732021-01-12 10:53:08 +0200731 int ret = composition->SetLayers(composition_layers.data(),
Roman Stratiienko36a7f282021-10-05 18:17:53 +0300732 composition_layers.size());
Sean Paulac874152016-03-10 16:00:26 -0500733 if (ret) {
734 ALOGE("Failed to set layers in the composition ret=%d", ret);
735 return HWC2::Error::BadLayer;
736 }
737
738 std::vector<DrmPlane *> primary_planes(primary_planes_);
739 std::vector<DrmPlane *> overlay_planes(overlay_planes_);
Rob Herringaf0d9752018-05-04 16:34:19 -0500740 ret = composition->Plan(&primary_planes, &overlay_planes);
Sean Paulac874152016-03-10 16:00:26 -0500741 if (ret) {
John Stultz66763d52021-08-24 04:59:25 +0000742 ALOGV("Failed to plan the composition ret=%d", ret);
Sean Paulac874152016-03-10 16:00:26 -0500743 return HWC2::Error::BadConfig;
744 }
745
Roman Stratiienko2a1f1ae2021-10-23 17:47:35 +0300746 a_args.composition = composition;
Roman Stratiienkof81d2c82022-01-11 19:47:24 +0200747 if (staged_mode) {
748 a_args.display_mode = *staged_mode;
749 }
Roman Stratiienkodccc6fb2021-10-23 17:35:44 +0300750 ret = compositor_.ExecuteAtomicCommit(a_args);
751
Sean Paulac874152016-03-10 16:00:26 -0500752 if (ret) {
Roman Stratiienko2a1f1ae2021-10-23 17:47:35 +0300753 if (!a_args.test_only)
John Stultz78c9f6c2018-05-24 16:43:35 -0700754 ALOGE("Failed to apply the frame composition ret=%d", ret);
Sean Paulac874152016-03-10 16:00:26 -0500755 return HWC2::Error::BadParameter;
756 }
Roman Stratiienkof81d2c82022-01-11 19:47:24 +0200757
758 if (!a_args.test_only) {
759 staged_mode.reset();
760 }
761
Rob Herring4f6c62e2018-05-17 14:33:02 -0500762 return HWC2::Error::None;
763}
764
Roman Stratiienko3e2f9e72021-05-21 14:33:28 +0300765/* Find API details at:
766 * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1805
767 */
Matteo Franchinc56eede2019-12-03 17:10:38 +0000768HWC2::Error DrmHwcTwo::HwcDisplay::PresentDisplay(int32_t *present_fence) {
Rob Herring4f6c62e2018-05-17 14:33:02 -0500769 HWC2::Error ret;
770
Roman Stratiienko0d1a2cd2019-11-28 17:51:16 +0200771 ++total_stats_.total_frames_;
772
Roman Stratiienko2a1f1ae2021-10-23 17:47:35 +0300773 AtomicCommitArgs a_args{};
774 ret = CreateComposition(a_args);
775
Roman Stratiienko0d1a2cd2019-11-28 17:51:16 +0200776 if (ret != HWC2::Error::None)
777 ++total_stats_.failed_kms_present_;
778
Rob Herring4f6c62e2018-05-17 14:33:02 -0500779 if (ret == HWC2::Error::BadLayer) {
780 // Can we really have no client or device layers?
Matteo Franchinc56eede2019-12-03 17:10:38 +0000781 *present_fence = -1;
Rob Herring4f6c62e2018-05-17 14:33:02 -0500782 return HWC2::Error::None;
783 }
784 if (ret != HWC2::Error::None)
785 return ret;
Sean Paulac874152016-03-10 16:00:26 -0500786
Roman Stratiienko2a1f1ae2021-10-23 17:47:35 +0300787 *present_fence = a_args.out_fence.Release();
Sean Paulac874152016-03-10 16:00:26 -0500788
789 ++frame_no_;
790 return HWC2::Error::None;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500791}
792
793HWC2::Error DrmHwcTwo::HwcDisplay::SetActiveConfig(hwc2_config_t config) {
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200794 int conf = static_cast<int>(config);
795
796 if (hwc_configs_.count(conf) == 0) {
797 ALOGE("Could not find active mode for %d", conf);
Sean Paulac874152016-03-10 16:00:26 -0500798 return HWC2::Error::BadConfig;
799 }
800
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200801 auto &mode = hwc_configs_[conf].mode;
802
Roman Stratiienkof81d2c82022-01-11 19:47:24 +0200803 staged_mode = mode;
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +0300804
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200805 active_config_id_ = conf;
Sean Paulac874152016-03-10 16:00:26 -0500806
807 // Setup the client layer's dimensions
808 hwc_rect_t display_frame = {.left = 0,
809 .top = 0,
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200810 .right = static_cast<int>(mode.h_display()),
811 .bottom = static_cast<int>(mode.v_display())};
Sean Paulac874152016-03-10 16:00:26 -0500812 client_layer_.SetLayerDisplayFrame(display_frame);
Sean Paulac874152016-03-10 16:00:26 -0500813
814 return HWC2::Error::None;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500815}
816
Roman Stratiienko3e2f9e72021-05-21 14:33:28 +0300817/* Find API details at:
818 * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1861
819 */
Sean Pauled2ec4b2016-03-10 15:35:40 -0500820HWC2::Error DrmHwcTwo::HwcDisplay::SetClientTarget(buffer_handle_t target,
821 int32_t acquire_fence,
822 int32_t dataspace,
Rob Herring1b2685c2017-11-29 10:19:57 -0600823 hwc_region_t /*damage*/) {
Roman Stratiienko03fd35c2022-01-04 14:30:37 +0200824 client_layer_.SetLayerBuffer(target, acquire_fence);
Sean Paulac874152016-03-10 16:00:26 -0500825 client_layer_.SetLayerDataspace(dataspace);
Roman Stratiienko33365c22020-10-10 23:06:36 +0300826
Roman Stratiienko03fd35c2022-01-04 14:30:37 +0200827 /*
828 * target can be nullptr, this does mean the Composer Service is calling
829 * cleanDisplayResources() on after receiving HOTPLUG event. See more at:
830 * 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
831 */
832 if (target == nullptr) {
833 return HWC2::Error::None;
834 }
835
Roman Stratiienko33365c22020-10-10 23:06:36 +0300836 /* TODO: Do not update source_crop every call.
837 * It makes sense to do it once after every hotplug event. */
Roman Stratiienkofc014f52021-12-23 19:04:29 +0200838 HwcDrmBo bo{};
Roman Stratiienko33365c22020-10-10 23:06:36 +0300839 BufferInfoGetter::GetInstance()->ConvertBoInfo(target, &bo);
840
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200841 hwc_frect_t source_crop = {.left = 0.0F,
842 .top = 0.0F,
Roman Stratiienkod26619b2021-08-04 19:55:37 +0300843 .right = static_cast<float>(bo.width),
844 .bottom = static_cast<float>(bo.height)};
Roman Stratiienko33365c22020-10-10 23:06:36 +0300845 client_layer_.SetLayerSourceCrop(source_crop);
846
Sean Paulac874152016-03-10 16:00:26 -0500847 return HWC2::Error::None;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500848}
849
850HWC2::Error DrmHwcTwo::HwcDisplay::SetColorMode(int32_t mode) {
Roman Stratiienkod146d6d2020-10-04 23:56:46 +0300851 if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_BT2100_HLG)
852 return HWC2::Error::BadParameter;
853
Kalyan Kondapallyda5839c2016-11-10 10:59:50 -0800854 if (mode != HAL_COLOR_MODE_NATIVE)
Roman Stratiienko27d2ed62020-09-26 23:59:19 +0300855 return HWC2::Error::Unsupported;
Kalyan Kondapallyda5839c2016-11-10 10:59:50 -0800856
857 color_mode_ = mode;
858 return HWC2::Error::None;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500859}
860
861HWC2::Error DrmHwcTwo::HwcDisplay::SetColorTransform(const float *matrix,
Sean Paulac874152016-03-10 16:00:26 -0500862 int32_t hint) {
Roman Kovalivskyi12b91a32019-12-11 19:09:51 +0200863 if (hint < HAL_COLOR_TRANSFORM_IDENTITY ||
864 hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA)
865 return HWC2::Error::BadParameter;
866
867 if (!matrix && hint == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX)
868 return HWC2::Error::BadParameter;
869
870 color_transform_hint_ = static_cast<android_color_transform_t>(hint);
871 if (color_transform_hint_ == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX)
872 std::copy(matrix, matrix + MATRIX_SIZE, color_transform_matrix_.begin());
873
874 return HWC2::Error::None;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500875}
876
Roman Stratiienko7f576ec2021-12-22 17:34:18 +0200877HWC2::Error DrmHwcTwo::HwcDisplay::SetOutputBuffer(buffer_handle_t /*buffer*/,
878 int32_t /*release_fence*/) {
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200879 // TODO(nobody): Need virtual display support
Roman Stratiienko7f576ec2021-12-22 17:34:18 +0200880 return HWC2::Error::Unsupported;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500881}
882
Sean Paulac874152016-03-10 16:00:26 -0500883HWC2::Error DrmHwcTwo::HwcDisplay::SetPowerMode(int32_t mode_in) {
Sean Paulac874152016-03-10 16:00:26 -0500884 auto mode = static_cast<HWC2::PowerMode>(mode_in);
Roman Stratiienkodccc6fb2021-10-23 17:35:44 +0300885 AtomicCommitArgs a_args{};
886
Sean Paulac874152016-03-10 16:00:26 -0500887 switch (mode) {
888 case HWC2::PowerMode::Off:
Roman Stratiienkodccc6fb2021-10-23 17:35:44 +0300889 a_args.active = false;
Sean Paulac874152016-03-10 16:00:26 -0500890 break;
891 case HWC2::PowerMode::On:
Roman Stratiienkof81d2c82022-01-11 19:47:24 +0200892 /*
893 * Setting the display to active before we have a composition
894 * can break some drivers, so skip setting a_args.active to
895 * true, as the next composition frame will implicitly activate
896 * the display
897 */
898 return HWC2::Error::None;
Sean Paulac874152016-03-10 16:00:26 -0500899 break;
Vincent Donnefort60ef7eb2019-10-09 11:39:28 +0100900 case HWC2::PowerMode::Doze:
901 case HWC2::PowerMode::DozeSuspend:
902 return HWC2::Error::Unsupported;
Sean Paulac874152016-03-10 16:00:26 -0500903 default:
904 ALOGI("Power mode %d is unsupported\n", mode);
Vincent Donnefort60ef7eb2019-10-09 11:39:28 +0100905 return HWC2::Error::BadParameter;
Sean Paulac874152016-03-10 16:00:26 -0500906 };
907
Roman Stratiienkodccc6fb2021-10-23 17:35:44 +0300908 int err = compositor_.ExecuteAtomicCommit(a_args);
909 if (err) {
910 ALOGE("Failed to apply the dpms composition err=%d", err);
Sean Paulac874152016-03-10 16:00:26 -0500911 return HWC2::Error::BadParameter;
912 }
913 return HWC2::Error::None;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500914}
915
916HWC2::Error DrmHwcTwo::HwcDisplay::SetVsyncEnabled(int32_t enabled) {
Andrii Chepurnyi4bdd0fe2018-07-27 15:14:37 +0300917 vsync_worker_.VSyncControl(HWC2_VSYNC_ENABLE == enabled);
Sean Paulac874152016-03-10 16:00:26 -0500918 return HWC2::Error::None;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500919}
920
921HWC2::Error DrmHwcTwo::HwcDisplay::ValidateDisplay(uint32_t *num_types,
Sean Paulac874152016-03-10 16:00:26 -0500922 uint32_t *num_requests) {
Matvii Zorinef3c7972020-08-11 15:15:44 +0300923 return backend_->ValidateDisplay(this, num_types, num_requests);
Sean Pauled2ec4b2016-03-10 15:35:40 -0500924}
925
Roman Stratiienko03fd35c2022-01-04 14:30:37 +0200926std::vector<HwcLayer *> DrmHwcTwo::HwcDisplay::GetOrderLayersByZPos() {
927 std::vector<HwcLayer *> ordered_layers;
Matvii Zorined90ef92021-01-29 18:32:06 +0200928 ordered_layers.reserve(layers_.size());
929
930 for (auto &[handle, layer] : layers_) {
931 ordered_layers.emplace_back(&layer);
932 }
933
934 std::sort(std::begin(ordered_layers), std::end(ordered_layers),
Roman Stratiienko03fd35c2022-01-04 14:30:37 +0200935 [](const HwcLayer *lhs, const HwcLayer *rhs) {
936 return lhs->GetZOrder() < rhs->GetZOrder();
Matvii Zorined90ef92021-01-29 18:32:06 +0200937 });
938
939 return ordered_layers;
940}
941
Roman Stratiienko6f5df172020-09-27 22:48:08 +0300942#if PLATFORM_SDK_VERSION > 29
943HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayConnectionType(uint32_t *outType) {
944 if (connector_->internal())
945 *outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::Internal);
946 else if (connector_->external())
947 *outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::External);
948 else
949 return HWC2::Error::BadConfig;
950
951 return HWC2::Error::None;
952}
953
954HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayVsyncPeriod(
955 hwc2_vsync_period_t *outVsyncPeriod /* ns */) {
Roman Stratiienkoa148f212021-11-16 18:23:18 +0200956 return GetDisplayAttribute(active_config_id_, HWC2_ATTRIBUTE_VSYNC_PERIOD,
957 (int32_t *)(outVsyncPeriod));
Roman Stratiienko6f5df172020-09-27 22:48:08 +0300958}
959
960HWC2::Error DrmHwcTwo::HwcDisplay::SetActiveConfigWithConstraints(
961 hwc2_config_t /*config*/,
962 hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints,
963 hwc_vsync_period_change_timeline_t *outTimeline) {
Roman Stratiienko6f5df172020-09-27 22:48:08 +0300964 if (vsyncPeriodChangeConstraints == nullptr || outTimeline == nullptr) {
965 return HWC2::Error::BadParameter;
966 }
967
968 return HWC2::Error::BadConfig;
969}
970
971HWC2::Error DrmHwcTwo::HwcDisplay::SetAutoLowLatencyMode(bool /*on*/) {
972 return HWC2::Error::Unsupported;
973}
974
975HWC2::Error DrmHwcTwo::HwcDisplay::GetSupportedContentTypes(
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200976 uint32_t *outNumSupportedContentTypes,
977 const uint32_t *outSupportedContentTypes) {
Roman Stratiienko6f5df172020-09-27 22:48:08 +0300978 if (outSupportedContentTypes == nullptr)
979 *outNumSupportedContentTypes = 0;
980
981 return HWC2::Error::None;
982}
983
984HWC2::Error DrmHwcTwo::HwcDisplay::SetContentType(int32_t contentType) {
Roman Stratiienko6f5df172020-09-27 22:48:08 +0300985 if (contentType != HWC2_CONTENT_TYPE_NONE)
986 return HWC2::Error::Unsupported;
987
988 /* TODO: Map to the DRM Connector property:
989 * https://elixir.bootlin.com/linux/v5.4-rc5/source/drivers/gpu/drm/drm_connector.c#L809
990 */
991
992 return HWC2::Error::None;
993}
994#endif
995
John Stultz8c7229d2020-02-07 21:31:08 +0000996#if PLATFORM_SDK_VERSION > 28
Lowry Li (Arm Technology China)b3d81782019-12-18 14:28:22 +0800997HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayIdentificationData(
998 uint8_t *outPort, uint32_t *outDataSize, uint8_t *outData) {
Roman Stratiienko3e8ce572021-09-29 12:46:28 +0300999 auto blob = connector_->GetEdidBlob();
Lowry Li (Arm Technology China)b3d81782019-12-18 14:28:22 +08001000
Roman Stratiienko3e8ce572021-09-29 12:46:28 +03001001 if (!blob) {
Lowry Li (Arm Technology China)b3d81782019-12-18 14:28:22 +08001002 ALOGE("Failed to get edid property value.");
1003 return HWC2::Error::Unsupported;
1004 }
1005
Andrii Chepurnyi8115dbe2020-04-14 13:03:57 +03001006 if (outData) {
1007 *outDataSize = std::min(*outDataSize, blob->length);
1008 memcpy(outData, blob->data, *outDataSize);
1009 } else {
1010 *outDataSize = blob->length;
1011 }
Lowry Li (Arm Technology China)b3d81782019-12-18 14:28:22 +08001012 *outPort = connector_->id();
Lowry Li (Arm Technology China)b3d81782019-12-18 14:28:22 +08001013
1014 return HWC2::Error::None;
1015}
1016
1017HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayCapabilities(
Roman Stratiienko7f576ec2021-12-22 17:34:18 +02001018 uint32_t *outNumCapabilities, uint32_t * /*outCapabilities*/) {
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +02001019 if (outNumCapabilities == nullptr) {
Lowry Li (Arm Technology China)b3d81782019-12-18 14:28:22 +08001020 return HWC2::Error::BadParameter;
1021 }
1022
1023 *outNumCapabilities = 0;
1024
1025 return HWC2::Error::None;
1026}
Andrii Chepurnyi2619aab2020-07-03 11:21:33 +03001027
1028HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayBrightnessSupport(
1029 bool *supported) {
1030 *supported = false;
1031 return HWC2::Error::None;
1032}
1033
1034HWC2::Error DrmHwcTwo::HwcDisplay::SetDisplayBrightness(
1035 float /* brightness */) {
1036 return HWC2::Error::Unsupported;
1037}
1038
John Stultz8c7229d2020-02-07 21:31:08 +00001039#endif /* PLATFORM_SDK_VERSION > 28 */
Lowry Li (Arm Technology China)b3d81782019-12-18 14:28:22 +08001040
Andrii Chepurnyi50d37452020-04-24 14:20:24 +03001041#if PLATFORM_SDK_VERSION > 27
1042
1043HWC2::Error DrmHwcTwo::HwcDisplay::GetRenderIntents(
1044 int32_t mode, uint32_t *outNumIntents,
1045 int32_t * /*android_render_intent_v1_1_t*/ outIntents) {
1046 if (mode != HAL_COLOR_MODE_NATIVE) {
1047 return HWC2::Error::BadParameter;
1048 }
1049
1050 if (outIntents == nullptr) {
1051 *outNumIntents = 1;
1052 return HWC2::Error::None;
1053 }
1054 *outNumIntents = 1;
1055 outIntents[0] = HAL_RENDER_INTENT_COLORIMETRIC;
1056 return HWC2::Error::None;
1057}
1058
Andrii Chepurnyi857a53f2020-04-29 23:15:28 +03001059HWC2::Error DrmHwcTwo::HwcDisplay::SetColorModeWithIntent(int32_t mode,
1060 int32_t intent) {
Roman Stratiienko27d2ed62020-09-26 23:59:19 +03001061 if (intent < HAL_RENDER_INTENT_COLORIMETRIC ||
1062 intent > HAL_RENDER_INTENT_TONE_MAP_ENHANCE)
1063 return HWC2::Error::BadParameter;
1064
1065 if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_BT2100_HLG)
1066 return HWC2::Error::BadParameter;
1067
Andrii Chepurnyi857a53f2020-04-29 23:15:28 +03001068 if (mode != HAL_COLOR_MODE_NATIVE)
Roman Stratiienko27d2ed62020-09-26 23:59:19 +03001069 return HWC2::Error::Unsupported;
1070
Andrii Chepurnyi857a53f2020-04-29 23:15:28 +03001071 if (intent != HAL_RENDER_INTENT_COLORIMETRIC)
Roman Stratiienko27d2ed62020-09-26 23:59:19 +03001072 return HWC2::Error::Unsupported;
1073
Andrii Chepurnyi857a53f2020-04-29 23:15:28 +03001074 color_mode_ = mode;
1075 return HWC2::Error::None;
1076}
1077
Andrii Chepurnyi50d37452020-04-24 14:20:24 +03001078#endif /* PLATFORM_SDK_VERSION > 27 */
1079
Roman Stratiienko24a7fc42021-12-23 16:25:20 +02001080const Backend *DrmHwcTwo::HwcDisplay::backend() const {
1081 return backend_.get();
1082}
1083
1084void DrmHwcTwo::HwcDisplay::set_backend(std::unique_ptr<Backend> backend) {
1085 backend_ = std::move(backend);
1086}
1087
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +03001088void DrmHwcTwo::HandleDisplayHotplug(hwc2_display_t displayid, int state) {
Roman Stratiienko863a3c22021-09-29 13:00:29 +03001089 const std::lock_guard<std::mutex> lock(callback_lock_);
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +03001090
Roman Stratiienko863a3c22021-09-29 13:00:29 +03001091 if (hotplug_callback_.first != nullptr &&
1092 hotplug_callback_.second != nullptr) {
1093 hotplug_callback_.first(hotplug_callback_.second, displayid,
1094 state == DRM_MODE_CONNECTED
1095 ? HWC2_CONNECTION_CONNECTED
1096 : HWC2_CONNECTION_DISCONNECTED);
1097 }
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +03001098}
1099
1100void DrmHwcTwo::HandleInitialHotplugState(DrmDevice *drmDevice) {
Roman Stratiienkod21071f2021-03-09 21:56:50 +02001101 for (const auto &conn : drmDevice->connectors()) {
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +03001102 if (conn->state() != DRM_MODE_CONNECTED)
1103 continue;
1104 HandleDisplayHotplug(conn->display(), conn->state());
1105 }
1106}
1107
Roman Stratiienko1e053b42021-10-25 22:54:20 +03001108void DrmHwcTwo::HandleHotplugUEvent() {
Roman Stratiienkofc014f52021-12-23 19:04:29 +02001109 for (const auto &drm : resource_manager_.GetDrmDevices()) {
Roman Stratiienko1e053b42021-10-25 22:54:20 +03001110 for (const auto &conn : drm->connectors()) {
1111 drmModeConnection old_state = conn->state();
1112 drmModeConnection cur_state = conn->UpdateModes()
1113 ? DRM_MODE_UNKNOWNCONNECTION
1114 : conn->state();
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +03001115
Roman Stratiienko1e053b42021-10-25 22:54:20 +03001116 if (cur_state == old_state)
1117 continue;
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +03001118
Roman Stratiienko1e053b42021-10-25 22:54:20 +03001119 ALOGI("%s event for connector %u on display %d",
1120 cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(),
1121 conn->display());
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +03001122
Roman Stratiienko1e053b42021-10-25 22:54:20 +03001123 int display_id = conn->display();
1124 if (cur_state == DRM_MODE_CONNECTED) {
1125 auto &display = displays_.at(display_id);
1126 display.ChosePreferredConfig();
1127 } else {
1128 auto &display = displays_.at(display_id);
1129 display.ClearDisplay();
1130 }
1131
1132 HandleDisplayHotplug(display_id, cur_state);
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +03001133 }
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +03001134 }
1135}
1136
Sean Paulf72cccd2018-08-27 13:59:08 -04001137} // namespace android