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