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 cuttlefish::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 cuttlefish::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