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 | |
Greg Hartman | ca7fb19 | 2017-09-28 16:14:12 -0700 | [diff] [blame] | 19 | #include "common/vsoc/lib/typed_region_view.h" |
Jorge E. Moreira | ccd5745 | 2017-09-29 15:19:07 -0700 | [diff] [blame] | 20 | #include "host/frontend/vnc_server/vnc_utils.h" |
Greg Hartman | ca7fb19 | 2017-09-28 16:14:12 -0700 | [diff] [blame] | 21 | #include "host/vsoc/gralloc/gralloc_buffer_region.h" |
Greg Hartman | ca7fb19 | 2017-09-28 16:14:12 -0700 | [diff] [blame] | 22 | |
Jorge E. Moreira | 2430701 | 2017-09-22 14:35:21 -0700 | [diff] [blame] | 23 | using avd::vnc::SimulatedHWComposer; |
Greg Hartman | ca7fb19 | 2017-09-28 16:14:12 -0700 | [diff] [blame] | 24 | using vsoc::gralloc::GrallocBufferRegion; |
Jorge E. Moreira | 2430701 | 2017-09-22 14:35:21 -0700 | [diff] [blame] | 25 | |
| 26 | SimulatedHWComposer::SimulatedHWComposer(BlackBoard* bb) |
| 27 | : |
| 28 | #ifdef FUZZ_TEST_VNC |
| 29 | engine_{std::random_device{}()}, |
| 30 | #endif |
Jorge E. Moreira | 2430701 | 2017-09-22 14:35:21 -0700 | [diff] [blame] | 31 | bb_{bb}, |
| 32 | stripes_(kMaxQueueElements, &SimulatedHWComposer::EraseHalfOfElements) { |
Greg Hartman | 86b114a | 2017-11-03 21:04:14 -0700 | [diff] [blame^] | 33 | stripe_maker_ = std::thread(&SimulatedHWComposer::MakeStripes, this); |
Jorge E. Moreira | 2430701 | 2017-09-22 14:35:21 -0700 | [diff] [blame] | 34 | } |
| 35 | |
| 36 | SimulatedHWComposer::~SimulatedHWComposer() { |
| 37 | close(); |
| 38 | stripe_maker_.join(); |
Jorge E. Moreira | 2430701 | 2017-09-22 14:35:21 -0700 | [diff] [blame] | 39 | } |
| 40 | |
| 41 | avd::vnc::Stripe SimulatedHWComposer::GetNewStripe() { |
| 42 | auto s = stripes_.Pop(); |
| 43 | #ifdef FUZZ_TEST_VNC |
| 44 | if (random_(engine_)) { |
| 45 | usleep(7000); |
| 46 | stripes_.Push(std::move(s)); |
| 47 | s = stripes_.Pop(); |
| 48 | } |
| 49 | #endif |
| 50 | return s; |
| 51 | } |
| 52 | |
| 53 | bool SimulatedHWComposer::closed() { |
| 54 | std::lock_guard<std::mutex> guard(m_); |
| 55 | return closed_; |
| 56 | } |
| 57 | |
| 58 | void SimulatedHWComposer::close() { |
| 59 | std::lock_guard<std::mutex> guard(m_); |
| 60 | closed_ = true; |
| 61 | } |
| 62 | |
| 63 | // Assuming the number of stripes is less than half the size of the queue |
| 64 | // this will be safe as the newest stripes won't be lost. In the real |
| 65 | // hwcomposer, where stripes are coming in a different order, the full |
| 66 | // queue case would probably need a different approach to be safe. |
| 67 | void SimulatedHWComposer::EraseHalfOfElements( |
| 68 | ThreadSafeQueue<Stripe>::QueueImpl* q) { |
| 69 | q->erase(q->begin(), std::next(q->begin(), kMaxQueueElements / 2)); |
| 70 | } |
| 71 | |
| 72 | void SimulatedHWComposer::MakeStripes() { |
| 73 | std::uint32_t previous_seq_num{}; |
| 74 | auto screen_height = ActualScreenHeight(); |
| 75 | Message raw_screen; |
| 76 | std::uint64_t stripe_seq_num = 1; |
| 77 | while (!closed()) { |
| 78 | bb_->WaitForAtLeastOneClientConnection(); |
Greg Hartman | ca7fb19 | 2017-09-28 16:14:12 -0700 | [diff] [blame] | 79 | vsoc_reg_off_t buffer_offset = |
Greg Hartman | 86b114a | 2017-11-03 21:04:14 -0700 | [diff] [blame^] | 80 | GetFBBroadcastRegionView()->WaitForNewFrameSince(&previous_seq_num); |
Jorge E. Moreira | 2430701 | 2017-09-22 14:35:21 -0700 | [diff] [blame] | 81 | |
| 82 | const auto* frame_start = |
Greg Hartman | ca7fb19 | 2017-09-28 16:14:12 -0700 | [diff] [blame] | 83 | GrallocBufferRegion::GetInstance()->OffsetToBufferPtr(buffer_offset); |
Jorge E. Moreira | 2430701 | 2017-09-22 14:35:21 -0700 | [diff] [blame] | 84 | raw_screen.assign(frame_start, frame_start + ScreenSizeInBytes()); |
| 85 | |
| 86 | for (int i = 0; i < kNumStripes; ++i) { |
| 87 | ++stripe_seq_num; |
| 88 | std::uint16_t y = (screen_height / kNumStripes) * i; |
| 89 | |
| 90 | // Last frames on the right and/or bottom handle extra pixels |
| 91 | // when a screen dimension is not evenly divisible by Frame::kNumSlots. |
| 92 | std::uint16_t height = |
| 93 | screen_height / kNumStripes + |
| 94 | (i + 1 == kNumStripes ? screen_height % kNumStripes : 0); |
| 95 | const auto* raw_start = |
| 96 | &raw_screen[y * ActualScreenWidth() * BytesPerPixel()]; |
| 97 | const auto* raw_end = |
| 98 | raw_start + (height * ActualScreenWidth() * BytesPerPixel()); |
| 99 | // creating a named object and setting individual data members in order |
| 100 | // to make klp happy |
| 101 | // TODO (haining) construct this inside the call when not compiling |
| 102 | // on klp |
| 103 | Stripe s{}; |
| 104 | s.index = i; |
| 105 | s.frame_id = previous_seq_num; |
| 106 | s.x = 0; |
| 107 | s.y = y; |
| 108 | s.width = ActualScreenWidth(); |
| 109 | s.height = height; |
| 110 | s.raw_data.assign(raw_start, raw_end); |
| 111 | s.seq_number = StripeSeqNumber{stripe_seq_num}; |
| 112 | s.orientation = ScreenOrientation::Portrait; |
| 113 | stripes_.Push(std::move(s)); |
| 114 | } |
| 115 | } |
| 116 | } |
| 117 | |
Greg Hartman | 7075378 | 2017-09-28 16:12:43 -0700 | [diff] [blame] | 118 | int SimulatedHWComposer::NumberOfStripes() { return kNumStripes; } |