OSDN Git Service

Merge "drm_hwcomposer: Reference count NvImporter buffers" into mnc-dev
[android-x86/external-drm_hwcomposer.git] / drmcompositor.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 LOG_TAG "hwc-drm-compositor"
18
19 #include "drmcompositor.h"
20 #include "drmcrtc.h"
21 #include "drmplane.h"
22 #include "drmresources.h"
23
24 #include <pthread.h>
25 #include <sstream>
26 #include <stdlib.h>
27 #include <time.h>
28
29 #include <cutils/log.h>
30 #include <sync/sync.h>
31
32 namespace android {
33
34 DrmCompositor::DrmCompositor(DrmResources *drm)
35     : drm_(drm),
36       worker_(this),
37       active_composition_(NULL),
38       frame_no_(0),
39       initialized_(false),
40       dump_frames_composited_(0),
41       dump_last_timestamp_ns_(0) {
42   struct timespec ts;
43   if (clock_gettime(CLOCK_MONOTONIC, &ts))
44     return;
45   dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
46 }
47
48 DrmCompositor::~DrmCompositor() {
49   if (initialized_)
50     pthread_mutex_destroy(&lock_);
51 }
52
53 int DrmCompositor::Init() {
54   int ret = pthread_mutex_init(&lock_, NULL);
55   if (ret) {
56     ALOGE("Failed to initialize drm compositor lock %d\n", ret);
57     return ret;
58   }
59   ret = worker_.Init();
60   if (ret) {
61     pthread_mutex_destroy(&lock_);
62     ALOGE("Failed to initialize compositor worker %d\n", ret);
63     return ret;
64   }
65
66   initialized_ = true;
67   return 0;
68 }
69
70 Composition *DrmCompositor::CreateComposition(Importer *importer) {
71   DrmComposition *composition = new DrmComposition(drm_, importer, frame_no_++);
72   if (!composition) {
73     ALOGE("Failed to allocate drm composition");
74     return NULL;
75   }
76   int ret = composition->Init();
77   if (ret) {
78     ALOGE("Failed to initialize drm composition %d", ret);
79     delete composition;
80     return NULL;
81   }
82   return composition;
83 }
84
85 int DrmCompositor::QueueComposition(Composition *composition) {
86   int ret = pthread_mutex_lock(&lock_);
87   if (ret) {
88     ALOGE("Failed to acquire compositor lock %d", ret);
89     return ret;
90   }
91
92   composite_queue_.push((DrmComposition *)composition);
93
94   ret = pthread_mutex_unlock(&lock_);
95   if (ret) {
96     ALOGE("Failed to release compositor lock %d", ret);
97     return ret;
98   }
99
100   worker_.Signal();
101   return 0;
102 }
103
104 int DrmCompositor::PerformModeset(DrmCompositionLayerMap_t::iterator begin,
105                                   DrmCompositionLayerMap_t::iterator end) {
106   DrmCompositionLayer *layer = NULL;
107   for (DrmCompositionLayerMap_t::iterator iter = begin; iter != end; ++iter) {
108     if (iter->second.layer.compositionType == HWC_FRAMEBUFFER_TARGET) {
109       layer = &iter->second;
110       break;
111     }
112   }
113   int display = begin->first;
114   if (!layer) {
115     ALOGE("Could not find target framebuffer for display %d", display);
116     return -ENOENT;
117   }
118
119   drmModeModeInfo m;
120   DrmConnector *connector = drm_->GetConnectorForDisplay(display);
121   connector->active_mode().ToModeModeInfo(&m);
122
123   uint32_t connectors = connector->id();
124   int ret = drmModeSetCrtc(drm_->fd(), layer->crtc->id(), layer->bo.fb_id, 0, 0,
125                            &connectors, 1, &m);
126   if (ret)
127     ALOGE("Failed set crtc for disp %d/%d", display, ret);
128   else
129     layer->crtc->set_requires_modeset(false);
130
131   return ret;
132 }
133
134 int DrmCompositor::CompositeDisplay(DrmCompositionLayerMap_t::iterator begin,
135                                     DrmCompositionLayerMap_t::iterator end) {
136   int ret = 0;
137   // Wait for all acquire fences to signal
138   for (DrmCompositionLayerMap_t::iterator iter = begin; iter != end; ++iter) {
139     hwc_layer_1_t *layer = &iter->second.layer;
140
141     if (layer->acquireFenceFd < 0)
142       continue;
143
144     ret = sync_wait(layer->acquireFenceFd, -1);
145     if (ret) {
146       ALOGE("Failed to wait for acquire %d/%d", layer->acquireFenceFd, ret);
147       return ret;
148     }
149     close(layer->acquireFenceFd);
150     layer->acquireFenceFd = -1;
151   }
152
153   DrmCrtc *crtc = begin->second.crtc;
154   if (crtc->requires_modeset()) {
155     ret = PerformModeset(begin, end);
156     if (ret)
157       ALOGE("Failed modeset on display %d", begin->first);
158     return ret;
159   }
160
161   drmModePropertySetPtr pset = drmModePropertySetAlloc();
162   if (!pset) {
163     ALOGE("Failed to allocate property set");
164     return -ENOMEM;
165   }
166
167   for (DrmCompositionLayerMap_t::iterator iter = begin; iter != end; ++iter) {
168     DrmCompositionLayer_t *comp = &iter->second;
169     hwc_layer_1_t *layer = &comp->layer;
170     DrmPlane *plane = comp->plane;
171
172     ret =
173         drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
174                               crtc->id()) ||
175         drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
176                               comp->bo.fb_id) ||
177         drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
178                               layer->displayFrame.left) ||
179         drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
180                               layer->displayFrame.top) ||
181         drmModePropertySetAdd(
182             pset, plane->id(), plane->crtc_w_property().id(),
183             layer->displayFrame.right - layer->displayFrame.left) ||
184         drmModePropertySetAdd(
185             pset, plane->id(), plane->crtc_h_property().id(),
186             layer->displayFrame.bottom - layer->displayFrame.top) ||
187         drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
188                               layer->sourceCropf.left) ||
189         drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
190                               layer->sourceCropf.top) ||
191         drmModePropertySetAdd(
192             pset, plane->id(), plane->src_w_property().id(),
193             (int)(layer->sourceCropf.right - layer->sourceCropf.left) << 16) ||
194         drmModePropertySetAdd(
195             pset, plane->id(), plane->src_h_property().id(),
196             (int)(layer->sourceCropf.bottom - layer->sourceCropf.top) << 16);
197     if (ret) {
198       ALOGE("Failed to add plane %d to set", plane->id());
199       break;
200     }
201   }
202
203   if (!ret) {
204     ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset);
205     if (ret)
206       ALOGE("Failed to commit pset ret=%d\n", ret);
207   }
208   if (pset)
209     drmModePropertySetFree(pset);
210
211   return ret;
212 }
213
214 int DrmCompositor::Composite() {
215   int ret = pthread_mutex_lock(&lock_);
216   if (ret) {
217     ALOGE("Failed to acquire compositor lock %d", ret);
218     return ret;
219   }
220   if (composite_queue_.empty()) {
221     ret = pthread_mutex_unlock(&lock_);
222     if (ret)
223       ALOGE("Failed to release compositor lock %d", ret);
224     return ret;
225   }
226
227   DrmComposition *composition = composite_queue_.front();
228   composite_queue_.pop();
229   ++dump_frames_composited_;
230
231   ret = pthread_mutex_unlock(&lock_);
232   if (ret) {
233     ALOGE("Failed to release compositor lock %d", ret);
234     return ret;
235   }
236
237   DrmCompositionLayerMap_t *map = composition->GetCompositionMap();
238   for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
239        iter != drm_->end_connectors(); ++iter) {
240     int display = (*iter)->display();
241     std::pair<DrmCompositionLayerMap_t::iterator,
242               DrmCompositionLayerMap_t::iterator> layer_iters =
243         map->equal_range(display);
244
245     if (layer_iters.first != layer_iters.second) {
246       ret = CompositeDisplay(layer_iters.first, layer_iters.second);
247       if (ret) {
248         ALOGE("Composite failed for display %d:", display);
249         break;
250       }
251     }
252   }
253
254   if (active_composition_) {
255     active_composition_->FinishComposition();
256     delete active_composition_;
257   }
258   active_composition_ = composition;
259   return ret;
260 }
261
262 bool DrmCompositor::HaveQueuedComposites() const {
263   int ret = pthread_mutex_lock(&lock_);
264   if (ret) {
265     ALOGE("Failed to acquire compositor lock %d", ret);
266     return false;
267   }
268
269   bool empty_ret = !composite_queue_.empty();
270
271   ret = pthread_mutex_unlock(&lock_);
272   if (ret) {
273     ALOGE("Failed to release compositor lock %d", ret);
274     return false;
275   }
276
277   return empty_ret;
278 }
279
280 void DrmCompositor::Dump(std::ostringstream *out) const {
281   uint64_t cur_ts;
282
283   int ret = pthread_mutex_lock(&lock_);
284   if (ret)
285     return;
286
287   uint64_t num_frames = dump_frames_composited_;
288   dump_frames_composited_ = 0;
289
290   struct timespec ts;
291   ret = clock_gettime(CLOCK_MONOTONIC, &ts);
292
293   ret |= pthread_mutex_unlock(&lock_);
294   if (ret)
295     return;
296
297   cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
298   uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
299   unsigned fps = num_ms ? (num_frames * 1000) / (num_ms) : 0;
300
301   *out << "DrmCompositor: num_frames=" << num_frames << " num_ms=" << num_ms <<
302           " fps=" << fps << "\n";
303
304   dump_last_timestamp_ns_ = cur_ts;
305 }
306 }