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