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 22 using cvd::vnc::SimulatedHWComposer; 23 using vsoc::screen::ScreenRegionView; 24 25 SimulatedHWComposer::SimulatedHWComposer(BlackBoard* bb) 26 : 27 #ifdef FUZZ_TEST_VNC 28 engine_{std::random_device{}()}, 29 #endif 30 bb_{bb}, 31 stripes_(kMaxQueueElements, &SimulatedHWComposer::EraseHalfOfElements) { 32 stripe_maker_ = std::thread(&SimulatedHWComposer::MakeStripes, this); 33 } 34 35 SimulatedHWComposer::~SimulatedHWComposer() { 36 close(); 37 stripe_maker_.join(); 38 } 39 40 cvd::vnc::Stripe SimulatedHWComposer::GetNewStripe() { 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(); 78 int buffer_idx = screen_connector_->WaitForNewFrameSince(&previous_seq_num); 79 const char* frame_start = 80 static_cast<char*>(screen_connector_->GetBuffer(buffer_idx)); 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(); 106 s.stride = ActualScreenStride(); 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 116 int SimulatedHWComposer::NumberOfStripes() { return kNumStripes; } 117