2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #define LOG_TAG "hwc-drm-display-composition"
19 #include "drmdisplaycomposition.h"
22 #include "drmresources.h"
27 #include <unordered_set>
29 #include <cutils/log.h>
31 #include <sync/sync.h>
32 #include <xf86drmMode.h>
36 const size_t DrmCompositionPlane::kSourceNone;
37 const size_t DrmCompositionPlane::kSourcePreComp;
38 const size_t DrmCompositionPlane::kSourceSquash;
39 const size_t DrmCompositionPlane::kSourceLayerMax;
41 DrmDisplayComposition::~DrmDisplayComposition() {
42 if (timeline_fd_ >= 0) {
43 SignalCompositionDone();
48 int DrmDisplayComposition::Init(DrmResources *drm, DrmCrtc *crtc,
49 Importer *importer, uint64_t frame_no) {
51 crtc_ = crtc; // Can be NULL if we haven't modeset yet
55 int ret = sw_sync_timeline_create();
57 ALOGE("Failed to create sw sync timeline %d", ret);
64 bool DrmDisplayComposition::validate_composition_type(DrmCompositionType des) {
65 return type_ == DRM_COMPOSITION_TYPE_EMPTY || type_ == des;
68 int DrmDisplayComposition::CreateNextTimelineFence() {
70 return sw_sync_fence_create(timeline_fd_, "hwc drm display composition fence",
74 int DrmDisplayComposition::IncreaseTimelineToPoint(int point) {
75 int timeline_increase = point - timeline_current_;
76 if (timeline_increase <= 0)
79 int ret = sw_sync_timeline_inc(timeline_fd_, timeline_increase);
81 ALOGE("Failed to increment sync timeline %d", ret);
83 timeline_current_ = point;
88 int DrmDisplayComposition::SetLayers(DrmHwcLayer *layers, size_t num_layers,
89 bool geometry_changed) {
90 if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME))
93 geometry_changed_ = geometry_changed;
95 for (size_t layer_index = 0; layer_index < num_layers; layer_index++) {
96 layers_.emplace_back(std::move(layers[layer_index]));
99 type_ = DRM_COMPOSITION_TYPE_FRAME;
103 int DrmDisplayComposition::SetDpmsMode(uint32_t dpms_mode) {
104 if (!validate_composition_type(DRM_COMPOSITION_TYPE_DPMS))
106 dpms_mode_ = dpms_mode;
107 type_ = DRM_COMPOSITION_TYPE_DPMS;
111 int DrmDisplayComposition::SetDisplayMode(const DrmMode &display_mode) {
112 if (!validate_composition_type(DRM_COMPOSITION_TYPE_MODESET))
114 display_mode_ = display_mode;
115 dpms_mode_ = DRM_MODE_DPMS_ON;
116 type_ = DRM_COMPOSITION_TYPE_MODESET;
120 int DrmDisplayComposition::AddPlaneDisable(DrmPlane *plane) {
121 composition_planes_.emplace_back(
122 DrmCompositionPlane{plane, crtc_, DrmCompositionPlane::kSourceNone});
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); }) +
133 overlay_planes->begin(), overlay_planes->end(),
134 [=](DrmPlane *plane) { return plane->GetCrtcSupported(*crtc); });
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;
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);
154 return TakePlane(crtc, overlay_planes);
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)
163 out.push_back(index_map[i]);
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");
177 if (num_used_layers + num_exclude_rects > 64) {
179 "Exclusion rectangles are being truncated to make the rectangle count "
181 num_exclude_rects = 64 - num_used_layers;
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());
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; });
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;
198 for (seperate_rects::RectSet<uint64_t, int> ®ion : seperate_regions) {
199 if (region.id_set.getBits() & exclude_mask)
201 regions.emplace_back(DrmCompositionRegion{
203 SetBitsToVector(region.id_set.getBits() >> num_exclude_rects,
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;
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);
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);
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);
236 for (DrmHwcLayer *layer : squash_layers) {
237 int ret = layer->release_fence.Set(CreateNextTimelineFence());
241 timeline_squash_done_ = timeline_;
243 for (DrmHwcLayer *layer : pre_comp_layers) {
244 int ret = layer->release_fence.Set(CreateNextTimelineFence());
248 timeline_pre_comp_done_ = timeline_;
250 for (DrmHwcLayer *layer : comp_layers) {
251 int ret = layer->release_fence.Set(CreateNextTimelineFence());
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)
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());
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());
281 std::vector<bool> changed_regions;
282 squash->GenerateHistory(layers_.data(), layers_.size(), changed_regions);
284 std::vector<bool> stable_regions;
285 squash->StableRegionsWithMarginalHistory(changed_regions, stable_regions);
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();
292 squash->RecordHistory(layers_.data(), layers_.size(), changed_regions);
294 // Changes in which regions are squashed triggers a rerender via
296 bool render_squash = squash->RecordAndCompareSquashed(stable_regions);
298 for (size_t region_index = 0; region_index < stable_regions.size();
300 const SquashState::Region ®ion = squash->regions()[region_index];
301 if (!stable_regions[region_index])
304 exclude_rects.emplace_back(region.rect);
307 squash_regions_.emplace_back();
308 squash_regions_.back().frame = region.rect;
311 int frame_area = region.rect.area();
312 // Source layers are sorted front to back i.e. top layer has lowest
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])
319 layer_squash_area[layer_index] += frame_area;
321 squash_regions_.back().source_layers.push_back(layer_index);
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()) {
335 layers_remaining.push_back(layer_index);
338 if (use_squash_framebuffer)
341 if (layers_remaining.size() > planes_can_use)
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]});
353 layers_remaining.erase(layers_remaining.begin(),
354 layers_remaining.begin() + last_composition_layer);
356 if (layers_remaining.size() > 0) {
357 composition_planes_.emplace_back(
358 DrmCompositionPlane{TakePlane(crtc_, primary_planes, overlay_planes),
359 crtc_, DrmCompositionPlane::kSourcePreComp});
361 SeparateLayers(layers_.data(), layers_remaining.data(),
362 layers_remaining.size(), exclude_rects.data(),
363 exclude_rects.size(), pre_comp_regions_);
366 if (use_squash_framebuffer) {
367 composition_planes_.emplace_back(
368 DrmCompositionPlane{TakePlane(crtc_, primary_planes, overlay_planes),
369 crtc_, DrmCompositionPlane::kSourceSquash});
372 return CreateAndAssignReleaseFences();
375 static const char *DrmCompositionTypeToString(DrmCompositionType type) {
377 case DRM_COMPOSITION_TYPE_EMPTY:
379 case DRM_COMPOSITION_TYPE_FRAME:
381 case DRM_COMPOSITION_TYPE_DPMS:
383 case DRM_COMPOSITION_TYPE_MODESET:
390 static const char *DPMSModeToString(int dpms_mode) {
392 case DRM_MODE_DPMS_ON:
394 case DRM_MODE_DPMS_OFF:
401 static void DumpBuffer(const DrmHwcBuffer &buffer, std::ostringstream *out) {
403 *out << "buffer=<invalid>";
407 *out << "buffer[w/h/format]=";
408 *out << buffer->width << "/" << buffer->height << "/" << buffer->format;
411 static const char *TransformToString(DrmHwcTransform transform) {
413 case DrmHwcTransform::kIdentity:
415 case DrmHwcTransform::kFlipH:
417 case DrmHwcTransform::kFlipV:
419 case DrmHwcTransform::kRotate90:
421 case DrmHwcTransform::kRotate180:
423 case DrmHwcTransform::kRotate270:
430 static const char *BlendingToString(DrmHwcBlending blending) {
432 case DrmHwcBlending::kNone:
434 case DrmHwcBlending::kPreMult:
436 case DrmHwcBlending::kCoverage:
443 static void DumpRegion(const DrmCompositionRegion ®ion,
444 std::ostringstream *out) {
446 region.frame.Dump(out);
447 *out << " source_layers=(";
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) {
460 void DrmDisplayComposition::Dump(std::ostringstream *out) const {
461 *out << "----DrmDisplayComposition"
462 << " crtc=" << (crtc_ ? crtc_->id() : -1)
463 << " type=" << DrmCompositionTypeToString(type_);
466 case DRM_COMPOSITION_TYPE_DPMS:
467 *out << " dpms_mode=" << DPMSModeToString(dpms_mode_);
469 case DRM_COMPOSITION_TYPE_MODESET:
470 *out << " display_mode=" << display_mode_.h_display() << "x"
471 << display_mode_.v_display();
477 *out << " timeline[current/squash/pre-comp/done]=" << timeline_current_ << "/"
478 << timeline_squash_done_ << "/" << timeline_pre_comp_done_ << "/"
479 << timeline_ << "\n";
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 << "] ";
486 DumpBuffer(layer.buffer, out);
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);
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)
504 if (comp_plane.source_layer <= DrmCompositionPlane::kSourceLayerMax) {
505 *out << comp_plane.source_layer;
507 switch (comp_plane.source_layer) {
508 case DrmCompositionPlane::kSourceNone:
511 case DrmCompositionPlane::kSourcePreComp:
514 case DrmCompositionPlane::kSourceSquash:
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);
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);