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"
33 #include <drm/drm_mode.h>
34 #include <cutils/log.h>
35 #include <sync/sync.h>
36 #include <utils/Trace.h>
40 DrmDisplayCompositor::DrmDisplayCompositor()
47 framebuffer_index_(0),
48 dump_frames_composited_(0),
49 dump_last_timestamp_ns_(0) {
51 if (clock_gettime(CLOCK_MONOTONIC, &ts))
53 dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
56 DrmDisplayCompositor::~DrmDisplayCompositor() {
62 int ret = pthread_mutex_lock(&lock_);
64 ALOGE("Failed to acquire compositor lock %d", ret);
66 while (!composite_queue_.empty()) {
67 composite_queue_.front().reset();
68 composite_queue_.pop();
70 active_composition_.reset();
72 ret = pthread_mutex_unlock(&lock_);
74 ALOGE("Failed to acquire compositor lock %d", ret);
76 pthread_mutex_destroy(&lock_);
79 int DrmDisplayCompositor::Init(DrmResources *drm, int display) {
83 int ret = pthread_mutex_init(&lock_, NULL);
85 ALOGE("Failed to initialize drm compositor lock %d\n", ret);
90 pthread_mutex_destroy(&lock_);
91 ALOGE("Failed to initialize compositor worker %d\n", ret);
99 int DrmDisplayCompositor::QueueComposition(
100 std::unique_ptr<DrmDisplayComposition> composition) {
101 switch (composition->type()) {
102 case DRM_COMPOSITION_TYPE_FRAME:
106 case DRM_COMPOSITION_TYPE_DPMS:
108 * Update the state as soon as we get it so we can start/stop queuing
111 active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON);
113 case DRM_COMPOSITION_TYPE_EMPTY:
116 ALOGE("Unknown composition type %d/%d", composition->type(), display_);
120 int ret = pthread_mutex_lock(&lock_);
122 ALOGE("Failed to acquire compositor lock %d", ret);
126 composite_queue_.push(std::move(composition));
128 ret = pthread_mutex_unlock(&lock_);
130 ALOGE("Failed to release compositor lock %d", ret);
138 static 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)
147 static bool drm_composition_layer_has_no_plane(
148 const DrmCompositionLayer_t &comp_layer) {
149 return comp_layer.plane == NULL;
152 int DrmDisplayCompositor::ApplyPreComposite(
153 DrmDisplayComposition *display_comp) {
155 DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
157 DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
158 if (connector == NULL) {
159 ALOGE("Failed to determine display mode: no connector for display %d",
164 const DrmMode &mode = connector->active_mode();
165 DrmFramebuffer &fb = framebuffers_[framebuffer_index_];
166 ret = fb.WaitReleased(-1);
168 ALOGE("Failed to wait for framebuffer release %d", ret);
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(),
178 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;
187 ret = pre_compositor_->CompositeAndFinish(
188 pre_comp_layers.data(), pre_comp_layers.size(), fb.buffer());
190 for (auto &pre_comp_layer : pre_comp_layers) {
191 if (pre_comp_layer.acquireFenceFd >= 0) {
192 close(pre_comp_layer.acquireFenceFd);
193 pre_comp_layer.acquireFenceFd = -1;
198 ALOGE("Failed to composite layers");
202 DrmCompositionLayer_t &pre_comp_layer =
203 layers->at(display_comp->pre_composition_layer_index());
204 ret = display_comp->importer()->ImportBuffer(fb.buffer()->handle,
207 ALOGE("Failed to import handle of layer %d", ret);
210 hwc_layer_1_t &pre_comp_output_layer = pre_comp_layer.layer;
211 pre_comp_output_layer.handle = fb.buffer()->handle;
212 pre_comp_output_layer.visibleRegionScreen.rects =
213 &pre_comp_output_layer.displayFrame;
214 pre_comp_output_layer.sourceCropf.right =
215 pre_comp_output_layer.displayFrame.right = fb.buffer()->getWidth();
216 pre_comp_output_layer.sourceCropf.bottom =
217 pre_comp_output_layer.displayFrame.bottom = fb.buffer()->getHeight();
219 fb.set_release_fence_fd(pre_comp_output_layer.releaseFenceFd);
220 framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
222 display_comp->RemoveNoPlaneLayers();
223 display_comp->SignalPreCompositionDone();
227 int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
230 if (display_comp->pre_composition_layer_index() >= 0) {
231 ret = ApplyPreComposite(display_comp);
236 drmModePropertySetPtr pset = drmModePropertySetAlloc();
238 ALOGE("Failed to allocate property set");
242 DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
243 for (DrmCompositionLayerVector_t::iterator iter = layers->begin();
244 iter != layers->end(); ++iter) {
245 hwc_layer_1_t *layer = &iter->layer;
247 if (layer->acquireFenceFd >= 0) {
248 ret = sync_wait(layer->acquireFenceFd, -1);
250 ALOGE("Failed to wait for acquire %d/%d", layer->acquireFenceFd, ret);
251 drmModePropertySetFree(pset);
254 close(layer->acquireFenceFd);
255 layer->acquireFenceFd = -1;
258 DrmPlane *plane = iter->plane;
259 DrmCrtc *crtc = iter->crtc;
261 // Disable the plane if there's no crtc
263 ret = drmModePropertySetAdd(pset, plane->id(),
264 plane->crtc_property().id(), 0) ||
265 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
268 ALOGE("Failed to add plane %d disable to pset", plane->id());
275 switch (layer->transform) {
276 case HWC_TRANSFORM_FLIP_H:
277 rotation = 1 << DRM_REFLECT_X;
279 case HWC_TRANSFORM_FLIP_V:
280 rotation = 1 << DRM_REFLECT_Y;
282 case HWC_TRANSFORM_ROT_90:
283 rotation = 1 << DRM_ROTATE_90;
285 case HWC_TRANSFORM_ROT_180:
286 rotation = 1 << DRM_ROTATE_180;
288 case HWC_TRANSFORM_ROT_270:
289 rotation = 1 << DRM_ROTATE_270;
295 ALOGE("Invalid transform value 0x%x given", layer->transform);
302 // TODO: Once we have atomic test, this should fall back to GL
303 if (rotation && plane->rotation_property().id() == 0) {
304 ALOGE("Rotation is not supported on plane %d", plane->id());
310 drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
312 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
314 drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
315 layer->displayFrame.left) ||
316 drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
317 layer->displayFrame.top) ||
318 drmModePropertySetAdd(
319 pset, plane->id(), plane->crtc_w_property().id(),
320 layer->displayFrame.right - layer->displayFrame.left) ||
321 drmModePropertySetAdd(
322 pset, plane->id(), plane->crtc_h_property().id(),
323 layer->displayFrame.bottom - layer->displayFrame.top) ||
324 drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
325 (int)(layer->sourceCropf.left) << 16) ||
326 drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
327 (int)(layer->sourceCropf.top) << 16) ||
328 drmModePropertySetAdd(
329 pset, plane->id(), plane->src_w_property().id(),
330 (int)(layer->sourceCropf.right - layer->sourceCropf.left) << 16) ||
331 drmModePropertySetAdd(
332 pset, plane->id(), plane->src_h_property().id(),
333 (int)(layer->sourceCropf.bottom - layer->sourceCropf.top) << 16);
335 ALOGE("Failed to add plane %d to set", plane->id());
339 if (plane->rotation_property().id()) {
340 ret = drmModePropertySetAdd(pset, plane->id(),
341 plane->rotation_property().id(), rotation);
343 ALOGE("Failed to add rotation property %d to plane %d",
344 plane->rotation_property().id(), plane->id());
351 ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset);
353 ALOGE("Failed to commit pset ret=%d\n", ret);
356 drmModePropertySetFree(pset);
361 int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
362 DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
364 ALOGE("Failed to get DrmConnector for display %d", display_);
368 const DrmProperty &prop = conn->dpms_property();
369 int ret = drmModeConnectorSetProperty(drm_->fd(), conn->id(), prop.id(),
370 display_comp->dpms_mode());
372 ALOGE("Failed to set DPMS property for connector %d", conn->id());
378 int DrmDisplayCompositor::Composite() {
381 if (!pre_compositor_) {
382 pre_compositor_.reset(new GLWorkerCompositor());
383 int ret = pre_compositor_->Init();
385 ALOGE("Failed to initialize OpenGL compositor %d", ret);
390 int ret = pthread_mutex_lock(&lock_);
392 ALOGE("Failed to acquire compositor lock %d", ret);
395 if (composite_queue_.empty()) {
396 ret = pthread_mutex_unlock(&lock_);
398 ALOGE("Failed to release compositor lock %d", ret);
402 std::unique_ptr<DrmDisplayComposition> composition(
403 std::move(composite_queue_.front()));
404 composite_queue_.pop();
406 ret = pthread_mutex_unlock(&lock_);
408 ALOGE("Failed to release compositor lock %d", ret);
412 switch (composition->type()) {
413 case DRM_COMPOSITION_TYPE_FRAME:
414 ret = ApplyFrame(composition.get());
416 ALOGE("Composite failed for display %d", display_);
419 ++dump_frames_composited_;
421 case DRM_COMPOSITION_TYPE_DPMS:
422 ret = ApplyDpms(composition.get());
424 ALOGE("Failed to apply dpms for display %d", display_);
427 ALOGE("Unknown composition type %d", composition->type());
431 if (active_composition_)
432 active_composition_->FinishComposition();
434 ret = pthread_mutex_lock(&lock_);
436 ALOGE("Failed to acquire lock for active_composition swap");
438 active_composition_.swap(composition);
441 ret = pthread_mutex_unlock(&lock_);
443 ALOGE("Failed to release lock for active_composition swap");
448 bool DrmDisplayCompositor::HaveQueuedComposites() const {
449 int ret = pthread_mutex_lock(&lock_);
451 ALOGE("Failed to acquire compositor lock %d", ret);
455 bool empty_ret = !composite_queue_.empty();
457 ret = pthread_mutex_unlock(&lock_);
459 ALOGE("Failed to release compositor lock %d", ret);
466 void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
469 int ret = pthread_mutex_lock(&lock_);
473 uint64_t num_frames = dump_frames_composited_;
474 dump_frames_composited_ = 0;
477 ret = clock_gettime(CLOCK_MONOTONIC, &ts);
479 DrmCompositionLayerVector_t layers;
480 if (active_composition_)
481 layers = *active_composition_->GetCompositionLayers();
485 ret |= pthread_mutex_unlock(&lock_);
489 cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
490 uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
491 float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f;
493 *out << "--DrmDisplayCompositor[" << display_
494 << "]: num_frames=" << num_frames << " num_ms=" << num_ms
495 << " fps=" << fps << "\n";
497 dump_last_timestamp_ns_ = cur_ts;
499 *out << "---- DrmDisplayCompositor Layers: num=" << layers.size() << "\n";
500 for (DrmCompositionLayerVector_t::iterator iter = layers.begin();
501 iter != layers.end(); ++iter) {
502 hwc_layer_1_t *layer = &iter->layer;
503 DrmPlane *plane = iter->plane;
505 *out << "------ DrmDisplayCompositor Layer: plane=" << plane->id() << " ";
507 DrmCrtc *crtc = iter->crtc;
509 *out << "disabled\n";
513 *out << "crtc=" << crtc->id()
514 << " crtc[x/y/w/h]=" << layer->displayFrame.left << "/"
515 << layer->displayFrame.top << "/"
516 << layer->displayFrame.right - layer->displayFrame.left << "/"
517 << layer->displayFrame.bottom - layer->displayFrame.top << " "
518 << " src[x/y/w/h]=" << layer->sourceCropf.left << "/"
519 << layer->sourceCropf.top << "/"
520 << layer->sourceCropf.right - layer->sourceCropf.left << "/"
521 << layer->sourceCropf.bottom - layer->sourceCropf.top
522 << " transform=" << layer->transform << "\n";