Home | History | Annotate | Download | only in OpenglSystemCommon
      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 {
     42 }
     43 
     44 HostConnection::~HostConnection()
     45 {
     46     delete m_stream;
     47     delete m_glEnc;
     48     delete m_gl2Enc;
     49     delete m_rcEnc;
     50 }
     51 
     52 HostConnection *HostConnection::get() {
     53     return getWithThreadInfo(getEGLThreadInfo());
     54 }
     55 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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