• 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/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