Home | History | Annotate | Download | only in drm_hwcomposer
      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 
     42 namespace android {
     43 
     44 void 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 &region = regions_.back();
     63     region.rect = out_region.rect;
     64     region.layer_refs = out_region.id_set.getBits();
     65   }
     66 }
     67 
     68 void 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 
     90 void 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 
     99 void 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 
    125 bool 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 
    144 void 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 &region = 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 
    172 static 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 
    179 DrmDisplayCompositor::FrameWorker::FrameWorker(DrmDisplayCompositor *compositor)
    180     : Worker("frame-worker", HAL_PRIORITY_URGENT_DISPLAY),
    181       compositor_(compositor) {
    182 }
    183 
    184 DrmDisplayCompositor::FrameWorker::~FrameWorker() {
    185 }
    186 
    187 int DrmDisplayCompositor::FrameWorker::Init() {
    188   return InitWorker();
    189 }
    190 
    191 void 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 
    212 void 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 
    246 DrmDisplayCompositor::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 
    264 DrmDisplayCompositor::~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 
    293 int 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 
    319 std::unique_ptr<DrmDisplayComposition> DrmDisplayCompositor::CreateComposition()
    320     const {
    321   return std::unique_ptr<DrmDisplayComposition>(new DrmDisplayComposition());
    322 }
    323 
    324 int 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 
    373 std::tuple<uint32_t, uint32_t, int>
    374 DrmDisplayCompositor::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 
    386 int 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 
    425 int 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> &regions = 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 
    457 int 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> &regions = 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 
    490 int 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 
    524 int 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 
    612 int 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 
    800 out:
    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 
    843 int 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 
    860 std::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 
    877 void 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 
    894 void 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 
    925 int 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 
   1020 bool 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 
   1038 int 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
   1063 int 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.
   1168 move_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 
   1182 void 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