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"
31 #include <drm/drm_mode.h>
32 #include <cutils/log.h>
33 #include <sync/sync.h>
34 #include <utils/Trace.h>
38 DrmDisplayCompositor::DrmDisplayCompositor()
45 dump_frames_composited_(0),
46 dump_last_timestamp_ns_(0) {
48 if (clock_gettime(CLOCK_MONOTONIC, &ts))
50 dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
53 DrmDisplayCompositor::~DrmDisplayCompositor() {
59 int ret = pthread_mutex_lock(&lock_);
61 ALOGE("Failed to acquire compositor lock %d", ret);
63 while (!composite_queue_.empty()) {
64 composite_queue_.front().reset();
65 composite_queue_.pop();
67 active_composition_.reset();
69 ret = pthread_mutex_unlock(&lock_);
71 ALOGE("Failed to acquire compositor lock %d", ret);
73 pthread_mutex_destroy(&lock_);
76 int DrmDisplayCompositor::Init(DrmResources *drm, int display) {
80 int ret = pthread_mutex_init(&lock_, NULL);
82 ALOGE("Failed to initialize drm compositor lock %d\n", ret);
87 pthread_mutex_destroy(&lock_);
88 ALOGE("Failed to initialize compositor worker %d\n", ret);
96 int DrmDisplayCompositor::QueueComposition(
97 std::unique_ptr<DrmDisplayComposition> composition) {
98 switch (composition->type()) {
99 case DRM_COMPOSITION_TYPE_FRAME:
103 case DRM_COMPOSITION_TYPE_DPMS:
105 * Update the state as soon as we get it so we can start/stop queuing
108 active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON);
110 case DRM_COMPOSITION_TYPE_EMPTY:
113 ALOGE("Unknown composition type %d/%d", composition->type(), display_);
117 int ret = pthread_mutex_lock(&lock_);
119 ALOGE("Failed to acquire compositor lock %d", ret);
123 composite_queue_.push(std::move(composition));
125 ret = pthread_mutex_unlock(&lock_);
127 ALOGE("Failed to release compositor lock %d", ret);
135 int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
138 drmModePropertySetPtr pset = drmModePropertySetAlloc();
140 ALOGE("Failed to allocate property set");
144 DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
145 for (DrmCompositionLayerVector_t::iterator iter = layers->begin();
146 iter != layers->end(); ++iter) {
147 hwc_layer_1_t *layer = &iter->layer;
149 if (layer->acquireFenceFd >= 0) {
150 ret = sync_wait(layer->acquireFenceFd, -1);
152 ALOGE("Failed to wait for acquire %d/%d", layer->acquireFenceFd, ret);
153 drmModePropertySetFree(pset);
156 close(layer->acquireFenceFd);
157 layer->acquireFenceFd = -1;
160 DrmPlane *plane = iter->plane;
161 DrmCrtc *crtc = iter->crtc;
163 // Disable the plane if there's no crtc
166 drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
168 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
171 ALOGE("Failed to add plane %d disable to pset", plane->id());
178 switch (layer->transform) {
179 case HWC_TRANSFORM_FLIP_H:
180 rotation = 1 << DRM_REFLECT_X;
182 case HWC_TRANSFORM_FLIP_V:
183 rotation = 1 << DRM_REFLECT_Y;
185 case HWC_TRANSFORM_ROT_90:
186 rotation = 1 << DRM_ROTATE_90;
188 case HWC_TRANSFORM_ROT_180:
189 rotation = 1 << DRM_ROTATE_180;
191 case HWC_TRANSFORM_ROT_270:
192 rotation = 1 << DRM_ROTATE_270;
198 ALOGE("Invalid transform value 0x%x given", layer->transform);
202 // TODO: Once we have atomic test, this should fall back to GL
203 if (rotation && plane->rotation_property().id() == 0) {
204 ALOGE("Rotation is not supported on plane %d", plane->id());
210 drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
212 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
214 drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
215 layer->displayFrame.left) ||
216 drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
217 layer->displayFrame.top) ||
218 drmModePropertySetAdd(
219 pset, plane->id(), plane->crtc_w_property().id(),
220 layer->displayFrame.right - layer->displayFrame.left) ||
221 drmModePropertySetAdd(
222 pset, plane->id(), plane->crtc_h_property().id(),
223 layer->displayFrame.bottom - layer->displayFrame.top) ||
224 drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
225 (int)(layer->sourceCropf.left) << 16) ||
226 drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
227 (int)(layer->sourceCropf.top) << 16) ||
228 drmModePropertySetAdd(
229 pset, plane->id(), plane->src_w_property().id(),
230 (int)(layer->sourceCropf.right - layer->sourceCropf.left) << 16) ||
231 drmModePropertySetAdd(
232 pset, plane->id(), plane->src_h_property().id(),
233 (int)(layer->sourceCropf.bottom - layer->sourceCropf.top) << 16);
235 ALOGE("Failed to add plane %d to set", plane->id());
239 if (plane->rotation_property().id()) {
240 ret = drmModePropertySetAdd(
241 pset, plane->id(), plane->rotation_property().id(), rotation);
243 ALOGE("Failed to add rotation property %d to plane %d",
244 plane->rotation_property().id(), plane->id());
251 ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset);
253 ALOGE("Failed to commit pset ret=%d\n", ret);
256 drmModePropertySetFree(pset);
261 int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
262 DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
264 ALOGE("Failed to get DrmConnector for display %d", display_);
268 const DrmProperty &prop = conn->dpms_property();
269 int ret = drmModeConnectorSetProperty(drm_->fd(), conn->id(), prop.id(),
270 display_comp->dpms_mode());
272 ALOGE("Failed to set DPMS property for connector %d", conn->id());
278 int DrmDisplayCompositor::Composite() {
280 int ret = pthread_mutex_lock(&lock_);
282 ALOGE("Failed to acquire compositor lock %d", ret);
285 if (composite_queue_.empty()) {
286 ret = pthread_mutex_unlock(&lock_);
288 ALOGE("Failed to release compositor lock %d", ret);
292 std::unique_ptr<DrmDisplayComposition> composition(
293 std::move(composite_queue_.front()));
294 composite_queue_.pop();
296 ret = pthread_mutex_unlock(&lock_);
298 ALOGE("Failed to release compositor lock %d", ret);
302 switch (composition->type()) {
303 case DRM_COMPOSITION_TYPE_FRAME:
304 ret = ApplyFrame(composition.get());
306 ALOGE("Composite failed for display %d", display_);
309 ++dump_frames_composited_;
311 case DRM_COMPOSITION_TYPE_DPMS:
312 ret = ApplyDpms(composition.get());
314 ALOGE("Failed to apply dpms for display %d", display_);
317 ALOGE("Unknown composition type %d", composition->type());
321 if (active_composition_)
322 active_composition_->FinishComposition();
324 ret = pthread_mutex_lock(&lock_);
326 ALOGE("Failed to acquire lock for active_composition swap");
328 active_composition_.swap(composition);
331 ret = pthread_mutex_unlock(&lock_);
333 ALOGE("Failed to release lock for active_composition swap");
338 bool DrmDisplayCompositor::HaveQueuedComposites() const {
339 int ret = pthread_mutex_lock(&lock_);
341 ALOGE("Failed to acquire compositor lock %d", ret);
345 bool empty_ret = !composite_queue_.empty();
347 ret = pthread_mutex_unlock(&lock_);
349 ALOGE("Failed to release compositor lock %d", ret);
356 void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
359 int ret = pthread_mutex_lock(&lock_);
363 uint64_t num_frames = dump_frames_composited_;
364 dump_frames_composited_ = 0;
367 ret = clock_gettime(CLOCK_MONOTONIC, &ts);
369 DrmCompositionLayerVector_t layers;
370 if (active_composition_)
371 layers = *active_composition_->GetCompositionLayers();
375 ret |= pthread_mutex_unlock(&lock_);
379 cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
380 uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
381 float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f;
383 *out << "--DrmDisplayCompositor[" << display_
384 << "]: num_frames=" << num_frames << " num_ms=" << num_ms
385 << " fps=" << fps << "\n";
387 dump_last_timestamp_ns_ = cur_ts;
389 *out << "---- DrmDisplayCompositor Layers: num=" << layers.size() << "\n";
390 for (DrmCompositionLayerVector_t::iterator iter = layers.begin();
391 iter != layers.end(); ++iter) {
392 hwc_layer_1_t *layer = &iter->layer;
393 DrmPlane *plane = iter->plane;
395 *out << "------ DrmDisplayCompositor Layer: plane=" << plane->id() << " ";
397 DrmCrtc *crtc = iter->crtc;
399 *out << "disabled\n";
403 *out << "crtc=" << crtc->id() << " crtc[x/y/w/h]=" <<
404 layer->displayFrame.left << "/" << layer->displayFrame.top << "/" <<
405 layer->displayFrame.right - layer->displayFrame.left << "/" <<
406 layer->displayFrame.bottom - layer->displayFrame.top << " " <<
407 " src[x/y/w/h]=" << layer->sourceCropf.left << "/" <<
408 layer->sourceCropf.top << "/" <<
409 layer->sourceCropf.right - layer->sourceCropf.left << "/" <<
410 layer->sourceCropf.bottom - layer->sourceCropf.top << " transform=" <<
411 layer->transform << "\n";