OSDN Git Service

drm_hwcomposer: reimplement Dump for DrmDisplayCompositor
[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 #include "drmcrtc.h"
22 #include "drmplane.h"
23 #include "drmresources.h"
24 #include "glworker.h"
25
26 #include <pthread.h>
27 #include <sched.h>
28 #include <sstream>
29 #include <stdlib.h>
30 #include <time.h>
31 #include <vector>
32
33 #include <drm/drm_mode.h>
34 #include <cutils/log.h>
35 #include <sync/sync.h>
36 #include <utils/Trace.h>
37
38 #define DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH 3
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<seperate_rects::RectSet<uint64_t, int>> out_regions;
56   seperate_rects::seperate_rects_64(in_rects, &out_regions);
57
58   for (const seperate_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,
67                                   std::vector<bool> &changed_regions) const {
68   std::bitset<kMaxLayers> changed_layers;
69   for (size_t i = 0; i < last_handles_.size(); i++) {
70     DrmHwcLayer *layer = &layers[i];
71     if (last_handles_[i] != layer->sf_handle) {
72       changed_layers.set(i);
73     }
74   }
75
76   changed_regions.resize(regions_.size());
77   for (size_t i = 0; i < regions_.size(); i++) {
78     changed_regions[i] = (regions_[i].layer_refs & changed_layers).any();
79   }
80 }
81
82 void SquashState::StableRegionsWithMarginalHistory(
83     const std::vector<bool> &changed_regions,
84     std::vector<bool> &stable_regions) const {
85   stable_regions.resize(regions_.size());
86   for (size_t i = 0; i < regions_.size(); i++) {
87     stable_regions[i] = !changed_regions[i] && is_stable(i);
88   }
89 }
90
91 void SquashState::RecordHistory(DrmHwcLayer *layers,
92                                 const std::vector<bool> &changed_regions) {
93   for (size_t i = 0; i < last_handles_.size(); i++) {
94     DrmHwcLayer *layer = &layers[i];
95     last_handles_[i] = layer->sf_handle;
96   }
97
98   for (size_t i = 0; i < regions_.size(); i++) {
99     regions_[i].change_history <<= 1;
100     regions_[i].change_history.set(/* LSB */ 0, changed_regions[i]);
101   }
102
103   valid_history_++;
104 }
105
106 void SquashState::RecordSquashed(const std::vector<bool> &squashed_regions) {
107   for (size_t i = 0; i < regions_.size(); i++) {
108     regions_[i].squashed = squashed_regions[i];
109   }
110 }
111
112 void SquashState::Dump(std::ostringstream *out) const {
113   *out << "----SquashState generation=" << generation_number_
114        << " history=" << valid_history_ << "\n"
115        << "    Regions: count=" << regions_.size() << "\n";
116   for (size_t i = 0; i < regions_.size(); i++) {
117     const Region &region = regions_[i];
118     *out << "      [" << i << "]"
119          << " history=" << region.change_history << " rect";
120     region.rect.Dump(out);
121     *out << " layers=(";
122     bool first = true;
123     for (size_t layer_index = 0; layer_index < kMaxLayers; layer_index++) {
124       if ((region.layer_refs &
125            std::bitset<kMaxLayers>((size_t)1 << layer_index))
126               .any()) {
127         if (!first)
128           *out << " ";
129         first = false;
130         *out << layer_index;
131       }
132     }
133     *out << ")";
134     if (region.squashed)
135       *out << " squashed";
136     *out << "\n";
137   }
138 }
139
140 DrmDisplayCompositor::DrmDisplayCompositor()
141     : drm_(NULL),
142       display_(-1),
143       worker_(this),
144       initialized_(false),
145       active_(false),
146       needs_modeset_(false),
147       framebuffer_index_(0),
148       dump_frames_composited_(0),
149       dump_last_timestamp_ns_(0) {
150   struct timespec ts;
151   if (clock_gettime(CLOCK_MONOTONIC, &ts))
152     return;
153   dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
154 }
155
156 DrmDisplayCompositor::~DrmDisplayCompositor() {
157   if (!initialized_)
158     return;
159
160   worker_.Exit();
161
162   int ret = pthread_mutex_lock(&lock_);
163   if (ret)
164     ALOGE("Failed to acquire compositor lock %d", ret);
165
166   while (!composite_queue_.empty()) {
167     composite_queue_.front().reset();
168     composite_queue_.pop();
169   }
170   active_composition_.reset();
171
172   ret = pthread_mutex_unlock(&lock_);
173   if (ret)
174     ALOGE("Failed to acquire compositor lock %d", ret);
175
176   pthread_mutex_destroy(&lock_);
177 }
178
179 int DrmDisplayCompositor::Init(DrmResources *drm, int display) {
180   drm_ = drm;
181   display_ = display;
182
183   int ret = pthread_mutex_init(&lock_, NULL);
184   if (ret) {
185     ALOGE("Failed to initialize drm compositor lock %d\n", ret);
186     return ret;
187   }
188   ret = worker_.Init();
189   if (ret) {
190     pthread_mutex_destroy(&lock_);
191     ALOGE("Failed to initialize compositor worker %d\n", ret);
192     return ret;
193   }
194
195   initialized_ = true;
196   return 0;
197 }
198
199 std::unique_ptr<DrmDisplayComposition> DrmDisplayCompositor::CreateComposition()
200     const {
201   return std::unique_ptr<DrmDisplayComposition>(new DrmDisplayComposition());
202 }
203
204 int DrmDisplayCompositor::QueueComposition(
205     std::unique_ptr<DrmDisplayComposition> composition) {
206   switch (composition->type()) {
207     case DRM_COMPOSITION_TYPE_FRAME:
208       if (!active_)
209         return -ENODEV;
210       break;
211     case DRM_COMPOSITION_TYPE_DPMS:
212       /*
213        * Update the state as soon as we get it so we can start/stop queuing
214        * frames asap.
215        */
216       active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON);
217       break;
218     case DRM_COMPOSITION_TYPE_MODESET:
219       break;
220     case DRM_COMPOSITION_TYPE_EMPTY:
221       return 0;
222     default:
223       ALOGE("Unknown composition type %d/%d", composition->type(), display_);
224       return -ENOENT;
225   }
226
227   int ret = pthread_mutex_lock(&lock_);
228   if (ret) {
229     ALOGE("Failed to acquire compositor lock %d", ret);
230     return ret;
231   }
232
233   // Block the queue if it gets too large. Otherwise, SurfaceFlinger will start
234   // to eat our buffer handles when we get about 1 second behind.
235   while (composite_queue_.size() >= DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH) {
236     pthread_mutex_unlock(&lock_);
237     sched_yield();
238     pthread_mutex_lock(&lock_);
239   }
240
241   composite_queue_.push(std::move(composition));
242
243   ret = pthread_mutex_unlock(&lock_);
244   if (ret) {
245     ALOGE("Failed to release compositor lock %d", ret);
246     return ret;
247   }
248
249   worker_.Signal();
250   return 0;
251 }
252
253 std::tuple<uint32_t, uint32_t, int>
254 DrmDisplayCompositor::GetActiveModeResolution() {
255   DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
256   if (connector == NULL) {
257     ALOGE("Failed to determine display mode: no connector for display %d",
258           display_);
259     return std::make_tuple(0, 0, -ENODEV);
260   }
261
262   const DrmMode &mode = connector->active_mode();
263   return std::make_tuple(mode.h_display(), mode.v_display(), 0);
264 }
265
266 int DrmDisplayCompositor::PrepareFramebuffer(
267     DrmFramebuffer &fb, DrmDisplayComposition *display_comp) {
268   int ret = fb.WaitReleased(-1);
269   if (ret) {
270     ALOGE("Failed to wait for framebuffer release %d", ret);
271     return ret;
272   }
273   uint32_t width, height;
274   std::tie(width, height, ret) = GetActiveModeResolution();
275   if (ret) {
276     ALOGE(
277         "Failed to allocate framebuffer because the display resolution could "
278         "not be determined %d",
279         ret);
280     return ret;
281   }
282
283   fb.set_release_fence_fd(-1);
284   if (!fb.Allocate(width, height)) {
285     ALOGE("Failed to allocate framebuffer with size %dx%d", width, height);
286     return -ENOMEM;
287   }
288
289   display_comp->layers().emplace_back();
290   DrmHwcLayer &pre_comp_layer = display_comp->layers().back();
291   pre_comp_layer.sf_handle = fb.buffer()->handle;
292   pre_comp_layer.source_crop = DrmHwcRect<float>(0, 0, width, height);
293   pre_comp_layer.display_frame = DrmHwcRect<int>(0, 0, width, height);
294   ret = pre_comp_layer.buffer.ImportBuffer(fb.buffer()->handle,
295                                            display_comp->importer());
296   if (ret) {
297     ALOGE("Failed to import framebuffer for display %d", ret);
298     return ret;
299   }
300
301   return ret;
302 }
303
304 int DrmDisplayCompositor::ApplyPreComposite(
305     DrmDisplayComposition *display_comp) {
306   int ret = 0;
307
308   DrmFramebuffer &fb = framebuffers_[framebuffer_index_];
309   ret = PrepareFramebuffer(fb, display_comp);
310   if (ret) {
311     ALOGE("Failed to prepare framebuffer for precomposite %d", ret);
312     return ret;
313   }
314
315   std::vector<DrmCompositionRegion> &regions = display_comp->pre_comp_regions();
316   ret = pre_compositor_->Composite(display_comp->layers().data(),
317                                    regions.data(), regions.size(), fb.buffer());
318   pre_compositor_->Finish();
319
320   if (ret) {
321     ALOGE("Failed to composite layers");
322     return ret;
323   }
324
325   ret = display_comp->CreateNextTimelineFence();
326   if (ret <= 0) {
327     ALOGE("Failed to create pre comp framebuffer release fence %d", ret);
328     return ret;
329   }
330
331   fb.set_release_fence_fd(ret);
332   display_comp->SignalPreCompDone();
333
334   return 0;
335 }
336
337 int DrmDisplayCompositor::DisablePlanes(DrmDisplayComposition *display_comp) {
338   drmModePropertySetPtr pset = drmModePropertySetAlloc();
339   if (!pset) {
340     ALOGE("Failed to allocate property set");
341     return -ENOMEM;
342   }
343
344   int ret;
345   std::vector<DrmCompositionPlane> &comp_planes =
346       display_comp->composition_planes();
347   for (DrmCompositionPlane &comp_plane : comp_planes) {
348     DrmPlane *plane = comp_plane.plane;
349     ret =
350         drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
351                               0) ||
352         drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(), 0);
353     if (ret) {
354       ALOGE("Failed to add plane %d disable to pset", plane->id());
355       drmModePropertySetFree(pset);
356       return ret;
357     }
358   }
359
360   ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset);
361   if (ret) {
362     ALOGE("Failed to commit pset ret=%d\n", ret);
363     drmModePropertySetFree(pset);
364     return ret;
365   }
366
367   drmModePropertySetFree(pset);
368   return 0;
369 }
370
371 int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
372   int ret = 0;
373
374   std::vector<DrmHwcLayer> &layers = display_comp->layers();
375   std::vector<DrmCompositionPlane> &comp_planes =
376       display_comp->composition_planes();
377   std::vector<DrmCompositionRegion> &pre_comp_regions =
378       display_comp->pre_comp_regions();
379
380   bool do_pre_comp = pre_comp_regions.size() > 0;
381   DrmFramebuffer *pre_comp_fb;
382   int pre_comp_layer_index = -1;
383
384   if (do_pre_comp) {
385     ret = ApplyPreComposite(display_comp);
386     if (ret)
387       return ret;
388
389     pre_comp_layer_index = layers.size() - 1;
390     framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
391   }
392
393   DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
394   if (!connector) {
395     ALOGE("Could not locate connector for display %d", display_);
396     return -ENODEV;
397   }
398   DrmCrtc *crtc = drm_->GetCrtcForDisplay(display_);
399   if (!crtc) {
400     ALOGE("Could not locate crtc for display %d", display_);
401     return -ENODEV;
402   }
403
404   drmModePropertySetPtr pset = drmModePropertySetAlloc();
405   if (!pset) {
406     ALOGE("Failed to allocate property set");
407     return -ENOMEM;
408   }
409
410   uint32_t blob_id = 0;
411   uint64_t old_blob_id;
412   if (needs_modeset_) {
413     DrmProperty old_mode;
414     ret = drm_->GetCrtcProperty(*crtc, crtc->mode_property().name().c_str(),
415                                 &old_mode);
416     if (ret) {
417       ALOGE("Failed to get old mode property from crtc %d", crtc->id());
418       drmModePropertySetFree(pset);
419       return ret;
420     }
421     ret = old_mode.value(&old_blob_id);
422     if (ret) {
423       ALOGE("Could not get old blob id value %d", ret);
424       drmModePropertySetFree(pset);
425       return ret;
426     }
427
428     struct drm_mode_modeinfo drm_mode;
429     memset(&drm_mode, 0, sizeof(drm_mode));
430     next_mode_.ToDrmModeModeInfo(&drm_mode);
431
432     ret = drm_->CreatePropertyBlob(&drm_mode, sizeof(struct drm_mode_modeinfo),
433                                    &blob_id);
434     if (ret) {
435       ALOGE("Failed to create mode property blob %d", ret);
436       drmModePropertySetFree(pset);
437       return ret;
438     }
439
440     ret = drmModePropertySetAdd(pset, crtc->id(), crtc->mode_property().id(),
441                                 blob_id) ||
442           drmModePropertySetAdd(pset, connector->id(),
443                                 connector->crtc_id_property().id(), crtc->id());
444     if (ret) {
445       ALOGE("Failed to add blob %d to pset", blob_id);
446       drmModePropertySetFree(pset);
447       drm_->DestroyPropertyBlob(blob_id);
448       return ret;
449     }
450   }
451
452   for (DrmCompositionPlane &comp_plane : comp_planes) {
453     DrmPlane *plane = comp_plane.plane;
454     DrmCrtc *crtc = comp_plane.crtc;
455
456     int fb_id = -1;
457     DrmHwcRect<int> display_frame;
458     DrmHwcRect<float> source_crop;
459     uint64_t rotation = 0;
460     switch (comp_plane.source_layer) {
461       case DrmCompositionPlane::kSourceNone:
462         break;
463       case DrmCompositionPlane::kSourcePreComp: {
464         if (!do_pre_comp) {
465           ALOGE(
466               "Can not use pre composite framebuffer with no pre composite "
467               "layers");
468           ret = -EINVAL;
469           goto out;
470         }
471         DrmHwcLayer &layer = layers[pre_comp_layer_index];
472         fb_id = layer.buffer->fb_id;
473         display_frame = layer.display_frame;
474         source_crop = layer.source_crop;
475       }
476       case DrmCompositionPlane::kSourceSquash:
477         break;
478       default: {
479         if (comp_plane.source_layer >= layers.size()) {
480           ALOGE("Source layer index %zu out of bounds %zu",
481                 comp_plane.source_layer, layers.size());
482           break;
483         }
484         DrmHwcLayer &layer = layers[comp_plane.source_layer];
485         if (layer.acquire_fence.get() >= 0) {
486           int acquire_fence = layer.acquire_fence.get();
487           for (int i = 0; i < kAcquireWaitTries; ++i) {
488             ret = sync_wait(acquire_fence, kAcquireWaitTimeoutMs);
489             if (ret)
490               ALOGW("Acquire fence %d wait %d failed (%d). Total time %d",
491                     acquire_fence, i, ret, (i + 1) * kAcquireWaitTimeoutMs);
492           }
493           if (ret) {
494             ALOGE("Failed to wait for acquire %d/%d", acquire_fence, ret);
495             break;
496           }
497           layer.acquire_fence.Close();
498         }
499         if (!layer.buffer) {
500           ALOGE("Expected a valid framebuffer for pset");
501           break;
502         }
503         fb_id = layer.buffer->fb_id;
504         display_frame = layer.display_frame;
505         source_crop = layer.source_crop;
506         switch (layer.transform) {
507           case DrmHwcTransform::kFlipH:
508             rotation = 1 << DRM_REFLECT_X;
509             break;
510           case DrmHwcTransform::kFlipV:
511             rotation = 1 << DRM_REFLECT_Y;
512             break;
513           case DrmHwcTransform::kRotate90:
514             rotation = 1 << DRM_ROTATE_90;
515             break;
516           case DrmHwcTransform::kRotate180:
517             rotation = 1 << DRM_ROTATE_180;
518             break;
519           case DrmHwcTransform::kRotate270:
520             rotation = 1 << DRM_ROTATE_270;
521             break;
522           case DrmHwcTransform::kIdentity:
523             rotation = 0;
524             break;
525           default:
526             ALOGE("Invalid transform value 0x%x given", layer.transform);
527             break;
528         }
529       }
530     }
531
532     // Disable the plane if there's no framebuffer
533     if (fb_id < 0) {
534       ret = drmModePropertySetAdd(pset, plane->id(),
535                                   plane->crtc_property().id(), 0) ||
536             drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
537                                   0);
538       if (ret) {
539         ALOGE("Failed to add plane %d disable to pset", plane->id());
540         break;
541       }
542       continue;
543     }
544
545     // TODO: Once we have atomic test, this should fall back to GL
546     if (rotation && plane->rotation_property().id() == 0) {
547       ALOGE("Rotation is not supported on plane %d", plane->id());
548       ret = -EINVAL;
549       break;
550     }
551
552     ret =
553         drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
554                               crtc->id()) ||
555         drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
556                               fb_id) ||
557         drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
558                               display_frame.left) ||
559         drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
560                               display_frame.top) ||
561         drmModePropertySetAdd(pset, plane->id(), plane->crtc_w_property().id(),
562                               display_frame.right - display_frame.left) ||
563         drmModePropertySetAdd(pset, plane->id(), plane->crtc_h_property().id(),
564                               display_frame.bottom - display_frame.top) ||
565         drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
566                               (int)(source_crop.left) << 16) ||
567         drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
568                               (int)(source_crop.top) << 16) ||
569         drmModePropertySetAdd(pset, plane->id(), plane->src_w_property().id(),
570                               (int)(source_crop.right - source_crop.left)
571                                   << 16) ||
572         drmModePropertySetAdd(pset, plane->id(), plane->src_h_property().id(),
573                               (int)(source_crop.bottom - source_crop.top)
574                                   << 16);
575     if (ret) {
576       ALOGE("Failed to add plane %d to set", plane->id());
577       break;
578     }
579
580     if (plane->rotation_property().id()) {
581       ret = drmModePropertySetAdd(pset, plane->id(),
582                                   plane->rotation_property().id(), rotation);
583       if (ret) {
584         ALOGE("Failed to add rotation property %d to plane %d",
585               plane->rotation_property().id(), plane->id());
586         break;
587       }
588     }
589   }
590
591 out:
592   if (!ret) {
593     ret = drmModePropertySetCommit(drm_->fd(), DRM_MODE_ATOMIC_ALLOW_MODESET,
594                                    drm_, pset);
595     if (ret) {
596       ALOGE("Failed to commit pset ret=%d\n", ret);
597       drmModePropertySetFree(pset);
598       if (needs_modeset_)
599         drm_->DestroyPropertyBlob(blob_id);
600       return ret;
601     }
602   }
603   if (pset)
604     drmModePropertySetFree(pset);
605
606   if (needs_modeset_) {
607     ret = drm_->DestroyPropertyBlob(old_blob_id);
608     if (ret) {
609       ALOGE("Failed to destroy old mode property blob %lld/%d", old_blob_id,
610             ret);
611       return ret;
612     }
613
614     /* TODO: Add dpms to the pset when the kernel supports it */
615     ret = ApplyDpms(display_comp);
616     if (ret) {
617       ALOGE("Failed to apply DPMS after modeset %d\n", ret);
618       return ret;
619     }
620
621     connector->set_active_mode(next_mode_);
622     needs_modeset_ = false;
623   }
624
625   return ret;
626 }
627
628 int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
629   DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
630   if (!conn) {
631     ALOGE("Failed to get DrmConnector for display %d", display_);
632     return -ENODEV;
633   }
634
635   const DrmProperty &prop = conn->dpms_property();
636   int ret = drmModeConnectorSetProperty(drm_->fd(), conn->id(), prop.id(),
637                                         display_comp->dpms_mode());
638   if (ret) {
639     ALOGE("Failed to set DPMS property for connector %d", conn->id());
640     return ret;
641   }
642   return 0;
643 }
644
645 int DrmDisplayCompositor::Composite() {
646   ATRACE_CALL();
647
648   if (!pre_compositor_) {
649     pre_compositor_.reset(new GLWorkerCompositor());
650     int ret = pre_compositor_->Init();
651     if (ret) {
652       ALOGE("Failed to initialize OpenGL compositor %d", ret);
653       return ret;
654     }
655   }
656
657   int ret = pthread_mutex_lock(&lock_);
658   if (ret) {
659     ALOGE("Failed to acquire compositor lock %d", ret);
660     return ret;
661   }
662   if (composite_queue_.empty()) {
663     ret = pthread_mutex_unlock(&lock_);
664     if (ret)
665       ALOGE("Failed to release compositor lock %d", ret);
666     return ret;
667   }
668
669   std::unique_ptr<DrmDisplayComposition> composition(
670       std::move(composite_queue_.front()));
671
672   composite_queue_.pop();
673
674   ret = pthread_mutex_unlock(&lock_);
675   if (ret) {
676     ALOGE("Failed to release compositor lock %d", ret);
677     return ret;
678   }
679
680   switch (composition->type()) {
681     case DRM_COMPOSITION_TYPE_FRAME:
682       ret = ApplyFrame(composition.get());
683       if (ret) {
684         ALOGE("Composite failed for display %d", display_);
685
686         // Disable the hw used by the last active composition. This allows us to
687         // signal the release fences from that composition to avoid hanging.
688         if (DisablePlanes(active_composition_.get()))
689           return ret;
690       }
691       ++dump_frames_composited_;
692       break;
693     case DRM_COMPOSITION_TYPE_DPMS:
694       ret = ApplyDpms(composition.get());
695       if (ret)
696         ALOGE("Failed to apply dpms for display %d", display_);
697       return ret;
698     case DRM_COMPOSITION_TYPE_MODESET:
699       next_mode_ = composition->display_mode();
700       needs_modeset_ = true;
701       return 0;
702     default:
703       ALOGE("Unknown composition type %d", composition->type());
704       return -EINVAL;
705   }
706
707   if (active_composition_)
708     active_composition_->SignalCompositionDone();
709
710   ret = pthread_mutex_lock(&lock_);
711   if (ret)
712     ALOGE("Failed to acquire lock for active_composition swap");
713
714   active_composition_.swap(composition);
715
716   if (!ret)
717     ret = pthread_mutex_unlock(&lock_);
718   if (ret)
719     ALOGE("Failed to release lock for active_composition swap");
720
721   return ret;
722 }
723
724 bool DrmDisplayCompositor::HaveQueuedComposites() const {
725   int ret = pthread_mutex_lock(&lock_);
726   if (ret) {
727     ALOGE("Failed to acquire compositor lock %d", ret);
728     return false;
729   }
730
731   bool empty_ret = !composite_queue_.empty();
732
733   ret = pthread_mutex_unlock(&lock_);
734   if (ret) {
735     ALOGE("Failed to release compositor lock %d", ret);
736     return false;
737   }
738
739   return empty_ret;
740 }
741
742 void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
743   int ret = pthread_mutex_lock(&lock_);
744   if (ret)
745     return;
746
747   uint64_t num_frames = dump_frames_composited_;
748   dump_frames_composited_ = 0;
749
750   struct timespec ts;
751   ret = clock_gettime(CLOCK_MONOTONIC, &ts);
752   if (ret) {
753     pthread_mutex_unlock(&lock_);
754     return;
755   }
756
757   uint64_t cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
758   uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
759   float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f;
760
761   *out << "--DrmDisplayCompositor[" << display_
762        << "]: num_frames=" << num_frames << " num_ms=" << num_ms
763        << " fps=" << fps << "\n";
764
765   dump_last_timestamp_ns_ = cur_ts;
766
767   if (active_composition_)
768     active_composition_->Dump(out);
769
770   pthread_mutex_unlock(&lock_);
771 }
772 }