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 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 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 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 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 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 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 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 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 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 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 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 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.type() == DrmCompositionPlane::Type::kDisable) { 986 dst->AddPlaneDisable(comp_plane.plane()); 987 continue; 988 } 989 990 for (auto i : comp_plane.source_layers()) { 991 DrmHwcLayer &layer = src_layers[i]; 992 993 // Squashing protected layers is impossible. 994 if (layer.protected_usage()) { 995 ret = -ENOTSUP; 996 goto move_layers_back; 997 } 998 999 // The OutputFds point to freed memory after hwc_set returns. They are 1000 // returned to the default to prevent DrmDisplayComposition::Plan from 1001 // filling the OutputFds. 1002 layer.release_fence = OutputFd(); 1003 dst_layers.emplace_back(std::move(layer)); 1004 squashed_comp.source_layers().push_back( 1005 squashed_comp.source_layers().size()); 1006 } 1007 1008 if (comp_plane.plane()->type() == DRM_PLANE_TYPE_PRIMARY) 1009 squashed_comp.set_plane(comp_plane.plane()); 1010 else 1011 dst->AddPlaneDisable(comp_plane.plane()); 1012 } 1013 1014 ret = dst->SetLayers(dst_layers.data(), dst_layers.size(), false); 1015 if (ret) { 1016 ALOGE("Failed to set layers for squash all composition %d", ret); 1017 goto move_layers_back; 1018 } 1019 1020 ret = dst->AddPlaneComposition(std::move(squashed_comp)); 1021 if (ret) { 1022 ALOGE("Failed to add squashed plane composition %d", ret); 1023 goto move_layers_back; 1024 } 1025 1026 ret = dst->FinalizeComposition(); 1027 if (ret) { 1028 ALOGE("Failed to plan for squash all composition %d", ret); 1029 goto move_layers_back; 1030 } 1031 1032 ret = ApplyPreComposite(dst); 1033 if (ret) { 1034 ALOGE("Failed to pre-composite for squash all composition %d", ret); 1035 goto move_layers_back; 1036 } 1037 1038 pre_comp_layer_index = dst->layers().size() - 1; 1039 framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS; 1040 1041 for (DrmCompositionPlane &plane : dst->composition_planes()) { 1042 if (plane.type() == DrmCompositionPlane::Type::kPrecomp) { 1043 // Replace source_layers with the output of the precomposite 1044 plane.source_layers().clear(); 1045 plane.source_layers().push_back(pre_comp_layer_index); 1046 break; 1047 } 1048 } 1049 1050 return 0; 1051 1052 // TODO(zachr): think of a better way to transfer ownership back to the active 1053 // composition. 1054 move_layers_back: 1055 for (size_t plane_index = 0; 1056 plane_index < src_planes.size() && plane_index < dst_layers.size();) { 1057 if (src_planes[plane_index].source_layers().empty()) { 1058 plane_index++; 1059 continue; 1060 } 1061 for (auto i : src_planes[plane_index].source_layers()) 1062 src_layers[i] = std::move(dst_layers[plane_index++]); 1063 } 1064 1065 return ret; 1066 } 1067 1068 void DrmDisplayCompositor::Dump(std::ostringstream *out) const { 1069 std::lock_guard<std::mutex> lk(mutex_); 1070 uint64_t num_frames = dump_frames_composited_; 1071 dump_frames_composited_ = 0; 1072 1073 struct timespec ts; 1074 int ret = clock_gettime(CLOCK_MONOTONIC, &ts); 1075 if (ret) { 1076 return; 1077 } 1078 1079 uint64_t cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; 1080 uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000); 1081 float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f; 1082 1083 *out << "--DrmDisplayCompositor[" << display_ 1084 << "]: num_frames=" << num_frames << " num_ms=" << num_ms 1085 << " fps=" << fps << "\n"; 1086 1087 dump_last_timestamp_ns_ = cur_ts; 1088 1089 *out << "----Jank Stats: " 1090 << " compositor_max_q_wait_us=" << max_duration_us 1091 << " frameworker_max_q_wait_us=" << frame_worker_.max_duration_us 1092 << "\n"; 1093 1094 max_duration_us = 0; 1095 frame_worker_.max_duration_us = 0; 1096 1097 if (active_composition_) 1098 active_composition_->Dump(out); 1099 1100 squash_state_.Dump(out); 1101 } 1102 1103 void DrmDisplayCompositor::ProcessIdle() { 1104 SquashAll(); 1105 } 1106 } 1107