1 /*
2 * Copyright (C) 2011 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 #include "HostConnection.h"
17
18 #include "GLEncoder.h"
19 #include "GL2Encoder.h"
20 #include "ProcessPipe.h"
21 #include "QemuPipeStream.h"
22 #include "TcpStream.h"
23 #include "ThreadInfo.h"
24
25 #include <cutils/log.h>
26
27 #define STREAM_BUFFER_SIZE (4*1024*1024)
28 #define STREAM_PORT_NUM 22468
29
30 /* Set to 1 to use a QEMU pipe, or 0 for a TCP connection */
31 #define USE_QEMU_PIPE 1
32
HostConnection()33 HostConnection::HostConnection() :
34 m_stream(NULL),
35 m_glEnc(NULL),
36 m_gl2Enc(NULL),
37 m_rcEnc(NULL),
38 m_checksumHelper(),
39 m_glExtensions(),
40 m_grallocOnly(true),
41 m_noHostError(false)
42 {
43 }
44
~HostConnection()45 HostConnection::~HostConnection()
46 {
47 delete m_stream;
48 delete m_glEnc;
49 delete m_gl2Enc;
50 delete m_rcEnc;
51 }
52
get()53 HostConnection *HostConnection::get() {
54 return getWithThreadInfo(getEGLThreadInfo());
55 }
56
getWithThreadInfo(EGLThreadInfo * tinfo)57 HostConnection *HostConnection::getWithThreadInfo(EGLThreadInfo* tinfo) {
58
59 /* TODO: Make this configurable with a system property */
60 const int useQemuPipe = USE_QEMU_PIPE;
61
62 // Get thread info
63 if (!tinfo) {
64 return NULL;
65 }
66
67 if (tinfo->hostConn == NULL) {
68 HostConnection *con = new HostConnection();
69 if (NULL == con) {
70 return NULL;
71 }
72
73 if (useQemuPipe) {
74 QemuPipeStream *stream = new QemuPipeStream(STREAM_BUFFER_SIZE);
75 if (!stream) {
76 ALOGE("Failed to create QemuPipeStream for host connection!!!\n");
77 delete con;
78 return NULL;
79 }
80 if (stream->connect() < 0) {
81 ALOGE("Failed to connect to host (QemuPipeStream)!!!\n");
82 delete stream;
83 delete con;
84 return NULL;
85 }
86 con->m_stream = stream;
87 con->m_pipeFd = stream->getSocket();
88 }
89 else /* !useQemuPipe */
90 {
91 TcpStream *stream = new TcpStream(STREAM_BUFFER_SIZE);
92 if (!stream) {
93 ALOGE("Failed to create TcpStream for host connection!!!\n");
94 delete con;
95 return NULL;
96 }
97
98 if (stream->connect("10.0.2.2", STREAM_PORT_NUM) < 0) {
99 ALOGE("Failed to connect to host (TcpStream)!!!\n");
100 delete stream;
101 delete con;
102 return NULL;
103 }
104 con->m_stream = stream;
105 }
106
107 // send zero 'clientFlags' to the host.
108 unsigned int *pClientFlags =
109 (unsigned int *)con->m_stream->allocBuffer(sizeof(unsigned int));
110 *pClientFlags = 0;
111 con->m_stream->commitBuffer(sizeof(unsigned int));
112
113 ALOGD("HostConnection::get() New Host Connection established %p, tid %d\n", con, gettid());
114 tinfo->hostConn = con;
115 }
116
117 return tinfo->hostConn;
118 }
119
exit()120 void HostConnection::exit() {
121 EGLThreadInfo *tinfo = getEGLThreadInfo();
122 if (!tinfo) {
123 return;
124 }
125
126 if (tinfo->hostConn) {
127 delete tinfo->hostConn;
128 tinfo->hostConn = NULL;
129 }
130 }
131
132
133
glEncoder()134 GLEncoder *HostConnection::glEncoder()
135 {
136 if (!m_glEnc) {
137 m_glEnc = new GLEncoder(m_stream, checksumHelper());
138 DBG("HostConnection::glEncoder new encoder %p, tid %d", m_glEnc, gettid());
139 m_glEnc->setContextAccessor(s_getGLContext);
140 }
141 return m_glEnc;
142 }
143
gl2Encoder()144 GL2Encoder *HostConnection::gl2Encoder()
145 {
146 if (!m_gl2Enc) {
147 m_gl2Enc = new GL2Encoder(m_stream, checksumHelper());
148 DBG("HostConnection::gl2Encoder new encoder %p, tid %d", m_gl2Enc, gettid());
149 m_gl2Enc->setContextAccessor(s_getGL2Context);
150 m_gl2Enc->setNoHostError(m_noHostError);
151 }
152 return m_gl2Enc;
153 }
154
rcEncoder()155 ExtendedRCEncoderContext *HostConnection::rcEncoder()
156 {
157 if (!m_rcEnc) {
158 m_rcEnc = new ExtendedRCEncoderContext(m_stream, checksumHelper());
159 setChecksumHelper(m_rcEnc);
160 queryAndSetSyncImpl(m_rcEnc);
161 queryAndSetDmaImpl(m_rcEnc);
162 queryAndSetGLESMaxVersion(m_rcEnc);
163 queryAndSetNoErrorState(m_rcEnc);
164 processPipeInit(m_rcEnc);
165 }
166 return m_rcEnc;
167 }
168
s_getGLContext()169 gl_client_context_t *HostConnection::s_getGLContext()
170 {
171 EGLThreadInfo *ti = getEGLThreadInfo();
172 if (ti->hostConn) {
173 return ti->hostConn->m_glEnc;
174 }
175 return NULL;
176 }
177
s_getGL2Context()178 gl2_client_context_t *HostConnection::s_getGL2Context()
179 {
180 EGLThreadInfo *ti = getEGLThreadInfo();
181 if (ti->hostConn) {
182 return ti->hostConn->m_gl2Enc;
183 }
184 return NULL;
185 }
186
queryGLExtensions(ExtendedRCEncoderContext * rcEnc)187 const std::string& HostConnection::queryGLExtensions(ExtendedRCEncoderContext *rcEnc) {
188 if (!m_glExtensions.empty()) {
189 return m_glExtensions;
190 }
191
192 // Extensions strings are usually quite long, preallocate enough here.
193 std::string extensions_buffer(1023, '\0');
194
195 // rcGetGLString() returns required size including the 0-terminator, so
196 // account it when passing/using the sizes.
197 int extensionSize = rcEnc->rcGetGLString(rcEnc, GL_EXTENSIONS,
198 &extensions_buffer[0],
199 extensions_buffer.size() + 1);
200 if (extensionSize < 0) {
201 extensions_buffer.resize(-extensionSize);
202 extensionSize = rcEnc->rcGetGLString(rcEnc, GL_EXTENSIONS,
203 &extensions_buffer[0],
204 -extensionSize + 1);
205 }
206
207 if (extensionSize > 0) {
208 extensions_buffer.resize(extensionSize - 1);
209 m_glExtensions.swap(extensions_buffer);
210 }
211
212 return m_glExtensions;
213 }
214
setChecksumHelper(ExtendedRCEncoderContext * rcEnc)215 void HostConnection::setChecksumHelper(ExtendedRCEncoderContext *rcEnc) {
216 const std::string& glExtensions = queryGLExtensions(rcEnc);
217 // check the host supported version
218 uint32_t checksumVersion = 0;
219 const char* checksumPrefix = ChecksumCalculator::getMaxVersionStrPrefix();
220 const char* glProtocolStr = strstr(glExtensions.c_str(), checksumPrefix);
221 if (glProtocolStr) {
222 uint32_t maxVersion = ChecksumCalculator::getMaxVersion();
223 sscanf(glProtocolStr+strlen(checksumPrefix), "%d", &checksumVersion);
224 if (maxVersion < checksumVersion) {
225 checksumVersion = maxVersion;
226 }
227 // The ordering of the following two commands matters!
228 // Must tell the host first before setting it in the guest
229 rcEnc->rcSelectChecksumHelper(rcEnc, checksumVersion, 0);
230 m_checksumHelper.setVersion(checksumVersion);
231 }
232 }
233
queryAndSetSyncImpl(ExtendedRCEncoderContext * rcEnc)234 void HostConnection::queryAndSetSyncImpl(ExtendedRCEncoderContext *rcEnc) {
235 const std::string& glExtensions = queryGLExtensions(rcEnc);
236 #if PLATFORM_SDK_VERSION <= 16 || (!defined(__i386__) && !defined(__x86_64__))
237 rcEnc->setSyncImpl(SYNC_IMPL_NONE);
238 #else
239 if (glExtensions.find(kRCNativeSyncV3) != std::string::npos) {
240 rcEnc->setSyncImpl(SYNC_IMPL_NATIVE_SYNC_V3);
241 } else if (glExtensions.find(kRCNativeSyncV2) != std::string::npos) {
242 rcEnc->setSyncImpl(SYNC_IMPL_NATIVE_SYNC_V2);
243 } else {
244 rcEnc->setSyncImpl(SYNC_IMPL_NONE);
245 }
246 #endif
247 }
248
queryAndSetDmaImpl(ExtendedRCEncoderContext * rcEnc)249 void HostConnection::queryAndSetDmaImpl(ExtendedRCEncoderContext *rcEnc) {
250 std::string glExtensions = queryGLExtensions(rcEnc);
251 #if PLATFORM_SDK_VERSION <= 16 || (!defined(__i386__) && !defined(__x86_64__))
252 rcEnc->setDmaImpl(DMA_IMPL_NONE);
253 #else
254 if (glExtensions.find(kDmaExtStr_v1) != std::string::npos) {
255 rcEnc->setDmaImpl(DMA_IMPL_v1);
256 } else {
257 rcEnc->setDmaImpl(DMA_IMPL_NONE);
258 }
259 #endif
260 }
261
queryAndSetGLESMaxVersion(ExtendedRCEncoderContext * rcEnc)262 void HostConnection::queryAndSetGLESMaxVersion(ExtendedRCEncoderContext* rcEnc) {
263 std::string glExtensions = queryGLExtensions(rcEnc);
264 if (glExtensions.find(kGLESMaxVersion_2) != std::string::npos) {
265 rcEnc->setGLESMaxVersion(GLES_MAX_VERSION_2);
266 } else if (glExtensions.find(kGLESMaxVersion_3_0) != std::string::npos) {
267 rcEnc->setGLESMaxVersion(GLES_MAX_VERSION_3_0);
268 } else if (glExtensions.find(kGLESMaxVersion_3_1) != std::string::npos) {
269 rcEnc->setGLESMaxVersion(GLES_MAX_VERSION_3_1);
270 } else if (glExtensions.find(kGLESMaxVersion_3_2) != std::string::npos) {
271 rcEnc->setGLESMaxVersion(GLES_MAX_VERSION_3_2);
272 } else {
273 ALOGW("Unrecognized GLES max version string in extensions: %s",
274 glExtensions.c_str());
275 rcEnc->setGLESMaxVersion(GLES_MAX_VERSION_2);
276 }
277 }
278
queryAndSetNoErrorState(ExtendedRCEncoderContext * rcEnc)279 void HostConnection::queryAndSetNoErrorState(ExtendedRCEncoderContext* rcEnc) {
280 std::string glExtensions = queryGLExtensions(rcEnc);
281 if (glExtensions.find(kGLESNoHostError) != std::string::npos) {
282 m_noHostError = true;
283 }
284 }
285