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