blob: 20219235cbf7697d4f3d81b500f21d85bfab2045 [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 Reizner2317bb12015-07-16 10:14:26 -070024#include "glworker.h"
Sean Paul98e73c82015-06-24 14:38:49 -070025
Zach Reizner2317bb12015-07-16 10:14:26 -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),
47 frame_no_(0),
48 initialized_(false),
Sean Pauldb7a17d2015-06-24 18:46:05 -070049 active_(false),
Zach Reizner2317bb12015-07-16 10:14:26 -070050 framebuffer_index_(0),
Sean Paul98e73c82015-06-24 14:38:49 -070051 dump_frames_composited_(0),
52 dump_last_timestamp_ns_(0) {
53 struct timespec ts;
54 if (clock_gettime(CLOCK_MONOTONIC, &ts))
55 return;
56 dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
57}
58
59DrmDisplayCompositor::~DrmDisplayCompositor() {
60 if (!initialized_)
61 return;
62
63 worker_.Exit();
64
65 int ret = pthread_mutex_lock(&lock_);
66 if (ret)
67 ALOGE("Failed to acquire compositor lock %d", ret);
68
69 while (!composite_queue_.empty()) {
70 composite_queue_.front().reset();
71 composite_queue_.pop();
72 }
73 active_composition_.reset();
74
75 ret = pthread_mutex_unlock(&lock_);
76 if (ret)
77 ALOGE("Failed to acquire compositor lock %d", ret);
78
79 pthread_mutex_destroy(&lock_);
80}
81
82int DrmDisplayCompositor::Init(DrmResources *drm, int display) {
83 drm_ = drm;
84 display_ = display;
85
86 int ret = pthread_mutex_init(&lock_, NULL);
87 if (ret) {
88 ALOGE("Failed to initialize drm compositor lock %d\n", ret);
89 return ret;
90 }
91 ret = worker_.Init();
92 if (ret) {
93 pthread_mutex_destroy(&lock_);
94 ALOGE("Failed to initialize compositor worker %d\n", ret);
95 return ret;
96 }
97
98 initialized_ = true;
99 return 0;
100}
101
102int DrmDisplayCompositor::QueueComposition(
103 std::unique_ptr<DrmDisplayComposition> composition) {
Sean Paulacb2a442015-06-24 18:43:01 -0700104 switch (composition->type()) {
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700105 case DRM_COMPOSITION_TYPE_FRAME:
106 if (!active_)
107 return -ENODEV;
108 break;
109 case DRM_COMPOSITION_TYPE_DPMS:
110 /*
111 * Update the state as soon as we get it so we can start/stop queuing
112 * frames asap.
113 */
114 active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON);
115 break;
116 case DRM_COMPOSITION_TYPE_EMPTY:
117 return 0;
118 default:
119 ALOGE("Unknown composition type %d/%d", composition->type(), display_);
120 return -ENOENT;
Sean Paulacb2a442015-06-24 18:43:01 -0700121 }
Sean Paul98e73c82015-06-24 14:38:49 -0700122
123 int ret = pthread_mutex_lock(&lock_);
124 if (ret) {
125 ALOGE("Failed to acquire compositor lock %d", ret);
126 return ret;
127 }
128
Zach Reiznerd410f042015-07-28 15:33:07 -0700129 // Block the queue if it gets too large. Otherwise, SurfaceFlinger will start
130 // to eat our buffer handles when we get about 1 second behind.
131 while (composite_queue_.size() >= DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH) {
132 pthread_mutex_unlock(&lock_);
133 sched_yield();
134 pthread_mutex_lock(&lock_);
135 }
136
Sean Paul98e73c82015-06-24 14:38:49 -0700137 composite_queue_.push(std::move(composition));
138
139 ret = pthread_mutex_unlock(&lock_);
140 if (ret) {
141 ALOGE("Failed to release compositor lock %d", ret);
142 return ret;
143 }
144
145 worker_.Signal();
146 return 0;
147}
148
Zach Reizner2317bb12015-07-16 10:14:26 -0700149static bool drm_composition_layer_has_plane(
150 const DrmCompositionLayer_t &comp_layer) {
151 if (comp_layer.plane != NULL)
152 if (comp_layer.plane->type() == DRM_PLANE_TYPE_OVERLAY ||
153 comp_layer.plane->type() == DRM_PLANE_TYPE_PRIMARY)
154 return true;
155 return false;
156}
157
158static bool drm_composition_layer_has_no_plane(
159 const DrmCompositionLayer_t &comp_layer) {
160 return comp_layer.plane == NULL;
161}
162
163int DrmDisplayCompositor::ApplyPreComposite(
164 DrmDisplayComposition *display_comp) {
165 int ret = 0;
166 DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
167
168 auto last_layer = find_if(layers->rbegin(), layers->rend(),
169 drm_composition_layer_has_plane);
170 if (last_layer == layers->rend()) {
171 ALOGE("Frame has no overlays");
172 return -EINVAL;
173 }
174
175 DrmCompositionLayer_t &comp_layer = *last_layer;
176 DrmPlane *stolen_plane = NULL;
177 std::swap(stolen_plane, comp_layer.plane);
178
179 DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
180 if (connector == NULL) {
181 ALOGE("Failed to determine display mode: no connector for display %d",
182 display_);
183 return -ENODEV;
184 }
185
186 const DrmMode &mode = connector->active_mode();
187 DrmFramebuffer &fb = framebuffers_[framebuffer_index_];
188 ret = fb.WaitReleased(-1);
189 if (ret) {
190 ALOGE("Failed to wait for framebuffer release %d", ret);
191 return ret;
192 }
193 fb.set_release_fence_fd(-1);
194 if (!fb.Allocate(mode.h_display(), mode.v_display())) {
195 ALOGE("Failed to allocate framebuffer with size %dx%d", mode.h_display(),
196 mode.v_display());
197 return -ENOMEM;
198 }
199
200 std::vector<hwc_layer_1_t> pre_comp_layers;
201 for (const auto &comp_layer : *layers)
202 if (comp_layer.plane == NULL)
203 pre_comp_layers.push_back(comp_layer.layer);
204
205 if (!pre_compositor_) {
206 pre_compositor_.reset(new GLWorkerCompositor());
207 ret = pre_compositor_->Init();
208 if (ret) {
209 ALOGE("Failed to initialize OpenGL compositor %d", ret);
210 return ret;
211 }
212 }
213 ret = pre_compositor_->CompositeAndFinish(
214 pre_comp_layers.data(), pre_comp_layers.size(), fb.buffer());
215 if (ret) {
216 ALOGE("Failed to composite layers");
217 return ret;
218 }
219
220 layers->erase(std::remove_if(layers->begin(), layers->end(),
221 drm_composition_layer_has_no_plane),
222 layers->end());
223
224 hwc_layer_1_t pre_comp_output_layer;
225 memset(&pre_comp_output_layer, 0, sizeof(pre_comp_output_layer));
226 pre_comp_output_layer.compositionType = HWC_OVERLAY;
227 pre_comp_output_layer.handle = fb.buffer()->handle;
228 pre_comp_output_layer.acquireFenceFd = -1;
229 pre_comp_output_layer.releaseFenceFd = -1;
230 pre_comp_output_layer.planeAlpha = 0xff;
231 pre_comp_output_layer.visibleRegionScreen.numRects = 1;
232 pre_comp_output_layer.visibleRegionScreen.rects =
233 &pre_comp_output_layer.displayFrame;
234 pre_comp_output_layer.sourceCropf.top =
235 pre_comp_output_layer.displayFrame.top = 0;
236 pre_comp_output_layer.sourceCropf.left =
237 pre_comp_output_layer.displayFrame.left = 0;
238 pre_comp_output_layer.sourceCropf.right =
239 pre_comp_output_layer.displayFrame.right = fb.buffer()->getWidth();
240 pre_comp_output_layer.sourceCropf.bottom =
241 pre_comp_output_layer.displayFrame.bottom = fb.buffer()->getHeight();
242
243 ret = display_comp->AddLayer(&pre_comp_output_layer,
244 drm_->GetCrtcForDisplay(display_), stolen_plane);
245 if (ret) {
246 ALOGE("Failed to add composited layer %d", ret);
247 return ret;
248 }
249
250 fb.set_release_fence_fd(pre_comp_output_layer.releaseFenceFd);
251 framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
252
253 return ret;
254}
255
Sean Paul98e73c82015-06-24 14:38:49 -0700256int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
257 int ret = 0;
258
Zach Reizner2317bb12015-07-16 10:14:26 -0700259 DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
260 bool use_pre_comp = std::any_of(layers->begin(), layers->end(),
261 drm_composition_layer_has_no_plane);
262
263 if (use_pre_comp) {
264 ret = ApplyPreComposite(display_comp);
265 if (ret)
266 return ret;
267 }
268
Sean Paul98e73c82015-06-24 14:38:49 -0700269 drmModePropertySetPtr pset = drmModePropertySetAlloc();
270 if (!pset) {
271 ALOGE("Failed to allocate property set");
272 return -ENOMEM;
273 }
274
Sean Paul98e73c82015-06-24 14:38:49 -0700275 for (DrmCompositionLayerVector_t::iterator iter = layers->begin();
276 iter != layers->end(); ++iter) {
277 hwc_layer_1_t *layer = &iter->layer;
278
279 if (layer->acquireFenceFd >= 0) {
280 ret = sync_wait(layer->acquireFenceFd, -1);
281 if (ret) {
282 ALOGE("Failed to wait for acquire %d/%d", layer->acquireFenceFd, ret);
283 drmModePropertySetFree(pset);
284 return ret;
285 }
286 close(layer->acquireFenceFd);
287 layer->acquireFenceFd = -1;
288 }
289
290 DrmPlane *plane = iter->plane;
Sean Paul2e46fbd2015-07-09 17:22:22 -0400291 DrmCrtc *crtc = iter->crtc;
292
293 // Disable the plane if there's no crtc
294 if (!crtc) {
Zach Reizner952f70a2015-07-17 14:10:03 -0700295 ret = drmModePropertySetAdd(pset, plane->id(),
296 plane->crtc_property().id(), 0) ||
297 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
298 0);
Sean Paul2e46fbd2015-07-09 17:22:22 -0400299 if (ret) {
300 ALOGE("Failed to add plane %d disable to pset", plane->id());
301 break;
302 }
303 continue;
304 }
305
Sean Paul1c4c3262015-07-14 15:51:52 -0400306 uint64_t rotation;
307 switch (layer->transform) {
308 case HWC_TRANSFORM_FLIP_H:
309 rotation = 1 << DRM_REFLECT_X;
310 break;
311 case HWC_TRANSFORM_FLIP_V:
312 rotation = 1 << DRM_REFLECT_Y;
313 break;
314 case HWC_TRANSFORM_ROT_90:
315 rotation = 1 << DRM_ROTATE_90;
316 break;
317 case HWC_TRANSFORM_ROT_180:
318 rotation = 1 << DRM_ROTATE_180;
319 break;
320 case HWC_TRANSFORM_ROT_270:
321 rotation = 1 << DRM_ROTATE_270;
322 break;
323 case 0:
324 rotation = 0;
325 break;
326 default:
327 ALOGE("Invalid transform value 0x%x given", layer->transform);
328 ret = -EINVAL;
329 break;
330 }
Zach Reizner952f70a2015-07-17 14:10:03 -0700331 if (ret)
332 break;
333
Sean Paul1c4c3262015-07-14 15:51:52 -0400334 // TODO: Once we have atomic test, this should fall back to GL
335 if (rotation && plane->rotation_property().id() == 0) {
336 ALOGE("Rotation is not supported on plane %d", plane->id());
337 ret = -EINVAL;
338 break;
339 }
340
Sean Paul98e73c82015-06-24 14:38:49 -0700341 ret =
342 drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
Sean Paul2e46fbd2015-07-09 17:22:22 -0400343 crtc->id()) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700344 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
345 iter->bo.fb_id) ||
346 drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
347 layer->displayFrame.left) ||
348 drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
349 layer->displayFrame.top) ||
350 drmModePropertySetAdd(
351 pset, plane->id(), plane->crtc_w_property().id(),
352 layer->displayFrame.right - layer->displayFrame.left) ||
353 drmModePropertySetAdd(
354 pset, plane->id(), plane->crtc_h_property().id(),
355 layer->displayFrame.bottom - layer->displayFrame.top) ||
356 drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
Sean Paul24323e82015-07-15 12:36:48 -0400357 (int)(layer->sourceCropf.left) << 16) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700358 drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
Sean Paul24323e82015-07-15 12:36:48 -0400359 (int)(layer->sourceCropf.top) << 16) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700360 drmModePropertySetAdd(
361 pset, plane->id(), plane->src_w_property().id(),
362 (int)(layer->sourceCropf.right - layer->sourceCropf.left) << 16) ||
363 drmModePropertySetAdd(
364 pset, plane->id(), plane->src_h_property().id(),
365 (int)(layer->sourceCropf.bottom - layer->sourceCropf.top) << 16);
366 if (ret) {
367 ALOGE("Failed to add plane %d to set", plane->id());
368 break;
369 }
Sean Paul1c4c3262015-07-14 15:51:52 -0400370
371 if (plane->rotation_property().id()) {
Zach Reizner952f70a2015-07-17 14:10:03 -0700372 ret = drmModePropertySetAdd(pset, plane->id(),
373 plane->rotation_property().id(), rotation);
Sean Paul1c4c3262015-07-14 15:51:52 -0400374 if (ret) {
375 ALOGE("Failed to add rotation property %d to plane %d",
376 plane->rotation_property().id(), plane->id());
377 break;
378 }
379 }
Sean Paul98e73c82015-06-24 14:38:49 -0700380 }
381
382 if (!ret) {
383 ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset);
384 if (ret)
385 ALOGE("Failed to commit pset ret=%d\n", ret);
386 }
387 if (pset)
388 drmModePropertySetFree(pset);
389
390 return ret;
391}
392
Sean Pauldb7a17d2015-06-24 18:46:05 -0700393int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
394 DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
395 if (!conn) {
396 ALOGE("Failed to get DrmConnector for display %d", display_);
397 return -ENODEV;
398 }
399
400 const DrmProperty &prop = conn->dpms_property();
401 int ret = drmModeConnectorSetProperty(drm_->fd(), conn->id(), prop.id(),
402 display_comp->dpms_mode());
403 if (ret) {
404 ALOGE("Failed to set DPMS property for connector %d", conn->id());
405 return ret;
406 }
407 return 0;
408}
409
Sean Paul98e73c82015-06-24 14:38:49 -0700410int DrmDisplayCompositor::Composite() {
411 ATRACE_CALL();
412 int ret = pthread_mutex_lock(&lock_);
413 if (ret) {
414 ALOGE("Failed to acquire compositor lock %d", ret);
415 return ret;
416 }
417 if (composite_queue_.empty()) {
418 ret = pthread_mutex_unlock(&lock_);
419 if (ret)
420 ALOGE("Failed to release compositor lock %d", ret);
421 return ret;
422 }
423
424 std::unique_ptr<DrmDisplayComposition> composition(
425 std::move(composite_queue_.front()));
426 composite_queue_.pop();
427
428 ret = pthread_mutex_unlock(&lock_);
429 if (ret) {
430 ALOGE("Failed to release compositor lock %d", ret);
431 return ret;
432 }
433
Sean Paulacb2a442015-06-24 18:43:01 -0700434 switch (composition->type()) {
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700435 case DRM_COMPOSITION_TYPE_FRAME:
436 ret = ApplyFrame(composition.get());
437 if (ret) {
438 ALOGE("Composite failed for display %d", display_);
439 return ret;
440 }
441 ++dump_frames_composited_;
442 break;
443 case DRM_COMPOSITION_TYPE_DPMS:
444 ret = ApplyDpms(composition.get());
445 if (ret)
446 ALOGE("Failed to apply dpms for display %d", display_);
Sean Paulacb2a442015-06-24 18:43:01 -0700447 return ret;
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700448 default:
449 ALOGE("Unknown composition type %d", composition->type());
450 return -EINVAL;
Sean Paul98e73c82015-06-24 14:38:49 -0700451 }
Sean Paul98e73c82015-06-24 14:38:49 -0700452
453 if (active_composition_)
454 active_composition_->FinishComposition();
455
Sean Paulfd37dfe2015-07-13 12:41:37 -0400456 ret = pthread_mutex_lock(&lock_);
457 if (ret)
458 ALOGE("Failed to acquire lock for active_composition swap");
459
Sean Paul98e73c82015-06-24 14:38:49 -0700460 active_composition_.swap(composition);
Sean Paulfd37dfe2015-07-13 12:41:37 -0400461
462 if (!ret)
463 ret = pthread_mutex_unlock(&lock_);
Zach Reizner952f70a2015-07-17 14:10:03 -0700464 if (ret)
465 ALOGE("Failed to release lock for active_composition swap");
Sean Paulfd37dfe2015-07-13 12:41:37 -0400466
Sean Paul98e73c82015-06-24 14:38:49 -0700467 return ret;
468}
469
470bool DrmDisplayCompositor::HaveQueuedComposites() const {
471 int ret = pthread_mutex_lock(&lock_);
472 if (ret) {
473 ALOGE("Failed to acquire compositor lock %d", ret);
474 return false;
475 }
476
477 bool empty_ret = !composite_queue_.empty();
478
479 ret = pthread_mutex_unlock(&lock_);
480 if (ret) {
481 ALOGE("Failed to release compositor lock %d", ret);
482 return false;
483 }
484
485 return empty_ret;
486}
487
488void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
489 uint64_t cur_ts;
490
491 int ret = pthread_mutex_lock(&lock_);
492 if (ret)
493 return;
494
495 uint64_t num_frames = dump_frames_composited_;
496 dump_frames_composited_ = 0;
497
498 struct timespec ts;
499 ret = clock_gettime(CLOCK_MONOTONIC, &ts);
500
Sean Paulfd37dfe2015-07-13 12:41:37 -0400501 DrmCompositionLayerVector_t layers;
502 if (active_composition_)
503 layers = *active_composition_->GetCompositionLayers();
504 else
505 ret = -EAGAIN;
506
Sean Paul98e73c82015-06-24 14:38:49 -0700507 ret |= pthread_mutex_unlock(&lock_);
508 if (ret)
509 return;
510
511 cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
512 uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
Stéphane Marchesin83959922015-07-13 12:35:41 -0700513 float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f;
Sean Paul98e73c82015-06-24 14:38:49 -0700514
515 *out << "--DrmDisplayCompositor[" << display_
516 << "]: num_frames=" << num_frames << " num_ms=" << num_ms
517 << " fps=" << fps << "\n";
518
519 dump_last_timestamp_ns_ = cur_ts;
Sean Paulfd37dfe2015-07-13 12:41:37 -0400520
521 *out << "---- DrmDisplayCompositor Layers: num=" << layers.size() << "\n";
522 for (DrmCompositionLayerVector_t::iterator iter = layers.begin();
523 iter != layers.end(); ++iter) {
524 hwc_layer_1_t *layer = &iter->layer;
525 DrmPlane *plane = iter->plane;
526
527 *out << "------ DrmDisplayCompositor Layer: plane=" << plane->id() << " ";
528
529 DrmCrtc *crtc = iter->crtc;
530 if (!crtc) {
531 *out << "disabled\n";
532 continue;
533 }
534
Zach Reizner952f70a2015-07-17 14:10:03 -0700535 *out << "crtc=" << crtc->id()
536 << " crtc[x/y/w/h]=" << layer->displayFrame.left << "/"
537 << layer->displayFrame.top << "/"
538 << layer->displayFrame.right - layer->displayFrame.left << "/"
539 << layer->displayFrame.bottom - layer->displayFrame.top << " "
540 << " src[x/y/w/h]=" << layer->sourceCropf.left << "/"
541 << layer->sourceCropf.top << "/"
542 << layer->sourceCropf.right - layer->sourceCropf.left << "/"
543 << layer->sourceCropf.bottom - layer->sourceCropf.top
544 << " transform=" << layer->transform << "\n";
Sean Paulfd37dfe2015-07-13 12:41:37 -0400545 }
Sean Paul98e73c82015-06-24 14:38:49 -0700546}
547}