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 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 72 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 94 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 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 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 148 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 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 183 DrmDisplayCompositor::FrameWorker::FrameWorker(DrmDisplayCompositor *compositor) 184 : QueueWorker("frame-worker", HAL_PRIORITY_URGENT_DISPLAY), 185 compositor_(compositor) { 186 } 187 188 int DrmDisplayCompositor::FrameWorker::Init() { 189 set_max_queue_size(DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH); 190 return InitWorker(); 191 } 192 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 214 void DrmDisplayCompositor::FrameWorker::ProcessWork( 215 std::unique_ptr<FrameState> frame) { 216 compositor_->ApplyFrame(std::move(frame->composition), frame->status); 217 } 218 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 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 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 266 std::unique_ptr<DrmDisplayComposition> DrmDisplayCompositor::CreateComposition() 267 const { 268 return std::unique_ptr<DrmDisplayComposition>(new DrmDisplayComposition()); 269 } 270 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> 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 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 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 display_comp->importer()); 380 pre_compositor_->Finish(); 381 382 if (ret) { 383 ALOGE("Failed to squash layers"); 384 return ret; 385 } 386 387 ret = display_comp->CreateNextTimelineFence(); 388 if (ret <= 0) { 389 ALOGE("Failed to create squash framebuffer release fence %d", ret); 390 return ret; 391 } 392 393 fb.set_release_fence_fd(ret); 394 display_comp->SignalSquashDone(); 395 396 return 0; 397 } 398 399 int DrmDisplayCompositor::ApplyPreComposite( 400 DrmDisplayComposition *display_comp) { 401 int ret = 0; 402 403 DrmFramebuffer &fb = framebuffers_[framebuffer_index_]; 404 ret = PrepareFramebuffer(fb, display_comp); 405 if (ret) { 406 ALOGE("Failed to prepare framebuffer for pre-composite %d", ret); 407 return ret; 408 } 409 410 std::vector<DrmCompositionRegion> ®ions = display_comp->pre_comp_regions(); 411 ret = pre_compositor_->Composite(display_comp->layers().data(), 412 regions.data(), regions.size(), fb.buffer(), 413 display_comp->importer()); 414 pre_compositor_->Finish(); 415 416 if (ret) { 417 ALOGE("Failed to pre-composite layers"); 418 return ret; 419 } 420 421 ret = display_comp->CreateNextTimelineFence(); 422 if (ret <= 0) { 423 ALOGE("Failed to create pre-composite framebuffer release fence %d", ret); 424 return ret; 425 } 426 427 fb.set_release_fence_fd(ret); 428 display_comp->SignalPreCompDone(); 429 430 return 0; 431 } 432 433 int DrmDisplayCompositor::DisablePlanes(DrmDisplayComposition *display_comp) { 434 drmModeAtomicReqPtr pset = drmModeAtomicAlloc(); 435 if (!pset) { 436 ALOGE("Failed to allocate property set"); 437 return -ENOMEM; 438 } 439 440 int ret; 441 std::vector<DrmCompositionPlane> &comp_planes = 442 display_comp->composition_planes(); 443 for (DrmCompositionPlane &comp_plane : comp_planes) { 444 DrmPlane *plane = comp_plane.plane(); 445 ret = drmModeAtomicAddProperty(pset, plane->id(), 446 plane->crtc_property().id(), 0) < 0 || 447 drmModeAtomicAddProperty(pset, plane->id(), plane->fb_property().id(), 448 0) < 0; 449 if (ret) { 450 ALOGE("Failed to add plane %d disable to pset", plane->id()); 451 drmModeAtomicFree(pset); 452 return ret; 453 } 454 } 455 456 ret = drmModeAtomicCommit(drm_->fd(), pset, 0, drm_); 457 if (ret) { 458 ALOGE("Failed to commit pset ret=%d\n", ret); 459 drmModeAtomicFree(pset); 460 return ret; 461 } 462 463 drmModeAtomicFree(pset); 464 return 0; 465 } 466 467 int DrmDisplayCompositor::PrepareFrame(DrmDisplayComposition *display_comp) { 468 int ret = 0; 469 470 std::vector<DrmHwcLayer> &layers = display_comp->layers(); 471 std::vector<DrmCompositionPlane> &comp_planes = 472 display_comp->composition_planes(); 473 std::vector<DrmCompositionRegion> &squash_regions = 474 display_comp->squash_regions(); 475 std::vector<DrmCompositionRegion> &pre_comp_regions = 476 display_comp->pre_comp_regions(); 477 478 int squash_layer_index = -1; 479 if (squash_regions.size() > 0) { 480 squash_framebuffer_index_ = (squash_framebuffer_index_ + 1) % 2; 481 ret = ApplySquash(display_comp); 482 if (ret) 483 return ret; 484 485 squash_layer_index = layers.size() - 1; 486 } else { 487 if (UsesSquash(comp_planes)) { 488 DrmFramebuffer &fb = squash_framebuffers_[squash_framebuffer_index_]; 489 layers.emplace_back(); 490 squash_layer_index = layers.size() - 1; 491 DrmHwcLayer &squash_layer = layers.back(); 492 ret = squash_layer.buffer.ImportBuffer(fb.buffer()->handle, 493 display_comp->importer()); 494 if (ret) { 495 ALOGE("Failed to import old squashed framebuffer %d", ret); 496 return ret; 497 } 498 squash_layer.sf_handle = fb.buffer()->handle; 499 squash_layer.blending = DrmHwcBlending::kPreMult; 500 squash_layer.source_crop = DrmHwcRect<float>( 501 0, 0, squash_layer.buffer->width, squash_layer.buffer->height); 502 squash_layer.display_frame = DrmHwcRect<int>( 503 0, 0, squash_layer.buffer->width, squash_layer.buffer->height); 504 ret = display_comp->CreateNextTimelineFence(); 505 506 if (ret <= 0) { 507 ALOGE("Failed to create squash framebuffer release fence %d", ret); 508 return ret; 509 } 510 511 fb.set_release_fence_fd(ret); 512 ret = 0; 513 } 514 } 515 516 bool do_pre_comp = pre_comp_regions.size() > 0; 517 int pre_comp_layer_index = -1; 518 if (do_pre_comp) { 519 ret = ApplyPreComposite(display_comp); 520 if (ret) 521 return ret; 522 523 pre_comp_layer_index = layers.size() - 1; 524 framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS; 525 } 526 527 for (DrmCompositionPlane &comp_plane : comp_planes) { 528 std::vector<size_t> &source_layers = comp_plane.source_layers(); 529 switch (comp_plane.type()) { 530 case DrmCompositionPlane::Type::kSquash: 531 if (source_layers.size()) 532 ALOGE("Squash source_layers is expected to be empty (%zu/%d)", 533 source_layers[0], squash_layer_index); 534 source_layers.push_back(squash_layer_index); 535 break; 536 case DrmCompositionPlane::Type::kPrecomp: 537 if (!do_pre_comp) { 538 ALOGE( 539 "Can not use pre composite framebuffer with no pre composite " 540 "regions"); 541 return -EINVAL; 542 } 543 // Replace source_layers with the output of the precomposite 544 source_layers.clear(); 545 source_layers.push_back(pre_comp_layer_index); 546 break; 547 default: 548 break; 549 } 550 } 551 552 return ret; 553 } 554 555 int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp, 556 bool test_only) { 557 ATRACE_CALL(); 558 559 int ret = 0; 560 561 std::vector<DrmHwcLayer> &layers = display_comp->layers(); 562 std::vector<DrmCompositionPlane> &comp_planes = 563 display_comp->composition_planes(); 564 std::vector<DrmCompositionRegion> &pre_comp_regions = 565 display_comp->pre_comp_regions(); 566 567 DrmConnector *connector = drm_->GetConnectorForDisplay(display_); 568 if (!connector) { 569 ALOGE("Could not locate connector for display %d", display_); 570 return -ENODEV; 571 } 572 DrmCrtc *crtc = drm_->GetCrtcForDisplay(display_); 573 if (!crtc) { 574 ALOGE("Could not locate crtc for display %d", display_); 575 return -ENODEV; 576 } 577 578 drmModeAtomicReqPtr pset = drmModeAtomicAlloc(); 579 if (!pset) { 580 ALOGE("Failed to allocate property set"); 581 return -ENOMEM; 582 } 583 584 if (mode_.needs_modeset) { 585 ret = drmModeAtomicAddProperty(pset, crtc->id(), crtc->mode_property().id(), 586 mode_.blob_id) < 0 || 587 drmModeAtomicAddProperty(pset, connector->id(), 588 connector->crtc_id_property().id(), 589 crtc->id()) < 0; 590 if (ret) { 591 ALOGE("Failed to add blob %d to pset", mode_.blob_id); 592 drmModeAtomicFree(pset); 593 return ret; 594 } 595 } 596 597 for (DrmCompositionPlane &comp_plane : comp_planes) { 598 DrmPlane *plane = comp_plane.plane(); 599 DrmCrtc *crtc = comp_plane.crtc(); 600 std::vector<size_t> &source_layers = comp_plane.source_layers(); 601 602 int fb_id = -1; 603 DrmHwcRect<int> display_frame; 604 DrmHwcRect<float> source_crop; 605 uint64_t rotation = 0; 606 uint64_t alpha = 0xFF; 607 608 if (comp_plane.type() != DrmCompositionPlane::Type::kDisable) { 609 if (source_layers.size() > 1) { 610 ALOGE("Can't handle more than one source layer sz=%zu type=%d", 611 source_layers.size(), comp_plane.type()); 612 continue; 613 } 614 615 if (source_layers.empty() || source_layers.front() >= layers.size()) { 616 ALOGE("Source layer index %zu out of bounds %zu type=%d", 617 source_layers.front(), layers.size(), comp_plane.type()); 618 break; 619 } 620 DrmHwcLayer &layer = layers[source_layers.front()]; 621 if (!test_only && layer.acquire_fence.get() >= 0) { 622 int acquire_fence = layer.acquire_fence.get(); 623 int total_fence_timeout = 0; 624 for (int i = 0; i < kAcquireWaitTries; ++i) { 625 int fence_timeout = kAcquireWaitTimeoutMs * (1 << i); 626 total_fence_timeout += fence_timeout; 627 ret = sync_wait(acquire_fence, fence_timeout); 628 if (ret) 629 ALOGW("Acquire fence %d wait %d failed (%d). Total time %d", 630 acquire_fence, i, ret, total_fence_timeout); 631 else 632 break; 633 } 634 if (ret) { 635 ALOGE("Failed to wait for acquire %d/%d", acquire_fence, ret); 636 break; 637 } 638 layer.acquire_fence.Close(); 639 } 640 if (!layer.buffer) { 641 ALOGE("Expected a valid framebuffer for pset"); 642 break; 643 } 644 fb_id = layer.buffer->fb_id; 645 display_frame = layer.display_frame; 646 source_crop = layer.source_crop; 647 if (layer.blending == DrmHwcBlending::kPreMult) 648 alpha = layer.alpha; 649 650 rotation = 0; 651 if (layer.transform & DrmHwcTransform::kFlipH) 652 rotation |= 1 << DRM_REFLECT_X; 653 if (layer.transform & DrmHwcTransform::kFlipV) 654 rotation |= 1 << DRM_REFLECT_Y; 655 if (layer.transform & DrmHwcTransform::kRotate90) 656 rotation |= 1 << DRM_ROTATE_90; 657 else if (layer.transform & DrmHwcTransform::kRotate180) 658 rotation |= 1 << DRM_ROTATE_180; 659 else if (layer.transform & DrmHwcTransform::kRotate270) 660 rotation |= 1 << DRM_ROTATE_270; 661 } 662 // Disable the plane if there's no framebuffer 663 if (fb_id < 0) { 664 ret = drmModeAtomicAddProperty(pset, plane->id(), 665 plane->crtc_property().id(), 0) < 0 || 666 drmModeAtomicAddProperty(pset, plane->id(), 667 plane->fb_property().id(), 0) < 0; 668 if (ret) { 669 ALOGE("Failed to add plane %d disable to pset", plane->id()); 670 break; 671 } 672 continue; 673 } 674 675 // TODO: Once we have atomic test, this should fall back to GL 676 if (rotation && plane->rotation_property().id() == 0) { 677 ALOGE("Rotation is not supported on plane %d", plane->id()); 678 ret = -EINVAL; 679 break; 680 } 681 682 // TODO: Once we have atomic test, this should fall back to GL 683 if (alpha != 0xFF && plane->alpha_property().id() == 0) { 684 ALOGE("Alpha is not supported on plane %d", plane->id()); 685 ret = -EINVAL; 686 break; 687 } 688 689 ret = drmModeAtomicAddProperty(pset, plane->id(), 690 plane->crtc_property().id(), crtc->id()) < 0; 691 ret |= drmModeAtomicAddProperty(pset, plane->id(), 692 plane->fb_property().id(), fb_id) < 0; 693 ret |= drmModeAtomicAddProperty(pset, plane->id(), 694 plane->crtc_x_property().id(), 695 display_frame.left) < 0; 696 ret |= drmModeAtomicAddProperty(pset, plane->id(), 697 plane->crtc_y_property().id(), 698 display_frame.top) < 0; 699 ret |= drmModeAtomicAddProperty( 700 pset, plane->id(), plane->crtc_w_property().id(), 701 display_frame.right - display_frame.left) < 0; 702 ret |= drmModeAtomicAddProperty( 703 pset, plane->id(), plane->crtc_h_property().id(), 704 display_frame.bottom - display_frame.top) < 0; 705 ret |= drmModeAtomicAddProperty(pset, plane->id(), 706 plane->src_x_property().id(), 707 (int)(source_crop.left) << 16) < 0; 708 ret |= drmModeAtomicAddProperty(pset, plane->id(), 709 plane->src_y_property().id(), 710 (int)(source_crop.top) << 16) < 0; 711 ret |= drmModeAtomicAddProperty( 712 pset, plane->id(), plane->src_w_property().id(), 713 (int)(source_crop.right - source_crop.left) << 16) < 0; 714 ret |= drmModeAtomicAddProperty( 715 pset, plane->id(), plane->src_h_property().id(), 716 (int)(source_crop.bottom - source_crop.top) << 16) < 0; 717 if (ret) { 718 ALOGE("Failed to add plane %d to set", plane->id()); 719 break; 720 } 721 722 if (plane->rotation_property().id()) { 723 ret = drmModeAtomicAddProperty(pset, plane->id(), 724 plane->rotation_property().id(), 725 rotation) < 0; 726 if (ret) { 727 ALOGE("Failed to add rotation property %d to plane %d", 728 plane->rotation_property().id(), plane->id()); 729 break; 730 } 731 } 732 733 if (plane->alpha_property().id()) { 734 ret = drmModeAtomicAddProperty(pset, plane->id(), 735 plane->alpha_property().id(), 736 alpha) < 0; 737 if (ret) { 738 ALOGE("Failed to add alpha property %d to plane %d", 739 plane->alpha_property().id(), plane->id()); 740 break; 741 } 742 } 743 } 744 745 out: 746 if (!ret) { 747 uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET; 748 if (test_only) 749 flags |= DRM_MODE_ATOMIC_TEST_ONLY; 750 751 ret = drmModeAtomicCommit(drm_->fd(), pset, flags, drm_); 752 if (ret) { 753 if (test_only) 754 ALOGI("Commit test pset failed ret=%d\n", ret); 755 else 756 ALOGE("Failed to commit pset ret=%d\n", ret); 757 drmModeAtomicFree(pset); 758 return ret; 759 } 760 } 761 if (pset) 762 drmModeAtomicFree(pset); 763 764 if (!test_only && mode_.needs_modeset) { 765 ret = drm_->DestroyPropertyBlob(mode_.old_blob_id); 766 if (ret) { 767 ALOGE("Failed to destroy old mode property blob %" PRIu32 "/%d", 768 mode_.old_blob_id, ret); 769 return ret; 770 } 771 772 /* TODO: Add dpms to the pset when the kernel supports it */ 773 ret = ApplyDpms(display_comp); 774 if (ret) { 775 ALOGE("Failed to apply DPMS after modeset %d\n", ret); 776 return ret; 777 } 778 779 connector->set_active_mode(mode_.mode); 780 mode_.old_blob_id = mode_.blob_id; 781 mode_.blob_id = 0; 782 mode_.needs_modeset = false; 783 } 784 785 return ret; 786 } 787 788 int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) { 789 DrmConnector *conn = drm_->GetConnectorForDisplay(display_); 790 if (!conn) { 791 ALOGE("Failed to get DrmConnector for display %d", display_); 792 return -ENODEV; 793 } 794 795 const DrmProperty &prop = conn->dpms_property(); 796 int ret = drmModeConnectorSetProperty(drm_->fd(), conn->id(), prop.id(), 797 display_comp->dpms_mode()); 798 if (ret) { 799 ALOGE("Failed to set DPMS property for connector %d", conn->id()); 800 return ret; 801 } 802 return 0; 803 } 804 805 std::tuple<int, uint32_t> DrmDisplayCompositor::CreateModeBlob( 806 const DrmMode &mode) { 807 struct drm_mode_modeinfo drm_mode; 808 memset(&drm_mode, 0, sizeof(drm_mode)); 809 mode.ToDrmModeModeInfo(&drm_mode); 810 811 uint32_t id = 0; 812 int ret = drm_->CreatePropertyBlob(&drm_mode, 813 sizeof(struct drm_mode_modeinfo), &id); 814 if (ret) { 815 ALOGE("Failed to create mode property blob %d", ret); 816 return std::make_tuple(ret, 0); 817 } 818 ALOGE("Create blob_id %" PRIu32 "\n", id); 819 return std::make_tuple(ret, id); 820 } 821 822 void DrmDisplayCompositor::ClearDisplay() { 823 std::lock_guard<std::mutex> lk(mutex_); 824 if (!active_composition_) 825 return; 826 827 if (DisablePlanes(active_composition_.get())) 828 return; 829 830 active_composition_->SignalCompositionDone(); 831 832 active_composition_.reset(NULL); 833 } 834 835 void DrmDisplayCompositor::ApplyFrame( 836 std::unique_ptr<DrmDisplayComposition> composition, int status) { 837 int ret = status; 838 839 if (!ret) 840 ret = CommitFrame(composition.get(), false); 841 842 if (ret) { 843 ALOGE("Composite failed for display %d", display_); 844 // Disable the hw used by the last active composition. This allows us to 845 // signal the release fences from that composition to avoid hanging. 846 ClearDisplay(); 847 return; 848 } 849 ++dump_frames_composited_; 850 851 if (active_composition_) 852 active_composition_->SignalCompositionDone(); 853 854 std::lock_guard<std::mutex> lk(mutex_); 855 active_composition_.swap(composition); 856 } 857 858 void DrmDisplayCompositor::ProcessWork( 859 std::unique_ptr<DrmDisplayComposition> composition) { 860 ATRACE_CALL(); 861 862 if (!pre_compositor_) { 863 pre_compositor_.reset(new GLWorkerCompositor()); 864 int ret = pre_compositor_->Init(); 865 if (ret) { 866 ALOGE("Failed to initialize OpenGL compositor %d", ret); 867 return; 868 } 869 } 870 871 int ret; 872 switch (composition->type()) { 873 case DRM_COMPOSITION_TYPE_FRAME: 874 ret = PrepareFrame(composition.get()); 875 if (ret) { 876 ALOGE("Failed to prepare frame for display %d", display_); 877 return; 878 } 879 if (composition->geometry_changed()) { 880 // Send the composition to the kernel to ensure we can commit it. This 881 // is just a test, it won't actually commit the frame. If rejected, 882 // squash the frame into one layer and use the squashed composition 883 ret = CommitFrame(composition.get(), true); 884 if (ret) 885 ALOGI("Commit test failed, squashing frame for display %d", display_); 886 use_hw_overlays_ = !ret; 887 } 888 889 // If use_hw_overlays_ is false, we can't use hardware to composite the 890 // frame. So squash all layers into a single composition and queue that 891 // instead. 892 if (!use_hw_overlays_) { 893 std::unique_ptr<DrmDisplayComposition> squashed = CreateComposition(); 894 ret = SquashFrame(composition.get(), squashed.get()); 895 if (!ret) { 896 composition = std::move(squashed); 897 } else { 898 ALOGE("Failed to squash frame for display %d", display_); 899 // Disable the hw used by the last active composition. This allows us 900 // to signal the release fences from that composition to avoid 901 // hanging. 902 ClearDisplay(); 903 return; 904 } 905 } 906 frame_worker_.QueueFrame(std::move(composition), ret); 907 break; 908 case DRM_COMPOSITION_TYPE_DPMS: 909 ret = ApplyDpms(composition.get()); 910 if (ret) 911 ALOGE("Failed to apply dpms for display %d", display_); 912 break; 913 case DRM_COMPOSITION_TYPE_MODESET: 914 mode_.mode = composition->display_mode(); 915 if (mode_.blob_id) 916 drm_->DestroyPropertyBlob(mode_.blob_id); 917 std::tie(ret, mode_.blob_id) = CreateModeBlob(mode_.mode); 918 if (ret) { 919 ALOGE("Failed to create mode blob for display %d", display_); 920 return; 921 } 922 mode_.needs_modeset = true; 923 break; 924 default: 925 ALOGE("Unknown composition type %d", composition->type()); 926 break; 927 } 928 } 929 930 int DrmDisplayCompositor::SquashAll() { 931 std::unique_lock<std::mutex> lk(mutex_); 932 int ret; 933 934 if (!active_composition_) 935 return 0; 936 937 std::unique_ptr<DrmDisplayComposition> comp = CreateComposition(); 938 ret = SquashFrame(active_composition_.get(), comp.get()); 939 940 // ApplyFrame needs the lock 941 lk.unlock(); 942 943 if (!ret) 944 ApplyFrame(std::move(comp), 0); 945 946 return ret; 947 } 948 949 // Returns: 950 // - 0 if src is successfully squashed into dst 951 // - -EALREADY if the src is already squashed 952 // - Appropriate error if the squash fails 953 int DrmDisplayCompositor::SquashFrame(DrmDisplayComposition *src, 954 DrmDisplayComposition *dst) { 955 if (src->type() != DRM_COMPOSITION_TYPE_FRAME) 956 return -ENOTSUP; 957 958 std::vector<DrmCompositionPlane> &src_planes = src->composition_planes(); 959 std::vector<DrmHwcLayer> &src_layers = src->layers(); 960 961 // Make sure there is more than one layer to squash. 962 size_t src_planes_with_layer = std::count_if( 963 src_planes.begin(), src_planes.end(), [](DrmCompositionPlane &p) { 964 return p.type() != DrmCompositionPlane::Type::kDisable; 965 }); 966 if (src_planes_with_layer <= 1) 967 return -EALREADY; 968 969 int pre_comp_layer_index; 970 971 int ret = dst->Init(drm_, src->crtc(), src->importer(), src->planner(), 972 src->frame_no()); 973 if (ret) { 974 ALOGE("Failed to init squash all composition %d", ret); 975 return ret; 976 } 977 978 DrmCompositionPlane squashed_comp(DrmCompositionPlane::Type::kPrecomp, NULL, 979 src->crtc()); 980 std::vector<DrmHwcLayer> dst_layers; 981 for (DrmCompositionPlane &comp_plane : src_planes) { 982 // Composition planes without DRM planes should never happen 983 if (comp_plane.plane() == NULL) { 984 ALOGE("Skipping squash all because of NULL plane"); 985 ret = -EINVAL; 986 goto move_layers_back; 987 } 988 989 if (comp_plane.plane()->type() == DRM_PLANE_TYPE_PRIMARY) 990 squashed_comp.set_plane(comp_plane.plane()); 991 else 992 dst->AddPlaneDisable(comp_plane.plane()); 993 994 if (comp_plane.type() == DrmCompositionPlane::Type::kDisable) 995 continue; 996 997 for (auto i : comp_plane.source_layers()) { 998 DrmHwcLayer &layer = src_layers[i]; 999 1000 // Squashing protected layers is impossible. 1001 if (layer.protected_usage()) { 1002 ret = -ENOTSUP; 1003 goto move_layers_back; 1004 } 1005 1006 // The OutputFds point to freed memory after hwc_set returns. They are 1007 // returned to the default to prevent DrmDisplayComposition::Plan from 1008 // filling the OutputFds. 1009 layer.release_fence = OutputFd(); 1010 dst_layers.emplace_back(std::move(layer)); 1011 squashed_comp.source_layers().push_back( 1012 squashed_comp.source_layers().size()); 1013 } 1014 } 1015 1016 if (squashed_comp.plane() == NULL) { 1017 ALOGE("Primary plane not found for squash"); 1018 ret = -ENOTSUP; 1019 goto move_layers_back; 1020 } 1021 1022 ret = dst->SetLayers(dst_layers.data(), dst_layers.size(), false); 1023 if (ret) { 1024 ALOGE("Failed to set layers for squash all composition %d", ret); 1025 goto move_layers_back; 1026 } 1027 1028 ret = dst->AddPlaneComposition(std::move(squashed_comp)); 1029 if (ret) { 1030 ALOGE("Failed to add squashed plane composition %d", ret); 1031 goto move_layers_back; 1032 } 1033 1034 ret = dst->FinalizeComposition(); 1035 if (ret) { 1036 ALOGE("Failed to plan for squash all composition %d", ret); 1037 goto move_layers_back; 1038 } 1039 1040 ret = ApplyPreComposite(dst); 1041 if (ret) { 1042 ALOGE("Failed to pre-composite for squash all composition %d", ret); 1043 goto move_layers_back; 1044 } 1045 1046 pre_comp_layer_index = dst->layers().size() - 1; 1047 framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS; 1048 1049 for (DrmCompositionPlane &plane : dst->composition_planes()) { 1050 if (plane.type() == DrmCompositionPlane::Type::kPrecomp) { 1051 // Replace source_layers with the output of the precomposite 1052 plane.source_layers().clear(); 1053 plane.source_layers().push_back(pre_comp_layer_index); 1054 break; 1055 } 1056 } 1057 1058 return 0; 1059 1060 // TODO(zachr): think of a better way to transfer ownership back to the active 1061 // composition. 1062 move_layers_back: 1063 for (size_t plane_index = 0; 1064 plane_index < src_planes.size() && plane_index < dst_layers.size();) { 1065 if (src_planes[plane_index].source_layers().empty()) { 1066 plane_index++; 1067 continue; 1068 } 1069 for (auto i : src_planes[plane_index].source_layers()) 1070 src_layers[i] = std::move(dst_layers[plane_index++]); 1071 } 1072 1073 return ret; 1074 } 1075 1076 void DrmDisplayCompositor::Dump(std::ostringstream *out) const { 1077 std::lock_guard<std::mutex> lk(mutex_); 1078 uint64_t num_frames = dump_frames_composited_; 1079 dump_frames_composited_ = 0; 1080 1081 struct timespec ts; 1082 int ret = clock_gettime(CLOCK_MONOTONIC, &ts); 1083 if (ret) { 1084 return; 1085 } 1086 1087 uint64_t cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; 1088 uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000); 1089 float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f; 1090 1091 *out << "--DrmDisplayCompositor[" << display_ 1092 << "]: num_frames=" << num_frames << " num_ms=" << num_ms 1093 << " fps=" << fps << "\n"; 1094 1095 dump_last_timestamp_ns_ = cur_ts; 1096 1097 *out << "----Jank Stats: " 1098 << " compositor_max_q_wait_us=" << max_duration_us 1099 << " frameworker_max_q_wait_us=" << frame_worker_.max_duration_us 1100 << "\n"; 1101 1102 max_duration_us = 0; 1103 frame_worker_.max_duration_us = 0; 1104 1105 if (active_composition_) 1106 active_composition_->Dump(out); 1107 1108 squash_state_.Dump(out); 1109 } 1110 1111 void DrmDisplayCompositor::ProcessIdle() { 1112 SquashAll(); 1113 } 1114 } 1115