drmdisplaycompositor.cpp revision b4a9aeff843e2a834335a4db0fef388ae37b423d
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 active_(false), 44 dump_frames_composited_(0), 45 dump_last_timestamp_ns_(0) { 46 struct timespec ts; 47 if (clock_gettime(CLOCK_MONOTONIC, &ts)) 48 return; 49 dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; 50} 51 52DrmDisplayCompositor::~DrmDisplayCompositor() { 53 if (!initialized_) 54 return; 55 56 worker_.Exit(); 57 58 int ret = pthread_mutex_lock(&lock_); 59 if (ret) 60 ALOGE("Failed to acquire compositor lock %d", ret); 61 62 while (!composite_queue_.empty()) { 63 composite_queue_.front().reset(); 64 composite_queue_.pop(); 65 } 66 active_composition_.reset(); 67 68 ret = pthread_mutex_unlock(&lock_); 69 if (ret) 70 ALOGE("Failed to acquire compositor lock %d", ret); 71 72 pthread_mutex_destroy(&lock_); 73} 74 75int DrmDisplayCompositor::Init(DrmResources *drm, int display) { 76 drm_ = drm; 77 display_ = display; 78 79 int ret = pthread_mutex_init(&lock_, NULL); 80 if (ret) { 81 ALOGE("Failed to initialize drm compositor lock %d\n", ret); 82 return ret; 83 } 84 ret = worker_.Init(); 85 if (ret) { 86 pthread_mutex_destroy(&lock_); 87 ALOGE("Failed to initialize compositor worker %d\n", ret); 88 return ret; 89 } 90 91 initialized_ = true; 92 return 0; 93} 94 95int DrmDisplayCompositor::QueueComposition( 96 std::unique_ptr<DrmDisplayComposition> composition) { 97 switch (composition->type()) { 98 case DRM_COMPOSITION_TYPE_FRAME: 99 if (!active_) 100 return -ENODEV; 101 break; 102 case DRM_COMPOSITION_TYPE_DPMS: 103 /* 104 * Update the state as soon as we get it so we can start/stop queuing 105 * frames asap. 106 */ 107 active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON); 108 break; 109 case DRM_COMPOSITION_TYPE_EMPTY: 110 return 0; 111 default: 112 ALOGE("Unknown composition type %d/%d", composition->type(), display_); 113 return -ENOENT; 114 } 115 116 int ret = pthread_mutex_lock(&lock_); 117 if (ret) { 118 ALOGE("Failed to acquire compositor lock %d", ret); 119 return ret; 120 } 121 122 composite_queue_.push(std::move(composition)); 123 124 ret = pthread_mutex_unlock(&lock_); 125 if (ret) { 126 ALOGE("Failed to release compositor lock %d", ret); 127 return ret; 128 } 129 130 worker_.Signal(); 131 return 0; 132} 133 134int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) { 135 int ret = 0; 136 137 drmModePropertySetPtr pset = drmModePropertySetAlloc(); 138 if (!pset) { 139 ALOGE("Failed to allocate property set"); 140 return -ENOMEM; 141 } 142 143 DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers(); 144 for (DrmCompositionLayerVector_t::iterator iter = layers->begin(); 145 iter != layers->end(); ++iter) { 146 hwc_layer_1_t *layer = &iter->layer; 147 148 if (layer->acquireFenceFd >= 0) { 149 ret = sync_wait(layer->acquireFenceFd, -1); 150 if (ret) { 151 ALOGE("Failed to wait for acquire %d/%d", layer->acquireFenceFd, ret); 152 drmModePropertySetFree(pset); 153 return ret; 154 } 155 close(layer->acquireFenceFd); 156 layer->acquireFenceFd = -1; 157 } 158 159 DrmPlane *plane = iter->plane; 160 ret = 161 drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(), 162 iter->crtc->id()) || 163 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(), 164 iter->bo.fb_id) || 165 drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(), 166 layer->displayFrame.left) || 167 drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(), 168 layer->displayFrame.top) || 169 drmModePropertySetAdd( 170 pset, plane->id(), plane->crtc_w_property().id(), 171 layer->displayFrame.right - layer->displayFrame.left) || 172 drmModePropertySetAdd( 173 pset, plane->id(), plane->crtc_h_property().id(), 174 layer->displayFrame.bottom - layer->displayFrame.top) || 175 drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(), 176 layer->sourceCropf.left) || 177 drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(), 178 layer->sourceCropf.top) || 179 drmModePropertySetAdd( 180 pset, plane->id(), plane->src_w_property().id(), 181 (int)(layer->sourceCropf.right - layer->sourceCropf.left) << 16) || 182 drmModePropertySetAdd( 183 pset, plane->id(), plane->src_h_property().id(), 184 (int)(layer->sourceCropf.bottom - layer->sourceCropf.top) << 16); 185 if (ret) { 186 ALOGE("Failed to add plane %d to set", plane->id()); 187 break; 188 } 189 } 190 191 if (!ret) { 192 ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset); 193 if (ret) 194 ALOGE("Failed to commit pset ret=%d\n", ret); 195 } 196 if (pset) 197 drmModePropertySetFree(pset); 198 199 return ret; 200} 201 202int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) { 203 DrmConnector *conn = drm_->GetConnectorForDisplay(display_); 204 if (!conn) { 205 ALOGE("Failed to get DrmConnector for display %d", display_); 206 return -ENODEV; 207 } 208 209 const DrmProperty &prop = conn->dpms_property(); 210 int ret = drmModeConnectorSetProperty(drm_->fd(), conn->id(), prop.id(), 211 display_comp->dpms_mode()); 212 if (ret) { 213 ALOGE("Failed to set DPMS property for connector %d", conn->id()); 214 return ret; 215 } 216 return 0; 217} 218 219int DrmDisplayCompositor::Composite() { 220 ATRACE_CALL(); 221 int ret = pthread_mutex_lock(&lock_); 222 if (ret) { 223 ALOGE("Failed to acquire compositor lock %d", ret); 224 return ret; 225 } 226 if (composite_queue_.empty()) { 227 ret = pthread_mutex_unlock(&lock_); 228 if (ret) 229 ALOGE("Failed to release compositor lock %d", ret); 230 return ret; 231 } 232 233 std::unique_ptr<DrmDisplayComposition> composition( 234 std::move(composite_queue_.front())); 235 composite_queue_.pop(); 236 237 ret = pthread_mutex_unlock(&lock_); 238 if (ret) { 239 ALOGE("Failed to release compositor lock %d", ret); 240 return ret; 241 } 242 243 switch (composition->type()) { 244 case DRM_COMPOSITION_TYPE_FRAME: 245 ret = ApplyFrame(composition.get()); 246 if (ret) { 247 ALOGE("Composite failed for display %d", display_); 248 return ret; 249 } 250 ++dump_frames_composited_; 251 break; 252 case DRM_COMPOSITION_TYPE_DPMS: 253 ret = ApplyDpms(composition.get()); 254 if (ret) 255 ALOGE("Failed to apply dpms for display %d", display_); 256 return ret; 257 default: 258 ALOGE("Unknown composition type %d", composition->type()); 259 return -EINVAL; 260 } 261 262 if (active_composition_) 263 active_composition_->FinishComposition(); 264 265 active_composition_.swap(composition); 266 return ret; 267} 268 269bool DrmDisplayCompositor::HaveQueuedComposites() const { 270 int ret = pthread_mutex_lock(&lock_); 271 if (ret) { 272 ALOGE("Failed to acquire compositor lock %d", ret); 273 return false; 274 } 275 276 bool empty_ret = !composite_queue_.empty(); 277 278 ret = pthread_mutex_unlock(&lock_); 279 if (ret) { 280 ALOGE("Failed to release compositor lock %d", ret); 281 return false; 282 } 283 284 return empty_ret; 285} 286 287void DrmDisplayCompositor::Dump(std::ostringstream *out) const { 288 uint64_t cur_ts; 289 290 int ret = pthread_mutex_lock(&lock_); 291 if (ret) 292 return; 293 294 uint64_t num_frames = dump_frames_composited_; 295 dump_frames_composited_ = 0; 296 297 struct timespec ts; 298 ret = clock_gettime(CLOCK_MONOTONIC, &ts); 299 300 ret |= pthread_mutex_unlock(&lock_); 301 if (ret) 302 return; 303 304 cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; 305 uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000); 306 unsigned fps = num_ms ? (num_frames * 1000) / (num_ms) : 0; 307 308 *out << "--DrmDisplayCompositor[" << display_ 309 << "]: num_frames=" << num_frames << " num_ms=" << num_ms 310 << " fps=" << fps << "\n"; 311 312 dump_last_timestamp_ns_ = cur_ts; 313} 314} 315