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 <fbl/algorithm.h> 6#include <math.h> 7#include <zircon/device/display-controller.h> 8 9#include "utils.h" 10#include "virtual-layer.h" 11 12static constexpr uint32_t kSrcFrameBouncePeriod = 90; 13static constexpr uint32_t kDestFrameBouncePeriod = 60; 14static constexpr uint32_t kRotationPeriod = 24; 15static constexpr uint32_t kScalePeriod = 45; 16 17static uint32_t get_fg_color() { 18 static uint32_t layer_count = 0; 19 static uint32_t colors[] = { 20 0xffff0000, 0xff00ff00, 0xff0000ff, 21 }; 22 return colors[layer_count++ % fbl::count_of(colors)]; 23} 24 25// Checks if two rectangles intersect, and if so, returns their intersection. 26static bool compute_intersection(const frame_t& a, const frame_t& b, frame_t* intersection) { 27 uint32_t left = fbl::max(a.x_pos, b.x_pos); 28 uint32_t right = fbl::min(a.x_pos + a.width, b.x_pos + b.width); 29 uint32_t top = fbl::max(a.y_pos, b.y_pos); 30 uint32_t bottom = fbl::min(a.y_pos + a.height, b.y_pos + b.height); 31 32 if (left >= right || top >= bottom) { 33 return false; 34 } 35 36 intersection->x_pos = left; 37 intersection->y_pos = top; 38 intersection->width = right - left; 39 intersection->height = bottom - top; 40 41 return true; 42} 43 44static uint32_t interpolate_scaling(uint32_t x, uint32_t frame_num) { 45 return x / 2 + interpolate(x / 2, frame_num, kScalePeriod); 46} 47 48VirtualLayer::VirtualLayer(Display* display) { 49 displays_.push_back(display); 50 width_ = display->mode().horizontal_resolution; 51 height_ = display->mode().vertical_resolution; 52} 53 54VirtualLayer::VirtualLayer(const fbl::Vector<Display>& displays) { 55 for (auto& d : displays) { 56 displays_.push_back(&d); 57 } 58 59 width_ = 0; 60 height_ = 0; 61 for (auto* d : displays_) { 62 width_ += d->mode().horizontal_resolution; 63 height_ = fbl::max(height_, d->mode().vertical_resolution); 64 } 65} 66 67layer_t* VirtualLayer::CreateLayer(zx_handle_t dc_handle) { 68 layers_.push_back(layer_t()); 69 layers_[layers_.size() - 1].active = false; 70 71 fuchsia_display_ControllerCreateLayerRequest create_layer_msg; 72 create_layer_msg.hdr.ordinal = fuchsia_display_ControllerCreateLayerOrdinal; 73 74 fuchsia_display_ControllerCreateLayerResponse create_layer_rsp; 75 zx_channel_call_args_t call_args = {}; 76 call_args.wr_bytes = &create_layer_msg; 77 call_args.rd_bytes = &create_layer_rsp; 78 call_args.wr_num_bytes = sizeof(create_layer_msg); 79 call_args.rd_num_bytes = sizeof(create_layer_rsp); 80 uint32_t actual_bytes, actual_handles; 81 if (zx_channel_call(dc_handle, 0, ZX_TIME_INFINITE, &call_args, 82 &actual_bytes, &actual_handles) != ZX_OK) { 83 printf("Creating layer failed\n"); 84 return nullptr; 85 } 86 if (create_layer_rsp.res != ZX_OK) { 87 printf("Creating layer failed\n"); 88 return nullptr; 89 } 90 layers_[layers_.size() - 1].id = create_layer_rsp.layer_id; 91 92 return &layers_[layers_.size() - 1]; 93} 94 95PrimaryLayer::PrimaryLayer(Display* display) : VirtualLayer(display) { 96 image_format_ = display->format(); 97} 98 99PrimaryLayer::PrimaryLayer(const fbl::Vector<Display>& displays) : VirtualLayer(displays) { 100 image_format_ = displays_[0]->format(); 101 SetImageDimens(width_, height_); 102} 103 104bool PrimaryLayer::Init(zx_handle_t dc_handle) { 105 if ((displays_.size() > 1 || rotates_) && scaling_) { 106 printf("Unsupported config\n"); 107 return false; 108 } 109 uint32_t fg_color = get_fg_color(); 110 uint32_t bg_color = alpha_enable_ ? 0x3fffffff : 0xffffffff; 111 112 images_[0] = Image::Create( 113 dc_handle, image_width_, image_height_, image_format_, fg_color, bg_color, false); 114 if (layer_flipping_) { 115 images_[1] = Image::Create( 116 dc_handle, image_width_, image_height_, image_format_, fg_color, bg_color, false); 117 } else { 118 images_[0]->Render(-1, -1); 119 } 120 121 if (!images_[0] || (layer_flipping_ && !images_[1])) { 122 return false; 123 } 124 125 for (unsigned i = 0; i < displays_.size(); i++) { 126 layer_t* layer = CreateLayer(dc_handle); 127 if (layer == nullptr) { 128 return false; 129 } 130 131 if (!images_[0]->Import(dc_handle, &layer->import_info[0])) { 132 return false; 133 } 134 if (layer_flipping_) { 135 if (!images_[1]->Import(dc_handle, &layer->import_info[1])) { 136 return false; 137 } 138 } else { 139 zx_object_signal(layer->import_info[alt_image_].events[WAIT_EVENT], 140 0, ZX_EVENT_SIGNALED); 141 } 142 143 fuchsia_display_ControllerSetLayerPrimaryConfigRequest config; 144 config.hdr.ordinal = fuchsia_display_ControllerSetLayerPrimaryConfigOrdinal; 145 config.layer_id = layer->id; 146 images_[0]->GetConfig(&config.image_config); 147 148 if (zx_channel_write(dc_handle, 0, &config, sizeof(config), nullptr, 0) != ZX_OK) { 149 printf("Setting layer config failed\n"); 150 return false; 151 } 152 153 fuchsia_display_ControllerSetLayerPrimaryAlphaRequest alpha_config; 154 alpha_config.hdr.ordinal = fuchsia_display_ControllerSetLayerPrimaryAlphaOrdinal; 155 alpha_config.layer_id = layer->id; 156 alpha_config.mode = alpha_enable_ ? 157 fuchsia_display_AlphaMode_HW_MULTIPLY : fuchsia_display_AlphaMode_DISABLE; 158 alpha_config.val = alpha_val_; 159 160 if (zx_channel_write(dc_handle, 0, 161 &alpha_config, sizeof(alpha_config), nullptr, 0) != ZX_OK) { 162 printf("Setting layer alpha config failed\n"); 163 return false; 164 } 165 } 166 167 StepLayout(0); 168 if (!layer_flipping_) { 169 SetLayerImages(dc_handle, false); 170 } 171 if (!(pan_src_ || pan_dest_)) { 172 SetLayerPositions(dc_handle); 173 } 174 175 return true; 176} 177 178void PrimaryLayer::StepLayout(int32_t frame_num) { 179 if (layer_flipping_) { 180 alt_image_ = frame_num % 2; 181 } 182 if (pan_src_) { 183 src_frame_.x_pos = 184 interpolate(image_width_ - src_frame_.width, frame_num, kSrcFrameBouncePeriod); 185 186 } 187 if (pan_dest_) { 188 dest_frame_.x_pos = 189 interpolate(width_ - dest_frame_.width, frame_num, kDestFrameBouncePeriod); 190 } 191 if (rotates_) { 192 switch ((frame_num / kRotationPeriod) % 4) { 193 case 0: rotation_ = fuchsia_display_Transform_IDENTITY; break; 194 case 1: rotation_ = fuchsia_display_Transform_ROT_90; break; 195 case 2: rotation_ = fuchsia_display_Transform_ROT_180; break; 196 case 3: rotation_ = fuchsia_display_Transform_ROT_270; break; 197 } 198 199 if (frame_num % kRotationPeriod == 0 && frame_num != 0) { 200 uint32_t tmp = dest_frame_.width; 201 dest_frame_.width = dest_frame_.height; 202 dest_frame_.height = tmp; 203 } 204 } 205 206 frame_t display = {}; 207 for (unsigned i = 0; i < displays_.size(); i++) { 208 display.height = displays_[i]->mode().vertical_resolution; 209 display.width = displays_[i]->mode().horizontal_resolution; 210 211 // Calculate the portion of the dest frame which shows up on this display 212 if (compute_intersection(display, dest_frame_, &layers_[i].dest)) { 213 // Find the subset of the src region which shows up on this display 214 if (rotation_ == fuchsia_display_Transform_IDENTITY 215 || rotation_ == fuchsia_display_Transform_ROT_180) { 216 if (!scaling_) { 217 layers_[i].src.x_pos = 218 src_frame_.x_pos + (layers_[i].dest.x_pos - dest_frame_.x_pos); 219 layers_[i].src.y_pos = src_frame_.y_pos; 220 layers_[i].src.width = layers_[i].dest.width; 221 layers_[i].src.height = layers_[i].dest.height; 222 } else { 223 layers_[i].src.x_pos = src_frame_.x_pos + interpolate_scaling( 224 layers_[i].dest.x_pos - dest_frame_.x_pos, frame_num); 225 layers_[i].src.y_pos = src_frame_.y_pos; 226 layers_[i].src.width = interpolate_scaling(layers_[i].dest.width, frame_num); 227 layers_[i].src.height = interpolate_scaling(layers_[i].dest.height, frame_num); 228 } 229 } else { 230 layers_[i].src.x_pos = src_frame_.x_pos; 231 layers_[i].src.y_pos = 232 src_frame_.y_pos + (layers_[i].dest.y_pos - dest_frame_.y_pos); 233 layers_[i].src.height = layers_[i].dest.width; 234 layers_[i].src.width = layers_[i].dest.height; 235 } 236 237 // Put the dest frame coordinates in the display's coord space 238 layers_[i].dest.x_pos -= display.x_pos; 239 layers_[i].active = true; 240 } else { 241 layers_[i].active = false; 242 } 243 244 display.x_pos += display.width; 245 } 246 247 if (layer_toggle_) { 248 for (auto& layer : layers_) { 249 layer.active = !(frame_num % 2); 250 } 251 } 252} 253 254void PrimaryLayer::SendLayout(zx_handle_t channel) { 255 if (layer_flipping_) { 256 SetLayerImages(channel, alt_image_); 257 } 258 if (scaling_ || pan_src_ || pan_dest_) { 259 SetLayerPositions(channel); 260 } 261} 262 263bool PrimaryLayer::WaitForReady() { 264 return Wait(SIGNAL_EVENT); 265} 266 267void PrimaryLayer::Render(int32_t frame_num) { 268 if (!layer_flipping_) { 269 return; 270 } 271 images_[alt_image_]->Render(frame_num < 2 ? 0 : frame_num - 2, frame_num); 272 for (auto& layer : layers_) { 273 zx_object_signal(layer.import_info[alt_image_].events[WAIT_EVENT], 0, ZX_EVENT_SIGNALED); 274 } 275} 276 277void PrimaryLayer::SetLayerPositions(zx_handle_t dc_handle) { 278 fuchsia_display_ControllerSetLayerPrimaryPositionRequest msg; 279 msg.hdr.ordinal = fuchsia_display_ControllerSetLayerPrimaryPositionOrdinal; 280 281 for (auto& layer : layers_) { 282 msg.layer_id = layer.id; 283 msg.transform = rotation_; 284 285 msg.src_frame.width = layer.src.width; 286 msg.src_frame.height = layer.src.height; 287 msg.src_frame.x_pos = layer.src.x_pos; 288 msg.src_frame.y_pos = layer.src.y_pos; 289 290 msg.dest_frame.width = layer.dest.width; 291 msg.dest_frame.height = layer.dest.height; 292 msg.dest_frame.x_pos = layer.dest.x_pos; 293 msg.dest_frame.y_pos = layer.dest.y_pos; 294 295 if (zx_channel_write(dc_handle, 0, &msg, sizeof(msg), nullptr, 0) != ZX_OK) { 296 ZX_ASSERT(false); 297 } 298 } 299} 300 301void VirtualLayer::SetLayerImages(zx_handle_t dc_handle, bool alt_image) { 302 fuchsia_display_ControllerSetLayerImageRequest msg; 303 msg.hdr.ordinal = fuchsia_display_ControllerSetLayerImageOrdinal; 304 305 for (auto& layer : layers_) { 306 msg.layer_id = layer.id; 307 msg.image_id = layer.import_info[alt_image].id; 308 msg.wait_event_id = layer.import_info[alt_image].event_ids[WAIT_EVENT]; 309 msg.signal_event_id = layer.import_info[alt_image].event_ids[SIGNAL_EVENT]; 310 311 if (zx_channel_write(dc_handle, 0, &msg, sizeof(msg), nullptr, 0) != ZX_OK) { 312 ZX_ASSERT(false); 313 } 314 } 315} 316 317bool PrimaryLayer::Wait(uint32_t idx) { 318 zx_time_t deadline = zx_deadline_after(ZX_MSEC(100)); 319 for (auto& layer : layers_) { 320 uint32_t observed; 321 if (!layer.active) { 322 continue; 323 } 324 zx_handle_t event = layer.import_info[alt_image_].events[idx]; 325 zx_status_t res; 326 if ((res = zx_object_wait_one(event, ZX_EVENT_SIGNALED, deadline, &observed)) == ZX_OK) { 327 if (layer_flipping_) { 328 zx_object_signal(event, ZX_EVENT_SIGNALED, 0); 329 } 330 } else { 331 return false; 332 } 333 } 334 return true; 335} 336 337CursorLayer::CursorLayer(Display* display) : VirtualLayer(display) { } 338 339CursorLayer::CursorLayer(const fbl::Vector<Display>& displays) : VirtualLayer(displays) { } 340 341bool CursorLayer::Init(zx_handle_t dc_handle) { 342 fuchsia_display_CursorInfo info = displays_[0]->cursor(); 343 uint32_t bg_color = 0xffffffff; 344 image_ = Image::Create( 345 dc_handle, info.width, info.height, info.pixel_format, get_fg_color(), bg_color, true); 346 if (!image_) { 347 return false; 348 } 349 image_->Render(-1, -1); 350 351 for (unsigned i = 0; i < displays_.size(); i++) { 352 layer_t* layer = CreateLayer(dc_handle); 353 if (layer == nullptr) { 354 return false; 355 } 356 357 layer->active = true; 358 if (!image_->Import(dc_handle, &layer->import_info[0])) { 359 return false; 360 } 361 zx_object_signal(layer->import_info[0].events[WAIT_EVENT], 0, ZX_EVENT_SIGNALED); 362 363 fuchsia_display_ControllerSetLayerCursorConfigRequest config; 364 config.hdr.ordinal = fuchsia_display_ControllerSetLayerCursorConfigOrdinal; 365 config.layer_id = layer->id; 366 config.image_config.height = info.height; 367 config.image_config.width = info.width; 368 config.image_config.pixel_format = info.pixel_format; 369 config.image_config.type = IMAGE_TYPE_SIMPLE; 370 371 if (zx_channel_write(dc_handle, 0, &config, sizeof(config), nullptr, 0) != ZX_OK) { 372 printf("Setting layer config failed\n"); 373 return false; 374 } 375 } 376 377 SetLayerImages(dc_handle, false); 378 379 return true; 380} 381 382void CursorLayer::StepLayout(int32_t frame_num) { 383 fuchsia_display_CursorInfo info = displays_[0]->cursor(); 384 385 x_pos_ = interpolate(width_ + info.width, frame_num, kDestFrameBouncePeriod) - info.width; 386 y_pos_ = interpolate(height_ + info.height, frame_num, kDestFrameBouncePeriod) - info.height; 387} 388 389void CursorLayer::SendLayout(zx_handle_t dc_handle) { 390 fuchsia_display_ControllerSetLayerCursorPositionRequest msg; 391 msg.hdr.ordinal = fuchsia_display_ControllerSetLayerCursorPositionOrdinal; 392 393 uint32_t display_start = 0; 394 for (unsigned i = 0; i < displays_.size(); i++) { 395 msg.layer_id = layers_[i].id; 396 msg.x = x_pos_ - display_start; 397 msg.y = y_pos_; 398 399 if (zx_channel_write(dc_handle, 0, &msg, sizeof(msg), nullptr, 0) != ZX_OK) { 400 ZX_ASSERT(false); 401 } 402 403 display_start += displays_[i]->mode().horizontal_resolution; 404 } 405} 406 407ColorLayer::ColorLayer(Display* display) : VirtualLayer(display) { } 408 409ColorLayer::ColorLayer(const fbl::Vector<Display>& displays) : VirtualLayer(displays) { } 410 411bool ColorLayer::Init(zx_handle_t dc_handle) { 412 for (unsigned i = 0; i < displays_.size(); i++) { 413 layer_t* layer = CreateLayer(dc_handle); 414 if (layer == nullptr) { 415 return false; 416 } 417 418 layer->active = true; 419 420 constexpr uint32_t kColorLayerFormat = ZX_PIXEL_FORMAT_ARGB_8888; 421 uint32_t kColorLayerColor = get_fg_color(); 422 423 uint32_t size = sizeof(fuchsia_display_ControllerSetLayerColorConfigRequest) 424 + FIDL_ALIGN(ZX_PIXEL_FORMAT_BYTES(kColorLayerFormat)); 425 uint8_t data[size]; 426 427 auto config = reinterpret_cast<fuchsia_display_ControllerSetLayerColorConfigRequest*>(data); 428 config->hdr.ordinal = fuchsia_display_ControllerSetLayerColorConfigOrdinal; 429 config->layer_id = layer->id; 430 config->pixel_format = kColorLayerFormat; 431 config->color_bytes.count = ZX_PIXEL_FORMAT_BYTES(kColorLayerFormat); 432 config->color_bytes.data = reinterpret_cast<void*>(FIDL_ALLOC_PRESENT); 433 434 *reinterpret_cast<uint32_t*>(config + 1) = kColorLayerColor; 435 436 if (zx_channel_write(dc_handle, 0, data, size, nullptr, 0) != ZX_OK) { 437 printf("Setting layer config failed\n"); 438 return false; 439 } 440 } 441 442 return true; 443} 444