1 // Copyright (C) 2016 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include "RendererImpl.h"
15
16 #include "RenderChannelImpl.h"
17 #include "RenderThread.h"
18
19 #include "base/System.h"
20 #include "snapshot/common.h"
21 #include "host-common/logging.h"
22
23 #include "ErrorLog.h"
24 #include "FenceSync.h"
25 #include "FrameBuffer.h"
26
27 #include <algorithm>
28 #include <utility>
29
30 #include <assert.h>
31
32 namespace emugl {
33
34 // kUseSubwindowThread is used to determine whether the RenderWindow should use
35 // a separate thread to manage its subwindow GL/GLES context.
36 // For now, this feature is disabled entirely for the following
37 // reasons:
38 //
39 // - It must be disabled on Windows at all times, otherwise the main window
40 // becomes unresponsive after a few seconds of user interaction (e.g. trying
41 // to move it over the desktop). Probably due to the subtle issues around
42 // input on this platform (input-queue is global, message-queue is
43 // per-thread). Also, this messes considerably the display of the
44 // main window when running the executable under Wine.
45 //
46 // - On Linux/XGL and OSX/Cocoa, this used to be necessary to avoid corruption
47 // issues with the GL state of the main window when using the SDL UI.
48 // After the switch to Qt, this is no longer necessary and may actually cause
49 // undesired interactions between the UI thread and the RenderWindow thread:
50 // for example, in a multi-monitor setup the context might be recreated when
51 // dragging the window between monitors, triggering a Qt-specific callback
52 // in the context of RenderWindow thread, which will become blocked on the UI
53 // thread, which may in turn be blocked on something else.
54 static const bool kUseSubwindowThread = false;
55
56 // This object manages the cleanup of guest process resources when the process
57 // exits. It runs the cleanup in a separate thread to never block the main
58 // render thread for a low-priority task.
59 class RendererImpl::ProcessCleanupThread {
60 public:
ProcessCleanupThread()61 ProcessCleanupThread()
62 : mCleanupThread([this]() {
63 while (const auto id = mCleanupProcessIds.receive()) {
64 FrameBuffer::getFB()->cleanupProcGLObjects(*id);
65 }
66 }) {
67 mCleanupThread.start();
68 }
69
~ProcessCleanupThread()70 ~ProcessCleanupThread() {
71 mCleanupProcessIds.stop();
72 mCleanupThread.wait();
73 }
74
cleanup(uint64_t processId)75 void cleanup(uint64_t processId) {
76 mCleanupProcessIds.send(processId);
77 }
78
stop()79 void stop() {
80 mCleanupProcessIds.stop();
81 }
82
waitForCleanup()83 void waitForCleanup() {
84 mCleanupProcessIds.waitForEmpty();
85 }
86
87 private:
88 DISALLOW_COPY_AND_ASSIGN(ProcessCleanupThread);
89
90 android::base::MessageChannel<uint64_t, 64> mCleanupProcessIds;
91 android::base::FunctorThread mCleanupThread;
92 };
93
RendererImpl()94 RendererImpl::RendererImpl() {
95 mCleanupThread.reset(new ProcessCleanupThread());
96 }
97
~RendererImpl()98 RendererImpl::~RendererImpl() {
99 stop(true);
100 mRenderWindow.reset();
101 }
102
initialize(int width,int height,bool useSubWindow,bool egl2egl)103 bool RendererImpl::initialize(int width, int height, bool useSubWindow, bool egl2egl) {
104 if (android::base::getEnvironmentVariable("ANDROID_EMUGL_VERBOSE") == "1") {
105 // base_enable_verbose_logs();
106 }
107
108 if (mRenderWindow) {
109 return false;
110 }
111
112 std::unique_ptr<RenderWindow> renderWindow(new RenderWindow(
113 width, height, kUseSubwindowThread, useSubWindow, egl2egl));
114 if (!renderWindow) {
115 ERR("Could not create rendering window class\n");
116 GL_LOG("Could not create rendering window class");
117 return false;
118 }
119 if (!renderWindow->isValid()) {
120 ERR("Could not initialize emulated framebuffer\n");
121 return false;
122 }
123
124 mRenderWindow = std::move(renderWindow);
125 GL_LOG("OpenGL renderer initialized successfully");
126
127 // This render thread won't do anything but will only preload resources
128 // for the real threads to start faster.
129 mLoaderRenderThread.reset(new RenderThread(nullptr));
130 mLoaderRenderThread->start();
131
132 return true;
133 }
134
stop(bool wait)135 void RendererImpl::stop(bool wait) {
136 android::base::AutoLock lock(mChannelsLock);
137 mStopped = true;
138 auto channels = std::move(mChannels);
139 lock.unlock();
140
141 if (const auto fb = FrameBuffer::getFB()) {
142 fb->setShuttingDown();
143 }
144 for (const auto& c : channels) {
145 c->stopFromHost();
146 }
147 // We're stopping the renderer, so there's no need to clean up resources
148 // of some pending processes: we'll destroy everything soon.
149 mCleanupThread->stop();
150
151 mStoppedChannels.insert(mStoppedChannels.end(),
152 std::make_move_iterator(channels.begin()),
153 std::make_move_iterator(channels.end()));
154
155 if (!wait) {
156 return;
157 }
158
159 // Each render channel is referenced in the corresponing pipe object, so
160 // even if we clear the |channels| vector they could still be alive
161 // for a while. This means we need to make sure to wait for render thread
162 // exit explicitly.
163 for (const auto& c : mStoppedChannels) {
164 c->renderThread()->wait();
165 }
166 mStoppedChannels.clear();
167 }
168
finish()169 void RendererImpl::finish() {
170 {
171 android::base::AutoLock lock(mChannelsLock);
172 mRenderWindow->setPaused(true);
173 }
174 cleanupRenderThreads();
175 {
176 android::base::AutoLock lock(mChannelsLock);
177 mRenderWindow->setPaused(false);
178 }
179 }
180
cleanupRenderThreads()181 void RendererImpl::cleanupRenderThreads() {
182 android::base::AutoLock lock(mChannelsLock);
183 const auto channels = std::move(mChannels);
184 assert(mChannels.empty());
185 lock.unlock();
186 for (const auto& c : channels) {
187 // Please DO NOT notify the guest about this event (DO NOT call
188 // stopFromHost() ), because this is used to kill old threads when
189 // loading from a snapshot, and the newly loaded guest should not
190 // be notified for those behavior.
191 c->stop();
192 }
193 for (const auto& c : channels) {
194 c->renderThread()->wait();
195 }
196 }
197
waitForProcessCleanup()198 void RendererImpl::waitForProcessCleanup() {
199 mCleanupThread->waitForCleanup();
200 // Recreate it to make sure we've started from scratch and that we've
201 // finished all in-progress cleanups as well.
202 mCleanupThread.reset(new ProcessCleanupThread());
203 }
204
createRenderChannel(android::base::Stream * loadStream)205 RenderChannelPtr RendererImpl::createRenderChannel(
206 android::base::Stream* loadStream) {
207 const auto channel = std::make_shared<RenderChannelImpl>(loadStream);
208 {
209 android::base::AutoLock lock(mChannelsLock);
210
211 if (mStopped) {
212 return nullptr;
213 }
214
215 // Clean up the stopped channels.
216 mChannels.erase(
217 std::remove_if(mChannels.begin(), mChannels.end(),
218 [](const std::shared_ptr<RenderChannelImpl>& c) {
219 return c->renderThread()->isFinished();
220 }),
221 mChannels.end());
222 mChannels.emplace_back(channel);
223
224 // Take the time to check if our loader thread is done as well.
225 if (mLoaderRenderThread && mLoaderRenderThread->isFinished()) {
226 mLoaderRenderThread->wait();
227 mLoaderRenderThread.reset();
228 }
229
230 DBG("Started new RenderThread (total %" PRIu64 ") @%p\n",
231 static_cast<uint64_t>(mChannels.size()), channel->renderThread());
232 }
233
234 return channel;
235 }
236
addressSpaceGraphicsConsumerCreate(struct asg_context context,android::base::Stream * loadStream,android::emulation::asg::ConsumerCallbacks callbacks)237 void* RendererImpl::addressSpaceGraphicsConsumerCreate(
238 struct asg_context context,
239 android::base::Stream* loadStream,
240 android::emulation::asg::ConsumerCallbacks callbacks) {
241 auto thread = new RenderThread(context, loadStream, callbacks);
242 thread->start();
243 return (void*)thread;
244 }
245
addressSpaceGraphicsConsumerDestroy(void * consumer)246 void RendererImpl::addressSpaceGraphicsConsumerDestroy(void* consumer) {
247 RenderThread* thread = (RenderThread*)consumer;
248 thread->wait();
249 delete thread;
250 }
251
addressSpaceGraphicsConsumerPreSave(void * consumer)252 void RendererImpl::addressSpaceGraphicsConsumerPreSave(void* consumer) {
253 RenderThread* thread = (RenderThread*)consumer;
254 thread->pausePreSnapshot();
255 }
256
addressSpaceGraphicsConsumerSave(void * consumer,android::base::Stream * stream)257 void RendererImpl::addressSpaceGraphicsConsumerSave(void* consumer, android::base::Stream* stream) {
258 RenderThread* thread = (RenderThread*)consumer;
259 thread->save(stream);
260 }
261
addressSpaceGraphicsConsumerPostSave(void * consumer)262 void RendererImpl::addressSpaceGraphicsConsumerPostSave(void* consumer) {
263 RenderThread* thread = (RenderThread*)consumer;
264 thread->resume();
265 }
266
addressSpaceGraphicsConsumerRegisterPostLoadRenderThread(void * consumer)267 void RendererImpl::addressSpaceGraphicsConsumerRegisterPostLoadRenderThread(void* consumer) {
268 RenderThread* thread = (RenderThread*)consumer;
269 mAdditionalPostLoadRenderThreads.push_back(thread);
270 }
271
pauseAllPreSave()272 void RendererImpl::pauseAllPreSave() {
273 android::base::AutoLock lock(mChannelsLock);
274 if (mStopped) {
275 return;
276 }
277 for (const auto& c : mChannels) {
278 c->renderThread()->pausePreSnapshot();
279 }
280 lock.unlock();
281 waitForProcessCleanup();
282 }
283
resumeAll()284 void RendererImpl::resumeAll() {
285 {
286 android::base::AutoLock lock(mChannelsLock);
287 if (mStopped) {
288 return;
289 }
290 for (const auto& c : mChannels) {
291 c->renderThread()->resume();
292 }
293
294 for (const auto t: mAdditionalPostLoadRenderThreads) {
295 t->resume();
296 }
297 mAdditionalPostLoadRenderThreads.clear();
298 }
299
300 repaintOpenGLDisplay();
301 }
302
save(android::base::Stream * stream,const android::snapshot::ITextureSaverPtr & textureSaver)303 void RendererImpl::save(android::base::Stream* stream,
304 const android::snapshot::ITextureSaverPtr& textureSaver) {
305 stream->putByte(mStopped);
306 if (mStopped) {
307 return;
308 }
309 auto fb = FrameBuffer::getFB();
310 assert(fb);
311 fb->onSave(stream, textureSaver);
312
313 FenceSync::onSave(stream);
314 }
315
load(android::base::Stream * stream,const android::snapshot::ITextureLoaderPtr & textureLoader)316 bool RendererImpl::load(android::base::Stream* stream,
317 const android::snapshot::ITextureLoaderPtr& textureLoader) {
318
319 #ifdef SNAPSHOT_PROFILE
320 android::base::System::Duration startTime =
321 android::base::System::get()->getUnixTimeUs();
322 #endif
323 waitForProcessCleanup();
324 #ifdef SNAPSHOT_PROFILE
325 printf("Previous session cleanup time: %lld ms\n",
326 (long long)(android::base::System::get()
327 ->getUnixTimeUs() -
328 startTime) /
329 1000);
330 #endif
331
332 mStopped = stream->getByte();
333 if (mStopped) {
334 return true;
335 }
336 auto fb = FrameBuffer::getFB();
337 assert(fb);
338
339 bool res = true;
340
341 res = fb->onLoad(stream, textureLoader);
342 FenceSync::onLoad(stream);
343
344 return res;
345 }
346
fillGLESUsages(android_studio::EmulatorGLESUsages * usages)347 void RendererImpl::fillGLESUsages(android_studio::EmulatorGLESUsages* usages) {
348 auto fb = FrameBuffer::getFB();
349 if (fb) fb->fillGLESUsages(usages);
350 }
351
getScreenshot(unsigned int nChannels,unsigned int * width,unsigned int * height,std::vector<unsigned char> & pixels,int displayId,int desiredWidth,int desiredHeight,int desiredRotation)352 void RendererImpl::getScreenshot(unsigned int nChannels, unsigned int* width,
353 unsigned int* height, std::vector<unsigned char>& pixels, int displayId,
354 int desiredWidth, int desiredHeight, int desiredRotation) {
355 auto fb = FrameBuffer::getFB();
356 if (fb) fb->getScreenshot(nChannels, width, height, pixels, displayId,
357 desiredWidth, desiredHeight, desiredRotation);
358 }
359
setMultiDisplay(uint32_t id,int32_t x,int32_t y,uint32_t w,uint32_t h,uint32_t dpi,bool add)360 void RendererImpl::setMultiDisplay(uint32_t id,
361 int32_t x,
362 int32_t y,
363 uint32_t w,
364 uint32_t h,
365 uint32_t dpi,
366 bool add) {
367 auto fb = FrameBuffer::getFB();
368 if (fb) {
369 if (add) {
370 fb->createDisplay(&id);
371 fb->setDisplayPose(id, x, y, w, h, dpi);
372 } else {
373 fb->destroyDisplay(id);
374 }
375 }
376 }
377
setMultiDisplayColorBuffer(uint32_t id,uint32_t cb)378 void RendererImpl::setMultiDisplayColorBuffer(uint32_t id, uint32_t cb) {
379 auto fb = FrameBuffer::getFB();
380 if (fb) {
381 fb->setDisplayColorBuffer(id, cb);
382 }
383 }
384
getHardwareStrings()385 RendererImpl::HardwareStrings RendererImpl::getHardwareStrings() {
386 assert(mRenderWindow);
387
388 const char* vendor = nullptr;
389 const char* renderer = nullptr;
390 const char* version = nullptr;
391 if (!mRenderWindow->getHardwareStrings(&vendor, &renderer, &version)) {
392 return {};
393 }
394 HardwareStrings res;
395 res.vendor = vendor ? vendor : "";
396 res.renderer = renderer ? renderer : "";
397 res.version = version ? version : "";
398 return res;
399 }
400
setPostCallback(RendererImpl::OnPostCallback onPost,void * context,bool useBgraReadback,uint32_t displayId)401 void RendererImpl::setPostCallback(RendererImpl::OnPostCallback onPost,
402 void* context,
403 bool useBgraReadback,
404 uint32_t displayId) {
405 assert(mRenderWindow);
406 mRenderWindow->setPostCallback(onPost, context, displayId, useBgraReadback);
407 }
408
asyncReadbackSupported()409 bool RendererImpl::asyncReadbackSupported() {
410 assert(mRenderWindow);
411 return mRenderWindow->asyncReadbackSupported();
412 }
413
414 RendererImpl::ReadPixelsCallback
getReadPixelsCallback()415 RendererImpl::getReadPixelsCallback() {
416 assert(mRenderWindow);
417 return mRenderWindow->getReadPixelsCallback();
418 }
419
420 RendererImpl::FlushReadPixelPipeline
getFlushReadPixelPipeline()421 RendererImpl::getFlushReadPixelPipeline() {
422 assert(mRenderWindow);
423 return mRenderWindow->getFlushReadPixelPipeline();
424 }
425
showOpenGLSubwindow(FBNativeWindowType window,int wx,int wy,int ww,int wh,int fbw,int fbh,float dpr,float zRot,bool deleteExisting,bool hideWindow)426 bool RendererImpl::showOpenGLSubwindow(FBNativeWindowType window,
427 int wx,
428 int wy,
429 int ww,
430 int wh,
431 int fbw,
432 int fbh,
433 float dpr,
434 float zRot,
435 bool deleteExisting,
436 bool hideWindow) {
437 assert(mRenderWindow);
438 return mRenderWindow->setupSubWindow(window, wx, wy, ww, wh, fbw, fbh, dpr,
439 zRot, deleteExisting, hideWindow);
440 }
441
destroyOpenGLSubwindow()442 bool RendererImpl::destroyOpenGLSubwindow() {
443 assert(mRenderWindow);
444 return mRenderWindow->removeSubWindow();
445 }
446
setOpenGLDisplayRotation(float zRot)447 void RendererImpl::setOpenGLDisplayRotation(float zRot) {
448 assert(mRenderWindow);
449 mRenderWindow->setRotation(zRot);
450 }
451
setOpenGLDisplayTranslation(float px,float py)452 void RendererImpl::setOpenGLDisplayTranslation(float px, float py) {
453 assert(mRenderWindow);
454 mRenderWindow->setTranslation(px, py);
455 }
456
repaintOpenGLDisplay()457 void RendererImpl::repaintOpenGLDisplay() {
458 assert(mRenderWindow);
459 mRenderWindow->repaint();
460 }
461
hasGuestPostedAFrame()462 bool RendererImpl::hasGuestPostedAFrame() {
463 if (mRenderWindow) {
464 return mRenderWindow->hasGuestPostedAFrame();
465 }
466 return false;
467 }
468
resetGuestPostedAFrame()469 void RendererImpl::resetGuestPostedAFrame() {
470 if (mRenderWindow) {
471 mRenderWindow->resetGuestPostedAFrame();
472 }
473 }
474
setScreenMask(int width,int height,const unsigned char * rgbaData)475 void RendererImpl::setScreenMask(int width, int height, const unsigned char* rgbaData) {
476 assert(mRenderWindow);
477 mRenderWindow->setScreenMask(width, height, rgbaData);
478 }
479
cleanupProcGLObjects(uint64_t puid)480 void RendererImpl::cleanupProcGLObjects(uint64_t puid) {
481 mCleanupThread->cleanup(puid);
482 }
483
484 static struct AndroidVirtioGpuOps sVirtioGpuOps = {
485 .create_color_buffer_with_handle =
486 [](uint32_t width,
487 uint32_t height,
488 uint32_t format,
489 uint32_t fwkFormat,
__anona47589360302(uint32_t width, uint32_t height, uint32_t format, uint32_t fwkFormat, uint32_t handle) 490 uint32_t handle) {
491 FrameBuffer::getFB()->createColorBufferWithHandle(
492 width, height, (GLenum)format,
493 (FrameworkFormat)fwkFormat, handle);
494 },
495 .open_color_buffer =
__anona47589360402(uint32_t handle) 496 [](uint32_t handle) {
497 FrameBuffer::getFB()->openColorBuffer(handle);
498 },
499 .close_color_buffer =
__anona47589360502(uint32_t handle) 500 [](uint32_t handle) {
501 FrameBuffer::getFB()->closeColorBuffer(handle);
502 },
503 .update_color_buffer =
504 [](uint32_t handle,
505 int x,
506 int y,
507 int width,
508 int height,
509 uint32_t format,
510 uint32_t type,
__anona47589360602(uint32_t handle, int x, int y, int width, int height, uint32_t format, uint32_t type, void* pixels) 511 void* pixels) {
512 FrameBuffer::getFB()->updateColorBuffer(
513 handle, x, y, width, height, format, type, pixels);
514 },
515 .read_color_buffer =
516 [](uint32_t handle,
517 int x,
518 int y,
519 int width,
520 int height,
521 uint32_t format,
522 uint32_t type,
__anona47589360702(uint32_t handle, int x, int y, int width, int height, uint32_t format, uint32_t type, void* pixels) 523 void* pixels) {
524 FrameBuffer::getFB()->readColorBuffer(
525 handle, x, y, width, height, format, type, pixels);
526 },
527 .read_color_buffer_yuv =
528 [](uint32_t handle,
529 int x,
530 int y,
531 int width,
532 int height,
533 void* pixels,
__anona47589360802(uint32_t handle, int x, int y, int width, int height, void* pixels, uint32_t pixels_size) 534 uint32_t pixels_size) {
535 FrameBuffer::getFB()->readColorBufferYUV(
536 handle, x, y, width, height, pixels, pixels_size);
537 },
538 .post_color_buffer =
__anona47589360902(uint32_t handle) 539 [](uint32_t handle) { FrameBuffer::getFB()->post(handle); },
__anona47589360a02() 540 .repost = []() { FrameBuffer::getFB()->repost(); },
541 .create_yuv_textures =
542 [](uint32_t type,
543 uint32_t count,
544 int width,
545 int height,
__anona47589360b02(uint32_t type, uint32_t count, int width, int height, uint32_t* output) 546 uint32_t* output) {
547 FrameBuffer::getFB()->createYUVTextures(type, count, width,
548 height, output);
549 },
550 .destroy_yuv_textures =
__anona47589360c02(uint32_t type, uint32_t count, uint32_t* textures) 551 [](uint32_t type, uint32_t count, uint32_t* textures) {
552 FrameBuffer::getFB()->destroyYUVTextures(type, count,
553 textures);
554 },
555 .update_yuv_textures =
556 [](uint32_t type,
557 uint32_t* textures,
558 void* privData,
__anona47589360d02(uint32_t type, uint32_t* textures, void* privData, void* func) 559 void* func) {
560 FrameBuffer::getFB()->updateYUVTextures(type, textures,
561 privData, func);
562 },
563 .swap_textures_and_update_color_buffer =
564 [](uint32_t colorbufferhandle,
565 int x,
566 int y,
567 int width,
568 int height,
569 uint32_t format,
570 uint32_t type,
571 uint32_t texture_type,
__anona47589360e02(uint32_t colorbufferhandle, int x, int y, int width, int height, uint32_t format, uint32_t type, uint32_t texture_type, uint32_t* textures) 572 uint32_t* textures) {
573 FrameBuffer::getFB()->swapTexturesAndUpdateColorBuffer(
574 colorbufferhandle, x, y, width, height, format,
575 type, texture_type, textures);
576 },
__anona47589360f02() 577 .get_last_posted_color_buffer = []() {
578 return FrameBuffer::getFB()->getLastPostedColorBuffer();
579 },
__anona47589361002(uint32_t handle) 580 .bind_color_buffer_to_texture = [](uint32_t handle) {
581 FrameBuffer::getFB()->bindColorBufferToTexture2(handle);
582 },
__anona47589361102() 583 .get_global_egl_context = []() {
584 return FrameBuffer::getFB()->getGlobalEGLContext();
585 },
__anona47589361202(uint64_t eglsync) 586 .wait_for_gpu = [](uint64_t eglsync) {
587 FrameBuffer::getFB()->waitForGpu(eglsync);
588 },
__anona47589361302(uint64_t device, uint64_t fence) 589 .wait_for_gpu_vulkan = [](uint64_t device, uint64_t fence) {
590 FrameBuffer::getFB()->waitForGpuVulkan(device, fence);
591 },
__anona47589361402(bool guestManaged) 592 .set_guest_managed_color_buffer_lifetime = [](bool guestManaged) {
593 FrameBuffer::getFB()->setGuestManagedColorBufferLifetime(true);
594 },
595 };
596
getVirtioGpuOps()597 struct AndroidVirtioGpuOps* RendererImpl::getVirtioGpuOps() {
598 return &sVirtioGpuOps;
599 }
600
snapshotOperationCallback(int op,int stage)601 void RendererImpl::snapshotOperationCallback(int op, int stage) {
602 using namespace android::snapshot;
603 switch (op) {
604 case SNAPSHOTTER_OPERATION_LOAD:
605 if (stage == SNAPSHOTTER_STAGE_START) {
606 #ifdef SNAPSHOT_PROFILE
607 android::base::System::Duration startTime =
608 android::base::System::get()->getUnixTimeUs();
609 #endif
610 mRenderWindow->setPaused(true);
611 cleanupRenderThreads();
612 #ifdef SNAPSHOT_PROFILE
613 printf("Previous session suspend time: %lld ms\n",
614 (long long)(android::base::System::get()
615 ->getUnixTimeUs() -
616 startTime) /
617 1000);
618 #endif
619 }
620 if (stage == SNAPSHOTTER_STAGE_END) {
621 mRenderWindow->setPaused(false);
622 }
623 break;
624 default:
625 break;
626 }
627 }
628
629 } // namespace emugl
630