OSDN Git Service

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