• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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