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 "RenderThread.h"
17
18 #include "ChannelStream.h"
19 #include "FrameBuffer.h"
20 #include "ReadBuffer.h"
21 #include "RenderChannelImpl.h"
22 #include "RenderThreadInfo.h"
23 #include "RingStream.h"
24 #include "VkDecoderContext.h"
25 #include "aemu/base/HealthMonitor.h"
26 #include "aemu/base/Metrics.h"
27 #include "aemu/base/files/StreamSerializing.h"
28 #include "aemu/base/synchronization/Lock.h"
29 #include "aemu/base/synchronization/MessageChannel.h"
30 #include "aemu/base/system/System.h"
31 #include "apigen-codec-common/ChecksumCalculatorThreadInfo.h"
32 #include "host-common/feature_control.h"
33 #include "host-common/logging.h"
34 #include "vulkan/VkCommonOperations.h"
35
36 #if GFXSTREAM_ENABLE_HOST_GLES
37 #include "RenderControl.h"
38 #endif
39
40 #define EMUGL_DEBUG_LEVEL 0
41 #include "host-common/debug.h"
42
43 #ifndef _WIN32
44 #include <unistd.h>
45 #endif
46
47 #include <assert.h>
48 #include <string.h>
49
50 #include <unordered_map>
51
52 namespace gfxstream {
53
54 using android::base::AutoLock;
55 using android::base::EventHangMetadata;
56 using android::base::MessageChannel;
57 using emugl::GfxApiLogger;
58 using vk::VkDecoderContext;
59
60 struct RenderThread::SnapshotObjects {
61 RenderThreadInfo* threadInfo;
62 ChecksumCalculator* checksumCalc;
63 ChannelStream* channelStream;
64 RingStream* ringStream;
65 ReadBuffer* readBuffer;
66 };
67
getBenchmarkEnabledFromEnv()68 static bool getBenchmarkEnabledFromEnv() {
69 auto threadEnabled = android::base::getEnvironmentVariable("ANDROID_EMUGL_RENDERTHREAD_STATS");
70 if (threadEnabled == "1") return true;
71 return false;
72 }
73
74 // Start with a smaller buffer to not waste memory on a low-used render threads.
75 static constexpr int kStreamBufferSize = 128 * 1024;
76
77 // Requires this many threads on the system available to run unlimited.
78 static constexpr int kMinThreadsToRunUnlimited = 5;
79
80 // A thread run limiter that limits render threads to run one slice at a time.
81 static android::base::Lock sThreadRunLimiter;
82
RenderThread(RenderChannelImpl * channel,android::base::Stream * loadStream,uint32_t virtioGpuContextId)83 RenderThread::RenderThread(RenderChannelImpl* channel,
84 android::base::Stream* loadStream,
85 uint32_t virtioGpuContextId)
86 : android::base::Thread(android::base::ThreadFlags::MaskSignals, 2 * 1024 * 1024),
87 mChannel(channel),
88 mRunInLimitedMode(android::base::getCpuCoreCount() < kMinThreadsToRunUnlimited),
89 mContextId(virtioGpuContextId)
90 {
91 if (loadStream) {
92 const bool success = loadStream->getByte();
93 if (success) {
94 mStream.emplace(0);
95 android::base::loadStream(loadStream, &*mStream);
96 mState = SnapshotState::StartLoading;
97 } else {
98 mFinished.store(true, std::memory_order_relaxed);
99 }
100 }
101 }
102
RenderThread(struct asg_context context,android::base::Stream * loadStream,android::emulation::asg::ConsumerCallbacks callbacks,uint32_t contextId,uint32_t capsetId,std::optional<std::string> nameOpt)103 RenderThread::RenderThread(
104 struct asg_context context,
105 android::base::Stream* loadStream,
106 android::emulation::asg::ConsumerCallbacks callbacks,
107 uint32_t contextId, uint32_t capsetId,
108 std::optional<std::string> nameOpt)
109 : android::base::Thread(android::base::ThreadFlags::MaskSignals, 2 * 1024 * 1024,
110 std::move(nameOpt)),
111 mRingStream(
112 new RingStream(context, callbacks, kStreamBufferSize)),
113 mContextId(contextId), mCapsetId(capsetId) {
114 if (loadStream) {
115 const bool success = loadStream->getByte();
116 if (success) {
117 mStream.emplace(0);
118 android::base::loadStream(loadStream, &*mStream);
119 mState = SnapshotState::StartLoading;
120 } else {
121 mFinished.store(true, std::memory_order_relaxed);
122 }
123 }
124 }
125
126 // Note: the RenderThread destructor might be called from a different thread
127 // than from RenderThread::main() so thread specific cleanup likely belongs at
128 // the end of RenderThread::main().
129 RenderThread::~RenderThread() = default;
130
pausePreSnapshot()131 void RenderThread::pausePreSnapshot() {
132 AutoLock lock(mLock);
133 assert(mState == SnapshotState::Empty);
134 mStream.emplace();
135 mState = SnapshotState::StartSaving;
136 if (mRingStream) {
137 mRingStream->pausePreSnapshot();
138 // mCondVar.broadcastAndUnlock(&lock);
139 }
140 if (mChannel) {
141 mChannel->pausePreSnapshot();
142 mCondVar.broadcastAndUnlock(&lock);
143 }
144 }
145
resume(bool waitForSave)146 void RenderThread::resume(bool waitForSave) {
147 AutoLock lock(mLock);
148 // This function can be called for a thread from pre-snapshot loading
149 // state; it doesn't need to do anything.
150 if (mState == SnapshotState::Empty) {
151 return;
152 }
153 if (mRingStream) mRingStream->resume();
154 if (waitForSave) {
155 waitForSnapshotCompletion(&lock);
156 }
157 mNeedReloadProcessResources = true;
158 mStream.clear();
159 mState = SnapshotState::Empty;
160 if (mChannel) mChannel->resume();
161 if (mRingStream) mRingStream->resume();
162 mCondVar.broadcastAndUnlock(&lock);
163 }
164
save(android::base::Stream * stream)165 void RenderThread::save(android::base::Stream* stream) {
166 bool success;
167 {
168 AutoLock lock(mLock);
169 assert(mState == SnapshotState::StartSaving ||
170 mState == SnapshotState::InProgress ||
171 mState == SnapshotState::Finished);
172 waitForSnapshotCompletion(&lock);
173 success = mState == SnapshotState::Finished;
174 }
175
176 if (success) {
177 assert(mStream);
178 stream->putByte(1);
179 android::base::saveStream(stream, *mStream);
180 } else {
181 stream->putByte(0);
182 }
183 }
184
waitForSnapshotCompletion(AutoLock * lock)185 void RenderThread::waitForSnapshotCompletion(AutoLock* lock) {
186 while (mState != SnapshotState::Finished &&
187 !mFinished.load(std::memory_order_relaxed)) {
188 mCondVar.wait(lock);
189 }
190 }
191
192 template <class OpImpl>
snapshotOperation(AutoLock * lock,OpImpl && implFunc)193 void RenderThread::snapshotOperation(AutoLock* lock, OpImpl&& implFunc) {
194 assert(isPausedForSnapshotLocked());
195 mState = SnapshotState::InProgress;
196 mCondVar.broadcastAndUnlock(lock);
197
198 implFunc();
199
200 lock->lock();
201
202 mState = SnapshotState::Finished;
203 mCondVar.broadcast();
204
205 // Only return after we're allowed to proceed.
206 while (isPausedForSnapshotLocked()) {
207 mCondVar.wait(lock);
208 }
209 }
210
loadImpl(AutoLock * lock,const SnapshotObjects & objects)211 void RenderThread::loadImpl(AutoLock* lock, const SnapshotObjects& objects) {
212 snapshotOperation(lock, [this, &objects] {
213 objects.readBuffer->onLoad(&*mStream);
214 if (objects.channelStream) objects.channelStream->load(&*mStream);
215 if (objects.ringStream) objects.ringStream->load(&*mStream);
216 objects.checksumCalc->load(&*mStream);
217 objects.threadInfo->onLoad(&*mStream);
218 });
219 }
220
saveImpl(AutoLock * lock,const SnapshotObjects & objects)221 void RenderThread::saveImpl(AutoLock* lock, const SnapshotObjects& objects) {
222 snapshotOperation(lock, [this, &objects] {
223 objects.readBuffer->onSave(&*mStream);
224 if (objects.channelStream) objects.channelStream->save(&*mStream);
225 if (objects.ringStream) objects.ringStream->save(&*mStream);
226 objects.checksumCalc->save(&*mStream);
227 objects.threadInfo->onSave(&*mStream);
228 });
229 }
230
isPausedForSnapshotLocked() const231 bool RenderThread::isPausedForSnapshotLocked() const {
232 return mState != SnapshotState::Empty;
233 }
234
doSnapshotOperation(const SnapshotObjects & objects,SnapshotState state)235 bool RenderThread::doSnapshotOperation(const SnapshotObjects& objects,
236 SnapshotState state) {
237 AutoLock lock(mLock);
238 if (mState == state) {
239 switch (state) {
240 case SnapshotState::StartLoading:
241 loadImpl(&lock, objects);
242 return true;
243 case SnapshotState::StartSaving:
244 saveImpl(&lock, objects);
245 return true;
246 default:
247 return false;
248 }
249 }
250 return false;
251 }
252
setFinished()253 void RenderThread::setFinished() {
254 // Make sure it never happens that we wait forever for the thread to
255 // save to snapshot while it was not even going to.
256 AutoLock lock(mLock);
257 mFinished.store(true, std::memory_order_relaxed);
258 if (mState != SnapshotState::Empty) {
259 mCondVar.broadcastAndUnlock(&lock);
260 }
261 }
262
main()263 intptr_t RenderThread::main() {
264 if (mFinished.load(std::memory_order_relaxed)) {
265 ERR("Error: fail loading a RenderThread @%p", this);
266 return 0;
267 }
268
269 RenderThreadInfo tInfo;
270 ChecksumCalculatorThreadInfo tChecksumInfo;
271 ChecksumCalculator& checksumCalc = tChecksumInfo.get();
272 bool needRestoreFromSnapshot = false;
273
274 //
275 // initialize decoders
276 #if GFXSTREAM_ENABLE_HOST_GLES
277 if (!feature_is_enabled(kFeature_GuestUsesAngle)) {
278 tInfo.initGl();
279 }
280
281 initRenderControlContext(&tInfo.m_rcDec);
282 #endif
283
284 if (!mChannel && !mRingStream) {
285 GL_LOG("Exited a loader RenderThread @%p", this);
286 mFinished.store(true, std::memory_order_relaxed);
287 return 0;
288 }
289
290 ChannelStream stream(mChannel, RenderChannel::Buffer::kSmallSize);
291 IOStream* ioStream =
292 mChannel ? (IOStream*)&stream : (IOStream*)mRingStream.get();
293
294 ReadBuffer readBuf(kStreamBufferSize);
295 if (mRingStream) {
296 readBuf.setNeededFreeTailSize(0);
297 }
298
299 const SnapshotObjects snapshotObjects = {
300 &tInfo, &checksumCalc, &stream, mRingStream.get(), &readBuf,
301 };
302
303 // Framebuffer initialization is asynchronous, so we need to make sure
304 // it's completely initialized before running any GL commands.
305 FrameBuffer::waitUntilInitialized();
306 if (vk::getGlobalVkEmulation()) {
307 tInfo.m_vkInfo.emplace();
308 }
309
310 #if GFXSTREAM_ENABLE_HOST_MAGMA
311 tInfo.m_magmaInfo.emplace(mContextId);
312 #endif
313
314 // This is the only place where we try loading from snapshot.
315 // But the context bind / restoration will be delayed after receiving
316 // the first GL command.
317 if (doSnapshotOperation(snapshotObjects, SnapshotState::StartLoading)) {
318 GL_LOG("Loaded RenderThread @%p from snapshot", this);
319 needRestoreFromSnapshot = true;
320 } else {
321 // Not loading from a snapshot: continue regular startup, read
322 // the |flags|.
323 uint32_t flags = 0;
324 while (ioStream->read(&flags, sizeof(flags)) != sizeof(flags)) {
325 // Stream read may fail because of a pending snapshot.
326 if (!doSnapshotOperation(snapshotObjects, SnapshotState::StartSaving)) {
327 setFinished();
328 GL_LOG("Exited a RenderThread @%p early", this);
329 return 0;
330 }
331 }
332
333 // |flags| used to mean something, now they're not used.
334 (void)flags;
335 }
336
337 int stats_totalBytes = 0;
338 uint64_t stats_progressTimeUs = 0;
339 auto stats_t0 = android::base::getHighResTimeUs() / 1000;
340 bool benchmarkEnabled = getBenchmarkEnabledFromEnv();
341
342 //
343 // open dump file if RENDER_DUMP_DIR is defined
344 //
345 const char* dump_dir = getenv("RENDERER_DUMP_DIR");
346 FILE* dumpFP = nullptr;
347 if (dump_dir) {
348 // size_t bsize = strlen(dump_dir) + 32;
349 // char* fname = new char[bsize];
350 // snprintf(fname, bsize, "%s" PATH_SEP "stream_%p", dump_dir, this);
351 // dumpFP = android_fopen(fname, "wb");
352 // if (!dumpFP) {
353 // fprintf(stderr, "Warning: stream dump failed to open file %s\n",
354 // fname);
355 // }
356 // delete[] fname;
357 }
358
359 GfxApiLogger gfxLogger;
360 auto& metricsLogger = FrameBuffer::getFB()->getMetricsLogger();
361
362 const ProcessResources* processResources = nullptr;
363 bool anyProgress = false;
364 while (true) {
365 // Let's make sure we read enough data for at least some processing.
366 uint32_t packetSize;
367 if (readBuf.validData() >= 8) {
368 // We know that packet size is the second int32_t from the start.
369 packetSize = *(uint32_t*)(readBuf.buf() + 4);
370 if (!packetSize) {
371 // Emulator will get live-stuck here if packet size is read to be zero;
372 // crash right away so we can see these events.
373 // emugl::emugl_crash_reporter(
374 // "Guest should never send a size-0 GL packet\n");
375 }
376 } else {
377 // Read enough data to at least be able to get the packet size next
378 // time.
379 packetSize = 8;
380 }
381 if (!anyProgress) {
382 // If we didn't make any progress last time, then make sure we read at least one
383 // extra byte.
384 packetSize = std::max(packetSize, static_cast<uint32_t>(readBuf.validData() + 1));
385 }
386 int stat = 0;
387 if (packetSize > readBuf.validData()) {
388 stat = readBuf.getData(ioStream, packetSize);
389 if (stat <= 0) {
390 if (doSnapshotOperation(snapshotObjects, SnapshotState::StartSaving)) {
391 continue;
392 } else {
393 D("Warning: render thread could not read data from stream");
394 break;
395 }
396 } else if (needRestoreFromSnapshot) {
397 // If we're using RingStream that might load before FrameBuffer
398 // restores the contexts from the handles, so check again here.
399
400 tInfo.postLoadRefreshCurrentContextSurfacePtrs();
401 needRestoreFromSnapshot = false;
402 }
403 if (mNeedReloadProcessResources) {
404 processResources = nullptr;
405 mNeedReloadProcessResources = false;
406 }
407 }
408
409 DD("render thread read %i bytes, op %i, packet size %i",
410 readBuf.validData(), *(uint32_t*)readBuf.buf(),
411 *(uint32_t*)(readBuf.buf() + 4));
412
413 //
414 // log received bandwidth statistics
415 //
416 if (benchmarkEnabled) {
417 stats_totalBytes += readBuf.validData();
418 auto dt = android::base::getHighResTimeUs() / 1000 - stats_t0;
419 if (dt > 1000) {
420 float dts = (float)dt / 1000.0f;
421 printf("Used Bandwidth %5.3f MB/s, time in progress %f ms total %f ms\n", ((float)stats_totalBytes / dts) / (1024.0f*1024.0f),
422 stats_progressTimeUs / 1000.0f,
423 (float)dt);
424 readBuf.printStats();
425 stats_t0 = android::base::getHighResTimeUs() / 1000;
426 stats_progressTimeUs = 0;
427 stats_totalBytes = 0;
428 }
429 }
430
431 //
432 // dump stream to file if needed
433 //
434 if (dumpFP) {
435 int skip = readBuf.validData() - stat;
436 fwrite(readBuf.buf() + skip, 1, readBuf.validData() - skip, dumpFP);
437 fflush(dumpFP);
438 }
439
440 bool progress = false;
441 anyProgress = false;
442 do {
443 anyProgress |= progress;
444 std::unique_ptr<EventHangMetadata::HangAnnotations> renderThreadData =
445 std::make_unique<EventHangMetadata::HangAnnotations>();
446
447 const char* contextName = nullptr;
448 if (mNameOpt) {
449 contextName = (*mNameOpt).c_str();
450 }
451
452 auto* healthMonitor = FrameBuffer::getFB()->getHealthMonitor();
453 if (healthMonitor) {
454 if (contextName) {
455 renderThreadData->insert(
456 {{"renderthread_guest_process", contextName}});
457 }
458 if (readBuf.validData() >= 4) {
459 renderThreadData->insert(
460 {{"first_opcode", std::to_string(*(uint32_t*)readBuf.buf())},
461 {"buffer_length", std::to_string(readBuf.validData())}});
462 }
463 }
464 auto watchdog = WATCHDOG_BUILDER(healthMonitor, "RenderThread decode operation")
465 .setHangType(EventHangMetadata::HangType::kRenderThread)
466 .setAnnotations(std::move(renderThreadData))
467 .build();
468
469 #ifndef AEMU_BUILD
470 if (!tInfo.m_puid) {
471 tInfo.m_puid = mContextId;
472 }
473 #endif
474
475 if (!processResources && tInfo.m_puid) {
476 processResources = FrameBuffer::getFB()->getProcessResources(tInfo.m_puid);
477 }
478
479 progress = false;
480 size_t last;
481
482 //
483 // try to process some of the command buffer using the
484 // Vulkan decoder
485 //
486 // Note: It's risky to limit Vulkan decoding to one thread,
487 // so we do it outside the limiter
488 if (tInfo.m_vkInfo) {
489 tInfo.m_vkInfo->ctx_id = mContextId;
490 VkDecoderContext context = {
491 .processName = contextName,
492 .gfxApiLogger = &gfxLogger,
493 .healthMonitor = FrameBuffer::getFB()->getHealthMonitor(),
494 .metricsLogger = &metricsLogger,
495 };
496 last = tInfo.m_vkInfo->m_vkDec.decode(readBuf.buf(), readBuf.validData(), ioStream,
497 processResources, context);
498 if (last > 0) {
499 if (!processResources) {
500 ERR("Processed some Vulkan packets without process resources created. "
501 "That's problematic.");
502 }
503 readBuf.consume(last);
504 progress = true;
505 }
506 }
507
508 if (mRunInLimitedMode) {
509 sThreadRunLimiter.lock();
510 }
511
512 // try to process some of the command buffer using the GLESv1
513 // decoder
514 //
515 // DRIVER WORKAROUND:
516 // On Linux with NVIDIA GPU's at least, we need to avoid performing
517 // GLES ops while someone else holds the FrameBuffer write lock.
518 //
519 // To be more specific, on Linux with NVIDIA Quadro K2200 v361.xx,
520 // we get a segfault in the NVIDIA driver when glTexSubImage2D
521 // is called at the same time as glXMake(Context)Current.
522 //
523 // To fix, this driver workaround avoids calling
524 // any sort of GLES call when we are creating/destroying EGL
525 // contexts.
526 {
527 FrameBuffer::getFB()->lockContextStructureRead();
528 }
529
530 #if GFXSTREAM_ENABLE_HOST_GLES
531 if (tInfo.m_glInfo) {
532 {
533 last = tInfo.m_glInfo->m_glDec.decode(
534 readBuf.buf(), readBuf.validData(), ioStream, &checksumCalc);
535 if (last > 0) {
536 progress = true;
537 readBuf.consume(last);
538 }
539 }
540
541 //
542 // try to process some of the command buffer using the GLESv2
543 // decoder
544 //
545 {
546 last = tInfo.m_glInfo->m_gl2Dec.decode(readBuf.buf(), readBuf.validData(),
547 ioStream, &checksumCalc);
548
549 if (last > 0) {
550 progress = true;
551 readBuf.consume(last);
552 }
553 }
554 }
555 #endif
556
557 FrameBuffer::getFB()->unlockContextStructureRead();
558 //
559 // try to process some of the command buffer using the
560 // renderControl decoder
561 //
562 #if GFXSTREAM_ENABLE_HOST_GLES
563 {
564 last = tInfo.m_rcDec.decode(readBuf.buf(), readBuf.validData(),
565 ioStream, &checksumCalc);
566 if (last > 0) {
567 readBuf.consume(last);
568 progress = true;
569 }
570 }
571 #endif
572
573 //
574 // try to process some of the command buffer using the Magma
575 // decoder
576 //
577 #if GFXSTREAM_ENABLE_HOST_MAGMA
578 if (tInfo.m_magmaInfo && tInfo.m_magmaInfo->mMagmaDec)
579 {
580 last = tInfo.m_magmaInfo->mMagmaDec->decode(readBuf.buf(), readBuf.validData(),
581 ioStream, &checksumCalc);
582 if (last > 0) {
583 readBuf.consume(last);
584 progress = true;
585 }
586 }
587 #endif
588
589 if (mRunInLimitedMode) {
590 sThreadRunLimiter.unlock();
591 }
592
593 } while (progress);
594 }
595
596 if (dumpFP) {
597 fclose(dumpFP);
598 }
599
600 #if GFXSTREAM_ENABLE_HOST_GLES
601 if (tInfo.m_glInfo) {
602 FrameBuffer::getFB()->drainGlRenderThreadResources();
603 }
604 #endif
605
606 setFinished();
607
608 GL_LOG("Exited a RenderThread @%p", this);
609 return 0;
610 }
611
612 } // namespace gfxstream
613