OSDN Git Service

Merge "drm_hwcomposer: add transform support to OpenGL compositor" into mnc-dr-dev
[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 =
166           drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
167                                 0) ||
168           drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
169                                 0);
170       if (ret) {
171         ALOGE("Failed to add plane %d disable to pset", plane->id());
172         break;
173       }
174       continue;
175     }
176
177     uint64_t rotation;
178     switch (layer->transform) {
179       case HWC_TRANSFORM_FLIP_H:
180         rotation = 1 << DRM_REFLECT_X;
181         break;
182       case HWC_TRANSFORM_FLIP_V:
183         rotation = 1 << DRM_REFLECT_Y;
184         break;
185       case HWC_TRANSFORM_ROT_90:
186         rotation = 1 << DRM_ROTATE_90;
187         break;
188       case HWC_TRANSFORM_ROT_180:
189         rotation = 1 << DRM_ROTATE_180;
190         break;
191       case HWC_TRANSFORM_ROT_270:
192         rotation = 1 << DRM_ROTATE_270;
193         break;
194       case 0:
195         rotation = 0;
196         break;
197       default:
198         ALOGE("Invalid transform value 0x%x given", layer->transform);
199         ret = -EINVAL;
200         break;
201     }
202     // TODO: Once we have atomic test, this should fall back to GL
203     if (rotation && plane->rotation_property().id() == 0) {
204       ALOGE("Rotation is not supported on plane %d", plane->id());
205       ret = -EINVAL;
206       break;
207     }
208
209     ret =
210         drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
211                               crtc->id()) ||
212         drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
213                               iter->bo.fb_id) ||
214         drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
215                               layer->displayFrame.left) ||
216         drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
217                               layer->displayFrame.top) ||
218         drmModePropertySetAdd(
219             pset, plane->id(), plane->crtc_w_property().id(),
220             layer->displayFrame.right - layer->displayFrame.left) ||
221         drmModePropertySetAdd(
222             pset, plane->id(), plane->crtc_h_property().id(),
223             layer->displayFrame.bottom - layer->displayFrame.top) ||
224         drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
225                               (int)(layer->sourceCropf.left) << 16) ||
226         drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
227                               (int)(layer->sourceCropf.top) << 16) ||
228         drmModePropertySetAdd(
229             pset, plane->id(), plane->src_w_property().id(),
230             (int)(layer->sourceCropf.right - layer->sourceCropf.left) << 16) ||
231         drmModePropertySetAdd(
232             pset, plane->id(), plane->src_h_property().id(),
233             (int)(layer->sourceCropf.bottom - layer->sourceCropf.top) << 16);
234     if (ret) {
235       ALOGE("Failed to add plane %d to set", plane->id());
236       break;
237     }
238
239     if (plane->rotation_property().id()) {
240       ret = drmModePropertySetAdd(
241               pset, plane->id(), plane->rotation_property().id(), rotation);
242       if (ret) {
243         ALOGE("Failed to add rotation property %d to plane %d",
244               plane->rotation_property().id(), plane->id());
245         break;
246       }
247     }
248   }
249
250   if (!ret) {
251     ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset);
252     if (ret)
253       ALOGE("Failed to commit pset ret=%d\n", ret);
254   }
255   if (pset)
256     drmModePropertySetFree(pset);
257
258   return ret;
259 }
260
261 int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
262   DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
263   if (!conn) {
264     ALOGE("Failed to get DrmConnector for display %d", display_);
265     return -ENODEV;
266   }
267
268   const DrmProperty &prop = conn->dpms_property();
269   int ret = drmModeConnectorSetProperty(drm_->fd(), conn->id(), prop.id(),
270                                         display_comp->dpms_mode());
271   if (ret) {
272     ALOGE("Failed to set DPMS property for connector %d", conn->id());
273     return ret;
274   }
275   return 0;
276 }
277
278 int DrmDisplayCompositor::Composite() {
279   ATRACE_CALL();
280   int ret = pthread_mutex_lock(&lock_);
281   if (ret) {
282     ALOGE("Failed to acquire compositor lock %d", ret);
283     return ret;
284   }
285   if (composite_queue_.empty()) {
286     ret = pthread_mutex_unlock(&lock_);
287     if (ret)
288       ALOGE("Failed to release compositor lock %d", ret);
289     return ret;
290   }
291
292   std::unique_ptr<DrmDisplayComposition> composition(
293       std::move(composite_queue_.front()));
294   composite_queue_.pop();
295
296   ret = pthread_mutex_unlock(&lock_);
297   if (ret) {
298     ALOGE("Failed to release compositor lock %d", ret);
299     return ret;
300   }
301
302   switch (composition->type()) {
303     case DRM_COMPOSITION_TYPE_FRAME:
304       ret = ApplyFrame(composition.get());
305       if (ret) {
306         ALOGE("Composite failed for display %d", display_);
307         return ret;
308       }
309       ++dump_frames_composited_;
310       break;
311     case DRM_COMPOSITION_TYPE_DPMS:
312       ret = ApplyDpms(composition.get());
313       if (ret)
314         ALOGE("Failed to apply dpms for display %d", display_);
315       return ret;
316     default:
317       ALOGE("Unknown composition type %d", composition->type());
318       return -EINVAL;
319   }
320
321   if (active_composition_)
322     active_composition_->FinishComposition();
323
324   ret = pthread_mutex_lock(&lock_);
325   if (ret)
326     ALOGE("Failed to acquire lock for active_composition swap");
327
328   active_composition_.swap(composition);
329
330   if (!ret)
331     ret = pthread_mutex_unlock(&lock_);
332     if (ret)
333       ALOGE("Failed to release lock for active_composition swap");
334
335   return ret;
336 }
337
338 bool DrmDisplayCompositor::HaveQueuedComposites() const {
339   int ret = pthread_mutex_lock(&lock_);
340   if (ret) {
341     ALOGE("Failed to acquire compositor lock %d", ret);
342     return false;
343   }
344
345   bool empty_ret = !composite_queue_.empty();
346
347   ret = pthread_mutex_unlock(&lock_);
348   if (ret) {
349     ALOGE("Failed to release compositor lock %d", ret);
350     return false;
351   }
352
353   return empty_ret;
354 }
355
356 void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
357   uint64_t cur_ts;
358
359   int ret = pthread_mutex_lock(&lock_);
360   if (ret)
361     return;
362
363   uint64_t num_frames = dump_frames_composited_;
364   dump_frames_composited_ = 0;
365
366   struct timespec ts;
367   ret = clock_gettime(CLOCK_MONOTONIC, &ts);
368
369   DrmCompositionLayerVector_t layers;
370   if (active_composition_)
371     layers = *active_composition_->GetCompositionLayers();
372   else
373     ret = -EAGAIN;
374
375   ret |= pthread_mutex_unlock(&lock_);
376   if (ret)
377     return;
378
379   cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
380   uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
381   float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f;
382
383   *out << "--DrmDisplayCompositor[" << display_
384        << "]: num_frames=" << num_frames << " num_ms=" << num_ms
385        << " fps=" << fps << "\n";
386
387   dump_last_timestamp_ns_ = cur_ts;
388
389   *out << "---- DrmDisplayCompositor Layers: num=" << layers.size() << "\n";
390   for (DrmCompositionLayerVector_t::iterator iter = layers.begin();
391        iter != layers.end(); ++iter) {
392     hwc_layer_1_t *layer = &iter->layer;
393     DrmPlane *plane = iter->plane;
394
395     *out << "------ DrmDisplayCompositor Layer: plane=" << plane->id() << " ";
396
397     DrmCrtc *crtc = iter->crtc;
398     if (!crtc) {
399       *out << "disabled\n";
400       continue;
401     }
402
403     *out << "crtc=" << crtc->id() << " crtc[x/y/w/h]=" <<
404         layer->displayFrame.left << "/" << layer->displayFrame.top << "/" <<
405         layer->displayFrame.right - layer->displayFrame.left << "/" <<
406         layer->displayFrame.bottom - layer->displayFrame.top << " " <<
407         " src[x/y/w/h]=" << layer->sourceCropf.left << "/" <<
408         layer->sourceCropf.top << "/" <<
409         layer->sourceCropf.right - layer->sourceCropf.left << "/" <<
410         layer->sourceCropf.bottom - layer->sourceCropf.top <<  " transform=" <<
411         layer->transform << "\n";
412   }
413
414 }
415 }