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)); |
| 63 | layer.acquireFenceFd = -1; |
| 64 | memset(&bo, 0, sizeof(bo)); |
| 65 | } |
| 66 | |
| 67 | DrmCompositionLayer::~DrmCompositionLayer() { |
| 68 | } |
| 69 | |
| 70 | DrmDisplayComposition::DrmDisplayComposition() |
Sean Paul | acb2a44 | 2015-06-24 18:43:01 -0700 | [diff] [blame] | 71 | : drm_(NULL), |
| 72 | importer_(NULL), |
| 73 | type_(DRM_COMPOSITION_TYPE_EMPTY), |
| 74 | timeline_fd_(-1), |
Sean Paul | db7a17d | 2015-06-24 18:46:05 -0700 | [diff] [blame] | 75 | timeline_(0), |
Zach Reizner | ece0489 | 2015-07-17 14:13:28 -0700 | [diff] [blame] | 76 | timeline_current_(0), |
Sean Paul | db7a17d | 2015-06-24 18:46:05 -0700 | [diff] [blame] | 77 | dpms_mode_(DRM_MODE_DPMS_ON) { |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 78 | } |
| 79 | |
| 80 | DrmDisplayComposition::~DrmDisplayComposition() { |
| 81 | for (DrmCompositionLayerVector_t::iterator iter = layers_.begin(); |
| 82 | iter != layers_.end(); ++iter) { |
Sean Paul | 2e46fbd | 2015-07-09 17:22:22 -0400 | [diff] [blame] | 83 | if (importer_ && iter->bo.fb_id) |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 84 | importer_->ReleaseBuffer(&iter->bo); |
| 85 | |
Zach Reizner | b44fd10 | 2015-08-07 16:00:01 -0700 | [diff] [blame^] | 86 | if (iter->handle) { |
| 87 | gralloc_->unregisterBuffer(gralloc_, iter->handle); |
| 88 | free_buffer_handle(iter->handle); |
| 89 | } |
| 90 | |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 91 | if (iter->layer.acquireFenceFd >= 0) |
| 92 | close(iter->layer.acquireFenceFd); |
| 93 | } |
| 94 | |
Zach Reizner | ece0489 | 2015-07-17 14:13:28 -0700 | [diff] [blame] | 95 | if (timeline_fd_ >= 0) { |
| 96 | FinishComposition(); |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 97 | close(timeline_fd_); |
Zach Reizner | ece0489 | 2015-07-17 14:13:28 -0700 | [diff] [blame] | 98 | timeline_fd_ = -1; |
| 99 | } |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 100 | } |
| 101 | |
| 102 | int DrmDisplayComposition::Init(DrmResources *drm, Importer *importer) { |
| 103 | drm_ = drm; |
| 104 | importer_ = importer; |
| 105 | |
Zach Reizner | b44fd10 | 2015-08-07 16:00:01 -0700 | [diff] [blame^] | 106 | int ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, |
| 107 | (const hw_module_t **)&gralloc_); |
| 108 | if (ret) { |
| 109 | ALOGE("Failed to open gralloc module %d", ret); |
| 110 | return ret; |
| 111 | } |
| 112 | |
| 113 | ret = sw_sync_timeline_create(); |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 114 | if (ret < 0) { |
| 115 | ALOGE("Failed to create sw sync timeline %d", ret); |
| 116 | return ret; |
| 117 | } |
| 118 | timeline_fd_ = ret; |
| 119 | return 0; |
| 120 | } |
| 121 | |
Sean Paul | acb2a44 | 2015-06-24 18:43:01 -0700 | [diff] [blame] | 122 | DrmCompositionType DrmDisplayComposition::type() const { |
| 123 | return type_; |
| 124 | } |
| 125 | |
| 126 | bool DrmDisplayComposition::validate_composition_type(DrmCompositionType des) { |
| 127 | return type_ == DRM_COMPOSITION_TYPE_EMPTY || type_ == des; |
| 128 | } |
| 129 | |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 130 | int DrmDisplayComposition::AddLayer(hwc_layer_1_t *layer, hwc_drm_bo_t *bo, |
| 131 | DrmCrtc *crtc, DrmPlane *plane) { |
Sean Paul | acb2a44 | 2015-06-24 18:43:01 -0700 | [diff] [blame] | 132 | if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME)) |
| 133 | return -EINVAL; |
| 134 | |
Zach Reizner | b44fd10 | 2015-08-07 16:00:01 -0700 | [diff] [blame^] | 135 | native_handle_t *handle_copy = dup_buffer_handle(layer->handle); |
| 136 | if (handle_copy == NULL) { |
| 137 | ALOGE("Failed to duplicate handle"); |
| 138 | return -ENOMEM; |
| 139 | } |
| 140 | |
| 141 | int ret = gralloc_->registerBuffer(gralloc_, handle_copy); |
| 142 | if (ret) { |
| 143 | ALOGE("Failed to register buffer handle %d", ret); |
| 144 | free_buffer_handle(handle_copy); |
| 145 | return ret; |
| 146 | } |
| 147 | |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 148 | ++timeline_; |
| 149 | layer->releaseFenceFd = |
| 150 | sw_sync_fence_create(timeline_fd_, "drm_fence", timeline_); |
| 151 | if (layer->releaseFenceFd < 0) { |
Zach Reizner | b44fd10 | 2015-08-07 16:00:01 -0700 | [diff] [blame^] | 152 | free_buffer_handle(handle_copy); |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 153 | ALOGE("Could not create release fence %d", layer->releaseFenceFd); |
| 154 | return layer->releaseFenceFd; |
| 155 | } |
| 156 | |
| 157 | DrmCompositionLayer_t c_layer; |
| 158 | c_layer.layer = *layer; |
| 159 | c_layer.bo = *bo; |
| 160 | c_layer.crtc = crtc; |
| 161 | c_layer.plane = plane; |
Zach Reizner | b44fd10 | 2015-08-07 16:00:01 -0700 | [diff] [blame^] | 162 | c_layer.handle = handle_copy; |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 163 | |
| 164 | layer->acquireFenceFd = -1; // We own this now |
| 165 | layers_.push_back(c_layer); |
Sean Paul | acb2a44 | 2015-06-24 18:43:01 -0700 | [diff] [blame] | 166 | type_ = DRM_COMPOSITION_TYPE_FRAME; |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 167 | return 0; |
| 168 | } |
| 169 | |
Zach Reizner | 713a678 | 2015-07-31 15:12:44 -0700 | [diff] [blame] | 170 | int DrmDisplayComposition::AddLayer(hwc_layer_1_t *layer, DrmCrtc *crtc, |
| 171 | DrmPlane *plane) { |
| 172 | if (layer->transform != 0) |
| 173 | return -EINVAL; |
| 174 | |
| 175 | if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME)) |
| 176 | return -EINVAL; |
| 177 | |
| 178 | hwc_drm_bo_t bo; |
| 179 | int ret = importer_->ImportBuffer(layer->handle, &bo); |
| 180 | if (ret) { |
| 181 | ALOGE("Failed to import handle of layer %d", ret); |
| 182 | return ret; |
| 183 | } |
| 184 | |
| 185 | ret = AddLayer(layer, &bo, crtc, plane); |
| 186 | if (ret) |
| 187 | importer_->ReleaseBuffer(&bo); |
| 188 | |
| 189 | return ret; |
| 190 | } |
| 191 | |
Sean Paul | db7a17d | 2015-06-24 18:46:05 -0700 | [diff] [blame] | 192 | int DrmDisplayComposition::AddDpmsMode(uint32_t dpms_mode) { |
| 193 | if (!validate_composition_type(DRM_COMPOSITION_TYPE_DPMS)) |
| 194 | return -EINVAL; |
| 195 | dpms_mode_ = dpms_mode; |
| 196 | type_ = DRM_COMPOSITION_TYPE_DPMS; |
| 197 | return 0; |
| 198 | } |
| 199 | |
Sean Paul | 2e46fbd | 2015-07-09 17:22:22 -0400 | [diff] [blame] | 200 | int DrmDisplayComposition::AddPlaneDisable(DrmPlane *plane) { |
| 201 | DrmCompositionLayer_t c_layer; |
| 202 | c_layer.crtc = NULL; |
| 203 | c_layer.plane = plane; |
| 204 | layers_.push_back(c_layer); |
| 205 | return 0; |
| 206 | } |
| 207 | |
Zach Reizner | b44fd10 | 2015-08-07 16:00:01 -0700 | [diff] [blame^] | 208 | void DrmDisplayComposition::RemoveNoPlaneLayers() { |
| 209 | for (auto &comp_layer : layers_) { |
| 210 | if (comp_layer.plane != NULL) |
| 211 | continue; |
| 212 | |
| 213 | if (importer_ && comp_layer.bo.fb_id) { |
| 214 | importer_->ReleaseBuffer(&comp_layer.bo); |
| 215 | } |
| 216 | |
| 217 | if (comp_layer.handle) { |
| 218 | gralloc_->unregisterBuffer(gralloc_, comp_layer.handle); |
| 219 | free_buffer_handle(comp_layer.handle); |
| 220 | } |
| 221 | |
| 222 | if (comp_layer.layer.acquireFenceFd >= 0) { |
| 223 | close(comp_layer.layer.acquireFenceFd); |
| 224 | comp_layer.layer.acquireFenceFd = -1; |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | layers_.erase( |
| 229 | std::remove_if(layers_.begin(), layers_.end(), |
| 230 | [](DrmCompositionLayer_t &l) { return l.plane == NULL; }), |
| 231 | layers_.end()); |
| 232 | } |
| 233 | |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 234 | int DrmDisplayComposition::FinishComposition() { |
Zach Reizner | ece0489 | 2015-07-17 14:13:28 -0700 | [diff] [blame] | 235 | int timeline_increase = timeline_ - timeline_current_; |
| 236 | if (timeline_increase <= 0) |
| 237 | return 0; |
| 238 | |
| 239 | int ret = sw_sync_timeline_inc(timeline_fd_, timeline_increase); |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 240 | if (ret) |
| 241 | ALOGE("Failed to increment sync timeline %d", ret); |
Zach Reizner | ece0489 | 2015-07-17 14:13:28 -0700 | [diff] [blame] | 242 | else |
| 243 | timeline_current_ = timeline_; |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 244 | |
| 245 | return ret; |
| 246 | } |
| 247 | |
| 248 | DrmCompositionLayerVector_t *DrmDisplayComposition::GetCompositionLayers() { |
| 249 | return &layers_; |
| 250 | } |
Sean Paul | db7a17d | 2015-06-24 18:46:05 -0700 | [diff] [blame] | 251 | |
| 252 | uint32_t DrmDisplayComposition::dpms_mode() const { |
| 253 | return dpms_mode_; |
| 254 | } |
Zach Reizner | 46ddd45 | 2015-07-30 08:10:14 -0700 | [diff] [blame] | 255 | |
| 256 | Importer *DrmDisplayComposition::importer() const { |
| 257 | return importer_; |
| 258 | } |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 259 | } |