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