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