Jorge E. Moreira | ccd5745 | 2017-09-29 15:19:07 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2017 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include "host/frontend/vnc_server/simulated_hw_composer.h" |
Jorge E. Moreira | 2430701 | 2017-09-22 14:35:21 -0700 | [diff] [blame] | 18 | |
Jorge E. Moreira | ccd5745 | 2017-09-29 15:19:07 -0700 | [diff] [blame] | 19 | #include "host/frontend/vnc_server/vnc_utils.h" |
Jorge E. Moreira | 08ea9e4 | 2018-05-24 14:17:51 -0700 | [diff] [blame] | 20 | #include "host/libs/config/cuttlefish_config.h" |
Greg Hartman | ca7fb19 | 2017-09-28 16:14:12 -0700 | [diff] [blame] | 21 | |
Greg Hartman | 153b106 | 2017-11-11 12:09:21 -0800 | [diff] [blame] | 22 | using cvd::vnc::SimulatedHWComposer; |
Cody Schuffelen | 134ff03 | 2019-11-22 00:25:32 -0800 | [diff] [blame^] | 23 | using vsoc::screen::ScreenRegionView; |
Jorge E. Moreira | 2430701 | 2017-09-22 14:35:21 -0700 | [diff] [blame] | 24 | |
| 25 | SimulatedHWComposer::SimulatedHWComposer(BlackBoard* bb) |
| 26 | : |
| 27 | #ifdef FUZZ_TEST_VNC |
| 28 | engine_{std::random_device{}()}, |
| 29 | #endif |
Jorge E. Moreira | 2430701 | 2017-09-22 14:35:21 -0700 | [diff] [blame] | 30 | bb_{bb}, |
| 31 | stripes_(kMaxQueueElements, &SimulatedHWComposer::EraseHalfOfElements) { |
Greg Hartman | d072a34 | 2017-12-05 20:27:40 -0800 | [diff] [blame] | 32 | stripe_maker_ = std::thread(&SimulatedHWComposer::MakeStripes, this); |
Jorge E. Moreira | 2430701 | 2017-09-22 14:35:21 -0700 | [diff] [blame] | 33 | } |
| 34 | |
| 35 | SimulatedHWComposer::~SimulatedHWComposer() { |
| 36 | close(); |
| 37 | stripe_maker_.join(); |
Jorge E. Moreira | 2430701 | 2017-09-22 14:35:21 -0700 | [diff] [blame] | 38 | } |
| 39 | |
Greg Hartman | 153b106 | 2017-11-11 12:09:21 -0800 | [diff] [blame] | 40 | cvd::vnc::Stripe SimulatedHWComposer::GetNewStripe() { |
Jorge E. Moreira | 2430701 | 2017-09-22 14:35:21 -0700 | [diff] [blame] | 41 | auto s = stripes_.Pop(); |
| 42 | #ifdef FUZZ_TEST_VNC |
| 43 | if (random_(engine_)) { |
| 44 | usleep(7000); |
| 45 | stripes_.Push(std::move(s)); |
| 46 | s = stripes_.Pop(); |
| 47 | } |
| 48 | #endif |
| 49 | return s; |
| 50 | } |
| 51 | |
| 52 | bool SimulatedHWComposer::closed() { |
| 53 | std::lock_guard<std::mutex> guard(m_); |
| 54 | return closed_; |
| 55 | } |
| 56 | |
| 57 | void SimulatedHWComposer::close() { |
| 58 | std::lock_guard<std::mutex> guard(m_); |
| 59 | closed_ = true; |
| 60 | } |
| 61 | |
| 62 | // Assuming the number of stripes is less than half the size of the queue |
| 63 | // this will be safe as the newest stripes won't be lost. In the real |
| 64 | // hwcomposer, where stripes are coming in a different order, the full |
| 65 | // queue case would probably need a different approach to be safe. |
| 66 | void SimulatedHWComposer::EraseHalfOfElements( |
| 67 | ThreadSafeQueue<Stripe>::QueueImpl* q) { |
| 68 | q->erase(q->begin(), std::next(q->begin(), kMaxQueueElements / 2)); |
| 69 | } |
| 70 | |
| 71 | void SimulatedHWComposer::MakeStripes() { |
| 72 | std::uint32_t previous_seq_num{}; |
| 73 | auto screen_height = ActualScreenHeight(); |
| 74 | Message raw_screen; |
| 75 | std::uint64_t stripe_seq_num = 1; |
| 76 | while (!closed()) { |
| 77 | bb_->WaitForAtLeastOneClientConnection(); |
Jorge E. Moreira | c87c2c7 | 2019-03-06 16:12:23 -0800 | [diff] [blame] | 78 | int buffer_idx = screen_connector_->WaitForNewFrameSince(&previous_seq_num); |
Jorge E. Moreira | a581090 | 2018-02-13 11:50:34 -0800 | [diff] [blame] | 79 | const char* frame_start = |
Jorge E. Moreira | c87c2c7 | 2019-03-06 16:12:23 -0800 | [diff] [blame] | 80 | static_cast<char*>(screen_connector_->GetBuffer(buffer_idx)); |
Jorge E. Moreira | 2430701 | 2017-09-22 14:35:21 -0700 | [diff] [blame] | 81 | raw_screen.assign(frame_start, frame_start + ScreenSizeInBytes()); |
| 82 | |
| 83 | for (int i = 0; i < kNumStripes; ++i) { |
| 84 | ++stripe_seq_num; |
| 85 | std::uint16_t y = (screen_height / kNumStripes) * i; |
| 86 | |
| 87 | // Last frames on the right and/or bottom handle extra pixels |
| 88 | // when a screen dimension is not evenly divisible by Frame::kNumSlots. |
| 89 | std::uint16_t height = |
| 90 | screen_height / kNumStripes + |
| 91 | (i + 1 == kNumStripes ? screen_height % kNumStripes : 0); |
| 92 | const auto* raw_start = |
| 93 | &raw_screen[y * ActualScreenWidth() * BytesPerPixel()]; |
| 94 | const auto* raw_end = |
| 95 | raw_start + (height * ActualScreenWidth() * BytesPerPixel()); |
| 96 | // creating a named object and setting individual data members in order |
| 97 | // to make klp happy |
| 98 | // TODO (haining) construct this inside the call when not compiling |
| 99 | // on klp |
| 100 | Stripe s{}; |
| 101 | s.index = i; |
| 102 | s.frame_id = previous_seq_num; |
| 103 | s.x = 0; |
| 104 | s.y = y; |
| 105 | s.width = ActualScreenWidth(); |
Jorge E. Moreira | f163009 | 2019-04-05 16:14:03 -0700 | [diff] [blame] | 106 | s.stride = ActualScreenStride(); |
Jorge E. Moreira | 2430701 | 2017-09-22 14:35:21 -0700 | [diff] [blame] | 107 | s.height = height; |
| 108 | s.raw_data.assign(raw_start, raw_end); |
| 109 | s.seq_number = StripeSeqNumber{stripe_seq_num}; |
| 110 | s.orientation = ScreenOrientation::Portrait; |
| 111 | stripes_.Push(std::move(s)); |
| 112 | } |
| 113 | } |
| 114 | } |
| 115 | |
Greg Hartman | 7075378 | 2017-09-28 16:12:43 -0700 | [diff] [blame] | 116 | int SimulatedHWComposer::NumberOfStripes() { return kNumStripes; } |