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