OSDN Git Service

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