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 ATRACE_TAG ATRACE_TAG_GRAPHICS
18 #define LOG_TAG "hwc-drm-display-compositor"
19
20 #include "drmdisplaycompositor.h"
21
22 #include <sched.h>
23 #include <stdlib.h>
24 #include <time.h>
25 #include <algorithm>
26 #include <bitset>
27 #include <cinttypes>
28 #include <mutex>
29 #include <sstream>
30 #include <vector>
31
32 #include <cutils/log.h>
33 #include <drm/drm_mode.h>
34 #include <sync/sync.h>
35 #include <utils/Trace.h>
36
37 #include "drmcrtc.h"
38 #include "drmplane.h"
39 #include "drmresources.h"
40 #include "glworker.h"
41
42 #define DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH 2
43
44 namespace android {
45
46 static const int64_t kSquashWait = 500LL;
47
Init(DrmHwcLayer * layers,size_t num_layers)48 void SquashState::Init(DrmHwcLayer *layers, size_t num_layers) {
49 generation_number_++;
50 valid_history_ = 0;
51 regions_.clear();
52 last_handles_.clear();
53
54 std::vector<DrmHwcRect<int>> in_rects;
55 for (size_t i = 0; i < num_layers; i++) {
56 DrmHwcLayer *layer = &layers[i];
57 in_rects.emplace_back(layer->display_frame);
58 last_handles_.push_back(layer->sf_handle);
59 }
60
61 std::vector<separate_rects::RectSet<uint64_t, int>> out_regions;
62 separate_rects::separate_rects_64(in_rects, &out_regions);
63
64 for (const separate_rects::RectSet<uint64_t, int> &out_region : out_regions) {
65 regions_.emplace_back();
66 Region ®ion = regions_.back();
67 region.rect = out_region.rect;
68 region.layer_refs = out_region.id_set.getBits();
69 }
70 }
71
GenerateHistory(DrmHwcLayer * layers,size_t num_layers,std::vector<bool> & changed_regions) const72 void SquashState::GenerateHistory(DrmHwcLayer *layers, size_t num_layers,
73 std::vector<bool> &changed_regions) const {
74 changed_regions.resize(regions_.size());
75 if (num_layers != last_handles_.size()) {
76 ALOGE("SquashState::GenerateHistory expected %zu layers but got %zu layers",
77 last_handles_.size(), num_layers);
78 return;
79 }
80 std::bitset<kMaxLayers> changed_layers;
81 for (size_t i = 0; i < last_handles_.size(); i++) {
82 DrmHwcLayer *layer = &layers[i];
83 // Protected layers can't be squashed so we treat them as constantly
84 // changing.
85 if (layer->protected_usage() || last_handles_[i] != layer->sf_handle)
86 changed_layers.set(i);
87 }
88
89 for (size_t i = 0; i < regions_.size(); i++) {
90 changed_regions[i] = (regions_[i].layer_refs & changed_layers).any();
91 }
92 }
93
StableRegionsWithMarginalHistory(const std::vector<bool> & changed_regions,std::vector<bool> & stable_regions) const94 void SquashState::StableRegionsWithMarginalHistory(
95 const std::vector<bool> &changed_regions,
96 std::vector<bool> &stable_regions) const {
97 stable_regions.resize(regions_.size());
98 for (size_t i = 0; i < regions_.size(); i++) {
99 stable_regions[i] = !changed_regions[i] && is_stable(i);
100 }
101 }
102
RecordHistory(DrmHwcLayer * layers,size_t num_layers,const std::vector<bool> & changed_regions)103 void SquashState::RecordHistory(DrmHwcLayer *layers, size_t num_layers,
104 const std::vector<bool> &changed_regions) {
105 if (num_layers != last_handles_.size()) {
106 ALOGE("SquashState::RecordHistory expected %zu layers but got %zu layers",
107 last_handles_.size(), num_layers);
108 return;
109 }
110 if (changed_regions.size() != regions_.size()) {
111 ALOGE("SquashState::RecordHistory expected %zu regions but got %zu regions",
112 regions_.size(), changed_regions.size());
113 return;
114 }
115
116 for (size_t i = 0; i < last_handles_.size(); i++) {
117 DrmHwcLayer *layer = &layers[i];
118 last_handles_[i] = layer->sf_handle;
119 }
120
121 for (size_t i = 0; i < regions_.size(); i++) {
122 regions_[i].change_history <<= 1;
123 regions_[i].change_history.set(/* LSB */ 0, changed_regions[i]);
124 }
125
126 valid_history_++;
127 }
128
RecordAndCompareSquashed(const std::vector<bool> & squashed_regions)129 bool SquashState::RecordAndCompareSquashed(
130 const std::vector<bool> &squashed_regions) {
131 if (squashed_regions.size() != regions_.size()) {
132 ALOGE(
133 "SquashState::RecordAndCompareSquashed expected %zu regions but got "
134 "%zu regions",
135 regions_.size(), squashed_regions.size());
136 return false;
137 }
138 bool changed = false;
139 for (size_t i = 0; i < regions_.size(); i++) {
140 if (regions_[i].squashed != squashed_regions[i]) {
141 regions_[i].squashed = squashed_regions[i];
142 changed = true;
143 }
144 }
145 return changed;
146 }
147
Dump(std::ostringstream * out) const148 void SquashState::Dump(std::ostringstream *out) const {
149 *out << "----SquashState generation=" << generation_number_
150 << " history=" << valid_history_ << "\n"
151 << " Regions: count=" << regions_.size() << "\n";
152 for (size_t i = 0; i < regions_.size(); i++) {
153 const Region ®ion = regions_[i];
154 *out << " [" << i << "]"
155 << " history=" << region.change_history << " rect";
156 region.rect.Dump(out);
157 *out << " layers=(";
158 bool first = true;
159 for (size_t layer_index = 0; layer_index < kMaxLayers; layer_index++) {
160 if ((region.layer_refs &
161 std::bitset<kMaxLayers>((size_t)1 << layer_index))
162 .any()) {
163 if (!first)
164 *out << " ";
165 first = false;
166 *out << layer_index;
167 }
168 }
169 *out << ")";
170 if (region.squashed)
171 *out << " squashed";
172 *out << "\n";
173 }
174 }
175
UsesSquash(const std::vector<DrmCompositionPlane> & comp_planes)176 static bool UsesSquash(const std::vector<DrmCompositionPlane> &comp_planes) {
177 return std::any_of(comp_planes.begin(), comp_planes.end(),
178 [](const DrmCompositionPlane &plane) {
179 return plane.type() == DrmCompositionPlane::Type::kSquash;
180 });
181 }
182
FrameWorker(DrmDisplayCompositor * compositor)183 DrmDisplayCompositor::FrameWorker::FrameWorker(DrmDisplayCompositor *compositor)
184 : QueueWorker("frame-worker", HAL_PRIORITY_URGENT_DISPLAY),
185 compositor_(compositor) {
186 }
187
Init()188 int DrmDisplayCompositor::FrameWorker::Init() {
189 set_max_queue_size(DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH);
190 return InitWorker();
191 }
192
QueueFrame(std::unique_ptr<DrmDisplayComposition> composition,int status)193 void DrmDisplayCompositor::FrameWorker::QueueFrame(
194 std::unique_ptr<DrmDisplayComposition> composition, int status) {
195 std::unique_ptr<FrameState> frame(
196 new FrameState(std::move(composition), status));
197
198 auto start = std::chrono::high_resolution_clock::now();
199 int ret = QueueWork(std::move(frame));
200 if (ret) {
201 ALOGE("Unable to queue frame work (%d)", ret);
202 // TODO: error handling (timeout or exit)
203 return;
204 }
205 auto end = std::chrono::high_resolution_clock::now();
206
207 uint64_t duration_us =
208 std::chrono::duration_cast<std::chrono::microseconds>(end - start)
209 .count();
210 if (duration_us > max_duration_us)
211 max_duration_us = duration_us;
212 }
213
ProcessWork(std::unique_ptr<FrameState> frame)214 void DrmDisplayCompositor::FrameWorker::ProcessWork(
215 std::unique_ptr<FrameState> frame) {
216 compositor_->ApplyFrame(std::move(frame->composition), frame->status);
217 }
218
DrmDisplayCompositor()219 DrmDisplayCompositor::DrmDisplayCompositor()
220 : QueueWorker("drm-compositor", HAL_PRIORITY_URGENT_DISPLAY),
221 drm_(NULL),
222 display_(-1),
223 frame_worker_(this),
224 active_(false),
225 use_hw_overlays_(true),
226 framebuffer_index_(0),
227 squash_framebuffer_index_(0),
228 dump_frames_composited_(0),
229 dump_last_timestamp_ns_(0),
230 max_duration_us(0) {
231 struct timespec ts;
232 if (clock_gettime(CLOCK_MONOTONIC, &ts))
233 return;
234 dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
235 }
236
~DrmDisplayCompositor()237 DrmDisplayCompositor::~DrmDisplayCompositor() {
238 if (!initialized())
239 return;
240
241 frame_worker_.Exit();
242 Exit();
243
244 std::lock_guard<std::mutex> lk(mutex_);
245
246 if (mode_.blob_id)
247 drm_->DestroyPropertyBlob(mode_.blob_id);
248 if (mode_.old_blob_id)
249 drm_->DestroyPropertyBlob(mode_.old_blob_id);
250
251 active_composition_.reset();
252 }
253
Init(DrmResources * drm,int display)254 int DrmDisplayCompositor::Init(DrmResources *drm, int display) {
255 drm_ = drm;
256 display_ = display;
257
258 frame_worker_.Init();
259
260 set_max_queue_size(DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH);
261 set_idle_timeout(kSquashWait);
262
263 return InitWorker();
264 }
265
CreateComposition() const266 std::unique_ptr<DrmDisplayComposition> DrmDisplayCompositor::CreateComposition()
267 const {
268 return std::unique_ptr<DrmDisplayComposition>(new DrmDisplayComposition());
269 }
270
QueueComposition(std::unique_ptr<DrmDisplayComposition> composition)271 int DrmDisplayCompositor::QueueComposition(
272 std::unique_ptr<DrmDisplayComposition> composition) {
273 switch (composition->type()) {
274 case DRM_COMPOSITION_TYPE_FRAME:
275 if (!active_)
276 return -ENODEV;
277 break;
278 case DRM_COMPOSITION_TYPE_DPMS:
279 /*
280 * Update the state as soon as we get it so we can start/stop queuing
281 * frames asap.
282 */
283 active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON);
284 break;
285 case DRM_COMPOSITION_TYPE_MODESET:
286 break;
287 case DRM_COMPOSITION_TYPE_EMPTY:
288 return 0;
289 default:
290 ALOGE("Unknown composition type %d/%d", composition->type(), display_);
291 return -ENOENT;
292 }
293
294 auto start = std::chrono::high_resolution_clock::now();
295
296 int ret = QueueWork(std::move(composition));
297 if (ret) {
298 ALOGE("Unable to queue work (%d)", ret);
299 // TODO: error handling (timeout or exit)
300 return ret;
301 }
302
303 auto end = std::chrono::high_resolution_clock::now();
304
305 uint64_t duration_us =
306 std::chrono::duration_cast<std::chrono::microseconds>(end - start)
307 .count();
308 if (duration_us > max_duration_us)
309 max_duration_us = duration_us;
310
311 return 0;
312 }
313
314 std::tuple<uint32_t, uint32_t, int>
GetActiveModeResolution()315 DrmDisplayCompositor::GetActiveModeResolution() {
316 DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
317 if (connector == NULL) {
318 ALOGE("Failed to determine display mode: no connector for display %d",
319 display_);
320 return std::make_tuple(0, 0, -ENODEV);
321 }
322
323 const DrmMode &mode = connector->active_mode();
324 return std::make_tuple(mode.h_display(), mode.v_display(), 0);
325 }
326
PrepareFramebuffer(DrmFramebuffer & fb,DrmDisplayComposition * display_comp)327 int DrmDisplayCompositor::PrepareFramebuffer(
328 DrmFramebuffer &fb, DrmDisplayComposition *display_comp) {
329 int ret = fb.WaitReleased(-1);
330 if (ret) {
331 ALOGE("Failed to wait for framebuffer release %d", ret);
332 return ret;
333 }
334 uint32_t width, height;
335 std::tie(width, height, ret) = GetActiveModeResolution();
336 if (ret) {
337 ALOGE(
338 "Failed to allocate framebuffer because the display resolution could "
339 "not be determined %d",
340 ret);
341 return ret;
342 }
343
344 fb.set_release_fence_fd(-1);
345 if (!fb.Allocate(width, height)) {
346 ALOGE("Failed to allocate framebuffer with size %dx%d", width, height);
347 return -ENOMEM;
348 }
349
350 display_comp->layers().emplace_back();
351 DrmHwcLayer &pre_comp_layer = display_comp->layers().back();
352 pre_comp_layer.sf_handle = fb.buffer()->handle;
353 pre_comp_layer.blending = DrmHwcBlending::kPreMult;
354 pre_comp_layer.source_crop = DrmHwcRect<float>(0, 0, width, height);
355 pre_comp_layer.display_frame = DrmHwcRect<int>(0, 0, width, height);
356 ret = pre_comp_layer.buffer.ImportBuffer(fb.buffer()->handle,
357 display_comp->importer());
358 if (ret) {
359 ALOGE("Failed to import framebuffer for display %d", ret);
360 return ret;
361 }
362
363 return ret;
364 }
365
ApplySquash(DrmDisplayComposition * display_comp)366 int DrmDisplayCompositor::ApplySquash(DrmDisplayComposition *display_comp) {
367 int ret = 0;
368
369 DrmFramebuffer &fb = squash_framebuffers_[squash_framebuffer_index_];
370 ret = PrepareFramebuffer(fb, display_comp);
371 if (ret) {
372 ALOGE("Failed to prepare framebuffer for squash %d", ret);
373 return ret;
374 }
375
376 std::vector<DrmCompositionRegion> ®ions = display_comp->squash_regions();
377 ret = pre_compositor_->Composite(display_comp->layers().data(),
378 regions.data(), regions.size(), fb.buffer());
379 pre_compositor_->Finish();
380
381 if (ret) {
382 ALOGE("Failed to squash layers");
383 return ret;
384 }
385
386 ret = display_comp->CreateNextTimelineFence();
387 if (ret <= 0) {
388 ALOGE("Failed to create squash framebuffer release fence %d", ret);
389 return ret;
390 }
391
392 fb.set_release_fence_fd(ret);
393 display_comp->SignalSquashDone();
394
395 return 0;
396 }
397
ApplyPreComposite(DrmDisplayComposition * display_comp)398 int DrmDisplayCompositor::ApplyPreComposite(
399 DrmDisplayComposition *display_comp) {
400 int ret = 0;
401
402 DrmFramebuffer &fb = framebuffers_[framebuffer_index_];
403 ret = PrepareFramebuffer(fb, display_comp);
404 if (ret) {
405 ALOGE("Failed to prepare framebuffer for pre-composite %d", ret);
406 return ret;
407 }
408
409 std::vector<DrmCompositionRegion> ®ions = display_comp->pre_comp_regions();
410 ret = pre_compositor_->Composite(display_comp->layers().data(),
411 regions.data(), regions.size(), fb.buffer());
412 pre_compositor_->Finish();
413
414 if (ret) {
415 ALOGE("Failed to pre-composite layers");
416 return ret;
417 }
418
419 ret = display_comp->CreateNextTimelineFence();
420 if (ret <= 0) {
421 ALOGE("Failed to create pre-composite framebuffer release fence %d", ret);
422 return ret;
423 }
424
425 fb.set_release_fence_fd(ret);
426 display_comp->SignalPreCompDone();
427
428 return 0;
429 }
430
DisablePlanes(DrmDisplayComposition * display_comp)431 int DrmDisplayCompositor::DisablePlanes(DrmDisplayComposition *display_comp) {
432 drmModeAtomicReqPtr pset = drmModeAtomicAlloc();
433 if (!pset) {
434 ALOGE("Failed to allocate property set");
435 return -ENOMEM;
436 }
437
438 int ret;
439 std::vector<DrmCompositionPlane> &comp_planes =
440 display_comp->composition_planes();
441 for (DrmCompositionPlane &comp_plane : comp_planes) {
442 DrmPlane *plane = comp_plane.plane();
443 ret = drmModeAtomicAddProperty(pset, plane->id(),
444 plane->crtc_property().id(), 0) < 0 ||
445 drmModeAtomicAddProperty(pset, plane->id(), plane->fb_property().id(),
446 0) < 0;
447 if (ret) {
448 ALOGE("Failed to add plane %d disable to pset", plane->id());
449 drmModeAtomicFree(pset);
450 return ret;
451 }
452 }
453
454 ret = drmModeAtomicCommit(drm_->fd(), pset, 0, drm_);
455 if (ret) {
456 ALOGE("Failed to commit pset ret=%d\n", ret);
457 drmModeAtomicFree(pset);
458 return ret;
459 }
460
461 drmModeAtomicFree(pset);
462 return 0;
463 }
464
PrepareFrame(DrmDisplayComposition * display_comp)465 int DrmDisplayCompositor::PrepareFrame(DrmDisplayComposition *display_comp) {
466 int ret = 0;
467
468 std::vector<DrmHwcLayer> &layers = display_comp->layers();
469 std::vector<DrmCompositionPlane> &comp_planes =
470 display_comp->composition_planes();
471 std::vector<DrmCompositionRegion> &squash_regions =
472 display_comp->squash_regions();
473 std::vector<DrmCompositionRegion> &pre_comp_regions =
474 display_comp->pre_comp_regions();
475
476 int squash_layer_index = -1;
477 if (squash_regions.size() > 0) {
478 squash_framebuffer_index_ = (squash_framebuffer_index_ + 1) % 2;
479 ret = ApplySquash(display_comp);
480 if (ret)
481 return ret;
482
483 squash_layer_index = layers.size() - 1;
484 } else {
485 if (UsesSquash(comp_planes)) {
486 DrmFramebuffer &fb = squash_framebuffers_[squash_framebuffer_index_];
487 layers.emplace_back();
488 squash_layer_index = layers.size() - 1;
489 DrmHwcLayer &squash_layer = layers.back();
490 ret = squash_layer.buffer.ImportBuffer(fb.buffer()->handle,
491 display_comp->importer());
492 if (ret) {
493 ALOGE("Failed to import old squashed framebuffer %d", ret);
494 return ret;
495 }
496 squash_layer.sf_handle = fb.buffer()->handle;
497 squash_layer.blending = DrmHwcBlending::kPreMult;
498 squash_layer.source_crop = DrmHwcRect<float>(
499 0, 0, squash_layer.buffer->width, squash_layer.buffer->height);
500 squash_layer.display_frame = DrmHwcRect<int>(
501 0, 0, squash_layer.buffer->width, squash_layer.buffer->height);
502 ret = display_comp->CreateNextTimelineFence();
503
504 if (ret <= 0) {
505 ALOGE("Failed to create squash framebuffer release fence %d", ret);
506 return ret;
507 }
508
509 fb.set_release_fence_fd(ret);
510 ret = 0;
511 }
512 }
513
514 bool do_pre_comp = pre_comp_regions.size() > 0;
515 int pre_comp_layer_index = -1;
516 if (do_pre_comp) {
517 ret = ApplyPreComposite(display_comp);
518 if (ret)
519 return ret;
520
521 pre_comp_layer_index = layers.size() - 1;
522 framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
523 }
524
525 for (DrmCompositionPlane &comp_plane : comp_planes) {
526 std::vector<size_t> &source_layers = comp_plane.source_layers();
527 switch (comp_plane.type()) {
528 case DrmCompositionPlane::Type::kSquash:
529 if (source_layers.size())
530 ALOGE("Squash source_layers is expected to be empty (%zu/%d)",
531 source_layers[0], squash_layer_index);
532 source_layers.push_back(squash_layer_index);
533 break;
534 case DrmCompositionPlane::Type::kPrecomp:
535 if (!do_pre_comp) {
536 ALOGE(
537 "Can not use pre composite framebuffer with no pre composite "
538 "regions");
539 return -EINVAL;
540 }
541 // Replace source_layers with the output of the precomposite
542 source_layers.clear();
543 source_layers.push_back(pre_comp_layer_index);
544 break;
545 default:
546 break;
547 }
548 }
549
550 return ret;
551 }
552
CommitFrame(DrmDisplayComposition * display_comp,bool test_only)553 int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp,
554 bool test_only) {
555 ATRACE_CALL();
556
557 int ret = 0;
558
559 std::vector<DrmHwcLayer> &layers = display_comp->layers();
560 std::vector<DrmCompositionPlane> &comp_planes =
561 display_comp->composition_planes();
562 std::vector<DrmCompositionRegion> &pre_comp_regions =
563 display_comp->pre_comp_regions();
564
565 DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
566 if (!connector) {
567 ALOGE("Could not locate connector for display %d", display_);
568 return -ENODEV;
569 }
570 DrmCrtc *crtc = drm_->GetCrtcForDisplay(display_);
571 if (!crtc) {
572 ALOGE("Could not locate crtc for display %d", display_);
573 return -ENODEV;
574 }
575
576 drmModeAtomicReqPtr pset = drmModeAtomicAlloc();
577 if (!pset) {
578 ALOGE("Failed to allocate property set");
579 return -ENOMEM;
580 }
581
582 if (mode_.needs_modeset) {
583 ret = drmModeAtomicAddProperty(pset, crtc->id(), crtc->mode_property().id(),
584 mode_.blob_id) < 0 ||
585 drmModeAtomicAddProperty(pset, connector->id(),
586 connector->crtc_id_property().id(),
587 crtc->id()) < 0;
588 if (ret) {
589 ALOGE("Failed to add blob %d to pset", mode_.blob_id);
590 drmModeAtomicFree(pset);
591 return ret;
592 }
593 }
594
595 for (DrmCompositionPlane &comp_plane : comp_planes) {
596 DrmPlane *plane = comp_plane.plane();
597 DrmCrtc *crtc = comp_plane.crtc();
598 std::vector<size_t> &source_layers = comp_plane.source_layers();
599
600 int fb_id = -1;
601 DrmHwcRect<int> display_frame;
602 DrmHwcRect<float> source_crop;
603 uint64_t rotation = 0;
604 uint64_t alpha = 0xFF;
605
606 if (comp_plane.type() != DrmCompositionPlane::Type::kDisable) {
607 if (source_layers.size() > 1) {
608 ALOGE("Can't handle more than one source layer sz=%zu type=%d",
609 source_layers.size(), comp_plane.type());
610 continue;
611 }
612
613 if (source_layers.empty() || source_layers.front() >= layers.size()) {
614 ALOGE("Source layer index %zu out of bounds %zu type=%d",
615 source_layers.front(), layers.size(), comp_plane.type());
616 break;
617 }
618 DrmHwcLayer &layer = layers[source_layers.front()];
619 if (!test_only && layer.acquire_fence.get() >= 0) {
620 int acquire_fence = layer.acquire_fence.get();
621 int total_fence_timeout = 0;
622 for (int i = 0; i < kAcquireWaitTries; ++i) {
623 int fence_timeout = kAcquireWaitTimeoutMs * (1 << i);
624 total_fence_timeout += fence_timeout;
625 ret = sync_wait(acquire_fence, fence_timeout);
626 if (ret)
627 ALOGW("Acquire fence %d wait %d failed (%d). Total time %d",
628 acquire_fence, i, ret, total_fence_timeout);
629 }
630 if (ret) {
631 ALOGE("Failed to wait for acquire %d/%d", acquire_fence, ret);
632 break;
633 }
634 layer.acquire_fence.Close();
635 }
636 if (!layer.buffer) {
637 ALOGE("Expected a valid framebuffer for pset");
638 break;
639 }
640 fb_id = layer.buffer->fb_id;
641 display_frame = layer.display_frame;
642 source_crop = layer.source_crop;
643 if (layer.blending == DrmHwcBlending::kPreMult)
644 alpha = layer.alpha;
645
646 rotation = 0;
647 if (layer.transform & DrmHwcTransform::kFlipH)
648 rotation |= 1 << DRM_REFLECT_X;
649 if (layer.transform & DrmHwcTransform::kFlipV)
650 rotation |= 1 << DRM_REFLECT_Y;
651 if (layer.transform & DrmHwcTransform::kRotate90)
652 rotation |= 1 << DRM_ROTATE_90;
653 else if (layer.transform & DrmHwcTransform::kRotate180)
654 rotation |= 1 << DRM_ROTATE_180;
655 else if (layer.transform & DrmHwcTransform::kRotate270)
656 rotation |= 1 << DRM_ROTATE_270;
657 }
658 // Disable the plane if there's no framebuffer
659 if (fb_id < 0) {
660 ret = drmModeAtomicAddProperty(pset, plane->id(),
661 plane->crtc_property().id(), 0) < 0 ||
662 drmModeAtomicAddProperty(pset, plane->id(),
663 plane->fb_property().id(), 0) < 0;
664 if (ret) {
665 ALOGE("Failed to add plane %d disable to pset", plane->id());
666 break;
667 }
668 continue;
669 }
670
671 // TODO: Once we have atomic test, this should fall back to GL
672 if (rotation && plane->rotation_property().id() == 0) {
673 ALOGE("Rotation is not supported on plane %d", plane->id());
674 ret = -EINVAL;
675 break;
676 }
677
678 // TODO: Once we have atomic test, this should fall back to GL
679 if (alpha != 0xFF && plane->alpha_property().id() == 0) {
680 ALOGE("Alpha is not supported on plane %d", plane->id());
681 ret = -EINVAL;
682 break;
683 }
684
685 ret = drmModeAtomicAddProperty(pset, plane->id(),
686 plane->crtc_property().id(), crtc->id()) < 0;
687 ret |= drmModeAtomicAddProperty(pset, plane->id(),
688 plane->fb_property().id(), fb_id) < 0;
689 ret |= drmModeAtomicAddProperty(pset, plane->id(),
690 plane->crtc_x_property().id(),
691 display_frame.left) < 0;
692 ret |= drmModeAtomicAddProperty(pset, plane->id(),
693 plane->crtc_y_property().id(),
694 display_frame.top) < 0;
695 ret |= drmModeAtomicAddProperty(
696 pset, plane->id(), plane->crtc_w_property().id(),
697 display_frame.right - display_frame.left) < 0;
698 ret |= drmModeAtomicAddProperty(
699 pset, plane->id(), plane->crtc_h_property().id(),
700 display_frame.bottom - display_frame.top) < 0;
701 ret |= drmModeAtomicAddProperty(pset, plane->id(),
702 plane->src_x_property().id(),
703 (int)(source_crop.left) << 16) < 0;
704 ret |= drmModeAtomicAddProperty(pset, plane->id(),
705 plane->src_y_property().id(),
706 (int)(source_crop.top) << 16) < 0;
707 ret |= drmModeAtomicAddProperty(
708 pset, plane->id(), plane->src_w_property().id(),
709 (int)(source_crop.right - source_crop.left) << 16) < 0;
710 ret |= drmModeAtomicAddProperty(
711 pset, plane->id(), plane->src_h_property().id(),
712 (int)(source_crop.bottom - source_crop.top) << 16) < 0;
713 if (ret) {
714 ALOGE("Failed to add plane %d to set", plane->id());
715 break;
716 }
717
718 if (plane->rotation_property().id()) {
719 ret = drmModeAtomicAddProperty(pset, plane->id(),
720 plane->rotation_property().id(),
721 rotation) < 0;
722 if (ret) {
723 ALOGE("Failed to add rotation property %d to plane %d",
724 plane->rotation_property().id(), plane->id());
725 break;
726 }
727 }
728
729 if (plane->alpha_property().id()) {
730 ret = drmModeAtomicAddProperty(pset, plane->id(),
731 plane->alpha_property().id(),
732 alpha) < 0;
733 if (ret) {
734 ALOGE("Failed to add alpha property %d to plane %d",
735 plane->alpha_property().id(), plane->id());
736 break;
737 }
738 }
739 }
740
741 out:
742 if (!ret) {
743 uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
744 if (test_only)
745 flags |= DRM_MODE_ATOMIC_TEST_ONLY;
746
747 ret = drmModeAtomicCommit(drm_->fd(), pset, flags, drm_);
748 if (ret) {
749 if (test_only)
750 ALOGI("Commit test pset failed ret=%d\n", ret);
751 else
752 ALOGE("Failed to commit pset ret=%d\n", ret);
753 drmModeAtomicFree(pset);
754 return ret;
755 }
756 }
757 if (pset)
758 drmModeAtomicFree(pset);
759
760 if (!test_only && mode_.needs_modeset) {
761 ret = drm_->DestroyPropertyBlob(mode_.old_blob_id);
762 if (ret) {
763 ALOGE("Failed to destroy old mode property blob %" PRIu32 "/%d",
764 mode_.old_blob_id, ret);
765 return ret;
766 }
767
768 /* TODO: Add dpms to the pset when the kernel supports it */
769 ret = ApplyDpms(display_comp);
770 if (ret) {
771 ALOGE("Failed to apply DPMS after modeset %d\n", ret);
772 return ret;
773 }
774
775 connector->set_active_mode(mode_.mode);
776 mode_.old_blob_id = mode_.blob_id;
777 mode_.blob_id = 0;
778 mode_.needs_modeset = false;
779 }
780
781 return ret;
782 }
783
ApplyDpms(DrmDisplayComposition * display_comp)784 int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
785 DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
786 if (!conn) {
787 ALOGE("Failed to get DrmConnector for display %d", display_);
788 return -ENODEV;
789 }
790
791 const DrmProperty &prop = conn->dpms_property();
792 int ret = drmModeConnectorSetProperty(drm_->fd(), conn->id(), prop.id(),
793 display_comp->dpms_mode());
794 if (ret) {
795 ALOGE("Failed to set DPMS property for connector %d", conn->id());
796 return ret;
797 }
798 return 0;
799 }
800
CreateModeBlob(const DrmMode & mode)801 std::tuple<int, uint32_t> DrmDisplayCompositor::CreateModeBlob(
802 const DrmMode &mode) {
803 struct drm_mode_modeinfo drm_mode;
804 memset(&drm_mode, 0, sizeof(drm_mode));
805 mode.ToDrmModeModeInfo(&drm_mode);
806
807 uint32_t id = 0;
808 int ret = drm_->CreatePropertyBlob(&drm_mode,
809 sizeof(struct drm_mode_modeinfo), &id);
810 if (ret) {
811 ALOGE("Failed to create mode property blob %d", ret);
812 return std::make_tuple(ret, 0);
813 }
814 ALOGE("Create blob_id %" PRIu32 "\n", id);
815 return std::make_tuple(ret, id);
816 }
817
ClearDisplay()818 void DrmDisplayCompositor::ClearDisplay() {
819 std::lock_guard<std::mutex> lk(mutex_);
820 if (!active_composition_)
821 return;
822
823 if (DisablePlanes(active_composition_.get()))
824 return;
825
826 active_composition_->SignalCompositionDone();
827
828 active_composition_.reset(NULL);
829 }
830
ApplyFrame(std::unique_ptr<DrmDisplayComposition> composition,int status)831 void DrmDisplayCompositor::ApplyFrame(
832 std::unique_ptr<DrmDisplayComposition> composition, int status) {
833 int ret = status;
834
835 if (!ret)
836 ret = CommitFrame(composition.get(), false);
837
838 if (ret) {
839 ALOGE("Composite failed for display %d", display_);
840 // Disable the hw used by the last active composition. This allows us to
841 // signal the release fences from that composition to avoid hanging.
842 ClearDisplay();
843 return;
844 }
845 ++dump_frames_composited_;
846
847 if (active_composition_)
848 active_composition_->SignalCompositionDone();
849
850 std::lock_guard<std::mutex> lk(mutex_);
851 active_composition_.swap(composition);
852 }
853
ProcessWork(std::unique_ptr<DrmDisplayComposition> composition)854 void DrmDisplayCompositor::ProcessWork(
855 std::unique_ptr<DrmDisplayComposition> composition) {
856 ATRACE_CALL();
857
858 if (!pre_compositor_) {
859 pre_compositor_.reset(new GLWorkerCompositor());
860 int ret = pre_compositor_->Init();
861 if (ret) {
862 ALOGE("Failed to initialize OpenGL compositor %d", ret);
863 return;
864 }
865 }
866
867 int ret;
868 switch (composition->type()) {
869 case DRM_COMPOSITION_TYPE_FRAME:
870 ret = PrepareFrame(composition.get());
871 if (ret) {
872 ALOGE("Failed to prepare frame for display %d", display_);
873 return;
874 }
875 if (composition->geometry_changed()) {
876 // Send the composition to the kernel to ensure we can commit it. This
877 // is just a test, it won't actually commit the frame. If rejected,
878 // squash the frame into one layer and use the squashed composition
879 ret = CommitFrame(composition.get(), true);
880 if (ret)
881 ALOGI("Commit test failed, squashing frame for display %d", display_);
882 use_hw_overlays_ = !ret;
883 }
884
885 // If use_hw_overlays_ is false, we can't use hardware to composite the
886 // frame. So squash all layers into a single composition and queue that
887 // instead.
888 if (!use_hw_overlays_) {
889 std::unique_ptr<DrmDisplayComposition> squashed = CreateComposition();
890 ret = SquashFrame(composition.get(), squashed.get());
891 if (!ret) {
892 composition = std::move(squashed);
893 } else {
894 ALOGE("Failed to squash frame for display %d", display_);
895 // Disable the hw used by the last active composition. This allows us
896 // to signal the release fences from that composition to avoid
897 // hanging.
898 ClearDisplay();
899 return;
900 }
901 }
902 frame_worker_.QueueFrame(std::move(composition), ret);
903 break;
904 case DRM_COMPOSITION_TYPE_DPMS:
905 ret = ApplyDpms(composition.get());
906 if (ret)
907 ALOGE("Failed to apply dpms for display %d", display_);
908 break;
909 case DRM_COMPOSITION_TYPE_MODESET:
910 mode_.mode = composition->display_mode();
911 if (mode_.blob_id)
912 drm_->DestroyPropertyBlob(mode_.blob_id);
913 std::tie(ret, mode_.blob_id) = CreateModeBlob(mode_.mode);
914 if (ret) {
915 ALOGE("Failed to create mode blob for display %d", display_);
916 return;
917 }
918 mode_.needs_modeset = true;
919 break;
920 default:
921 ALOGE("Unknown composition type %d", composition->type());
922 break;
923 }
924 }
925
SquashAll()926 int DrmDisplayCompositor::SquashAll() {
927 std::unique_lock<std::mutex> lk(mutex_);
928 int ret;
929
930 if (!active_composition_)
931 return 0;
932
933 std::unique_ptr<DrmDisplayComposition> comp = CreateComposition();
934 ret = SquashFrame(active_composition_.get(), comp.get());
935
936 // ApplyFrame needs the lock
937 lk.unlock();
938
939 if (!ret)
940 ApplyFrame(std::move(comp), 0);
941
942 return ret;
943 }
944
945 // Returns:
946 // - 0 if src is successfully squashed into dst
947 // - -EALREADY if the src is already squashed
948 // - Appropriate error if the squash fails
SquashFrame(DrmDisplayComposition * src,DrmDisplayComposition * dst)949 int DrmDisplayCompositor::SquashFrame(DrmDisplayComposition *src,
950 DrmDisplayComposition *dst) {
951 if (src->type() != DRM_COMPOSITION_TYPE_FRAME)
952 return -ENOTSUP;
953
954 std::vector<DrmCompositionPlane> &src_planes = src->composition_planes();
955 std::vector<DrmHwcLayer> &src_layers = src->layers();
956
957 // Make sure there is more than one layer to squash.
958 size_t src_planes_with_layer = std::count_if(
959 src_planes.begin(), src_planes.end(), [](DrmCompositionPlane &p) {
960 return p.type() != DrmCompositionPlane::Type::kDisable;
961 });
962 if (src_planes_with_layer <= 1)
963 return -EALREADY;
964
965 int pre_comp_layer_index;
966
967 int ret = dst->Init(drm_, src->crtc(), src->importer(), src->planner(),
968 src->frame_no());
969 if (ret) {
970 ALOGE("Failed to init squash all composition %d", ret);
971 return ret;
972 }
973
974 DrmCompositionPlane squashed_comp(DrmCompositionPlane::Type::kPrecomp, NULL,
975 src->crtc());
976 std::vector<DrmHwcLayer> dst_layers;
977 for (DrmCompositionPlane &comp_plane : src_planes) {
978 // Composition planes without DRM planes should never happen
979 if (comp_plane.plane() == NULL) {
980 ALOGE("Skipping squash all because of NULL plane");
981 ret = -EINVAL;
982 goto move_layers_back;
983 }
984
985 if (comp_plane.plane()->type() == DRM_PLANE_TYPE_PRIMARY)
986 squashed_comp.set_plane(comp_plane.plane());
987 else
988 dst->AddPlaneDisable(comp_plane.plane());
989
990 if (comp_plane.type() == DrmCompositionPlane::Type::kDisable)
991 continue;
992
993 for (auto i : comp_plane.source_layers()) {
994 DrmHwcLayer &layer = src_layers[i];
995
996 // Squashing protected layers is impossible.
997 if (layer.protected_usage()) {
998 ret = -ENOTSUP;
999 goto move_layers_back;
1000 }
1001
1002 // The OutputFds point to freed memory after hwc_set returns. They are
1003 // returned to the default to prevent DrmDisplayComposition::Plan from
1004 // filling the OutputFds.
1005 layer.release_fence = OutputFd();
1006 dst_layers.emplace_back(std::move(layer));
1007 squashed_comp.source_layers().push_back(
1008 squashed_comp.source_layers().size());
1009 }
1010 }
1011
1012 if (squashed_comp.plane() == NULL) {
1013 ALOGE("Primary plane not found for squash");
1014 ret = -ENOTSUP;
1015 goto move_layers_back;
1016 }
1017
1018 ret = dst->SetLayers(dst_layers.data(), dst_layers.size(), false);
1019 if (ret) {
1020 ALOGE("Failed to set layers for squash all composition %d", ret);
1021 goto move_layers_back;
1022 }
1023
1024 ret = dst->AddPlaneComposition(std::move(squashed_comp));
1025 if (ret) {
1026 ALOGE("Failed to add squashed plane composition %d", ret);
1027 goto move_layers_back;
1028 }
1029
1030 ret = dst->FinalizeComposition();
1031 if (ret) {
1032 ALOGE("Failed to plan for squash all composition %d", ret);
1033 goto move_layers_back;
1034 }
1035
1036 ret = ApplyPreComposite(dst);
1037 if (ret) {
1038 ALOGE("Failed to pre-composite for squash all composition %d", ret);
1039 goto move_layers_back;
1040 }
1041
1042 pre_comp_layer_index = dst->layers().size() - 1;
1043 framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
1044
1045 for (DrmCompositionPlane &plane : dst->composition_planes()) {
1046 if (plane.type() == DrmCompositionPlane::Type::kPrecomp) {
1047 // Replace source_layers with the output of the precomposite
1048 plane.source_layers().clear();
1049 plane.source_layers().push_back(pre_comp_layer_index);
1050 break;
1051 }
1052 }
1053
1054 return 0;
1055
1056 // TODO(zachr): think of a better way to transfer ownership back to the active
1057 // composition.
1058 move_layers_back:
1059 for (size_t plane_index = 0;
1060 plane_index < src_planes.size() && plane_index < dst_layers.size();) {
1061 if (src_planes[plane_index].source_layers().empty()) {
1062 plane_index++;
1063 continue;
1064 }
1065 for (auto i : src_planes[plane_index].source_layers())
1066 src_layers[i] = std::move(dst_layers[plane_index++]);
1067 }
1068
1069 return ret;
1070 }
1071
Dump(std::ostringstream * out) const1072 void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
1073 std::lock_guard<std::mutex> lk(mutex_);
1074 uint64_t num_frames = dump_frames_composited_;
1075 dump_frames_composited_ = 0;
1076
1077 struct timespec ts;
1078 int ret = clock_gettime(CLOCK_MONOTONIC, &ts);
1079 if (ret) {
1080 return;
1081 }
1082
1083 uint64_t cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
1084 uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
1085 float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f;
1086
1087 *out << "--DrmDisplayCompositor[" << display_
1088 << "]: num_frames=" << num_frames << " num_ms=" << num_ms
1089 << " fps=" << fps << "\n";
1090
1091 dump_last_timestamp_ns_ = cur_ts;
1092
1093 *out << "----Jank Stats: "
1094 << " compositor_max_q_wait_us=" << max_duration_us
1095 << " frameworker_max_q_wait_us=" << frame_worker_.max_duration_us
1096 << "\n";
1097
1098 max_duration_us = 0;
1099 frame_worker_.max_duration_us = 0;
1100
1101 if (active_composition_)
1102 active_composition_->Dump(out);
1103
1104 squash_state_.Dump(out);
1105 }
1106
ProcessIdle()1107 void DrmDisplayCompositor::ProcessIdle() {
1108 SquashAll();
1109 }
1110 }
1111