2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
18 #define LOG_TAG "hwc-drm-display-compositor"
20 #include "drmdisplaycompositor.h"
23 #include "drmresources.h"
34 #include <drm/drm_mode.h>
35 #include <cutils/log.h>
36 #include <sync/sync.h>
37 #include <utils/Trace.h>
39 #define DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH 3
43 DrmDisplayCompositor::DrmDisplayCompositor()
49 needs_modeset_(false),
50 framebuffer_index_(0),
51 dump_frames_composited_(0),
52 dump_last_timestamp_ns_(0) {
54 if (clock_gettime(CLOCK_MONOTONIC, &ts))
56 dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
59 DrmDisplayCompositor::~DrmDisplayCompositor() {
65 int ret = pthread_mutex_lock(&lock_);
67 ALOGE("Failed to acquire compositor lock %d", ret);
69 while (!composite_queue_.empty()) {
70 composite_queue_.front().reset();
71 composite_queue_.pop();
73 active_composition_.reset();
75 ret = pthread_mutex_unlock(&lock_);
77 ALOGE("Failed to acquire compositor lock %d", ret);
79 pthread_mutex_destroy(&lock_);
82 int DrmDisplayCompositor::Init(DrmResources *drm, int display) {
86 int ret = pthread_mutex_init(&lock_, NULL);
88 ALOGE("Failed to initialize drm compositor lock %d\n", ret);
93 pthread_mutex_destroy(&lock_);
94 ALOGE("Failed to initialize compositor worker %d\n", ret);
102 int DrmDisplayCompositor::QueueComposition(
103 std::unique_ptr<DrmDisplayComposition> composition) {
104 switch (composition->type()) {
105 case DRM_COMPOSITION_TYPE_FRAME:
109 case DRM_COMPOSITION_TYPE_DPMS:
111 * Update the state as soon as we get it so we can start/stop queuing
114 active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON);
116 case DRM_COMPOSITION_TYPE_MODESET:
118 case DRM_COMPOSITION_TYPE_EMPTY:
121 ALOGE("Unknown composition type %d/%d", composition->type(), display_);
125 int ret = pthread_mutex_lock(&lock_);
127 ALOGE("Failed to acquire compositor lock %d", ret);
131 // 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_);
136 pthread_mutex_lock(&lock_);
139 composite_queue_.push(std::move(composition));
141 ret = pthread_mutex_unlock(&lock_);
143 ALOGE("Failed to release compositor lock %d", ret);
151 static bool drm_composition_layer_has_plane(
152 const DrmCompositionLayer &comp_layer) {
153 if (comp_layer.plane != NULL)
154 if (comp_layer.plane->type() == DRM_PLANE_TYPE_OVERLAY ||
155 comp_layer.plane->type() == DRM_PLANE_TYPE_PRIMARY)
160 static bool drm_composition_layer_has_no_plane(
161 const DrmCompositionLayer &comp_layer) {
162 return comp_layer.plane == NULL;
165 int DrmDisplayCompositor::ApplyPreComposite(
166 DrmDisplayComposition *display_comp) {
168 std::vector<DrmCompositionLayer> *layers =
169 display_comp->GetCompositionLayers();
171 DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
172 if (connector == NULL) {
173 ALOGE("Failed to determine display mode: no connector for display %d",
178 const DrmMode &mode = connector->active_mode();
179 DrmFramebuffer &fb = framebuffers_[framebuffer_index_];
180 ret = fb.WaitReleased(fb.kReleaseWaitTimeoutMs);
182 ALOGE("Failed to wait for framebuffer release %d", ret);
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(),
192 std::vector<DrmCompositionLayer> pre_comp_layers;
193 for (auto &comp_layer : *layers) {
194 if (comp_layer.plane == NULL) {
195 pre_comp_layers.emplace_back(std::move(comp_layer));
199 ret = pre_compositor_->Composite(pre_comp_layers.data(),
200 pre_comp_layers.size(), fb.buffer());
201 pre_compositor_->Finish();
204 ALOGE("Failed to composite layers");
208 DrmCompositionLayer &pre_comp_layer =
209 layers->at(display_comp->pre_composition_layer_index());
210 ret = pre_comp_layer.buffer.ImportBuffer(fb.buffer()->handle,
211 display_comp->importer());
213 ALOGE("Failed to import handle of layer %d", ret);
216 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());
221 // TODO(zachr) get a release fence
222 // fb.set_release_fence_fd(pre_comp_layer.release_fence.Release());
223 framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
225 display_comp->RemoveNoPlaneLayers();
226 display_comp->SignalPreCompositionDone();
230 int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
233 if (display_comp->pre_composition_layer_index() >= 0) {
234 ret = ApplyPreComposite(display_comp);
239 DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
241 ALOGE("Could not locate connector for display %d", display_);
244 DrmCrtc *crtc = drm_->GetCrtcForDisplay(display_);
246 ALOGE("Could not locate crtc for display %d", display_);
250 drmModePropertySetPtr pset = drmModePropertySetAlloc();
252 ALOGE("Failed to allocate property set");
256 uint32_t blob_id = 0;
257 uint64_t old_blob_id;
258 if (needs_modeset_) {
259 DrmProperty old_mode;
260 ret = drm_->GetCrtcProperty(*crtc, crtc->mode_property().name().c_str(),
263 ALOGE("Failed to get old mode property from crtc %d", crtc->id());
264 drmModePropertySetFree(pset);
267 ret = old_mode.value(&old_blob_id);
269 ALOGE("Could not get old blob id value %d", ret);
270 drmModePropertySetFree(pset);
274 struct drm_mode_modeinfo drm_mode;
275 memset(&drm_mode, 0, sizeof(drm_mode));
276 next_mode_.ToDrmModeModeInfo(&drm_mode);
278 ret = drm_->CreatePropertyBlob(&drm_mode, sizeof(struct drm_mode_modeinfo),
281 ALOGE("Failed to create mode property blob %d", ret);
282 drmModePropertySetFree(pset);
286 ret = drmModePropertySetAdd(pset, crtc->id(), crtc->mode_property().id(),
288 drmModePropertySetAdd(pset, connector->id(),
289 connector->crtc_id_property().id(), crtc->id());
291 ALOGE("Failed to add blob %d to pset", blob_id);
292 drmModePropertySetFree(pset);
293 drm_->DestroyPropertyBlob(blob_id);
298 std::vector<DrmCompositionLayer> *layers =
299 display_comp->GetCompositionLayers();
300 for (DrmCompositionLayer &layer : *layers) {
301 int acquire_fence = layer.acquire_fence.get();
302 if (acquire_fence >= 0) {
303 for (int i = 0; i < kAcquireWaitTries; ++i) {
304 ret = sync_wait(acquire_fence, kAcquireWaitTimeoutMs);
306 ALOGW("Acquire fence %d wait %d failed (%d). Total time %d",
307 acquire_fence, i, ret, (i + 1) * kAcquireWaitTimeoutMs);
310 ALOGE("Failed to wait for acquire %d/%d", acquire_fence, ret);
311 drmModePropertySetFree(pset);
312 drm_->DestroyPropertyBlob(blob_id);
315 layer.acquire_fence.Close();
318 DrmPlane *plane = layer.plane;
320 // Disable the plane if there's no crtc
322 ret = drmModePropertySetAdd(pset, plane->id(),
323 plane->crtc_property().id(), 0) ||
324 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
327 ALOGE("Failed to add plane %d disable to pset", plane->id());
334 ALOGE("Expected a valid framebuffer for pset");
340 switch (layer.transform) {
341 case DrmHwcTransform::kFlipH:
342 rotation = 1 << DRM_REFLECT_X;
344 case DrmHwcTransform::kFlipV:
345 rotation = 1 << DRM_REFLECT_Y;
347 case DrmHwcTransform::kRotate90:
348 rotation = 1 << DRM_ROTATE_90;
350 case DrmHwcTransform::kRotate180:
351 rotation = 1 << DRM_ROTATE_180;
353 case DrmHwcTransform::kRotate270:
354 rotation = 1 << DRM_ROTATE_270;
356 case DrmHwcTransform::kIdentity:
360 ALOGE("Invalid transform value 0x%x given", layer.transform);
367 // TODO: Once we have atomic test, this should fall back to GL
368 if (rotation && plane->rotation_property().id() == 0) {
369 ALOGE("Rotation is not supported on plane %d", plane->id());
375 drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
377 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
378 layer.buffer->fb_id) ||
379 drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
380 layer.display_frame.left) ||
381 drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
382 layer.display_frame.top) ||
383 drmModePropertySetAdd(
384 pset, plane->id(), plane->crtc_w_property().id(),
385 layer.display_frame.right - layer.display_frame.left) ||
386 drmModePropertySetAdd(
387 pset, plane->id(), plane->crtc_h_property().id(),
388 layer.display_frame.bottom - layer.display_frame.top) ||
389 drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
390 (int)(layer.source_crop.left) << 16) ||
391 drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
392 (int)(layer.source_crop.top) << 16) ||
393 drmModePropertySetAdd(
394 pset, plane->id(), plane->src_w_property().id(),
395 (int)(layer.source_crop.right - layer.source_crop.left) << 16) ||
396 drmModePropertySetAdd(
397 pset, plane->id(), plane->src_h_property().id(),
398 (int)(layer.source_crop.bottom - layer.source_crop.top) << 16);
400 ALOGE("Failed to add plane %d to set", plane->id());
404 if (plane->rotation_property().id()) {
405 ret = drmModePropertySetAdd(pset, plane->id(),
406 plane->rotation_property().id(), rotation);
408 ALOGE("Failed to add rotation property %d to plane %d",
409 plane->rotation_property().id(), plane->id());
416 ret = drmModePropertySetCommit(drm_->fd(), DRM_MODE_ATOMIC_ALLOW_MODESET,
419 ALOGE("Failed to commit pset ret=%d\n", ret);
420 drmModePropertySetFree(pset);
422 drm_->DestroyPropertyBlob(blob_id);
427 drmModePropertySetFree(pset);
429 if (needs_modeset_) {
430 ret = drm_->DestroyPropertyBlob(old_blob_id);
432 ALOGE("Failed to destroy old mode property blob %lld/%d", old_blob_id,
437 /* TODO: Add dpms to the pset when the kernel supports it */
438 ret = ApplyDpms(display_comp);
440 ALOGE("Failed to apply DPMS after modeset %d\n", ret);
444 connector->set_active_mode(next_mode_);
445 needs_modeset_ = false;
451 int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
452 DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
454 ALOGE("Failed to get DrmConnector for display %d", display_);
458 const DrmProperty &prop = conn->dpms_property();
459 int ret = drmModeConnectorSetProperty(drm_->fd(), conn->id(), prop.id(),
460 display_comp->dpms_mode());
462 ALOGE("Failed to set DPMS property for connector %d", conn->id());
468 int DrmDisplayCompositor::Composite() {
471 if (!pre_compositor_) {
472 pre_compositor_.reset(new GLWorkerCompositor());
473 int ret = pre_compositor_->Init();
475 ALOGE("Failed to initialize OpenGL compositor %d", ret);
480 int ret = pthread_mutex_lock(&lock_);
482 ALOGE("Failed to acquire compositor lock %d", ret);
485 if (composite_queue_.empty()) {
486 ret = pthread_mutex_unlock(&lock_);
488 ALOGE("Failed to release compositor lock %d", ret);
492 std::unique_ptr<DrmDisplayComposition> composition(
493 std::move(composite_queue_.front()));
495 composite_queue_.pop();
497 ret = pthread_mutex_unlock(&lock_);
499 ALOGE("Failed to release compositor lock %d", ret);
503 switch (composition->type()) {
504 case DRM_COMPOSITION_TYPE_FRAME:
505 ret = ApplyFrame(composition.get());
507 ALOGE("Composite failed for display %d", display_);
510 ++dump_frames_composited_;
512 case DRM_COMPOSITION_TYPE_DPMS:
513 ret = ApplyDpms(composition.get());
515 ALOGE("Failed to apply dpms for display %d", display_);
517 case DRM_COMPOSITION_TYPE_MODESET:
518 next_mode_ = composition->display_mode();
519 needs_modeset_ = true;
522 ALOGE("Unknown composition type %d", composition->type());
526 if (active_composition_)
527 active_composition_->FinishComposition();
529 ret = pthread_mutex_lock(&lock_);
531 ALOGE("Failed to acquire lock for active_composition swap");
533 active_composition_.swap(composition);
536 ret = pthread_mutex_unlock(&lock_);
538 ALOGE("Failed to release lock for active_composition swap");
543 bool DrmDisplayCompositor::HaveQueuedComposites() const {
544 int ret = pthread_mutex_lock(&lock_);
546 ALOGE("Failed to acquire compositor lock %d", ret);
550 bool empty_ret = !composite_queue_.empty();
552 ret = pthread_mutex_unlock(&lock_);
554 ALOGE("Failed to release compositor lock %d", ret);
561 struct DrmDumpLayer {
564 DrmHwcTransform transform;
565 DrmHwcRect<float> source_crop;
566 DrmHwcRect<int> display_frame;
568 DrmDumpLayer(DrmCompositionLayer &rhs)
569 : plane_id(rhs.plane->id()),
570 crtc_id(rhs.crtc ? rhs.crtc->id() : -1),
571 transform(rhs.transform),
572 source_crop(rhs.source_crop),
573 display_frame(rhs.display_frame) {
577 void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
580 int ret = pthread_mutex_lock(&lock_);
584 uint64_t num_frames = dump_frames_composited_;
585 dump_frames_composited_ = 0;
588 ret = clock_gettime(CLOCK_MONOTONIC, &ts);
590 std::vector<DrmCompositionLayer> *input_layers =
591 active_composition_->GetCompositionLayers();
592 std::vector<DrmDumpLayer> layers;
593 if (active_composition_)
594 layers.insert(layers.begin(), input_layers->begin(), input_layers->end());
598 ret |= pthread_mutex_unlock(&lock_);
602 cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
603 uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
604 float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f;
606 *out << "--DrmDisplayCompositor[" << display_
607 << "]: num_frames=" << num_frames << " num_ms=" << num_ms
608 << " fps=" << fps << "\n";
610 dump_last_timestamp_ns_ = cur_ts;
612 *out << "---- DrmDisplayCompositor Layers: num=" << layers.size() << "\n";
613 for (std::vector<DrmDumpLayer>::iterator iter = layers.begin();
614 iter != layers.end(); ++iter) {
615 *out << "------ DrmDisplayCompositor Layer: plane=" << iter->plane_id
618 if (iter->crtc_id < 0) {
619 *out << "disabled\n";
623 *out << "crtc=" << iter->crtc_id
624 << " crtc[x/y/w/h]=" << iter->display_frame.left << "/"
625 << iter->display_frame.top << "/"
626 << iter->display_frame.right - iter->display_frame.left << "/"
627 << iter->display_frame.bottom - iter->display_frame.top << " "
628 << " src[x/y/w/h]=" << iter->source_crop.left << "/"
629 << iter->source_crop.top << "/"
630 << iter->source_crop.right - iter->source_crop.left << "/"
631 << iter->source_crop.bottom - iter->source_crop.top
632 << " transform=" << (uint32_t)iter->transform << "\n";