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