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