1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <fcntl.h>
8 #include <unistd.h>
9 #include <errno.h>
10 #include <string.h>
11
12 #include <lib/fidl/coding.h>
13 #include <zircon/assert.h>
14 #include <zircon/device/display-controller.h>
15 #include <zircon/pixelformat.h>
16 #include <zircon/process.h>
17 #include <zircon/syscalls.h>
18 #include <zircon/types.h>
19
20 #include "fuchsia/hardware/display/c/fidl.h"
21 #include "lib/framebuffer/framebuffer.h"
22
23 static int32_t dc_fd = -1;
24 static zx_handle_t dc_handle = ZX_HANDLE_INVALID;
25
26 static int32_t txid;
27 static int32_t display_id;
28 static int32_t layer_id;
29
30 static int32_t width;
31 static int32_t height;
32 static int32_t stride;
33 static zx_pixel_format_t format;
34 static bool type_set;
35 static uint32_t image_type;
36
37 static zx_handle_t vmo = ZX_HANDLE_INVALID;
38
39 static bool inited = false;
40 static bool in_single_buffer_mode;
41
set_layer_config(int32_t layer_id,uint32_t width,uint32_t height,zx_pixel_format_t format,int32_t type)42 static zx_status_t set_layer_config(int32_t layer_id, uint32_t width, uint32_t height,
43 zx_pixel_format_t format, int32_t type) {
44 fuchsia_hardware_display_ControllerSetLayerPrimaryConfigRequest layer_cfg_msg = {};
45 layer_cfg_msg.hdr.ordinal = fuchsia_hardware_display_ControllerSetLayerPrimaryConfigOrdinal;
46 layer_cfg_msg.layer_id = layer_id;
47 layer_cfg_msg.image_config.width = width;
48 layer_cfg_msg.image_config.height = height;
49 layer_cfg_msg.image_config.pixel_format = format;
50 layer_cfg_msg.image_config.type = type;
51
52 return zx_channel_write(dc_handle, 0, &layer_cfg_msg, sizeof(layer_cfg_msg), NULL, 0);
53 }
54
fb_bind(bool single_buffer,const char ** err_msg_out)55 zx_status_t fb_bind(bool single_buffer, const char** err_msg_out) {
56 const char* err_msg;
57 if (!err_msg_out) {
58 err_msg_out = &err_msg;
59 }
60 *err_msg_out = "";
61
62 if (inited) {
63 *err_msg_out = "framebufer already initialzied";
64 return ZX_ERR_ALREADY_BOUND;
65 }
66
67 // TODO(stevensd): Don't hardcode display controller 0
68 zx_status_t status;
69 dc_fd = open("/dev/class/display-controller/000", O_RDWR);
70 if (dc_fd < 0) {
71 *err_msg_out = "Failed to open display controller";
72 status = ZX_ERR_NO_RESOURCES;
73 goto err;
74 }
75
76 if (ioctl_display_controller_get_handle(dc_fd, &dc_handle) != sizeof(zx_handle_t)) {
77 *err_msg_out = "Failed to get display controller handle";
78 status = ZX_ERR_INTERNAL;
79 goto err;
80 }
81
82 uint8_t bytes[ZX_CHANNEL_MAX_MSG_BYTES];
83 uint32_t actual_bytes, actual_handles;
84 bool has_display = false;
85 do {
86 zx_handle_t observed;
87 uint32_t signals = ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED;
88 if ((status = zx_object_wait_one(dc_handle,
89 signals, ZX_TIME_INFINITE, &observed)) != ZX_OK) {
90 *err_msg_out = "Failed waiting for display";
91 goto err;
92 }
93 if (observed & ZX_CHANNEL_PEER_CLOSED) {
94 *err_msg_out = "Display controller connection closed";
95 status = ZX_ERR_PEER_CLOSED;
96 goto err;
97 }
98
99 if ((status = zx_channel_read(dc_handle, 0, bytes, NULL, ZX_CHANNEL_MAX_MSG_BYTES, 0,
100 &actual_bytes, &actual_handles)) != ZX_OK
101 || actual_bytes < sizeof(fidl_message_header_t)) {
102 *err_msg_out = "Reading display addded callback failed";
103 goto err;
104 }
105
106 fidl_message_header_t* hdr = (fidl_message_header_t*) bytes;
107 if (hdr->ordinal == fuchsia_hardware_display_ControllerDisplaysChangedOrdinal) {
108 if ((status = fidl_decode(&fuchsia_hardware_display_ControllerDisplaysChangedEventTable,
109 bytes, actual_bytes, NULL, 0, err_msg_out)) != ZX_OK) {
110 goto err;
111 }
112 has_display = true;
113 }
114 } while (!has_display);
115
116 // We're guaranteed that added contains at least one display, since we haven't
117 // been notified of any displays to remove.
118 fuchsia_hardware_display_ControllerDisplaysChangedEvent* changes =
119 (fuchsia_hardware_display_ControllerDisplaysChangedEvent*)bytes;
120 fuchsia_hardware_display_Info* display = (fuchsia_hardware_display_Info*)changes->added.data;
121 fuchsia_hardware_display_Mode* mode = (fuchsia_hardware_display_Mode*)display->modes.data;
122 zx_pixel_format_t pixel_format = ((int32_t*)(display->pixel_format.data))[0];
123
124 fuchsia_hardware_display_ControllerComputeLinearImageStrideRequest stride_msg;
125 stride_msg.hdr.ordinal = fuchsia_hardware_display_ControllerComputeLinearImageStrideOrdinal;
126 stride_msg.hdr.txid = txid++;
127 stride_msg.width = mode->horizontal_resolution;
128 stride_msg.pixel_format = pixel_format;
129
130 fuchsia_hardware_display_ControllerComputeLinearImageStrideResponse stride_rsp;
131 zx_channel_call_args_t stride_call = {};
132 stride_call.wr_bytes = &stride_msg;
133 stride_call.rd_bytes = &stride_rsp;
134 stride_call.wr_num_bytes = sizeof(stride_msg);
135 stride_call.rd_num_bytes = sizeof(stride_rsp);
136 if ((status = zx_channel_call(dc_handle, 0, ZX_TIME_INFINITE, &stride_call,
137 &actual_bytes, &actual_handles)) != ZX_OK) {
138 *err_msg_out = "Failed to get linear stride";
139 goto err;
140 }
141
142 fuchsia_hardware_display_ControllerCreateLayerRequest create_layer_msg;
143 create_layer_msg.hdr.ordinal = fuchsia_hardware_display_ControllerCreateLayerOrdinal;
144
145 fuchsia_hardware_display_ControllerCreateLayerResponse create_layer_rsp;
146 zx_channel_call_args_t call_args = {};
147 call_args.wr_bytes = &create_layer_msg;
148 call_args.rd_bytes = &create_layer_rsp;
149 call_args.wr_num_bytes = sizeof(create_layer_msg);
150 call_args.rd_num_bytes = sizeof(create_layer_rsp);
151 if ((status = zx_channel_call(dc_handle, 0, ZX_TIME_INFINITE, &call_args,
152 &actual_bytes, &actual_handles)) != ZX_OK) {
153 *err_msg_out = "Create layer call failed";
154 goto err;
155 }
156 if (create_layer_rsp.res != ZX_OK) {
157 *err_msg_out = "Failed to create layer";
158 status = create_layer_rsp.res;
159 goto err;
160 }
161
162 uint8_t fidl_bytes[sizeof(fuchsia_hardware_display_ControllerSetDisplayLayersRequest) +
163 FIDL_ALIGN(sizeof(uint64_t))];
164 fuchsia_hardware_display_ControllerSetDisplayLayersRequest* set_display_layer_request =
165 (fuchsia_hardware_display_ControllerSetDisplayLayersRequest*)fidl_bytes;
166 *(uint64_t*)(fidl_bytes + sizeof(fuchsia_hardware_display_ControllerSetDisplayLayersRequest)) =
167 create_layer_rsp.layer_id;
168
169 set_display_layer_request->hdr.ordinal =
170 fuchsia_hardware_display_ControllerSetDisplayLayersOrdinal;
171 set_display_layer_request->display_id = display->id;
172 set_display_layer_request->layer_ids.count = 1;
173 set_display_layer_request->layer_ids.data = (void*) FIDL_ALLOC_PRESENT;
174
175 if ((status = zx_channel_write(dc_handle, 0, fidl_bytes,
176 sizeof(fidl_bytes), NULL, 0)) != ZX_OK) {
177 *err_msg_out = "Failed to set display layers";
178 goto err;
179 }
180
181 if ((status = set_layer_config(create_layer_rsp.layer_id, mode->horizontal_resolution,
182 mode->vertical_resolution, pixel_format,
183 IMAGE_TYPE_SIMPLE)) != ZX_OK) {
184 *err_msg_out = "Failed to set layer config";
185 goto err;
186 }
187
188 display_id = display->id;
189 layer_id = create_layer_rsp.layer_id;
190
191 width = mode->horizontal_resolution;
192 height = mode->vertical_resolution;
193 format = pixel_format;
194 stride = stride_rsp.stride;
195
196 type_set = false;
197
198 inited = true;
199
200 if (single_buffer) {
201 uint32_t size = stride * height * ZX_PIXEL_FORMAT_BYTES(format);
202 fuchsia_hardware_display_ControllerAllocateVmoRequest alloc_msg;
203 alloc_msg.hdr.ordinal = fuchsia_hardware_display_ControllerAllocateVmoOrdinal;
204 alloc_msg.hdr.txid = txid++;
205 alloc_msg.size = size;
206
207 fuchsia_hardware_display_ControllerAllocateVmoResponse alloc_rsp;
208 zx_channel_call_args_t call_args = {};
209 call_args.wr_bytes = &alloc_msg;
210 call_args.rd_bytes = &alloc_rsp;
211 call_args.rd_handles = &vmo;
212 call_args.wr_num_bytes = sizeof(alloc_msg);
213 call_args.rd_num_bytes = sizeof(alloc_rsp);
214 call_args.rd_num_handles = 1;
215 uint32_t actual_bytes, actual_handles;
216 if ((status = zx_channel_call(dc_handle, 0, ZX_TIME_INFINITE, &call_args,
217 &actual_bytes, &actual_handles)) != ZX_OK) {
218 *err_msg_out = "Failed vmo alloc call";
219 goto err;
220 }
221 if (alloc_rsp.res != ZX_OK) {
222 status = alloc_rsp.res;
223 *err_msg_out = "Failed to alloc vmo";
224 goto err;
225 }
226
227 // Failure to set the cache policy isn't a fatal error
228 zx_vmo_set_cache_policy(vmo, ZX_CACHE_POLICY_WRITE_COMBINING);
229
230 zx_handle_t dup;
231 if ((status = zx_handle_duplicate(vmo, ZX_RIGHT_SAME_RIGHTS, &dup)) != ZX_OK) {
232 *err_msg_out = "Couldn't duplicate vmo\n";;
233 goto err;
234 }
235
236 // fb_(present|import)_image expect to not be in single buffer
237 // mode, so make sure this is false for now. It will get set properly later.
238 in_single_buffer_mode = false;
239
240 uint64_t image_id;
241 if ((status = fb_import_image(dup, 0, &image_id)) != ZX_OK) {
242 *err_msg_out = "Couldn't import framebuffer";
243 goto err;
244 }
245
246 if ((status = fb_present_image(image_id, INVALID_ID, INVALID_ID, INVALID_ID)) != ZX_OK) {
247 *err_msg_out = "Failed to present single_buffer mode framebuffer";
248 goto err;
249 }
250 }
251
252 in_single_buffer_mode = single_buffer;
253
254 return ZX_OK;
255 err:
256 inited = false;
257
258 zx_handle_close(dc_handle);
259 dc_handle = ZX_HANDLE_INVALID;
260
261 if (dc_fd >= 0) {
262 close(dc_fd);
263 dc_fd = -1;
264 }
265
266 zx_handle_close(vmo);
267 vmo = ZX_HANDLE_INVALID;
268
269 return status;
270 }
271
fb_release()272 void fb_release() {
273 if (!inited) {
274 return;
275 }
276
277 zx_handle_close(dc_handle);
278 dc_handle = ZX_HANDLE_INVALID;
279
280 close(dc_fd);
281 dc_fd = -1;
282
283 if (in_single_buffer_mode) {
284 zx_handle_close(vmo);
285 vmo = ZX_HANDLE_INVALID;
286 }
287
288 inited = false;
289 }
290
fb_get_config(uint32_t * width_out,uint32_t * height_out,uint32_t * linear_stride_px_out,zx_pixel_format_t * format_out)291 void fb_get_config(uint32_t* width_out, uint32_t* height_out,
292 uint32_t* linear_stride_px_out, zx_pixel_format_t* format_out) {
293 ZX_ASSERT(inited);
294
295 *width_out = width;
296 *height_out = height;
297 *format_out = format;
298 *linear_stride_px_out = stride;
299 }
300
fb_get_single_buffer()301 zx_handle_t fb_get_single_buffer() {
302 ZX_ASSERT(inited && in_single_buffer_mode);
303 return vmo;
304 }
305
fb_import_image(zx_handle_t handle,uint32_t type,uint64_t * id_out)306 zx_status_t fb_import_image(zx_handle_t handle, uint32_t type, uint64_t *id_out) {
307 ZX_ASSERT(inited && !in_single_buffer_mode);
308 zx_status_t status;
309
310 if (type_set && type != image_type) {
311 return ZX_ERR_BAD_STATE;
312 } else if (!type_set && type != IMAGE_TYPE_SIMPLE) {
313 if ((status = set_layer_config(layer_id, width, height, format, type)) != ZX_OK) {
314 return status;
315 }
316 image_type = type;
317 type_set = true;
318 }
319
320 fuchsia_hardware_display_ControllerImportVmoImageRequest import_msg = {};
321 import_msg.hdr.ordinal = fuchsia_hardware_display_ControllerImportVmoImageOrdinal;
322 import_msg.hdr.txid = txid++;
323 import_msg.image_config.height = height;
324 import_msg.image_config.width = width;
325 import_msg.image_config.pixel_format = format;
326 import_msg.image_config.type = type;
327 import_msg.vmo = FIDL_HANDLE_PRESENT;
328 import_msg.offset = 0;
329
330 fuchsia_hardware_display_ControllerImportVmoImageResponse import_rsp;
331 zx_channel_call_args_t import_call = {};
332 import_call.wr_bytes = &import_msg;
333 import_call.wr_handles = &handle;
334 import_call.rd_bytes = &import_rsp;
335 import_call.wr_num_bytes = sizeof(import_msg);
336 import_call.wr_num_handles = 1;
337 import_call.rd_num_bytes = sizeof(import_rsp);
338 uint32_t actual_bytes, actual_handles;
339 if ((status = zx_channel_call(dc_handle, 0, ZX_TIME_INFINITE, &import_call,
340 &actual_bytes, &actual_handles)) != ZX_OK) {
341 return status;
342 }
343
344 if (import_rsp.res != ZX_OK) {
345 return import_rsp.res;
346 }
347
348 *id_out = import_rsp.image_id;
349 return ZX_OK;
350 }
351
fb_release_image(uint64_t image_id)352 void fb_release_image(uint64_t image_id) {
353 ZX_ASSERT(inited && !in_single_buffer_mode);
354
355 fuchsia_hardware_display_ControllerReleaseEventRequest release_img_msg;
356 release_img_msg.hdr.ordinal = fuchsia_hardware_display_ControllerReleaseEventOrdinal;
357 release_img_msg.hdr.txid = txid++;
358 release_img_msg.id = image_id;
359
360 // There's nothing meaningful to do if this call fails
361 zx_channel_write(dc_handle, 0, &release_img_msg, sizeof(release_img_msg), NULL, 0);
362 }
363
fb_import_event(zx_handle_t handle,uint64_t id)364 zx_status_t fb_import_event(zx_handle_t handle, uint64_t id) {
365 ZX_ASSERT(inited && !in_single_buffer_mode);
366
367 fuchsia_hardware_display_ControllerImportEventRequest import_evt_msg;
368 import_evt_msg.hdr.ordinal = fuchsia_hardware_display_ControllerImportEventOrdinal;
369 import_evt_msg.hdr.txid = txid++;
370 import_evt_msg.id = id;
371 import_evt_msg.event = FIDL_HANDLE_PRESENT;
372
373 return zx_channel_write(dc_handle, 0, &import_evt_msg, sizeof(import_evt_msg), &handle, 1);
374 }
375
fb_release_event(uint64_t id)376 void fb_release_event(uint64_t id) {
377 ZX_ASSERT(inited && !in_single_buffer_mode);
378
379 fuchsia_hardware_display_ControllerReleaseEventRequest release_evt_msg;
380 release_evt_msg.hdr.ordinal = fuchsia_hardware_display_ControllerReleaseEventOrdinal;
381 release_evt_msg.hdr.txid = txid++;
382 release_evt_msg.id = id;
383
384 // There's nothing meaningful we can do if this call fails
385 zx_channel_write(dc_handle, 0, &release_evt_msg, sizeof(release_evt_msg), NULL, 0);
386 }
387
fb_present_image2(uint64_t image_id,uint64_t wait_event_id,uint64_t signal_event_id)388 zx_status_t fb_present_image2(uint64_t image_id, uint64_t wait_event_id, uint64_t signal_event_id) {
389 return fb_present_image(image_id, wait_event_id, INVALID_ID, signal_event_id);
390 }
391
fb_present_image(uint64_t image_id,uint64_t wait_event_id,uint64_t present_event_id,uint64_t signal_event_id)392 zx_status_t fb_present_image(uint64_t image_id, uint64_t wait_event_id,
393 uint64_t present_event_id, uint64_t signal_event_id) {
394 ZX_ASSERT(present_event_id == INVALID_ID);
395 ZX_ASSERT(inited && !in_single_buffer_mode);
396 zx_status_t status;
397
398 fuchsia_hardware_display_ControllerSetLayerImageRequest set_msg;
399 set_msg.hdr.ordinal = fuchsia_hardware_display_ControllerSetLayerImageOrdinal;
400 set_msg.hdr.txid = txid++;
401 set_msg.layer_id = layer_id;
402 set_msg.image_id = image_id;
403 set_msg.wait_event_id = wait_event_id;
404 set_msg.signal_event_id = signal_event_id;
405 if ((status = zx_channel_write(dc_handle, 0, &set_msg, sizeof(set_msg), NULL, 0)) != ZX_OK) {
406 return status;
407 }
408
409 // It's not necessary to validate the configuration, since we're guaranteed that a single
410 // fullscreen framebuffer on a single monitor will work.
411 fuchsia_hardware_display_ControllerApplyConfigRequest apply_msg;
412 apply_msg.hdr.txid = txid++;
413 apply_msg.hdr.ordinal = fuchsia_hardware_display_ControllerApplyConfigOrdinal;
414 return zx_channel_write(dc_handle, 0, &apply_msg, sizeof(apply_msg), NULL, 0);
415 }
416
fb_alloc_image_buffer(zx_handle_t * vmo_out)417 zx_status_t fb_alloc_image_buffer(zx_handle_t* vmo_out) {
418 uint32_t size = stride * height * ZX_PIXEL_FORMAT_BYTES(format);
419 fuchsia_hardware_display_ControllerAllocateVmoRequest alloc_msg;
420 alloc_msg.hdr.ordinal = fuchsia_hardware_display_ControllerAllocateVmoOrdinal;
421 alloc_msg.hdr.txid = txid++;
422 alloc_msg.size = size;
423
424 fuchsia_hardware_display_ControllerAllocateVmoResponse alloc_rsp;
425 zx_channel_call_args_t call_args = {};
426 call_args.wr_bytes = &alloc_msg;
427 call_args.rd_bytes = &alloc_rsp;
428 call_args.rd_handles = vmo_out;
429 call_args.wr_num_bytes = sizeof(alloc_msg);
430 call_args.rd_num_bytes = sizeof(alloc_rsp);
431 call_args.rd_num_handles = 1;
432 uint32_t actual_bytes, actual_handles;
433 zx_status_t status;
434 if ((status = zx_channel_call(dc_handle, 0, ZX_TIME_INFINITE, &call_args,
435 &actual_bytes, &actual_handles)) != ZX_OK) {
436 if (alloc_rsp.res != ZX_OK) {
437 status = alloc_rsp.res;
438 }
439 return status;
440 }
441 static const char kVmoName[] = "framebuffer";
442 zx_object_set_property(*vmo_out, ZX_PROP_NAME, kVmoName, sizeof(kVmoName));
443 return ZX_OK;
444 }
445
fb_enable_vsync(bool enable)446 zx_status_t fb_enable_vsync(bool enable) {
447 fuchsia_hardware_display_ControllerEnableVsyncRequest enable_vsync;
448 enable_vsync.hdr.ordinal = fuchsia_hardware_display_ControllerEnableVsyncOrdinal;
449 enable_vsync.enable = enable;
450 zx_status_t status;
451 if ((status = zx_channel_write(dc_handle, 0, &enable_vsync, sizeof(enable_vsync),
452 NULL, 0)) != ZX_OK) {
453 return status;
454 }
455 return ZX_OK;
456 }
457
fb_wait_for_vsync(zx_time_t * timestamp,uint64_t * image_id)458 zx_status_t fb_wait_for_vsync(zx_time_t* timestamp, uint64_t* image_id) {
459 zx_status_t status;
460
461 zx_handle_t observed;
462 uint32_t signals = ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED;
463 if ((status = zx_object_wait_one(dc_handle, signals, ZX_TIME_INFINITE,
464 &observed)) != ZX_OK) {
465 return status;
466 }
467 if (observed & ZX_CHANNEL_PEER_CLOSED) {
468 return ZX_ERR_PEER_CLOSED;
469 }
470
471 uint8_t bytes[ZX_CHANNEL_MAX_MSG_BYTES];
472 uint32_t actual_bytes, actual_handles;
473 if ((status = zx_channel_read(dc_handle, 0, bytes, NULL, ZX_CHANNEL_MAX_MSG_BYTES, 0,
474 &actual_bytes, &actual_handles)) != ZX_OK) {
475 return ZX_ERR_STOP;
476 }
477
478 if (actual_bytes < sizeof(fidl_message_header_t)) {
479 return ZX_ERR_INTERNAL;
480 }
481
482 fidl_message_header_t* header = (fidl_message_header_t*) bytes;
483
484 switch (header->ordinal) {
485 case fuchsia_hardware_display_ControllerDisplaysChangedOrdinal:
486 return ZX_ERR_STOP;
487 case fuchsia_hardware_display_ControllerClientOwnershipChangeOrdinal:
488 return ZX_ERR_NEXT;
489 case fuchsia_hardware_display_ControllerVsyncOrdinal:
490 break;
491 default:
492 return ZX_ERR_STOP;
493 }
494
495 const char* err_msg;
496 if ((status = fidl_decode(&fuchsia_hardware_display_ControllerVsyncEventTable, bytes,
497 actual_bytes, NULL, 0, &err_msg)) != ZX_OK) {
498 return ZX_ERR_STOP;
499 }
500
501 fuchsia_hardware_display_ControllerVsyncEvent* vsync =
502 (fuchsia_hardware_display_ControllerVsyncEvent*)bytes;
503 *timestamp = vsync->timestamp;
504 *image_id = vsync->images.count ? *((uint64_t*)vsync->images.data) : FB_INVALID_ID;
505 return ZX_OK;
506 }
507