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/display/c/fidl.h" 21#include "lib/framebuffer/framebuffer.h" 22 23static int32_t dc_fd = -1; 24static zx_handle_t dc_handle = ZX_HANDLE_INVALID; 25 26static int32_t txid; 27static int32_t display_id; 28static int32_t layer_id; 29 30static int32_t width; 31static int32_t height; 32static int32_t stride; 33static zx_pixel_format_t format; 34static bool type_set; 35static uint32_t image_type; 36 37static zx_handle_t vmo = ZX_HANDLE_INVALID; 38 39static bool inited = false; 40static bool in_single_buffer_mode; 41 42static 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_display_ControllerSetLayerPrimaryConfigRequest layer_cfg_msg = {}; 45 layer_cfg_msg.hdr.ordinal = fuchsia_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 55zx_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_display_ControllerDisplaysChangedOrdinal) { 108 if ((status = fidl_decode(&fuchsia_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_display_ControllerDisplaysChangedEvent* changes = 119 (fuchsia_display_ControllerDisplaysChangedEvent*) bytes; 120 fuchsia_display_Info* display = (fuchsia_display_Info*) changes->added.data; 121 fuchsia_display_Mode* mode = (fuchsia_display_Mode*) display->modes.data; 122 zx_pixel_format_t pixel_format = ((int32_t*)(display->pixel_format.data))[0]; 123 124 fuchsia_display_ControllerComputeLinearImageStrideRequest stride_msg; 125 stride_msg.hdr.ordinal = fuchsia_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_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_display_ControllerCreateLayerRequest create_layer_msg; 143 create_layer_msg.hdr.ordinal = fuchsia_display_ControllerCreateLayerOrdinal; 144 145 fuchsia_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_display_ControllerSetDisplayLayersRequest) 163 + FIDL_ALIGN(sizeof(uint64_t))]; 164 fuchsia_display_ControllerSetDisplayLayersRequest* set_display_layer_request = 165 (fuchsia_display_ControllerSetDisplayLayersRequest*) fidl_bytes; 166 *(uint64_t*)(fidl_bytes + sizeof(fuchsia_display_ControllerSetDisplayLayersRequest)) = 167 create_layer_rsp.layer_id; 168 169 set_display_layer_request->hdr.ordinal = fuchsia_display_ControllerSetDisplayLayersOrdinal; 170 set_display_layer_request->display_id = display->id; 171 set_display_layer_request->layer_ids.count = 1; 172 set_display_layer_request->layer_ids.data = (void*) FIDL_ALLOC_PRESENT; 173 174 if ((status = zx_channel_write(dc_handle, 0, fidl_bytes, 175 sizeof(fidl_bytes), NULL, 0)) != ZX_OK) { 176 *err_msg_out = "Failed to set display layers"; 177 goto err; 178 } 179 180 if ((status = set_layer_config(create_layer_rsp.layer_id, mode->horizontal_resolution, 181 mode->vertical_resolution, pixel_format, 182 IMAGE_TYPE_SIMPLE)) != ZX_OK) { 183 *err_msg_out = "Failed to set layer config"; 184 goto err; 185 } 186 187 display_id = display->id; 188 layer_id = create_layer_rsp.layer_id; 189 190 width = mode->horizontal_resolution; 191 height = mode->vertical_resolution; 192 format = pixel_format; 193 stride = stride_rsp.stride; 194 195 type_set = false; 196 197 inited = true; 198 199 if (single_buffer) { 200 uint32_t size = stride * height * ZX_PIXEL_FORMAT_BYTES(format); 201 fuchsia_display_ControllerAllocateVmoRequest alloc_msg; 202 alloc_msg.hdr.ordinal = fuchsia_display_ControllerAllocateVmoOrdinal; 203 alloc_msg.hdr.txid = txid++; 204 alloc_msg.size = size; 205 206 fuchsia_display_ControllerAllocateVmoResponse alloc_rsp; 207 zx_channel_call_args_t call_args = {}; 208 call_args.wr_bytes = &alloc_msg; 209 call_args.rd_bytes = &alloc_rsp; 210 call_args.rd_handles = &vmo; 211 call_args.wr_num_bytes = sizeof(alloc_msg); 212 call_args.rd_num_bytes = sizeof(alloc_rsp); 213 call_args.rd_num_handles = 1; 214 uint32_t actual_bytes, actual_handles; 215 if ((status = zx_channel_call(dc_handle, 0, ZX_TIME_INFINITE, &call_args, 216 &actual_bytes, &actual_handles)) != ZX_OK) { 217 *err_msg_out = "Failed vmo alloc call"; 218 goto err; 219 } 220 if (alloc_rsp.res != ZX_OK) { 221 status = alloc_rsp.res; 222 *err_msg_out = "Failed to alloc vmo"; 223 goto err; 224 } 225 226 // Failure to set the cache policy isn't a fatal error 227 zx_vmo_set_cache_policy(vmo, ZX_CACHE_POLICY_WRITE_COMBINING); 228 229 zx_handle_t dup; 230 if ((status = zx_handle_duplicate(vmo, ZX_RIGHT_SAME_RIGHTS, &dup)) != ZX_OK) { 231 *err_msg_out = "Couldn't duplicate vmo\n";; 232 goto err; 233 } 234 235 // fb_(present|import)_image expect to not be in single buffer 236 // mode, so make sure this is false for now. It will get set properly later. 237 in_single_buffer_mode = false; 238 239 uint64_t image_id; 240 if ((status = fb_import_image(dup, 0, &image_id)) != ZX_OK) { 241 *err_msg_out = "Couldn't import framebuffer"; 242 goto err; 243 } 244 245 if ((status = fb_present_image(image_id, INVALID_ID, INVALID_ID, INVALID_ID)) != ZX_OK) { 246 *err_msg_out = "Failed to present single_buffer mode framebuffer"; 247 goto err; 248 } 249 } 250 251 in_single_buffer_mode = single_buffer; 252 253 return ZX_OK; 254err: 255 inited = false; 256 257 zx_handle_close(dc_handle); 258 dc_handle = ZX_HANDLE_INVALID; 259 260 if (dc_fd >= 0) { 261 close(dc_fd); 262 dc_fd = -1; 263 } 264 265 zx_handle_close(vmo); 266 vmo = ZX_HANDLE_INVALID; 267 268 return status; 269} 270 271void fb_release() { 272 if (!inited) { 273 return; 274 } 275 276 zx_handle_close(dc_handle); 277 dc_handle = ZX_HANDLE_INVALID; 278 279 close(dc_fd); 280 dc_fd = -1; 281 282 if (in_single_buffer_mode) { 283 zx_handle_close(vmo); 284 vmo = ZX_HANDLE_INVALID; 285 } 286 287 inited = false; 288} 289 290void fb_get_config(uint32_t* width_out, uint32_t* height_out, 291 uint32_t* linear_stride_px_out, zx_pixel_format_t* format_out) { 292 ZX_ASSERT(inited); 293 294 *width_out = width; 295 *height_out = height; 296 *format_out = format; 297 *linear_stride_px_out = stride; 298} 299 300zx_handle_t fb_get_single_buffer() { 301 ZX_ASSERT(inited && in_single_buffer_mode); 302 return vmo; 303} 304 305zx_status_t fb_import_image(zx_handle_t handle, uint32_t type, uint64_t *id_out) { 306 ZX_ASSERT(inited && !in_single_buffer_mode); 307 zx_status_t status; 308 309 if (type_set && type != image_type) { 310 return ZX_ERR_BAD_STATE; 311 } else if (!type_set && type != IMAGE_TYPE_SIMPLE) { 312 if ((status = set_layer_config(layer_id, width, height, format, type)) != ZX_OK) { 313 return status; 314 } 315 image_type = type; 316 type_set = true; 317 } 318 319 fuchsia_display_ControllerImportVmoImageRequest import_msg = {}; 320 import_msg.hdr.ordinal = fuchsia_display_ControllerImportVmoImageOrdinal; 321 import_msg.hdr.txid = txid++; 322 import_msg.image_config.height = height; 323 import_msg.image_config.width = width; 324 import_msg.image_config.pixel_format = format; 325 import_msg.image_config.type = type; 326 import_msg.vmo = FIDL_HANDLE_PRESENT; 327 import_msg.offset = 0; 328 329 fuchsia_display_ControllerImportVmoImageResponse import_rsp; 330 zx_channel_call_args_t import_call = {}; 331 import_call.wr_bytes = &import_msg; 332 import_call.wr_handles = &handle; 333 import_call.rd_bytes = &import_rsp; 334 import_call.wr_num_bytes = sizeof(import_msg); 335 import_call.wr_num_handles = 1; 336 import_call.rd_num_bytes = sizeof(import_rsp); 337 uint32_t actual_bytes, actual_handles; 338 if ((status = zx_channel_call(dc_handle, 0, ZX_TIME_INFINITE, &import_call, 339 &actual_bytes, &actual_handles)) != ZX_OK) { 340 return status; 341 } 342 343 if (import_rsp.res != ZX_OK) { 344 return import_rsp.res; 345 } 346 347 *id_out = import_rsp.image_id; 348 return ZX_OK; 349} 350 351void fb_release_image(uint64_t image_id) { 352 ZX_ASSERT(inited && !in_single_buffer_mode); 353 354 fuchsia_display_ControllerReleaseEventRequest release_img_msg; 355 release_img_msg.hdr.ordinal = fuchsia_display_ControllerReleaseEventOrdinal; 356 release_img_msg.hdr.txid = txid++; 357 release_img_msg.id = image_id; 358 359 // There's nothing meaningful to do if this call fails 360 zx_channel_write(dc_handle, 0, &release_img_msg, sizeof(release_img_msg), NULL, 0); 361} 362 363zx_status_t fb_import_event(zx_handle_t handle, uint64_t id) { 364 ZX_ASSERT(inited && !in_single_buffer_mode); 365 366 fuchsia_display_ControllerImportEventRequest import_evt_msg; 367 import_evt_msg.hdr.ordinal = fuchsia_display_ControllerImportEventOrdinal; 368 import_evt_msg.hdr.txid = txid++; 369 import_evt_msg.id = id; 370 import_evt_msg.event = FIDL_HANDLE_PRESENT; 371 372 return zx_channel_write(dc_handle, 0, &import_evt_msg, sizeof(import_evt_msg), &handle, 1); 373} 374 375void fb_release_event(uint64_t id) { 376 ZX_ASSERT(inited && !in_single_buffer_mode); 377 378 fuchsia_display_ControllerReleaseEventRequest release_evt_msg; 379 release_evt_msg.hdr.ordinal = fuchsia_display_ControllerReleaseEventOrdinal; 380 release_evt_msg.hdr.txid = txid++; 381 release_evt_msg.id = id; 382 383 // There's nothing meaningful we can do if this call fails 384 zx_channel_write(dc_handle, 0, &release_evt_msg, sizeof(release_evt_msg), NULL, 0); 385} 386 387zx_status_t fb_present_image2(uint64_t image_id, uint64_t wait_event_id, uint64_t signal_event_id) { 388 return fb_present_image(image_id, wait_event_id, INVALID_ID, signal_event_id); 389} 390 391zx_status_t fb_present_image(uint64_t image_id, uint64_t wait_event_id, 392 uint64_t present_event_id, uint64_t signal_event_id) { 393 ZX_ASSERT(present_event_id == INVALID_ID); 394 ZX_ASSERT(inited && !in_single_buffer_mode); 395 zx_status_t status; 396 397 fuchsia_display_ControllerSetLayerImageRequest set_msg; 398 set_msg.hdr.ordinal = fuchsia_display_ControllerSetLayerImageOrdinal; 399 set_msg.hdr.txid = txid++; 400 set_msg.layer_id = layer_id; 401 set_msg.image_id = image_id; 402 set_msg.wait_event_id = wait_event_id; 403 set_msg.signal_event_id = signal_event_id; 404 if ((status = zx_channel_write(dc_handle, 0, &set_msg, sizeof(set_msg), NULL, 0)) != ZX_OK) { 405 return status; 406 } 407 408 // It's not necessary to validate the configuration, since we're guaranteed that a single 409 // fullscreen framebuffer on a single monitor will work. 410 fuchsia_display_ControllerApplyConfigRequest apply_msg; 411 apply_msg.hdr.txid = txid++; 412 apply_msg.hdr.ordinal = fuchsia_display_ControllerApplyConfigOrdinal; 413 return zx_channel_write(dc_handle, 0, &apply_msg, sizeof(apply_msg), NULL, 0); 414} 415 416zx_status_t fb_alloc_image_buffer(zx_handle_t* vmo_out) { 417 uint32_t size = stride * height * ZX_PIXEL_FORMAT_BYTES(format); 418 fuchsia_display_ControllerAllocateVmoRequest alloc_msg; 419 alloc_msg.hdr.ordinal = fuchsia_display_ControllerAllocateVmoOrdinal; 420 alloc_msg.hdr.txid = txid++; 421 alloc_msg.size = size; 422 423 fuchsia_display_ControllerAllocateVmoResponse alloc_rsp; 424 zx_channel_call_args_t call_args = {}; 425 call_args.wr_bytes = &alloc_msg; 426 call_args.rd_bytes = &alloc_rsp; 427 call_args.rd_handles = vmo_out; 428 call_args.wr_num_bytes = sizeof(alloc_msg); 429 call_args.rd_num_bytes = sizeof(alloc_rsp); 430 call_args.rd_num_handles = 1; 431 uint32_t actual_bytes, actual_handles; 432 zx_status_t status; 433 if ((status = zx_channel_call(dc_handle, 0, ZX_TIME_INFINITE, &call_args, 434 &actual_bytes, &actual_handles)) != ZX_OK) { 435 if (alloc_rsp.res != ZX_OK) { 436 status = alloc_rsp.res; 437 } 438 return status; 439 } 440 static const char kVmoName[] = "framebuffer"; 441 zx_object_set_property(*vmo_out, ZX_PROP_NAME, kVmoName, sizeof(kVmoName)); 442 return ZX_OK; 443} 444 445zx_status_t fb_enable_vsync(bool enable) { 446 fuchsia_display_ControllerEnableVsyncRequest enable_vsync; 447 enable_vsync.hdr.ordinal = fuchsia_display_ControllerEnableVsyncOrdinal; 448 enable_vsync.enable = enable; 449 zx_status_t status; 450 if ((status = zx_channel_write(dc_handle, 0, &enable_vsync, sizeof(enable_vsync), 451 NULL, 0)) != ZX_OK) { 452 return status; 453 } 454 return ZX_OK; 455} 456 457zx_status_t fb_wait_for_vsync(zx_time_t* timestamp, uint64_t* image_id) { 458 zx_status_t status; 459 460 zx_handle_t observed; 461 uint32_t signals = ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED; 462 if ((status = zx_object_wait_one(dc_handle, signals, ZX_TIME_INFINITE, 463 &observed)) != ZX_OK) { 464 return status; 465 } 466 if (observed & ZX_CHANNEL_PEER_CLOSED) { 467 return ZX_ERR_PEER_CLOSED; 468 } 469 470 uint8_t bytes[ZX_CHANNEL_MAX_MSG_BYTES]; 471 uint32_t actual_bytes, actual_handles; 472 if ((status = zx_channel_read(dc_handle, 0, bytes, NULL, ZX_CHANNEL_MAX_MSG_BYTES, 0, 473 &actual_bytes, &actual_handles)) != ZX_OK) { 474 return ZX_ERR_STOP; 475 } 476 477 if (actual_bytes < sizeof(fidl_message_header_t)) { 478 return ZX_ERR_INTERNAL; 479 } 480 481 fidl_message_header_t* header = (fidl_message_header_t*) bytes; 482 483 switch (header->ordinal) { 484 case fuchsia_display_ControllerDisplaysChangedOrdinal: 485 return ZX_ERR_STOP; 486 case fuchsia_display_ControllerClientOwnershipChangeOrdinal: 487 return ZX_ERR_NEXT; 488 case fuchsia_display_ControllerVsyncOrdinal: 489 break; 490 default: 491 return ZX_ERR_STOP; 492 } 493 494 const char* err_msg; 495 if ((status = fidl_decode(&fuchsia_display_ControllerVsyncEventTable, 496 bytes, actual_bytes, NULL, 0, &err_msg)) != ZX_OK) { 497 return ZX_ERR_STOP; 498 } 499 500 fuchsia_display_ControllerVsyncEvent* vsync = 501 (fuchsia_display_ControllerVsyncEvent*) bytes; 502 *timestamp = vsync->timestamp; 503 *image_id = vsync->images.count ? *((uint64_t*)vsync->images.data) : FB_INVALID_ID; 504 return ZX_OK; 505} 506