• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifdef GOLDFISH_NO_GL
19 struct gl_client_context_t {
20     int placeholder;
21 };
22 class GLEncoder : public gl_client_context_t {
23 public:
GLEncoder(IOStream *,ChecksumCalculator *)24     GLEncoder(IOStream*, ChecksumCalculator*) { }
setContextAccessor(gl_client_context_t * ())25     void setContextAccessor(gl_client_context_t *()) { }
26 };
27 struct gl2_client_context_t {
28     int placeholder;
29 };
30 class GL2Encoder : public gl2_client_context_t {
31 public:
GL2Encoder(IOStream *,ChecksumCalculator *)32     GL2Encoder(IOStream*, ChecksumCalculator*) { }
setContextAccessor(gl2_client_context_t * ())33     void setContextAccessor(gl2_client_context_t *()) { }
setNoHostError(bool)34     void setNoHostError(bool) { }
35 };
36 #else
37 #include "GLEncoder.h"
38 #include "GL2Encoder.h"
39 #endif
40 
41 #ifdef GOLDFISH_VULKAN
42 #include "VkEncoder.h"
43 #else
44 namespace goldfish_vk {
45 struct VkEncoder {
VkEncodergoldfish_vk::VkEncoder46     VkEncoder(IOStream*) { }
47     int placeholder;
48 };
49 } // namespace goldfish_vk
50 #endif
51 
52 using goldfish_vk::VkEncoder;
53 
54 #include "ProcessPipe.h"
55 #include "QemuPipeStream.h"
56 #include "TcpStream.h"
57 #include "ThreadInfo.h"
58 
59 #include "gralloc_cb.h"
60 
61 #ifdef VIRTIO_GPU
62 #include "VirtioGpuStream.h"
63 #endif
64 
65 #if PLATFORM_SDK_VERSION < 26
66 #include <cutils/log.h>
67 #else
68 #include <log/log.h>
69 #endif
70 
71 #define STREAM_BUFFER_SIZE  (4*1024*1024)
72 #define STREAM_PORT_NUM     22468
73 
74 enum HostConnectionType {
75     HOST_CONNECTION_TCP = 0,
76     HOST_CONNECTION_QEMU_PIPE = 1,
77     HOST_CONNECTION_VIRTIO_GPU = 2,
78 };
79 
80 class GoldfishGralloc : public Gralloc
81 {
82 public:
getHostHandle(native_handle_t const * handle)83     uint32_t getHostHandle(native_handle_t const* handle)
84     {
85         return ((cb_handle_t *)handle)->hostHandle;
86     }
87 
getFormat(native_handle_t const * handle)88     int getFormat(native_handle_t const* handle)
89     {
90         return ((cb_handle_t *)handle)->format;
91     }
92 };
93 
94 class GoldfishProcessPipe : public ProcessPipe
95 {
96 public:
processPipeInit(renderControl_encoder_context_t * rcEnc)97     bool processPipeInit(renderControl_encoder_context_t *rcEnc)
98     {
99         return ::processPipeInit(rcEnc);
100     }
101 };
102 
103 static GoldfishGralloc m_goldfishGralloc;
104 static GoldfishProcessPipe m_goldfishProcessPipe;
105 
HostConnection()106 HostConnection::HostConnection() :
107     m_stream(NULL),
108     m_glEnc(NULL),
109     m_gl2Enc(NULL),
110     m_vkEnc(NULL),
111     m_rcEnc(NULL),
112     m_checksumHelper(),
113     m_glExtensions(),
114     m_grallocOnly(true),
115     m_noHostError(false)
116 {
117 }
118 
~HostConnection()119 HostConnection::~HostConnection()
120 {
121     delete m_stream;
122     delete m_glEnc;
123     delete m_gl2Enc;
124     delete m_rcEnc;
125 }
126 
127 // static
connect(HostConnection * con)128 HostConnection* HostConnection::connect(HostConnection* con) {
129     if (!con) return con;
130 
131     const enum HostConnectionType connType = HOST_CONNECTION_VIRTIO_GPU;
132 
133     switch (connType) {
134         default:
135         case HOST_CONNECTION_QEMU_PIPE: {
136             QemuPipeStream *stream = new QemuPipeStream(STREAM_BUFFER_SIZE);
137             if (!stream) {
138                 ALOGE("Failed to create QemuPipeStream for host connection!!!\n");
139                 delete con;
140                 return NULL;
141             }
142             if (stream->connect() < 0) {
143                 ALOGE("Failed to connect to host (QemuPipeStream)!!!\n");
144                 delete stream;
145                 delete con;
146                 return NULL;
147             }
148             con->m_stream = stream;
149             con->m_grallocHelper = &m_goldfishGralloc;
150             con->m_processPipe = &m_goldfishProcessPipe;
151             break;
152         }
153         case HOST_CONNECTION_TCP: {
154             TcpStream *stream = new TcpStream(STREAM_BUFFER_SIZE);
155             if (!stream) {
156                 ALOGE("Failed to create TcpStream for host connection!!!\n");
157                 delete con;
158                 return NULL;
159             }
160 
161             if (stream->connect("10.0.2.2", STREAM_PORT_NUM) < 0) {
162                 ALOGE("Failed to connect to host (TcpStream)!!!\n");
163                 delete stream;
164                 delete con;
165                 return NULL;
166             }
167             con->m_stream = stream;
168             con->m_grallocHelper = &m_goldfishGralloc;
169             con->m_processPipe = &m_goldfishProcessPipe;
170             break;
171         }
172 #ifdef VIRTIO_GPU
173         case HOST_CONNECTION_VIRTIO_GPU: {
174             VirtioGpuStream *stream = new VirtioGpuStream(STREAM_BUFFER_SIZE);
175             if (!stream) {
176                 ALOGE("Failed to create VirtioGpu for host connection!!!\n");
177                 delete con;
178                 return NULL;
179             }
180             if (stream->connect() < 0) {
181                 ALOGE("Failed to connect to host (VirtioGpu)!!!\n");
182                 delete stream;
183                 delete con;
184                 return NULL;
185             }
186             con->m_stream = stream;
187             con->m_grallocHelper = stream->getGralloc();
188             con->m_processPipe = stream->getProcessPipe();
189             break;
190         }
191 #endif
192     }
193 
194     // send zero 'clientFlags' to the host.
195     unsigned int *pClientFlags =
196             (unsigned int *)con->m_stream->allocBuffer(sizeof(unsigned int));
197     *pClientFlags = 0;
198     con->m_stream->commitBuffer(sizeof(unsigned int));
199 
200     ALOGD("HostConnection::get() New Host Connection established %p, tid %d\n",
201           con, getCurrentThreadId());
202     return con;
203 }
204 
get()205 HostConnection *HostConnection::get() {
206     return getWithThreadInfo(getEGLThreadInfo());
207 }
208 
getWithThreadInfo(EGLThreadInfo * tinfo)209 HostConnection *HostConnection::getWithThreadInfo(EGLThreadInfo* tinfo) {
210 
211     /* TODO: Make this configurable with a system property */
212     const enum HostConnectionType connType = HOST_CONNECTION_VIRTIO_GPU;
213 
214     // Get thread info
215     if (!tinfo) {
216         return NULL;
217     }
218 
219     if (tinfo->hostConn == NULL) {
220         HostConnection *con = new HostConnection();
221         con = connect(con);
222 
223         tinfo->hostConn = con;
224     }
225 
226     return tinfo->hostConn;
227 }
228 
exit()229 void HostConnection::exit() {
230     EGLThreadInfo *tinfo = getEGLThreadInfo();
231     if (!tinfo) {
232         return;
233     }
234 
235     if (tinfo->hostConn) {
236         delete tinfo->hostConn;
237         tinfo->hostConn = NULL;
238     }
239 }
240 
241 // static
createUnique()242 HostConnection *HostConnection::createUnique() {
243     ALOGD("%s: call\n", __func__);
244     return connect(new HostConnection());
245 }
246 
247 // static
teardownUnique(HostConnection * con)248 void HostConnection::teardownUnique(HostConnection* con) {
249     delete con;
250 }
251 
glEncoder()252 GLEncoder *HostConnection::glEncoder()
253 {
254     if (!m_glEnc) {
255         m_glEnc = new GLEncoder(m_stream, checksumHelper());
256         DBG("HostConnection::glEncoder new encoder %p, tid %d",
257             m_glEnc, getCurrentThreadId());
258         m_glEnc->setContextAccessor(s_getGLContext);
259     }
260     return m_glEnc;
261 }
262 
gl2Encoder()263 GL2Encoder *HostConnection::gl2Encoder()
264 {
265     if (!m_gl2Enc) {
266         m_gl2Enc = new GL2Encoder(m_stream, checksumHelper());
267         DBG("HostConnection::gl2Encoder new encoder %p, tid %d",
268             m_gl2Enc, getCurrentThreadId());
269         m_gl2Enc->setContextAccessor(s_getGL2Context);
270         m_gl2Enc->setNoHostError(m_noHostError);
271     }
272     return m_gl2Enc;
273 }
274 
vkEncoder()275 VkEncoder *HostConnection::vkEncoder()
276 {
277     if (!m_vkEnc) {
278         m_vkEnc = new VkEncoder(m_stream);
279     }
280     return m_vkEnc;
281 }
282 
rcEncoder()283 ExtendedRCEncoderContext *HostConnection::rcEncoder()
284 {
285     if (!m_rcEnc) {
286         m_rcEnc = new ExtendedRCEncoderContext(m_stream, checksumHelper());
287         setChecksumHelper(m_rcEnc);
288         queryAndSetSyncImpl(m_rcEnc);
289         queryAndSetDmaImpl(m_rcEnc);
290         queryAndSetGLESMaxVersion(m_rcEnc);
291         queryAndSetNoErrorState(m_rcEnc);
292         queryAndSetHostCompositionImpl(m_rcEnc);
293         queryAndSetDirectMemSupport(m_rcEnc);
294         queryAndSetVulkanSupport(m_rcEnc);
295         if (m_processPipe) {
296             m_processPipe->processPipeInit(m_rcEnc);
297         }
298     }
299     return m_rcEnc;
300 }
301 
s_getGLContext()302 gl_client_context_t *HostConnection::s_getGLContext()
303 {
304     EGLThreadInfo *ti = getEGLThreadInfo();
305     if (ti->hostConn) {
306         return ti->hostConn->m_glEnc;
307     }
308     return NULL;
309 }
310 
s_getGL2Context()311 gl2_client_context_t *HostConnection::s_getGL2Context()
312 {
313     EGLThreadInfo *ti = getEGLThreadInfo();
314     if (ti->hostConn) {
315         return ti->hostConn->m_gl2Enc;
316     }
317     return NULL;
318 }
319 
queryGLExtensions(ExtendedRCEncoderContext * rcEnc)320 const std::string& HostConnection::queryGLExtensions(ExtendedRCEncoderContext *rcEnc) {
321     if (!m_glExtensions.empty()) {
322         return m_glExtensions;
323     }
324 
325     // Extensions strings are usually quite long, preallocate enough here.
326     std::string extensions_buffer(1023, '\0');
327 
328     // rcGetGLString() returns required size including the 0-terminator, so
329     // account it when passing/using the sizes.
330     int extensionSize = rcEnc->rcGetGLString(rcEnc, GL_EXTENSIONS,
331                                              &extensions_buffer[0],
332                                              extensions_buffer.size() + 1);
333     if (extensionSize < 0) {
334         extensions_buffer.resize(-extensionSize);
335         extensionSize = rcEnc->rcGetGLString(rcEnc, GL_EXTENSIONS,
336                                              &extensions_buffer[0],
337                                             -extensionSize + 1);
338     }
339 
340     if (extensionSize > 0) {
341         extensions_buffer.resize(extensionSize - 1);
342         m_glExtensions.swap(extensions_buffer);
343     }
344 
345     return m_glExtensions;
346 }
347 
queryAndSetHostCompositionImpl(ExtendedRCEncoderContext * rcEnc)348 void HostConnection::queryAndSetHostCompositionImpl(ExtendedRCEncoderContext *rcEnc) {
349     const std::string& glExtensions = queryGLExtensions(rcEnc);
350     ALOGD("HostComposition ext %s", glExtensions.c_str());
351     if (glExtensions.find(kHostCompositionV1) != std::string::npos) {
352         rcEnc->setHostComposition(HOST_COMPOSITION_V1);
353     }
354     else {
355         rcEnc->setHostComposition(HOST_COMPOSITION_NONE);
356     }
357 }
358 
setChecksumHelper(ExtendedRCEncoderContext * rcEnc)359 void HostConnection::setChecksumHelper(ExtendedRCEncoderContext *rcEnc) {
360     const std::string& glExtensions = queryGLExtensions(rcEnc);
361     // check the host supported version
362     uint32_t checksumVersion = 0;
363     const char* checksumPrefix = ChecksumCalculator::getMaxVersionStrPrefix();
364     const char* glProtocolStr = strstr(glExtensions.c_str(), checksumPrefix);
365     if (glProtocolStr) {
366         uint32_t maxVersion = ChecksumCalculator::getMaxVersion();
367         sscanf(glProtocolStr+strlen(checksumPrefix), "%d", &checksumVersion);
368         if (maxVersion < checksumVersion) {
369             checksumVersion = maxVersion;
370         }
371         // The ordering of the following two commands matters!
372         // Must tell the host first before setting it in the guest
373         rcEnc->rcSelectChecksumHelper(rcEnc, checksumVersion, 0);
374         m_checksumHelper.setVersion(checksumVersion);
375     }
376 }
377 
queryAndSetSyncImpl(ExtendedRCEncoderContext * rcEnc)378 void HostConnection::queryAndSetSyncImpl(ExtendedRCEncoderContext *rcEnc) {
379     const std::string& glExtensions = queryGLExtensions(rcEnc);
380 #if PLATFORM_SDK_VERSION <= 16 || (!defined(__i386__) && !defined(__x86_64__))
381     rcEnc->setSyncImpl(SYNC_IMPL_NONE);
382 #else
383     if (glExtensions.find(kRCNativeSyncV3) != std::string::npos) {
384         rcEnc->setSyncImpl(SYNC_IMPL_NATIVE_SYNC_V3);
385     } else if (glExtensions.find(kRCNativeSyncV2) != std::string::npos) {
386         rcEnc->setSyncImpl(SYNC_IMPL_NATIVE_SYNC_V2);
387     } else {
388         rcEnc->setSyncImpl(SYNC_IMPL_NONE);
389     }
390 #endif
391 }
392 
queryAndSetDmaImpl(ExtendedRCEncoderContext * rcEnc)393 void HostConnection::queryAndSetDmaImpl(ExtendedRCEncoderContext *rcEnc) {
394     std::string glExtensions = queryGLExtensions(rcEnc);
395 #if PLATFORM_SDK_VERSION <= 16 || (!defined(__i386__) && !defined(__x86_64__))
396     rcEnc->setDmaImpl(DMA_IMPL_NONE);
397 #else
398     if (glExtensions.find(kDmaExtStr_v1) != std::string::npos) {
399         rcEnc->setDmaImpl(DMA_IMPL_v1);
400     } else {
401         rcEnc->setDmaImpl(DMA_IMPL_NONE);
402     }
403 #endif
404 }
405 
queryAndSetGLESMaxVersion(ExtendedRCEncoderContext * rcEnc)406 void HostConnection::queryAndSetGLESMaxVersion(ExtendedRCEncoderContext* rcEnc) {
407     std::string glExtensions = queryGLExtensions(rcEnc);
408     if (glExtensions.find(kGLESMaxVersion_2) != std::string::npos) {
409         rcEnc->setGLESMaxVersion(GLES_MAX_VERSION_2);
410     } else if (glExtensions.find(kGLESMaxVersion_3_0) != std::string::npos) {
411         rcEnc->setGLESMaxVersion(GLES_MAX_VERSION_3_0);
412     } else if (glExtensions.find(kGLESMaxVersion_3_1) != std::string::npos) {
413         rcEnc->setGLESMaxVersion(GLES_MAX_VERSION_3_1);
414     } else if (glExtensions.find(kGLESMaxVersion_3_2) != std::string::npos) {
415         rcEnc->setGLESMaxVersion(GLES_MAX_VERSION_3_2);
416     } else {
417         ALOGW("Unrecognized GLES max version string in extensions: %s",
418               glExtensions.c_str());
419         rcEnc->setGLESMaxVersion(GLES_MAX_VERSION_2);
420     }
421 }
422 
queryAndSetNoErrorState(ExtendedRCEncoderContext * rcEnc)423 void HostConnection::queryAndSetNoErrorState(ExtendedRCEncoderContext* rcEnc) {
424     std::string glExtensions = queryGLExtensions(rcEnc);
425     if (glExtensions.find(kGLESNoHostError) != std::string::npos) {
426         m_noHostError = true;
427     }
428 }
429 
queryAndSetDirectMemSupport(ExtendedRCEncoderContext * rcEnc)430 void HostConnection::queryAndSetDirectMemSupport(ExtendedRCEncoderContext* rcEnc) {
431     std::string glExtensions = queryGLExtensions(rcEnc);
432     if (glExtensions.find(kGLDirectMem) != std::string::npos) {
433         rcEnc->featureInfo()->hasDirectMem = true;
434     }
435 }
436 
queryAndSetVulkanSupport(ExtendedRCEncoderContext * rcEnc)437 void HostConnection::queryAndSetVulkanSupport(ExtendedRCEncoderContext* rcEnc) {
438     std::string glExtensions = queryGLExtensions(rcEnc);
439     if (glExtensions.find(kVulkan) != std::string::npos) {
440         rcEnc->featureInfo()->hasVulkan = true;
441     }
442 }
443 
queryAndSetDeferredVulkanCommandsSupport(ExtendedRCEncoderContext * rcEnc)444 void HostConnection::queryAndSetDeferredVulkanCommandsSupport(ExtendedRCEncoderContext* rcEnc) {
445     std::string glExtensions = queryGLExtensions(rcEnc);
446     if (glExtensions.find(kDeferredVulkanCommands) != std::string::npos) {
447         rcEnc->featureInfo()->hasDeferredVulkanCommands = true;
448     }
449 }
450