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