OSDN Git Service

3b3deef7a3329cf08177b410aff697317ebca96f
[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 <algorithm>
27 #include <pthread.h>
28 #include <sched.h>
29 #include <sstream>
30 #include <stdlib.h>
31 #include <time.h>
32 #include <vector>
33
34 #include <drm/drm_mode.h>
35 #include <cutils/log.h>
36 #include <sync/sync.h>
37 #include <utils/Trace.h>
38
39 #define DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH 3
40
41 namespace android {
42
43 DrmDisplayCompositor::DrmDisplayCompositor()
44     : drm_(NULL),
45       display_(-1),
46       worker_(this),
47       initialized_(false),
48       active_(false),
49       needs_modeset_(false),
50       framebuffer_index_(0),
51       dump_frames_composited_(0),
52       dump_last_timestamp_ns_(0) {
53   struct timespec ts;
54   if (clock_gettime(CLOCK_MONOTONIC, &ts))
55     return;
56   dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
57 }
58
59 DrmDisplayCompositor::~DrmDisplayCompositor() {
60   if (!initialized_)
61     return;
62
63   worker_.Exit();
64
65   int ret = pthread_mutex_lock(&lock_);
66   if (ret)
67     ALOGE("Failed to acquire compositor lock %d", ret);
68
69   while (!composite_queue_.empty()) {
70     composite_queue_.front().reset();
71     composite_queue_.pop();
72   }
73   active_composition_.reset();
74
75   ret = pthread_mutex_unlock(&lock_);
76   if (ret)
77     ALOGE("Failed to acquire compositor lock %d", ret);
78
79   pthread_mutex_destroy(&lock_);
80 }
81
82 int DrmDisplayCompositor::Init(DrmResources *drm, int display) {
83   drm_ = drm;
84   display_ = display;
85
86   int ret = pthread_mutex_init(&lock_, NULL);
87   if (ret) {
88     ALOGE("Failed to initialize drm compositor lock %d\n", ret);
89     return ret;
90   }
91   ret = worker_.Init();
92   if (ret) {
93     pthread_mutex_destroy(&lock_);
94     ALOGE("Failed to initialize compositor worker %d\n", ret);
95     return ret;
96   }
97
98   initialized_ = true;
99   return 0;
100 }
101
102 int DrmDisplayCompositor::QueueComposition(
103     std::unique_ptr<DrmDisplayComposition> composition) {
104   switch (composition->type()) {
105     case DRM_COMPOSITION_TYPE_FRAME:
106       if (!active_)
107         return -ENODEV;
108       break;
109     case DRM_COMPOSITION_TYPE_DPMS:
110       /*
111        * Update the state as soon as we get it so we can start/stop queuing
112        * frames asap.
113        */
114       active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON);
115       break;
116     case DRM_COMPOSITION_TYPE_MODESET:
117       break;
118     case DRM_COMPOSITION_TYPE_EMPTY:
119       return 0;
120     default:
121       ALOGE("Unknown composition type %d/%d", composition->type(), display_);
122       return -ENOENT;
123   }
124
125   int ret = pthread_mutex_lock(&lock_);
126   if (ret) {
127     ALOGE("Failed to acquire compositor lock %d", ret);
128     return ret;
129   }
130
131   // Block the queue if it gets too large. Otherwise, SurfaceFlinger will start
132   // to eat our buffer handles when we get about 1 second behind.
133   while (composite_queue_.size() >= DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH) {
134     pthread_mutex_unlock(&lock_);
135     sched_yield();
136     pthread_mutex_lock(&lock_);
137   }
138
139   composite_queue_.push(std::move(composition));
140
141   ret = pthread_mutex_unlock(&lock_);
142   if (ret) {
143     ALOGE("Failed to release compositor lock %d", ret);
144     return ret;
145   }
146
147   worker_.Signal();
148   return 0;
149 }
150
151 static bool drm_composition_layer_has_plane(
152     const DrmCompositionLayer &comp_layer) {
153   if (comp_layer.plane != NULL)
154     if (comp_layer.plane->type() == DRM_PLANE_TYPE_OVERLAY ||
155         comp_layer.plane->type() == DRM_PLANE_TYPE_PRIMARY)
156       return true;
157   return false;
158 }
159
160 static bool drm_composition_layer_has_no_plane(
161     const DrmCompositionLayer &comp_layer) {
162   return comp_layer.plane == NULL;
163 }
164
165 int DrmDisplayCompositor::ApplyPreComposite(
166     DrmDisplayComposition *display_comp) {
167   int ret = 0;
168   std::vector<DrmCompositionLayer> *layers =
169       display_comp->GetCompositionLayers();
170
171   DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
172   if (connector == NULL) {
173     ALOGE("Failed to determine display mode: no connector for display %d",
174           display_);
175     return -ENODEV;
176   }
177
178   const DrmMode &mode = connector->active_mode();
179   DrmFramebuffer &fb = framebuffers_[framebuffer_index_];
180   ret = fb.WaitReleased(fb.kReleaseWaitTimeoutMs);
181   if (ret) {
182     ALOGE("Failed to wait for framebuffer release %d", ret);
183     return ret;
184   }
185   fb.set_release_fence_fd(-1);
186   if (!fb.Allocate(mode.h_display(), mode.v_display())) {
187     ALOGE("Failed to allocate framebuffer with size %dx%d", mode.h_display(),
188           mode.v_display());
189     return -ENOMEM;
190   }
191
192   std::vector<DrmCompositionLayer> pre_comp_layers;
193   for (auto &comp_layer : *layers) {
194     if (comp_layer.plane == NULL) {
195       pre_comp_layers.emplace_back(std::move(comp_layer));
196     }
197   }
198
199   ret = pre_compositor_->Composite(pre_comp_layers.data(),
200                                    pre_comp_layers.size(), fb.buffer());
201   pre_compositor_->Finish();
202
203   if (ret) {
204     ALOGE("Failed to composite layers");
205     return ret;
206   }
207
208   DrmCompositionLayer &pre_comp_layer =
209       layers->at(display_comp->pre_composition_layer_index());
210   ret = pre_comp_layer.buffer.ImportBuffer(fb.buffer()->handle,
211                                            display_comp->importer());
212   if (ret) {
213     ALOGE("Failed to import handle of layer %d", ret);
214     return ret;
215   }
216   pre_comp_layer.source_crop = DrmHwcRect<float>(0, 0, fb.buffer()->getWidth(),
217                                                  fb.buffer()->getHeight());
218   pre_comp_layer.display_frame =
219       DrmHwcRect<int>(0, 0, fb.buffer()->getWidth(), fb.buffer()->getHeight());
220
221   // TODO(zachr) get a release fence
222   // fb.set_release_fence_fd(pre_comp_layer.release_fence.Release());
223   framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
224
225   display_comp->RemoveNoPlaneLayers();
226   display_comp->SignalPreCompositionDone();
227   return ret;
228 }
229
230 int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
231   int ret = 0;
232
233   if (display_comp->pre_composition_layer_index() >= 0) {
234     ret = ApplyPreComposite(display_comp);
235     if (ret)
236       return ret;
237   }
238
239   DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
240   if (!connector) {
241     ALOGE("Could not locate connector for display %d", display_);
242     return -ENODEV;
243   }
244   DrmCrtc *crtc = drm_->GetCrtcForDisplay(display_);
245   if (!crtc) {
246     ALOGE("Could not locate crtc for display %d", display_);
247     return -ENODEV;
248   }
249
250   drmModePropertySetPtr pset = drmModePropertySetAlloc();
251   if (!pset) {
252     ALOGE("Failed to allocate property set");
253     return -ENOMEM;
254   }
255
256   uint32_t blob_id = 0;
257   uint64_t old_blob_id;
258   if (needs_modeset_) {
259     DrmProperty old_mode;
260     ret = drm_->GetCrtcProperty(*crtc, crtc->mode_property().name().c_str(),
261                                 &old_mode);
262     if (ret) {
263       ALOGE("Failed to get old mode property from crtc %d", crtc->id());
264       drmModePropertySetFree(pset);
265       return ret;
266     }
267     ret = old_mode.value(&old_blob_id);
268     if (ret) {
269       ALOGE("Could not get old blob id value %d", ret);
270       drmModePropertySetFree(pset);
271       return ret;
272     }
273
274     struct drm_mode_modeinfo drm_mode;
275     memset(&drm_mode, 0, sizeof(drm_mode));
276     next_mode_.ToDrmModeModeInfo(&drm_mode);
277
278     ret = drm_->CreatePropertyBlob(&drm_mode, sizeof(struct drm_mode_modeinfo),
279                                    &blob_id);
280     if (ret) {
281       ALOGE("Failed to create mode property blob %d", ret);
282       drmModePropertySetFree(pset);
283       return ret;
284     }
285
286     ret = drmModePropertySetAdd(pset, crtc->id(), crtc->mode_property().id(),
287                                 blob_id) ||
288           drmModePropertySetAdd(pset, connector->id(),
289                                 connector->crtc_id_property().id(), crtc->id());
290     if (ret) {
291       ALOGE("Failed to add blob %d to pset", blob_id);
292       drmModePropertySetFree(pset);
293       drm_->DestroyPropertyBlob(blob_id);
294       return ret;
295     }
296   }
297
298   std::vector<DrmCompositionLayer> *layers =
299       display_comp->GetCompositionLayers();
300   for (DrmCompositionLayer &layer : *layers) {
301     int acquire_fence = layer.acquire_fence.get();
302     if (acquire_fence >= 0) {
303       for (int i = 0; i < kAcquireWaitTries; ++i) {
304         ret = sync_wait(acquire_fence, kAcquireWaitTimeoutMs);
305         if (ret)
306           ALOGW("Acquire fence %d wait %d failed (%d). Total time %d",
307                 acquire_fence, i, ret, (i + 1) * kAcquireWaitTimeoutMs);
308       }
309       if (ret) {
310         ALOGE("Failed to wait for acquire %d/%d", acquire_fence, ret);
311         drmModePropertySetFree(pset);
312         drm_->DestroyPropertyBlob(blob_id);
313         return ret;
314       }
315       layer.acquire_fence.Close();
316     }
317
318     DrmPlane *plane = layer.plane;
319
320     // Disable the plane if there's no crtc
321     if (!layer.crtc) {
322       ret = drmModePropertySetAdd(pset, plane->id(),
323                                   plane->crtc_property().id(), 0) ||
324             drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
325                                   0);
326       if (ret) {
327         ALOGE("Failed to add plane %d disable to pset", plane->id());
328         break;
329       }
330       continue;
331     }
332
333     if (!layer.buffer) {
334       ALOGE("Expected a valid framebuffer for pset");
335       ret = -EINVAL;
336       break;
337     }
338
339     uint64_t rotation;
340     switch (layer.transform) {
341       case DrmHwcTransform::kFlipH:
342         rotation = 1 << DRM_REFLECT_X;
343         break;
344       case DrmHwcTransform::kFlipV:
345         rotation = 1 << DRM_REFLECT_Y;
346         break;
347       case DrmHwcTransform::kRotate90:
348         rotation = 1 << DRM_ROTATE_90;
349         break;
350       case DrmHwcTransform::kRotate180:
351         rotation = 1 << DRM_ROTATE_180;
352         break;
353       case DrmHwcTransform::kRotate270:
354         rotation = 1 << DRM_ROTATE_270;
355         break;
356       case DrmHwcTransform::kIdentity:
357         rotation = 0;
358         break;
359       default:
360         ALOGE("Invalid transform value 0x%x given", layer.transform);
361         ret = -EINVAL;
362         break;
363     }
364     if (ret)
365       break;
366
367     // TODO: Once we have atomic test, this should fall back to GL
368     if (rotation && plane->rotation_property().id() == 0) {
369       ALOGE("Rotation is not supported on plane %d", plane->id());
370       ret = -EINVAL;
371       break;
372     }
373
374     ret =
375         drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
376                               layer.crtc->id()) ||
377         drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
378                               layer.buffer->fb_id) ||
379         drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
380                               layer.display_frame.left) ||
381         drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
382                               layer.display_frame.top) ||
383         drmModePropertySetAdd(
384             pset, plane->id(), plane->crtc_w_property().id(),
385             layer.display_frame.right - layer.display_frame.left) ||
386         drmModePropertySetAdd(
387             pset, plane->id(), plane->crtc_h_property().id(),
388             layer.display_frame.bottom - layer.display_frame.top) ||
389         drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
390                               (int)(layer.source_crop.left) << 16) ||
391         drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
392                               (int)(layer.source_crop.top) << 16) ||
393         drmModePropertySetAdd(
394             pset, plane->id(), plane->src_w_property().id(),
395             (int)(layer.source_crop.right - layer.source_crop.left) << 16) ||
396         drmModePropertySetAdd(
397             pset, plane->id(), plane->src_h_property().id(),
398             (int)(layer.source_crop.bottom - layer.source_crop.top) << 16);
399     if (ret) {
400       ALOGE("Failed to add plane %d to set", plane->id());
401       break;
402     }
403
404     if (plane->rotation_property().id()) {
405       ret = drmModePropertySetAdd(pset, plane->id(),
406                                   plane->rotation_property().id(), rotation);
407       if (ret) {
408         ALOGE("Failed to add rotation property %d to plane %d",
409               plane->rotation_property().id(), plane->id());
410         break;
411       }
412     }
413   }
414
415   if (!ret) {
416     ret = drmModePropertySetCommit(drm_->fd(), DRM_MODE_ATOMIC_ALLOW_MODESET,
417                                    drm_, pset);
418     if (ret) {
419       ALOGE("Failed to commit pset ret=%d\n", ret);
420       drmModePropertySetFree(pset);
421       if (needs_modeset_)
422         drm_->DestroyPropertyBlob(blob_id);
423       return ret;
424     }
425   }
426   if (pset)
427     drmModePropertySetFree(pset);
428
429   if (needs_modeset_) {
430     ret = drm_->DestroyPropertyBlob(old_blob_id);
431     if (ret) {
432       ALOGE("Failed to destroy old mode property blob %lld/%d", old_blob_id,
433             ret);
434       return ret;
435     }
436
437     /* TODO: Add dpms to the pset when the kernel supports it */
438     ret = ApplyDpms(display_comp);
439     if (ret) {
440       ALOGE("Failed to apply DPMS after modeset %d\n", ret);
441       return ret;
442     }
443
444     connector->set_active_mode(next_mode_);
445     needs_modeset_ = false;
446   }
447
448   return ret;
449 }
450
451 int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
452   DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
453   if (!conn) {
454     ALOGE("Failed to get DrmConnector for display %d", display_);
455     return -ENODEV;
456   }
457
458   const DrmProperty &prop = conn->dpms_property();
459   int ret = drmModeConnectorSetProperty(drm_->fd(), conn->id(), prop.id(),
460                                         display_comp->dpms_mode());
461   if (ret) {
462     ALOGE("Failed to set DPMS property for connector %d", conn->id());
463     return ret;
464   }
465   return 0;
466 }
467
468 int DrmDisplayCompositor::Composite() {
469   ATRACE_CALL();
470
471   if (!pre_compositor_) {
472     pre_compositor_.reset(new GLWorkerCompositor());
473     int ret = pre_compositor_->Init();
474     if (ret) {
475       ALOGE("Failed to initialize OpenGL compositor %d", ret);
476       return ret;
477     }
478   }
479
480   int ret = pthread_mutex_lock(&lock_);
481   if (ret) {
482     ALOGE("Failed to acquire compositor lock %d", ret);
483     return ret;
484   }
485   if (composite_queue_.empty()) {
486     ret = pthread_mutex_unlock(&lock_);
487     if (ret)
488       ALOGE("Failed to release compositor lock %d", ret);
489     return ret;
490   }
491
492   std::unique_ptr<DrmDisplayComposition> composition(
493       std::move(composite_queue_.front()));
494
495   composite_queue_.pop();
496
497   ret = pthread_mutex_unlock(&lock_);
498   if (ret) {
499     ALOGE("Failed to release compositor lock %d", ret);
500     return ret;
501   }
502
503   switch (composition->type()) {
504     case DRM_COMPOSITION_TYPE_FRAME:
505       ret = ApplyFrame(composition.get());
506       if (ret) {
507         ALOGE("Composite failed for display %d", display_);
508         return ret;
509       }
510       ++dump_frames_composited_;
511       break;
512     case DRM_COMPOSITION_TYPE_DPMS:
513       ret = ApplyDpms(composition.get());
514       if (ret)
515         ALOGE("Failed to apply dpms for display %d", display_);
516       return ret;
517     case DRM_COMPOSITION_TYPE_MODESET:
518       next_mode_ = composition->display_mode();
519       needs_modeset_ = true;
520       return 0;
521     default:
522       ALOGE("Unknown composition type %d", composition->type());
523       return -EINVAL;
524   }
525
526   if (active_composition_)
527     active_composition_->FinishComposition();
528
529   ret = pthread_mutex_lock(&lock_);
530   if (ret)
531     ALOGE("Failed to acquire lock for active_composition swap");
532
533   active_composition_.swap(composition);
534
535   if (!ret)
536     ret = pthread_mutex_unlock(&lock_);
537   if (ret)
538     ALOGE("Failed to release lock for active_composition swap");
539
540   return ret;
541 }
542
543 bool DrmDisplayCompositor::HaveQueuedComposites() const {
544   int ret = pthread_mutex_lock(&lock_);
545   if (ret) {
546     ALOGE("Failed to acquire compositor lock %d", ret);
547     return false;
548   }
549
550   bool empty_ret = !composite_queue_.empty();
551
552   ret = pthread_mutex_unlock(&lock_);
553   if (ret) {
554     ALOGE("Failed to release compositor lock %d", ret);
555     return false;
556   }
557
558   return empty_ret;
559 }
560
561 struct DrmDumpLayer {
562   int plane_id;
563   int crtc_id;
564   DrmHwcTransform transform;
565   DrmHwcRect<float> source_crop;
566   DrmHwcRect<int> display_frame;
567
568   DrmDumpLayer(DrmCompositionLayer &rhs)
569       : plane_id(rhs.plane->id()),
570         crtc_id(rhs.crtc ? rhs.crtc->id() : -1),
571         transform(rhs.transform),
572         source_crop(rhs.source_crop),
573         display_frame(rhs.display_frame) {
574   }
575 };
576
577 void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
578   uint64_t cur_ts;
579
580   int ret = pthread_mutex_lock(&lock_);
581   if (ret)
582     return;
583
584   uint64_t num_frames = dump_frames_composited_;
585   dump_frames_composited_ = 0;
586
587   struct timespec ts;
588   ret = clock_gettime(CLOCK_MONOTONIC, &ts);
589
590   std::vector<DrmCompositionLayer> *input_layers =
591       active_composition_->GetCompositionLayers();
592   std::vector<DrmDumpLayer> layers;
593   if (active_composition_)
594     layers.insert(layers.begin(), input_layers->begin(), input_layers->end());
595   else
596     ret = -EAGAIN;
597
598   ret |= pthread_mutex_unlock(&lock_);
599   if (ret)
600     return;
601
602   cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
603   uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
604   float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f;
605
606   *out << "--DrmDisplayCompositor[" << display_
607        << "]: num_frames=" << num_frames << " num_ms=" << num_ms
608        << " fps=" << fps << "\n";
609
610   dump_last_timestamp_ns_ = cur_ts;
611
612   *out << "---- DrmDisplayCompositor Layers: num=" << layers.size() << "\n";
613   for (std::vector<DrmDumpLayer>::iterator iter = layers.begin();
614        iter != layers.end(); ++iter) {
615     *out << "------ DrmDisplayCompositor Layer: plane=" << iter->plane_id
616          << " ";
617
618     if (iter->crtc_id < 0) {
619       *out << "disabled\n";
620       continue;
621     }
622
623     *out << "crtc=" << iter->crtc_id
624          << " crtc[x/y/w/h]=" << iter->display_frame.left << "/"
625          << iter->display_frame.top << "/"
626          << iter->display_frame.right - iter->display_frame.left << "/"
627          << iter->display_frame.bottom - iter->display_frame.top << " "
628          << " src[x/y/w/h]=" << iter->source_crop.left << "/"
629          << iter->source_crop.top << "/"
630          << iter->source_crop.right - iter->source_crop.left << "/"
631          << iter->source_crop.bottom - iter->source_crop.top
632          << " transform=" << (uint32_t)iter->transform << "\n";
633   }
634 }
635 }