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