blob: ffca4dfb023f126cadbea99dc9ce4a08315f05f3 [file] [log] [blame]
Sean Paulb386f1b2015-05-13 06:33:23 -07001/*
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
30namespace android {
31
32DrmCompositor::DrmCompositor(DrmResources *drm)
33 : drm_(drm),
34 worker_(this),
35 active_composition_(NULL),
36 frame_no_(0),
37 initialized_(false) {
38}
39
40DrmCompositor::~DrmCompositor() {
41 if (initialized_)
42 pthread_mutex_destroy(&lock_);
43}
44
45int 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
62Composition *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
77int 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
96int 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
126int 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
206int 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
253bool 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}