drmdisplaycompositor.cpp revision 98e73c89a683a92f44c99fb8dc85e51bdda243ba
1/* 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" 24 25#include <pthread.h> 26#include <sstream> 27#include <stdlib.h> 28#include <time.h> 29#include <vector> 30 31#include <cutils/log.h> 32#include <sync/sync.h> 33#include <utils/Trace.h> 34 35namespace android { 36 37DrmDisplayCompositor::DrmDisplayCompositor() 38 : drm_(NULL), 39 display_(-1), 40 worker_(this), 41 frame_no_(0), 42 initialized_(false), 43 dump_frames_composited_(0), 44 dump_last_timestamp_ns_(0) { 45 struct timespec ts; 46 if (clock_gettime(CLOCK_MONOTONIC, &ts)) 47 return; 48 dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; 49} 50 51DrmDisplayCompositor::~DrmDisplayCompositor() { 52 if (!initialized_) 53 return; 54 55 worker_.Exit(); 56 57 int ret = pthread_mutex_lock(&lock_); 58 if (ret) 59 ALOGE("Failed to acquire compositor lock %d", ret); 60 61 while (!composite_queue_.empty()) { 62 composite_queue_.front().reset(); 63 composite_queue_.pop(); 64 } 65 active_composition_.reset(); 66 67 ret = pthread_mutex_unlock(&lock_); 68 if (ret) 69 ALOGE("Failed to acquire compositor lock %d", ret); 70 71 pthread_mutex_destroy(&lock_); 72} 73 74int DrmDisplayCompositor::Init(DrmResources *drm, int display) { 75 drm_ = drm; 76 display_ = display; 77 78 int ret = pthread_mutex_init(&lock_, NULL); 79 if (ret) { 80 ALOGE("Failed to initialize drm compositor lock %d\n", ret); 81 return ret; 82 } 83 ret = worker_.Init(); 84 if (ret) { 85 pthread_mutex_destroy(&lock_); 86 ALOGE("Failed to initialize compositor worker %d\n", ret); 87 return ret; 88 } 89 90 initialized_ = true; 91 return 0; 92} 93 94int DrmDisplayCompositor::QueueComposition( 95 std::unique_ptr<DrmDisplayComposition> composition) { 96 if (composition->GetCompositionLayers()->empty()) 97 return 0; 98 99 int ret = pthread_mutex_lock(&lock_); 100 if (ret) { 101 ALOGE("Failed to acquire compositor lock %d", ret); 102 return ret; 103 } 104 105 composite_queue_.push(std::move(composition)); 106 107 ret = pthread_mutex_unlock(&lock_); 108 if (ret) { 109 ALOGE("Failed to release compositor lock %d", ret); 110 return ret; 111 } 112 113 worker_.Signal(); 114 return 0; 115} 116 117int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) { 118 int ret = 0; 119 120 drmModePropertySetPtr pset = drmModePropertySetAlloc(); 121 if (!pset) { 122 ALOGE("Failed to allocate property set"); 123 return -ENOMEM; 124 } 125 126 DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers(); 127 for (DrmCompositionLayerVector_t::iterator iter = layers->begin(); 128 iter != layers->end(); ++iter) { 129 hwc_layer_1_t *layer = &iter->layer; 130 131 if (layer->acquireFenceFd >= 0) { 132 ret = sync_wait(layer->acquireFenceFd, -1); 133 if (ret) { 134 ALOGE("Failed to wait for acquire %d/%d", layer->acquireFenceFd, ret); 135 drmModePropertySetFree(pset); 136 return ret; 137 } 138 close(layer->acquireFenceFd); 139 layer->acquireFenceFd = -1; 140 } 141 142 DrmPlane *plane = iter->plane; 143 ret = 144 drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(), 145 iter->crtc->id()) || 146 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(), 147 iter->bo.fb_id) || 148 drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(), 149 layer->displayFrame.left) || 150 drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(), 151 layer->displayFrame.top) || 152 drmModePropertySetAdd( 153 pset, plane->id(), plane->crtc_w_property().id(), 154 layer->displayFrame.right - layer->displayFrame.left) || 155 drmModePropertySetAdd( 156 pset, plane->id(), plane->crtc_h_property().id(), 157 layer->displayFrame.bottom - layer->displayFrame.top) || 158 drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(), 159 layer->sourceCropf.left) || 160 drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(), 161 layer->sourceCropf.top) || 162 drmModePropertySetAdd( 163 pset, plane->id(), plane->src_w_property().id(), 164 (int)(layer->sourceCropf.right - layer->sourceCropf.left) << 16) || 165 drmModePropertySetAdd( 166 pset, plane->id(), plane->src_h_property().id(), 167 (int)(layer->sourceCropf.bottom - layer->sourceCropf.top) << 16); 168 if (ret) { 169 ALOGE("Failed to add plane %d to set", plane->id()); 170 break; 171 } 172 } 173 174 if (!ret) { 175 ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset); 176 if (ret) 177 ALOGE("Failed to commit pset ret=%d\n", ret); 178 } 179 if (pset) 180 drmModePropertySetFree(pset); 181 182 return ret; 183} 184 185int DrmDisplayCompositor::Composite() { 186 ATRACE_CALL(); 187 int ret = pthread_mutex_lock(&lock_); 188 if (ret) { 189 ALOGE("Failed to acquire compositor lock %d", ret); 190 return ret; 191 } 192 if (composite_queue_.empty()) { 193 ret = pthread_mutex_unlock(&lock_); 194 if (ret) 195 ALOGE("Failed to release compositor lock %d", ret); 196 return ret; 197 } 198 199 std::unique_ptr<DrmDisplayComposition> composition( 200 std::move(composite_queue_.front())); 201 composite_queue_.pop(); 202 203 ret = pthread_mutex_unlock(&lock_); 204 if (ret) { 205 ALOGE("Failed to release compositor lock %d", ret); 206 return ret; 207 } 208 209 ret = ApplyFrame(composition.get()); 210 if (ret) { 211 ALOGE("Composite failed for display %d", display_); 212 return ret; 213 } 214 ++dump_frames_composited_; 215 216 if (active_composition_) 217 active_composition_->FinishComposition(); 218 219 active_composition_.swap(composition); 220 return ret; 221} 222 223bool DrmDisplayCompositor::HaveQueuedComposites() const { 224 int ret = pthread_mutex_lock(&lock_); 225 if (ret) { 226 ALOGE("Failed to acquire compositor lock %d", ret); 227 return false; 228 } 229 230 bool empty_ret = !composite_queue_.empty(); 231 232 ret = pthread_mutex_unlock(&lock_); 233 if (ret) { 234 ALOGE("Failed to release compositor lock %d", ret); 235 return false; 236 } 237 238 return empty_ret; 239} 240 241void DrmDisplayCompositor::Dump(std::ostringstream *out) const { 242 uint64_t cur_ts; 243 244 int ret = pthread_mutex_lock(&lock_); 245 if (ret) 246 return; 247 248 uint64_t num_frames = dump_frames_composited_; 249 dump_frames_composited_ = 0; 250 251 struct timespec ts; 252 ret = clock_gettime(CLOCK_MONOTONIC, &ts); 253 254 ret |= pthread_mutex_unlock(&lock_); 255 if (ret) 256 return; 257 258 cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; 259 uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000); 260 unsigned fps = num_ms ? (num_frames * 1000) / (num_ms) : 0; 261 262 *out << "--DrmDisplayCompositor[" << display_ 263 << "]: num_frames=" << num_frames << " num_ms=" << num_ms 264 << " fps=" << fps << "\n"; 265 266 dump_last_timestamp_ns_ = cur_ts; 267} 268} 269