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