blob: b293681fae878d8b288d1c97842822a6829998c6 [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"
Zach Reizner713a6782015-07-31 15:12:44 -070024#include "glworker.h"
Sean Paul98e73c82015-06-24 14:38:49 -070025
Zach Reizner713a6782015-07-31 15:12:44 -070026#include <algorithm>
Sean Paul98e73c82015-06-24 14:38:49 -070027#include <pthread.h>
Zach Reiznerd410f042015-07-28 15:33:07 -070028#include <sched.h>
Sean Paul98e73c82015-06-24 14:38:49 -070029#include <sstream>
30#include <stdlib.h>
31#include <time.h>
32#include <vector>
33
Sean Paul1c4c3262015-07-14 15:51:52 -040034#include <drm/drm_mode.h>
Sean Paul98e73c82015-06-24 14:38:49 -070035#include <cutils/log.h>
36#include <sync/sync.h>
37#include <utils/Trace.h>
38
Zach Reiznerd410f042015-07-28 15:33:07 -070039#define DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH 3
40
Sean Paul98e73c82015-06-24 14:38:49 -070041namespace android {
42
43DrmDisplayCompositor::DrmDisplayCompositor()
44 : drm_(NULL),
45 display_(-1),
46 worker_(this),
Sean Paul98e73c82015-06-24 14:38:49 -070047 initialized_(false),
Sean Pauldb7a17d2015-06-24 18:46:05 -070048 active_(false),
Zach Reizner713a6782015-07-31 15:12:44 -070049 framebuffer_index_(0),
Sean Paul98e73c82015-06-24 14:38:49 -070050 dump_frames_composited_(0),
51 dump_last_timestamp_ns_(0) {
52 struct timespec ts;
53 if (clock_gettime(CLOCK_MONOTONIC, &ts))
54 return;
55 dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
56}
57
58DrmDisplayCompositor::~DrmDisplayCompositor() {
59 if (!initialized_)
60 return;
61
62 worker_.Exit();
63
64 int ret = pthread_mutex_lock(&lock_);
65 if (ret)
66 ALOGE("Failed to acquire compositor lock %d", ret);
67
68 while (!composite_queue_.empty()) {
69 composite_queue_.front().reset();
70 composite_queue_.pop();
71 }
72 active_composition_.reset();
73
74 ret = pthread_mutex_unlock(&lock_);
75 if (ret)
76 ALOGE("Failed to acquire compositor lock %d", ret);
77
78 pthread_mutex_destroy(&lock_);
79}
80
81int DrmDisplayCompositor::Init(DrmResources *drm, int display) {
82 drm_ = drm;
83 display_ = display;
84
85 int ret = pthread_mutex_init(&lock_, NULL);
86 if (ret) {
87 ALOGE("Failed to initialize drm compositor lock %d\n", ret);
88 return ret;
89 }
90 ret = worker_.Init();
91 if (ret) {
92 pthread_mutex_destroy(&lock_);
93 ALOGE("Failed to initialize compositor worker %d\n", ret);
94 return ret;
95 }
96
97 initialized_ = true;
98 return 0;
99}
100
101int DrmDisplayCompositor::QueueComposition(
102 std::unique_ptr<DrmDisplayComposition> composition) {
Sean Paulacb2a442015-06-24 18:43:01 -0700103 switch (composition->type()) {
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700104 case DRM_COMPOSITION_TYPE_FRAME:
105 if (!active_)
106 return -ENODEV;
107 break;
108 case DRM_COMPOSITION_TYPE_DPMS:
109 /*
110 * Update the state as soon as we get it so we can start/stop queuing
111 * frames asap.
112 */
113 active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON);
114 break;
115 case DRM_COMPOSITION_TYPE_EMPTY:
116 return 0;
117 default:
118 ALOGE("Unknown composition type %d/%d", composition->type(), display_);
119 return -ENOENT;
Sean Paulacb2a442015-06-24 18:43:01 -0700120 }
Sean Paul98e73c82015-06-24 14:38:49 -0700121
122 int ret = pthread_mutex_lock(&lock_);
123 if (ret) {
124 ALOGE("Failed to acquire compositor lock %d", ret);
125 return ret;
126 }
127
Zach Reiznerd410f042015-07-28 15:33:07 -0700128 // Block the queue if it gets too large. Otherwise, SurfaceFlinger will start
129 // to eat our buffer handles when we get about 1 second behind.
130 while (composite_queue_.size() >= DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH) {
131 pthread_mutex_unlock(&lock_);
132 sched_yield();
133 pthread_mutex_lock(&lock_);
134 }
135
Sean Paul98e73c82015-06-24 14:38:49 -0700136 composite_queue_.push(std::move(composition));
137
138 ret = pthread_mutex_unlock(&lock_);
139 if (ret) {
140 ALOGE("Failed to release compositor lock %d", ret);
141 return ret;
142 }
143
144 worker_.Signal();
145 return 0;
146}
147
Zach Reizner713a6782015-07-31 15:12:44 -0700148static bool drm_composition_layer_has_plane(
149 const DrmCompositionLayer_t &comp_layer) {
150 if (comp_layer.plane != NULL)
151 if (comp_layer.plane->type() == DRM_PLANE_TYPE_OVERLAY ||
152 comp_layer.plane->type() == DRM_PLANE_TYPE_PRIMARY)
153 return true;
154 return false;
155}
156
157static bool drm_composition_layer_has_no_plane(
158 const DrmCompositionLayer_t &comp_layer) {
159 return comp_layer.plane == NULL;
160}
161
162int DrmDisplayCompositor::ApplyPreComposite(
163 DrmDisplayComposition *display_comp) {
164 int ret = 0;
165 DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
166
Zach Reizner713a6782015-07-31 15:12:44 -0700167 DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
168 if (connector == NULL) {
169 ALOGE("Failed to determine display mode: no connector for display %d",
170 display_);
171 return -ENODEV;
172 }
173
174 const DrmMode &mode = connector->active_mode();
175 DrmFramebuffer &fb = framebuffers_[framebuffer_index_];
176 ret = fb.WaitReleased(-1);
177 if (ret) {
178 ALOGE("Failed to wait for framebuffer release %d", ret);
179 return ret;
180 }
181 fb.set_release_fence_fd(-1);
182 if (!fb.Allocate(mode.h_display(), mode.v_display())) {
183 ALOGE("Failed to allocate framebuffer with size %dx%d", mode.h_display(),
184 mode.v_display());
185 return -ENOMEM;
186 }
187
Zach Reiznerb44fd102015-08-07 16:00:01 -0700188 std::vector<hwc_layer_1_t> pre_comp_layers;
189 for (auto &comp_layer : *layers) {
190 if (comp_layer.plane == NULL) {
191 pre_comp_layers.push_back(comp_layer.layer);
192 pre_comp_layers.back().handle = comp_layer.handle;
193 comp_layer.layer.acquireFenceFd = -1;
194 }
195 }
196
Zach Reizner8d63e7f2015-08-20 14:52:12 -0700197 ret = pre_compositor_->Composite(pre_comp_layers.data(),
198 pre_comp_layers.size(), fb.buffer());
199 pre_compositor_->Finish();
Zach Reiznerb44fd102015-08-07 16:00:01 -0700200
201 for (auto &pre_comp_layer : pre_comp_layers) {
202 if (pre_comp_layer.acquireFenceFd >= 0) {
203 close(pre_comp_layer.acquireFenceFd);
204 pre_comp_layer.acquireFenceFd = -1;
205 }
206 }
207
Zach Reizner713a6782015-07-31 15:12:44 -0700208 if (ret) {
209 ALOGE("Failed to composite layers");
210 return ret;
211 }
212
Zach Reizner09807052015-08-13 14:53:41 -0700213 DrmCompositionLayer_t &pre_comp_layer =
214 layers->at(display_comp->pre_composition_layer_index());
215 ret = display_comp->importer()->ImportBuffer(fb.buffer()->handle,
216 &pre_comp_layer.bo);
217 if (ret) {
218 ALOGE("Failed to import handle of layer %d", ret);
219 return ret;
220 }
221 hwc_layer_1_t &pre_comp_output_layer = pre_comp_layer.layer;
Zach Reizner713a6782015-07-31 15:12:44 -0700222 pre_comp_output_layer.handle = fb.buffer()->handle;
Zach Reizner713a6782015-07-31 15:12:44 -0700223 pre_comp_output_layer.visibleRegionScreen.rects =
224 &pre_comp_output_layer.displayFrame;
Zach Reizner713a6782015-07-31 15:12:44 -0700225 pre_comp_output_layer.sourceCropf.right =
226 pre_comp_output_layer.displayFrame.right = fb.buffer()->getWidth();
227 pre_comp_output_layer.sourceCropf.bottom =
228 pre_comp_output_layer.displayFrame.bottom = fb.buffer()->getHeight();
229
Zach Reizner713a6782015-07-31 15:12:44 -0700230 fb.set_release_fence_fd(pre_comp_output_layer.releaseFenceFd);
231 framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
232
Zach Reizner09807052015-08-13 14:53:41 -0700233 display_comp->RemoveNoPlaneLayers();
234 display_comp->SignalPreCompositionDone();
Zach Reizner713a6782015-07-31 15:12:44 -0700235 return ret;
236}
237
Sean Paul98e73c82015-06-24 14:38:49 -0700238int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
239 int ret = 0;
240
Zach Reizner09807052015-08-13 14:53:41 -0700241 if (display_comp->pre_composition_layer_index() >= 0) {
Zach Reizner713a6782015-07-31 15:12:44 -0700242 ret = ApplyPreComposite(display_comp);
243 if (ret)
244 return ret;
245 }
246
Sean Paul98e73c82015-06-24 14:38:49 -0700247 drmModePropertySetPtr pset = drmModePropertySetAlloc();
248 if (!pset) {
249 ALOGE("Failed to allocate property set");
250 return -ENOMEM;
251 }
252
Zach Reizner09807052015-08-13 14:53:41 -0700253 DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
Sean Paul98e73c82015-06-24 14:38:49 -0700254 for (DrmCompositionLayerVector_t::iterator iter = layers->begin();
255 iter != layers->end(); ++iter) {
256 hwc_layer_1_t *layer = &iter->layer;
257
258 if (layer->acquireFenceFd >= 0) {
259 ret = sync_wait(layer->acquireFenceFd, -1);
260 if (ret) {
261 ALOGE("Failed to wait for acquire %d/%d", layer->acquireFenceFd, ret);
262 drmModePropertySetFree(pset);
263 return ret;
264 }
265 close(layer->acquireFenceFd);
266 layer->acquireFenceFd = -1;
267 }
268
269 DrmPlane *plane = iter->plane;
Sean Paul2e46fbd2015-07-09 17:22:22 -0400270 DrmCrtc *crtc = iter->crtc;
271
272 // Disable the plane if there's no crtc
273 if (!crtc) {
Zach Reizner952f70a2015-07-17 14:10:03 -0700274 ret = drmModePropertySetAdd(pset, plane->id(),
275 plane->crtc_property().id(), 0) ||
276 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
277 0);
Sean Paul2e46fbd2015-07-09 17:22:22 -0400278 if (ret) {
279 ALOGE("Failed to add plane %d disable to pset", plane->id());
280 break;
281 }
282 continue;
283 }
284
Sean Paul1c4c3262015-07-14 15:51:52 -0400285 uint64_t rotation;
286 switch (layer->transform) {
287 case HWC_TRANSFORM_FLIP_H:
288 rotation = 1 << DRM_REFLECT_X;
289 break;
290 case HWC_TRANSFORM_FLIP_V:
291 rotation = 1 << DRM_REFLECT_Y;
292 break;
293 case HWC_TRANSFORM_ROT_90:
294 rotation = 1 << DRM_ROTATE_90;
295 break;
296 case HWC_TRANSFORM_ROT_180:
297 rotation = 1 << DRM_ROTATE_180;
298 break;
299 case HWC_TRANSFORM_ROT_270:
300 rotation = 1 << DRM_ROTATE_270;
301 break;
302 case 0:
303 rotation = 0;
304 break;
305 default:
306 ALOGE("Invalid transform value 0x%x given", layer->transform);
307 ret = -EINVAL;
308 break;
309 }
Zach Reizner952f70a2015-07-17 14:10:03 -0700310 if (ret)
311 break;
312
Sean Paul1c4c3262015-07-14 15:51:52 -0400313 // TODO: Once we have atomic test, this should fall back to GL
314 if (rotation && plane->rotation_property().id() == 0) {
315 ALOGE("Rotation is not supported on plane %d", plane->id());
316 ret = -EINVAL;
317 break;
318 }
319
Sean Paul98e73c82015-06-24 14:38:49 -0700320 ret =
321 drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
Sean Paul2e46fbd2015-07-09 17:22:22 -0400322 crtc->id()) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700323 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
324 iter->bo.fb_id) ||
325 drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
326 layer->displayFrame.left) ||
327 drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
328 layer->displayFrame.top) ||
329 drmModePropertySetAdd(
330 pset, plane->id(), plane->crtc_w_property().id(),
331 layer->displayFrame.right - layer->displayFrame.left) ||
332 drmModePropertySetAdd(
333 pset, plane->id(), plane->crtc_h_property().id(),
334 layer->displayFrame.bottom - layer->displayFrame.top) ||
335 drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
Sean Paul24323e82015-07-15 12:36:48 -0400336 (int)(layer->sourceCropf.left) << 16) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700337 drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
Sean Paul24323e82015-07-15 12:36:48 -0400338 (int)(layer->sourceCropf.top) << 16) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700339 drmModePropertySetAdd(
340 pset, plane->id(), plane->src_w_property().id(),
341 (int)(layer->sourceCropf.right - layer->sourceCropf.left) << 16) ||
342 drmModePropertySetAdd(
343 pset, plane->id(), plane->src_h_property().id(),
344 (int)(layer->sourceCropf.bottom - layer->sourceCropf.top) << 16);
345 if (ret) {
346 ALOGE("Failed to add plane %d to set", plane->id());
347 break;
348 }
Sean Paul1c4c3262015-07-14 15:51:52 -0400349
350 if (plane->rotation_property().id()) {
Zach Reizner952f70a2015-07-17 14:10:03 -0700351 ret = drmModePropertySetAdd(pset, plane->id(),
352 plane->rotation_property().id(), rotation);
Sean Paul1c4c3262015-07-14 15:51:52 -0400353 if (ret) {
354 ALOGE("Failed to add rotation property %d to plane %d",
355 plane->rotation_property().id(), plane->id());
356 break;
357 }
358 }
Sean Paul98e73c82015-06-24 14:38:49 -0700359 }
360
361 if (!ret) {
362 ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset);
363 if (ret)
364 ALOGE("Failed to commit pset ret=%d\n", ret);
365 }
366 if (pset)
367 drmModePropertySetFree(pset);
368
369 return ret;
370}
371
Sean Pauldb7a17d2015-06-24 18:46:05 -0700372int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
373 DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
374 if (!conn) {
375 ALOGE("Failed to get DrmConnector for display %d", display_);
376 return -ENODEV;
377 }
378
379 const DrmProperty &prop = conn->dpms_property();
380 int ret = drmModeConnectorSetProperty(drm_->fd(), conn->id(), prop.id(),
381 display_comp->dpms_mode());
382 if (ret) {
383 ALOGE("Failed to set DPMS property for connector %d", conn->id());
384 return ret;
385 }
386 return 0;
387}
388
Sean Paul98e73c82015-06-24 14:38:49 -0700389int DrmDisplayCompositor::Composite() {
390 ATRACE_CALL();
Zach Reizner09807052015-08-13 14:53:41 -0700391
392 if (!pre_compositor_) {
393 pre_compositor_.reset(new GLWorkerCompositor());
394 int ret = pre_compositor_->Init();
395 if (ret) {
396 ALOGE("Failed to initialize OpenGL compositor %d", ret);
397 return ret;
398 }
399 }
400
Sean Paul98e73c82015-06-24 14:38:49 -0700401 int ret = pthread_mutex_lock(&lock_);
402 if (ret) {
403 ALOGE("Failed to acquire compositor lock %d", ret);
404 return ret;
405 }
406 if (composite_queue_.empty()) {
407 ret = pthread_mutex_unlock(&lock_);
408 if (ret)
409 ALOGE("Failed to release compositor lock %d", ret);
410 return ret;
411 }
412
413 std::unique_ptr<DrmDisplayComposition> composition(
414 std::move(composite_queue_.front()));
415 composite_queue_.pop();
416
417 ret = pthread_mutex_unlock(&lock_);
418 if (ret) {
419 ALOGE("Failed to release compositor lock %d", ret);
420 return ret;
421 }
422
Sean Paulacb2a442015-06-24 18:43:01 -0700423 switch (composition->type()) {
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700424 case DRM_COMPOSITION_TYPE_FRAME:
425 ret = ApplyFrame(composition.get());
426 if (ret) {
427 ALOGE("Composite failed for display %d", display_);
428 return ret;
429 }
430 ++dump_frames_composited_;
431 break;
432 case DRM_COMPOSITION_TYPE_DPMS:
433 ret = ApplyDpms(composition.get());
434 if (ret)
435 ALOGE("Failed to apply dpms for display %d", display_);
Sean Paulacb2a442015-06-24 18:43:01 -0700436 return ret;
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700437 default:
438 ALOGE("Unknown composition type %d", composition->type());
439 return -EINVAL;
Sean Paul98e73c82015-06-24 14:38:49 -0700440 }
Sean Paul98e73c82015-06-24 14:38:49 -0700441
442 if (active_composition_)
443 active_composition_->FinishComposition();
444
Sean Paulfd37dfe2015-07-13 12:41:37 -0400445 ret = pthread_mutex_lock(&lock_);
446 if (ret)
447 ALOGE("Failed to acquire lock for active_composition swap");
448
Sean Paul98e73c82015-06-24 14:38:49 -0700449 active_composition_.swap(composition);
Sean Paulfd37dfe2015-07-13 12:41:37 -0400450
451 if (!ret)
452 ret = pthread_mutex_unlock(&lock_);
Zach Reizner952f70a2015-07-17 14:10:03 -0700453 if (ret)
454 ALOGE("Failed to release lock for active_composition swap");
Sean Paulfd37dfe2015-07-13 12:41:37 -0400455
Sean Paul98e73c82015-06-24 14:38:49 -0700456 return ret;
457}
458
459bool DrmDisplayCompositor::HaveQueuedComposites() const {
460 int ret = pthread_mutex_lock(&lock_);
461 if (ret) {
462 ALOGE("Failed to acquire compositor lock %d", ret);
463 return false;
464 }
465
466 bool empty_ret = !composite_queue_.empty();
467
468 ret = pthread_mutex_unlock(&lock_);
469 if (ret) {
470 ALOGE("Failed to release compositor lock %d", ret);
471 return false;
472 }
473
474 return empty_ret;
475}
476
477void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
478 uint64_t cur_ts;
479
480 int ret = pthread_mutex_lock(&lock_);
481 if (ret)
482 return;
483
484 uint64_t num_frames = dump_frames_composited_;
485 dump_frames_composited_ = 0;
486
487 struct timespec ts;
488 ret = clock_gettime(CLOCK_MONOTONIC, &ts);
489
Sean Paulfd37dfe2015-07-13 12:41:37 -0400490 DrmCompositionLayerVector_t layers;
491 if (active_composition_)
492 layers = *active_composition_->GetCompositionLayers();
493 else
494 ret = -EAGAIN;
495
Sean Paul98e73c82015-06-24 14:38:49 -0700496 ret |= pthread_mutex_unlock(&lock_);
497 if (ret)
498 return;
499
500 cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
501 uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
Stéphane Marchesin83959922015-07-13 12:35:41 -0700502 float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f;
Sean Paul98e73c82015-06-24 14:38:49 -0700503
504 *out << "--DrmDisplayCompositor[" << display_
505 << "]: num_frames=" << num_frames << " num_ms=" << num_ms
506 << " fps=" << fps << "\n";
507
508 dump_last_timestamp_ns_ = cur_ts;
Sean Paulfd37dfe2015-07-13 12:41:37 -0400509
510 *out << "---- DrmDisplayCompositor Layers: num=" << layers.size() << "\n";
511 for (DrmCompositionLayerVector_t::iterator iter = layers.begin();
512 iter != layers.end(); ++iter) {
513 hwc_layer_1_t *layer = &iter->layer;
514 DrmPlane *plane = iter->plane;
515
516 *out << "------ DrmDisplayCompositor Layer: plane=" << plane->id() << " ";
517
518 DrmCrtc *crtc = iter->crtc;
519 if (!crtc) {
520 *out << "disabled\n";
521 continue;
522 }
523
Zach Reizner952f70a2015-07-17 14:10:03 -0700524 *out << "crtc=" << crtc->id()
525 << " crtc[x/y/w/h]=" << layer->displayFrame.left << "/"
526 << layer->displayFrame.top << "/"
527 << layer->displayFrame.right - layer->displayFrame.left << "/"
528 << layer->displayFrame.bottom - layer->displayFrame.top << " "
529 << " src[x/y/w/h]=" << layer->sourceCropf.left << "/"
530 << layer->sourceCropf.top << "/"
531 << layer->sourceCropf.right - layer->sourceCropf.left << "/"
532 << layer->sourceCropf.bottom - layer->sourceCropf.top
533 << " transform=" << layer->transform << "\n";
Sean Paulfd37dfe2015-07-13 12:41:37 -0400534 }
Sean Paul98e73c82015-06-24 14:38:49 -0700535}
536}