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 "GoldfishAddressSpaceStream.h"
19 #include "VirtioGpuAddressSpaceStream.h"
20 #include "aemu/base/threads/AndroidThread.h"
21 #if defined(__ANDROID__)
22 #include "android-base/properties.h"
23 #endif
24 #include "renderControl_types.h"
25 
26 using gfxstream::guest::ChecksumCalculator;
27 using gfxstream::guest::IOStream;
28 
29 #ifdef GOLDFISH_NO_GL
30 struct gl_client_context_t {
31     int placeholder;
32 };
33 class GLEncoder : public gl_client_context_t {
34 public:
GLEncoder(IOStream *,ChecksumCalculator *)35     GLEncoder(IOStream*, ChecksumCalculator*) { }
setContextAccessor(gl_client_context_t * ())36     void setContextAccessor(gl_client_context_t *()) { }
37 };
38 struct gl2_client_context_t {
39     int placeholder;
40 };
41 class GL2Encoder : public gl2_client_context_t {
42 public:
GL2Encoder(IOStream *,ChecksumCalculator *)43     GL2Encoder(IOStream*, ChecksumCalculator*) { }
setContextAccessor(gl2_client_context_t * ())44     void setContextAccessor(gl2_client_context_t *()) { }
setNoHostError(bool)45     void setNoHostError(bool) { }
setDrawCallFlushInterval(uint32_t)46     void setDrawCallFlushInterval(uint32_t) { }
setHasAsyncUnmapBuffer(int)47     void setHasAsyncUnmapBuffer(int) { }
setHasSyncBufferData(int)48     void setHasSyncBufferData(int) { }
49 };
50 #else
51 #include "GLEncoder.h"
52 #include "GL2Encoder.h"
53 #endif
54 
55 #include "AddressSpaceStream.h"
56 #include <unistd.h>
57 
58 #include "ProcessPipe.h"
59 #include "QemuPipeStream.h"
60 #include "ThreadInfo.h"
61 
62 #include "VirtGpu.h"
63 #include "VirtioGpuPipeStream.h"
64 
65 #if defined(__linux__) || defined(__ANDROID__)
66 #include <fstream>
67 #include <string>
68 #include <unistd.h>
69 #endif
70 
71 #undef LOG_TAG
72 #define LOG_TAG "HostConnection"
73 #include <cutils/log.h>
74 
75 #define STREAM_BUFFER_SIZE  (4*1024*1024)
76 
77 constexpr const auto kEglProp = "ro.hardware.egl";
78 
getConnectionTypeFromProperty(enum VirtGpuCapset capset)79 static HostConnectionType getConnectionTypeFromProperty(enum VirtGpuCapset capset) {
80 #if defined(__Fuchsia__) || defined(LINUX_GUEST_BUILD)
81     return HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE;
82 #else
83     std::string transport;
84 
85 #if defined(__ANDROID__)
86     transport = android::base::GetProperty("ro.boot.hardware.gltransport", "");
87 #else
88     const char* transport_envvar = getenv("GFXSTREAM_TRANSPORT");
89     if (transport_envvar != nullptr) {
90         transport = std::string(transport_envvar);
91     }
92 #endif
93 
94     if (transport.empty()) {
95 #if defined(__ANDROID__)
96         return HOST_CONNECTION_QEMU_PIPE;
97 #else
98         return HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE;
99 #endif
100     }
101 
102     if (transport == "asg") {
103         return HOST_CONNECTION_ADDRESS_SPACE;
104     }
105     if (transport == "pipe") {
106         return HOST_CONNECTION_QEMU_PIPE;
107     }
108 
109     if (transport == "virtio-gpu-asg" || transport == "virtio-gpu-pipe") {
110         std::string egl;
111 #if defined(__ANDROID__)
112         egl = android::base::GetProperty(kEglProp, "");
113 #endif
114         // ANGLE doesn't work well without ASG, particularly if HostComposer uses a pipe
115         // transport and VK uses ASG.
116         if (capset == kCapsetGfxStreamVulkan || egl == "angle") {
117             return HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE;
118         } else {
119             return HOST_CONNECTION_VIRTIO_GPU_PIPE;
120         }
121     }
122 
123     return HOST_CONNECTION_QEMU_PIPE;
124 #endif
125 }
126 
getDrawCallFlushIntervalFromProperty()127 static uint32_t getDrawCallFlushIntervalFromProperty() {
128     constexpr uint32_t kDefaultValue = 800;
129     uint32_t value = kDefaultValue;
130 
131 #if defined(__ANDROID__)
132     value = android::base::GetUintProperty("ro.boot.qemu.gltransport.drawFlushInterval",
133                                            kDefaultValue);
134 #endif
135     return value;
136 }
137 
HostConnection()138 HostConnection::HostConnection() : m_checksumHelper(), m_noHostError(true), m_rendernodeFd(-1) {}
139 
~HostConnection()140 HostConnection::~HostConnection()
141 {
142     // round-trip to ensure that queued commands have been processed
143     // before process pipe closure is detected.
144     if (m_rcEnc) {
145         (void)m_rcEnc->rcGetRendererVersion(m_rcEnc.get());
146     }
147 
148     if (m_stream) {
149         m_stream->decRef();
150     }
151 }
152 
153 // static
connect(enum VirtGpuCapset capset)154 std::unique_ptr<HostConnection> HostConnection::connect(enum VirtGpuCapset capset) {
155     const enum HostConnectionType connType = getConnectionTypeFromProperty(capset);
156     uint32_t noRenderControlEnc = 0;
157 
158     // Use "new" to access a non-public constructor.
159     auto con = std::unique_ptr<HostConnection>(new HostConnection);
160     con->m_connectionType = connType;
161 
162     switch (connType) {
163         case HOST_CONNECTION_ADDRESS_SPACE: {
164 #if defined(__ANDROID__)
165             auto stream = createGoldfishAddressSpaceStream(STREAM_BUFFER_SIZE);
166             if (!stream) {
167                 ALOGE("Failed to create AddressSpaceStream for host connection\n");
168                 return nullptr;
169             }
170             con->m_stream = stream;
171 #else
172             ALOGE("Fatal: HOST_CONNECTION_ADDRESS_SPACE not supported on this host.");
173             abort();
174 #endif
175 
176             break;
177         }
178 #if !defined(__Fuchsia__)
179         case HOST_CONNECTION_QEMU_PIPE: {
180             auto stream = new QemuPipeStream(STREAM_BUFFER_SIZE);
181             if (!stream) {
182                 ALOGE("Failed to create QemuPipeStream for host connection\n");
183                 return nullptr;
184             }
185             if (stream->connect() < 0) {
186                 ALOGE("Failed to connect to host (QemuPipeStream)\n");
187                 return nullptr;
188             }
189             con->m_stream = stream;
190             break;
191         }
192 #endif
193         case HOST_CONNECTION_VIRTIO_GPU_PIPE: {
194             auto stream = new VirtioGpuPipeStream(STREAM_BUFFER_SIZE, INVALID_DESCRIPTOR);
195             if (!stream) {
196                 ALOGE("Failed to create VirtioGpu for host connection\n");
197                 return nullptr;
198             }
199             if (stream->connect() < 0) {
200                 ALOGE("Failed to connect to host (VirtioGpu)\n");
201                 return nullptr;
202             }
203 
204             auto rendernodeFd = stream->getRendernodeFd();
205             auto device = VirtGpuDevice::getInstance(capset);
206             con->m_stream = stream;
207             con->m_rendernodeFd = rendernodeFd;
208             break;
209         }
210         case HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE: {
211             // Use kCapsetGfxStreamVulkan for now, Ranchu HWC needs to be modified to pass in
212             // right capset.
213             auto device = VirtGpuDevice::getInstance(kCapsetGfxStreamVulkan);
214             auto deviceHandle = device->getDeviceHandle();
215             auto stream = createVirtioGpuAddressSpaceStream(kCapsetGfxStreamVulkan);
216             if (!stream) {
217                 ALOGE("Failed to create virtgpu AddressSpaceStream\n");
218                 return nullptr;
219             }
220             con->m_stream = stream;
221             con->m_rendernodeFd = deviceHandle;
222             break;
223         }
224         default:
225             break;
226     }
227 
228 #if defined(ANDROID)
229     con->m_grallocHelper.reset(gfxstream::createPlatformGralloc(con->m_rendernodeFd));
230     if (!con->m_grallocHelper) {
231         ALOGE("Failed to create platform Gralloc!");
232         abort();
233     }
234 
235     con->m_anwHelper.reset(gfxstream::createPlatformANativeWindowHelper());
236     if (!con->m_anwHelper) {
237         ALOGE("Failed to create platform ANativeWindowHelper!");
238         abort();
239     }
240 #endif
241 
242     con->m_syncHelper.reset(gfxstream::createPlatformSyncHelper());
243 
244     // send zero 'clientFlags' to the host.
245     unsigned int *pClientFlags =
246             (unsigned int *)con->m_stream->allocBuffer(sizeof(unsigned int));
247     *pClientFlags = 0;
248     con->m_stream->commitBuffer(sizeof(unsigned int));
249 
250     if (capset == kCapsetGfxStreamMagma) {
251         noRenderControlEnc = 1;
252     } else if (capset == kCapsetGfxStreamVulkan) {
253         VirtGpuDevice* instance = VirtGpuDevice::getInstance(kCapsetGfxStreamVulkan);
254         auto caps = instance->getCaps();
255         noRenderControlEnc = caps.vulkanCapset.noRenderControlEnc;
256     }
257 
258     auto handle = (connType == HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE) ? con->m_rendernodeFd : -1;
259     processPipeInit(handle, connType, noRenderControlEnc);
260     if (!noRenderControlEnc && capset == kCapsetGfxStreamVulkan) {
261         con->rcEncoder();
262     }
263 
264     return con;
265 }
266 
get()267 HostConnection* HostConnection::get() { return getWithThreadInfo(getEGLThreadInfo(), kCapsetNone); }
268 
getOrCreate(enum VirtGpuCapset capset)269 HostConnection* HostConnection::getOrCreate(enum VirtGpuCapset capset) {
270     return getWithThreadInfo(getEGLThreadInfo(), capset);
271 }
272 
getWithThreadInfo(EGLThreadInfo * tinfo,enum VirtGpuCapset capset)273 HostConnection* HostConnection::getWithThreadInfo(EGLThreadInfo* tinfo, enum VirtGpuCapset capset) {
274     // Get thread info
275     if (!tinfo) {
276         return NULL;
277     }
278 
279     if (tinfo->hostConn == NULL) {
280         tinfo->hostConn = HostConnection::createUnique(capset);
281     }
282 
283     return tinfo->hostConn.get();
284 }
285 
exit()286 void HostConnection::exit() {
287     EGLThreadInfo *tinfo = getEGLThreadInfo();
288     if (!tinfo) {
289         return;
290     }
291 
292 #if defined(ANDROID)
293     if (tinfo->hostConn) {
294         tinfo->hostConn->m_grallocHelper = nullptr;
295     }
296 #endif
297 
298     tinfo->hostConn.reset();
299 }
300 
301 // static
createUnique(enum VirtGpuCapset capset)302 std::unique_ptr<HostConnection> HostConnection::createUnique(enum VirtGpuCapset capset) {
303     return connect(capset);
304 }
305 
glEncoder()306 GLEncoder *HostConnection::glEncoder()
307 {
308     if (!m_glEnc) {
309         m_glEnc = std::make_unique<GLEncoder>(m_stream, &m_checksumHelper);
310         m_glEnc->setContextAccessor(s_getGLContext);
311     }
312     return m_glEnc.get();
313 }
314 
gl2Encoder()315 GL2Encoder *HostConnection::gl2Encoder()
316 {
317     if (!m_gl2Enc) {
318         m_gl2Enc = std::make_unique<GL2Encoder>(m_stream, &m_checksumHelper);
319         m_gl2Enc->setContextAccessor(s_getGL2Context);
320         m_gl2Enc->setNoHostError(m_noHostError);
321         m_gl2Enc->setDrawCallFlushInterval(
322             getDrawCallFlushIntervalFromProperty());
323         m_gl2Enc->setHasAsyncUnmapBuffer(m_rcEnc->hasAsyncUnmapBuffer());
324         m_gl2Enc->setHasSyncBufferData(m_rcEnc->hasSyncBufferData());
325     }
326     return m_gl2Enc.get();
327 }
328 
rcEncoder()329 ExtendedRCEncoderContext *HostConnection::rcEncoder()
330 {
331     if (!m_rcEnc) {
332         m_rcEnc = std::make_unique<ExtendedRCEncoderContext>(m_stream, &m_checksumHelper);
333 
334         ExtendedRCEncoderContext* rcEnc = m_rcEnc.get();
335         rcEnc->setChecksumHelper(&m_checksumHelper);
336         rcEnc->queryAndSetSyncImpl();
337         rcEnc->queryAndSetDmaImpl();
338         rcEnc->queryAndSetGLESMaxVersion();
339         rcEnc->queryAndSetNoErrorState(m_noHostError);
340         rcEnc->queryAndSetHostCompositionImpl();
341         rcEnc->queryAndSetDirectMemSupport();
342         rcEnc->queryAndSetVulkanSupport();
343         rcEnc->queryAndSetDeferredVulkanCommandsSupport();
344         rcEnc->queryAndSetVulkanNullOptionalStringsSupport();
345         rcEnc->queryAndSetVulkanCreateResourcesWithRequirementsSupport();
346         rcEnc->queryAndSetVulkanIgnoredHandles();
347         rcEnc->queryAndSetYUVCache();
348         rcEnc->queryAndSetAsyncUnmapBuffer();
349         rcEnc->queryAndSetVirtioGpuNext();
350         rcEnc->queryHasSharedSlotsHostMemoryAllocator();
351         rcEnc->queryAndSetVulkanFreeMemorySync();
352         rcEnc->queryAndSetVirtioGpuNativeSync();
353         rcEnc->queryAndSetVulkanShaderFloat16Int8Support();
354         rcEnc->queryAndSetVulkanAsyncQueueSubmitSupport();
355         rcEnc->queryAndSetHostSideTracingSupport();
356         rcEnc->queryAndSetAsyncFrameCommands();
357         rcEnc->queryAndSetVulkanQueueSubmitWithCommandsSupport();
358         rcEnc->queryAndSetVulkanBatchedDescriptorSetUpdateSupport();
359         rcEnc->queryAndSetSyncBufferData();
360         rcEnc->queryAndSetVulkanAsyncQsri();
361         rcEnc->queryAndSetReadColorBufferDma();
362         rcEnc->queryAndSetHWCMultiConfigs();
363         rcEnc->queryAndSetVulkanAuxCommandBufferMemory();
364         rcEnc->queryVersion();
365 
366         rcEnc->rcSetPuid(rcEnc, getPuid());
367     }
368     return m_rcEnc.get();
369 }
370 
s_getGLContext()371 gl_client_context_t *HostConnection::s_getGLContext()
372 {
373     EGLThreadInfo *ti = getEGLThreadInfo();
374     if (ti->hostConn) {
375         return ti->hostConn->m_glEnc.get();
376     }
377     return NULL;
378 }
379 
s_getGL2Context()380 gl2_client_context_t *HostConnection::s_getGL2Context()
381 {
382     EGLThreadInfo *ti = getEGLThreadInfo();
383     if (ti->hostConn) {
384         return ti->hostConn->m_gl2Enc.get();
385     }
386     return NULL;
387 }
388 
setVulkanFeatureInfo(void * info)389 void HostConnection::setVulkanFeatureInfo(void* info) {
390     ExtendedRCEncoderContext* rcEnc = m_rcEnc.get();
391     rcEnc->setVulkanFeatureInfo(info);
392 }
393