OSDN Git Service

Merge "Revert "drm_hwcomposer: remove GLCompositor and the GLWorker thread"" into...
[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 <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 namespace android {
39
40 DrmDisplayCompositor::DrmDisplayCompositor()
41     : drm_(NULL),
42       display_(-1),
43       worker_(this),
44       frame_no_(0),
45       initialized_(false),
46       active_(false),
47       framebuffer_index_(0),
48       dump_frames_composited_(0),
49       dump_last_timestamp_ns_(0) {
50   struct timespec ts;
51   if (clock_gettime(CLOCK_MONOTONIC, &ts))
52     return;
53   dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
54 }
55
56 DrmDisplayCompositor::~DrmDisplayCompositor() {
57   if (!initialized_)
58     return;
59
60   worker_.Exit();
61
62   int ret = pthread_mutex_lock(&lock_);
63   if (ret)
64     ALOGE("Failed to acquire compositor lock %d", ret);
65
66   while (!composite_queue_.empty()) {
67     composite_queue_.front().reset();
68     composite_queue_.pop();
69   }
70   active_composition_.reset();
71
72   ret = pthread_mutex_unlock(&lock_);
73   if (ret)
74     ALOGE("Failed to acquire compositor lock %d", ret);
75
76   pthread_mutex_destroy(&lock_);
77 }
78
79 int DrmDisplayCompositor::Init(DrmResources *drm, int display) {
80   drm_ = drm;
81   display_ = display;
82
83   int ret = pthread_mutex_init(&lock_, NULL);
84   if (ret) {
85     ALOGE("Failed to initialize drm compositor lock %d\n", ret);
86     return ret;
87   }
88   ret = worker_.Init();
89   if (ret) {
90     pthread_mutex_destroy(&lock_);
91     ALOGE("Failed to initialize compositor worker %d\n", ret);
92     return ret;
93   }
94
95   initialized_ = true;
96   return 0;
97 }
98
99 int DrmDisplayCompositor::QueueComposition(
100     std::unique_ptr<DrmDisplayComposition> composition) {
101   switch (composition->type()) {
102     case DRM_COMPOSITION_TYPE_FRAME:
103       if (!active_)
104         return -ENODEV;
105       break;
106     case DRM_COMPOSITION_TYPE_DPMS:
107       /*
108        * Update the state as soon as we get it so we can start/stop queuing
109        * frames asap.
110        */
111       active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON);
112       break;
113     case DRM_COMPOSITION_TYPE_EMPTY:
114       return 0;
115     default:
116       ALOGE("Unknown composition type %d/%d", composition->type(), display_);
117       return -ENOENT;
118   }
119
120   int ret = pthread_mutex_lock(&lock_);
121   if (ret) {
122     ALOGE("Failed to acquire compositor lock %d", ret);
123     return ret;
124   }
125
126   composite_queue_.push(std::move(composition));
127
128   ret = pthread_mutex_unlock(&lock_);
129   if (ret) {
130     ALOGE("Failed to release compositor lock %d", ret);
131     return ret;
132   }
133
134   worker_.Signal();
135   return 0;
136 }
137
138 static bool drm_composition_layer_has_plane(
139     const DrmCompositionLayer_t &comp_layer) {
140   if (comp_layer.plane != NULL)
141     if (comp_layer.plane->type() == DRM_PLANE_TYPE_OVERLAY ||
142         comp_layer.plane->type() == DRM_PLANE_TYPE_PRIMARY)
143       return true;
144   return false;
145 }
146
147 static bool drm_composition_layer_has_no_plane(
148     const DrmCompositionLayer_t &comp_layer) {
149   return comp_layer.plane == NULL;
150 }
151
152 int DrmDisplayCompositor::ApplyPreComposite(
153     DrmDisplayComposition *display_comp) {
154   int ret = 0;
155   DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
156
157   auto last_layer = find_if(layers->rbegin(), layers->rend(),
158                             drm_composition_layer_has_plane);
159   if (last_layer == layers->rend()) {
160     ALOGE("Frame has no overlays");
161     return -EINVAL;
162   }
163
164   DrmCompositionLayer_t &comp_layer = *last_layer;
165   DrmPlane *stolen_plane = NULL;
166   std::swap(stolen_plane, comp_layer.plane);
167
168   DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
169   if (connector == NULL) {
170     ALOGE("Failed to determine display mode: no connector for display %d",
171           display_);
172     return -ENODEV;
173   }
174
175   const DrmMode &mode = connector->active_mode();
176   DrmFramebuffer &fb = framebuffers_[framebuffer_index_];
177   ret = fb.WaitReleased(-1);
178   if (ret) {
179     ALOGE("Failed to wait for framebuffer release %d", ret);
180     return ret;
181   }
182   fb.set_release_fence_fd(-1);
183   if (!fb.Allocate(mode.h_display(), mode.v_display())) {
184     ALOGE("Failed to allocate framebuffer with size %dx%d", mode.h_display(),
185           mode.v_display());
186     return -ENOMEM;
187   }
188
189   std::vector<hwc_layer_1_t> pre_comp_layers;
190   for (const auto &comp_layer : *layers)
191     if (comp_layer.plane == NULL)
192       pre_comp_layers.push_back(comp_layer.layer);
193
194   if (!pre_compositor_) {
195     pre_compositor_.reset(new GLWorkerCompositor());
196     ret = pre_compositor_->Init();
197     if (ret) {
198       ALOGE("Failed to initialize OpenGL compositor %d", ret);
199       return ret;
200     }
201   }
202   ret = pre_compositor_->CompositeAndFinish(
203       pre_comp_layers.data(), pre_comp_layers.size(), fb.buffer());
204   if (ret) {
205     ALOGE("Failed to composite layers");
206     return ret;
207   }
208
209   layers->erase(std::remove_if(layers->begin(), layers->end(),
210                                drm_composition_layer_has_no_plane),
211                 layers->end());
212
213   hwc_layer_1_t pre_comp_output_layer;
214   memset(&pre_comp_output_layer, 0, sizeof(pre_comp_output_layer));
215   pre_comp_output_layer.compositionType = HWC_OVERLAY;
216   pre_comp_output_layer.handle = fb.buffer()->handle;
217   pre_comp_output_layer.acquireFenceFd = -1;
218   pre_comp_output_layer.releaseFenceFd = -1;
219   pre_comp_output_layer.planeAlpha = 0xff;
220   pre_comp_output_layer.visibleRegionScreen.numRects = 1;
221   pre_comp_output_layer.visibleRegionScreen.rects =
222       &pre_comp_output_layer.displayFrame;
223   pre_comp_output_layer.sourceCropf.top =
224       pre_comp_output_layer.displayFrame.top = 0;
225   pre_comp_output_layer.sourceCropf.left =
226       pre_comp_output_layer.displayFrame.left = 0;
227   pre_comp_output_layer.sourceCropf.right =
228       pre_comp_output_layer.displayFrame.right = fb.buffer()->getWidth();
229   pre_comp_output_layer.sourceCropf.bottom =
230       pre_comp_output_layer.displayFrame.bottom = fb.buffer()->getHeight();
231
232   ret = display_comp->AddLayer(&pre_comp_output_layer,
233                                drm_->GetCrtcForDisplay(display_), stolen_plane);
234   if (ret) {
235     ALOGE("Failed to add composited layer %d", ret);
236     return ret;
237   }
238
239   fb.set_release_fence_fd(pre_comp_output_layer.releaseFenceFd);
240   framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
241
242   return ret;
243 }
244
245 int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
246   int ret = 0;
247
248   DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
249   bool use_pre_comp = std::any_of(layers->begin(), layers->end(),
250                                   drm_composition_layer_has_no_plane);
251
252   if (use_pre_comp) {
253     ret = ApplyPreComposite(display_comp);
254     if (ret)
255       return ret;
256   }
257
258   drmModePropertySetPtr pset = drmModePropertySetAlloc();
259   if (!pset) {
260     ALOGE("Failed to allocate property set");
261     return -ENOMEM;
262   }
263
264   for (DrmCompositionLayerVector_t::iterator iter = layers->begin();
265        iter != layers->end(); ++iter) {
266     hwc_layer_1_t *layer = &iter->layer;
267
268     if (layer->acquireFenceFd >= 0) {
269       ret = sync_wait(layer->acquireFenceFd, -1);
270       if (ret) {
271         ALOGE("Failed to wait for acquire %d/%d", layer->acquireFenceFd, ret);
272         drmModePropertySetFree(pset);
273         return ret;
274       }
275       close(layer->acquireFenceFd);
276       layer->acquireFenceFd = -1;
277     }
278
279     DrmPlane *plane = iter->plane;
280     DrmCrtc *crtc = iter->crtc;
281
282     // Disable the plane if there's no crtc
283     if (!crtc) {
284       ret = drmModePropertySetAdd(pset, plane->id(),
285                                   plane->crtc_property().id(), 0) ||
286             drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
287                                   0);
288       if (ret) {
289         ALOGE("Failed to add plane %d disable to pset", plane->id());
290         break;
291       }
292       continue;
293     }
294
295     uint64_t rotation;
296     switch (layer->transform) {
297       case HWC_TRANSFORM_FLIP_H:
298         rotation = 1 << DRM_REFLECT_X;
299         break;
300       case HWC_TRANSFORM_FLIP_V:
301         rotation = 1 << DRM_REFLECT_Y;
302         break;
303       case HWC_TRANSFORM_ROT_90:
304         rotation = 1 << DRM_ROTATE_90;
305         break;
306       case HWC_TRANSFORM_ROT_180:
307         rotation = 1 << DRM_ROTATE_180;
308         break;
309       case HWC_TRANSFORM_ROT_270:
310         rotation = 1 << DRM_ROTATE_270;
311         break;
312       case 0:
313         rotation = 0;
314         break;
315       default:
316         ALOGE("Invalid transform value 0x%x given", layer->transform);
317         ret = -EINVAL;
318         break;
319     }
320     if (ret)
321       break;
322
323     // TODO: Once we have atomic test, this should fall back to GL
324     if (rotation && plane->rotation_property().id() == 0) {
325       ALOGE("Rotation is not supported on plane %d", plane->id());
326       ret = -EINVAL;
327       break;
328     }
329
330     ret =
331         drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
332                               crtc->id()) ||
333         drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
334                               iter->bo.fb_id) ||
335         drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
336                               layer->displayFrame.left) ||
337         drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
338                               layer->displayFrame.top) ||
339         drmModePropertySetAdd(
340             pset, plane->id(), plane->crtc_w_property().id(),
341             layer->displayFrame.right - layer->displayFrame.left) ||
342         drmModePropertySetAdd(
343             pset, plane->id(), plane->crtc_h_property().id(),
344             layer->displayFrame.bottom - layer->displayFrame.top) ||
345         drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
346                               (int)(layer->sourceCropf.left) << 16) ||
347         drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
348                               (int)(layer->sourceCropf.top) << 16) ||
349         drmModePropertySetAdd(
350             pset, plane->id(), plane->src_w_property().id(),
351             (int)(layer->sourceCropf.right - layer->sourceCropf.left) << 16) ||
352         drmModePropertySetAdd(
353             pset, plane->id(), plane->src_h_property().id(),
354             (int)(layer->sourceCropf.bottom - layer->sourceCropf.top) << 16);
355     if (ret) {
356       ALOGE("Failed to add plane %d to set", plane->id());
357       break;
358     }
359
360     if (plane->rotation_property().id()) {
361       ret = drmModePropertySetAdd(pset, plane->id(),
362                                   plane->rotation_property().id(), rotation);
363       if (ret) {
364         ALOGE("Failed to add rotation property %d to plane %d",
365               plane->rotation_property().id(), plane->id());
366         break;
367       }
368     }
369   }
370
371   if (!ret) {
372     ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset);
373     if (ret)
374       ALOGE("Failed to commit pset ret=%d\n", ret);
375   }
376   if (pset)
377     drmModePropertySetFree(pset);
378
379   return ret;
380 }
381
382 int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
383   DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
384   if (!conn) {
385     ALOGE("Failed to get DrmConnector for display %d", display_);
386     return -ENODEV;
387   }
388
389   const DrmProperty &prop = conn->dpms_property();
390   int ret = drmModeConnectorSetProperty(drm_->fd(), conn->id(), prop.id(),
391                                         display_comp->dpms_mode());
392   if (ret) {
393     ALOGE("Failed to set DPMS property for connector %d", conn->id());
394     return ret;
395   }
396   return 0;
397 }
398
399 int DrmDisplayCompositor::Composite() {
400   ATRACE_CALL();
401   int ret = pthread_mutex_lock(&lock_);
402   if (ret) {
403     ALOGE("Failed to acquire compositor lock %d", ret);
404     return ret;
405   }
406   if (composite_queue_.empty()) {
407     ret = pthread_mutex_unlock(&lock_);
408     if (ret)
409       ALOGE("Failed to release compositor lock %d", ret);
410     return ret;
411   }
412
413   std::unique_ptr<DrmDisplayComposition> composition(
414       std::move(composite_queue_.front()));
415   composite_queue_.pop();
416
417   ret = pthread_mutex_unlock(&lock_);
418   if (ret) {
419     ALOGE("Failed to release compositor lock %d", ret);
420     return ret;
421   }
422
423   switch (composition->type()) {
424     case DRM_COMPOSITION_TYPE_FRAME:
425       ret = ApplyFrame(composition.get());
426       if (ret) {
427         ALOGE("Composite failed for display %d", display_);
428         return ret;
429       }
430       ++dump_frames_composited_;
431       break;
432     case DRM_COMPOSITION_TYPE_DPMS:
433       ret = ApplyDpms(composition.get());
434       if (ret)
435         ALOGE("Failed to apply dpms for display %d", display_);
436       return ret;
437     default:
438       ALOGE("Unknown composition type %d", composition->type());
439       return -EINVAL;
440   }
441
442   if (active_composition_)
443     active_composition_->FinishComposition();
444
445   ret = pthread_mutex_lock(&lock_);
446   if (ret)
447     ALOGE("Failed to acquire lock for active_composition swap");
448
449   active_composition_.swap(composition);
450
451   if (!ret)
452     ret = pthread_mutex_unlock(&lock_);
453   if (ret)
454     ALOGE("Failed to release lock for active_composition swap");
455
456   return ret;
457 }
458
459 bool DrmDisplayCompositor::HaveQueuedComposites() const {
460   int ret = pthread_mutex_lock(&lock_);
461   if (ret) {
462     ALOGE("Failed to acquire compositor lock %d", ret);
463     return false;
464   }
465
466   bool empty_ret = !composite_queue_.empty();
467
468   ret = pthread_mutex_unlock(&lock_);
469   if (ret) {
470     ALOGE("Failed to release compositor lock %d", ret);
471     return false;
472   }
473
474   return empty_ret;
475 }
476
477 void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
478   uint64_t cur_ts;
479
480   int ret = pthread_mutex_lock(&lock_);
481   if (ret)
482     return;
483
484   uint64_t num_frames = dump_frames_composited_;
485   dump_frames_composited_ = 0;
486
487   struct timespec ts;
488   ret = clock_gettime(CLOCK_MONOTONIC, &ts);
489
490   DrmCompositionLayerVector_t layers;
491   if (active_composition_)
492     layers = *active_composition_->GetCompositionLayers();
493   else
494     ret = -EAGAIN;
495
496   ret |= pthread_mutex_unlock(&lock_);
497   if (ret)
498     return;
499
500   cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
501   uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
502   float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f;
503
504   *out << "--DrmDisplayCompositor[" << display_
505        << "]: num_frames=" << num_frames << " num_ms=" << num_ms
506        << " fps=" << fps << "\n";
507
508   dump_last_timestamp_ns_ = cur_ts;
509
510   *out << "---- DrmDisplayCompositor Layers: num=" << layers.size() << "\n";
511   for (DrmCompositionLayerVector_t::iterator iter = layers.begin();
512        iter != layers.end(); ++iter) {
513     hwc_layer_1_t *layer = &iter->layer;
514     DrmPlane *plane = iter->plane;
515
516     *out << "------ DrmDisplayCompositor Layer: plane=" << plane->id() << " ";
517
518     DrmCrtc *crtc = iter->crtc;
519     if (!crtc) {
520       *out << "disabled\n";
521       continue;
522     }
523
524     *out << "crtc=" << crtc->id()
525          << " crtc[x/y/w/h]=" << layer->displayFrame.left << "/"
526          << layer->displayFrame.top << "/"
527          << layer->displayFrame.right - layer->displayFrame.left << "/"
528          << layer->displayFrame.bottom - layer->displayFrame.top << " "
529          << " src[x/y/w/h]=" << layer->sourceCropf.left << "/"
530          << layer->sourceCropf.top << "/"
531          << layer->sourceCropf.right - layer->sourceCropf.left << "/"
532          << layer->sourceCropf.bottom - layer->sourceCropf.top
533          << " transform=" << layer->transform << "\n";
534   }
535 }
536 }