Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2015 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-drm-display-composition" |
| 18 | |
| 19 | #include "drmdisplaycomposition.h" |
| 20 | #include "drmcrtc.h" |
| 21 | #include "drmplane.h" |
| 22 | #include "drmresources.h" |
| 23 | |
| 24 | #include <stdlib.h> |
| 25 | |
| 26 | #include <cutils/log.h> |
| 27 | #include <sw_sync.h> |
| 28 | #include <sync/sync.h> |
Sean Paul | db7a17d | 2015-06-24 18:46:05 -0700 | [diff] [blame] | 29 | #include <xf86drmMode.h> |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 30 | |
| 31 | namespace android { |
| 32 | |
Zach Reizner | b44fd10 | 2015-08-07 16:00:01 -0700 | [diff] [blame] | 33 | static native_handle_t *dup_buffer_handle(buffer_handle_t handle) { |
| 34 | native_handle_t *new_handle = |
| 35 | native_handle_create(handle->numFds, handle->numInts); |
| 36 | if (new_handle == NULL) |
| 37 | return NULL; |
| 38 | |
| 39 | const int *old_data = handle->data; |
| 40 | int *new_data = new_handle->data; |
| 41 | for (int i = 0; i < handle->numFds; i++) { |
| 42 | *new_data = dup(*old_data); |
| 43 | old_data++; |
| 44 | new_data++; |
| 45 | } |
| 46 | memcpy(new_data, old_data, sizeof(int) * handle->numInts); |
| 47 | |
| 48 | return new_handle; |
| 49 | } |
| 50 | |
| 51 | static void free_buffer_handle(native_handle_t *handle) { |
| 52 | int ret = native_handle_close(handle); |
| 53 | if (ret) |
| 54 | ALOGE("Failed to close native handle %d", ret); |
| 55 | ret = native_handle_delete(handle); |
| 56 | if (ret) |
| 57 | ALOGE("Failed to delete native handle %d", ret); |
| 58 | } |
| 59 | |
| 60 | DrmCompositionLayer::DrmCompositionLayer() |
| 61 | : crtc(NULL), plane(NULL), handle(NULL) { |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 62 | memset(&layer, 0, sizeof(layer)); |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 63 | layer.releaseFenceFd = -1; |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 64 | layer.acquireFenceFd = -1; |
| 65 | memset(&bo, 0, sizeof(bo)); |
| 66 | } |
| 67 | |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 68 | DrmDisplayComposition::DrmDisplayComposition() |
Sean Paul | acb2a44 | 2015-06-24 18:43:01 -0700 | [diff] [blame] | 69 | : drm_(NULL), |
| 70 | importer_(NULL), |
| 71 | type_(DRM_COMPOSITION_TYPE_EMPTY), |
| 72 | timeline_fd_(-1), |
Sean Paul | db7a17d | 2015-06-24 18:46:05 -0700 | [diff] [blame] | 73 | timeline_(0), |
Zach Reizner | ece0489 | 2015-07-17 14:13:28 -0700 | [diff] [blame] | 74 | timeline_current_(0), |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 75 | timeline_pre_comp_done_(0), |
| 76 | pre_composition_layer_index_(-1), |
Sean Paul | bdc67bf | 2015-09-21 10:04:02 -0400 | [diff] [blame^] | 77 | dpms_mode_(DRM_MODE_DPMS_ON), |
| 78 | frame_no_(0) { |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 79 | } |
| 80 | |
| 81 | DrmDisplayComposition::~DrmDisplayComposition() { |
| 82 | for (DrmCompositionLayerVector_t::iterator iter = layers_.begin(); |
| 83 | iter != layers_.end(); ++iter) { |
Sean Paul | 2e46fbd | 2015-07-09 17:22:22 -0400 | [diff] [blame] | 84 | if (importer_ && iter->bo.fb_id) |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 85 | importer_->ReleaseBuffer(&iter->bo); |
| 86 | |
Zach Reizner | b44fd10 | 2015-08-07 16:00:01 -0700 | [diff] [blame] | 87 | if (iter->handle) { |
| 88 | gralloc_->unregisterBuffer(gralloc_, iter->handle); |
| 89 | free_buffer_handle(iter->handle); |
| 90 | } |
| 91 | |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 92 | if (iter->layer.acquireFenceFd >= 0) |
| 93 | close(iter->layer.acquireFenceFd); |
| 94 | } |
| 95 | |
Zach Reizner | ece0489 | 2015-07-17 14:13:28 -0700 | [diff] [blame] | 96 | if (timeline_fd_ >= 0) { |
| 97 | FinishComposition(); |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 98 | close(timeline_fd_); |
Zach Reizner | ece0489 | 2015-07-17 14:13:28 -0700 | [diff] [blame] | 99 | timeline_fd_ = -1; |
| 100 | } |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 101 | } |
| 102 | |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 103 | int DrmDisplayComposition::Init(DrmResources *drm, DrmCrtc *crtc, |
Sean Paul | bdc67bf | 2015-09-21 10:04:02 -0400 | [diff] [blame^] | 104 | Importer *importer, uint64_t frame_no) { |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 105 | drm_ = drm; |
Sean Paul | 2143d3b | 2015-09-04 01:33:06 -0400 | [diff] [blame] | 106 | crtc_ = crtc; // Can be NULL if we haven't modeset yet |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 107 | importer_ = importer; |
Sean Paul | bdc67bf | 2015-09-21 10:04:02 -0400 | [diff] [blame^] | 108 | frame_no_ = frame_no; |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 109 | |
Zach Reizner | b44fd10 | 2015-08-07 16:00:01 -0700 | [diff] [blame] | 110 | int ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, |
| 111 | (const hw_module_t **)&gralloc_); |
| 112 | if (ret) { |
| 113 | ALOGE("Failed to open gralloc module %d", ret); |
| 114 | return ret; |
| 115 | } |
| 116 | |
| 117 | ret = sw_sync_timeline_create(); |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 118 | if (ret < 0) { |
| 119 | ALOGE("Failed to create sw sync timeline %d", ret); |
| 120 | return ret; |
| 121 | } |
| 122 | timeline_fd_ = ret; |
| 123 | return 0; |
| 124 | } |
| 125 | |
Sean Paul | acb2a44 | 2015-06-24 18:43:01 -0700 | [diff] [blame] | 126 | DrmCompositionType DrmDisplayComposition::type() const { |
| 127 | return type_; |
| 128 | } |
| 129 | |
| 130 | bool DrmDisplayComposition::validate_composition_type(DrmCompositionType des) { |
| 131 | return type_ == DRM_COMPOSITION_TYPE_EMPTY || type_ == des; |
| 132 | } |
| 133 | |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 134 | static DrmPlane *TakePlane(DrmCrtc *crtc, std::vector<DrmPlane *> *planes) { |
| 135 | for (auto iter = planes->begin(); iter != planes->end(); ++iter) { |
| 136 | if ((*iter)->GetCrtcSupported(*crtc)) { |
| 137 | DrmPlane *plane = *iter; |
| 138 | planes->erase(iter); |
| 139 | return plane; |
| 140 | } |
Zach Reizner | b44fd10 | 2015-08-07 16:00:01 -0700 | [diff] [blame] | 141 | } |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 142 | return NULL; |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 143 | } |
| 144 | |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 145 | static DrmPlane *TakePlane(DrmCrtc *crtc, |
| 146 | std::vector<DrmPlane *> *primary_planes, |
| 147 | std::vector<DrmPlane *> *overlay_planes) { |
| 148 | DrmPlane *plane = TakePlane(crtc, primary_planes); |
| 149 | if (plane) |
| 150 | return plane; |
| 151 | return TakePlane(crtc, overlay_planes); |
| 152 | } |
Zach Reizner | 713a678 | 2015-07-31 15:12:44 -0700 | [diff] [blame] | 153 | |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 154 | int DrmDisplayComposition::CreateNextTimelineFence() { |
| 155 | ++timeline_; |
| 156 | return sw_sync_fence_create(timeline_fd_, "drm_fence", timeline_); |
| 157 | } |
Zach Reizner | 713a678 | 2015-07-31 15:12:44 -0700 | [diff] [blame] | 158 | |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 159 | int DrmDisplayComposition::IncreaseTimelineToPoint(int point) { |
| 160 | int timeline_increase = point - timeline_current_; |
| 161 | if (timeline_increase <= 0) |
| 162 | return 0; |
Zach Reizner | 713a678 | 2015-07-31 15:12:44 -0700 | [diff] [blame] | 163 | |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 164 | int ret = sw_sync_timeline_inc(timeline_fd_, timeline_increase); |
Zach Reizner | 713a678 | 2015-07-31 15:12:44 -0700 | [diff] [blame] | 165 | if (ret) |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 166 | ALOGE("Failed to increment sync timeline %d", ret); |
| 167 | else |
| 168 | timeline_current_ = point; |
Zach Reizner | 713a678 | 2015-07-31 15:12:44 -0700 | [diff] [blame] | 169 | |
| 170 | return ret; |
| 171 | } |
| 172 | |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 173 | int DrmDisplayComposition::SetLayers(hwc_layer_1_t *layers, size_t num_layers, |
| 174 | size_t *layer_indices, |
| 175 | std::vector<DrmPlane *> *primary_planes, |
| 176 | std::vector<DrmPlane *> *overlay_planes) { |
| 177 | int ret = 0; |
| 178 | if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME)) |
| 179 | return -EINVAL; |
| 180 | |
| 181 | for (size_t layer_index = 0; layer_index < num_layers; layer_index++) { |
| 182 | hwc_layer_1_t *layer = &layers[layer_indices[layer_index]]; |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 183 | |
| 184 | native_handle_t *handle_copy = dup_buffer_handle(layer->handle); |
| 185 | if (handle_copy == NULL) { |
| 186 | ALOGE("Failed to duplicate handle"); |
| 187 | return -ENOMEM; |
| 188 | } |
| 189 | |
| 190 | int ret = gralloc_->registerBuffer(gralloc_, handle_copy); |
| 191 | if (ret) { |
| 192 | ALOGE("Failed to register buffer handle %d", ret); |
| 193 | free_buffer_handle(handle_copy); |
| 194 | return ret; |
| 195 | } |
| 196 | |
| 197 | layers_.emplace_back(); |
| 198 | DrmCompositionLayer_t *c_layer = &layers_.back(); |
| 199 | c_layer->layer = *layer; |
| 200 | c_layer->handle = handle_copy; |
| 201 | c_layer->crtc = crtc_; |
| 202 | |
| 203 | ret = importer_->ImportBuffer(layer->handle, &c_layer->bo); |
| 204 | if (ret) { |
| 205 | ALOGE("Failed to import handle of layer %d", ret); |
| 206 | goto fail; |
| 207 | } |
| 208 | |
| 209 | if (pre_composition_layer_index_ == -1) { |
| 210 | c_layer->plane = TakePlane(crtc_, primary_planes, overlay_planes); |
| 211 | if (c_layer->plane == NULL) { |
| 212 | if (layers_.size() <= 1) { |
| 213 | ALOGE("Failed to match any planes to the crtc of this display"); |
| 214 | ret = -ENODEV; |
| 215 | goto fail; |
| 216 | } |
| 217 | |
| 218 | layers_.emplace_back(); |
| 219 | // c_layer's address might have changed when we resized the vector |
| 220 | c_layer = &layers_[layers_.size() - 2]; |
| 221 | DrmCompositionLayer_t &pre_comp_layer = layers_.back(); |
| 222 | pre_comp_layer.crtc = crtc_; |
| 223 | hwc_layer_1_t &pre_comp_output_layer = pre_comp_layer.layer; |
| 224 | memset(&pre_comp_output_layer, 0, sizeof(pre_comp_output_layer)); |
| 225 | pre_comp_output_layer.compositionType = HWC_OVERLAY; |
| 226 | pre_comp_output_layer.acquireFenceFd = -1; |
| 227 | pre_comp_output_layer.releaseFenceFd = -1; |
| 228 | pre_comp_output_layer.planeAlpha = 0xff; |
| 229 | pre_comp_output_layer.visibleRegionScreen.numRects = 1; |
| 230 | pre_comp_output_layer.visibleRegionScreen.rects = |
| 231 | &pre_comp_output_layer.displayFrame; |
| 232 | |
| 233 | pre_composition_layer_index_ = layers_.size() - 1; |
| 234 | |
| 235 | // This is all to fix up the previous layer, which has now become part |
| 236 | // of the set of pre-composition layers because we are stealing its |
| 237 | // plane. |
| 238 | DrmCompositionLayer_t &last_c_layer = layers_[layers_.size() - 3]; |
| 239 | std::swap(pre_comp_layer.plane, last_c_layer.plane); |
| 240 | hwc_layer_1_t *last_layer = &layers[layer_indices[layer_index - 1]]; |
| 241 | ret = last_layer->releaseFenceFd = CreateNextTimelineFence(); |
| 242 | if (ret < 0) { |
| 243 | ALOGE("Could not create release fence %d", ret); |
| 244 | goto fail; |
| 245 | } |
| 246 | } |
| 247 | } |
| 248 | |
| 249 | if (c_layer->plane == NULL) { |
| 250 | // Layers to be pre composited all get the earliest release fences as they |
| 251 | // will get released soonest. |
| 252 | ret = layer->releaseFenceFd = CreateNextTimelineFence(); |
| 253 | if (ret < 0) { |
| 254 | ALOGE("Could not create release fence %d", ret); |
| 255 | goto fail; |
| 256 | } |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | timeline_pre_comp_done_ = timeline_; |
| 261 | |
| 262 | for (size_t layer_index = 0; layer_index < num_layers; layer_index++) { |
| 263 | hwc_layer_1_t *layer = &layers[layer_indices[layer_index]]; |
| 264 | if (layer->releaseFenceFd >= 0) |
| 265 | continue; |
| 266 | |
| 267 | ret = layer->releaseFenceFd = CreateNextTimelineFence(); |
| 268 | if (ret < 0) { |
| 269 | ALOGE("Could not create release fence %d", ret); |
| 270 | goto fail; |
| 271 | } |
| 272 | } |
| 273 | |
| 274 | for (size_t layer_index = 0; layer_index < num_layers; layer_index++) { |
| 275 | hwc_layer_1_t *layer = &layers[layer_indices[layer_index]]; |
| 276 | layer->acquireFenceFd = -1; // We own this now |
| 277 | } |
| 278 | |
| 279 | type_ = DRM_COMPOSITION_TYPE_FRAME; |
| 280 | return 0; |
| 281 | |
| 282 | fail: |
| 283 | |
| 284 | for (size_t c_layer_index = 0; c_layer_index < layers_.size(); |
| 285 | c_layer_index++) { |
| 286 | DrmCompositionLayer_t &c_layer = layers_[c_layer_index]; |
| 287 | if (c_layer.handle) { |
| 288 | gralloc_->unregisterBuffer(gralloc_, c_layer.handle); |
| 289 | free_buffer_handle(c_layer.handle); |
| 290 | } |
| 291 | if (c_layer.bo.fb_id) |
| 292 | importer_->ReleaseBuffer(&c_layer.bo); |
| 293 | if (c_layer.plane != NULL) { |
| 294 | std::vector<DrmPlane *> *return_to = |
| 295 | (c_layer.plane->type() == DRM_PLANE_TYPE_PRIMARY) ? primary_planes |
| 296 | : overlay_planes; |
| 297 | return_to->insert(return_to->begin() + c_layer_index, c_layer.plane); |
| 298 | } |
| 299 | } |
| 300 | layers_.clear(); |
| 301 | |
| 302 | for (size_t layer_index = 0; layer_index < num_layers; layer_index++) { |
| 303 | hwc_layer_1_t *layer = &layers[layer_indices[layer_index]]; |
| 304 | if (layer->releaseFenceFd >= 0) { |
| 305 | close(layer->releaseFenceFd); |
| 306 | layer->releaseFenceFd = -1; |
| 307 | } |
| 308 | } |
| 309 | sw_sync_timeline_inc(timeline_fd_, timeline_ - timeline_current_); |
| 310 | |
| 311 | timeline_ = timeline_current_; |
| 312 | return ret; |
| 313 | } |
| 314 | |
| 315 | int DrmDisplayComposition::SetDpmsMode(uint32_t dpms_mode) { |
Sean Paul | db7a17d | 2015-06-24 18:46:05 -0700 | [diff] [blame] | 316 | if (!validate_composition_type(DRM_COMPOSITION_TYPE_DPMS)) |
| 317 | return -EINVAL; |
| 318 | dpms_mode_ = dpms_mode; |
| 319 | type_ = DRM_COMPOSITION_TYPE_DPMS; |
| 320 | return 0; |
| 321 | } |
| 322 | |
Sean Paul | 2e46fbd | 2015-07-09 17:22:22 -0400 | [diff] [blame] | 323 | int DrmDisplayComposition::AddPlaneDisable(DrmPlane *plane) { |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 324 | layers_.emplace_back(); |
| 325 | DrmCompositionLayer_t &c_layer = layers_.back(); |
Sean Paul | 2e46fbd | 2015-07-09 17:22:22 -0400 | [diff] [blame] | 326 | c_layer.crtc = NULL; |
| 327 | c_layer.plane = plane; |
Sean Paul | 2e46fbd | 2015-07-09 17:22:22 -0400 | [diff] [blame] | 328 | return 0; |
| 329 | } |
| 330 | |
Zach Reizner | b44fd10 | 2015-08-07 16:00:01 -0700 | [diff] [blame] | 331 | void DrmDisplayComposition::RemoveNoPlaneLayers() { |
| 332 | for (auto &comp_layer : layers_) { |
| 333 | if (comp_layer.plane != NULL) |
| 334 | continue; |
| 335 | |
| 336 | if (importer_ && comp_layer.bo.fb_id) { |
| 337 | importer_->ReleaseBuffer(&comp_layer.bo); |
| 338 | } |
| 339 | |
| 340 | if (comp_layer.handle) { |
| 341 | gralloc_->unregisterBuffer(gralloc_, comp_layer.handle); |
| 342 | free_buffer_handle(comp_layer.handle); |
| 343 | } |
| 344 | |
| 345 | if (comp_layer.layer.acquireFenceFd >= 0) { |
| 346 | close(comp_layer.layer.acquireFenceFd); |
| 347 | comp_layer.layer.acquireFenceFd = -1; |
| 348 | } |
| 349 | } |
| 350 | |
| 351 | layers_.erase( |
| 352 | std::remove_if(layers_.begin(), layers_.end(), |
| 353 | [](DrmCompositionLayer_t &l) { return l.plane == NULL; }), |
| 354 | layers_.end()); |
| 355 | } |
| 356 | |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 357 | int DrmDisplayComposition::SignalPreCompositionDone() { |
| 358 | return IncreaseTimelineToPoint(timeline_pre_comp_done_); |
| 359 | } |
| 360 | |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 361 | int DrmDisplayComposition::FinishComposition() { |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 362 | return IncreaseTimelineToPoint(timeline_); |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 363 | } |
| 364 | |
| 365 | DrmCompositionLayerVector_t *DrmDisplayComposition::GetCompositionLayers() { |
| 366 | return &layers_; |
| 367 | } |
Sean Paul | db7a17d | 2015-06-24 18:46:05 -0700 | [diff] [blame] | 368 | |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 369 | int DrmDisplayComposition::pre_composition_layer_index() const { |
| 370 | return pre_composition_layer_index_; |
| 371 | } |
| 372 | |
Sean Paul | db7a17d | 2015-06-24 18:46:05 -0700 | [diff] [blame] | 373 | uint32_t DrmDisplayComposition::dpms_mode() const { |
| 374 | return dpms_mode_; |
| 375 | } |
Zach Reizner | 46ddd45 | 2015-07-30 08:10:14 -0700 | [diff] [blame] | 376 | |
Sean Paul | bdc67bf | 2015-09-21 10:04:02 -0400 | [diff] [blame^] | 377 | uint64_t DrmDisplayComposition::frame_no() const { |
| 378 | return frame_no_; |
| 379 | } |
| 380 | |
Zach Reizner | 46ddd45 | 2015-07-30 08:10:14 -0700 | [diff] [blame] | 381 | Importer *DrmDisplayComposition::importer() const { |
| 382 | return importer_; |
| 383 | } |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 384 | } |