blob: 9f349c08cb68b8e36c5efbfc278b149ce2b8e9cd [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
26#include <pthread.h>
Zach Reiznerd410f042015-07-28 15:33:07 -070027#include <sched.h>
Sean Paul98e73c82015-06-24 14:38:49 -070028#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
Zach Reiznerd410f042015-07-28 15:33:07 -070038#define DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH 3
39
Sean Paul98e73c82015-06-24 14:38:49 -070040namespace android {
41
Zach Reizner92f8e632015-10-12 17:47:13 -070042void SquashState::Init(DrmHwcLayer *layers, size_t num_layers) {
43 generation_number_++;
44 valid_history_ = 0;
45 regions_.clear();
46 last_handles_.clear();
47
48 std::vector<DrmHwcRect<int>> in_rects;
49 for (size_t i = 0; i < num_layers; i++) {
50 DrmHwcLayer *layer = &layers[i];
51 in_rects.emplace_back(layer->display_frame);
52 last_handles_.push_back(layer->sf_handle);
53 }
54
55 std::vector<seperate_rects::RectSet<uint64_t, int>> out_regions;
56 seperate_rects::seperate_rects_64(in_rects, &out_regions);
57
58 for (const seperate_rects::RectSet<uint64_t, int> &out_region : out_regions) {
59 regions_.emplace_back();
60 Region &region = regions_.back();
61 region.rect = out_region.rect;
62 region.layer_refs = out_region.id_set.getBits();
63 }
64}
65
66void SquashState::GenerateHistory(DrmHwcLayer *layers,
67 std::vector<bool> &changed_regions) const {
68 std::bitset<kMaxLayers> changed_layers;
69 for (size_t i = 0; i < last_handles_.size(); i++) {
70 DrmHwcLayer *layer = &layers[i];
71 if (last_handles_[i] != layer->sf_handle) {
72 changed_layers.set(i);
73 }
74 }
75
76 changed_regions.resize(regions_.size());
77 for (size_t i = 0; i < regions_.size(); i++) {
78 changed_regions[i] = (regions_[i].layer_refs & changed_layers).any();
79 }
80}
81
82void SquashState::StableRegionsWithMarginalHistory(
83 const std::vector<bool> &changed_regions,
84 std::vector<bool> &stable_regions) const {
85 stable_regions.resize(regions_.size());
86 for (size_t i = 0; i < regions_.size(); i++) {
87 stable_regions[i] = !changed_regions[i] && is_stable(i);
88 }
89}
90
91void SquashState::RecordHistory(DrmHwcLayer *layers,
92 const std::vector<bool> &changed_regions) {
93 for (size_t i = 0; i < last_handles_.size(); i++) {
94 DrmHwcLayer *layer = &layers[i];
95 last_handles_[i] = layer->sf_handle;
96 }
97
98 for (size_t i = 0; i < regions_.size(); i++) {
99 regions_[i].change_history <<= 1;
100 regions_[i].change_history.set(/* LSB */ 0, changed_regions[i]);
101 }
102
103 valid_history_++;
104}
105
106void SquashState::RecordSquashed(const std::vector<bool> &squashed_regions) {
107 for (size_t i = 0; i < regions_.size(); i++) {
108 regions_[i].squashed = squashed_regions[i];
109 }
110}
111
Sean Paul98e73c82015-06-24 14:38:49 -0700112DrmDisplayCompositor::DrmDisplayCompositor()
113 : drm_(NULL),
114 display_(-1),
115 worker_(this),
Sean Paul98e73c82015-06-24 14:38:49 -0700116 initialized_(false),
Sean Pauldb7a17d2015-06-24 18:46:05 -0700117 active_(false),
Sean Paul57355412015-09-19 09:14:34 -0400118 needs_modeset_(false),
Zach Reizner713a6782015-07-31 15:12:44 -0700119 framebuffer_index_(0),
Sean Paul98e73c82015-06-24 14:38:49 -0700120 dump_frames_composited_(0),
121 dump_last_timestamp_ns_(0) {
122 struct timespec ts;
123 if (clock_gettime(CLOCK_MONOTONIC, &ts))
124 return;
125 dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
126}
127
128DrmDisplayCompositor::~DrmDisplayCompositor() {
129 if (!initialized_)
130 return;
131
132 worker_.Exit();
133
134 int ret = pthread_mutex_lock(&lock_);
135 if (ret)
136 ALOGE("Failed to acquire compositor lock %d", ret);
137
138 while (!composite_queue_.empty()) {
139 composite_queue_.front().reset();
140 composite_queue_.pop();
141 }
142 active_composition_.reset();
143
144 ret = pthread_mutex_unlock(&lock_);
145 if (ret)
146 ALOGE("Failed to acquire compositor lock %d", ret);
147
148 pthread_mutex_destroy(&lock_);
149}
150
151int DrmDisplayCompositor::Init(DrmResources *drm, int display) {
152 drm_ = drm;
153 display_ = display;
154
155 int ret = pthread_mutex_init(&lock_, NULL);
156 if (ret) {
157 ALOGE("Failed to initialize drm compositor lock %d\n", ret);
158 return ret;
159 }
160 ret = worker_.Init();
161 if (ret) {
162 pthread_mutex_destroy(&lock_);
163 ALOGE("Failed to initialize compositor worker %d\n", ret);
164 return ret;
165 }
166
167 initialized_ = true;
168 return 0;
169}
170
Zach Reizner92f8e632015-10-12 17:47:13 -0700171std::unique_ptr<DrmDisplayComposition> DrmDisplayCompositor::CreateComposition()
172 const {
173 return std::unique_ptr<DrmDisplayComposition>(new DrmDisplayComposition());
174}
175
Sean Paul98e73c82015-06-24 14:38:49 -0700176int DrmDisplayCompositor::QueueComposition(
177 std::unique_ptr<DrmDisplayComposition> composition) {
Sean Paulacb2a442015-06-24 18:43:01 -0700178 switch (composition->type()) {
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700179 case DRM_COMPOSITION_TYPE_FRAME:
180 if (!active_)
181 return -ENODEV;
182 break;
183 case DRM_COMPOSITION_TYPE_DPMS:
184 /*
185 * Update the state as soon as we get it so we can start/stop queuing
186 * frames asap.
187 */
188 active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON);
189 break;
Sean Paul57355412015-09-19 09:14:34 -0400190 case DRM_COMPOSITION_TYPE_MODESET:
191 break;
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700192 case DRM_COMPOSITION_TYPE_EMPTY:
193 return 0;
194 default:
195 ALOGE("Unknown composition type %d/%d", composition->type(), display_);
196 return -ENOENT;
Sean Paulacb2a442015-06-24 18:43:01 -0700197 }
Sean Paul98e73c82015-06-24 14:38:49 -0700198
199 int ret = pthread_mutex_lock(&lock_);
200 if (ret) {
201 ALOGE("Failed to acquire compositor lock %d", ret);
202 return ret;
203 }
204
Zach Reiznerd410f042015-07-28 15:33:07 -0700205 // Block the queue if it gets too large. Otherwise, SurfaceFlinger will start
206 // to eat our buffer handles when we get about 1 second behind.
207 while (composite_queue_.size() >= DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH) {
208 pthread_mutex_unlock(&lock_);
209 sched_yield();
210 pthread_mutex_lock(&lock_);
211 }
212
Sean Paul98e73c82015-06-24 14:38:49 -0700213 composite_queue_.push(std::move(composition));
214
215 ret = pthread_mutex_unlock(&lock_);
216 if (ret) {
217 ALOGE("Failed to release compositor lock %d", ret);
218 return ret;
219 }
220
221 worker_.Signal();
222 return 0;
223}
224
Zach Reizner92f8e632015-10-12 17:47:13 -0700225std::tuple<uint32_t, uint32_t, int>
226DrmDisplayCompositor::GetActiveModeResolution() {
227 DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
228 if (connector == NULL) {
229 ALOGE("Failed to determine display mode: no connector for display %d",
230 display_);
231 return std::make_tuple(0, 0, -ENODEV);
232 }
233
234 const DrmMode &mode = connector->active_mode();
235 return std::make_tuple(mode.h_display(), mode.v_display(), 0);
Zach Reizner713a6782015-07-31 15:12:44 -0700236}
237
Zach Reizner92f8e632015-10-12 17:47:13 -0700238int DrmDisplayCompositor::PrepareFramebuffer(
239 DrmFramebuffer &fb, DrmDisplayComposition *display_comp) {
240 int ret = fb.WaitReleased(-1);
241 if (ret) {
242 ALOGE("Failed to wait for framebuffer release %d", ret);
243 return ret;
244 }
245 uint32_t width, height;
246 std::tie(width, height, ret) = GetActiveModeResolution();
247 if (ret) {
248 ALOGE(
249 "Failed to allocate framebuffer because the display resolution could "
250 "not be determined %d",
251 ret);
252 return ret;
253 }
254
255 fb.set_release_fence_fd(-1);
256 if (!fb.Allocate(width, height)) {
257 ALOGE("Failed to allocate framebuffer with size %dx%d", width, height);
258 return -ENOMEM;
259 }
260
261 display_comp->layers().emplace_back();
262 DrmHwcLayer &pre_comp_layer = display_comp->layers().back();
263 pre_comp_layer.sf_handle = fb.buffer()->handle;
264 pre_comp_layer.source_crop = DrmHwcRect<float>(0, 0, width, height);
265 pre_comp_layer.display_frame = DrmHwcRect<int>(0, 0, width, height);
266 ret = pre_comp_layer.buffer.ImportBuffer(fb.buffer()->handle,
267 display_comp->importer());
268 if (ret) {
269 ALOGE("Failed to import framebuffer for display %d", ret);
270 return ret;
271 }
272
273 return ret;
Zach Reizner713a6782015-07-31 15:12:44 -0700274}
275
276int DrmDisplayCompositor::ApplyPreComposite(
277 DrmDisplayComposition *display_comp) {
278 int ret = 0;
Zach Reizner713a6782015-07-31 15:12:44 -0700279
Zach Reizner713a6782015-07-31 15:12:44 -0700280 DrmFramebuffer &fb = framebuffers_[framebuffer_index_];
Zach Reizner92f8e632015-10-12 17:47:13 -0700281 ret = PrepareFramebuffer(fb, display_comp);
Zach Reizner713a6782015-07-31 15:12:44 -0700282 if (ret) {
Zach Reizner92f8e632015-10-12 17:47:13 -0700283 ALOGE("Failed to prepare framebuffer for precomposite %d", ret);
Zach Reizner713a6782015-07-31 15:12:44 -0700284 return ret;
285 }
Zach Reizner713a6782015-07-31 15:12:44 -0700286
Zach Reizner92f8e632015-10-12 17:47:13 -0700287 std::vector<DrmCompositionRegion> &regions = display_comp->pre_comp_regions();
288 ret = pre_compositor_->Composite(display_comp->layers().data(),
289 regions.data(), regions.size(), fb.buffer());
Zach Reizner8d63e7f2015-08-20 14:52:12 -0700290 pre_compositor_->Finish();
Zach Reiznerb44fd102015-08-07 16:00:01 -0700291
Zach Reizner713a6782015-07-31 15:12:44 -0700292 if (ret) {
293 ALOGE("Failed to composite layers");
294 return ret;
295 }
296
Zach Reizner92f8e632015-10-12 17:47:13 -0700297 ret = display_comp->CreateNextTimelineFence();
298 if (ret <= 0) {
299 ALOGE("Failed to create pre comp framebuffer release fence %d", ret);
Zach Reizner09807052015-08-13 14:53:41 -0700300 return ret;
301 }
Zach Reizner713a6782015-07-31 15:12:44 -0700302
Zach Reizner92f8e632015-10-12 17:47:13 -0700303 fb.set_release_fence_fd(ret);
304 display_comp->SignalPreCompDone();
Zach Reizner713a6782015-07-31 15:12:44 -0700305
Zach Reizner92f8e632015-10-12 17:47:13 -0700306 return 0;
Zach Reizner713a6782015-07-31 15:12:44 -0700307}
308
Sean Paul7b1e4bc2015-10-13 15:47:22 -0400309int DrmDisplayCompositor::DisablePlanes(DrmDisplayComposition *display_comp) {
310 drmModePropertySetPtr pset = drmModePropertySetAlloc();
311 if (!pset) {
312 ALOGE("Failed to allocate property set");
313 return -ENOMEM;
314 }
315
316 int ret;
Zach Reizner92f8e632015-10-12 17:47:13 -0700317 std::vector<DrmCompositionPlane> &comp_planes =
318 display_comp->composition_planes();
319 for (DrmCompositionPlane &comp_plane : comp_planes) {
320 DrmPlane *plane = comp_plane.plane;
321 ret =
322 drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
323 0) ||
324 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(), 0);
Sean Paul7b1e4bc2015-10-13 15:47:22 -0400325 if (ret) {
326 ALOGE("Failed to add plane %d disable to pset", plane->id());
327 drmModePropertySetFree(pset);
328 return ret;
329 }
330 }
331
332 ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset);
333 if (ret) {
334 ALOGE("Failed to commit pset ret=%d\n", ret);
335 drmModePropertySetFree(pset);
336 return ret;
337 }
338
339 drmModePropertySetFree(pset);
340 return 0;
341}
342
Sean Paul98e73c82015-06-24 14:38:49 -0700343int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
344 int ret = 0;
345
Zach Reizner92f8e632015-10-12 17:47:13 -0700346 std::vector<DrmHwcLayer> &layers = display_comp->layers();
347 std::vector<DrmCompositionPlane> &comp_planes =
348 display_comp->composition_planes();
349 std::vector<DrmCompositionRegion> &pre_comp_regions =
350 display_comp->pre_comp_regions();
351
352 bool do_pre_comp = pre_comp_regions.size() > 0;
353 DrmFramebuffer *pre_comp_fb;
354 int pre_comp_layer_index = -1;
355
356 if (do_pre_comp) {
Zach Reizner713a6782015-07-31 15:12:44 -0700357 ret = ApplyPreComposite(display_comp);
358 if (ret)
359 return ret;
Zach Reizner92f8e632015-10-12 17:47:13 -0700360
361 pre_comp_layer_index = layers.size() - 1;
362 framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
Zach Reizner713a6782015-07-31 15:12:44 -0700363 }
364
Sean Paul57355412015-09-19 09:14:34 -0400365 DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
366 if (!connector) {
367 ALOGE("Could not locate connector for display %d", display_);
368 return -ENODEV;
369 }
370 DrmCrtc *crtc = drm_->GetCrtcForDisplay(display_);
371 if (!crtc) {
372 ALOGE("Could not locate crtc for display %d", display_);
373 return -ENODEV;
374 }
375
Sean Paul98e73c82015-06-24 14:38:49 -0700376 drmModePropertySetPtr pset = drmModePropertySetAlloc();
377 if (!pset) {
378 ALOGE("Failed to allocate property set");
379 return -ENOMEM;
380 }
381
Sean Paul57355412015-09-19 09:14:34 -0400382 uint32_t blob_id = 0;
383 uint64_t old_blob_id;
384 if (needs_modeset_) {
385 DrmProperty old_mode;
386 ret = drm_->GetCrtcProperty(*crtc, crtc->mode_property().name().c_str(),
387 &old_mode);
388 if (ret) {
389 ALOGE("Failed to get old mode property from crtc %d", crtc->id());
390 drmModePropertySetFree(pset);
391 return ret;
392 }
393 ret = old_mode.value(&old_blob_id);
394 if (ret) {
395 ALOGE("Could not get old blob id value %d", ret);
396 drmModePropertySetFree(pset);
397 return ret;
398 }
399
400 struct drm_mode_modeinfo drm_mode;
401 memset(&drm_mode, 0, sizeof(drm_mode));
402 next_mode_.ToDrmModeModeInfo(&drm_mode);
403
404 ret = drm_->CreatePropertyBlob(&drm_mode, sizeof(struct drm_mode_modeinfo),
405 &blob_id);
406 if (ret) {
407 ALOGE("Failed to create mode property blob %d", ret);
408 drmModePropertySetFree(pset);
409 return ret;
410 }
411
412 ret = drmModePropertySetAdd(pset, crtc->id(), crtc->mode_property().id(),
413 blob_id) ||
414 drmModePropertySetAdd(pset, connector->id(),
415 connector->crtc_id_property().id(), crtc->id());
416 if (ret) {
417 ALOGE("Failed to add blob %d to pset", blob_id);
418 drmModePropertySetFree(pset);
419 drm_->DestroyPropertyBlob(blob_id);
420 return ret;
421 }
422 }
423
Zach Reizner92f8e632015-10-12 17:47:13 -0700424 for (DrmCompositionPlane &comp_plane : comp_planes) {
425 DrmPlane *plane = comp_plane.plane;
426 DrmCrtc *crtc = comp_plane.crtc;
427
428 int fb_id = -1;
429 DrmHwcRect<int> display_frame;
430 DrmHwcRect<float> source_crop;
431 uint64_t rotation = 0;
432 switch (comp_plane.source_layer) {
433 case DrmCompositionPlane::kSourceNone:
434 break;
435 case DrmCompositionPlane::kSourcePreComp: {
436 if (!do_pre_comp) {
437 ALOGE(
438 "Can not use pre composite framebuffer with no pre composite "
439 "layers");
440 ret = -EINVAL;
441 goto out;
442 }
443 DrmHwcLayer &layer = layers[pre_comp_layer_index];
444 fb_id = layer.buffer->fb_id;
445 display_frame = layer.display_frame;
446 source_crop = layer.source_crop;
Sean Paul971be152015-10-13 15:44:45 -0400447 }
Zach Reizner92f8e632015-10-12 17:47:13 -0700448 case DrmCompositionPlane::kSourceSquash:
449 break;
450 default: {
451 if (comp_plane.source_layer >= layers.size()) {
452 ALOGE("Source layer index %zu out of bounds %zu",
453 comp_plane.source_layer, layers.size());
454 break;
455 }
456 DrmHwcLayer &layer = layers[comp_plane.source_layer];
457 if (layer.acquire_fence.get() >= 0) {
458 int acquire_fence = layer.acquire_fence.get();
459 for (int i = 0; i < kAcquireWaitTries; ++i) {
460 ret = sync_wait(acquire_fence, kAcquireWaitTimeoutMs);
461 if (ret)
462 ALOGW("Acquire fence %d wait %d failed (%d). Total time %d",
463 acquire_fence, i, ret, (i + 1) * kAcquireWaitTimeoutMs);
464 }
465 if (ret) {
466 ALOGE("Failed to wait for acquire %d/%d", acquire_fence, ret);
467 break;
468 }
469 layer.acquire_fence.Close();
470 }
471 if (!layer.buffer) {
472 ALOGE("Expected a valid framebuffer for pset");
473 break;
474 }
475 fb_id = layer.buffer->fb_id;
476 display_frame = layer.display_frame;
477 source_crop = layer.source_crop;
478 switch (layer.transform) {
479 case DrmHwcTransform::kFlipH:
480 rotation = 1 << DRM_REFLECT_X;
481 break;
482 case DrmHwcTransform::kFlipV:
483 rotation = 1 << DRM_REFLECT_Y;
484 break;
485 case DrmHwcTransform::kRotate90:
486 rotation = 1 << DRM_ROTATE_90;
487 break;
488 case DrmHwcTransform::kRotate180:
489 rotation = 1 << DRM_ROTATE_180;
490 break;
491 case DrmHwcTransform::kRotate270:
492 rotation = 1 << DRM_ROTATE_270;
493 break;
494 case DrmHwcTransform::kIdentity:
495 rotation = 0;
496 break;
497 default:
498 ALOGE("Invalid transform value 0x%x given", layer.transform);
499 break;
500 }
Sean Paul98e73c82015-06-24 14:38:49 -0700501 }
Sean Paul98e73c82015-06-24 14:38:49 -0700502 }
503
Zach Reizner92f8e632015-10-12 17:47:13 -0700504 // Disable the plane if there's no framebuffer
505 if (fb_id < 0) {
Zach Reizner952f70a2015-07-17 14:10:03 -0700506 ret = drmModePropertySetAdd(pset, plane->id(),
507 plane->crtc_property().id(), 0) ||
508 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
509 0);
Sean Paul2e46fbd2015-07-09 17:22:22 -0400510 if (ret) {
511 ALOGE("Failed to add plane %d disable to pset", plane->id());
512 break;
513 }
514 continue;
515 }
516
Sean Paul1c4c3262015-07-14 15:51:52 -0400517 // TODO: Once we have atomic test, this should fall back to GL
518 if (rotation && plane->rotation_property().id() == 0) {
519 ALOGE("Rotation is not supported on plane %d", plane->id());
520 ret = -EINVAL;
521 break;
522 }
523
Sean Paul98e73c82015-06-24 14:38:49 -0700524 ret =
525 drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
Zach Reizner92f8e632015-10-12 17:47:13 -0700526 crtc->id()) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700527 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
Zach Reizner92f8e632015-10-12 17:47:13 -0700528 fb_id) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700529 drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
Zach Reizner92f8e632015-10-12 17:47:13 -0700530 display_frame.left) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700531 drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
Zach Reizner92f8e632015-10-12 17:47:13 -0700532 display_frame.top) ||
533 drmModePropertySetAdd(pset, plane->id(), plane->crtc_w_property().id(),
534 display_frame.right - display_frame.left) ||
535 drmModePropertySetAdd(pset, plane->id(), plane->crtc_h_property().id(),
536 display_frame.bottom - display_frame.top) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700537 drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
Zach Reizner92f8e632015-10-12 17:47:13 -0700538 (int)(source_crop.left) << 16) ||
Sean Paul98e73c82015-06-24 14:38:49 -0700539 drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
Zach Reizner92f8e632015-10-12 17:47:13 -0700540 (int)(source_crop.top) << 16) ||
541 drmModePropertySetAdd(pset, plane->id(), plane->src_w_property().id(),
542 (int)(source_crop.right - source_crop.left)
543 << 16) ||
544 drmModePropertySetAdd(pset, plane->id(), plane->src_h_property().id(),
545 (int)(source_crop.bottom - source_crop.top)
546 << 16);
Sean Paul98e73c82015-06-24 14:38:49 -0700547 if (ret) {
548 ALOGE("Failed to add plane %d to set", plane->id());
549 break;
550 }
Sean Paul1c4c3262015-07-14 15:51:52 -0400551
552 if (plane->rotation_property().id()) {
Zach Reizner952f70a2015-07-17 14:10:03 -0700553 ret = drmModePropertySetAdd(pset, plane->id(),
554 plane->rotation_property().id(), rotation);
Sean Paul1c4c3262015-07-14 15:51:52 -0400555 if (ret) {
556 ALOGE("Failed to add rotation property %d to plane %d",
557 plane->rotation_property().id(), plane->id());
558 break;
559 }
560 }
Sean Paul98e73c82015-06-24 14:38:49 -0700561 }
562
Zach Reizner92f8e632015-10-12 17:47:13 -0700563out:
Sean Paul98e73c82015-06-24 14:38:49 -0700564 if (!ret) {
Sean Paul57355412015-09-19 09:14:34 -0400565 ret = drmModePropertySetCommit(drm_->fd(), DRM_MODE_ATOMIC_ALLOW_MODESET,
566 drm_, pset);
567 if (ret) {
Sean Paul98e73c82015-06-24 14:38:49 -0700568 ALOGE("Failed to commit pset ret=%d\n", ret);
Sean Paul57355412015-09-19 09:14:34 -0400569 drmModePropertySetFree(pset);
570 if (needs_modeset_)
571 drm_->DestroyPropertyBlob(blob_id);
572 return ret;
573 }
Sean Paul98e73c82015-06-24 14:38:49 -0700574 }
575 if (pset)
576 drmModePropertySetFree(pset);
577
Sean Paul57355412015-09-19 09:14:34 -0400578 if (needs_modeset_) {
579 ret = drm_->DestroyPropertyBlob(old_blob_id);
580 if (ret) {
581 ALOGE("Failed to destroy old mode property blob %lld/%d", old_blob_id,
582 ret);
583 return ret;
584 }
585
586 /* TODO: Add dpms to the pset when the kernel supports it */
587 ret = ApplyDpms(display_comp);
588 if (ret) {
589 ALOGE("Failed to apply DPMS after modeset %d\n", ret);
590 return ret;
591 }
592
593 connector->set_active_mode(next_mode_);
594 needs_modeset_ = false;
595 }
596
Sean Paul98e73c82015-06-24 14:38:49 -0700597 return ret;
598}
599
Sean Pauldb7a17d2015-06-24 18:46:05 -0700600int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
601 DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
602 if (!conn) {
603 ALOGE("Failed to get DrmConnector for display %d", display_);
604 return -ENODEV;
605 }
606
607 const DrmProperty &prop = conn->dpms_property();
608 int ret = drmModeConnectorSetProperty(drm_->fd(), conn->id(), prop.id(),
609 display_comp->dpms_mode());
610 if (ret) {
611 ALOGE("Failed to set DPMS property for connector %d", conn->id());
612 return ret;
613 }
614 return 0;
615}
616
Sean Paul98e73c82015-06-24 14:38:49 -0700617int DrmDisplayCompositor::Composite() {
618 ATRACE_CALL();
Zach Reizner09807052015-08-13 14:53:41 -0700619
620 if (!pre_compositor_) {
621 pre_compositor_.reset(new GLWorkerCompositor());
622 int ret = pre_compositor_->Init();
623 if (ret) {
624 ALOGE("Failed to initialize OpenGL compositor %d", ret);
625 return ret;
626 }
627 }
628
Sean Paul98e73c82015-06-24 14:38:49 -0700629 int ret = pthread_mutex_lock(&lock_);
630 if (ret) {
631 ALOGE("Failed to acquire compositor lock %d", ret);
632 return ret;
633 }
634 if (composite_queue_.empty()) {
635 ret = pthread_mutex_unlock(&lock_);
636 if (ret)
637 ALOGE("Failed to release compositor lock %d", ret);
638 return ret;
639 }
640
641 std::unique_ptr<DrmDisplayComposition> composition(
642 std::move(composite_queue_.front()));
Zach Reizner4a253652015-09-10 18:30:54 -0700643
Sean Paul98e73c82015-06-24 14:38:49 -0700644 composite_queue_.pop();
645
646 ret = pthread_mutex_unlock(&lock_);
647 if (ret) {
648 ALOGE("Failed to release compositor lock %d", ret);
649 return ret;
650 }
651
Sean Paulacb2a442015-06-24 18:43:01 -0700652 switch (composition->type()) {
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700653 case DRM_COMPOSITION_TYPE_FRAME:
654 ret = ApplyFrame(composition.get());
655 if (ret) {
656 ALOGE("Composite failed for display %d", display_);
Sean Paul7b1e4bc2015-10-13 15:47:22 -0400657
658 // Disable the hw used by the last active composition. This allows us to
659 // signal the release fences from that composition to avoid hanging.
660 if (DisablePlanes(active_composition_.get()))
661 return ret;
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700662 }
663 ++dump_frames_composited_;
664 break;
665 case DRM_COMPOSITION_TYPE_DPMS:
666 ret = ApplyDpms(composition.get());
667 if (ret)
668 ALOGE("Failed to apply dpms for display %d", display_);
Sean Paulacb2a442015-06-24 18:43:01 -0700669 return ret;
Sean Paul57355412015-09-19 09:14:34 -0400670 case DRM_COMPOSITION_TYPE_MODESET:
671 next_mode_ = composition->display_mode();
672 needs_modeset_ = true;
673 return 0;
Zach Reiznerb4a9aef2015-07-16 09:45:59 -0700674 default:
675 ALOGE("Unknown composition type %d", composition->type());
676 return -EINVAL;
Sean Paul98e73c82015-06-24 14:38:49 -0700677 }
Sean Paul98e73c82015-06-24 14:38:49 -0700678
679 if (active_composition_)
Zach Reizner92f8e632015-10-12 17:47:13 -0700680 active_composition_->SignalCompositionDone();
Sean Paul98e73c82015-06-24 14:38:49 -0700681
Sean Paulfd37dfe2015-07-13 12:41:37 -0400682 ret = pthread_mutex_lock(&lock_);
683 if (ret)
684 ALOGE("Failed to acquire lock for active_composition swap");
685
Sean Paul98e73c82015-06-24 14:38:49 -0700686 active_composition_.swap(composition);
Sean Paulfd37dfe2015-07-13 12:41:37 -0400687
688 if (!ret)
689 ret = pthread_mutex_unlock(&lock_);
Zach Reizner952f70a2015-07-17 14:10:03 -0700690 if (ret)
691 ALOGE("Failed to release lock for active_composition swap");
Sean Paulfd37dfe2015-07-13 12:41:37 -0400692
Sean Paul98e73c82015-06-24 14:38:49 -0700693 return ret;
694}
695
696bool DrmDisplayCompositor::HaveQueuedComposites() const {
697 int ret = pthread_mutex_lock(&lock_);
698 if (ret) {
699 ALOGE("Failed to acquire compositor lock %d", ret);
700 return false;
701 }
702
703 bool empty_ret = !composite_queue_.empty();
704
705 ret = pthread_mutex_unlock(&lock_);
706 if (ret) {
707 ALOGE("Failed to release compositor lock %d", ret);
708 return false;
709 }
710
711 return empty_ret;
712}
713
714void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
Sean Paul98e73c82015-06-24 14:38:49 -0700715}
716}