blob: e0d808ff82a99635509649e6cb0fe3729c1ddb63 [file] [log] [blame]
Sean Paul98e73c82015-06-24 14:38:49 -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 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
Sean Paul1c4c3262015-07-14 15:51:52 -040031#include <drm/drm_mode.h>
Sean Paul98e73c82015-06-24 14:38:49 -070032#include <cutils/log.h>
33#include <sync/sync.h>
34#include <utils/Trace.h>
35
36namespace android {
37
38DrmDisplayCompositor::DrmDisplayCompositor()
39 : drm_(NULL),
40 display_(-1),
41 worker_(this),
42 frame_no_(0),
43 initialized_(false),
Sean Pauldb7a17d2015-06-24 18:46:05 -070044 active_(false),
Sean Paul98e73c82015-06-24 14:38:49 -070045 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
53DrmDisplayCompositor::~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
76int 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
96int DrmDisplayCompositor::QueueComposition(
97 std::unique_ptr<DrmDisplayComposition> composition) {
Sean Paulacb2a442015-06-24 18:43:01 -070098 switch (composition->type()) {
Zach Reiznerb4a9aef2015-07-16 09:45:59 -070099 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;
Sean Paulacb2a442015-06-24 18:43:01 -0700115 }
Sean Paul98e73c82015-06-24 14:38:49 -0700116
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
135int 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;
Sean Paul2e46fbd2015-07-09 17:22:22 -0400161 DrmCrtc *crtc = iter->crtc;
162
163 // Disable the plane if there's no crtc
164 if (!crtc) {
Zach Reizner952f70a2015-07-17 14:10:03 -0700165 ret = drmModePropertySetAdd(pset, plane->id(),
166 plane->crtc_property().id(), 0) ||
167 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
168 0);
Sean Paul2e46fbd2015-07-09 17:22:22 -0400169 if (ret) {
170 ALOGE("Failed to add plane %d disable to pset", plane->id());
171 break;
172 }
173 continue;
174 }
175
Sean Paul1c4c3262015-07-14 15:51:52 -0400176 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 }
Zach Reizner952f70a2015-07-17 14:10:03 -0700201 if (ret)
202 break;
203
Sean Paul1c4c3262015-07-14 15:51:52 -0400204 // 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
Sean Paul98e73c82015-06-24 14:38:49 -0700211 ret =
212 drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
Sean Paul2e46fbd2015-07-09 17:22:22 -0400213 crtc->id()) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700214 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(),
Sean Paul24323e82015-07-15 12:36:48 -0400227 (int)(layer->sourceCropf.left) << 16) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700228 drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
Sean Paul24323e82015-07-15 12:36:48 -0400229 (int)(layer->sourceCropf.top) << 16) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700230 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 }
Sean Paul1c4c3262015-07-14 15:51:52 -0400240
241 if (plane->rotation_property().id()) {
Zach Reizner952f70a2015-07-17 14:10:03 -0700242 ret = drmModePropertySetAdd(pset, plane->id(),
243 plane->rotation_property().id(), rotation);
Sean Paul1c4c3262015-07-14 15:51:52 -0400244 if (ret) {
245 ALOGE("Failed to add rotation property %d to plane %d",
246 plane->rotation_property().id(), plane->id());
247 break;
248 }
249 }
Sean Paul98e73c82015-06-24 14:38:49 -0700250 }
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
Sean Pauldb7a17d2015-06-24 18:46:05 -0700263int 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
Sean Paul98e73c82015-06-24 14:38:49 -0700280int 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
Sean Paulacb2a442015-06-24 18:43:01 -0700304 switch (composition->type()) {
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700305 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_);
Sean Paulacb2a442015-06-24 18:43:01 -0700317 return ret;
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700318 default:
319 ALOGE("Unknown composition type %d", composition->type());
320 return -EINVAL;
Sean Paul98e73c82015-06-24 14:38:49 -0700321 }
Sean Paul98e73c82015-06-24 14:38:49 -0700322
323 if (active_composition_)
324 active_composition_->FinishComposition();
325
Sean Paulfd37dfe2015-07-13 12:41:37 -0400326 ret = pthread_mutex_lock(&lock_);
327 if (ret)
328 ALOGE("Failed to acquire lock for active_composition swap");
329
Sean Paul98e73c82015-06-24 14:38:49 -0700330 active_composition_.swap(composition);
Sean Paulfd37dfe2015-07-13 12:41:37 -0400331
332 if (!ret)
333 ret = pthread_mutex_unlock(&lock_);
Zach Reizner952f70a2015-07-17 14:10:03 -0700334 if (ret)
335 ALOGE("Failed to release lock for active_composition swap");
Sean Paulfd37dfe2015-07-13 12:41:37 -0400336
Sean Paul98e73c82015-06-24 14:38:49 -0700337 return ret;
338}
339
340bool 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
358void 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
Sean Paulfd37dfe2015-07-13 12:41:37 -0400371 DrmCompositionLayerVector_t layers;
372 if (active_composition_)
373 layers = *active_composition_->GetCompositionLayers();
374 else
375 ret = -EAGAIN;
376
Sean Paul98e73c82015-06-24 14:38:49 -0700377 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);
Stéphane Marchesin83959922015-07-13 12:35:41 -0700383 float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f;
Sean Paul98e73c82015-06-24 14:38:49 -0700384
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;
Sean Paulfd37dfe2015-07-13 12:41:37 -0400390
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
Zach Reizner952f70a2015-07-17 14:10:03 -0700405 *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";
Sean Paulfd37dfe2015-07-13 12:41:37 -0400415 }
Sean Paul98e73c82015-06-24 14:38:49 -0700416}
417}