blob: ea82f7e9d13a8b3f6ed2d844daaf130619be2877 [file] [log] [blame]
Jorge E. Moreirac87c2c72019-03-06 16:12:23 -08001/*
2 * Copyright (C) 2019 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/screen_connector.h"
18
19#include <atomic>
20#include <condition_variable>
21
22#include <gflags/gflags.h>
23
24#include <common/vsoc/lib/screen_region_view.h>
25#include <host/libs/config/cuttlefish_config.h>
26#include "host/frontend/vnc_server/vnc_utils.h"
27
28DEFINE_int32(frame_server_fd, -1, "");
29
30namespace cvd {
31namespace vnc {
32
33namespace {
34class VSoCScreenConnector : public ScreenConnector {
35 public:
36 int WaitForNewFrameSince(std::uint32_t* seq_num) override {
37 if (!screen_view_) return -1;
38 return screen_view_->WaitForNewFrameSince(seq_num);
39 }
40
41 void* GetBuffer(int buffer_idx) override {
42 if (!screen_view_) return nullptr;
43 return screen_view_->GetBuffer(buffer_idx);
44 }
45
46 private:
47 vsoc::screen::ScreenRegionView* screen_view_ =
48 vsoc::screen::ScreenRegionView::GetInstance(vsoc::GetDomain().c_str());
49};
50
51// TODO(b/128852363): Substitute with one based on memory shared with the
52// wayland mock
53class SocketBasedScreenConnector : public ScreenConnector {
54 public:
55 SocketBasedScreenConnector(vsoc::CuttlefishConfig* config) : config_(config) {
56 screen_server_thread_ = std::thread([this]() { ServerLoop(); });
57 }
58
59 int WaitForNewFrameSince(std::uint32_t* seq_num) override {
60 std::unique_lock<std::mutex> lock(new_frame_mtx_);
61 while (seq_num_ == *seq_num) {
62 new_frame_cond_var_.wait(lock);
63 }
64 return newest_buffer_;
65 }
66
67 void* GetBuffer(int buffer_idx) override {
68 if (buffer_idx < 0) return nullptr;
69 buffer_idx %= NUM_BUFFERS_;
70 return &buffer_[buffer_idx * ScreenSizeInBytes()];
71 }
72
73 private:
74 static constexpr int NUM_BUFFERS_ = 4;
75
76 void ServerLoop() {
77 if (FLAGS_frame_server_fd < 0) {
78 LOG(FATAL) << "Invalid file descriptor: " << FLAGS_frame_server_fd;
79 return;
80 }
81 auto server = SharedFD::Dup(FLAGS_frame_server_fd);
82 close(FLAGS_frame_server_fd);
83 if (!server->IsOpen()) {
84 LOG(FATAL) << "Unable to dup screen server: " << server->StrError();
85 return;
86 }
87
88 int current_buffer = 0;
89
90 while (1) {
91 auto conn = SharedFD::Accept(*server);
92 while (conn->IsOpen()) {
93 SendScreenParameters(conn);
94
95 int32_t size = 0;
96 conn->Read(&size, sizeof(size));
97 auto buff = reinterpret_cast<uint8_t*>(GetBuffer(current_buffer));
98 while (size > 0) {
99 auto read = conn->Read(buff, size);
100 if (read < 0) {
101 LOG(ERROR) << "Failed to read from hwcomposer: "
102 << conn->StrError();
103 return;
104 }
105 size -= read;
106 buff += read;
107 }
108 BroadcastNewFrame(current_buffer);
109 current_buffer = (current_buffer + 1) % NUM_BUFFERS_;
110 }
111 }
112 }
113
114 void SendScreenParameters(SharedFD conn) const {
115 // TODO(b/128842613): Send this info from the configuration server
116 int32_t screen_params[4];
117 screen_params[0] = config_->x_res();
118 screen_params[1] = config_->y_res();
119 screen_params[2] = config_->dpi();
120 screen_params[3] = config_->refresh_rate_hz();
121 int buff_size = sizeof(screen_params);
122 int res = conn->Write(screen_params, buff_size);
123 if (res != buff_size) {
124 LOG(FATAL)
125 << "Unable to send full screen parameters to the hwcomposer ("
126 << res << "): " << conn->StrError();
127 }
128 }
129
130 void BroadcastNewFrame(int buffer_idx) {
131 {
132 std::lock_guard<std::mutex> lock(new_frame_mtx_);
133 seq_num_++;
134 newest_buffer_ = buffer_idx;
135 }
136 new_frame_cond_var_.notify_all();
137 }
138
139 vsoc::CuttlefishConfig* config_;
140 std::vector<std::uint8_t> buffer_ =
141 std::vector<std::uint8_t>(NUM_BUFFERS_ * ScreenSizeInBytes());
142 std::uint32_t seq_num_{0};
143 int newest_buffer_ = 0;
144 std::condition_variable new_frame_cond_var_;
145 std::mutex new_frame_mtx_;
146 std::thread screen_server_thread_;
147};
148} // namespace
149
150ScreenConnector* ScreenConnector::Get() {
151 auto config = vsoc::CuttlefishConfig::Get();
152 if (config->enable_ivserver()) {
153 return new VSoCScreenConnector();
154 } else {
155 return new SocketBasedScreenConnector(config);
156 }
157}
158
159} // namespace vnc
160} // namespace cvd