OSDN Git Service

drm_hwcomposer: clang-format style and gcc warning fixes
[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
25 #include <pthread.h>
26 #include <sstream>
27 #include <stdlib.h>
28 #include <time.h>
29 #include <vector>
30
31 #include <drm/drm_mode.h>
32 #include <cutils/log.h>
33 #include <sync/sync.h>
34 #include <utils/Trace.h>
35
36 namespace android {
37
38 DrmDisplayCompositor::DrmDisplayCompositor()
39     : drm_(NULL),
40       display_(-1),
41       worker_(this),
42       frame_no_(0),
43       initialized_(false),
44       active_(false),
45       dump_frames_composited_(0),
46       dump_last_timestamp_ns_(0) {
47   struct timespec ts;
48   if (clock_gettime(CLOCK_MONOTONIC, &ts))
49     return;
50   dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
51 }
52
53 DrmDisplayCompositor::~DrmDisplayCompositor() {
54   if (!initialized_)
55     return;
56
57   worker_.Exit();
58
59   int ret = pthread_mutex_lock(&lock_);
60   if (ret)
61     ALOGE("Failed to acquire compositor lock %d", ret);
62
63   while (!composite_queue_.empty()) {
64     composite_queue_.front().reset();
65     composite_queue_.pop();
66   }
67   active_composition_.reset();
68
69   ret = pthread_mutex_unlock(&lock_);
70   if (ret)
71     ALOGE("Failed to acquire compositor lock %d", ret);
72
73   pthread_mutex_destroy(&lock_);
74 }
75
76 int DrmDisplayCompositor::Init(DrmResources *drm, int display) {
77   drm_ = drm;
78   display_ = display;
79
80   int ret = pthread_mutex_init(&lock_, NULL);
81   if (ret) {
82     ALOGE("Failed to initialize drm compositor lock %d\n", ret);
83     return ret;
84   }
85   ret = worker_.Init();
86   if (ret) {
87     pthread_mutex_destroy(&lock_);
88     ALOGE("Failed to initialize compositor worker %d\n", ret);
89     return ret;
90   }
91
92   initialized_ = true;
93   return 0;
94 }
95
96 int DrmDisplayCompositor::QueueComposition(
97     std::unique_ptr<DrmDisplayComposition> composition) {
98   switch (composition->type()) {
99     case DRM_COMPOSITION_TYPE_FRAME:
100       if (!active_)
101         return -ENODEV;
102       break;
103     case DRM_COMPOSITION_TYPE_DPMS:
104       /*
105        * Update the state as soon as we get it so we can start/stop queuing
106        * frames asap.
107        */
108       active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON);
109       break;
110     case DRM_COMPOSITION_TYPE_EMPTY:
111       return 0;
112     default:
113       ALOGE("Unknown composition type %d/%d", composition->type(), display_);
114       return -ENOENT;
115   }
116
117   int ret = pthread_mutex_lock(&lock_);
118   if (ret) {
119     ALOGE("Failed to acquire compositor lock %d", ret);
120     return ret;
121   }
122
123   composite_queue_.push(std::move(composition));
124
125   ret = pthread_mutex_unlock(&lock_);
126   if (ret) {
127     ALOGE("Failed to release compositor lock %d", ret);
128     return ret;
129   }
130
131   worker_.Signal();
132   return 0;
133 }
134
135 int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
136   int ret = 0;
137
138   drmModePropertySetPtr pset = drmModePropertySetAlloc();
139   if (!pset) {
140     ALOGE("Failed to allocate property set");
141     return -ENOMEM;
142   }
143
144   DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
145   for (DrmCompositionLayerVector_t::iterator iter = layers->begin();
146        iter != layers->end(); ++iter) {
147     hwc_layer_1_t *layer = &iter->layer;
148
149     if (layer->acquireFenceFd >= 0) {
150       ret = sync_wait(layer->acquireFenceFd, -1);
151       if (ret) {
152         ALOGE("Failed to wait for acquire %d/%d", layer->acquireFenceFd, ret);
153         drmModePropertySetFree(pset);
154         return ret;
155       }
156       close(layer->acquireFenceFd);
157       layer->acquireFenceFd = -1;
158     }
159
160     DrmPlane *plane = iter->plane;
161     DrmCrtc *crtc = iter->crtc;
162
163     // Disable the plane if there's no crtc
164     if (!crtc) {
165       ret = drmModePropertySetAdd(pset, plane->id(),
166                                   plane->crtc_property().id(), 0) ||
167             drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
168                                   0);
169       if (ret) {
170         ALOGE("Failed to add plane %d disable to pset", plane->id());
171         break;
172       }
173       continue;
174     }
175
176     uint64_t rotation;
177     switch (layer->transform) {
178       case HWC_TRANSFORM_FLIP_H:
179         rotation = 1 << DRM_REFLECT_X;
180         break;
181       case HWC_TRANSFORM_FLIP_V:
182         rotation = 1 << DRM_REFLECT_Y;
183         break;
184       case HWC_TRANSFORM_ROT_90:
185         rotation = 1 << DRM_ROTATE_90;
186         break;
187       case HWC_TRANSFORM_ROT_180:
188         rotation = 1 << DRM_ROTATE_180;
189         break;
190       case HWC_TRANSFORM_ROT_270:
191         rotation = 1 << DRM_ROTATE_270;
192         break;
193       case 0:
194         rotation = 0;
195         break;
196       default:
197         ALOGE("Invalid transform value 0x%x given", layer->transform);
198         ret = -EINVAL;
199         break;
200     }
201     if (ret)
202       break;
203
204     // TODO: Once we have atomic test, this should fall back to GL
205     if (rotation && plane->rotation_property().id() == 0) {
206       ALOGE("Rotation is not supported on plane %d", plane->id());
207       ret = -EINVAL;
208       break;
209     }
210
211     ret =
212         drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
213                               crtc->id()) ||
214         drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
215                               iter->bo.fb_id) ||
216         drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
217                               layer->displayFrame.left) ||
218         drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
219                               layer->displayFrame.top) ||
220         drmModePropertySetAdd(
221             pset, plane->id(), plane->crtc_w_property().id(),
222             layer->displayFrame.right - layer->displayFrame.left) ||
223         drmModePropertySetAdd(
224             pset, plane->id(), plane->crtc_h_property().id(),
225             layer->displayFrame.bottom - layer->displayFrame.top) ||
226         drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
227                               (int)(layer->sourceCropf.left) << 16) ||
228         drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
229                               (int)(layer->sourceCropf.top) << 16) ||
230         drmModePropertySetAdd(
231             pset, plane->id(), plane->src_w_property().id(),
232             (int)(layer->sourceCropf.right - layer->sourceCropf.left) << 16) ||
233         drmModePropertySetAdd(
234             pset, plane->id(), plane->src_h_property().id(),
235             (int)(layer->sourceCropf.bottom - layer->sourceCropf.top) << 16);
236     if (ret) {
237       ALOGE("Failed to add plane %d to set", plane->id());
238       break;
239     }
240
241     if (plane->rotation_property().id()) {
242       ret = drmModePropertySetAdd(pset, plane->id(),
243                                   plane->rotation_property().id(), rotation);
244       if (ret) {
245         ALOGE("Failed to add rotation property %d to plane %d",
246               plane->rotation_property().id(), plane->id());
247         break;
248       }
249     }
250   }
251
252   if (!ret) {
253     ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset);
254     if (ret)
255       ALOGE("Failed to commit pset ret=%d\n", ret);
256   }
257   if (pset)
258     drmModePropertySetFree(pset);
259
260   return ret;
261 }
262
263 int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
264   DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
265   if (!conn) {
266     ALOGE("Failed to get DrmConnector for display %d", display_);
267     return -ENODEV;
268   }
269
270   const DrmProperty &prop = conn->dpms_property();
271   int ret = drmModeConnectorSetProperty(drm_->fd(), conn->id(), prop.id(),
272                                         display_comp->dpms_mode());
273   if (ret) {
274     ALOGE("Failed to set DPMS property for connector %d", conn->id());
275     return ret;
276   }
277   return 0;
278 }
279
280 int DrmDisplayCompositor::Composite() {
281   ATRACE_CALL();
282   int ret = pthread_mutex_lock(&lock_);
283   if (ret) {
284     ALOGE("Failed to acquire compositor lock %d", ret);
285     return ret;
286   }
287   if (composite_queue_.empty()) {
288     ret = pthread_mutex_unlock(&lock_);
289     if (ret)
290       ALOGE("Failed to release compositor lock %d", ret);
291     return ret;
292   }
293
294   std::unique_ptr<DrmDisplayComposition> composition(
295       std::move(composite_queue_.front()));
296   composite_queue_.pop();
297
298   ret = pthread_mutex_unlock(&lock_);
299   if (ret) {
300     ALOGE("Failed to release compositor lock %d", ret);
301     return ret;
302   }
303
304   switch (composition->type()) {
305     case DRM_COMPOSITION_TYPE_FRAME:
306       ret = ApplyFrame(composition.get());
307       if (ret) {
308         ALOGE("Composite failed for display %d", display_);
309         return ret;
310       }
311       ++dump_frames_composited_;
312       break;
313     case DRM_COMPOSITION_TYPE_DPMS:
314       ret = ApplyDpms(composition.get());
315       if (ret)
316         ALOGE("Failed to apply dpms for display %d", display_);
317       return ret;
318     default:
319       ALOGE("Unknown composition type %d", composition->type());
320       return -EINVAL;
321   }
322
323   if (active_composition_)
324     active_composition_->FinishComposition();
325
326   ret = pthread_mutex_lock(&lock_);
327   if (ret)
328     ALOGE("Failed to acquire lock for active_composition swap");
329
330   active_composition_.swap(composition);
331
332   if (!ret)
333     ret = pthread_mutex_unlock(&lock_);
334   if (ret)
335     ALOGE("Failed to release lock for active_composition swap");
336
337   return ret;
338 }
339
340 bool DrmDisplayCompositor::HaveQueuedComposites() const {
341   int ret = pthread_mutex_lock(&lock_);
342   if (ret) {
343     ALOGE("Failed to acquire compositor lock %d", ret);
344     return false;
345   }
346
347   bool empty_ret = !composite_queue_.empty();
348
349   ret = pthread_mutex_unlock(&lock_);
350   if (ret) {
351     ALOGE("Failed to release compositor lock %d", ret);
352     return false;
353   }
354
355   return empty_ret;
356 }
357
358 void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
359   uint64_t cur_ts;
360
361   int ret = pthread_mutex_lock(&lock_);
362   if (ret)
363     return;
364
365   uint64_t num_frames = dump_frames_composited_;
366   dump_frames_composited_ = 0;
367
368   struct timespec ts;
369   ret = clock_gettime(CLOCK_MONOTONIC, &ts);
370
371   DrmCompositionLayerVector_t layers;
372   if (active_composition_)
373     layers = *active_composition_->GetCompositionLayers();
374   else
375     ret = -EAGAIN;
376
377   ret |= pthread_mutex_unlock(&lock_);
378   if (ret)
379     return;
380
381   cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
382   uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
383   float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f;
384
385   *out << "--DrmDisplayCompositor[" << display_
386        << "]: num_frames=" << num_frames << " num_ms=" << num_ms
387        << " fps=" << fps << "\n";
388
389   dump_last_timestamp_ns_ = cur_ts;
390
391   *out << "---- DrmDisplayCompositor Layers: num=" << layers.size() << "\n";
392   for (DrmCompositionLayerVector_t::iterator iter = layers.begin();
393        iter != layers.end(); ++iter) {
394     hwc_layer_1_t *layer = &iter->layer;
395     DrmPlane *plane = iter->plane;
396
397     *out << "------ DrmDisplayCompositor Layer: plane=" << plane->id() << " ";
398
399     DrmCrtc *crtc = iter->crtc;
400     if (!crtc) {
401       *out << "disabled\n";
402       continue;
403     }
404
405     *out << "crtc=" << crtc->id()
406          << " crtc[x/y/w/h]=" << layer->displayFrame.left << "/"
407          << layer->displayFrame.top << "/"
408          << layer->displayFrame.right - layer->displayFrame.left << "/"
409          << layer->displayFrame.bottom - layer->displayFrame.top << " "
410          << " src[x/y/w/h]=" << layer->sourceCropf.left << "/"
411          << layer->sourceCropf.top << "/"
412          << layer->sourceCropf.right - layer->sourceCropf.left << "/"
413          << layer->sourceCropf.bottom - layer->sourceCropf.top
414          << " transform=" << layer->transform << "\n";
415   }
416 }
417 }