blob: 7259d071ea31ae686bf2113122a3544417c63b12 [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>
28#include <sstream>
29#include <stdlib.h>
30#include <time.h>
31#include <vector>
32
Sean Paul1c4c3262015-07-14 15:51:52 -040033#include <drm/drm_mode.h>
Sean Paul98e73c82015-06-24 14:38:49 -070034#include <cutils/log.h>
35#include <sync/sync.h>
36#include <utils/Trace.h>
37
38namespace android {
39
40DrmDisplayCompositor::DrmDisplayCompositor()
41 : drm_(NULL),
42 display_(-1),
43 worker_(this),
44 frame_no_(0),
45 initialized_(false),
Sean Pauldb7a17d2015-06-24 18:46:05 -070046 active_(false),
Zach Reizner713a6782015-07-31 15:12:44 -070047 framebuffer_index_(0),
Sean Paul98e73c82015-06-24 14:38:49 -070048 dump_frames_composited_(0),
49 dump_last_timestamp_ns_(0) {
50 struct timespec ts;
51 if (clock_gettime(CLOCK_MONOTONIC, &ts))
52 return;
53 dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
54}
55
56DrmDisplayCompositor::~DrmDisplayCompositor() {
57 if (!initialized_)
58 return;
59
60 worker_.Exit();
61
62 int ret = pthread_mutex_lock(&lock_);
63 if (ret)
64 ALOGE("Failed to acquire compositor lock %d", ret);
65
66 while (!composite_queue_.empty()) {
67 composite_queue_.front().reset();
68 composite_queue_.pop();
69 }
70 active_composition_.reset();
71
72 ret = pthread_mutex_unlock(&lock_);
73 if (ret)
74 ALOGE("Failed to acquire compositor lock %d", ret);
75
76 pthread_mutex_destroy(&lock_);
77}
78
79int DrmDisplayCompositor::Init(DrmResources *drm, int display) {
80 drm_ = drm;
81 display_ = display;
82
83 int ret = pthread_mutex_init(&lock_, NULL);
84 if (ret) {
85 ALOGE("Failed to initialize drm compositor lock %d\n", ret);
86 return ret;
87 }
88 ret = worker_.Init();
89 if (ret) {
90 pthread_mutex_destroy(&lock_);
91 ALOGE("Failed to initialize compositor worker %d\n", ret);
92 return ret;
93 }
94
95 initialized_ = true;
96 return 0;
97}
98
99int DrmDisplayCompositor::QueueComposition(
100 std::unique_ptr<DrmDisplayComposition> composition) {
Sean Paulacb2a442015-06-24 18:43:01 -0700101 switch (composition->type()) {
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700102 case DRM_COMPOSITION_TYPE_FRAME:
103 if (!active_)
104 return -ENODEV;
105 break;
106 case DRM_COMPOSITION_TYPE_DPMS:
107 /*
108 * Update the state as soon as we get it so we can start/stop queuing
109 * frames asap.
110 */
111 active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON);
112 break;
113 case DRM_COMPOSITION_TYPE_EMPTY:
114 return 0;
115 default:
116 ALOGE("Unknown composition type %d/%d", composition->type(), display_);
117 return -ENOENT;
Sean Paulacb2a442015-06-24 18:43:01 -0700118 }
Sean Paul98e73c82015-06-24 14:38:49 -0700119
120 int ret = pthread_mutex_lock(&lock_);
121 if (ret) {
122 ALOGE("Failed to acquire compositor lock %d", ret);
123 return ret;
124 }
125
126 composite_queue_.push(std::move(composition));
127
128 ret = pthread_mutex_unlock(&lock_);
129 if (ret) {
130 ALOGE("Failed to release compositor lock %d", ret);
131 return ret;
132 }
133
134 worker_.Signal();
135 return 0;
136}
137
Zach Reizner713a6782015-07-31 15:12:44 -0700138static bool drm_composition_layer_has_plane(
139 const DrmCompositionLayer_t &comp_layer) {
140 if (comp_layer.plane != NULL)
141 if (comp_layer.plane->type() == DRM_PLANE_TYPE_OVERLAY ||
142 comp_layer.plane->type() == DRM_PLANE_TYPE_PRIMARY)
143 return true;
144 return false;
145}
146
147static bool drm_composition_layer_has_no_plane(
148 const DrmCompositionLayer_t &comp_layer) {
149 return comp_layer.plane == NULL;
150}
151
152int DrmDisplayCompositor::ApplyPreComposite(
153 DrmDisplayComposition *display_comp) {
154 int ret = 0;
155 DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
156
Zach Reizner713a6782015-07-31 15:12:44 -0700157 DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
158 if (connector == NULL) {
159 ALOGE("Failed to determine display mode: no connector for display %d",
160 display_);
161 return -ENODEV;
162 }
163
164 const DrmMode &mode = connector->active_mode();
165 DrmFramebuffer &fb = framebuffers_[framebuffer_index_];
166 ret = fb.WaitReleased(-1);
167 if (ret) {
168 ALOGE("Failed to wait for framebuffer release %d", ret);
169 return ret;
170 }
171 fb.set_release_fence_fd(-1);
172 if (!fb.Allocate(mode.h_display(), mode.v_display())) {
173 ALOGE("Failed to allocate framebuffer with size %dx%d", mode.h_display(),
174 mode.v_display());
175 return -ENOMEM;
176 }
177
Zach Reiznerb44fd102015-08-07 16:00:01 -0700178 std::vector<hwc_layer_1_t> pre_comp_layers;
179 for (auto &comp_layer : *layers) {
180 if (comp_layer.plane == NULL) {
181 pre_comp_layers.push_back(comp_layer.layer);
182 pre_comp_layers.back().handle = comp_layer.handle;
183 comp_layer.layer.acquireFenceFd = -1;
184 }
185 }
186
Zach Reizner713a6782015-07-31 15:12:44 -0700187 ret = pre_compositor_->CompositeAndFinish(
188 pre_comp_layers.data(), pre_comp_layers.size(), fb.buffer());
Zach Reiznerb44fd102015-08-07 16:00:01 -0700189
190 for (auto &pre_comp_layer : pre_comp_layers) {
191 if (pre_comp_layer.acquireFenceFd >= 0) {
192 close(pre_comp_layer.acquireFenceFd);
193 pre_comp_layer.acquireFenceFd = -1;
194 }
195 }
196
Zach Reizner713a6782015-07-31 15:12:44 -0700197 if (ret) {
198 ALOGE("Failed to composite layers");
199 return ret;
200 }
201
Zach Reizner09807052015-08-13 14:53:41 -0700202 DrmCompositionLayer_t &pre_comp_layer =
203 layers->at(display_comp->pre_composition_layer_index());
204 ret = display_comp->importer()->ImportBuffer(fb.buffer()->handle,
205 &pre_comp_layer.bo);
206 if (ret) {
207 ALOGE("Failed to import handle of layer %d", ret);
208 return ret;
209 }
210 hwc_layer_1_t &pre_comp_output_layer = pre_comp_layer.layer;
Zach Reizner713a6782015-07-31 15:12:44 -0700211 pre_comp_output_layer.handle = fb.buffer()->handle;
Zach Reizner713a6782015-07-31 15:12:44 -0700212 pre_comp_output_layer.visibleRegionScreen.rects =
213 &pre_comp_output_layer.displayFrame;
Zach Reizner713a6782015-07-31 15:12:44 -0700214 pre_comp_output_layer.sourceCropf.right =
215 pre_comp_output_layer.displayFrame.right = fb.buffer()->getWidth();
216 pre_comp_output_layer.sourceCropf.bottom =
217 pre_comp_output_layer.displayFrame.bottom = fb.buffer()->getHeight();
218
Zach Reizner713a6782015-07-31 15:12:44 -0700219 fb.set_release_fence_fd(pre_comp_output_layer.releaseFenceFd);
220 framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
221
Zach Reizner09807052015-08-13 14:53:41 -0700222 display_comp->RemoveNoPlaneLayers();
223 display_comp->SignalPreCompositionDone();
Zach Reizner713a6782015-07-31 15:12:44 -0700224 return ret;
225}
226
Sean Paul98e73c82015-06-24 14:38:49 -0700227int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
228 int ret = 0;
229
Zach Reizner09807052015-08-13 14:53:41 -0700230 if (display_comp->pre_composition_layer_index() >= 0) {
Zach Reizner713a6782015-07-31 15:12:44 -0700231 ret = ApplyPreComposite(display_comp);
232 if (ret)
233 return ret;
234 }
235
Sean Paul98e73c82015-06-24 14:38:49 -0700236 drmModePropertySetPtr pset = drmModePropertySetAlloc();
237 if (!pset) {
238 ALOGE("Failed to allocate property set");
239 return -ENOMEM;
240 }
241
Zach Reizner09807052015-08-13 14:53:41 -0700242 DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
Sean Paul98e73c82015-06-24 14:38:49 -0700243 for (DrmCompositionLayerVector_t::iterator iter = layers->begin();
244 iter != layers->end(); ++iter) {
245 hwc_layer_1_t *layer = &iter->layer;
246
247 if (layer->acquireFenceFd >= 0) {
248 ret = sync_wait(layer->acquireFenceFd, -1);
249 if (ret) {
250 ALOGE("Failed to wait for acquire %d/%d", layer->acquireFenceFd, ret);
251 drmModePropertySetFree(pset);
252 return ret;
253 }
254 close(layer->acquireFenceFd);
255 layer->acquireFenceFd = -1;
256 }
257
258 DrmPlane *plane = iter->plane;
Sean Paul2e46fbd2015-07-09 17:22:22 -0400259 DrmCrtc *crtc = iter->crtc;
260
261 // Disable the plane if there's no crtc
262 if (!crtc) {
Zach Reizner952f70a2015-07-17 14:10:03 -0700263 ret = drmModePropertySetAdd(pset, plane->id(),
264 plane->crtc_property().id(), 0) ||
265 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
266 0);
Sean Paul2e46fbd2015-07-09 17:22:22 -0400267 if (ret) {
268 ALOGE("Failed to add plane %d disable to pset", plane->id());
269 break;
270 }
271 continue;
272 }
273
Sean Paul1c4c3262015-07-14 15:51:52 -0400274 uint64_t rotation;
275 switch (layer->transform) {
276 case HWC_TRANSFORM_FLIP_H:
277 rotation = 1 << DRM_REFLECT_X;
278 break;
279 case HWC_TRANSFORM_FLIP_V:
280 rotation = 1 << DRM_REFLECT_Y;
281 break;
282 case HWC_TRANSFORM_ROT_90:
283 rotation = 1 << DRM_ROTATE_90;
284 break;
285 case HWC_TRANSFORM_ROT_180:
286 rotation = 1 << DRM_ROTATE_180;
287 break;
288 case HWC_TRANSFORM_ROT_270:
289 rotation = 1 << DRM_ROTATE_270;
290 break;
291 case 0:
292 rotation = 0;
293 break;
294 default:
295 ALOGE("Invalid transform value 0x%x given", layer->transform);
296 ret = -EINVAL;
297 break;
298 }
Zach Reizner952f70a2015-07-17 14:10:03 -0700299 if (ret)
300 break;
301
Sean Paul1c4c3262015-07-14 15:51:52 -0400302 // TODO: Once we have atomic test, this should fall back to GL
303 if (rotation && plane->rotation_property().id() == 0) {
304 ALOGE("Rotation is not supported on plane %d", plane->id());
305 ret = -EINVAL;
306 break;
307 }
308
Sean Paul98e73c82015-06-24 14:38:49 -0700309 ret =
310 drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
Sean Paul2e46fbd2015-07-09 17:22:22 -0400311 crtc->id()) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700312 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
313 iter->bo.fb_id) ||
314 drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
315 layer->displayFrame.left) ||
316 drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
317 layer->displayFrame.top) ||
318 drmModePropertySetAdd(
319 pset, plane->id(), plane->crtc_w_property().id(),
320 layer->displayFrame.right - layer->displayFrame.left) ||
321 drmModePropertySetAdd(
322 pset, plane->id(), plane->crtc_h_property().id(),
323 layer->displayFrame.bottom - layer->displayFrame.top) ||
324 drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
Sean Paul24323e82015-07-15 12:36:48 -0400325 (int)(layer->sourceCropf.left) << 16) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700326 drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
Sean Paul24323e82015-07-15 12:36:48 -0400327 (int)(layer->sourceCropf.top) << 16) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700328 drmModePropertySetAdd(
329 pset, plane->id(), plane->src_w_property().id(),
330 (int)(layer->sourceCropf.right - layer->sourceCropf.left) << 16) ||
331 drmModePropertySetAdd(
332 pset, plane->id(), plane->src_h_property().id(),
333 (int)(layer->sourceCropf.bottom - layer->sourceCropf.top) << 16);
334 if (ret) {
335 ALOGE("Failed to add plane %d to set", plane->id());
336 break;
337 }
Sean Paul1c4c3262015-07-14 15:51:52 -0400338
339 if (plane->rotation_property().id()) {
Zach Reizner952f70a2015-07-17 14:10:03 -0700340 ret = drmModePropertySetAdd(pset, plane->id(),
341 plane->rotation_property().id(), rotation);
Sean Paul1c4c3262015-07-14 15:51:52 -0400342 if (ret) {
343 ALOGE("Failed to add rotation property %d to plane %d",
344 plane->rotation_property().id(), plane->id());
345 break;
346 }
347 }
Sean Paul98e73c82015-06-24 14:38:49 -0700348 }
349
350 if (!ret) {
351 ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset);
352 if (ret)
353 ALOGE("Failed to commit pset ret=%d\n", ret);
354 }
355 if (pset)
356 drmModePropertySetFree(pset);
357
358 return ret;
359}
360
Sean Pauldb7a17d2015-06-24 18:46:05 -0700361int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
362 DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
363 if (!conn) {
364 ALOGE("Failed to get DrmConnector for display %d", display_);
365 return -ENODEV;
366 }
367
368 const DrmProperty &prop = conn->dpms_property();
369 int ret = drmModeConnectorSetProperty(drm_->fd(), conn->id(), prop.id(),
370 display_comp->dpms_mode());
371 if (ret) {
372 ALOGE("Failed to set DPMS property for connector %d", conn->id());
373 return ret;
374 }
375 return 0;
376}
377
Sean Paul98e73c82015-06-24 14:38:49 -0700378int DrmDisplayCompositor::Composite() {
379 ATRACE_CALL();
Zach Reizner09807052015-08-13 14:53:41 -0700380
381 if (!pre_compositor_) {
382 pre_compositor_.reset(new GLWorkerCompositor());
383 int ret = pre_compositor_->Init();
384 if (ret) {
385 ALOGE("Failed to initialize OpenGL compositor %d", ret);
386 return ret;
387 }
388 }
389
Sean Paul98e73c82015-06-24 14:38:49 -0700390 int ret = pthread_mutex_lock(&lock_);
391 if (ret) {
392 ALOGE("Failed to acquire compositor lock %d", ret);
393 return ret;
394 }
395 if (composite_queue_.empty()) {
396 ret = pthread_mutex_unlock(&lock_);
397 if (ret)
398 ALOGE("Failed to release compositor lock %d", ret);
399 return ret;
400 }
401
402 std::unique_ptr<DrmDisplayComposition> composition(
403 std::move(composite_queue_.front()));
404 composite_queue_.pop();
405
406 ret = pthread_mutex_unlock(&lock_);
407 if (ret) {
408 ALOGE("Failed to release compositor lock %d", ret);
409 return ret;
410 }
411
Sean Paulacb2a442015-06-24 18:43:01 -0700412 switch (composition->type()) {
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700413 case DRM_COMPOSITION_TYPE_FRAME:
414 ret = ApplyFrame(composition.get());
415 if (ret) {
416 ALOGE("Composite failed for display %d", display_);
417 return ret;
418 }
419 ++dump_frames_composited_;
420 break;
421 case DRM_COMPOSITION_TYPE_DPMS:
422 ret = ApplyDpms(composition.get());
423 if (ret)
424 ALOGE("Failed to apply dpms for display %d", display_);
Sean Paulacb2a442015-06-24 18:43:01 -0700425 return ret;
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700426 default:
427 ALOGE("Unknown composition type %d", composition->type());
428 return -EINVAL;
Sean Paul98e73c82015-06-24 14:38:49 -0700429 }
Sean Paul98e73c82015-06-24 14:38:49 -0700430
431 if (active_composition_)
432 active_composition_->FinishComposition();
433
Sean Paulfd37dfe2015-07-13 12:41:37 -0400434 ret = pthread_mutex_lock(&lock_);
435 if (ret)
436 ALOGE("Failed to acquire lock for active_composition swap");
437
Sean Paul98e73c82015-06-24 14:38:49 -0700438 active_composition_.swap(composition);
Sean Paulfd37dfe2015-07-13 12:41:37 -0400439
440 if (!ret)
441 ret = pthread_mutex_unlock(&lock_);
Zach Reizner952f70a2015-07-17 14:10:03 -0700442 if (ret)
443 ALOGE("Failed to release lock for active_composition swap");
Sean Paulfd37dfe2015-07-13 12:41:37 -0400444
Sean Paul98e73c82015-06-24 14:38:49 -0700445 return ret;
446}
447
448bool DrmDisplayCompositor::HaveQueuedComposites() const {
449 int ret = pthread_mutex_lock(&lock_);
450 if (ret) {
451 ALOGE("Failed to acquire compositor lock %d", ret);
452 return false;
453 }
454
455 bool empty_ret = !composite_queue_.empty();
456
457 ret = pthread_mutex_unlock(&lock_);
458 if (ret) {
459 ALOGE("Failed to release compositor lock %d", ret);
460 return false;
461 }
462
463 return empty_ret;
464}
465
466void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
467 uint64_t cur_ts;
468
469 int ret = pthread_mutex_lock(&lock_);
470 if (ret)
471 return;
472
473 uint64_t num_frames = dump_frames_composited_;
474 dump_frames_composited_ = 0;
475
476 struct timespec ts;
477 ret = clock_gettime(CLOCK_MONOTONIC, &ts);
478
Sean Paulfd37dfe2015-07-13 12:41:37 -0400479 DrmCompositionLayerVector_t layers;
480 if (active_composition_)
481 layers = *active_composition_->GetCompositionLayers();
482 else
483 ret = -EAGAIN;
484
Sean Paul98e73c82015-06-24 14:38:49 -0700485 ret |= pthread_mutex_unlock(&lock_);
486 if (ret)
487 return;
488
489 cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
490 uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
Stéphane Marchesin83959922015-07-13 12:35:41 -0700491 float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f;
Sean Paul98e73c82015-06-24 14:38:49 -0700492
493 *out << "--DrmDisplayCompositor[" << display_
494 << "]: num_frames=" << num_frames << " num_ms=" << num_ms
495 << " fps=" << fps << "\n";
496
497 dump_last_timestamp_ns_ = cur_ts;
Sean Paulfd37dfe2015-07-13 12:41:37 -0400498
499 *out << "---- DrmDisplayCompositor Layers: num=" << layers.size() << "\n";
500 for (DrmCompositionLayerVector_t::iterator iter = layers.begin();
501 iter != layers.end(); ++iter) {
502 hwc_layer_1_t *layer = &iter->layer;
503 DrmPlane *plane = iter->plane;
504
505 *out << "------ DrmDisplayCompositor Layer: plane=" << plane->id() << " ";
506
507 DrmCrtc *crtc = iter->crtc;
508 if (!crtc) {
509 *out << "disabled\n";
510 continue;
511 }
512
Zach Reizner952f70a2015-07-17 14:10:03 -0700513 *out << "crtc=" << crtc->id()
514 << " crtc[x/y/w/h]=" << layer->displayFrame.left << "/"
515 << layer->displayFrame.top << "/"
516 << layer->displayFrame.right - layer->displayFrame.left << "/"
517 << layer->displayFrame.bottom - layer->displayFrame.top << " "
518 << " src[x/y/w/h]=" << layer->sourceCropf.left << "/"
519 << layer->sourceCropf.top << "/"
520 << layer->sourceCropf.right - layer->sourceCropf.left << "/"
521 << layer->sourceCropf.bottom - layer->sourceCropf.top
522 << " transform=" << layer->transform << "\n";
Sean Paulfd37dfe2015-07-13 12:41:37 -0400523 }
Sean Paul98e73c82015-06-24 14:38:49 -0700524}
525}