blob: 20779dd6d0db6d2da0a524745786015045cabb48 [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),
Sean Paul57355412015-09-19 09:14:34 -040049 needs_modeset_(false),
Zach Reizner713a6782015-07-31 15:12:44 -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;
Sean Paul57355412015-09-19 09:14:34 -0400116 case DRM_COMPOSITION_TYPE_MODESET:
117 break;
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700118 case DRM_COMPOSITION_TYPE_EMPTY:
119 return 0;
120 default:
121 ALOGE("Unknown composition type %d/%d", composition->type(), display_);
122 return -ENOENT;
Sean Paulacb2a442015-06-24 18:43:01 -0700123 }
Sean Paul98e73c82015-06-24 14:38:49 -0700124
125 int ret = pthread_mutex_lock(&lock_);
126 if (ret) {
127 ALOGE("Failed to acquire compositor lock %d", ret);
128 return ret;
129 }
130
Zach Reiznerd410f042015-07-28 15:33:07 -0700131 // Block the queue if it gets too large. Otherwise, SurfaceFlinger will start
132 // to eat our buffer handles when we get about 1 second behind.
133 while (composite_queue_.size() >= DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH) {
134 pthread_mutex_unlock(&lock_);
135 sched_yield();
136 pthread_mutex_lock(&lock_);
137 }
138
Sean Paul98e73c82015-06-24 14:38:49 -0700139 composite_queue_.push(std::move(composition));
140
141 ret = pthread_mutex_unlock(&lock_);
142 if (ret) {
143 ALOGE("Failed to release compositor lock %d", ret);
144 return ret;
145 }
146
147 worker_.Signal();
148 return 0;
149}
150
Zach Reizner713a6782015-07-31 15:12:44 -0700151static bool drm_composition_layer_has_plane(
Zach Reizner4a253652015-09-10 18:30:54 -0700152 const DrmCompositionLayer &comp_layer) {
Zach Reizner713a6782015-07-31 15:12:44 -0700153 if (comp_layer.plane != NULL)
154 if (comp_layer.plane->type() == DRM_PLANE_TYPE_OVERLAY ||
155 comp_layer.plane->type() == DRM_PLANE_TYPE_PRIMARY)
156 return true;
157 return false;
158}
159
160static bool drm_composition_layer_has_no_plane(
Zach Reizner4a253652015-09-10 18:30:54 -0700161 const DrmCompositionLayer &comp_layer) {
Zach Reizner713a6782015-07-31 15:12:44 -0700162 return comp_layer.plane == NULL;
163}
164
165int DrmDisplayCompositor::ApplyPreComposite(
166 DrmDisplayComposition *display_comp) {
167 int ret = 0;
Zach Reizner4a253652015-09-10 18:30:54 -0700168 std::vector<DrmCompositionLayer> *layers =
169 display_comp->GetCompositionLayers();
Zach Reizner713a6782015-07-31 15:12:44 -0700170
Zach Reizner713a6782015-07-31 15:12:44 -0700171 DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
172 if (connector == NULL) {
173 ALOGE("Failed to determine display mode: no connector for display %d",
174 display_);
175 return -ENODEV;
176 }
177
178 const DrmMode &mode = connector->active_mode();
179 DrmFramebuffer &fb = framebuffers_[framebuffer_index_];
Sean Pauld106b912015-09-29 00:56:00 -0400180 ret = fb.WaitReleased(fb.kReleaseWaitTimeoutMs);
Zach Reizner713a6782015-07-31 15:12:44 -0700181 if (ret) {
182 ALOGE("Failed to wait for framebuffer release %d", ret);
183 return ret;
184 }
185 fb.set_release_fence_fd(-1);
186 if (!fb.Allocate(mode.h_display(), mode.v_display())) {
187 ALOGE("Failed to allocate framebuffer with size %dx%d", mode.h_display(),
188 mode.v_display());
189 return -ENOMEM;
190 }
191
Zach Reizner4a253652015-09-10 18:30:54 -0700192 std::vector<DrmCompositionLayer> pre_comp_layers;
Zach Reiznerb44fd102015-08-07 16:00:01 -0700193 for (auto &comp_layer : *layers) {
194 if (comp_layer.plane == NULL) {
Zach Reizner4a253652015-09-10 18:30:54 -0700195 pre_comp_layers.emplace_back(std::move(comp_layer));
Zach Reiznerb44fd102015-08-07 16:00:01 -0700196 }
197 }
198
Zach Reizner8d63e7f2015-08-20 14:52:12 -0700199 ret = pre_compositor_->Composite(pre_comp_layers.data(),
200 pre_comp_layers.size(), fb.buffer());
201 pre_compositor_->Finish();
Zach Reiznerb44fd102015-08-07 16:00:01 -0700202
Zach Reizner713a6782015-07-31 15:12:44 -0700203 if (ret) {
204 ALOGE("Failed to composite layers");
205 return ret;
206 }
207
Zach Reizner4a253652015-09-10 18:30:54 -0700208 DrmCompositionLayer &pre_comp_layer =
Zach Reizner09807052015-08-13 14:53:41 -0700209 layers->at(display_comp->pre_composition_layer_index());
Zach Reizner4a253652015-09-10 18:30:54 -0700210 ret = pre_comp_layer.buffer.ImportBuffer(fb.buffer()->handle,
211 display_comp->importer());
Zach Reizner09807052015-08-13 14:53:41 -0700212 if (ret) {
213 ALOGE("Failed to import handle of layer %d", ret);
214 return ret;
215 }
Zach Reizner4a253652015-09-10 18:30:54 -0700216 pre_comp_layer.source_crop = DrmHwcRect<float>(0, 0, fb.buffer()->getWidth(),
217 fb.buffer()->getHeight());
218 pre_comp_layer.display_frame =
219 DrmHwcRect<int>(0, 0, fb.buffer()->getWidth(), fb.buffer()->getHeight());
Zach Reizner713a6782015-07-31 15:12:44 -0700220
Zach Reizner4a253652015-09-10 18:30:54 -0700221 // TODO(zachr) get a release fence
222 // fb.set_release_fence_fd(pre_comp_layer.release_fence.Release());
Zach Reizner713a6782015-07-31 15:12:44 -0700223 framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
224
Zach Reizner09807052015-08-13 14:53:41 -0700225 display_comp->RemoveNoPlaneLayers();
226 display_comp->SignalPreCompositionDone();
Zach Reizner713a6782015-07-31 15:12:44 -0700227 return ret;
228}
229
Sean Paul7b1e4bc2015-10-13 15:47:22 -0400230int DrmDisplayCompositor::DisablePlanes(DrmDisplayComposition *display_comp) {
231 drmModePropertySetPtr pset = drmModePropertySetAlloc();
232 if (!pset) {
233 ALOGE("Failed to allocate property set");
234 return -ENOMEM;
235 }
236
237 int ret;
238 std::vector<DrmCompositionLayer> *layers =
239 display_comp->GetCompositionLayers();
240 for (DrmCompositionLayer &layer : *layers) {
241 DrmPlane *plane = layer.plane;
242 ret = drmModePropertySetAdd(pset, plane->id(),
243 plane->crtc_property().id(), 0) ||
244 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
245 0);
246 if (ret) {
247 ALOGE("Failed to add plane %d disable to pset", plane->id());
248 drmModePropertySetFree(pset);
249 return ret;
250 }
251 }
252
253 ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset);
254 if (ret) {
255 ALOGE("Failed to commit pset ret=%d\n", ret);
256 drmModePropertySetFree(pset);
257 return ret;
258 }
259
260 drmModePropertySetFree(pset);
261 return 0;
262}
263
Sean Paul98e73c82015-06-24 14:38:49 -0700264int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
265 int ret = 0;
266
Zach Reizner09807052015-08-13 14:53:41 -0700267 if (display_comp->pre_composition_layer_index() >= 0) {
Zach Reizner713a6782015-07-31 15:12:44 -0700268 ret = ApplyPreComposite(display_comp);
269 if (ret)
270 return ret;
271 }
272
Sean Paul57355412015-09-19 09:14:34 -0400273 DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
274 if (!connector) {
275 ALOGE("Could not locate connector for display %d", display_);
276 return -ENODEV;
277 }
278 DrmCrtc *crtc = drm_->GetCrtcForDisplay(display_);
279 if (!crtc) {
280 ALOGE("Could not locate crtc for display %d", display_);
281 return -ENODEV;
282 }
283
Sean Paul98e73c82015-06-24 14:38:49 -0700284 drmModePropertySetPtr pset = drmModePropertySetAlloc();
285 if (!pset) {
286 ALOGE("Failed to allocate property set");
287 return -ENOMEM;
288 }
289
Sean Paul57355412015-09-19 09:14:34 -0400290 uint32_t blob_id = 0;
291 uint64_t old_blob_id;
292 if (needs_modeset_) {
293 DrmProperty old_mode;
294 ret = drm_->GetCrtcProperty(*crtc, crtc->mode_property().name().c_str(),
295 &old_mode);
296 if (ret) {
297 ALOGE("Failed to get old mode property from crtc %d", crtc->id());
298 drmModePropertySetFree(pset);
299 return ret;
300 }
301 ret = old_mode.value(&old_blob_id);
302 if (ret) {
303 ALOGE("Could not get old blob id value %d", ret);
304 drmModePropertySetFree(pset);
305 return ret;
306 }
307
308 struct drm_mode_modeinfo drm_mode;
309 memset(&drm_mode, 0, sizeof(drm_mode));
310 next_mode_.ToDrmModeModeInfo(&drm_mode);
311
312 ret = drm_->CreatePropertyBlob(&drm_mode, sizeof(struct drm_mode_modeinfo),
313 &blob_id);
314 if (ret) {
315 ALOGE("Failed to create mode property blob %d", ret);
316 drmModePropertySetFree(pset);
317 return ret;
318 }
319
320 ret = drmModePropertySetAdd(pset, crtc->id(), crtc->mode_property().id(),
321 blob_id) ||
322 drmModePropertySetAdd(pset, connector->id(),
323 connector->crtc_id_property().id(), crtc->id());
324 if (ret) {
325 ALOGE("Failed to add blob %d to pset", blob_id);
326 drmModePropertySetFree(pset);
327 drm_->DestroyPropertyBlob(blob_id);
328 return ret;
329 }
330 }
331
Zach Reizner4a253652015-09-10 18:30:54 -0700332 std::vector<DrmCompositionLayer> *layers =
333 display_comp->GetCompositionLayers();
334 for (DrmCompositionLayer &layer : *layers) {
335 int acquire_fence = layer.acquire_fence.get();
336 if (acquire_fence >= 0) {
Sean Paul971be152015-10-13 15:44:45 -0400337 for (int i = 0; i < kAcquireWaitTries; ++i) {
338 ret = sync_wait(acquire_fence, kAcquireWaitTimeoutMs);
339 if (ret)
340 ALOGW("Acquire fence %d wait %d failed (%d). Total time %d",
341 acquire_fence, i, ret, (i + 1) * kAcquireWaitTimeoutMs);
342 }
Sean Paul98e73c82015-06-24 14:38:49 -0700343 if (ret) {
Zach Reizner4a253652015-09-10 18:30:54 -0700344 ALOGE("Failed to wait for acquire %d/%d", acquire_fence, ret);
Sean Paul98e73c82015-06-24 14:38:49 -0700345 drmModePropertySetFree(pset);
Sean Paul57355412015-09-19 09:14:34 -0400346 drm_->DestroyPropertyBlob(blob_id);
Sean Paul98e73c82015-06-24 14:38:49 -0700347 return ret;
348 }
Zach Reizner4a253652015-09-10 18:30:54 -0700349 layer.acquire_fence.Close();
Sean Paul98e73c82015-06-24 14:38:49 -0700350 }
351
Zach Reizner4a253652015-09-10 18:30:54 -0700352 DrmPlane *plane = layer.plane;
Sean Paul2e46fbd2015-07-09 17:22:22 -0400353
354 // Disable the plane if there's no crtc
Sean Paul57355412015-09-19 09:14:34 -0400355 if (!layer.crtc) {
Zach Reizner952f70a2015-07-17 14:10:03 -0700356 ret = drmModePropertySetAdd(pset, plane->id(),
357 plane->crtc_property().id(), 0) ||
358 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
359 0);
Sean Paul2e46fbd2015-07-09 17:22:22 -0400360 if (ret) {
361 ALOGE("Failed to add plane %d disable to pset", plane->id());
362 break;
363 }
364 continue;
365 }
366
Zach Reizner4a253652015-09-10 18:30:54 -0700367 if (!layer.buffer) {
368 ALOGE("Expected a valid framebuffer for pset");
369 ret = -EINVAL;
370 break;
371 }
372
Sean Paul1c4c3262015-07-14 15:51:52 -0400373 uint64_t rotation;
Zach Reizner4a253652015-09-10 18:30:54 -0700374 switch (layer.transform) {
375 case DrmHwcTransform::kFlipH:
Sean Paul1c4c3262015-07-14 15:51:52 -0400376 rotation = 1 << DRM_REFLECT_X;
377 break;
Zach Reizner4a253652015-09-10 18:30:54 -0700378 case DrmHwcTransform::kFlipV:
Sean Paul1c4c3262015-07-14 15:51:52 -0400379 rotation = 1 << DRM_REFLECT_Y;
380 break;
Zach Reizner4a253652015-09-10 18:30:54 -0700381 case DrmHwcTransform::kRotate90:
Sean Paul1c4c3262015-07-14 15:51:52 -0400382 rotation = 1 << DRM_ROTATE_90;
383 break;
Zach Reizner4a253652015-09-10 18:30:54 -0700384 case DrmHwcTransform::kRotate180:
Sean Paul1c4c3262015-07-14 15:51:52 -0400385 rotation = 1 << DRM_ROTATE_180;
386 break;
Zach Reizner4a253652015-09-10 18:30:54 -0700387 case DrmHwcTransform::kRotate270:
Sean Paul1c4c3262015-07-14 15:51:52 -0400388 rotation = 1 << DRM_ROTATE_270;
389 break;
Zach Reizner4a253652015-09-10 18:30:54 -0700390 case DrmHwcTransform::kIdentity:
Sean Paul1c4c3262015-07-14 15:51:52 -0400391 rotation = 0;
392 break;
393 default:
Zach Reizner4a253652015-09-10 18:30:54 -0700394 ALOGE("Invalid transform value 0x%x given", layer.transform);
Sean Paul1c4c3262015-07-14 15:51:52 -0400395 ret = -EINVAL;
396 break;
397 }
Zach Reizner952f70a2015-07-17 14:10:03 -0700398 if (ret)
399 break;
400
Sean Paul1c4c3262015-07-14 15:51:52 -0400401 // TODO: Once we have atomic test, this should fall back to GL
402 if (rotation && plane->rotation_property().id() == 0) {
403 ALOGE("Rotation is not supported on plane %d", plane->id());
404 ret = -EINVAL;
405 break;
406 }
407
Sean Paul98e73c82015-06-24 14:38:49 -0700408 ret =
409 drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
Sean Paul57355412015-09-19 09:14:34 -0400410 layer.crtc->id()) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700411 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
Zach Reizner4a253652015-09-10 18:30:54 -0700412 layer.buffer->fb_id) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700413 drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
Zach Reizner4a253652015-09-10 18:30:54 -0700414 layer.display_frame.left) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700415 drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
Zach Reizner4a253652015-09-10 18:30:54 -0700416 layer.display_frame.top) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700417 drmModePropertySetAdd(
418 pset, plane->id(), plane->crtc_w_property().id(),
Zach Reizner4a253652015-09-10 18:30:54 -0700419 layer.display_frame.right - layer.display_frame.left) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700420 drmModePropertySetAdd(
421 pset, plane->id(), plane->crtc_h_property().id(),
Zach Reizner4a253652015-09-10 18:30:54 -0700422 layer.display_frame.bottom - layer.display_frame.top) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700423 drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
Zach Reizner4a253652015-09-10 18:30:54 -0700424 (int)(layer.source_crop.left) << 16) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700425 drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
Zach Reizner4a253652015-09-10 18:30:54 -0700426 (int)(layer.source_crop.top) << 16) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700427 drmModePropertySetAdd(
428 pset, plane->id(), plane->src_w_property().id(),
Zach Reizner4a253652015-09-10 18:30:54 -0700429 (int)(layer.source_crop.right - layer.source_crop.left) << 16) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700430 drmModePropertySetAdd(
431 pset, plane->id(), plane->src_h_property().id(),
Zach Reizner4a253652015-09-10 18:30:54 -0700432 (int)(layer.source_crop.bottom - layer.source_crop.top) << 16);
Sean Paul98e73c82015-06-24 14:38:49 -0700433 if (ret) {
434 ALOGE("Failed to add plane %d to set", plane->id());
435 break;
436 }
Sean Paul1c4c3262015-07-14 15:51:52 -0400437
438 if (plane->rotation_property().id()) {
Zach Reizner952f70a2015-07-17 14:10:03 -0700439 ret = drmModePropertySetAdd(pset, plane->id(),
440 plane->rotation_property().id(), rotation);
Sean Paul1c4c3262015-07-14 15:51:52 -0400441 if (ret) {
442 ALOGE("Failed to add rotation property %d to plane %d",
443 plane->rotation_property().id(), plane->id());
444 break;
445 }
446 }
Sean Paul98e73c82015-06-24 14:38:49 -0700447 }
448
449 if (!ret) {
Sean Paul57355412015-09-19 09:14:34 -0400450 ret = drmModePropertySetCommit(drm_->fd(), DRM_MODE_ATOMIC_ALLOW_MODESET,
451 drm_, pset);
452 if (ret) {
Sean Paul98e73c82015-06-24 14:38:49 -0700453 ALOGE("Failed to commit pset ret=%d\n", ret);
Sean Paul57355412015-09-19 09:14:34 -0400454 drmModePropertySetFree(pset);
455 if (needs_modeset_)
456 drm_->DestroyPropertyBlob(blob_id);
457 return ret;
458 }
Sean Paul98e73c82015-06-24 14:38:49 -0700459 }
460 if (pset)
461 drmModePropertySetFree(pset);
462
Sean Paul57355412015-09-19 09:14:34 -0400463 if (needs_modeset_) {
464 ret = drm_->DestroyPropertyBlob(old_blob_id);
465 if (ret) {
466 ALOGE("Failed to destroy old mode property blob %lld/%d", old_blob_id,
467 ret);
468 return ret;
469 }
470
471 /* TODO: Add dpms to the pset when the kernel supports it */
472 ret = ApplyDpms(display_comp);
473 if (ret) {
474 ALOGE("Failed to apply DPMS after modeset %d\n", ret);
475 return ret;
476 }
477
478 connector->set_active_mode(next_mode_);
479 needs_modeset_ = false;
480 }
481
Sean Paul98e73c82015-06-24 14:38:49 -0700482 return ret;
483}
484
Sean Pauldb7a17d2015-06-24 18:46:05 -0700485int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
486 DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
487 if (!conn) {
488 ALOGE("Failed to get DrmConnector for display %d", display_);
489 return -ENODEV;
490 }
491
492 const DrmProperty &prop = conn->dpms_property();
493 int ret = drmModeConnectorSetProperty(drm_->fd(), conn->id(), prop.id(),
494 display_comp->dpms_mode());
495 if (ret) {
496 ALOGE("Failed to set DPMS property for connector %d", conn->id());
497 return ret;
498 }
499 return 0;
500}
501
Sean Paul98e73c82015-06-24 14:38:49 -0700502int DrmDisplayCompositor::Composite() {
503 ATRACE_CALL();
Zach Reizner09807052015-08-13 14:53:41 -0700504
505 if (!pre_compositor_) {
506 pre_compositor_.reset(new GLWorkerCompositor());
507 int ret = pre_compositor_->Init();
508 if (ret) {
509 ALOGE("Failed to initialize OpenGL compositor %d", ret);
510 return ret;
511 }
512 }
513
Sean Paul98e73c82015-06-24 14:38:49 -0700514 int ret = pthread_mutex_lock(&lock_);
515 if (ret) {
516 ALOGE("Failed to acquire compositor lock %d", ret);
517 return ret;
518 }
519 if (composite_queue_.empty()) {
520 ret = pthread_mutex_unlock(&lock_);
521 if (ret)
522 ALOGE("Failed to release compositor lock %d", ret);
523 return ret;
524 }
525
526 std::unique_ptr<DrmDisplayComposition> composition(
527 std::move(composite_queue_.front()));
Zach Reizner4a253652015-09-10 18:30:54 -0700528
Sean Paul98e73c82015-06-24 14:38:49 -0700529 composite_queue_.pop();
530
531 ret = pthread_mutex_unlock(&lock_);
532 if (ret) {
533 ALOGE("Failed to release compositor lock %d", ret);
534 return ret;
535 }
536
Sean Paulacb2a442015-06-24 18:43:01 -0700537 switch (composition->type()) {
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700538 case DRM_COMPOSITION_TYPE_FRAME:
539 ret = ApplyFrame(composition.get());
540 if (ret) {
541 ALOGE("Composite failed for display %d", display_);
Sean Paul7b1e4bc2015-10-13 15:47:22 -0400542
543 // Disable the hw used by the last active composition. This allows us to
544 // signal the release fences from that composition to avoid hanging.
545 if (DisablePlanes(active_composition_.get()))
546 return ret;
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700547 }
548 ++dump_frames_composited_;
549 break;
550 case DRM_COMPOSITION_TYPE_DPMS:
551 ret = ApplyDpms(composition.get());
552 if (ret)
553 ALOGE("Failed to apply dpms for display %d", display_);
Sean Paulacb2a442015-06-24 18:43:01 -0700554 return ret;
Sean Paul57355412015-09-19 09:14:34 -0400555 case DRM_COMPOSITION_TYPE_MODESET:
556 next_mode_ = composition->display_mode();
557 needs_modeset_ = true;
558 return 0;
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700559 default:
560 ALOGE("Unknown composition type %d", composition->type());
561 return -EINVAL;
Sean Paul98e73c82015-06-24 14:38:49 -0700562 }
Sean Paul98e73c82015-06-24 14:38:49 -0700563
564 if (active_composition_)
565 active_composition_->FinishComposition();
566
Sean Paulfd37dfe2015-07-13 12:41:37 -0400567 ret = pthread_mutex_lock(&lock_);
568 if (ret)
569 ALOGE("Failed to acquire lock for active_composition swap");
570
Sean Paul98e73c82015-06-24 14:38:49 -0700571 active_composition_.swap(composition);
Sean Paulfd37dfe2015-07-13 12:41:37 -0400572
573 if (!ret)
574 ret = pthread_mutex_unlock(&lock_);
Zach Reizner952f70a2015-07-17 14:10:03 -0700575 if (ret)
576 ALOGE("Failed to release lock for active_composition swap");
Sean Paulfd37dfe2015-07-13 12:41:37 -0400577
Sean Paul98e73c82015-06-24 14:38:49 -0700578 return ret;
579}
580
581bool DrmDisplayCompositor::HaveQueuedComposites() const {
582 int ret = pthread_mutex_lock(&lock_);
583 if (ret) {
584 ALOGE("Failed to acquire compositor lock %d", ret);
585 return false;
586 }
587
588 bool empty_ret = !composite_queue_.empty();
589
590 ret = pthread_mutex_unlock(&lock_);
591 if (ret) {
592 ALOGE("Failed to release compositor lock %d", ret);
593 return false;
594 }
595
596 return empty_ret;
597}
598
Zach Reizner4a253652015-09-10 18:30:54 -0700599struct DrmDumpLayer {
600 int plane_id;
601 int crtc_id;
602 DrmHwcTransform transform;
603 DrmHwcRect<float> source_crop;
604 DrmHwcRect<int> display_frame;
605
606 DrmDumpLayer(DrmCompositionLayer &rhs)
607 : plane_id(rhs.plane->id()),
608 crtc_id(rhs.crtc ? rhs.crtc->id() : -1),
609 transform(rhs.transform),
610 source_crop(rhs.source_crop),
611 display_frame(rhs.display_frame) {
612 }
613};
614
Sean Paul98e73c82015-06-24 14:38:49 -0700615void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
616 uint64_t cur_ts;
617
618 int ret = pthread_mutex_lock(&lock_);
619 if (ret)
620 return;
621
622 uint64_t num_frames = dump_frames_composited_;
623 dump_frames_composited_ = 0;
624
625 struct timespec ts;
626 ret = clock_gettime(CLOCK_MONOTONIC, &ts);
627
Zach Reizner4a253652015-09-10 18:30:54 -0700628 std::vector<DrmCompositionLayer> *input_layers =
629 active_composition_->GetCompositionLayers();
630 std::vector<DrmDumpLayer> layers;
Sean Paulfd37dfe2015-07-13 12:41:37 -0400631 if (active_composition_)
Zach Reizner4a253652015-09-10 18:30:54 -0700632 layers.insert(layers.begin(), input_layers->begin(), input_layers->end());
Sean Paulfd37dfe2015-07-13 12:41:37 -0400633 else
634 ret = -EAGAIN;
635
Sean Paul98e73c82015-06-24 14:38:49 -0700636 ret |= pthread_mutex_unlock(&lock_);
637 if (ret)
638 return;
639
640 cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
641 uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
Stéphane Marchesin83959922015-07-13 12:35:41 -0700642 float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f;
Sean Paul98e73c82015-06-24 14:38:49 -0700643
644 *out << "--DrmDisplayCompositor[" << display_
645 << "]: num_frames=" << num_frames << " num_ms=" << num_ms
646 << " fps=" << fps << "\n";
647
648 dump_last_timestamp_ns_ = cur_ts;
Sean Paulfd37dfe2015-07-13 12:41:37 -0400649
650 *out << "---- DrmDisplayCompositor Layers: num=" << layers.size() << "\n";
Zach Reizner4a253652015-09-10 18:30:54 -0700651 for (std::vector<DrmDumpLayer>::iterator iter = layers.begin();
Sean Paulfd37dfe2015-07-13 12:41:37 -0400652 iter != layers.end(); ++iter) {
Zach Reizner4a253652015-09-10 18:30:54 -0700653 *out << "------ DrmDisplayCompositor Layer: plane=" << iter->plane_id
654 << " ";
Sean Paulfd37dfe2015-07-13 12:41:37 -0400655
Zach Reizner4a253652015-09-10 18:30:54 -0700656 if (iter->crtc_id < 0) {
Sean Paulfd37dfe2015-07-13 12:41:37 -0400657 *out << "disabled\n";
658 continue;
659 }
660
Zach Reizner4a253652015-09-10 18:30:54 -0700661 *out << "crtc=" << iter->crtc_id
662 << " crtc[x/y/w/h]=" << iter->display_frame.left << "/"
663 << iter->display_frame.top << "/"
664 << iter->display_frame.right - iter->display_frame.left << "/"
665 << iter->display_frame.bottom - iter->display_frame.top << " "
666 << " src[x/y/w/h]=" << iter->source_crop.left << "/"
667 << iter->source_crop.top << "/"
668 << iter->source_crop.right - iter->source_crop.left << "/"
669 << iter->source_crop.bottom - iter->source_crop.top
670 << " transform=" << (uint32_t)iter->transform << "\n";
Sean Paulfd37dfe2015-07-13 12:41:37 -0400671 }
Sean Paul98e73c82015-06-24 14:38:49 -0700672}
673}