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 <gflags/gflags.h>
20 
21 #include "host/frontend/vnc_server/vnc_utils.h"
22 #include "host/libs/config/cuttlefish_config.h"
23 
24 DEFINE_int32(frame_server_fd, -1, "");
25 
26 using cvd::vnc::SimulatedHWComposer;
27 
SimulatedHWComposer(BlackBoard * bb)28 SimulatedHWComposer::SimulatedHWComposer(BlackBoard* bb)
29     :
30 #ifdef FUZZ_TEST_VNC
31       engine_{std::random_device{}()},
32 #endif
33       bb_{bb},
34       stripes_(kMaxQueueElements, &SimulatedHWComposer::EraseHalfOfElements),
35       screen_connector_(ScreenConnector::Get(FLAGS_frame_server_fd)) {
36   stripe_maker_ = std::thread(&SimulatedHWComposer::MakeStripes, this);
37 }
38 
~SimulatedHWComposer()39 SimulatedHWComposer::~SimulatedHWComposer() {
40   close();
41   stripe_maker_.join();
42 }
43 
GetNewStripe()44 cvd::vnc::Stripe SimulatedHWComposer::GetNewStripe() {
45   auto s = stripes_.Pop();
46 #ifdef FUZZ_TEST_VNC
47   if (random_(engine_)) {
48     usleep(7000);
49     stripes_.Push(std::move(s));
50     s = stripes_.Pop();
51   }
52 #endif
53   return s;
54 }
55 
closed()56 bool SimulatedHWComposer::closed() {
57   std::lock_guard<std::mutex> guard(m_);
58   return closed_;
59 }
60 
close()61 void SimulatedHWComposer::close() {
62   std::lock_guard<std::mutex> guard(m_);
63   closed_ = true;
64 }
65 
66 // Assuming the number of stripes is less than half the size of the queue
67 // this will be safe as the newest stripes won't be lost. In the real
68 // hwcomposer, where stripes are coming in a different order, the full
69 // queue case would probably need a different approach to be safe.
EraseHalfOfElements(ThreadSafeQueue<Stripe>::QueueImpl * q)70 void SimulatedHWComposer::EraseHalfOfElements(
71     ThreadSafeQueue<Stripe>::QueueImpl* q) {
72   q->erase(q->begin(), std::next(q->begin(), kMaxQueueElements / 2));
73 }
74 
MakeStripes()75 void SimulatedHWComposer::MakeStripes() {
76   std::uint32_t previous_frame_number = 0;
77   auto screen_height = ScreenConnector::ScreenHeight();
78   Message raw_screen;
79   std::uint64_t stripe_seq_num = 1;
80 
81   const FrameCallback frame_callback = [&](uint32_t frame_number,
82                                            uint8_t* frame_pixels) {
83     raw_screen.assign(frame_pixels,
84                       frame_pixels + ScreenConnector::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 = &raw_screen[y * ScreenConnector::ScreenWidth() *
96                                           ScreenConnector::BytesPerPixel()];
97       const auto* raw_end =
98           raw_start + (height * ScreenConnector::ScreenWidth() *
99                        ScreenConnector::BytesPerPixel());
100       // creating a named object and setting individual data members in order
101       // to make klp happy
102       // TODO (haining) construct this inside the call when not compiling
103       // on klp
104       Stripe s{};
105       s.index = i;
106       s.frame_id = frame_number;
107       s.x = 0;
108       s.y = y;
109       s.width = ScreenConnector::ScreenWidth();
110       s.stride = ScreenConnector::ScreenStride();
111       s.height = height;
112       s.raw_data.assign(raw_start, raw_end);
113       s.seq_number = StripeSeqNumber{stripe_seq_num};
114       s.orientation = ScreenOrientation::Portrait;
115       stripes_.Push(std::move(s));
116     }
117 
118     previous_frame_number = frame_number;
119   };
120 
121   while (!closed()) {
122     bb_->WaitForAtLeastOneClientConnection();
123 
124     screen_connector_->OnFrameAfter(previous_frame_number, frame_callback);
125   }
126 }
127 
NumberOfStripes()128 int SimulatedHWComposer::NumberOfStripes() { return kNumStripes; }
129