blob: 9130085de2c98b7af0f4d5eba8004ddc6838af3b [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 Reizner8d63e7f2015-08-20 14:52:12 -0700187 ret = pre_compositor_->Composite(pre_comp_layers.data(),
188 pre_comp_layers.size(), fb.buffer());
189 pre_compositor_->Finish();
Zach Reiznerb44fd102015-08-07 16:00:01 -0700190
191 for (auto &pre_comp_layer : pre_comp_layers) {
192 if (pre_comp_layer.acquireFenceFd >= 0) {
193 close(pre_comp_layer.acquireFenceFd);
194 pre_comp_layer.acquireFenceFd = -1;
195 }
196 }
197
Zach Reizner713a6782015-07-31 15:12:44 -0700198 if (ret) {
199 ALOGE("Failed to composite layers");
200 return ret;
201 }
202
Zach Reizner09807052015-08-13 14:53:41 -0700203 DrmCompositionLayer_t &pre_comp_layer =
204 layers->at(display_comp->pre_composition_layer_index());
205 ret = display_comp->importer()->ImportBuffer(fb.buffer()->handle,
206 &pre_comp_layer.bo);
207 if (ret) {
208 ALOGE("Failed to import handle of layer %d", ret);
209 return ret;
210 }
211 hwc_layer_1_t &pre_comp_output_layer = pre_comp_layer.layer;
Zach Reizner713a6782015-07-31 15:12:44 -0700212 pre_comp_output_layer.handle = fb.buffer()->handle;
Zach Reizner713a6782015-07-31 15:12:44 -0700213 pre_comp_output_layer.visibleRegionScreen.rects =
214 &pre_comp_output_layer.displayFrame;
Zach Reizner713a6782015-07-31 15:12:44 -0700215 pre_comp_output_layer.sourceCropf.right =
216 pre_comp_output_layer.displayFrame.right = fb.buffer()->getWidth();
217 pre_comp_output_layer.sourceCropf.bottom =
218 pre_comp_output_layer.displayFrame.bottom = fb.buffer()->getHeight();
219
Zach Reizner713a6782015-07-31 15:12:44 -0700220 fb.set_release_fence_fd(pre_comp_output_layer.releaseFenceFd);
221 framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
222
Zach Reizner09807052015-08-13 14:53:41 -0700223 display_comp->RemoveNoPlaneLayers();
224 display_comp->SignalPreCompositionDone();
Zach Reizner713a6782015-07-31 15:12:44 -0700225 return ret;
226}
227
Sean Paul98e73c82015-06-24 14:38:49 -0700228int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
229 int ret = 0;
230
Zach Reizner09807052015-08-13 14:53:41 -0700231 if (display_comp->pre_composition_layer_index() >= 0) {
Zach Reizner713a6782015-07-31 15:12:44 -0700232 ret = ApplyPreComposite(display_comp);
233 if (ret)
234 return ret;
235 }
236
Sean Paul98e73c82015-06-24 14:38:49 -0700237 drmModePropertySetPtr pset = drmModePropertySetAlloc();
238 if (!pset) {
239 ALOGE("Failed to allocate property set");
240 return -ENOMEM;
241 }
242
Zach Reizner09807052015-08-13 14:53:41 -0700243 DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
Sean Paul98e73c82015-06-24 14:38:49 -0700244 for (DrmCompositionLayerVector_t::iterator iter = layers->begin();
245 iter != layers->end(); ++iter) {
246 hwc_layer_1_t *layer = &iter->layer;
247
248 if (layer->acquireFenceFd >= 0) {
249 ret = sync_wait(layer->acquireFenceFd, -1);
250 if (ret) {
251 ALOGE("Failed to wait for acquire %d/%d", layer->acquireFenceFd, ret);
252 drmModePropertySetFree(pset);
253 return ret;
254 }
255 close(layer->acquireFenceFd);
256 layer->acquireFenceFd = -1;
257 }
258
259 DrmPlane *plane = iter->plane;
Sean Paul2e46fbd2015-07-09 17:22:22 -0400260 DrmCrtc *crtc = iter->crtc;
261
262 // Disable the plane if there's no crtc
263 if (!crtc) {
Zach Reizner952f70a2015-07-17 14:10:03 -0700264 ret = drmModePropertySetAdd(pset, plane->id(),
265 plane->crtc_property().id(), 0) ||
266 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
267 0);
Sean Paul2e46fbd2015-07-09 17:22:22 -0400268 if (ret) {
269 ALOGE("Failed to add plane %d disable to pset", plane->id());
270 break;
271 }
272 continue;
273 }
274
Sean Paul1c4c3262015-07-14 15:51:52 -0400275 uint64_t rotation;
276 switch (layer->transform) {
277 case HWC_TRANSFORM_FLIP_H:
278 rotation = 1 << DRM_REFLECT_X;
279 break;
280 case HWC_TRANSFORM_FLIP_V:
281 rotation = 1 << DRM_REFLECT_Y;
282 break;
283 case HWC_TRANSFORM_ROT_90:
284 rotation = 1 << DRM_ROTATE_90;
285 break;
286 case HWC_TRANSFORM_ROT_180:
287 rotation = 1 << DRM_ROTATE_180;
288 break;
289 case HWC_TRANSFORM_ROT_270:
290 rotation = 1 << DRM_ROTATE_270;
291 break;
292 case 0:
293 rotation = 0;
294 break;
295 default:
296 ALOGE("Invalid transform value 0x%x given", layer->transform);
297 ret = -EINVAL;
298 break;
299 }
Zach Reizner952f70a2015-07-17 14:10:03 -0700300 if (ret)
301 break;
302
Sean Paul1c4c3262015-07-14 15:51:52 -0400303 // TODO: Once we have atomic test, this should fall back to GL
304 if (rotation && plane->rotation_property().id() == 0) {
305 ALOGE("Rotation is not supported on plane %d", plane->id());
306 ret = -EINVAL;
307 break;
308 }
309
Sean Paul98e73c82015-06-24 14:38:49 -0700310 ret =
311 drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
Sean Paul2e46fbd2015-07-09 17:22:22 -0400312 crtc->id()) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700313 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
314 iter->bo.fb_id) ||
315 drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
316 layer->displayFrame.left) ||
317 drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
318 layer->displayFrame.top) ||
319 drmModePropertySetAdd(
320 pset, plane->id(), plane->crtc_w_property().id(),
321 layer->displayFrame.right - layer->displayFrame.left) ||
322 drmModePropertySetAdd(
323 pset, plane->id(), plane->crtc_h_property().id(),
324 layer->displayFrame.bottom - layer->displayFrame.top) ||
325 drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
Sean Paul24323e82015-07-15 12:36:48 -0400326 (int)(layer->sourceCropf.left) << 16) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700327 drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
Sean Paul24323e82015-07-15 12:36:48 -0400328 (int)(layer->sourceCropf.top) << 16) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700329 drmModePropertySetAdd(
330 pset, plane->id(), plane->src_w_property().id(),
331 (int)(layer->sourceCropf.right - layer->sourceCropf.left) << 16) ||
332 drmModePropertySetAdd(
333 pset, plane->id(), plane->src_h_property().id(),
334 (int)(layer->sourceCropf.bottom - layer->sourceCropf.top) << 16);
335 if (ret) {
336 ALOGE("Failed to add plane %d to set", plane->id());
337 break;
338 }
Sean Paul1c4c3262015-07-14 15:51:52 -0400339
340 if (plane->rotation_property().id()) {
Zach Reizner952f70a2015-07-17 14:10:03 -0700341 ret = drmModePropertySetAdd(pset, plane->id(),
342 plane->rotation_property().id(), rotation);
Sean Paul1c4c3262015-07-14 15:51:52 -0400343 if (ret) {
344 ALOGE("Failed to add rotation property %d to plane %d",
345 plane->rotation_property().id(), plane->id());
346 break;
347 }
348 }
Sean Paul98e73c82015-06-24 14:38:49 -0700349 }
350
351 if (!ret) {
352 ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset);
353 if (ret)
354 ALOGE("Failed to commit pset ret=%d\n", ret);
355 }
356 if (pset)
357 drmModePropertySetFree(pset);
358
359 return ret;
360}
361
Sean Pauldb7a17d2015-06-24 18:46:05 -0700362int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
363 DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
364 if (!conn) {
365 ALOGE("Failed to get DrmConnector for display %d", display_);
366 return -ENODEV;
367 }
368
369 const DrmProperty &prop = conn->dpms_property();
370 int ret = drmModeConnectorSetProperty(drm_->fd(), conn->id(), prop.id(),
371 display_comp->dpms_mode());
372 if (ret) {
373 ALOGE("Failed to set DPMS property for connector %d", conn->id());
374 return ret;
375 }
376 return 0;
377}
378
Sean Paul98e73c82015-06-24 14:38:49 -0700379int DrmDisplayCompositor::Composite() {
380 ATRACE_CALL();
Zach Reizner09807052015-08-13 14:53:41 -0700381
382 if (!pre_compositor_) {
383 pre_compositor_.reset(new GLWorkerCompositor());
384 int ret = pre_compositor_->Init();
385 if (ret) {
386 ALOGE("Failed to initialize OpenGL compositor %d", ret);
387 return ret;
388 }
389 }
390
Sean Paul98e73c82015-06-24 14:38:49 -0700391 int ret = pthread_mutex_lock(&lock_);
392 if (ret) {
393 ALOGE("Failed to acquire compositor lock %d", ret);
394 return ret;
395 }
396 if (composite_queue_.empty()) {
397 ret = pthread_mutex_unlock(&lock_);
398 if (ret)
399 ALOGE("Failed to release compositor lock %d", ret);
400 return ret;
401 }
402
403 std::unique_ptr<DrmDisplayComposition> composition(
404 std::move(composite_queue_.front()));
405 composite_queue_.pop();
406
407 ret = pthread_mutex_unlock(&lock_);
408 if (ret) {
409 ALOGE("Failed to release compositor lock %d", ret);
410 return ret;
411 }
412
Sean Paulacb2a442015-06-24 18:43:01 -0700413 switch (composition->type()) {
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700414 case DRM_COMPOSITION_TYPE_FRAME:
415 ret = ApplyFrame(composition.get());
416 if (ret) {
417 ALOGE("Composite failed for display %d", display_);
418 return ret;
419 }
420 ++dump_frames_composited_;
421 break;
422 case DRM_COMPOSITION_TYPE_DPMS:
423 ret = ApplyDpms(composition.get());
424 if (ret)
425 ALOGE("Failed to apply dpms for display %d", display_);
Sean Paulacb2a442015-06-24 18:43:01 -0700426 return ret;
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700427 default:
428 ALOGE("Unknown composition type %d", composition->type());
429 return -EINVAL;
Sean Paul98e73c82015-06-24 14:38:49 -0700430 }
Sean Paul98e73c82015-06-24 14:38:49 -0700431
432 if (active_composition_)
433 active_composition_->FinishComposition();
434
Sean Paulfd37dfe2015-07-13 12:41:37 -0400435 ret = pthread_mutex_lock(&lock_);
436 if (ret)
437 ALOGE("Failed to acquire lock for active_composition swap");
438
Sean Paul98e73c82015-06-24 14:38:49 -0700439 active_composition_.swap(composition);
Sean Paulfd37dfe2015-07-13 12:41:37 -0400440
441 if (!ret)
442 ret = pthread_mutex_unlock(&lock_);
Zach Reizner952f70a2015-07-17 14:10:03 -0700443 if (ret)
444 ALOGE("Failed to release lock for active_composition swap");
Sean Paulfd37dfe2015-07-13 12:41:37 -0400445
Sean Paul98e73c82015-06-24 14:38:49 -0700446 return ret;
447}
448
449bool DrmDisplayCompositor::HaveQueuedComposites() const {
450 int ret = pthread_mutex_lock(&lock_);
451 if (ret) {
452 ALOGE("Failed to acquire compositor lock %d", ret);
453 return false;
454 }
455
456 bool empty_ret = !composite_queue_.empty();
457
458 ret = pthread_mutex_unlock(&lock_);
459 if (ret) {
460 ALOGE("Failed to release compositor lock %d", ret);
461 return false;
462 }
463
464 return empty_ret;
465}
466
467void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
468 uint64_t cur_ts;
469
470 int ret = pthread_mutex_lock(&lock_);
471 if (ret)
472 return;
473
474 uint64_t num_frames = dump_frames_composited_;
475 dump_frames_composited_ = 0;
476
477 struct timespec ts;
478 ret = clock_gettime(CLOCK_MONOTONIC, &ts);
479
Sean Paulfd37dfe2015-07-13 12:41:37 -0400480 DrmCompositionLayerVector_t layers;
481 if (active_composition_)
482 layers = *active_composition_->GetCompositionLayers();
483 else
484 ret = -EAGAIN;
485
Sean Paul98e73c82015-06-24 14:38:49 -0700486 ret |= pthread_mutex_unlock(&lock_);
487 if (ret)
488 return;
489
490 cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
491 uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
Stéphane Marchesin83959922015-07-13 12:35:41 -0700492 float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f;
Sean Paul98e73c82015-06-24 14:38:49 -0700493
494 *out << "--DrmDisplayCompositor[" << display_
495 << "]: num_frames=" << num_frames << " num_ms=" << num_ms
496 << " fps=" << fps << "\n";
497
498 dump_last_timestamp_ns_ = cur_ts;
Sean Paulfd37dfe2015-07-13 12:41:37 -0400499
500 *out << "---- DrmDisplayCompositor Layers: num=" << layers.size() << "\n";
501 for (DrmCompositionLayerVector_t::iterator iter = layers.begin();
502 iter != layers.end(); ++iter) {
503 hwc_layer_1_t *layer = &iter->layer;
504 DrmPlane *plane = iter->plane;
505
506 *out << "------ DrmDisplayCompositor Layer: plane=" << plane->id() << " ";
507
508 DrmCrtc *crtc = iter->crtc;
509 if (!crtc) {
510 *out << "disabled\n";
511 continue;
512 }
513
Zach Reizner952f70a2015-07-17 14:10:03 -0700514 *out << "crtc=" << crtc->id()
515 << " crtc[x/y/w/h]=" << layer->displayFrame.left << "/"
516 << layer->displayFrame.top << "/"
517 << layer->displayFrame.right - layer->displayFrame.left << "/"
518 << layer->displayFrame.bottom - layer->displayFrame.top << " "
519 << " src[x/y/w/h]=" << layer->sourceCropf.left << "/"
520 << layer->sourceCropf.top << "/"
521 << layer->sourceCropf.right - layer->sourceCropf.left << "/"
522 << layer->sourceCropf.bottom - layer->sourceCropf.top
523 << " transform=" << layer->transform << "\n";
Sean Paulfd37dfe2015-07-13 12:41:37 -0400524 }
Sean Paul98e73c82015-06-24 14:38:49 -0700525}
526}