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 #include "TcpStream.h" 18 #include "QemuPipeStream.h" 19 #include "ThreadInfo.h" 20 #include <cutils/log.h> 21 #include "GLEncoder.h" 22 #include "GL2Encoder.h" 23 #include <memory> 24 25 #define STREAM_BUFFER_SIZE 4*1024*1024 26 #define STREAM_PORT_NUM 22468 27 28 /* Set to 1 to use a QEMU pipe, or 0 for a TCP connection */ 29 #define USE_QEMU_PIPE 1 30 31 HostConnection::HostConnection() : 32 m_stream(NULL), 33 m_glEnc(NULL), 34 m_gl2Enc(NULL), 35 m_rcEnc(NULL), 36 m_checksumHelper() 37 { 38 } 39 40 HostConnection::~HostConnection() 41 { 42 delete m_stream; 43 delete m_glEnc; 44 delete m_gl2Enc; 45 delete m_rcEnc; 46 } 47 48 HostConnection *HostConnection::get() 49 { 50 /* TODO: Make this configurable with a system property */ 51 const int useQemuPipe = USE_QEMU_PIPE; 52 53 // Get thread info 54 EGLThreadInfo *tinfo = getEGLThreadInfo(); 55 if (!tinfo) { 56 return NULL; 57 } 58 59 if (tinfo->hostConn == NULL) { 60 HostConnection *con = new HostConnection(); 61 if (NULL == con) { 62 return NULL; 63 } 64 65 if (useQemuPipe) { 66 QemuPipeStream *stream = new QemuPipeStream(STREAM_BUFFER_SIZE); 67 if (!stream) { 68 ALOGE("Failed to create QemuPipeStream for host connection!!!\n"); 69 delete con; 70 return NULL; 71 } 72 if (stream->connect() < 0) { 73 ALOGE("Failed to connect to host (QemuPipeStream)!!!\n"); 74 delete stream; 75 delete con; 76 return NULL; 77 } 78 con->m_stream = stream; 79 } 80 else /* !useQemuPipe */ 81 { 82 TcpStream *stream = new TcpStream(STREAM_BUFFER_SIZE); 83 if (!stream) { 84 ALOGE("Failed to create TcpStream for host connection!!!\n"); 85 delete con; 86 return NULL; 87 } 88 89 if (stream->connect("10.0.2.2", STREAM_PORT_NUM) < 0) { 90 ALOGE("Failed to connect to host (TcpStream)!!!\n"); 91 delete stream; 92 delete con; 93 return NULL; 94 } 95 con->m_stream = stream; 96 } 97 98 // send zero 'clientFlags' to the host. 99 unsigned int *pClientFlags = 100 (unsigned int *)con->m_stream->allocBuffer(sizeof(unsigned int)); 101 *pClientFlags = 0; 102 con->m_stream->commitBuffer(sizeof(unsigned int)); 103 104 ALOGD("HostConnection::get() New Host Connection established %p, tid %d\n", con, gettid()); 105 tinfo->hostConn = con; 106 } 107 108 return tinfo->hostConn; 109 } 110 111 GLEncoder *HostConnection::glEncoder() 112 { 113 if (!m_glEnc) { 114 m_glEnc = new GLEncoder(m_stream, checksumHelper()); 115 DBG("HostConnection::glEncoder new encoder %p, tid %d", m_glEnc, gettid()); 116 m_glEnc->setContextAccessor(s_getGLContext); 117 } 118 return m_glEnc; 119 } 120 121 GL2Encoder *HostConnection::gl2Encoder() 122 { 123 if (!m_gl2Enc) { 124 m_gl2Enc = new GL2Encoder(m_stream, checksumHelper()); 125 DBG("HostConnection::gl2Encoder new encoder %p, tid %d", m_gl2Enc, gettid()); 126 m_gl2Enc->setContextAccessor(s_getGL2Context); 127 } 128 return m_gl2Enc; 129 } 130 131 renderControl_encoder_context_t *HostConnection::rcEncoder() 132 { 133 if (!m_rcEnc) { 134 m_rcEnc = new renderControl_encoder_context_t(m_stream, checksumHelper()); 135 // TODO: disable checksum as a workaround in a glTexSubImage2D problem 136 // Uncomment the following line when the root cause is solved 137 //setChecksumHelper(m_rcEnc); 138 } 139 return m_rcEnc; 140 } 141 142 gl_client_context_t *HostConnection::s_getGLContext() 143 { 144 EGLThreadInfo *ti = getEGLThreadInfo(); 145 if (ti->hostConn) { 146 return ti->hostConn->m_glEnc; 147 } 148 return NULL; 149 } 150 151 gl2_client_context_t *HostConnection::s_getGL2Context() 152 { 153 EGLThreadInfo *ti = getEGLThreadInfo(); 154 if (ti->hostConn) { 155 return ti->hostConn->m_gl2Enc; 156 } 157 return NULL; 158 } 159 160 void HostConnection::setChecksumHelper(renderControl_encoder_context_t *rcEnc) { 161 std::unique_ptr<char[]> glExtensions; 162 int extensionSize = rcEnc->rcGetGLString(rcEnc, GL_EXTENSIONS, NULL, 0); 163 if (extensionSize < 0) { 164 glExtensions = std::unique_ptr<char[]>(new char[-extensionSize]); 165 extensionSize = rcEnc->rcGetGLString(rcEnc, GL_EXTENSIONS, glExtensions.get(), -extensionSize); 166 if (extensionSize <= 0) { 167 glExtensions.reset(); 168 } 169 } 170 // check the host supported version 171 uint32_t checksumVersion = 0; 172 const char* checksumPrefix = ChecksumCalculator::getMaxVersionStrPrefix(); 173 const char* glProtocolStr = glExtensions.get() ? 174 strstr(glExtensions.get(), checksumPrefix) : NULL; 175 if (glProtocolStr) { 176 uint32_t maxVersion = ChecksumCalculator::getMaxVersion(); 177 sscanf(glProtocolStr+strlen(checksumPrefix), "%d", &checksumVersion); 178 if (maxVersion < checksumVersion) { 179 checksumVersion = maxVersion; 180 } 181 // The ordering of the following two commands matters! 182 // Must tell the host first before setting it in the guest 183 rcEnc->rcSelectChecksumHelper(rcEnc, checksumVersion, 0); 184 m_checksumHelper.setVersion(checksumVersion); 185 } 186 } 187