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 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 45 HostConnection::~HostConnection() 46 { 47 delete m_stream; 48 delete m_glEnc; 49 delete m_gl2Enc; 50 delete m_rcEnc; 51 } 52 53 HostConnection *HostConnection::get() { 54 return getWithThreadInfo(getEGLThreadInfo()); 55 } 56 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 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 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 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 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 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 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 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 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 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 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 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 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