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 | 4a25365 | 2015-09-10 18:30:54 -0700 | [diff] [blame^] | 33 | DrmCompositionLayer::DrmCompositionLayer(DrmCrtc *crtc, DrmHwcLayer &&l) |
| 34 | : crtc(crtc), |
| 35 | sf_handle(l.sf_handle), |
| 36 | buffer(std::move(l.buffer)), |
| 37 | handle(std::move(l.handle)), |
| 38 | transform(l.transform), |
| 39 | blending(l.blending), |
| 40 | alpha(l.alpha), |
| 41 | source_crop(l.source_crop), |
| 42 | display_frame(l.display_frame), |
| 43 | source_damage(l.source_damage), |
| 44 | acquire_fence(std::move(l.acquire_fence)) { |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 45 | } |
| 46 | |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 47 | DrmDisplayComposition::DrmDisplayComposition() |
Sean Paul | acb2a44 | 2015-06-24 18:43:01 -0700 | [diff] [blame] | 48 | : drm_(NULL), |
| 49 | importer_(NULL), |
| 50 | type_(DRM_COMPOSITION_TYPE_EMPTY), |
| 51 | timeline_fd_(-1), |
Sean Paul | db7a17d | 2015-06-24 18:46:05 -0700 | [diff] [blame] | 52 | timeline_(0), |
Zach Reizner | ece0489 | 2015-07-17 14:13:28 -0700 | [diff] [blame] | 53 | timeline_current_(0), |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 54 | timeline_pre_comp_done_(0), |
| 55 | pre_composition_layer_index_(-1), |
Sean Paul | bdc67bf | 2015-09-21 10:04:02 -0400 | [diff] [blame] | 56 | dpms_mode_(DRM_MODE_DPMS_ON), |
| 57 | frame_no_(0) { |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 58 | } |
| 59 | |
| 60 | DrmDisplayComposition::~DrmDisplayComposition() { |
Zach Reizner | ece0489 | 2015-07-17 14:13:28 -0700 | [diff] [blame] | 61 | if (timeline_fd_ >= 0) { |
| 62 | FinishComposition(); |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 63 | close(timeline_fd_); |
Zach Reizner | ece0489 | 2015-07-17 14:13:28 -0700 | [diff] [blame] | 64 | timeline_fd_ = -1; |
| 65 | } |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 66 | } |
| 67 | |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 68 | int DrmDisplayComposition::Init(DrmResources *drm, DrmCrtc *crtc, |
Sean Paul | bdc67bf | 2015-09-21 10:04:02 -0400 | [diff] [blame] | 69 | Importer *importer, uint64_t frame_no) { |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 70 | drm_ = drm; |
Zach Reizner | 4a25365 | 2015-09-10 18:30:54 -0700 | [diff] [blame^] | 71 | crtc_ = crtc; // Can be NULL if we haven't modeset yet |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 72 | importer_ = importer; |
Sean Paul | bdc67bf | 2015-09-21 10:04:02 -0400 | [diff] [blame] | 73 | frame_no_ = frame_no; |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 74 | |
Zach Reizner | 4a25365 | 2015-09-10 18:30:54 -0700 | [diff] [blame^] | 75 | int ret = sw_sync_timeline_create(); |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 76 | if (ret < 0) { |
| 77 | ALOGE("Failed to create sw sync timeline %d", ret); |
| 78 | return ret; |
| 79 | } |
| 80 | timeline_fd_ = ret; |
| 81 | return 0; |
| 82 | } |
| 83 | |
Sean Paul | acb2a44 | 2015-06-24 18:43:01 -0700 | [diff] [blame] | 84 | DrmCompositionType DrmDisplayComposition::type() const { |
| 85 | return type_; |
| 86 | } |
| 87 | |
| 88 | bool DrmDisplayComposition::validate_composition_type(DrmCompositionType des) { |
| 89 | return type_ == DRM_COMPOSITION_TYPE_EMPTY || type_ == des; |
| 90 | } |
| 91 | |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 92 | static DrmPlane *TakePlane(DrmCrtc *crtc, std::vector<DrmPlane *> *planes) { |
| 93 | for (auto iter = planes->begin(); iter != planes->end(); ++iter) { |
| 94 | if ((*iter)->GetCrtcSupported(*crtc)) { |
| 95 | DrmPlane *plane = *iter; |
| 96 | planes->erase(iter); |
| 97 | return plane; |
| 98 | } |
Zach Reizner | b44fd10 | 2015-08-07 16:00:01 -0700 | [diff] [blame] | 99 | } |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 100 | return NULL; |
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 | static DrmPlane *TakePlane(DrmCrtc *crtc, |
| 104 | std::vector<DrmPlane *> *primary_planes, |
| 105 | std::vector<DrmPlane *> *overlay_planes) { |
| 106 | DrmPlane *plane = TakePlane(crtc, primary_planes); |
| 107 | if (plane) |
| 108 | return plane; |
| 109 | return TakePlane(crtc, overlay_planes); |
| 110 | } |
Zach Reizner | 713a678 | 2015-07-31 15:12:44 -0700 | [diff] [blame] | 111 | |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 112 | int DrmDisplayComposition::CreateNextTimelineFence() { |
| 113 | ++timeline_; |
| 114 | return sw_sync_fence_create(timeline_fd_, "drm_fence", timeline_); |
| 115 | } |
Zach Reizner | 713a678 | 2015-07-31 15:12:44 -0700 | [diff] [blame] | 116 | |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 117 | int DrmDisplayComposition::IncreaseTimelineToPoint(int point) { |
| 118 | int timeline_increase = point - timeline_current_; |
| 119 | if (timeline_increase <= 0) |
| 120 | return 0; |
Zach Reizner | 713a678 | 2015-07-31 15:12:44 -0700 | [diff] [blame] | 121 | |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 122 | int ret = sw_sync_timeline_inc(timeline_fd_, timeline_increase); |
Zach Reizner | 713a678 | 2015-07-31 15:12:44 -0700 | [diff] [blame] | 123 | if (ret) |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 124 | ALOGE("Failed to increment sync timeline %d", ret); |
| 125 | else |
| 126 | timeline_current_ = point; |
Zach Reizner | 713a678 | 2015-07-31 15:12:44 -0700 | [diff] [blame] | 127 | |
| 128 | return ret; |
| 129 | } |
| 130 | |
Zach Reizner | 4a25365 | 2015-09-10 18:30:54 -0700 | [diff] [blame^] | 131 | int DrmDisplayComposition::SetLayers(DrmHwcLayer *layers, size_t num_layers, |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 132 | std::vector<DrmPlane *> *primary_planes, |
| 133 | std::vector<DrmPlane *> *overlay_planes) { |
| 134 | int ret = 0; |
| 135 | if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME)) |
| 136 | return -EINVAL; |
| 137 | |
| 138 | for (size_t layer_index = 0; layer_index < num_layers; layer_index++) { |
Zach Reizner | 4a25365 | 2015-09-10 18:30:54 -0700 | [diff] [blame^] | 139 | DrmHwcLayer *layer = &layers[layer_index]; |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 140 | |
Zach Reizner | 4a25365 | 2015-09-10 18:30:54 -0700 | [diff] [blame^] | 141 | layers_.emplace_back(crtc_, std::move(*layer)); |
| 142 | DrmCompositionLayer *c_layer = &layers_.back(); |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 143 | |
| 144 | if (pre_composition_layer_index_ == -1) { |
| 145 | c_layer->plane = TakePlane(crtc_, primary_planes, overlay_planes); |
| 146 | if (c_layer->plane == NULL) { |
| 147 | if (layers_.size() <= 1) { |
| 148 | ALOGE("Failed to match any planes to the crtc of this display"); |
| 149 | ret = -ENODEV; |
| 150 | goto fail; |
| 151 | } |
| 152 | |
| 153 | layers_.emplace_back(); |
| 154 | // c_layer's address might have changed when we resized the vector |
| 155 | c_layer = &layers_[layers_.size() - 2]; |
Zach Reizner | 4a25365 | 2015-09-10 18:30:54 -0700 | [diff] [blame^] | 156 | DrmCompositionLayer &pre_comp_layer = layers_.back(); |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 157 | pre_comp_layer.crtc = crtc_; |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 158 | |
| 159 | pre_composition_layer_index_ = layers_.size() - 1; |
| 160 | |
| 161 | // This is all to fix up the previous layer, which has now become part |
| 162 | // of the set of pre-composition layers because we are stealing its |
| 163 | // plane. |
Zach Reizner | 4a25365 | 2015-09-10 18:30:54 -0700 | [diff] [blame^] | 164 | DrmCompositionLayer &last_c_layer = layers_[layers_.size() - 3]; |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 165 | std::swap(pre_comp_layer.plane, last_c_layer.plane); |
Zach Reizner | 4a25365 | 2015-09-10 18:30:54 -0700 | [diff] [blame^] | 166 | OutputFd &last_release_fence = layers[layer_index - 1].release_fence; |
| 167 | last_release_fence.Set(CreateNextTimelineFence()); |
| 168 | ret = last_release_fence.get(); |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 169 | if (ret < 0) { |
| 170 | ALOGE("Could not create release fence %d", ret); |
| 171 | goto fail; |
| 172 | } |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | if (c_layer->plane == NULL) { |
| 177 | // Layers to be pre composited all get the earliest release fences as they |
| 178 | // will get released soonest. |
Zach Reizner | 4a25365 | 2015-09-10 18:30:54 -0700 | [diff] [blame^] | 179 | layer->release_fence.Set(CreateNextTimelineFence()); |
| 180 | ret = layer->release_fence.get(); |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 181 | if (ret < 0) { |
| 182 | ALOGE("Could not create release fence %d", ret); |
| 183 | goto fail; |
| 184 | } |
| 185 | } |
| 186 | } |
| 187 | |
| 188 | timeline_pre_comp_done_ = timeline_; |
| 189 | |
| 190 | for (size_t layer_index = 0; layer_index < num_layers; layer_index++) { |
Zach Reizner | 4a25365 | 2015-09-10 18:30:54 -0700 | [diff] [blame^] | 191 | DrmHwcLayer *layer = &layers[layer_index]; |
| 192 | if (layer->release_fence.get() >= 0) |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 193 | continue; |
| 194 | |
Zach Reizner | 4a25365 | 2015-09-10 18:30:54 -0700 | [diff] [blame^] | 195 | ret = layer->release_fence.Set(CreateNextTimelineFence()); |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 196 | if (ret < 0) { |
| 197 | ALOGE("Could not create release fence %d", ret); |
| 198 | goto fail; |
| 199 | } |
| 200 | } |
| 201 | |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 202 | type_ = DRM_COMPOSITION_TYPE_FRAME; |
| 203 | return 0; |
| 204 | |
| 205 | fail: |
| 206 | |
| 207 | for (size_t c_layer_index = 0; c_layer_index < layers_.size(); |
| 208 | c_layer_index++) { |
Zach Reizner | 4a25365 | 2015-09-10 18:30:54 -0700 | [diff] [blame^] | 209 | DrmCompositionLayer &c_layer = layers_[c_layer_index]; |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 210 | if (c_layer.plane != NULL) { |
| 211 | std::vector<DrmPlane *> *return_to = |
| 212 | (c_layer.plane->type() == DRM_PLANE_TYPE_PRIMARY) ? primary_planes |
| 213 | : overlay_planes; |
| 214 | return_to->insert(return_to->begin() + c_layer_index, c_layer.plane); |
| 215 | } |
| 216 | } |
Zach Reizner | 4a25365 | 2015-09-10 18:30:54 -0700 | [diff] [blame^] | 217 | |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 218 | layers_.clear(); |
| 219 | |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 220 | sw_sync_timeline_inc(timeline_fd_, timeline_ - timeline_current_); |
| 221 | |
| 222 | timeline_ = timeline_current_; |
| 223 | return ret; |
| 224 | } |
| 225 | |
| 226 | int DrmDisplayComposition::SetDpmsMode(uint32_t dpms_mode) { |
Sean Paul | db7a17d | 2015-06-24 18:46:05 -0700 | [diff] [blame] | 227 | if (!validate_composition_type(DRM_COMPOSITION_TYPE_DPMS)) |
| 228 | return -EINVAL; |
| 229 | dpms_mode_ = dpms_mode; |
| 230 | type_ = DRM_COMPOSITION_TYPE_DPMS; |
| 231 | return 0; |
| 232 | } |
| 233 | |
Sean Paul | 2e46fbd | 2015-07-09 17:22:22 -0400 | [diff] [blame] | 234 | int DrmDisplayComposition::AddPlaneDisable(DrmPlane *plane) { |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 235 | layers_.emplace_back(); |
Zach Reizner | 4a25365 | 2015-09-10 18:30:54 -0700 | [diff] [blame^] | 236 | DrmCompositionLayer &c_layer = layers_.back(); |
Sean Paul | 2e46fbd | 2015-07-09 17:22:22 -0400 | [diff] [blame] | 237 | c_layer.crtc = NULL; |
| 238 | c_layer.plane = plane; |
Sean Paul | 2e46fbd | 2015-07-09 17:22:22 -0400 | [diff] [blame] | 239 | return 0; |
| 240 | } |
| 241 | |
Zach Reizner | b44fd10 | 2015-08-07 16:00:01 -0700 | [diff] [blame] | 242 | void DrmDisplayComposition::RemoveNoPlaneLayers() { |
Zach Reizner | b44fd10 | 2015-08-07 16:00:01 -0700 | [diff] [blame] | 243 | layers_.erase( |
| 244 | std::remove_if(layers_.begin(), layers_.end(), |
Zach Reizner | 4a25365 | 2015-09-10 18:30:54 -0700 | [diff] [blame^] | 245 | [](DrmCompositionLayer &l) { return l.plane == NULL; }), |
Zach Reizner | b44fd10 | 2015-08-07 16:00:01 -0700 | [diff] [blame] | 246 | layers_.end()); |
| 247 | } |
| 248 | |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 249 | int DrmDisplayComposition::SignalPreCompositionDone() { |
| 250 | return IncreaseTimelineToPoint(timeline_pre_comp_done_); |
| 251 | } |
| 252 | |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 253 | int DrmDisplayComposition::FinishComposition() { |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 254 | return IncreaseTimelineToPoint(timeline_); |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 255 | } |
| 256 | |
Zach Reizner | 4a25365 | 2015-09-10 18:30:54 -0700 | [diff] [blame^] | 257 | std::vector<DrmCompositionLayer> |
| 258 | *DrmDisplayComposition::GetCompositionLayers() { |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 259 | return &layers_; |
| 260 | } |
Sean Paul | db7a17d | 2015-06-24 18:46:05 -0700 | [diff] [blame] | 261 | |
Zach Reizner | 0980705 | 2015-08-13 14:53:41 -0700 | [diff] [blame] | 262 | int DrmDisplayComposition::pre_composition_layer_index() const { |
| 263 | return pre_composition_layer_index_; |
| 264 | } |
| 265 | |
Sean Paul | db7a17d | 2015-06-24 18:46:05 -0700 | [diff] [blame] | 266 | uint32_t DrmDisplayComposition::dpms_mode() const { |
| 267 | return dpms_mode_; |
| 268 | } |
Zach Reizner | 46ddd45 | 2015-07-30 08:10:14 -0700 | [diff] [blame] | 269 | |
Sean Paul | bdc67bf | 2015-09-21 10:04:02 -0400 | [diff] [blame] | 270 | uint64_t DrmDisplayComposition::frame_no() const { |
| 271 | return frame_no_; |
| 272 | } |
| 273 | |
Zach Reizner | 46ddd45 | 2015-07-30 08:10:14 -0700 | [diff] [blame] | 274 | Importer *DrmDisplayComposition::importer() const { |
| 275 | return importer_; |
| 276 | } |
Sean Paul | 98e73c8 | 2015-06-24 14:38:49 -0700 | [diff] [blame] | 277 | } |