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