blob: 0c6d445e209adcc5b8319a552ee4d16bf9be6e23 [file] [log] [blame]
Sean Paulb386f1b2015-05-13 06:33:23 -07001/*
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
Stéphane Marchesinbe98c8c2015-06-23 16:18:10 -070017#define ATRACE_TAG ATRACE_TAG_GRAPHICS
Sean Paulb386f1b2015-05-13 06:33:23 -070018#define LOG_TAG "hwc-drm-compositor"
19
20#include "drmcompositor.h"
21#include "drmcrtc.h"
22#include "drmplane.h"
23#include "drmresources.h"
24
25#include <pthread.h>
Sean Paulc8dcfe02015-06-10 17:29:05 -040026#include <sstream>
Sean Paulb386f1b2015-05-13 06:33:23 -070027#include <stdlib.h>
Sean Paulc8dcfe02015-06-10 17:29:05 -040028#include <time.h>
Stéphane Marchesinbe98c8c2015-06-23 16:18:10 -070029#include <utils/Trace.h>
Sean Paulb386f1b2015-05-13 06:33:23 -070030
31#include <cutils/log.h>
32#include <sync/sync.h>
33
34namespace android {
35
36DrmCompositor::DrmCompositor(DrmResources *drm)
37 : drm_(drm),
38 worker_(this),
39 active_composition_(NULL),
40 frame_no_(0),
Sean Paulc8dcfe02015-06-10 17:29:05 -040041 initialized_(false),
42 dump_frames_composited_(0),
43 dump_last_timestamp_ns_(0) {
44 struct timespec ts;
45 if (clock_gettime(CLOCK_MONOTONIC, &ts))
46 return;
47 dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
Sean Paulb386f1b2015-05-13 06:33:23 -070048}
49
50DrmCompositor::~DrmCompositor() {
51 if (initialized_)
52 pthread_mutex_destroy(&lock_);
53}
54
55int DrmCompositor::Init() {
56 int ret = pthread_mutex_init(&lock_, NULL);
57 if (ret) {
58 ALOGE("Failed to initialize drm compositor lock %d\n", ret);
59 return ret;
60 }
61 ret = worker_.Init();
62 if (ret) {
63 pthread_mutex_destroy(&lock_);
64 ALOGE("Failed to initialize compositor worker %d\n", ret);
65 return ret;
66 }
67
68 initialized_ = true;
69 return 0;
70}
71
72Composition *DrmCompositor::CreateComposition(Importer *importer) {
73 DrmComposition *composition = new DrmComposition(drm_, importer, frame_no_++);
74 if (!composition) {
75 ALOGE("Failed to allocate drm composition");
76 return NULL;
77 }
78 int ret = composition->Init();
79 if (ret) {
80 ALOGE("Failed to initialize drm composition %d", ret);
81 delete composition;
82 return NULL;
83 }
84 return composition;
85}
86
87int DrmCompositor::QueueComposition(Composition *composition) {
88 int ret = pthread_mutex_lock(&lock_);
89 if (ret) {
90 ALOGE("Failed to acquire compositor lock %d", ret);
91 return ret;
92 }
93
94 composite_queue_.push((DrmComposition *)composition);
95
96 ret = pthread_mutex_unlock(&lock_);
97 if (ret) {
98 ALOGE("Failed to release compositor lock %d", ret);
99 return ret;
100 }
101
102 worker_.Signal();
103 return 0;
104}
105
Sean Paulb386f1b2015-05-13 06:33:23 -0700106int DrmCompositor::CompositeDisplay(DrmCompositionLayerMap_t::iterator begin,
107 DrmCompositionLayerMap_t::iterator end) {
108 int ret = 0;
109 // Wait for all acquire fences to signal
110 for (DrmCompositionLayerMap_t::iterator iter = begin; iter != end; ++iter) {
111 hwc_layer_1_t *layer = &iter->second.layer;
112
113 if (layer->acquireFenceFd < 0)
114 continue;
115
116 ret = sync_wait(layer->acquireFenceFd, -1);
117 if (ret) {
118 ALOGE("Failed to wait for acquire %d/%d", layer->acquireFenceFd, ret);
119 return ret;
120 }
121 close(layer->acquireFenceFd);
122 layer->acquireFenceFd = -1;
123 }
124
Sean Paulb386f1b2015-05-13 06:33:23 -0700125 drmModePropertySetPtr pset = drmModePropertySetAlloc();
126 if (!pset) {
127 ALOGE("Failed to allocate property set");
128 return -ENOMEM;
129 }
130
131 for (DrmCompositionLayerMap_t::iterator iter = begin; iter != end; ++iter) {
132 DrmCompositionLayer_t *comp = &iter->second;
133 hwc_layer_1_t *layer = &comp->layer;
134 DrmPlane *plane = comp->plane;
135
136 ret =
137 drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
Sean Paul877be972015-06-03 14:08:27 -0400138 begin->second.crtc->id()) ||
Sean Paulb386f1b2015-05-13 06:33:23 -0700139 drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
140 comp->bo.fb_id) ||
141 drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
142 layer->displayFrame.left) ||
143 drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
144 layer->displayFrame.top) ||
145 drmModePropertySetAdd(
146 pset, plane->id(), plane->crtc_w_property().id(),
147 layer->displayFrame.right - layer->displayFrame.left) ||
148 drmModePropertySetAdd(
149 pset, plane->id(), plane->crtc_h_property().id(),
150 layer->displayFrame.bottom - layer->displayFrame.top) ||
151 drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
152 layer->sourceCropf.left) ||
153 drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
154 layer->sourceCropf.top) ||
155 drmModePropertySetAdd(
156 pset, plane->id(), plane->src_w_property().id(),
157 (int)(layer->sourceCropf.right - layer->sourceCropf.left) << 16) ||
158 drmModePropertySetAdd(
159 pset, plane->id(), plane->src_h_property().id(),
160 (int)(layer->sourceCropf.bottom - layer->sourceCropf.top) << 16);
161 if (ret) {
162 ALOGE("Failed to add plane %d to set", plane->id());
163 break;
164 }
165 }
166
167 if (!ret) {
168 ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset);
169 if (ret)
170 ALOGE("Failed to commit pset ret=%d\n", ret);
171 }
172 if (pset)
173 drmModePropertySetFree(pset);
174
175 return ret;
176}
177
178int DrmCompositor::Composite() {
Stéphane Marchesinbe98c8c2015-06-23 16:18:10 -0700179 ATRACE_CALL();
Sean Paulb386f1b2015-05-13 06:33:23 -0700180 int ret = pthread_mutex_lock(&lock_);
181 if (ret) {
182 ALOGE("Failed to acquire compositor lock %d", ret);
183 return ret;
184 }
185 if (composite_queue_.empty()) {
186 ret = pthread_mutex_unlock(&lock_);
187 if (ret)
188 ALOGE("Failed to release compositor lock %d", ret);
189 return ret;
190 }
191
192 DrmComposition *composition = composite_queue_.front();
193 composite_queue_.pop();
Sean Paulc8dcfe02015-06-10 17:29:05 -0400194 ++dump_frames_composited_;
Sean Paulb386f1b2015-05-13 06:33:23 -0700195
196 ret = pthread_mutex_unlock(&lock_);
197 if (ret) {
198 ALOGE("Failed to release compositor lock %d", ret);
199 return ret;
200 }
201
202 DrmCompositionLayerMap_t *map = composition->GetCompositionMap();
203 for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
204 iter != drm_->end_connectors(); ++iter) {
205 int display = (*iter)->display();
206 std::pair<DrmCompositionLayerMap_t::iterator,
207 DrmCompositionLayerMap_t::iterator> layer_iters =
208 map->equal_range(display);
209
210 if (layer_iters.first != layer_iters.second) {
211 ret = CompositeDisplay(layer_iters.first, layer_iters.second);
212 if (ret) {
213 ALOGE("Composite failed for display %d:", display);
214 break;
215 }
216 }
217 }
218
219 if (active_composition_) {
220 active_composition_->FinishComposition();
221 delete active_composition_;
222 }
223 active_composition_ = composition;
224 return ret;
225}
226
227bool DrmCompositor::HaveQueuedComposites() const {
228 int ret = pthread_mutex_lock(&lock_);
229 if (ret) {
230 ALOGE("Failed to acquire compositor lock %d", ret);
231 return false;
232 }
233
234 bool empty_ret = !composite_queue_.empty();
235
236 ret = pthread_mutex_unlock(&lock_);
237 if (ret) {
238 ALOGE("Failed to release compositor lock %d", ret);
239 return false;
240 }
241
242 return empty_ret;
243}
Sean Paulc8dcfe02015-06-10 17:29:05 -0400244
245void DrmCompositor::Dump(std::ostringstream *out) const {
246 uint64_t cur_ts;
247
248 int ret = pthread_mutex_lock(&lock_);
249 if (ret)
250 return;
251
252 uint64_t num_frames = dump_frames_composited_;
253 dump_frames_composited_ = 0;
254
255 struct timespec ts;
256 ret = clock_gettime(CLOCK_MONOTONIC, &ts);
257
258 ret |= pthread_mutex_unlock(&lock_);
259 if (ret)
260 return;
261
262 cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
263 uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
264 unsigned fps = num_ms ? (num_frames * 1000) / (num_ms) : 0;
265
266 *out << "DrmCompositor: num_frames=" << num_frames << " num_ms=" << num_ms <<
267 " fps=" << fps << "\n";
268
269 dump_last_timestamp_ns_ = cur_ts;
270}
Sean Paulb386f1b2015-05-13 06:33:23 -0700271}