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