OSDN Git Service

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