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