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" 18 19 #include "host/frontend/vnc_server/vnc_utils.h" 20 #include "host/libs/config/cuttlefish_config.h" 21 #include "common/vsoc/lib/screen_region_view.h" 22 23 using cvd::vnc::SimulatedHWComposer; 24 using vsoc::screen::ScreenRegionView; 25 26 SimulatedHWComposer::SimulatedHWComposer(BlackBoard* bb) 27 : 28 #ifdef FUZZ_TEST_VNC 29 engine_{std::random_device{}()}, 30 #endif 31 bb_{bb}, 32 stripes_(kMaxQueueElements, &SimulatedHWComposer::EraseHalfOfElements) { 33 stripe_maker_ = std::thread(&SimulatedHWComposer::MakeStripes, this); 34 } 35 36 SimulatedHWComposer::~SimulatedHWComposer() { 37 close(); 38 stripe_maker_.join(); 39 } 40 41 cvd::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 auto screen_view = ScreenRegionView::GetInstance(vsoc::GetDomain().c_str()); 78 while (!closed()) { 79 bb_->WaitForAtLeastOneClientConnection(); 80 int buffer_idx = screen_view->WaitForNewFrameSince(&previous_seq_num); 81 const char* frame_start = 82 static_cast<char*>(screen_view->GetBuffer(buffer_idx)); 83 raw_screen.assign(frame_start, frame_start + ScreenSizeInBytes()); 84 85 for (int i = 0; i < kNumStripes; ++i) { 86 ++stripe_seq_num; 87 std::uint16_t y = (screen_height / kNumStripes) * i; 88 89 // Last frames on the right and/or bottom handle extra pixels 90 // when a screen dimension is not evenly divisible by Frame::kNumSlots. 91 std::uint16_t height = 92 screen_height / kNumStripes + 93 (i + 1 == kNumStripes ? screen_height % kNumStripes : 0); 94 const auto* raw_start = 95 &raw_screen[y * ActualScreenWidth() * BytesPerPixel()]; 96 const auto* raw_end = 97 raw_start + (height * ActualScreenWidth() * BytesPerPixel()); 98 // creating a named object and setting individual data members in order 99 // to make klp happy 100 // TODO (haining) construct this inside the call when not compiling 101 // on klp 102 Stripe s{}; 103 s.index = i; 104 s.frame_id = previous_seq_num; 105 s.x = 0; 106 s.y = y; 107 s.width = ActualScreenWidth(); 108 s.height = height; 109 s.raw_data.assign(raw_start, raw_end); 110 s.seq_number = StripeSeqNumber{stripe_seq_num}; 111 s.orientation = ScreenOrientation::Portrait; 112 stripes_.Push(std::move(s)); 113 } 114 } 115 } 116 117 int SimulatedHWComposer::NumberOfStripes() { return kNumStripes; } 118