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