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 framebuffer_index_(0),
50 dump_frames_composited_(0),
51 dump_last_timestamp_ns_(0) {
53 if (clock_gettime(CLOCK_MONOTONIC, &ts))
55 dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
58 DrmDisplayCompositor::~DrmDisplayCompositor() {
64 int ret = pthread_mutex_lock(&lock_);
66 ALOGE("Failed to acquire compositor lock %d", ret);
68 while (!composite_queue_.empty()) {
69 composite_queue_.front().reset();
70 composite_queue_.pop();
72 active_composition_.reset();
74 ret = pthread_mutex_unlock(&lock_);
76 ALOGE("Failed to acquire compositor lock %d", ret);
78 pthread_mutex_destroy(&lock_);
81 int DrmDisplayCompositor::Init(DrmResources *drm, int display) {
85 int ret = pthread_mutex_init(&lock_, NULL);
87 ALOGE("Failed to initialize drm compositor lock %d\n", ret);
92 pthread_mutex_destroy(&lock_);
93 ALOGE("Failed to initialize compositor worker %d\n", ret);
101 int DrmDisplayCompositor::QueueComposition(
102 std::unique_ptr<DrmDisplayComposition> composition) {
103 switch (composition->type()) {
104 case DRM_COMPOSITION_TYPE_FRAME:
108 case DRM_COMPOSITION_TYPE_DPMS:
110 * Update the state as soon as we get it so we can start/stop queuing
113 active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON);
115 case DRM_COMPOSITION_TYPE_EMPTY:
118 ALOGE("Unknown composition type %d/%d", composition->type(), display_);
122 int ret = pthread_mutex_lock(&lock_);
124 ALOGE("Failed to acquire compositor lock %d", ret);
128 // Block the queue if it gets too large. Otherwise, SurfaceFlinger will start
129 // to eat our buffer handles when we get about 1 second behind.
130 while (composite_queue_.size() >= DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH) {
131 pthread_mutex_unlock(&lock_);
133 pthread_mutex_lock(&lock_);
136 composite_queue_.push(std::move(composition));
138 ret = pthread_mutex_unlock(&lock_);
140 ALOGE("Failed to release compositor lock %d", ret);
148 static bool drm_composition_layer_has_plane(
149 const DrmCompositionLayer &comp_layer) {
150 if (comp_layer.plane != NULL)
151 if (comp_layer.plane->type() == DRM_PLANE_TYPE_OVERLAY ||
152 comp_layer.plane->type() == DRM_PLANE_TYPE_PRIMARY)
157 static bool drm_composition_layer_has_no_plane(
158 const DrmCompositionLayer &comp_layer) {
159 return comp_layer.plane == NULL;
162 int DrmDisplayCompositor::ApplyPreComposite(
163 DrmDisplayComposition *display_comp) {
165 std::vector<DrmCompositionLayer> *layers =
166 display_comp->GetCompositionLayers();
168 DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
169 if (connector == NULL) {
170 ALOGE("Failed to determine display mode: no connector for display %d",
175 const DrmMode &mode = connector->active_mode();
176 DrmFramebuffer &fb = framebuffers_[framebuffer_index_];
177 ret = fb.WaitReleased(-1);
179 ALOGE("Failed to wait for framebuffer release %d", ret);
182 fb.set_release_fence_fd(-1);
183 if (!fb.Allocate(mode.h_display(), mode.v_display())) {
184 ALOGE("Failed to allocate framebuffer with size %dx%d", mode.h_display(),
189 std::vector<DrmCompositionLayer> pre_comp_layers;
190 for (auto &comp_layer : *layers) {
191 if (comp_layer.plane == NULL) {
192 pre_comp_layers.emplace_back(std::move(comp_layer));
196 ret = pre_compositor_->Composite(pre_comp_layers.data(),
197 pre_comp_layers.size(), fb.buffer());
198 pre_compositor_->Finish();
201 ALOGE("Failed to composite layers");
205 DrmCompositionLayer &pre_comp_layer =
206 layers->at(display_comp->pre_composition_layer_index());
207 ret = pre_comp_layer.buffer.ImportBuffer(fb.buffer()->handle,
208 display_comp->importer());
210 ALOGE("Failed to import handle of layer %d", ret);
213 pre_comp_layer.source_crop = DrmHwcRect<float>(0, 0, fb.buffer()->getWidth(),
214 fb.buffer()->getHeight());
215 pre_comp_layer.display_frame =
216 DrmHwcRect<int>(0, 0, fb.buffer()->getWidth(), fb.buffer()->getHeight());
218 // TODO(zachr) get a release fence
219 // fb.set_release_fence_fd(pre_comp_layer.release_fence.Release());
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 std::vector<DrmCompositionLayer> *layers =
243 display_comp->GetCompositionLayers();
244 for (DrmCompositionLayer &layer : *layers) {
245 int acquire_fence = layer.acquire_fence.get();
246 if (acquire_fence >= 0) {
247 ret = sync_wait(acquire_fence, -1);
249 ALOGE("Failed to wait for acquire %d/%d", acquire_fence, ret);
250 drmModePropertySetFree(pset);
253 layer.acquire_fence.Close();
256 DrmPlane *plane = layer.plane;
257 DrmCrtc *crtc = layer.crtc;
259 // Disable the plane if there's no crtc
261 ret = drmModePropertySetAdd(pset, plane->id(),
262 plane->crtc_property().id(), 0) ||
263 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
266 ALOGE("Failed to add plane %d disable to pset", plane->id());
273 ALOGE("Expected a valid framebuffer for pset");
279 switch (layer.transform) {
280 case DrmHwcTransform::kFlipH:
281 rotation = 1 << DRM_REFLECT_X;
283 case DrmHwcTransform::kFlipV:
284 rotation = 1 << DRM_REFLECT_Y;
286 case DrmHwcTransform::kRotate90:
287 rotation = 1 << DRM_ROTATE_90;
289 case DrmHwcTransform::kRotate180:
290 rotation = 1 << DRM_ROTATE_180;
292 case DrmHwcTransform::kRotate270:
293 rotation = 1 << DRM_ROTATE_270;
295 case DrmHwcTransform::kIdentity:
299 ALOGE("Invalid transform value 0x%x given", layer.transform);
306 // TODO: Once we have atomic test, this should fall back to GL
307 if (rotation && plane->rotation_property().id() == 0) {
308 ALOGE("Rotation is not supported on plane %d", plane->id());
314 drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
316 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
317 layer.buffer->fb_id) ||
318 drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
319 layer.display_frame.left) ||
320 drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
321 layer.display_frame.top) ||
322 drmModePropertySetAdd(
323 pset, plane->id(), plane->crtc_w_property().id(),
324 layer.display_frame.right - layer.display_frame.left) ||
325 drmModePropertySetAdd(
326 pset, plane->id(), plane->crtc_h_property().id(),
327 layer.display_frame.bottom - layer.display_frame.top) ||
328 drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
329 (int)(layer.source_crop.left) << 16) ||
330 drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
331 (int)(layer.source_crop.top) << 16) ||
332 drmModePropertySetAdd(
333 pset, plane->id(), plane->src_w_property().id(),
334 (int)(layer.source_crop.right - layer.source_crop.left) << 16) ||
335 drmModePropertySetAdd(
336 pset, plane->id(), plane->src_h_property().id(),
337 (int)(layer.source_crop.bottom - layer.source_crop.top) << 16);
339 ALOGE("Failed to add plane %d to set", plane->id());
343 if (plane->rotation_property().id()) {
344 ret = drmModePropertySetAdd(pset, plane->id(),
345 plane->rotation_property().id(), rotation);
347 ALOGE("Failed to add rotation property %d to plane %d",
348 plane->rotation_property().id(), plane->id());
355 ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset);
357 ALOGE("Failed to commit pset ret=%d\n", ret);
360 drmModePropertySetFree(pset);
365 int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
366 DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
368 ALOGE("Failed to get DrmConnector for display %d", display_);
372 const DrmProperty &prop = conn->dpms_property();
373 int ret = drmModeConnectorSetProperty(drm_->fd(), conn->id(), prop.id(),
374 display_comp->dpms_mode());
376 ALOGE("Failed to set DPMS property for connector %d", conn->id());
382 int DrmDisplayCompositor::Composite() {
385 if (!pre_compositor_) {
386 pre_compositor_.reset(new GLWorkerCompositor());
387 int ret = pre_compositor_->Init();
389 ALOGE("Failed to initialize OpenGL compositor %d", ret);
394 int ret = pthread_mutex_lock(&lock_);
396 ALOGE("Failed to acquire compositor lock %d", ret);
399 if (composite_queue_.empty()) {
400 ret = pthread_mutex_unlock(&lock_);
402 ALOGE("Failed to release compositor lock %d", ret);
406 std::unique_ptr<DrmDisplayComposition> composition(
407 std::move(composite_queue_.front()));
409 composite_queue_.pop();
411 ret = pthread_mutex_unlock(&lock_);
413 ALOGE("Failed to release compositor lock %d", ret);
417 switch (composition->type()) {
418 case DRM_COMPOSITION_TYPE_FRAME:
419 ret = ApplyFrame(composition.get());
421 ALOGE("Composite failed for display %d", display_);
424 ++dump_frames_composited_;
426 case DRM_COMPOSITION_TYPE_DPMS:
427 ret = ApplyDpms(composition.get());
429 ALOGE("Failed to apply dpms for display %d", display_);
432 ALOGE("Unknown composition type %d", composition->type());
436 if (active_composition_)
437 active_composition_->FinishComposition();
439 ret = pthread_mutex_lock(&lock_);
441 ALOGE("Failed to acquire lock for active_composition swap");
443 active_composition_.swap(composition);
446 ret = pthread_mutex_unlock(&lock_);
448 ALOGE("Failed to release lock for active_composition swap");
453 bool DrmDisplayCompositor::HaveQueuedComposites() const {
454 int ret = pthread_mutex_lock(&lock_);
456 ALOGE("Failed to acquire compositor lock %d", ret);
460 bool empty_ret = !composite_queue_.empty();
462 ret = pthread_mutex_unlock(&lock_);
464 ALOGE("Failed to release compositor lock %d", ret);
471 struct DrmDumpLayer {
474 DrmHwcTransform transform;
475 DrmHwcRect<float> source_crop;
476 DrmHwcRect<int> display_frame;
478 DrmDumpLayer(DrmCompositionLayer &rhs)
479 : plane_id(rhs.plane->id()),
480 crtc_id(rhs.crtc ? rhs.crtc->id() : -1),
481 transform(rhs.transform),
482 source_crop(rhs.source_crop),
483 display_frame(rhs.display_frame) {
487 void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
490 int ret = pthread_mutex_lock(&lock_);
494 uint64_t num_frames = dump_frames_composited_;
495 dump_frames_composited_ = 0;
498 ret = clock_gettime(CLOCK_MONOTONIC, &ts);
500 std::vector<DrmCompositionLayer> *input_layers =
501 active_composition_->GetCompositionLayers();
502 std::vector<DrmDumpLayer> layers;
503 if (active_composition_)
504 layers.insert(layers.begin(), input_layers->begin(), input_layers->end());
508 ret |= pthread_mutex_unlock(&lock_);
512 cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
513 uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
514 float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f;
516 *out << "--DrmDisplayCompositor[" << display_
517 << "]: num_frames=" << num_frames << " num_ms=" << num_ms
518 << " fps=" << fps << "\n";
520 dump_last_timestamp_ns_ = cur_ts;
522 *out << "---- DrmDisplayCompositor Layers: num=" << layers.size() << "\n";
523 for (std::vector<DrmDumpLayer>::iterator iter = layers.begin();
524 iter != layers.end(); ++iter) {
525 *out << "------ DrmDisplayCompositor Layer: plane=" << iter->plane_id
528 if (iter->crtc_id < 0) {
529 *out << "disabled\n";
533 *out << "crtc=" << iter->crtc_id
534 << " crtc[x/y/w/h]=" << iter->display_frame.left << "/"
535 << iter->display_frame.top << "/"
536 << iter->display_frame.right - iter->display_frame.left << "/"
537 << iter->display_frame.bottom - iter->display_frame.top << " "
538 << " src[x/y/w/h]=" << iter->source_crop.left << "/"
539 << iter->source_crop.top << "/"
540 << iter->source_crop.right - iter->source_crop.left << "/"
541 << iter->source_crop.bottom - iter->source_crop.top
542 << " transform=" << (uint32_t)iter->transform << "\n";