blob: f18712c8c44cca54252cf4c760ff9ba114630e77 [file] [log] [blame]
Cody Schuffelen134ff032019-11-22 00:25:32 -08001/*
2 * Copyright (C) 2017 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#include <pthread.h>
18#include <sys/resource.h>
19#include <sys/time.h>
20
21#include <hardware/hwcomposer.h>
22#include <hardware/hwcomposer_defs.h>
23#include <log/log.h>
24
25#include "common/vsoc/lib/screen_region_view.h"
26#include "guest/hals/gralloc/gralloc_vsoc_priv.h"
27
28// This file contains just a skeleton hwcomposer, the first step in the
29// multisided vsoc hwcomposer for cuttlefish.
30
31using vsoc::screen::ScreenRegionView;
32
33// TODO(jemoreira): ScreenRegionView may become the HWC region
34namespace {
35
36// Ensures that the layer does not include any inconsistencies
37int SanityCheckLayer(const hwc_layer_1& layer) {
38 // Check displayFrame
39 if (layer.displayFrame.left > layer.displayFrame.right ||
40 layer.displayFrame.top > layer.displayFrame.bottom) {
41 ALOGE(
42 "%s: Malformed rectangle (displayFrame): [left = %d, right = %d, top = "
43 "%d, bottom = %d]",
44 __FUNCTION__, layer.displayFrame.left, layer.displayFrame.right,
45 layer.displayFrame.top, layer.displayFrame.bottom);
46 return -EINVAL;
47 }
48 // Check sourceCrop
49 if (layer.sourceCrop.left > layer.sourceCrop.right ||
50 layer.sourceCrop.top > layer.sourceCrop.bottom) {
51 ALOGE(
52 "%s: Malformed rectangle (sourceCrop): [left = %d, right = %d, top = "
53 "%d, bottom = %d]",
54 __FUNCTION__, layer.sourceCrop.left, layer.sourceCrop.right,
55 layer.sourceCrop.top, layer.sourceCrop.bottom);
56 return -EINVAL;
57 }
58 const vsoc_buffer_handle_t* p_handle =
59 reinterpret_cast<const vsoc_buffer_handle_t*>(layer.handle);
60 if (!p_handle) {
61 ALOGE("Layer has a NULL buffer handle");
62 return -EINVAL;
63 }
64 if (layer.sourceCrop.left < 0 || layer.sourceCrop.top < 0 ||
65 layer.sourceCrop.right > p_handle->x_res ||
66 layer.sourceCrop.bottom > p_handle->y_res) {
67 ALOGE(
68 "%s: Invalid sourceCrop for buffer handle: sourceCrop = [left = %d, "
69 "right = %d, top = %d, bottom = %d], handle = [width = %d, height = "
70 "%d]",
71 __FUNCTION__, layer.sourceCrop.left, layer.sourceCrop.right,
72 layer.sourceCrop.top, layer.sourceCrop.bottom, p_handle->x_res,
73 p_handle->y_res);
74 return -EINVAL;
75 }
76 return 0;
77}
78
79struct vsoc_hwc_device {
80 hwc_composer_device_1_t base;
81 const hwc_procs_t* procs;
82 pthread_t vsync_thread;
83 int64_t vsync_base_timestamp;
84 int32_t vsync_period_ns;
85 uint32_t frame_num;
86};
87
88void* vsync_thread(void* arg) {
89 vsoc_hwc_device* pdev = reinterpret_cast<vsoc_hwc_device*>(arg);
90 setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
91
92 int64_t base_timestamp = pdev->vsync_base_timestamp;
93 int64_t last_logged = base_timestamp / 1e9;
94 int sent = 0;
95 int last_sent = 0;
96 static const int log_interval = 60;
97 void (*vsync_proc)(const struct hwc_procs*, int, int64_t) = nullptr;
98 bool log_no_procs = true, log_no_vsync = true;
99 while (true) {
100 struct timespec rt;
101 if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) {
102 ALOGE("%s:%d error in vsync thread clock_gettime: %s", __FILE__, __LINE__,
103 strerror(errno));
104 }
105 int64_t timestamp = int64_t(rt.tv_sec) * 1e9 + rt.tv_nsec;
106 // Given now's timestamp calculate the time of the next vsync.
107 timestamp += pdev->vsync_period_ns -
108 (timestamp - base_timestamp) % pdev->vsync_period_ns;
109
110 rt.tv_sec = timestamp / 1e9;
111 rt.tv_nsec = timestamp % static_cast<int32_t>(1e9);
112 int err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &rt, NULL);
113 if (err == -1) {
114 ALOGE("error in vsync thread: %s", strerror(errno));
115 if (errno == EINTR) {
116 continue;
117 }
118 }
119
120 // The vsync thread is started on device open, it may run before the
121 // registerProcs callback has a chance to be called, so we need to make sure
122 // procs is not NULL before dereferencing it.
123 if (pdev && pdev->procs) {
124 vsync_proc = pdev->procs->vsync;
125 } else if (log_no_procs) {
126 log_no_procs = false;
127 ALOGI("procs is not set yet, unable to deliver vsync event");
128 }
129 if (vsync_proc) {
130 vsync_proc(const_cast<hwc_procs_t*>(pdev->procs), 0, timestamp);
131 ++sent;
132 } else if (log_no_vsync) {
133 log_no_vsync = false;
134 ALOGE("vsync callback is null (but procs was already set)");
135 }
136 if (rt.tv_sec - last_logged > log_interval) {
137 ALOGI("Sent %d syncs in %ds", sent - last_sent, log_interval);
138 last_logged = rt.tv_sec;
139 last_sent = sent;
140 }
141 }
142
143 return NULL;
144}
145
146int hwc_prepare(struct hwc_composer_device_1* /*dev*/, size_t numDisplays,
147 hwc_display_contents_1_t** displays) {
148 if (!numDisplays || !displays) return 0;
149 hwc_display_contents_1_t* list = displays[HWC_DISPLAY_PRIMARY];
150 if (!list) return 0;
151
152 for (size_t i = 0; i < list->numHwLayers; i++) {
153 if (list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) {
154 continue;
155 }
156 list->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
157 }
158
159 return 0;
160}
161
162int hwc_set(struct hwc_composer_device_1* dev, size_t numDisplays,
163 hwc_display_contents_1_t** displays) {
164 if (!numDisplays || !displays) return 0;
165 hwc_display_contents_1_t* list = displays[HWC_DISPLAY_PRIMARY];
166 if (!list) return 0;
167 if (!dev) {
168 ALOGE("%s: dev is NULL", __FUNCTION__);
169 return -EINVAL;
170 }
171
172 for (size_t i = 0; i < list->numHwLayers; i++) {
173 if (vsoc_buffer_handle_t::validate(list->hwLayers[i].handle)) {
174 return -EINVAL;
175 }
176 if (list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) {
177 if (SanityCheckLayer(list->hwLayers[i])) {
178 ALOGW("Skipping layer %zu due to failed sanity check", i);
179 continue;
180 }
181 const vsoc_buffer_handle_t* fb_handle =
182 reinterpret_cast<const vsoc_buffer_handle_t*>(
183 list->hwLayers[i].handle);
184 ScreenRegionView::GetInstance()->BroadcastNewFrame(fb_handle->offset);
185 break;
186 }
187 }
188
189 return 0;
190}
191
192int hwc_eventControl(struct hwc_composer_device_1* /*dev*/, int disp, int event,
193 int /*enabled*/) {
194 if (event == HWC_EVENT_VSYNC || disp != HWC_DISPLAY_PRIMARY) {
195 return 0;
196 }
197 return -EINVAL;
198}
199
200int hwc_blank(struct hwc_composer_device_1* /*dev*/, int disp, int /*blank*/) {
201 if (disp != HWC_DISPLAY_PRIMARY) {
202 return -EINVAL;
203 }
204 return 0;
205}
206
207int hwc_query(struct hwc_composer_device_1* dev, int what, int* value) {
208 vsoc_hwc_device* pdev = reinterpret_cast<vsoc_hwc_device*>(dev);
209 switch (what) {
210 case HWC_BACKGROUND_LAYER_SUPPORTED:
211 // we don't support the background layer
212 *value = 0;
213 break;
214 case HWC_VSYNC_PERIOD:
215 *value = pdev->vsync_period_ns;
216 break;
217 case HWC_DISPLAY_TYPES_SUPPORTED:
218 // We only support the primary display
219 *value = HWC_DISPLAY_PRIMARY_BIT;
220 break;
221 default:
222 // unsupported query
223 ALOGE("%s badness unsupported query what=%d", __FUNCTION__, what);
224 return -EINVAL;
225 }
226 return 0;
227}
228
229void hwc_registerProcs(struct hwc_composer_device_1* dev,
230 hwc_procs_t const* procs) {
231 reinterpret_cast<vsoc_hwc_device*>(dev)->procs = procs;
232}
233
234void hwc_dump(struct hwc_composer_device_1* /*dev*/, char* /*buff*/,
235 int /*buff_len*/) {}
236
237int hwc_getDisplayConfigs(struct hwc_composer_device_1* /*dev*/, int disp,
238 uint32_t* configs, size_t* numConfigs) {
239 if (*numConfigs == 0) return 0;
240
241 if (disp == HWC_DISPLAY_PRIMARY) {
242 configs[0] = 0;
243 *numConfigs = 1;
244 return 0;
245 }
246
247 return -EINVAL;
248}
249
250int32_t vsoc_hwc_attribute(uint32_t attribute) {
251 auto screen_view = ScreenRegionView::GetInstance();
252 switch (attribute) {
253 case HWC_DISPLAY_VSYNC_PERIOD:
254 return 1000000000 / screen_view->refresh_rate_hz();
255 case HWC_DISPLAY_WIDTH:
256 return screen_view->x_res();
257 case HWC_DISPLAY_HEIGHT:
258 return screen_view->y_res();
259 case HWC_DISPLAY_DPI_X:
260 case HWC_DISPLAY_DPI_Y:
261 // The number of pixels per thousand inches
262 return screen_view->dpi() * 1000;
263 case HWC_DISPLAY_COLOR_TRANSFORM:
264 // TODO(jemoreira): Add the other color transformations
265 return HAL_COLOR_TRANSFORM_IDENTITY;
266 default:
267 ALOGE("unknown display attribute %u", attribute);
268 return -EINVAL;
269 }
270}
271
272int hwc_getDisplayAttributes(struct hwc_composer_device_1* /*dev*/, int disp,
273 uint32_t /*config*/, const uint32_t* attributes,
274 int32_t* values) {
275 if (disp != HWC_DISPLAY_PRIMARY) {
276 ALOGE("Unknown display type %u", disp);
277 return -EINVAL;
278 }
279
280 for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) {
281 values[i] = vsoc_hwc_attribute(attributes[i]);
282 }
283
284 return 0;
285}
286
287int hwc_close(hw_device_t* device) {
288 vsoc_hwc_device* dev = reinterpret_cast<vsoc_hwc_device*>(device);
289 pthread_kill(dev->vsync_thread, SIGTERM);
290 pthread_join(dev->vsync_thread, NULL);
291 delete dev;
292 return 0;
293}
294
295int hwc_open(const struct hw_module_t* module, const char* name,
296 struct hw_device_t** device) {
297 ALOGI("Opening vsoc hwcomposer device: %s", __FUNCTION__);
298 if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
299 ALOGE("%s called with bad name %s", __FUNCTION__, name);
300 return -EINVAL;
301 }
302
303 vsoc_hwc_device* dev = new vsoc_hwc_device();
304 if (!dev) {
305 ALOGE("%s failed to allocate dev", __FUNCTION__);
306 return -ENOMEM;
307 }
308 memset(dev, 0, sizeof(*dev));
309
310 int refreshRate = 60;
311 dev->vsync_period_ns = 1000000000 / refreshRate;
312 struct timespec rt;
313 if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) {
314 ALOGE("%s:%d error in clock_gettime: %s", __FILE__, __LINE__,
315 strerror(errno));
316 }
317 dev->vsync_base_timestamp = int64_t(rt.tv_sec) * 1e9 + rt.tv_nsec;
318
319 dev->base.common.tag = HARDWARE_DEVICE_TAG;
320 dev->base.common.version = HWC_DEVICE_API_VERSION_1_1;
321 dev->base.common.module = const_cast<hw_module_t*>(module);
322 dev->base.common.close = hwc_close;
323
324 dev->base.prepare = hwc_prepare;
325 dev->base.set = hwc_set;
326 dev->base.query = hwc_query;
327 dev->base.registerProcs = hwc_registerProcs;
328 dev->base.dump = hwc_dump;
329 dev->base.blank = hwc_blank;
330 dev->base.eventControl = hwc_eventControl;
331 dev->base.getDisplayConfigs = hwc_getDisplayConfigs;
332 dev->base.getDisplayAttributes = hwc_getDisplayAttributes;
333
334 if (!ScreenRegionView::GetInstance()) {
335 ALOGE("Unable to open screen region (%s)", __FUNCTION__);
336 delete dev;
337 return -1;
338 }
339
340 int ret = pthread_create(&dev->vsync_thread, NULL, vsync_thread, dev);
341 if (ret) {
342 ALOGE("failed to start vsync thread: %s", strerror(ret));
343 delete dev;
344 } else {
345 *device = &dev->base.common;
346 }
347
348 return -ret;
349}
350
351struct hw_module_methods_t hwc_module_methods = {hwc_open};
352
353} // namespace
354
355hwc_module_t HAL_MODULE_INFO_SYM = {{HARDWARE_MODULE_TAG,
356 HWC_MODULE_API_VERSION_0_1,
357 HARDWARE_HAL_API_VERSION,
358 HWC_HARDWARE_MODULE_ID,
359 "Cuttlefish hwcomposer module",
360 "Google",
361 &hwc_module_methods,
362 NULL,
363 {0}}};