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 <algorithm>
27 #include <unordered_set>
28
29 #include <cutils/log.h>
30 #include <sw_sync.h>
31 #include <sync/sync.h>
32 #include <xf86drmMode.h>
33
34 namespace android {
35
36 const size_t DrmCompositionPlane::kSourceNone;
37 const size_t DrmCompositionPlane::kSourcePreComp;
38 const size_t DrmCompositionPlane::kSourceSquash;
39 const size_t DrmCompositionPlane::kSourceLayerMax;
40
~DrmDisplayComposition()41 DrmDisplayComposition::~DrmDisplayComposition() {
42 if (timeline_fd_ >= 0) {
43 SignalCompositionDone();
44 close(timeline_fd_);
45 }
46 }
47
Init(DrmResources * drm,DrmCrtc * crtc,Importer * importer,uint64_t frame_no)48 int DrmDisplayComposition::Init(DrmResources *drm, DrmCrtc *crtc,
49 Importer *importer, uint64_t frame_no) {
50 drm_ = drm;
51 crtc_ = crtc; // Can be NULL if we haven't modeset yet
52 importer_ = importer;
53 frame_no_ = frame_no;
54
55 int ret = sw_sync_timeline_create();
56 if (ret < 0) {
57 ALOGE("Failed to create sw sync timeline %d", ret);
58 return ret;
59 }
60 timeline_fd_ = ret;
61 return 0;
62 }
63
validate_composition_type(DrmCompositionType des)64 bool DrmDisplayComposition::validate_composition_type(DrmCompositionType des) {
65 return type_ == DRM_COMPOSITION_TYPE_EMPTY || type_ == des;
66 }
67
CreateNextTimelineFence()68 int DrmDisplayComposition::CreateNextTimelineFence() {
69 ++timeline_;
70 return sw_sync_fence_create(timeline_fd_, "hwc drm display composition fence",
71 timeline_);
72 }
73
IncreaseTimelineToPoint(int point)74 int DrmDisplayComposition::IncreaseTimelineToPoint(int point) {
75 int timeline_increase = point - timeline_current_;
76 if (timeline_increase <= 0)
77 return 0;
78
79 int ret = sw_sync_timeline_inc(timeline_fd_, timeline_increase);
80 if (ret)
81 ALOGE("Failed to increment sync timeline %d", ret);
82 else
83 timeline_current_ = point;
84
85 return ret;
86 }
87
SetLayers(DrmHwcLayer * layers,size_t num_layers,bool geometry_changed)88 int DrmDisplayComposition::SetLayers(DrmHwcLayer *layers, size_t num_layers,
89 bool geometry_changed) {
90 if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME))
91 return -EINVAL;
92
93 geometry_changed_ = geometry_changed;
94
95 for (size_t layer_index = 0; layer_index < num_layers; layer_index++) {
96 layers_.emplace_back(std::move(layers[layer_index]));
97 }
98
99 type_ = DRM_COMPOSITION_TYPE_FRAME;
100 return 0;
101 }
102
SetDpmsMode(uint32_t dpms_mode)103 int DrmDisplayComposition::SetDpmsMode(uint32_t dpms_mode) {
104 if (!validate_composition_type(DRM_COMPOSITION_TYPE_DPMS))
105 return -EINVAL;
106 dpms_mode_ = dpms_mode;
107 type_ = DRM_COMPOSITION_TYPE_DPMS;
108 return 0;
109 }
110
SetDisplayMode(const DrmMode & display_mode)111 int DrmDisplayComposition::SetDisplayMode(const DrmMode &display_mode) {
112 if (!validate_composition_type(DRM_COMPOSITION_TYPE_MODESET))
113 return -EINVAL;
114 display_mode_ = display_mode;
115 dpms_mode_ = DRM_MODE_DPMS_ON;
116 type_ = DRM_COMPOSITION_TYPE_MODESET;
117 return 0;
118 }
119
AddPlaneDisable(DrmPlane * plane)120 int DrmDisplayComposition::AddPlaneDisable(DrmPlane *plane) {
121 composition_planes_.emplace_back(
122 DrmCompositionPlane{plane, crtc_, DrmCompositionPlane::kSourceNone});
123 return 0;
124 }
125
CountUsablePlanes(DrmCrtc * crtc,std::vector<DrmPlane * > * primary_planes,std::vector<DrmPlane * > * overlay_planes)126 static size_t CountUsablePlanes(DrmCrtc *crtc,
127 std::vector<DrmPlane *> *primary_planes,
128 std::vector<DrmPlane *> *overlay_planes) {
129 return std::count_if(
130 primary_planes->begin(), primary_planes->end(),
131 [=](DrmPlane *plane) { return plane->GetCrtcSupported(*crtc); }) +
132 std::count_if(
133 overlay_planes->begin(), overlay_planes->end(),
134 [=](DrmPlane *plane) { return plane->GetCrtcSupported(*crtc); });
135 }
136
TakePlane(DrmCrtc * crtc,std::vector<DrmPlane * > * planes)137 static DrmPlane *TakePlane(DrmCrtc *crtc, std::vector<DrmPlane *> *planes) {
138 for (auto iter = planes->begin(); iter != planes->end(); ++iter) {
139 if ((*iter)->GetCrtcSupported(*crtc)) {
140 DrmPlane *plane = *iter;
141 planes->erase(iter);
142 return plane;
143 }
144 }
145 return NULL;
146 }
147
TakePlane(DrmCrtc * crtc,std::vector<DrmPlane * > * primary_planes,std::vector<DrmPlane * > * overlay_planes)148 static DrmPlane *TakePlane(DrmCrtc *crtc,
149 std::vector<DrmPlane *> *primary_planes,
150 std::vector<DrmPlane *> *overlay_planes) {
151 DrmPlane *plane = TakePlane(crtc, primary_planes);
152 if (plane)
153 return plane;
154 return TakePlane(crtc, overlay_planes);
155 }
156
SetBitsToVector(uint64_t in,size_t * index_map)157 static std::vector<size_t> SetBitsToVector(uint64_t in, size_t *index_map) {
158 std::vector<size_t> out;
159 size_t msb = sizeof(in) * 8 - 1;
160 uint64_t mask = (uint64_t)1 << msb;
161 for (size_t i = msb; mask != (uint64_t)0; i--, mask >>= 1)
162 if (in & mask)
163 out.push_back(index_map[i]);
164 return out;
165 }
166
SeparateLayers(DrmHwcLayer * layers,size_t * used_layers,size_t num_used_layers,DrmHwcRect<int> * exclude_rects,size_t num_exclude_rects,std::vector<DrmCompositionRegion> & regions)167 static void SeparateLayers(DrmHwcLayer *layers, size_t *used_layers,
168 size_t num_used_layers,
169 DrmHwcRect<int> *exclude_rects,
170 size_t num_exclude_rects,
171 std::vector<DrmCompositionRegion> ®ions) {
172 if (num_used_layers > 64) {
173 ALOGE("Failed to separate layers because there are more than 64");
174 return;
175 }
176
177 if (num_used_layers + num_exclude_rects > 64) {
178 ALOGW(
179 "Exclusion rectangles are being truncated to make the rectangle count "
180 "fit into 64");
181 num_exclude_rects = 64 - num_used_layers;
182 }
183
184 // We inject all the exclude rects into the rects list. Any resulting rect
185 // that includes ANY of the first num_exclude_rects is rejected.
186 std::vector<DrmHwcRect<int>> layer_rects(num_used_layers + num_exclude_rects);
187 std::copy(exclude_rects, exclude_rects + num_exclude_rects,
188 layer_rects.begin());
189 std::transform(
190 used_layers, used_layers + num_used_layers,
191 layer_rects.begin() + num_exclude_rects,
192 [=](size_t layer_index) { return layers[layer_index].display_frame; });
193
194 std::vector<seperate_rects::RectSet<uint64_t, int>> seperate_regions;
195 seperate_rects::seperate_rects_64(layer_rects, &seperate_regions);
196 uint64_t exclude_mask = ((uint64_t)1 << num_exclude_rects) - 1;
197
198 for (seperate_rects::RectSet<uint64_t, int> ®ion : seperate_regions) {
199 if (region.id_set.getBits() & exclude_mask)
200 continue;
201 regions.emplace_back(DrmCompositionRegion{
202 region.rect,
203 SetBitsToVector(region.id_set.getBits() >> num_exclude_rects,
204 used_layers)});
205 }
206 }
207
CreateAndAssignReleaseFences()208 int DrmDisplayComposition::CreateAndAssignReleaseFences() {
209 std::unordered_set<DrmHwcLayer *> squash_layers;
210 std::unordered_set<DrmHwcLayer *> pre_comp_layers;
211 std::unordered_set<DrmHwcLayer *> comp_layers;
212
213 for (const DrmCompositionRegion ®ion : squash_regions_) {
214 for (size_t source_layer_index : region.source_layers) {
215 DrmHwcLayer *source_layer = &layers_[source_layer_index];
216 squash_layers.emplace(source_layer);
217 }
218 }
219
220 for (const DrmCompositionRegion ®ion : pre_comp_regions_) {
221 for (size_t source_layer_index : region.source_layers) {
222 DrmHwcLayer *source_layer = &layers_[source_layer_index];
223 pre_comp_layers.emplace(source_layer);
224 squash_layers.erase(source_layer);
225 }
226 }
227
228 for (const DrmCompositionPlane &plane : composition_planes_) {
229 if (plane.source_layer <= DrmCompositionPlane::kSourceLayerMax) {
230 DrmHwcLayer *source_layer = &layers_[plane.source_layer];
231 comp_layers.emplace(source_layer);
232 pre_comp_layers.erase(source_layer);
233 }
234 }
235
236 for (DrmHwcLayer *layer : squash_layers) {
237 int ret = layer->release_fence.Set(CreateNextTimelineFence());
238 if (ret < 0)
239 return ret;
240 }
241 timeline_squash_done_ = timeline_;
242
243 for (DrmHwcLayer *layer : pre_comp_layers) {
244 int ret = layer->release_fence.Set(CreateNextTimelineFence());
245 if (ret < 0)
246 return ret;
247 }
248 timeline_pre_comp_done_ = timeline_;
249
250 for (DrmHwcLayer *layer : comp_layers) {
251 int ret = layer->release_fence.Set(CreateNextTimelineFence());
252 if (ret < 0)
253 return ret;
254 }
255
256 return 0;
257 }
258
Plan(SquashState * squash,std::vector<DrmPlane * > * primary_planes,std::vector<DrmPlane * > * overlay_planes)259 int DrmDisplayComposition::Plan(SquashState *squash,
260 std::vector<DrmPlane *> *primary_planes,
261 std::vector<DrmPlane *> *overlay_planes) {
262 if (type_ != DRM_COMPOSITION_TYPE_FRAME)
263 return 0;
264
265 size_t planes_can_use =
266 CountUsablePlanes(crtc_, primary_planes, overlay_planes);
267 if (planes_can_use == 0) {
268 ALOGE("Display %d has no usable planes", crtc_->display());
269 return -ENODEV;
270 }
271
272 bool use_squash_framebuffer = false;
273 // Used to determine which layers were entirely squashed
274 std::vector<int> layer_squash_area(layers_.size(), 0);
275 // Used to avoid rerendering regions that were squashed
276 std::vector<DrmHwcRect<int>> exclude_rects;
277 if (squash != NULL && planes_can_use >= 3) {
278 if (geometry_changed_) {
279 squash->Init(layers_.data(), layers_.size());
280 } else {
281 std::vector<bool> changed_regions;
282 squash->GenerateHistory(layers_.data(), layers_.size(), changed_regions);
283
284 std::vector<bool> stable_regions;
285 squash->StableRegionsWithMarginalHistory(changed_regions, stable_regions);
286
287 // Only if SOME region is stable
288 use_squash_framebuffer =
289 std::find(stable_regions.begin(), stable_regions.end(), true) !=
290 stable_regions.end();
291
292 squash->RecordHistory(layers_.data(), layers_.size(), changed_regions);
293
294 // Changes in which regions are squashed triggers a rerender via
295 // squash_regions.
296 bool render_squash = squash->RecordAndCompareSquashed(stable_regions);
297
298 for (size_t region_index = 0; region_index < stable_regions.size();
299 region_index++) {
300 const SquashState::Region ®ion = squash->regions()[region_index];
301 if (!stable_regions[region_index])
302 continue;
303
304 exclude_rects.emplace_back(region.rect);
305
306 if (render_squash) {
307 squash_regions_.emplace_back();
308 squash_regions_.back().frame = region.rect;
309 }
310
311 int frame_area = region.rect.area();
312 // Source layers are sorted front to back i.e. top layer has lowest
313 // index.
314 for (size_t layer_index = layers_.size();
315 layer_index-- > 0; // Yes, I double checked this
316 /* See condition */) {
317 if (!region.layer_refs[layer_index])
318 continue;
319 layer_squash_area[layer_index] += frame_area;
320 if (render_squash)
321 squash_regions_.back().source_layers.push_back(layer_index);
322 }
323 }
324 }
325 }
326
327 std::vector<size_t> layers_remaining;
328 for (size_t layer_index = 0; layer_index < layers_.size(); layer_index++) {
329 // Skip layers that were completely squashed
330 if (layer_squash_area[layer_index] >=
331 layers_[layer_index].display_frame.area()) {
332 continue;
333 }
334
335 layers_remaining.push_back(layer_index);
336 }
337
338 if (use_squash_framebuffer)
339 planes_can_use--;
340
341 if (layers_remaining.size() > planes_can_use)
342 planes_can_use--;
343
344 size_t last_composition_layer = 0;
345 for (last_composition_layer = 0;
346 last_composition_layer < layers_remaining.size() && planes_can_use > 0;
347 last_composition_layer++, planes_can_use--) {
348 composition_planes_.emplace_back(
349 DrmCompositionPlane{TakePlane(crtc_, primary_planes, overlay_planes),
350 crtc_, layers_remaining[last_composition_layer]});
351 }
352
353 layers_remaining.erase(layers_remaining.begin(),
354 layers_remaining.begin() + last_composition_layer);
355
356 if (layers_remaining.size() > 0) {
357 composition_planes_.emplace_back(
358 DrmCompositionPlane{TakePlane(crtc_, primary_planes, overlay_planes),
359 crtc_, DrmCompositionPlane::kSourcePreComp});
360
361 SeparateLayers(layers_.data(), layers_remaining.data(),
362 layers_remaining.size(), exclude_rects.data(),
363 exclude_rects.size(), pre_comp_regions_);
364 }
365
366 if (use_squash_framebuffer) {
367 composition_planes_.emplace_back(
368 DrmCompositionPlane{TakePlane(crtc_, primary_planes, overlay_planes),
369 crtc_, DrmCompositionPlane::kSourceSquash});
370 }
371
372 return CreateAndAssignReleaseFences();
373 }
374
DrmCompositionTypeToString(DrmCompositionType type)375 static const char *DrmCompositionTypeToString(DrmCompositionType type) {
376 switch (type) {
377 case DRM_COMPOSITION_TYPE_EMPTY:
378 return "EMPTY";
379 case DRM_COMPOSITION_TYPE_FRAME:
380 return "FRAME";
381 case DRM_COMPOSITION_TYPE_DPMS:
382 return "DPMS";
383 case DRM_COMPOSITION_TYPE_MODESET:
384 return "MODESET";
385 default:
386 return "<invalid>";
387 }
388 }
389
DPMSModeToString(int dpms_mode)390 static const char *DPMSModeToString(int dpms_mode) {
391 switch (dpms_mode) {
392 case DRM_MODE_DPMS_ON:
393 return "ON";
394 case DRM_MODE_DPMS_OFF:
395 return "OFF";
396 default:
397 return "<invalid>";
398 }
399 }
400
DumpBuffer(const DrmHwcBuffer & buffer,std::ostringstream * out)401 static void DumpBuffer(const DrmHwcBuffer &buffer, std::ostringstream *out) {
402 if (!buffer) {
403 *out << "buffer=<invalid>";
404 return;
405 }
406
407 *out << "buffer[w/h/format]=";
408 *out << buffer->width << "/" << buffer->height << "/" << buffer->format;
409 }
410
TransformToString(DrmHwcTransform transform)411 static const char *TransformToString(DrmHwcTransform transform) {
412 switch (transform) {
413 case DrmHwcTransform::kIdentity:
414 return "IDENTITY";
415 case DrmHwcTransform::kFlipH:
416 return "FLIPH";
417 case DrmHwcTransform::kFlipV:
418 return "FLIPV";
419 case DrmHwcTransform::kRotate90:
420 return "ROTATE90";
421 case DrmHwcTransform::kRotate180:
422 return "ROTATE180";
423 case DrmHwcTransform::kRotate270:
424 return "ROTATE270";
425 default:
426 return "<invalid>";
427 }
428 }
429
BlendingToString(DrmHwcBlending blending)430 static const char *BlendingToString(DrmHwcBlending blending) {
431 switch (blending) {
432 case DrmHwcBlending::kNone:
433 return "NONE";
434 case DrmHwcBlending::kPreMult:
435 return "PREMULT";
436 case DrmHwcBlending::kCoverage:
437 return "COVERAGE";
438 default:
439 return "<invalid>";
440 }
441 }
442
DumpRegion(const DrmCompositionRegion & region,std::ostringstream * out)443 static void DumpRegion(const DrmCompositionRegion ®ion,
444 std::ostringstream *out) {
445 *out << "frame";
446 region.frame.Dump(out);
447 *out << " source_layers=(";
448
449 const std::vector<size_t> &source_layers = region.source_layers;
450 for (size_t i = 0; i < source_layers.size(); i++) {
451 *out << source_layers[i];
452 if (i < source_layers.size() - 1) {
453 *out << " ";
454 }
455 }
456
457 *out << ")";
458 }
459
Dump(std::ostringstream * out) const460 void DrmDisplayComposition::Dump(std::ostringstream *out) const {
461 *out << "----DrmDisplayComposition"
462 << " crtc=" << (crtc_ ? crtc_->id() : -1)
463 << " type=" << DrmCompositionTypeToString(type_);
464
465 switch (type_) {
466 case DRM_COMPOSITION_TYPE_DPMS:
467 *out << " dpms_mode=" << DPMSModeToString(dpms_mode_);
468 break;
469 case DRM_COMPOSITION_TYPE_MODESET:
470 *out << " display_mode=" << display_mode_.h_display() << "x"
471 << display_mode_.v_display();
472 break;
473 default:
474 break;
475 }
476
477 *out << " timeline[current/squash/pre-comp/done]=" << timeline_current_ << "/"
478 << timeline_squash_done_ << "/" << timeline_pre_comp_done_ << "/"
479 << timeline_ << "\n";
480
481 *out << " Layers: count=" << layers_.size() << "\n";
482 for (size_t i = 0; i < layers_.size(); i++) {
483 const DrmHwcLayer &layer = layers_[i];
484 *out << " [" << i << "] ";
485
486 DumpBuffer(layer.buffer, out);
487
488 *out << " transform=" << TransformToString(layer.transform)
489 << " blending[a=" << (int)layer.alpha
490 << "]=" << BlendingToString(layer.blending) << " source_crop";
491 layer.source_crop.Dump(out);
492 *out << " display_frame";
493 layer.display_frame.Dump(out);
494
495 *out << "\n";
496 }
497
498 *out << " Planes: count=" << composition_planes_.size() << "\n";
499 for (size_t i = 0; i < composition_planes_.size(); i++) {
500 const DrmCompositionPlane &comp_plane = composition_planes_[i];
501 *out << " [" << i << "]"
502 << " plane=" << (comp_plane.plane ? comp_plane.plane->id() : -1)
503 << " source_layer=";
504 if (comp_plane.source_layer <= DrmCompositionPlane::kSourceLayerMax) {
505 *out << comp_plane.source_layer;
506 } else {
507 switch (comp_plane.source_layer) {
508 case DrmCompositionPlane::kSourceNone:
509 *out << "NONE";
510 break;
511 case DrmCompositionPlane::kSourcePreComp:
512 *out << "PRECOMP";
513 break;
514 case DrmCompositionPlane::kSourceSquash:
515 *out << "SQUASH";
516 break;
517 default:
518 *out << "<invalid>";
519 break;
520 }
521 }
522
523 *out << "\n";
524 }
525
526 *out << " Squash Regions: count=" << squash_regions_.size() << "\n";
527 for (size_t i = 0; i < squash_regions_.size(); i++) {
528 *out << " [" << i << "] ";
529 DumpRegion(squash_regions_[i], out);
530 *out << "\n";
531 }
532
533 *out << " Pre-Comp Regions: count=" << pre_comp_regions_.size() << "\n";
534 for (size_t i = 0; i < pre_comp_regions_.size(); i++) {
535 *out << " [" << i << "] ";
536 DumpRegion(pre_comp_regions_[i], out);
537 *out << "\n";
538 }
539 }
540 }
541