1 /*
2 * Copyright (C) 2011-2015 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
17 #include "FrameBuffer.h"
18
19 #include <iomanip>
20 #include <stdio.h>
21 #include <string.h>
22 #include <time.h>
23
24 #include "DispatchTables.h"
25 #include "GLESVersionDetector.h"
26 #include "NativeSubWindow.h"
27 #include "OpenGLESDispatch/EGLDispatch.h"
28 #include "RenderControl.h"
29 #include "RenderThreadInfo.h"
30 #include "YUVConverter.h"
31 #include "base/LayoutResolver.h"
32 #include "base/Lock.h"
33 #include "base/Lookup.h"
34 #include "base/MemoryTracker.h"
35 #include "base/SharedLibrary.h"
36 #include "base/StreamSerializing.h"
37 #include "base/System.h"
38 #include "base/Tracing.h"
39 #include "gles2_dec/gles2_dec.h"
40 #include "host-common/GfxstreamFatalError.h"
41 #include "host-common/crash_reporter.h"
42 #include "host-common/feature_control.h"
43 #include "host-common/logging.h"
44 #include "host-common/misc.h"
45 #include "host-common/vm_operations.h"
46 #include "vulkan/VkCommonOperations.h"
47 #include "vulkan/VkDecoderGlobalState.h"
48
49 using android::base::AutoLock;
50 using android::base::Stream;
51 using android::base::WorkerProcessingResult;
52 using emugl::ABORT_REASON_OTHER;
53 using emugl::FatalError;
54
55 namespace {
56
EglDebugCallback(EGLenum error,const char * command,EGLint messageType,EGLLabelKHR threadLabel,EGLLabelKHR objectLabel,const char * message)57 static void EGLAPIENTRY EglDebugCallback(EGLenum error,
58 const char *command,
59 EGLint messageType,
60 EGLLabelKHR threadLabel,
61 EGLLabelKHR objectLabel,
62 const char *message) {
63 GL_LOG("command:%s message:%s", command, message);
64 }
65
GlDebugCallback(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar * message,const void * userParam)66 static void GL_APIENTRY GlDebugCallback(GLenum source,
67 GLenum type,
68 GLuint id,
69 GLenum severity,
70 GLsizei length,
71 const GLchar *message,
72 const void *userParam) {
73 GL_LOG("message:%s", message);
74 }
75
76 // Helper class to call the bind_locked() / unbind_locked() properly.
77 typedef ColorBuffer::RecursiveScopedHelperContext ScopedBind;
78
79 // Implementation of a ColorBuffer::Helper instance that redirects calls
80 // to a FrameBuffer instance.
81 class ColorBufferHelper : public ColorBuffer::Helper {
82 public:
ColorBufferHelper(FrameBuffer * fb)83 ColorBufferHelper(FrameBuffer* fb) : mFb(fb) {}
84
setupContext()85 virtual bool setupContext() override {
86 mIsBound = mFb->bind_locked();
87 return mIsBound;
88 }
89
teardownContext()90 virtual void teardownContext() override {
91 mFb->unbind_locked();
92 mIsBound = false;
93 }
94
getTextureDraw() const95 virtual TextureDraw* getTextureDraw() const override {
96 return mFb->getTextureDraw();
97 }
98
isBound() const99 virtual bool isBound() const override { return mIsBound; }
100
101 private:
102 FrameBuffer* mFb;
103 bool mIsBound = false;
104 };
105
106 } // namespace
107
108 // static std::string getTimeStampString() {
109 // const time_t timestamp = android::base::getUnixTimeUs();
110 // const struct tm *timeinfo = localtime(×tamp);
111 // // Target format: 07-31 4:44:33
112 // char b[64];
113 // snprintf(
114 // b,
115 // sizeof(b) - 1,
116 // "%02u-%02u %02u:%02u:%02u",
117 // timeinfo->tm_mon + 1,
118 // timeinfo->tm_mday,
119 // timeinfo->tm_hour,
120 // timeinfo->tm_min,
121 // timeinfo->tm_sec);
122 // return std::string(b);
123 // }
124
125 // static unsigned int getUptimeMs() {
126 // return android::base::getUptimeMs();
127 // }
128
dumpPerfStats()129 static void dumpPerfStats() {
130 // auto usage = System::get()->getMemUsage();
131 // std::string memoryStats =
132 // emugl::getMemoryTracker()
133 // ? emugl::getMemoryTracker()->printUsage()
134 // : "";
135 // auto cpuUsage = emugl::getCpuUsage();
136 // std::string lastStats =
137 // cpuUsage ? cpuUsage->printUsage() : "";
138 // printf("%s Uptime: %u ms Resident memory: %f mb %s \n%s\n",
139 // getTimeStampString().c_str(), getUptimeMs(),
140 // (float)usage.resident / 1048576.0f, lastStats.c_str(),
141 // memoryStats.c_str());
142 }
143
144 class PerfStatThread : public android::base::Thread {
145 public:
PerfStatThread(bool * perfStatActive)146 PerfStatThread(bool* perfStatActive) :
147 Thread(), m_perfStatActive(perfStatActive) {}
148
main()149 virtual intptr_t main() {
150 while (*m_perfStatActive) {
151 sleepMs(1000);
152 dumpPerfStats();
153 }
154 return 0;
155 }
156
157 private:
158 bool* m_perfStatActive;
159 };
160
161 FrameBuffer* FrameBuffer::s_theFrameBuffer = NULL;
162 HandleType FrameBuffer::s_nextHandle = 0;
163
164 static const GLint gles2ContextAttribsESOrGLCompat[] =
165 { EGL_CONTEXT_CLIENT_VERSION, 2,
166 EGL_NONE };
167
168 static const GLint gles2ContextAttribsCoreGL[] =
169 { EGL_CONTEXT_CLIENT_VERSION, 2,
170 EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR,
171 EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR,
172 EGL_NONE };
173
174 static const GLint gles3ContextAttribsESOrGLCompat[] =
175 { EGL_CONTEXT_CLIENT_VERSION, 3,
176 EGL_NONE };
177
178 static const GLint gles3ContextAttribsCoreGL[] =
179 { EGL_CONTEXT_CLIENT_VERSION, 3,
180 EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR,
181 EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR,
182 EGL_NONE };
183
getGlesMaxContextAttribs()184 const GLint* getGlesMaxContextAttribs() {
185 int glesMaj, glesMin;
186 emugl::getGlesVersion(&glesMaj, &glesMin);
187 if (shouldEnableCoreProfile()) {
188 if (glesMaj == 2) {
189 return gles2ContextAttribsCoreGL;
190 } else {
191 return gles3ContextAttribsCoreGL;
192 }
193 }
194 if (glesMaj == 2) {
195 return gles2ContextAttribsESOrGLCompat;
196 } else {
197 return gles3ContextAttribsESOrGLCompat;
198 }
199 }
200
getGLES2ExtensionString(EGLDisplay p_dpy)201 static char* getGLES2ExtensionString(EGLDisplay p_dpy) {
202 EGLConfig config;
203 EGLSurface surface;
204
205 static const GLint configAttribs[] = {EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
206 EGL_RENDERABLE_TYPE,
207 EGL_OPENGL_ES2_BIT, EGL_NONE};
208
209 int n;
210 if (!s_egl.eglChooseConfig(p_dpy, configAttribs, &config, 1, &n) ||
211 n == 0) {
212 ERR("Could not find GLES 2.x config!");
213 return NULL;
214 }
215
216 static const EGLint pbufAttribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
217
218 surface = s_egl.eglCreatePbufferSurface(p_dpy, config, pbufAttribs);
219 if (surface == EGL_NO_SURFACE) {
220 ERR("Could not create GLES 2.x Pbuffer!");
221 return NULL;
222 }
223
224 EGLContext ctx = s_egl.eglCreateContext(p_dpy, config, EGL_NO_CONTEXT,
225 getGlesMaxContextAttribs());
226 if (ctx == EGL_NO_CONTEXT) {
227 ERR("Could not create GLES 2.x Context!");
228 s_egl.eglDestroySurface(p_dpy, surface);
229 return NULL;
230 }
231
232 if (!s_egl.eglMakeCurrent(p_dpy, surface, surface, ctx)) {
233 ERR("Could not make GLES 2.x context current!");
234 s_egl.eglDestroySurface(p_dpy, surface);
235 s_egl.eglDestroyContext(p_dpy, ctx);
236 return NULL;
237 }
238
239 // the string pointer may become invalid when the context is destroyed
240 const char* s = (const char*)s_gles2.glGetString(GL_EXTENSIONS);
241 char* extString = strdup(s ? s : "");
242
243 // It is rare but some drivers actually fail this...
244 if (!s_egl.eglMakeCurrent(p_dpy, NULL, NULL, NULL)) {
245 ERR("Could not unbind context. Please try updating graphics card driver!");
246 free(extString);
247 extString = NULL;
248 }
249 s_egl.eglDestroyContext(p_dpy, ctx);
250 s_egl.eglDestroySurface(p_dpy, surface);
251
252 return extString;
253 }
254
255 // A condition variable needed to wait for framebuffer initialization.
256 namespace {
257 struct InitializedGlobals {
258 android::base::Lock lock;
259 android::base::ConditionVariable condVar;
260 };
261 } // namespace
262
263 // |sInitialized| caches the initialized framebuffer state - this way
264 // happy path doesn't need to lock the mutex.
265 static std::atomic<bool> sInitialized{false};
sGlobals()266 static InitializedGlobals* sGlobals() {
267 static InitializedGlobals* g = new InitializedGlobals;
268 return g;
269 }
270
waitUntilInitialized()271 void FrameBuffer::waitUntilInitialized() {
272 if (sInitialized.load(std::memory_order_relaxed)) {
273 return;
274 }
275
276 #if SNAPSHOT_PROFILE > 1
277 const auto startTime = android::base::getHighResTimeUs();
278 #endif
279 {
280 AutoLock l(sGlobals()->lock);
281 sGlobals()->condVar.wait(
282 &l, [] { return sInitialized.load(std::memory_order_acquire); });
283 }
284 #if SNAPSHOT_PROFILE > 1
285 printf("Waited for FrameBuffer initialization for %.03f ms\n",
286 (android::base::getHighResTimeUs() - startTime) / 1000.0);
287 #endif
288 }
289
finalize()290 void FrameBuffer::finalize() {
291 AutoLock lock(sGlobals()->lock);
292 AutoLock fbLock(m_lock);
293 m_perfStats = false;
294 m_perfThread->wait(NULL);
295 sInitialized.store(true, std::memory_order_relaxed);
296 sGlobals()->condVar.broadcastAndUnlock(&lock);
297
298 for (auto it : m_platformEglContexts) {
299 destroySharedTrivialContext(it.second.context, it.second.surface);
300 }
301
302 if (m_shuttingDown) {
303 // The only visible thing in the framebuffer is subwindow. Everything else
304 // will get cleaned when the process exits.
305 if (m_useSubWindow) {
306 m_postWorker.reset();
307 removeSubWindow_locked();
308 }
309 return;
310 }
311
312 sweepColorBuffersLocked();
313
314 m_buffers.clear();
315 m_colorbuffers.clear();
316 m_colorBufferDelayedCloseList.clear();
317 if (m_useSubWindow) {
318 removeSubWindow_locked();
319 }
320 m_windows.clear();
321 m_contexts.clear();
322 if (m_eglDisplay != EGL_NO_DISPLAY) {
323 s_egl.eglMakeCurrent(m_eglDisplay, NULL, NULL, NULL);
324 if (m_eglContext != EGL_NO_CONTEXT) {
325 s_egl.eglDestroyContext(m_eglDisplay, m_eglContext);
326 m_eglContext = EGL_NO_CONTEXT;
327 }
328 if (m_pbufContext != EGL_NO_CONTEXT) {
329 s_egl.eglDestroyContext(m_eglDisplay, m_pbufContext);
330 m_pbufContext = EGL_NO_CONTEXT;
331 }
332 if (m_pbufSurface != EGL_NO_SURFACE) {
333 s_egl.eglDestroySurface(m_eglDisplay, m_pbufSurface);
334 m_pbufSurface = EGL_NO_SURFACE;
335 }
336 if (m_eglSurface != EGL_NO_SURFACE) {
337 s_egl.eglDestroySurface(m_eglDisplay, m_eglSurface);
338 m_eglSurface = EGL_NO_SURFACE;
339 }
340 m_eglDisplay = EGL_NO_DISPLAY;
341 }
342
343 m_readbackThread.enqueue({ReadbackCmd::Exit});
344 if (m_vkSurface != VK_NULL_HANDLE) {
345 emugl::vkDispatch(false /* not for testing */)
346 ->vkDestroySurfaceKHR(m_vkInstance, m_vkSurface, nullptr);
347 }
348 }
349
initialize(int width,int height,bool useSubWindow,bool egl2egl)350 bool FrameBuffer::initialize(int width, int height, bool useSubWindow,
351 bool egl2egl) {
352 GL_LOG("FrameBuffer::initialize");
353 if (s_theFrameBuffer != NULL) {
354 return true;
355 }
356
357 android::base::initializeTracing();
358
359 //
360 // allocate space for the FrameBuffer object
361 //
362 std::unique_ptr<FrameBuffer> fb(
363 new FrameBuffer(width, height, useSubWindow));
364 if (!fb) {
365 GL_LOG("Failed to create fb");
366 ERR("Failed to create fb\n");
367 return false;
368 }
369
370 std::unique_ptr<ScopedBind> eglColorBufferBind;
371
372 std::unique_ptr<emugl::RenderDocWithMultipleVkInstances> renderDocMultipleVkInstances = nullptr;
373 if (!android::base::getEnvironmentVariable("ANDROID_EMU_RENDERDOC").empty()) {
374 SharedLibrary* renderdocLib = nullptr;
375 #ifdef _WIN32
376 renderdocLib = SharedLibrary::open(R"(C:\Program Files\RenderDoc\renderdoc.dll)");
377 #elif defined(__linux__)
378 renderdocLib = SharedLibrary::open("librenderdoc.so");
379 #endif
380 fb->m_renderDoc = emugl::RenderDoc::create(renderdocLib);
381 if (fb->m_renderDoc) {
382 INFO("RenderDoc integration enabled.");
383 renderDocMultipleVkInstances =
384 std::make_unique<emugl::RenderDocWithMultipleVkInstances>(*fb->m_renderDoc);
385 if (!renderDocMultipleVkInstances) {
386 ERR("Failed to initialize RenderDoc with multiple VkInstances. Can't capture any "
387 "information from guest VkInstances with RenderDoc.");
388 }
389 }
390 }
391 // Initialize Vulkan emulation state
392 //
393 // Note: This must happen before any use of s_egl,
394 // or it's possible that the existing EGL display and contexts
395 // used by underlying EGL driver might become invalid,
396 // preventing new contexts from being created that share
397 // against those contexts.
398 goldfish_vk::VkEmulation* vkEmu = nullptr;
399 goldfish_vk::VulkanDispatch* vkDispatch = nullptr;
400 if (feature_is_enabled(kFeature_Vulkan)) {
401 vkDispatch = emugl::vkDispatch(false /* not for testing */);
402 vkEmu = goldfish_vk::createGlobalVkEmulation(vkDispatch);
403 if (!vkEmu) {
404 ERR("Failed to initialize global Vulkan emulation. Disable the Vulkan support.");
405 }
406 }
407 if (vkEmu) {
408 fb->m_vulkanEnabled = true;
409 if (feature_is_enabled(kFeature_VulkanNativeSwapchain)) {
410 fb->m_vkInstance = vkEmu->instance;
411 }
412 if (vkEmu->deviceInfo.supportsIdProperties) {
413 GL_LOG("Supports id properties, got a vulkan device UUID");
414 fprintf(stderr, "%s: Supports id properties, got a vulkan device UUID\n", __func__);
415 memcpy(fb->m_vulkanUUID, vkEmu->deviceInfo.idProps.deviceUUID, VK_UUID_SIZE);
416 } else {
417 GL_LOG("Doesn't support id properties, no vulkan device UUID");
418 fprintf(stderr, "%s: Doesn't support id properties, no vulkan device UUID\n", __func__);
419 }
420 }
421
422 if (s_egl.eglUseOsEglApi) {
423 auto useNullBackend = EGL_FALSE;
424 if (egl2egl && feature_is_enabled(kFeature_VulkanNativeSwapchain)) {
425 useNullBackend = EGL_TRUE;
426 }
427 s_egl.eglUseOsEglApi(egl2egl, useNullBackend);
428 }
429 //
430 // Initialize backend EGL display
431 //
432 fb->m_eglDisplay = s_egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
433 if (fb->m_eglDisplay == EGL_NO_DISPLAY) {
434 GL_LOG("Failed to Initialize backend EGL display");
435 ERR("Failed to Initialize backend EGL display\n");
436 return false;
437 }
438
439 GL_LOG("call eglInitialize");
440 if (!s_egl.eglInitialize(fb->m_eglDisplay, &fb->m_caps.eglMajor,
441 &fb->m_caps.eglMinor)) {
442 GL_LOG("Failed to eglInitialize");
443 ERR("Failed to eglInitialize\n");
444 return false;
445 }
446
447 GL_LOG("egl: %d %d", fb->m_caps.eglMajor, fb->m_caps.eglMinor);
448 s_egl.eglBindAPI(EGL_OPENGL_ES_API);
449
450
451 #ifdef ENABLE_GL_LOG
452 if (s_egl.eglDebugMessageControlKHR) {
453 const EGLAttrib controls[] = {
454 EGL_DEBUG_MSG_CRITICAL_KHR,
455 EGL_TRUE,
456 EGL_DEBUG_MSG_ERROR_KHR,
457 EGL_TRUE,
458 EGL_DEBUG_MSG_WARN_KHR,
459 EGL_TRUE,
460 EGL_DEBUG_MSG_INFO_KHR,
461 EGL_FALSE,
462 EGL_NONE,
463 EGL_NONE,
464 };
465
466 if (s_egl.eglDebugMessageControlKHR(&EglDebugCallback, controls) == EGL_SUCCESS) {
467 GL_LOG("Successfully set eglDebugMessageControlKHR");
468 } else {
469 GL_LOG("Failed to eglDebugMessageControlKHR");
470 }
471 } else {
472 GL_LOG("eglDebugMessageControlKHR not available");
473 }
474 #endif
475
476 GLESDispatchMaxVersion dispatchMaxVersion =
477 calcMaxVersionFromDispatch(fb->m_eglDisplay);
478
479 FrameBuffer::setMaxGLESVersion(dispatchMaxVersion);
480 if (s_egl.eglSetMaxGLESVersion) {
481 // eglSetMaxGLESVersion must be called before any context binding
482 // because it changes how we initialize the dispatcher table.
483 s_egl.eglSetMaxGLESVersion(dispatchMaxVersion);
484 }
485
486 int glesMaj, glesMin;
487 emugl::getGlesVersion(&glesMaj, &glesMin);
488
489 GL_LOG("gles version: %d %d\n", glesMaj, glesMin);
490
491 fb->m_asyncReadbackSupported = glesMaj > 2;
492 if (fb->m_asyncReadbackSupported) {
493 GL_LOG("Async readback supported");
494 } else {
495 GL_LOG("Async readback not supported");
496 }
497
498 // TODO (b/207426737): remove Imagination-specific workaround
499 auto vendor = s_egl.eglQueryString(fb->m_eglDisplay, EGL_VENDOR);
500 bool disable_fast_blit = (strcmp(vendor, "Imagination Technologies") == 0);
501
502 fb->m_fastBlitSupported =
503 (dispatchMaxVersion > GLES_DISPATCH_MAX_VERSION_2) &&
504 !disable_fast_blit &&
505 (emugl::getRenderer() == SELECTED_RENDERER_HOST ||
506 emugl::getRenderer() == SELECTED_RENDERER_SWIFTSHADER_INDIRECT ||
507 emugl::getRenderer() == SELECTED_RENDERER_ANGLE_INDIRECT);
508
509 fb->m_guestUsesAngle =
510 feature_is_enabled(
511 kFeature_GuestUsesAngle);
512
513 std::unique_ptr<goldfish_vk::VkEmulationFeatures> vkEmulationFeatures =
514 std::make_unique<goldfish_vk::VkEmulationFeatures>(goldfish_vk::VkEmulationFeatures{
515 .glInteropSupported = false, // Set later.
516 .deferredCommands =
517 android::base::getEnvironmentVariable("ANDROID_EMU_VK_DISABLE_DEFERRED_COMMANDS")
518 .empty(),
519 .createResourceWithRequirements =
520 android::base::getEnvironmentVariable(
521 "ANDROID_EMU_VK_DISABLE_USE_CREATE_RESOURCES_WITH_REQUIREMENTS")
522 .empty(),
523 .useVulkanNativeSwapchain = feature_is_enabled(kFeature_VulkanNativeSwapchain),
524 .guestRenderDoc = std::move(renderDocMultipleVkInstances),
525 });
526
527 //
528 // if GLES2 plugin has loaded - try to make GLES2 context and
529 // get GLES2 extension string
530 //
531 char* gles2Extensions = getGLES2ExtensionString(fb->m_eglDisplay);
532 if (!gles2Extensions) {
533 // Could not create GLES2 context - drop GL2 capability
534 ERR("Failed to obtain GLES 2.x extensions string!");
535 return false;
536 }
537
538 //
539 // Create EGL context for framebuffer post rendering.
540 //
541 GLint surfaceType = (useSubWindow ? EGL_WINDOW_BIT : 0) | EGL_PBUFFER_BIT;
542
543 // On Linux, we need RGB888 exactly, or eglMakeCurrent will fail,
544 // as glXMakeContextCurrent needs to match the format of the
545 // native pixmap.
546 EGLint wantedRedSize = 8;
547 EGLint wantedGreenSize = 8;
548 EGLint wantedBlueSize = 8;
549
550 const GLint configAttribs[] = {
551 EGL_RED_SIZE, wantedRedSize, EGL_GREEN_SIZE,
552 wantedGreenSize, EGL_BLUE_SIZE, wantedBlueSize,
553 EGL_SURFACE_TYPE, surfaceType, EGL_RENDERABLE_TYPE,
554 EGL_OPENGL_ES2_BIT, EGL_NONE};
555
556 EGLint total_num_configs = 0;
557 s_egl.eglGetConfigs(fb->m_eglDisplay, NULL, 0, &total_num_configs);
558
559 std::vector<EGLConfig> all_configs(total_num_configs);
560 EGLint total_egl_compatible_configs = 0;
561 s_egl.eglChooseConfig(fb->m_eglDisplay, configAttribs, &all_configs[0],
562 total_num_configs, &total_egl_compatible_configs);
563
564 EGLint exact_match_index = -1;
565 for (EGLint i = 0; i < total_egl_compatible_configs; i++) {
566 EGLint r, g, b;
567 EGLConfig c = all_configs[i];
568 s_egl.eglGetConfigAttrib(fb->m_eglDisplay, c, EGL_RED_SIZE, &r);
569 s_egl.eglGetConfigAttrib(fb->m_eglDisplay, c, EGL_GREEN_SIZE, &g);
570 s_egl.eglGetConfigAttrib(fb->m_eglDisplay, c, EGL_BLUE_SIZE, &b);
571
572 if (r == wantedRedSize && g == wantedGreenSize && b == wantedBlueSize) {
573 exact_match_index = i;
574 break;
575 }
576 }
577
578 if (exact_match_index < 0) {
579 GL_LOG("Failed on eglChooseConfig");
580 ERR("Failed on eglChooseConfig\n");
581 return false;
582 }
583
584 fb->m_eglConfig = all_configs[exact_match_index];
585
586 GL_LOG("attempting to create egl context");
587 fb->m_eglContext = s_egl.eglCreateContext(fb->m_eglDisplay, fb->m_eglConfig,
588 EGL_NO_CONTEXT, getGlesMaxContextAttribs());
589 if (fb->m_eglContext == EGL_NO_CONTEXT) {
590 ERR("Failed to create context 0x%x", s_egl.eglGetError());
591 return false;
592 }
593
594 GL_LOG("attempting to create egl pbuffer context");
595 //
596 // Create another context which shares with the eglContext to be used
597 // when we bind the pbuffer. That prevent switching drawable binding
598 // back and forth on framebuffer context.
599 // The main purpose of it is to solve a "blanking" behaviour we see on
600 // on Mac platform when switching binded drawable for a context however
601 // it is more efficient on other platforms as well.
602 //
603 fb->m_pbufContext =
604 s_egl.eglCreateContext(fb->m_eglDisplay, fb->m_eglConfig,
605 fb->m_eglContext, getGlesMaxContextAttribs());
606 if (fb->m_pbufContext == EGL_NO_CONTEXT) {
607 ERR("Failed to create Pbuffer Context 0x%x", s_egl.eglGetError());
608 return false;
609 }
610
611 GL_LOG("context creation successful");
612
613 //
614 // create a 1x1 pbuffer surface which will be used for binding
615 // the FB context.
616 // The FB output will go to a subwindow, if one exist.
617 //
618 static const EGLint pbufAttribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
619
620 fb->m_pbufSurface = s_egl.eglCreatePbufferSurface(
621 fb->m_eglDisplay, fb->m_eglConfig, pbufAttribs);
622 if (fb->m_pbufSurface == EGL_NO_SURFACE) {
623 ERR("Failed to create pbuf surface for FB 0x%x", s_egl.eglGetError());
624 return false;
625 }
626
627 GL_LOG("attempting to make context current");
628 // Make the context current
629 eglColorBufferBind = std::make_unique<ScopedBind>(fb->m_colorBufferHelper);
630 if (!eglColorBufferBind->isOk()) {
631 ERR("Failed to make current");
632 return false;
633 }
634 GL_LOG("context-current successful");
635
636 //
637 // Initilize framebuffer capabilities
638 //
639 const bool has_gl_oes_image =
640 emugl::hasExtension(gles2Extensions, "GL_OES_EGL_image");
641
642 fb->m_caps.has_eglimage_texture_2d = false;
643 fb->m_caps.has_eglimage_renderbuffer = false;
644 if (has_gl_oes_image) {
645 const char* const eglExtensions =
646 s_egl.eglQueryString(fb->m_eglDisplay, EGL_EXTENSIONS);
647 if (eglExtensions != nullptr) {
648 fb->m_caps.has_eglimage_texture_2d =
649 emugl::hasExtension(eglExtensions, "EGL_KHR_gl_texture_2D_image");
650 fb->m_caps.has_eglimage_renderbuffer =
651 emugl::hasExtension(eglExtensions, "EGL_KHR_gl_renderbuffer_image");
652 }
653 }
654
655 //
656 // Fail initialization if not all of the following extensions
657 // exist:
658 // EGL_KHR_gl_texture_2d_image
659 // GL_OES_EGL_IMAGE (by both GLES implementations [1 and 2])
660 //
661 if (!fb->m_caps.has_eglimage_texture_2d) {
662 ERR("Failed: Missing egl_image related extension(s)");
663 return false;
664 }
665
666 GL_LOG("host system has enough extensions");
667 //
668 // Initialize set of configs
669 //
670 fb->m_configs = new FbConfigList(fb->m_eglDisplay);
671 if (fb->m_configs->empty()) {
672 ERR("Failed: Initialize set of configs");
673 return false;
674 }
675
676 //
677 // Check that we have config for each GLES and GLES2
678 //
679 size_t nConfigs = fb->m_configs->size();
680 int nGLConfigs = 0;
681 int nGL2Configs = 0;
682 for (size_t i = 0; i < nConfigs; ++i) {
683 GLint rtype = fb->m_configs->get(i)->getRenderableType();
684 if (0 != (rtype & EGL_OPENGL_ES_BIT)) {
685 nGLConfigs++;
686 }
687 if (0 != (rtype & EGL_OPENGL_ES2_BIT)) {
688 nGL2Configs++;
689 }
690 }
691
692 //
693 // Don't fail initialization if no GLES configs exist
694 //
695
696 //
697 // If no configs at all, exit
698 //
699 if (nGLConfigs + nGL2Configs == 0) {
700 ERR("Failed: No GLES 2.x configs found!");
701 return false;
702 }
703
704 GL_LOG("There are sufficient EGLconfigs available");
705
706 #ifdef ENABLE_GL_LOG
707 bool debugSetup = false;
708 if (s_gles2.glDebugMessageCallback) {
709 s_gles2.glEnable(GL_DEBUG_OUTPUT);
710 s_gles2.glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
711 s_gles2.glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE,
712 GL_DEBUG_SEVERITY_HIGH, 0, nullptr, GL_TRUE);
713 s_gles2.glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE,
714 GL_DEBUG_SEVERITY_MEDIUM, 0, nullptr, GL_TRUE);
715 s_gles2.glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE,
716 GL_DEBUG_SEVERITY_LOW, 0, nullptr, GL_TRUE);
717 s_gles2.glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE,
718 GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr,
719 GL_TRUE);
720 s_gles2.glDebugMessageCallback(&GlDebugCallback, nullptr);
721 debugSetup = s_gles2.glGetError() == GL_NO_ERROR;
722 if (!debugSetup) {
723 ERR("Failed to set up glDebugMessageCallback");
724 } else {
725 GL_LOG("Successfully set up glDebugMessageCallback");
726 }
727 }
728 if (s_gles2.glDebugMessageCallbackKHR && !debugSetup) {
729 s_gles2.glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE,
730 GL_DEBUG_SEVERITY_HIGH_KHR, 0, nullptr,
731 GL_TRUE);
732 s_gles2.glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE,
733 GL_DEBUG_SEVERITY_MEDIUM_KHR, 0, nullptr,
734 GL_TRUE);
735 s_gles2.glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE,
736 GL_DEBUG_SEVERITY_LOW_KHR, 0, nullptr,
737 GL_TRUE);
738 s_gles2.glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE,
739 GL_DEBUG_SEVERITY_NOTIFICATION_KHR, 0, nullptr,
740 GL_TRUE);
741 s_gles2.glDebugMessageCallbackKHR(&GlDebugCallback, nullptr);
742 debugSetup = s_gles2.glGetError() == GL_NO_ERROR;
743 if (!debugSetup) {
744 ERR("Failed to set up glDebugMessageCallbackKHR");
745 } else {
746 GL_LOG("Successfully set up glDebugMessageCallbackKHR");
747 }
748 }
749 if (!debugSetup) {
750 GL_LOG("glDebugMessageCallback and glDebugMessageCallbackKHR not available");
751 }
752 #endif
753
754 //
755 // Cache the GL strings so we don't have to think about threading or
756 // current-context when asked for them.
757 //
758 bool useVulkanGraphicsDiagInfo =
759 vkEmu && feature_is_enabled(kFeature_VulkanNativeSwapchain) && fb->m_guestUsesAngle;
760
761 if (useVulkanGraphicsDiagInfo) {
762 fb->m_graphicsAdapterVendor = vkEmu->deviceInfo.driverVendor;
763 fb->m_graphicsAdapterName = vkEmu->deviceInfo.physdevProps.deviceName;
764
765 uint32_t vkVersion = vkEmu->vulkanInstanceVersion;
766
767 std::stringstream versionStringBuilder;
768 versionStringBuilder << "Vulkan " << VK_API_VERSION_MAJOR(vkVersion) << "."
769 << VK_API_VERSION_MINOR(vkVersion) << "."
770 << VK_API_VERSION_PATCH(vkVersion) << " "
771 << vkEmu->deviceInfo.driverVendor << " "
772 << vkEmu->deviceInfo.driverVersion;
773 fb->m_graphicsApiVersion = versionStringBuilder.str();
774
775 std::stringstream instanceExtensionsStringBuilder;
776 for (auto& ext : vkEmu->instanceExtensions) {
777 if (instanceExtensionsStringBuilder.tellp() != 0) {
778 instanceExtensionsStringBuilder << " ";
779 }
780 instanceExtensionsStringBuilder << ext.extensionName;
781 }
782
783 fb->m_graphicsApiExtensions = instanceExtensionsStringBuilder.str();
784
785 std::stringstream deviceExtensionsStringBuilder;
786 for (auto& ext : vkEmu->deviceInfo.extensions) {
787 if (deviceExtensionsStringBuilder.tellp() != 0) {
788 deviceExtensionsStringBuilder << " ";
789 }
790 deviceExtensionsStringBuilder << ext.extensionName;
791 }
792
793 fb->m_graphicsDeviceExtensions = deviceExtensionsStringBuilder.str();
794 } else {
795 fb->m_graphicsAdapterVendor = (const char*)s_gles2.glGetString(GL_VENDOR);
796 fb->m_graphicsAdapterName = (const char*)s_gles2.glGetString(GL_RENDERER);
797 fb->m_graphicsApiVersion = (const char*)s_gles2.glGetString(GL_VERSION);
798 fb->m_graphicsApiExtensions = (const char*)s_gles2.glGetString(GL_EXTENSIONS);
799 fb->m_graphicsDeviceExtensions = "N/A";
800 }
801
802 // Attempt to get the device UUID of the gles and match with Vulkan. If
803 // they match, interop is possible. If they don't, then don't trust the
804 // result of interop query to egl and fall back to CPU copy, as we might
805 // have initialized Vulkan devices and GLES contexts from different
806 // physical devices.
807
808 bool vkglesUuidsGood = true;
809
810 // First, if the VkEmulation instance doesn't support ext memory capabilities,
811 // it won't support uuids.
812 if (!vkEmu || !vkEmu->deviceInfo.supportsIdProperties) {
813 vkglesUuidsGood = false;
814 }
815
816 s_gles2.glGetError();
817
818 GLint numDeviceUuids = 0;
819 s_gles2.glGetIntegerv(GL_NUM_DEVICE_UUIDS_EXT, &numDeviceUuids);
820
821 // If underlying gles doesn't support UUID query, we definitely don't
822 // support interop and should not proceed further.
823
824 if (!numDeviceUuids || 1 != numDeviceUuids) {
825 // If numDeviceUuids != 1 it's unclear what gles we're using (SLI? Xinerama?)
826 // and we shouldn't try to interop.
827 vkglesUuidsGood = false;
828 }
829
830 if (vkglesUuidsGood && 1 == numDeviceUuids) {
831 s_gles2.glGetUnsignedBytei_vEXT(GL_DEVICE_UUID_EXT, 0, fb->m_glesUUID);
832 GL_LOG("Underlying gles supports UUID");
833 if (0 == memcmp(fb->m_vulkanUUID, fb->m_glesUUID, VK_UUID_SIZE)) {
834 GL_LOG("vk/gles UUIDs match");
835 } else {
836 GL_LOG("vk/gles UUIDs do not match");
837 vkglesUuidsGood = false;
838 }
839 }
840
841 fb->m_textureDraw = new TextureDraw();
842 if (!fb->m_textureDraw) {
843 ERR("Failed: creation of TextureDraw instance");
844 return false;
845 }
846
847 if (s_egl.eglQueryVulkanInteropSupportANDROID) {
848 fb->m_vulkanInteropSupported =
849 s_egl.eglQueryVulkanInteropSupportANDROID();
850 if (!vkglesUuidsGood) {
851 fb->m_vulkanInteropSupported = false;
852 }
853 }
854
855 GL_LOG("interop? %d", fb->m_vulkanInteropSupported);
856 // TODO: 0-copy gl interop on swiftshader vk
857 if (android::base::getEnvironmentVariable("ANDROID_EMU_VK_ICD") == "swiftshader") {
858 fb->m_vulkanInteropSupported = false;
859 GL_LOG("vk icd swiftshader, disable interop");
860 }
861
862 GL_LOG("glvk interop final: %d", fb->m_vulkanInteropSupported);
863 vkEmulationFeatures->glInteropSupported = fb->m_vulkanInteropSupported;
864 if (feature_is_enabled(kFeature_Vulkan)) {
865 goldfish_vk::initVkEmulationFeatures(std::move(vkEmulationFeatures));
866 if (vkEmu->displayVk) {
867 fb->m_displayVk = vkEmu->displayVk.get();
868 }
869 }
870
871 INFO("Graphics Adapter Vendor %s", fb->m_graphicsAdapterVendor.c_str());
872 INFO("Graphics Adapter %s", fb->m_graphicsAdapterName.c_str());
873 INFO("Graphics API Version %s", fb->m_graphicsApiVersion.c_str());
874 INFO("Graphics API Extensions %s", fb->m_graphicsApiExtensions.c_str());
875 INFO("Graphics Device Extensions %s", fb->m_graphicsDeviceExtensions.c_str());
876
877 // Start up the single sync thread. If we are using Vulkan native
878 // swapchain, then don't initialize SyncThread worker threads with EGL
879 // contexts.
880 SyncThread::initialize(/* noGL */ fb->m_displayVk != nullptr);
881
882 //
883 // Keep the singleton framebuffer pointer
884 //
885 s_theFrameBuffer = fb.release();
886 {
887 AutoLock lock(sGlobals()->lock);
888 sInitialized.store(true, std::memory_order_release);
889 sGlobals()->condVar.broadcastAndUnlock(&lock);
890 }
891
892 GL_LOG("basic EGL initialization successful");
893
894 // Nothing else to do - we're ready to rock!
895 return true;
896 }
897
importMemoryToColorBuffer(void * handle,uint64_t size,bool dedicated,bool vulkanOnly,uint32_t colorBufferHandle,VkImage image,const VkImageCreateInfo & imageCi)898 bool FrameBuffer::importMemoryToColorBuffer(
899 #ifdef _WIN32
900 void* handle,
901 #else
902 int handle,
903 #endif
904 uint64_t size, bool dedicated, bool vulkanOnly, uint32_t colorBufferHandle, VkImage image,
905 const VkImageCreateInfo& imageCi) {
906 AutoLock mutex(m_lock);
907
908 ColorBufferMap::iterator c(m_colorbuffers.find(colorBufferHandle));
909 if (c == m_colorbuffers.end()) {
910 // bad colorbuffer handle
911 ERR("FB: importMemoryToColorBuffer cb handle %#x not found", colorBufferHandle);
912 return false;
913 }
914
915 auto& cb = *c->second.cb;
916 std::shared_ptr<DisplayVk::DisplayBufferInfo> db = nullptr;
917 if (m_displayVk) {
918 db = m_displayVk->createDisplayBuffer(image, imageCi);
919 if (!db) {
920 ERR("Fail to create display buffer for ColorBuffer %" PRIu64 ".",
921 static_cast<uint64_t>(colorBufferHandle));
922 }
923 }
924 return cb.importMemory(handle, size, dedicated, imageCi.tiling == VK_IMAGE_TILING_LINEAR,
925 vulkanOnly, std::move(db));
926 }
927
setColorBufferInUse(uint32_t colorBufferHandle,bool inUse)928 void FrameBuffer::setColorBufferInUse(
929 uint32_t colorBufferHandle,
930 bool inUse) {
931
932 AutoLock mutex(m_lock);
933
934 ColorBufferMap::iterator c(m_colorbuffers.find(colorBufferHandle));
935 if (c == m_colorbuffers.end()) {
936 // bad colorbuffer handle
937 ERR("FB: setColorBufferInUse cb handle %#x not found", colorBufferHandle);
938 return;
939 }
940
941 (*c).second.cb->setInUse(inUse);
942 }
943
disableFastBlit()944 void FrameBuffer::disableFastBlit() {
945 m_fastBlitSupported = false;
946 }
947
fillGLESUsages(android_studio::EmulatorGLESUsages * usages)948 void FrameBuffer::fillGLESUsages(android_studio::EmulatorGLESUsages* usages) {
949 if (s_egl.eglFillUsages) {
950 s_egl.eglFillUsages(usages);
951 }
952 }
953
954 static GLESDispatchMaxVersion sMaxGLESVersion = GLES_DISPATCH_MAX_VERSION_2;
955
956 // static
setMaxGLESVersion(GLESDispatchMaxVersion version)957 void FrameBuffer::setMaxGLESVersion(GLESDispatchMaxVersion version) {
958 sMaxGLESVersion = version;
959 }
960
getMaxGLESVersion()961 GLESDispatchMaxVersion FrameBuffer::getMaxGLESVersion() {
962 return sMaxGLESVersion;
963 }
964
FrameBuffer(int p_width,int p_height,bool useSubWindow)965 FrameBuffer::FrameBuffer(int p_width, int p_height, bool useSubWindow)
966 : m_framebufferWidth(p_width),
967 m_framebufferHeight(p_height),
968 m_windowWidth(p_width),
969 m_windowHeight(p_height),
970 m_useSubWindow(useSubWindow),
971 m_fpsStats(getenv("SHOW_FPS_STATS") != nullptr),
972 m_perfStats(
973 !android::base::getEnvironmentVariable("SHOW_PERF_STATS").empty()),
974 m_perfThread(new PerfStatThread(&m_perfStats)),
975 m_colorBufferHelper(new ColorBufferHelper(this)),
976 m_readbackThread([this](FrameBuffer::Readback&& readback) {
977 return sendReadbackWorkerCmd(readback);
978 }),
979 m_refCountPipeEnabled(feature_is_enabled(
980 kFeature_RefCountPipe)),
981 m_noDelayCloseColorBufferEnabled(feature_is_enabled(
982 kFeature_NoDelayCloseColorBuffer)),
__anon169bbcf70502(Post&& post) 983 m_postThread([this](Post&& post) {
984 return postWorkerFunc(post);
985 }) {
986 uint32_t displayId = 0;
987 if (createDisplay(&displayId) < 0) {
988 fprintf(stderr, "Failed to create default display\n");
989 }
990
991 setDisplayPose(displayId, 0, 0, getWidth(), getHeight(), 0);
992 m_perfThread->start();
993
994 memset(m_vulkanUUID, 0x0, VK_UUID_SIZE);
995 memset(m_glesUUID, 0x0, GL_UUID_SIZE_EXT);
996 }
997
~FrameBuffer()998 FrameBuffer::~FrameBuffer() {
999 finalize();
1000
1001 if (m_postThread.isStarted()) {
1002 m_postThread.enqueue({ PostCmd::Exit, });
1003 }
1004
1005 delete m_textureDraw;
1006 delete m_configs;
1007 delete m_colorBufferHelper;
1008 delete m_perfThread;
1009
1010 if (s_theFrameBuffer) {
1011 s_theFrameBuffer = nullptr;
1012 }
1013 sInitialized.store(false, std::memory_order_relaxed);
1014
1015 m_readbackThread.join();
1016 m_postThread.join();
1017
1018 m_postWorker.reset();
1019 m_readbackWorker.reset();
1020
1021 goldfish_vk::teardownGlobalVkEmulation();
1022 SyncThread::destroy();
1023 }
1024
1025 WorkerProcessingResult
sendReadbackWorkerCmd(const Readback & readback)1026 FrameBuffer::sendReadbackWorkerCmd(const Readback& readback) {
1027 ensureReadbackWorker();
1028 switch (readback.cmd) {
1029 case ReadbackCmd::Init:
1030 m_readbackWorker->initGL();
1031 return WorkerProcessingResult::Continue;
1032 case ReadbackCmd::GetPixels:
1033 m_readbackWorker->getPixels(readback.displayId, readback.pixelsOut, readback.bytes);
1034 return WorkerProcessingResult::Continue;
1035 case ReadbackCmd::AddRecordDisplay:
1036 m_readbackWorker->setRecordDisplay(readback.displayId, readback.width, readback.height, true);
1037 return WorkerProcessingResult::Continue;
1038 case ReadbackCmd::DelRecordDisplay:
1039 m_readbackWorker->setRecordDisplay(readback.displayId, 0, 0, false);
1040 return WorkerProcessingResult::Continue;
1041 case ReadbackCmd::Exit:
1042 return WorkerProcessingResult::Stop;
1043 }
1044 return WorkerProcessingResult::Stop;
1045 }
1046
postWorkerFunc(Post & post)1047 WorkerProcessingResult FrameBuffer::postWorkerFunc(Post& post) {
1048 switch (post.cmd) {
1049 case PostCmd::Post:
1050 m_postWorker->post(post.cb);
1051 break;
1052 case PostCmd::Viewport:
1053 m_postWorker->viewport(post.viewport.width,
1054 post.viewport.height);
1055 break;
1056 case PostCmd::Compose: {
1057 std::shared_future<void> waitForGpu;
1058 if (post.composeVersion <= 1) {
1059 m_postWorker->compose((ComposeDevice*)post.composeBuffer.data(),
1060 post.composeBuffer.size(),
1061 std::move(post.composeCallback));
1062 } else {
1063 auto composeCallback = std::make_shared<Post::ComposeCallback>(
1064 [composeCallback =
1065 std::move(post.composeCallback)](std::shared_future<void> waitForGpu) {
1066 SyncThread::get()->triggerGeneral(
1067 [composeCallback = std::move(composeCallback), waitForGpu] {
1068 (*composeCallback)(waitForGpu);
1069 },
1070 "Wait for host composition");
1071 });
1072 m_postWorker->compose(
1073 (ComposeDevice_v2*)post.composeBuffer.data(),
1074 post.composeBuffer.size(), std::move(composeCallback));
1075 }
1076 break;
1077 }
1078 case PostCmd::Clear:
1079 m_postWorker->clear();
1080 break;
1081 case PostCmd::Screenshot:
1082 m_postWorker->screenshot(
1083 post.screenshot.cb,
1084 post.screenshot.screenwidth,
1085 post.screenshot.screenheight,
1086 post.screenshot.format,
1087 post.screenshot.type,
1088 post.screenshot.rotation,
1089 post.screenshot.pixels);
1090 break;
1091 case PostCmd::Exit:
1092 return WorkerProcessingResult::Stop;
1093 default:
1094 break;
1095 }
1096 return WorkerProcessingResult::Continue;
1097 }
1098
sendPostWorkerCmd(Post post)1099 std::future<void> FrameBuffer::sendPostWorkerCmd(Post post) {
1100 #ifdef __APPLE__
1101 bool postOnlyOnMainThread = m_subWin && (emugl::getRenderer() == SELECTED_RENDERER_HOST);
1102 #else
1103 bool postOnlyOnMainThread = false;
1104 #endif
1105
1106 if (!m_postThread.isStarted()) {
1107 if (postOnlyOnMainThread) {
1108 EGLContext prevContext = s_egl.eglGetCurrentContext();
1109 EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
1110 EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
1111 m_prevContext = prevContext;
1112 m_prevReadSurf = prevReadSurf;
1113 m_prevDrawSurf = prevDrawSurf;
1114 }
1115 m_postWorker.reset(new PostWorker(
1116 [this]() {
1117 if (m_displayVk) {
1118 if (m_vkSurface == VK_NULL_HANDLE) {
1119 return false;
1120 }
1121 INFO("Recreating swapchain...");
1122 m_displayVk->bindToSurface(m_vkSurface, static_cast<uint32_t>(m_windowWidth),
1123 static_cast<uint32_t>(m_windowHeight));
1124 INFO("Recreating swapchain completes.");
1125 return true;
1126 }
1127 if (m_subWin) {
1128 return bindSubwin_locked();
1129 } else {
1130 return bindFakeWindow_locked();
1131 }
1132 },
1133 postOnlyOnMainThread, m_eglContext, m_eglSurface, m_displayVk));
1134 m_postThread.start();
1135 }
1136
1137 // If we want to run only in the main thread and we are actually running
1138 // in the main thread already, don't use the PostWorker thread. Ideally,
1139 // PostWorker should handle this and dispatch directly, but we'll need to
1140 // transfer ownership of the thread to PostWorker.
1141 // TODO(lfy): do that refactor
1142 // For now, this fixes a screenshot issue on macOS.
1143 std::future<void> res = std::async(std::launch::deferred, [] {});
1144 res.wait();
1145 PostCmd postCmd = post.cmd;
1146 if (postOnlyOnMainThread && (PostCmd::Screenshot == post.cmd) &&
1147 emugl::get_emugl_window_operations().isRunningInUiThread()) {
1148 post.cb->readPixelsScaled(
1149 post.screenshot.screenwidth,
1150 post.screenshot.screenheight,
1151 post.screenshot.format,
1152 post.screenshot.type,
1153 post.screenshot.rotation,
1154 post.screenshot.pixels);
1155 } else {
1156 std::future<void> completeFuture =
1157 m_postThread.enqueue(Post(std::move(post)));
1158 if (!postOnlyOnMainThread ||
1159 (PostCmd::Screenshot == post.cmd &&
1160 !emugl::get_emugl_window_operations().isRunningInUiThread())) {
1161 res = std::move(completeFuture);
1162 }
1163 }
1164 return res;
1165 }
1166
setPostCallback(emugl::Renderer::OnPostCallback onPost,void * onPostContext,uint32_t displayId,bool useBgraReadback)1167 void FrameBuffer::setPostCallback(
1168 emugl::Renderer::OnPostCallback onPost,
1169 void* onPostContext,
1170 uint32_t displayId,
1171 bool useBgraReadback) {
1172 AutoLock lock(m_lock);
1173 if (onPost) {
1174 uint32_t w, h;
1175 if (!emugl::get_emugl_multi_display_operations().getMultiDisplay(displayId,
1176 nullptr,
1177 nullptr,
1178 &w, &h,
1179 nullptr,
1180 nullptr,
1181 nullptr)) {
1182 ERR("display %d not exist, cancelling OnPost callback", displayId);
1183 return;
1184 }
1185 if (m_onPost.find(displayId) != m_onPost.end()) {
1186 ERR("display %d already configured for recording", displayId);
1187 return;
1188 }
1189 m_onPost[displayId].cb = onPost;
1190 m_onPost[displayId].context = onPostContext;
1191 m_onPost[displayId].displayId = displayId;
1192 m_onPost[displayId].width = w;
1193 m_onPost[displayId].height = h;
1194 m_onPost[displayId].img = new unsigned char[4 * w * h];
1195 m_onPost[displayId].readBgra = useBgraReadback;
1196 if (!m_readbackThread.isStarted()) {
1197 m_readbackThread.start();
1198 m_readbackThread.enqueue({ ReadbackCmd::Init });
1199 }
1200 std::future<void> completeFuture = m_readbackThread.enqueue(
1201 {ReadbackCmd::AddRecordDisplay, displayId, 0, nullptr, 0, w, h});
1202 completeFuture.wait();
1203 } else {
1204 std::future<void> completeFuture = m_readbackThread.enqueue(
1205 {ReadbackCmd::DelRecordDisplay, displayId});
1206 completeFuture.wait();
1207 m_onPost.erase(displayId);
1208 }
1209 }
1210
subWindowRepaint(void * param)1211 static void subWindowRepaint(void* param) {
1212 GL_LOG("call repost from subWindowRepaint callback");
1213 auto fb = static_cast<FrameBuffer*>(param);
1214 fb->repost();
1215 }
1216
setupSubWindow(FBNativeWindowType p_window,int wx,int wy,int ww,int wh,int fbw,int fbh,float dpr,float zRot,bool deleteExisting,bool hideWindow)1217 bool FrameBuffer::setupSubWindow(FBNativeWindowType p_window,
1218 int wx,
1219 int wy,
1220 int ww,
1221 int wh,
1222 int fbw,
1223 int fbh,
1224 float dpr,
1225 float zRot,
1226 bool deleteExisting,
1227 bool hideWindow) {
1228 GL_LOG("Begin setupSubWindow");
1229 if (!m_useSubWindow) {
1230 ERR("%s: Cannot create native sub-window in this configuration\n",
1231 __FUNCTION__);
1232 return false;
1233 }
1234
1235 // Do a quick check before even taking the lock - maybe we don't need to
1236 // do anything here.
1237
1238 const bool createSubWindow = !m_subWin || deleteExisting;
1239
1240 // On Mac, since window coordinates are Y-up and not Y-down, the
1241 // subwindow may not change dimensions, but because the main window
1242 // did, the subwindow technically needs to be re-positioned. This
1243 // can happen on rotation, so a change in Z-rotation can be checked
1244 // for this case. However, this *should not* be done on Windows/Linux,
1245 // because the functions used to resize a native window on those hosts
1246 // will block if the shape doesn't actually change, freezing the
1247 // emulator.
1248 const bool moveSubWindow =
1249 !createSubWindow && !(m_x == wx && m_y == wy &&
1250 m_windowWidth == ww && m_windowHeight == wh
1251 #if defined(__APPLE__)
1252 && m_zRot == zRot
1253 #endif
1254 );
1255
1256 const bool redrawSubwindow =
1257 createSubWindow || moveSubWindow || m_zRot != zRot || m_dpr != dpr;
1258 if (!createSubWindow && !moveSubWindow && !redrawSubwindow) {
1259 assert(sInitialized.load(std::memory_order_relaxed));
1260 GL_LOG("Exit setupSubWindow (nothing to do)");
1261 #if SNAPSHOT_PROFILE > 1
1262 // printf("FrameBuffer::%s(): nothing to do at %lld ms\n", __func__,
1263 // (long long)System::get()->getProcessTimes().wallClockMs);
1264 #endif
1265 return true;
1266 }
1267
1268 #if SNAPSHOT_PROFILE > 1
1269 // printf("FrameBuffer::%s(%s): start at %lld ms\n", __func__,
1270 // deleteExisting ? "deleteExisting" : "keepExisting",
1271 // (long long)System::get()->getProcessTimes().wallClockMs);
1272 #endif
1273
1274 AutoLock mutex(m_lock);
1275
1276 #if SNAPSHOT_PROFILE > 1
1277 // printf("FrameBuffer::%s(): got lock at %lld ms\n", __func__,
1278 // (long long)System::get()->getProcessTimes().wallClockMs);
1279 #endif
1280
1281 if (deleteExisting) {
1282 // TODO: look into reusing the existing native window when possible.
1283 removeSubWindow_locked();
1284 }
1285
1286 bool success = false;
1287
1288 // If the subwindow doesn't exist, create it with the appropriate dimensions
1289 if (!m_subWin) {
1290 // Create native subwindow for FB display output
1291 m_x = wx;
1292 m_y = wy;
1293 m_windowWidth = ww;
1294 m_windowHeight = wh;
1295
1296 m_subWin = ::createSubWindow(p_window, m_x, m_y, m_windowWidth,
1297 m_windowHeight, subWindowRepaint, this,
1298 hideWindow);
1299 if (m_subWin) {
1300 m_nativeWindow = p_window;
1301
1302 if (m_displayVk != nullptr) {
1303 // create VkSurface from the generated subwindow, and bind to
1304 // the DisplayVk
1305 // TODO(kaiyili, b/179477624): add support for other platforms
1306 #ifdef _WIN32
1307 VkWin32SurfaceCreateInfoKHR surfaceCi = {};
1308 surfaceCi.sType =
1309 VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
1310 surfaceCi.hinstance = GetModuleHandle(nullptr);
1311 surfaceCi.hwnd = m_subWin;
1312 VK_CHECK(emugl::vkDispatch(false /* not for testing */)
1313 ->vkCreateWin32SurfaceKHR(m_vkInstance, &surfaceCi,
1314 nullptr, &m_vkSurface));
1315 #endif
1316 if (m_renderDoc) {
1317 m_renderDoc->call(emugl::RenderDoc::kSetActiveWindow,
1318 RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(m_vkInstance),
1319 reinterpret_cast<RENDERDOC_WindowHandle>(m_subWin));
1320 }
1321 } else {
1322 // create EGLSurface from the generated subwindow
1323 m_eglSurface = s_egl.eglCreateWindowSurface(
1324 m_eglDisplay, m_eglConfig, m_subWin, NULL);
1325
1326 if (m_eglSurface == EGL_NO_SURFACE) {
1327 // NOTE: This can typically happen with software-only renderers
1328 // like OSMesa.
1329 destroySubWindow(m_subWin);
1330 m_subWin = (EGLNativeWindowType)0;
1331 } else {
1332 m_px = 0;
1333 m_py = 0;
1334
1335 success = true;
1336 }
1337 }
1338 }
1339 }
1340
1341 // At this point, if the subwindow doesn't exist, it is because it either
1342 // couldn't be created
1343 // in the first place or the EGLSurface couldn't be created.
1344 if (m_subWin) {
1345 if (!moveSubWindow) {
1346 // Ensure that at least viewport parameters are properly updated.
1347 success = true;
1348 } else {
1349 // Only attempt to update window geometry if anything has actually
1350 // changed.
1351 m_x = wx;
1352 m_y = wy;
1353 m_windowWidth = ww;
1354 m_windowHeight = wh;
1355
1356 success = ::moveSubWindow(m_nativeWindow, m_subWin, m_x, m_y,
1357 m_windowWidth, m_windowHeight);
1358 }
1359
1360 if (success && redrawSubwindow) {
1361 // Subwin creation or movement was successful,
1362 // update viewport and z rotation and draw
1363 // the last posted color buffer.
1364 m_dpr = dpr;
1365 m_zRot = zRot;
1366 if (m_displayVk == nullptr) {
1367 Post postCmd;
1368 postCmd.cmd = PostCmd::Viewport;
1369 postCmd.viewport.width = fbw;
1370 postCmd.viewport.height = fbh;
1371 std::future<void> completeFuture =
1372 sendPostWorkerCmd(std::move(postCmd));
1373 completeFuture.wait();
1374
1375 bool posted = false;
1376
1377 if (m_lastPostedColorBuffer) {
1378 GL_LOG("setupSubwindow: draw last posted cb");
1379 posted = postImpl(m_lastPostedColorBuffer, false);
1380 }
1381
1382 if (!posted) {
1383 Post postCmd;
1384 postCmd.cmd = PostCmd::Clear;
1385 std::future<void> completeFuture =
1386 sendPostWorkerCmd(std::move(postCmd));
1387 completeFuture.wait();
1388 }
1389 }
1390 }
1391 }
1392
1393 if (success && redrawSubwindow) {
1394 bool bindSuccess = bind_locked();
1395 assert(bindSuccess);
1396 (void)bindSuccess;
1397 s_gles2.glViewport(0, 0, fbw * dpr, fbh * dpr);
1398 unbind_locked();
1399 }
1400 mutex.unlock();
1401
1402 // Nobody ever checks for the return code, so there will be no retries or
1403 // even aborted run; if we don't mark the framebuffer as initialized here
1404 // its users will hang forever; if we do mark it, they will crash - which
1405 // is a better outcome (crash report == bug fixed).
1406 AutoLock lock(sGlobals()->lock);
1407 sInitialized.store(true, std::memory_order_relaxed);
1408 sGlobals()->condVar.broadcastAndUnlock(&lock);
1409
1410 #if SNAPSHOT_PROFILE > 1
1411 // printf("FrameBuffer::%s(): end at %lld ms\n", __func__,
1412 // (long long)System::get()->getProcessTimes().wallClockMs);
1413 #endif
1414
1415 GL_LOG("Exit setupSubWindow (successful setup)");
1416 return success;
1417 }
1418
removeSubWindow()1419 bool FrameBuffer::removeSubWindow() {
1420 if (!m_useSubWindow) {
1421 ERR("Cannot remove native sub-window in this configuration");
1422 return false;
1423 }
1424 AutoLock lock(sGlobals()->lock);
1425 sInitialized.store(false, std::memory_order_relaxed);
1426 sGlobals()->condVar.broadcastAndUnlock(&lock);
1427
1428 AutoLock mutex(m_lock);
1429 return removeSubWindow_locked();
1430 }
1431
removeSubWindow_locked()1432 bool FrameBuffer::removeSubWindow_locked() {
1433 if (!m_useSubWindow) {
1434 ERR("Cannot remove native sub-window in this configuration");
1435 return false;
1436 }
1437 bool removed = false;
1438 if (m_subWin) {
1439 s_egl.eglMakeCurrent(m_eglDisplay, NULL, NULL, NULL);
1440 s_egl.eglDestroySurface(m_eglDisplay, m_eglSurface);
1441 destroySubWindow(m_subWin);
1442
1443 m_eglSurface = EGL_NO_SURFACE;
1444 m_subWin = (EGLNativeWindowType)0;
1445 removed = true;
1446 }
1447 return removed;
1448 }
1449
genHandle_locked()1450 HandleType FrameBuffer::genHandle_locked() {
1451 HandleType id;
1452 do {
1453 id = ++s_nextHandle;
1454 } while (id == 0 || m_contexts.find(id) != m_contexts.end() ||
1455 m_windows.find(id) != m_windows.end() ||
1456 m_colorbuffers.find(id) != m_colorbuffers.end() ||
1457 m_buffers.find(id) != m_buffers.end());
1458
1459 return id;
1460 }
1461
createColorBuffer(int p_width,int p_height,GLenum p_internalFormat,FrameworkFormat p_frameworkFormat)1462 HandleType FrameBuffer::createColorBuffer(int p_width,
1463 int p_height,
1464 GLenum p_internalFormat,
1465 FrameworkFormat p_frameworkFormat) {
1466
1467 AutoLock mutex(m_lock);
1468 return createColorBufferLocked(p_width, p_height, p_internalFormat,
1469 p_frameworkFormat);
1470 }
1471
createColorBufferWithHandle(int p_width,int p_height,GLenum p_internalFormat,FrameworkFormat p_frameworkFormat,HandleType handle)1472 void FrameBuffer::createColorBufferWithHandle(
1473 int p_width,
1474 int p_height,
1475 GLenum p_internalFormat,
1476 FrameworkFormat p_frameworkFormat,
1477 HandleType handle) {
1478
1479 HandleType resHandle;
1480 {
1481 AutoLock mutex(m_lock);
1482
1483 // Check for handle collision
1484 if (m_colorbuffers.count(handle) != 0) {
1485 // emugl::emugl_crash_reporter(
1486 // "FATAL: color buffer with handle %u already exists",
1487 // handle);
1488 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER));
1489 }
1490
1491 resHandle = createColorBufferWithHandleLocked(
1492 p_width, p_height, p_internalFormat, p_frameworkFormat,
1493 handle);
1494 }
1495
1496 if (m_displayVk && resHandle == handle) {
1497 goldfish_vk::setupVkColorBuffer(
1498 handle,
1499 false /* not vulkan only */,
1500 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT /* memory property */,
1501 nullptr /* exported */);
1502 }
1503 }
1504
createColorBufferLocked(int p_width,int p_height,GLenum p_internalFormat,FrameworkFormat p_frameworkFormat)1505 HandleType FrameBuffer::createColorBufferLocked(int p_width,
1506 int p_height,
1507 GLenum p_internalFormat,
1508 FrameworkFormat p_frameworkFormat) {
1509 sweepColorBuffersLocked();
1510
1511 return createColorBufferWithHandleLocked(
1512 p_width, p_height, p_internalFormat, p_frameworkFormat,
1513 genHandle_locked());
1514 }
1515
createColorBufferWithHandleLocked(int p_width,int p_height,GLenum p_internalFormat,FrameworkFormat p_frameworkFormat,HandleType handle)1516 HandleType FrameBuffer::createColorBufferWithHandleLocked(
1517 int p_width,
1518 int p_height,
1519 GLenum p_internalFormat,
1520 FrameworkFormat p_frameworkFormat,
1521 HandleType handle) {
1522
1523 sweepColorBuffersLocked();
1524
1525 ColorBufferPtr cb(ColorBuffer::create(getDisplay(), p_width, p_height,
1526 p_internalFormat, p_frameworkFormat,
1527 handle, m_colorBufferHelper,
1528 m_fastBlitSupported));
1529 if (cb.get() != NULL) {
1530 assert(m_colorbuffers.count(handle) == 0);
1531 // When guest feature flag RefCountPipe is on, no reference counting is
1532 // needed. We only memoize the mapping from handle to ColorBuffer.
1533 // Explicitly set refcount to 1 to avoid the colorbuffer being added to
1534 // m_colorBufferDelayedCloseList in FrameBuffer::onLoad().
1535 if (m_refCountPipeEnabled) {
1536 m_colorbuffers.try_emplace(
1537 handle, ColorBufferRef{std::move(cb), 1, false, 0});
1538 } else {
1539 // Android master default api level is 1000
1540 int apiLevel = 1000;
1541 emugl::getAvdInfo(nullptr, &apiLevel);
1542 // pre-O and post-O use different color buffer memory management
1543 // logic
1544 if (apiLevel > 0 && apiLevel < 26) {
1545 m_colorbuffers.try_emplace(
1546 handle,
1547 ColorBufferRef{std::move(cb), 1, false, 0});
1548
1549 RenderThreadInfo* tInfo = RenderThreadInfo::get();
1550 uint64_t puid = tInfo->m_puid;
1551 if (puid) {
1552 m_procOwnedColorBuffers[puid].insert(handle);
1553 }
1554
1555 } else {
1556 m_colorbuffers.try_emplace(
1557 handle,
1558 ColorBufferRef{std::move(cb), 0, false, 0});
1559 }
1560 }
1561 } else {
1562 handle = 0;
1563 ERR("Create color buffer failed.\n");
1564 }
1565 return handle;
1566 }
1567
createBuffer(uint64_t p_size,uint32_t memoryProperty)1568 HandleType FrameBuffer::createBuffer(uint64_t p_size, uint32_t memoryProperty) {
1569 AutoLock mutex(m_lock);
1570 HandleType handle = createBufferLocked(p_size);
1571 m_lock.unlock();
1572
1573 bool setupStatus =
1574 goldfish_vk::setupVkBuffer(handle, /* vulkanOnly */ true, memoryProperty);
1575 assert(setupStatus);
1576 return handle;
1577 }
1578
createBufferLocked(int p_size)1579 HandleType FrameBuffer::createBufferLocked(int p_size) {
1580 return createBufferWithHandleLocked(p_size, genHandle_locked());
1581 }
1582
createBufferWithHandleLocked(int p_size,HandleType handle)1583 HandleType FrameBuffer::createBufferWithHandleLocked(int p_size,
1584 HandleType handle) {
1585 if (m_colorbuffers.count(handle) != 0) {
1586 // emugl::emugl_crash_reporter(
1587 // "FATAL: color buffer with handle %u already exists", handle);
1588 // abort();
1589 }
1590
1591 if (m_buffers.count(handle) != 0) {
1592 // emugl::emugl_crash_reporter(
1593 // "FATAL: buffer with handle %u already exists", handle);
1594 // abort();
1595 }
1596
1597 BufferPtr buffer(Buffer::create(p_size, handle));
1598
1599 if (buffer) {
1600 m_buffers[handle] = {std::move(buffer)};
1601 } else {
1602 handle = 0;
1603 ERR("Create buffer failed.\n");
1604 }
1605 return handle;
1606 }
1607
createRenderContext(int p_config,HandleType p_share,GLESApi version)1608 HandleType FrameBuffer::createRenderContext(int p_config,
1609 HandleType p_share,
1610 GLESApi version) {
1611 AutoLock mutex(m_lock);
1612 android::base::AutoWriteLock contextLock(m_contextStructureLock);
1613 HandleType ret = 0;
1614
1615 const FbConfig* config = getConfigs()->get(p_config);
1616 if (!config) {
1617 return ret;
1618 }
1619
1620 RenderContextPtr share;
1621 if (p_share != 0) {
1622 RenderContextMap::iterator s(m_contexts.find(p_share));
1623 if (s == m_contexts.end()) {
1624 return ret;
1625 }
1626 share = (*s).second;
1627 }
1628 EGLContext sharedContext =
1629 share.get() ? share->getEGLContext() : EGL_NO_CONTEXT;
1630
1631 ret = genHandle_locked();
1632 RenderContextPtr rctx(RenderContext::create(
1633 m_eglDisplay, config->getEglConfig(), sharedContext, ret, version));
1634 if (rctx.get() != NULL) {
1635 m_contexts[ret] = rctx;
1636 RenderThreadInfo* tinfo = RenderThreadInfo::get();
1637 uint64_t puid = tinfo->m_puid;
1638 // The new emulator manages render contexts per guest process.
1639 // Fall back to per-thread management if the system image does not
1640 // support it.
1641 if (puid) {
1642 m_procOwnedRenderContext[puid].insert(ret);
1643 } else { // legacy path to manage context lifetime by threads
1644 tinfo->m_contextSet.insert(ret);
1645 }
1646 } else {
1647 ret = 0;
1648 }
1649
1650 return ret;
1651 }
1652
createWindowSurface(int p_config,int p_width,int p_height)1653 HandleType FrameBuffer::createWindowSurface(int p_config,
1654 int p_width,
1655 int p_height) {
1656 AutoLock mutex(m_lock);
1657
1658 HandleType ret = 0;
1659
1660 const FbConfig* config = getConfigs()->get(p_config);
1661 if (!config) {
1662 return ret;
1663 }
1664
1665 ret = genHandle_locked();
1666 WindowSurfacePtr win(WindowSurface::create(
1667 getDisplay(), config->getEglConfig(), p_width, p_height, ret));
1668 if (win.get() != NULL) {
1669 m_windows[ret] = { win, 0 };
1670 RenderThreadInfo* tInfo = RenderThreadInfo::get();
1671 uint64_t puid = tInfo->m_puid;
1672 if (puid) {
1673 m_procOwnedWindowSurfaces[puid].insert(ret);
1674 } else { // legacy path to manage window surface lifetime by threads
1675 tInfo->m_windowSet.insert(ret);
1676 }
1677 }
1678
1679 return ret;
1680 }
1681
drainRenderContext()1682 void FrameBuffer::drainRenderContext() {
1683 if (m_shuttingDown) {
1684 return;
1685 }
1686
1687 RenderThreadInfo* const tinfo = RenderThreadInfo::get();
1688 if (tinfo->m_contextSet.empty()) {
1689 return;
1690 }
1691
1692 AutoLock mutex(m_lock);
1693 android::base::AutoWriteLock contextLock(m_contextStructureLock);
1694 for (const HandleType contextHandle : tinfo->m_contextSet) {
1695 m_contexts.erase(contextHandle);
1696 }
1697 tinfo->m_contextSet.clear();
1698 }
1699
drainWindowSurface()1700 void FrameBuffer::drainWindowSurface() {
1701 if (m_shuttingDown) {
1702 return;
1703 }
1704 RenderThreadInfo* const tinfo = RenderThreadInfo::get();
1705 if (tinfo->m_windowSet.empty()) {
1706 return;
1707 }
1708
1709 std::vector<HandleType> colorBuffersToCleanup;
1710
1711 AutoLock mutex(m_lock);
1712 ScopedBind bind(m_colorBufferHelper);
1713 for (const HandleType winHandle : tinfo->m_windowSet) {
1714 const auto winIt = m_windows.find(winHandle);
1715 if (winIt != m_windows.end()) {
1716 if (const HandleType oldColorBufferHandle = winIt->second.second) {
1717 if (!m_guestManagedColorBufferLifetime) {
1718 if (m_refCountPipeEnabled) {
1719 if (decColorBufferRefCountLocked(oldColorBufferHandle)) {
1720 colorBuffersToCleanup.push_back(oldColorBufferHandle);
1721 }
1722 } else {
1723 if (closeColorBufferLocked(oldColorBufferHandle)) {
1724 colorBuffersToCleanup.push_back(oldColorBufferHandle);
1725 }
1726 }
1727 }
1728 m_windows.erase(winIt);
1729 }
1730 }
1731 }
1732 tinfo->m_windowSet.clear();
1733
1734 m_lock.unlock();
1735
1736 for (auto handle: colorBuffersToCleanup) {
1737 goldfish_vk::teardownVkColorBuffer(handle);
1738 }
1739 }
1740
DestroyRenderContext(HandleType p_context)1741 void FrameBuffer::DestroyRenderContext(HandleType p_context) {
1742 AutoLock mutex(m_lock);
1743 sweepColorBuffersLocked();
1744
1745 android::base::AutoWriteLock contextLock(m_contextStructureLock);
1746 m_contexts.erase(p_context);
1747 RenderThreadInfo* tinfo = RenderThreadInfo::get();
1748 uint64_t puid = tinfo->m_puid;
1749 // The new emulator manages render contexts per guest process.
1750 // Fall back to per-thread management if the system image does not
1751 // support it.
1752 if (puid) {
1753 auto ite = m_procOwnedRenderContext.find(puid);
1754 if (ite != m_procOwnedRenderContext.end()) {
1755 ite->second.erase(p_context);
1756 }
1757 } else {
1758 tinfo->m_contextSet.erase(p_context);
1759 }
1760 }
1761
DestroyWindowSurface(HandleType p_surface)1762 void FrameBuffer::DestroyWindowSurface(HandleType p_surface) {
1763 if (m_shuttingDown) {
1764 return;
1765 }
1766 AutoLock mutex(m_lock);
1767 auto colorBuffersToCleanup = DestroyWindowSurfaceLocked(p_surface);
1768
1769 mutex.unlock();
1770
1771 for (auto handle : colorBuffersToCleanup) {
1772 goldfish_vk::teardownVkColorBuffer(handle);
1773 }
1774 }
1775
DestroyWindowSurfaceLocked(HandleType p_surface)1776 std::vector<HandleType> FrameBuffer::DestroyWindowSurfaceLocked(HandleType p_surface) {
1777 std::vector<HandleType> colorBuffersToCleanUp;
1778 const auto w = m_windows.find(p_surface);
1779 if (w != m_windows.end()) {
1780 ScopedBind bind(m_colorBufferHelper);
1781 if (!m_guestManagedColorBufferLifetime) {
1782 if (m_refCountPipeEnabled) {
1783 if (decColorBufferRefCountLocked(w->second.second)) {
1784 colorBuffersToCleanUp.push_back(w->second.second);
1785 }
1786 } else {
1787 if (closeColorBufferLocked(w->second.second)) {
1788 colorBuffersToCleanUp.push_back(w->second.second);
1789 }
1790 }
1791 }
1792 m_windows.erase(w);
1793 RenderThreadInfo* tinfo = RenderThreadInfo::get();
1794 uint64_t puid = tinfo->m_puid;
1795 if (puid) {
1796 auto ite = m_procOwnedWindowSurfaces.find(puid);
1797 if (ite != m_procOwnedWindowSurfaces.end()) {
1798 ite->second.erase(p_surface);
1799 }
1800 } else {
1801 tinfo->m_windowSet.erase(p_surface);
1802 }
1803 }
1804 return colorBuffersToCleanUp;
1805 }
1806
openColorBuffer(HandleType p_colorbuffer)1807 int FrameBuffer::openColorBuffer(HandleType p_colorbuffer) {
1808 // When guest feature flag RefCountPipe is on, no reference counting is
1809 // needed.
1810 if (m_refCountPipeEnabled)
1811 return 0;
1812
1813 RenderThreadInfo* tInfo = RenderThreadInfo::get();
1814
1815 AutoLock mutex(m_lock);
1816
1817 ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
1818 if (c == m_colorbuffers.end()) {
1819 // bad colorbuffer handle
1820 ERR("FB: openColorBuffer cb handle %#x not found", p_colorbuffer);
1821 return -1;
1822 }
1823
1824 c->second.refcount++;
1825 markOpened(&c->second);
1826
1827 uint64_t puid = tInfo ? tInfo->m_puid : 0;
1828 if (puid) {
1829 m_procOwnedColorBuffers[puid].insert(p_colorbuffer);
1830 }
1831 return 0;
1832 }
1833
closeColorBuffer(HandleType p_colorbuffer)1834 void FrameBuffer::closeColorBuffer(HandleType p_colorbuffer) {
1835 // When guest feature flag RefCountPipe is on, no reference counting is
1836 // needed.
1837 if (m_refCountPipeEnabled) {
1838 return;
1839 }
1840
1841 RenderThreadInfo* tInfo = RenderThreadInfo::get();
1842
1843 std::vector<HandleType> toCleanup;
1844
1845 AutoLock mutex(m_lock);
1846 uint64_t puid = tInfo ? tInfo->m_puid : 0;
1847 if (puid) {
1848 auto ite = m_procOwnedColorBuffers.find(puid);
1849 if (ite != m_procOwnedColorBuffers.end()) {
1850 const auto& cb = ite->second.find(p_colorbuffer);
1851 if (cb != ite->second.end()) {
1852 ite->second.erase(cb);
1853 if (closeColorBufferLocked(p_colorbuffer)) {
1854 toCleanup.push_back(p_colorbuffer);
1855 }
1856 }
1857 }
1858 } else {
1859 if (closeColorBufferLocked(p_colorbuffer)) {
1860 toCleanup.push_back(p_colorbuffer);
1861 }
1862 }
1863
1864 mutex.unlock();
1865
1866 for (auto handle : toCleanup) {
1867 goldfish_vk::teardownVkColorBuffer(handle);
1868 }
1869 }
1870
closeBuffer(HandleType p_buffer)1871 void FrameBuffer::closeBuffer(HandleType p_buffer) {
1872 AutoLock mutex(m_lock);
1873
1874 if (m_buffers.find(p_buffer) == m_buffers.end()) {
1875 ERR("closeColorBuffer: cannot find buffer %u",
1876 static_cast<uint32_t>(p_buffer));
1877 } else {
1878 goldfish_vk::teardownVkBuffer(p_buffer);
1879 m_buffers.erase(p_buffer);
1880 }
1881 }
1882
closeColorBufferLocked(HandleType p_colorbuffer,bool forced)1883 bool FrameBuffer::closeColorBufferLocked(HandleType p_colorbuffer,
1884 bool forced) {
1885 // When guest feature flag RefCountPipe is on, no reference counting is
1886 // needed.
1887 if (m_refCountPipeEnabled) {
1888 return false;
1889 }
1890
1891 if (m_noDelayCloseColorBufferEnabled)
1892 forced = true;
1893
1894 ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
1895 if (c == m_colorbuffers.end()) {
1896 // This is harmless: it is normal for guest system to issue
1897 // closeColorBuffer command when the color buffer is already
1898 // garbage collected on the host. (we dont have a mechanism
1899 // to give guest a notice yet)
1900 return false;
1901 }
1902
1903 bool deleted = false;
1904 // The guest can and will gralloc_alloc/gralloc_free and then
1905 // gralloc_register a buffer, due to API level (O+) or
1906 // timing issues.
1907 // So, we don't actually close the color buffer when refcount
1908 // reached zero, unless it has been opened at least once already.
1909 // Instead, put it on a 'delayed close' list to return to it later.
1910 if (--c->second.refcount == 0) {
1911 if (forced) {
1912 eraseDelayedCloseColorBufferLocked(c->first, c->second.closedTs);
1913 m_colorbuffers.erase(c);
1914 deleted = true;
1915 } else {
1916 c->second.closedTs = android::base::getUnixTimeUs();
1917 m_colorBufferDelayedCloseList.push_back(
1918 {c->second.closedTs, p_colorbuffer});
1919 }
1920 }
1921
1922 performDelayedColorBufferCloseLocked(false);
1923
1924 return deleted;
1925 }
1926
performDelayedColorBufferCloseLocked(bool forced)1927 void FrameBuffer::performDelayedColorBufferCloseLocked(bool forced) {
1928 // Let's wait just long enough to make sure it's not because of instant
1929 // timestamp change (end of previous second -> beginning of a next one),
1930 // but not for long - this is a workaround for race conditions, and they
1931 // are quick.
1932 static constexpr int kColorBufferClosingDelaySec = 1;
1933
1934 const auto now = android::base::getUnixTimeUs();
1935 auto it = m_colorBufferDelayedCloseList.begin();
1936 while (it != m_colorBufferDelayedCloseList.end() &&
1937 (forced ||
1938 it->ts + kColorBufferClosingDelaySec <= now)) {
1939 if (it->cbHandle != 0) {
1940 const auto& cb = m_colorbuffers.find(it->cbHandle);
1941 if (cb != m_colorbuffers.end()) {
1942 m_colorbuffers.erase(cb);
1943 }
1944 }
1945 ++it;
1946 }
1947 m_colorBufferDelayedCloseList.erase(
1948 m_colorBufferDelayedCloseList.begin(), it);
1949 }
1950
eraseDelayedCloseColorBufferLocked(HandleType cb,uint64_t ts)1951 void FrameBuffer::eraseDelayedCloseColorBufferLocked(
1952 HandleType cb, uint64_t ts)
1953 {
1954 // Find the first delayed buffer with a timestamp <= |ts|
1955 auto it = std::lower_bound(
1956 m_colorBufferDelayedCloseList.begin(),
1957 m_colorBufferDelayedCloseList.end(), ts,
1958 [](const ColorBufferCloseInfo& ci, uint64_t ts) {
1959 return ci.ts < ts;
1960 });
1961 while (it != m_colorBufferDelayedCloseList.end() &&
1962 it->ts == ts) {
1963 // if this is the one we need - clear it out.
1964 if (it->cbHandle == cb) {
1965 it->cbHandle = 0;
1966 break;
1967 }
1968 ++it;
1969 }
1970 }
1971
cleanupProcGLObjects(uint64_t puid)1972 void FrameBuffer::cleanupProcGLObjects(uint64_t puid) {
1973 bool renderThreadWithThisPuidExists = false;
1974
1975 do {
1976 renderThreadWithThisPuidExists = false;
1977 RenderThreadInfo::forAllRenderThreadInfos(
1978 [puid, &renderThreadWithThisPuidExists](RenderThreadInfo* i) {
1979 if (i->m_puid == puid) {
1980 renderThreadWithThisPuidExists = true;
1981 }
1982 });
1983 android::base::sleepUs(10000);
1984 } while (renderThreadWithThisPuidExists);
1985
1986 AutoLock mutex(m_lock);
1987 if (!m_eglDisplay) {
1988 return;
1989 }
1990 auto colorBuffersToCleanup = cleanupProcGLObjects_locked(puid);
1991
1992 // Run other cleanup callbacks
1993 // Avoid deadlock by first storing a separate list of callbacks
1994 std::vector<std::function<void()>> callbacks;
1995
1996 {
1997 auto procIte = m_procOwnedCleanupCallbacks.find(puid);
1998 if (procIte != m_procOwnedCleanupCallbacks.end()) {
1999 for (auto it : procIte->second) {
2000 callbacks.push_back(it.second);
2001 }
2002 m_procOwnedCleanupCallbacks.erase(procIte);
2003 }
2004 }
2005
2006 {
2007 auto procIte = m_procOwnedSequenceNumbers.find(puid);
2008 if (procIte != m_procOwnedSequenceNumbers.end()) {
2009 delete procIte->second;
2010 m_procOwnedSequenceNumbers.erase(procIte);
2011 }
2012 }
2013
2014 mutex.unlock();
2015
2016 for (auto handle : colorBuffersToCleanup) {
2017 goldfish_vk::teardownVkColorBuffer(handle);
2018 }
2019
2020 for (auto cb : callbacks) {
2021 cb();
2022 }
2023 }
2024
cleanupProcGLObjects_locked(uint64_t puid,bool forced)2025 std::vector<HandleType> FrameBuffer::cleanupProcGLObjects_locked(uint64_t puid, bool forced) {
2026 std::vector<HandleType> colorBuffersToCleanup;
2027 {
2028 ScopedBind bind(m_colorBufferHelper);
2029 // Clean up window surfaces
2030 {
2031 auto procIte = m_procOwnedWindowSurfaces.find(puid);
2032 if (procIte != m_procOwnedWindowSurfaces.end()) {
2033 for (auto whndl : procIte->second) {
2034 auto w = m_windows.find(whndl);
2035 if (!m_guestManagedColorBufferLifetime) {
2036 if (m_refCountPipeEnabled) {
2037 if (decColorBufferRefCountLocked(w->second.second)) {
2038 colorBuffersToCleanup.push_back(w->second.second);
2039 }
2040 } else {
2041 if (closeColorBufferLocked(w->second.second, forced)) {
2042 colorBuffersToCleanup.push_back(w->second.second);
2043 }
2044 }
2045 }
2046 m_windows.erase(w);
2047 }
2048 m_procOwnedWindowSurfaces.erase(procIte);
2049 }
2050 }
2051 // Clean up color buffers.
2052 // A color buffer needs to be closed as many times as it is opened by
2053 // the guest process, to give the correct reference count.
2054 // (Note that a color buffer can be shared across guest processes.)
2055 {
2056 if (!m_guestManagedColorBufferLifetime) {
2057 auto procIte = m_procOwnedColorBuffers.find(puid);
2058 if (procIte != m_procOwnedColorBuffers.end()) {
2059 for (auto cb : procIte->second) {
2060 if (closeColorBufferLocked(cb, forced)) {
2061 colorBuffersToCleanup.push_back(cb);
2062 }
2063 }
2064 m_procOwnedColorBuffers.erase(procIte);
2065 }
2066 }
2067 }
2068
2069 // Clean up EGLImage handles
2070 {
2071 auto procIte = m_procOwnedEGLImages.find(puid);
2072 if (procIte != m_procOwnedEGLImages.end()) {
2073 if (!procIte->second.empty()) {
2074 for (auto eglImg : procIte->second) {
2075 s_egl.eglDestroyImageKHR(
2076 m_eglDisplay,
2077 reinterpret_cast<EGLImageKHR>((HandleType)eglImg));
2078 }
2079 }
2080 m_procOwnedEGLImages.erase(procIte);
2081 }
2082 }
2083 }
2084 // Unbind before cleaning up contexts
2085 // Cleanup render contexts
2086 {
2087 auto procIte = m_procOwnedRenderContext.find(puid);
2088 if (procIte != m_procOwnedRenderContext.end()) {
2089 for (auto ctx : procIte->second) {
2090 m_contexts.erase(ctx);
2091 }
2092 m_procOwnedRenderContext.erase(procIte);
2093 }
2094 }
2095
2096 return colorBuffersToCleanup;
2097 }
2098
markOpened(ColorBufferRef * cbRef)2099 void FrameBuffer::markOpened(ColorBufferRef* cbRef) {
2100 cbRef->opened = true;
2101 eraseDelayedCloseColorBufferLocked(cbRef->cb->getHndl(), cbRef->closedTs);
2102 cbRef->closedTs = 0;
2103 }
2104
flushWindowSurfaceColorBuffer(HandleType p_surface)2105 bool FrameBuffer::flushWindowSurfaceColorBuffer(HandleType p_surface) {
2106 AutoLock mutex(m_lock);
2107
2108 WindowSurfaceMap::iterator w(m_windows.find(p_surface));
2109 if (w == m_windows.end()) {
2110 ERR("FB::flushWindowSurfaceColorBuffer: window handle %#x not found",
2111 p_surface);
2112 // bad surface handle
2113 return false;
2114 }
2115
2116 GLenum resetStatus = s_gles2.glGetGraphicsResetStatusEXT();
2117 if (resetStatus != GL_NO_ERROR) {
2118 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) <<
2119 "Stream server aborting due to graphics reset. ResetStatus: " <<
2120 std::hex << resetStatus;
2121 }
2122
2123 WindowSurface* surface = (*w).second.first.get();
2124 surface->flushColorBuffer();
2125
2126 return true;
2127 }
2128
getWindowSurfaceColorBufferHandle(HandleType p_surface)2129 HandleType FrameBuffer::getWindowSurfaceColorBufferHandle(HandleType p_surface) {
2130 AutoLock mutex(m_lock);
2131
2132 auto it = m_windowSurfaceToColorBuffer.find(p_surface);
2133
2134 if (it == m_windowSurfaceToColorBuffer.end()) return 0;
2135
2136 return it->second;
2137 }
2138
setWindowSurfaceColorBuffer(HandleType p_surface,HandleType p_colorbuffer)2139 bool FrameBuffer::setWindowSurfaceColorBuffer(HandleType p_surface,
2140 HandleType p_colorbuffer) {
2141 AutoLock mutex(m_lock);
2142
2143 WindowSurfaceMap::iterator w(m_windows.find(p_surface));
2144 if (w == m_windows.end()) {
2145 // bad surface handle
2146 ERR("bad window surface handle %#x", p_surface);
2147 return false;
2148 }
2149
2150 ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
2151 if (c == m_colorbuffers.end()) {
2152 ERR("bad color buffer handle %#x", p_colorbuffer);
2153 // bad colorbuffer handle
2154 return false;
2155 }
2156
2157 (*w).second.first->setColorBuffer((*c).second.cb);
2158 markOpened(&c->second);
2159 if (w->second.second) {
2160 if (!m_guestManagedColorBufferLifetime) {
2161 if (m_refCountPipeEnabled) {
2162 decColorBufferRefCountLocked(w->second.second);
2163 } else {
2164 closeColorBufferLocked(w->second.second);
2165 }
2166 }
2167 }
2168
2169 if (!m_guestManagedColorBufferLifetime) {
2170 c->second.refcount++;
2171 }
2172
2173 (*w).second.second = p_colorbuffer;
2174
2175 m_windowSurfaceToColorBuffer[p_surface] = p_colorbuffer;
2176
2177 return true;
2178 }
2179
readColorBuffer(HandleType p_colorbuffer,int x,int y,int width,int height,GLenum format,GLenum type,void * pixels)2180 void FrameBuffer::readColorBuffer(HandleType p_colorbuffer,
2181 int x,
2182 int y,
2183 int width,
2184 int height,
2185 GLenum format,
2186 GLenum type,
2187 void* pixels) {
2188 AutoLock mutex(m_lock);
2189
2190 ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
2191 if (c == m_colorbuffers.end()) {
2192 // bad colorbuffer handle
2193 return;
2194 }
2195
2196 (*c).second.cb->readPixels(x, y, width, height, format, type, pixels);
2197 }
2198
readColorBufferYUV(HandleType p_colorbuffer,int x,int y,int width,int height,void * pixels,uint32_t pixels_size)2199 void FrameBuffer::readColorBufferYUV(HandleType p_colorbuffer,
2200 int x,
2201 int y,
2202 int width,
2203 int height,
2204 void* pixels,
2205 uint32_t pixels_size) {
2206 AutoLock mutex(m_lock);
2207
2208 ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
2209 if (c == m_colorbuffers.end()) {
2210 // bad colorbuffer handle
2211 return;
2212 }
2213
2214 (*c).second.cb->readPixelsYUVCached(x, y, width, height, pixels, pixels_size);
2215 }
2216
createYUVTextures(uint32_t type,uint32_t count,int width,int height,uint32_t * output)2217 void FrameBuffer::createYUVTextures(uint32_t type,
2218 uint32_t count,
2219 int width,
2220 int height,
2221 uint32_t* output) {
2222 FrameworkFormat format = static_cast<FrameworkFormat>(type);
2223 AutoLock mutex(m_lock);
2224 ScopedBind bind(m_colorBufferHelper);
2225 for (uint32_t i = 0; i < count; ++i) {
2226 if (format == FRAMEWORK_FORMAT_NV12) {
2227 YUVConverter::createYUVGLTex(GL_TEXTURE0, width, height,
2228 format, YUVPlane::Y, &output[2 * i]);
2229 YUVConverter::createYUVGLTex(GL_TEXTURE1, width / 2, height / 2,
2230 format, YUVPlane::UV, &output[2 * i + 1]);
2231 } else if (format == FRAMEWORK_FORMAT_YUV_420_888) {
2232 YUVConverter::createYUVGLTex(GL_TEXTURE0, width, height,
2233 format, YUVPlane::Y, &output[3 * i]);
2234 YUVConverter::createYUVGLTex(GL_TEXTURE1, width / 2, height / 2,
2235 format, YUVPlane::U, &output[3 * i + 1]);
2236 YUVConverter::createYUVGLTex(GL_TEXTURE2, width / 2, height / 2,
2237 format, YUVPlane::V, &output[3 * i + 2]);
2238 }
2239 }
2240 }
2241
destroyYUVTextures(uint32_t type,uint32_t count,uint32_t * textures)2242 void FrameBuffer::destroyYUVTextures(uint32_t type,
2243 uint32_t count,
2244 uint32_t* textures) {
2245 AutoLock mutex(m_lock);
2246 ScopedBind bind(m_colorBufferHelper);
2247 if (type == FRAMEWORK_FORMAT_NV12) {
2248 s_gles2.glDeleteTextures(2 * count, textures);
2249 } else if (type == FRAMEWORK_FORMAT_YUV_420_888) {
2250 s_gles2.glDeleteTextures(3 * count, textures);
2251 }
2252 }
2253
2254 extern "C" {
2255 typedef void (*yuv_updater_t)(void* privData,
2256 uint32_t type,
2257 uint32_t* textures);
2258 }
2259
updateYUVTextures(uint32_t type,uint32_t * textures,void * privData,void * func)2260 void FrameBuffer::updateYUVTextures(uint32_t type,
2261 uint32_t* textures,
2262 void* privData,
2263 void* func) {
2264 AutoLock mutex(m_lock);
2265 ScopedBind bind(m_colorBufferHelper);
2266
2267 yuv_updater_t updater = (yuv_updater_t)func;
2268 uint32_t gtextures[3] = {0, 0, 0};
2269
2270 if (type == FRAMEWORK_FORMAT_NV12) {
2271 gtextures[0] = s_gles2.glGetGlobalTexName(textures[0]);
2272 gtextures[1] = s_gles2.glGetGlobalTexName(textures[1]);
2273 } else if (type == FRAMEWORK_FORMAT_YUV_420_888) {
2274 gtextures[0] = s_gles2.glGetGlobalTexName(textures[0]);
2275 gtextures[1] = s_gles2.glGetGlobalTexName(textures[1]);
2276 gtextures[2] = s_gles2.glGetGlobalTexName(textures[2]);
2277 }
2278
2279 updater(privData, type, gtextures);
2280 }
2281
swapTexturesAndUpdateColorBuffer(uint32_t p_colorbuffer,int x,int y,int width,int height,uint32_t format,uint32_t type,uint32_t texture_type,uint32_t * textures)2282 void FrameBuffer::swapTexturesAndUpdateColorBuffer(uint32_t p_colorbuffer,
2283 int x,
2284 int y,
2285 int width,
2286 int height,
2287 uint32_t format,
2288 uint32_t type,
2289 uint32_t texture_type,
2290 uint32_t* textures) {
2291 {
2292 AutoLock mutex(m_lock);
2293 ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
2294 if (c == m_colorbuffers.end()) {
2295 // bad colorbuffer handle
2296 return;
2297 }
2298 (*c).second.cb->swapYUVTextures(texture_type, textures);
2299 }
2300
2301 updateColorBuffer(p_colorbuffer, x, y, width, height, format, type,
2302 nullptr);
2303 }
2304
updateColorBuffer(HandleType p_colorbuffer,int x,int y,int width,int height,GLenum format,GLenum type,void * pixels)2305 bool FrameBuffer::updateColorBuffer(HandleType p_colorbuffer,
2306 int x,
2307 int y,
2308 int width,
2309 int height,
2310 GLenum format,
2311 GLenum type,
2312 void* pixels) {
2313 if (width == 0 || height == 0) {
2314 return false;
2315 }
2316
2317 AutoLock mutex(m_lock);
2318
2319 ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
2320 if (c == m_colorbuffers.end()) {
2321 // bad colorbuffer handle
2322 return false;
2323 }
2324
2325 (*c).second.cb->subUpdate(x, y, width, height, format, type, pixels);
2326
2327 return true;
2328 }
2329
replaceColorBufferContents(HandleType p_colorbuffer,const void * pixels,size_t numBytes)2330 bool FrameBuffer::replaceColorBufferContents(
2331 HandleType p_colorbuffer, const void* pixels, size_t numBytes) {
2332 AutoLock mutex(m_lock);
2333
2334 ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
2335 if (c == m_colorbuffers.end()) {
2336 // bad colorbuffer handle
2337 return false;
2338 }
2339
2340 return (*c).second.cb->replaceContents(pixels, numBytes);
2341 }
2342
readColorBufferContents(HandleType p_colorbuffer,size_t * numBytes,void * pixels)2343 bool FrameBuffer::readColorBufferContents(
2344 HandleType p_colorbuffer, size_t* numBytes, void* pixels) {
2345
2346 AutoLock mutex(m_lock);
2347
2348 ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
2349 if (c == m_colorbuffers.end()) {
2350 // bad colorbuffer handle
2351 return false;
2352 }
2353
2354 return (*c).second.cb->readContents(numBytes, pixels);
2355 }
2356
getColorBufferInfo(HandleType p_colorbuffer,int * width,int * height,GLint * internalformat,FrameworkFormat * frameworkFormat)2357 bool FrameBuffer::getColorBufferInfo(
2358 HandleType p_colorbuffer, int* width, int* height, GLint* internalformat,
2359 FrameworkFormat* frameworkFormat) {
2360
2361 AutoLock mutex(m_lock);
2362
2363 ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
2364 if (c == m_colorbuffers.end()) {
2365 // bad colorbuffer handle
2366 return false;
2367 }
2368
2369 auto cb = (*c).second.cb;
2370
2371 *width = cb->getWidth();
2372 *height = cb->getHeight();
2373 *internalformat = cb->getInternalFormat();
2374 if (frameworkFormat) {
2375 *frameworkFormat = cb->getFrameworkFormat();
2376 }
2377
2378 return true;
2379 }
2380
getBufferInfo(HandleType p_buffer,int * size)2381 bool FrameBuffer::getBufferInfo(HandleType p_buffer, int* size) {
2382 AutoLock mutex(m_lock);
2383
2384 BufferMap::iterator c(m_buffers.find(p_buffer));
2385 if (c == m_buffers.end()) {
2386 // Bad buffer handle.
2387 return false;
2388 }
2389
2390 auto buf = (*c).second.buffer;
2391 *size = buf->getSize();
2392 return true;
2393 }
2394
bindColorBufferToTexture(HandleType p_colorbuffer)2395 bool FrameBuffer::bindColorBufferToTexture(HandleType p_colorbuffer) {
2396 AutoLock mutex(m_lock);
2397
2398 ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
2399 if (c == m_colorbuffers.end()) {
2400 // bad colorbuffer handle
2401 return false;
2402 }
2403
2404 return (*c).second.cb->bindToTexture();
2405 }
2406
bindColorBufferToTexture2(HandleType p_colorbuffer)2407 bool FrameBuffer::bindColorBufferToTexture2(HandleType p_colorbuffer) {
2408 AutoLock mutex(m_lock);
2409
2410 ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
2411 if (c == m_colorbuffers.end()) {
2412 // bad colorbuffer handle
2413 return false;
2414 }
2415
2416 return (*c).second.cb->bindToTexture2();
2417 }
2418
bindColorBufferToRenderbuffer(HandleType p_colorbuffer)2419 bool FrameBuffer::bindColorBufferToRenderbuffer(HandleType p_colorbuffer) {
2420 AutoLock mutex(m_lock);
2421
2422 ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
2423 if (c == m_colorbuffers.end()) {
2424 // bad colorbuffer handle
2425 return false;
2426 }
2427
2428 return (*c).second.cb->bindToRenderbuffer();
2429 }
2430
bindContext(HandleType p_context,HandleType p_drawSurface,HandleType p_readSurface)2431 bool FrameBuffer::bindContext(HandleType p_context,
2432 HandleType p_drawSurface,
2433 HandleType p_readSurface) {
2434 if (m_shuttingDown) {
2435 return false;
2436 }
2437
2438 AutoLock mutex(m_lock);
2439
2440 WindowSurfacePtr draw, read;
2441 RenderContextPtr ctx;
2442
2443 //
2444 // if this is not an unbind operation - make sure all handles are good
2445 //
2446 if (p_context || p_drawSurface || p_readSurface) {
2447 ctx = getContext_locked(p_context);
2448 if (!ctx)
2449 return false;
2450 WindowSurfaceMap::iterator w(m_windows.find(p_drawSurface));
2451 if (w == m_windows.end()) {
2452 // bad surface handle
2453 return false;
2454 }
2455 draw = (*w).second.first;
2456
2457 if (p_readSurface != p_drawSurface) {
2458 WindowSurfaceMap::iterator w(m_windows.find(p_readSurface));
2459 if (w == m_windows.end()) {
2460 // bad surface handle
2461 return false;
2462 }
2463 read = (*w).second.first;
2464 } else {
2465 read = draw;
2466 }
2467 } else {
2468 // if unbind operation, sweep color buffers
2469 sweepColorBuffersLocked();
2470 }
2471
2472 if (!s_egl.eglMakeCurrent(m_eglDisplay,
2473 draw ? draw->getEGLSurface() : EGL_NO_SURFACE,
2474 read ? read->getEGLSurface() : EGL_NO_SURFACE,
2475 ctx ? ctx->getEGLContext() : EGL_NO_CONTEXT)) {
2476 ERR("eglMakeCurrent failed");
2477 return false;
2478 }
2479
2480 //
2481 // Bind the surface(s) to the context
2482 //
2483 RenderThreadInfo* tinfo = RenderThreadInfo::get();
2484 WindowSurfacePtr bindDraw, bindRead;
2485 if (draw.get() == NULL && read.get() == NULL) {
2486 // Unbind the current read and draw surfaces from the context
2487 bindDraw = tinfo->currDrawSurf;
2488 bindRead = tinfo->currReadSurf;
2489 } else {
2490 bindDraw = draw;
2491 bindRead = read;
2492 }
2493
2494 if (bindDraw.get() != NULL && bindRead.get() != NULL) {
2495 if (bindDraw.get() != bindRead.get()) {
2496 bindDraw->bind(ctx, WindowSurface::BIND_DRAW);
2497 bindRead->bind(ctx, WindowSurface::BIND_READ);
2498 } else {
2499 bindDraw->bind(ctx, WindowSurface::BIND_READDRAW);
2500 }
2501 }
2502
2503 //
2504 // update thread info with current bound context
2505 //
2506 tinfo->currContext = ctx;
2507 tinfo->currDrawSurf = draw;
2508 tinfo->currReadSurf = read;
2509 if (ctx) {
2510 if (ctx->clientVersion() > GLESApi_CM)
2511 tinfo->m_gl2Dec.setContextData(&ctx->decoderContextData());
2512 else
2513 tinfo->m_glDec.setContextData(&ctx->decoderContextData());
2514 } else {
2515 tinfo->m_glDec.setContextData(NULL);
2516 tinfo->m_gl2Dec.setContextData(NULL);
2517 }
2518 return true;
2519 }
2520
getContext_locked(HandleType p_context)2521 RenderContextPtr FrameBuffer::getContext_locked(HandleType p_context) {
2522 return android::base::findOrDefault(m_contexts, p_context);
2523 }
2524
getColorBuffer_locked(HandleType p_colorBuffer)2525 ColorBufferPtr FrameBuffer::getColorBuffer_locked(HandleType p_colorBuffer) {
2526 auto i = m_colorbuffers.find(p_colorBuffer);
2527 if (i == m_colorbuffers.end()) {
2528 return nullptr;
2529 }
2530 return i->second.cb;
2531 }
2532
getWindowSurface_locked(HandleType p_windowsurface)2533 WindowSurfacePtr FrameBuffer::getWindowSurface_locked(HandleType p_windowsurface) {
2534 return android::base::findOrDefault(m_windows, p_windowsurface).first;
2535 }
2536
createClientImage(HandleType context,EGLenum target,GLuint buffer)2537 HandleType FrameBuffer::createClientImage(HandleType context,
2538 EGLenum target,
2539 GLuint buffer) {
2540 EGLContext eglContext = EGL_NO_CONTEXT;
2541 if (context) {
2542 AutoLock mutex(m_lock);
2543 RenderContextMap::const_iterator rcIt = m_contexts.find(context);
2544 if (rcIt == m_contexts.end()) {
2545 // bad context handle
2546 return false;
2547 }
2548 eglContext =
2549 rcIt->second ? rcIt->second->getEGLContext() : EGL_NO_CONTEXT;
2550 }
2551
2552 EGLImageKHR image = s_egl.eglCreateImageKHR(
2553 m_eglDisplay, eglContext, target,
2554 reinterpret_cast<EGLClientBuffer>(buffer), NULL);
2555 HandleType imgHnd = (HandleType) reinterpret_cast<uintptr_t>(image);
2556
2557 RenderThreadInfo* tInfo = RenderThreadInfo::get();
2558 uint64_t puid = tInfo->m_puid;
2559 if (puid) {
2560 AutoLock mutex(m_lock);
2561 m_procOwnedEGLImages[puid].insert(imgHnd);
2562 }
2563 return imgHnd;
2564 }
2565
destroyClientImage(HandleType image)2566 EGLBoolean FrameBuffer::destroyClientImage(HandleType image) {
2567 // eglDestroyImageKHR has its own lock already.
2568 EGLBoolean ret = s_egl.eglDestroyImageKHR(
2569 m_eglDisplay, reinterpret_cast<EGLImageKHR>(image));
2570 if (!ret)
2571 return false;
2572 RenderThreadInfo* tInfo = RenderThreadInfo::get();
2573 uint64_t puid = tInfo->m_puid;
2574 if (puid) {
2575 AutoLock mutex(m_lock);
2576 m_procOwnedEGLImages[puid].erase(image);
2577 // We don't explicitly call m_procOwnedEGLImages.erase(puid) when the
2578 // size reaches 0, since it could go between zero and one many times in
2579 // the lifetime of a process. It will be cleaned up by
2580 // cleanupProcGLObjects(puid) when the process is dead.
2581 }
2582 return true;
2583 }
2584
2585 //
2586 // The framebuffer lock should be held when calling this function !
2587 //
bind_locked()2588 bool FrameBuffer::bind_locked() {
2589 EGLContext prevContext = s_egl.eglGetCurrentContext();
2590 EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
2591 EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
2592
2593 if (prevContext != m_pbufContext || prevReadSurf != m_pbufSurface ||
2594 prevDrawSurf != m_pbufSurface) {
2595 if (!s_egl.eglMakeCurrent(m_eglDisplay, m_pbufSurface, m_pbufSurface,
2596 m_pbufContext)) {
2597 if (!m_shuttingDown)
2598 ERR("eglMakeCurrent failed");
2599 return false;
2600 }
2601 } else {
2602 ERR("Nested %s call detected, should never happen\n", __func__);
2603 }
2604
2605 m_prevContext = prevContext;
2606 m_prevReadSurf = prevReadSurf;
2607 m_prevDrawSurf = prevDrawSurf;
2608 return true;
2609 }
2610
bindSubwin_locked()2611 bool FrameBuffer::bindSubwin_locked() {
2612 EGLContext prevContext = s_egl.eglGetCurrentContext();
2613 EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
2614 EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
2615
2616 if (prevContext != m_eglContext || prevReadSurf != m_eglSurface ||
2617 prevDrawSurf != m_eglSurface) {
2618 if (!s_egl.eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface,
2619 m_eglContext)) {
2620 ERR("eglMakeCurrent failed in binding subwindow!");
2621 return false;
2622 }
2623 }
2624
2625 //
2626 // initialize GL state in eglContext if not yet initilaized
2627 //
2628 if (!m_eglContextInitialized) {
2629 m_eglContextInitialized = true;
2630 }
2631
2632 m_prevContext = prevContext;
2633 m_prevReadSurf = prevReadSurf;
2634 m_prevDrawSurf = prevDrawSurf;
2635 return true;
2636 }
2637
bindFakeWindow_locked()2638 bool FrameBuffer::bindFakeWindow_locked() {
2639 if (m_eglFakeWindowSurface == EGL_NO_SURFACE) {
2640 // initialize here
2641 m_eglFakeWindowContext = s_egl.eglCreateContext(
2642 m_eglDisplay, m_eglConfig, m_eglContext,
2643 getGlesMaxContextAttribs());
2644
2645 static const EGLint kFakeWindowPbufAttribs[] = {
2646 EGL_WIDTH, m_framebufferWidth, EGL_HEIGHT,
2647 m_framebufferWidth, EGL_NONE,
2648 };
2649
2650 m_eglFakeWindowSurface = s_egl.eglCreatePbufferSurface(
2651 m_eglDisplay, m_eglConfig, kFakeWindowPbufAttribs);
2652 }
2653
2654 if (!s_egl.eglMakeCurrent(m_eglDisplay, m_eglFakeWindowSurface,
2655 m_eglFakeWindowSurface, m_eglFakeWindowContext)) {
2656 ERR("eglMakeCurrent failed in binding fake window!");
2657 return false;
2658 }
2659 return true;
2660 }
2661
unbind_locked()2662 bool FrameBuffer::unbind_locked() {
2663 EGLContext curContext = s_egl.eglGetCurrentContext();
2664 EGLSurface curReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
2665 EGLSurface curDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
2666
2667 if (m_prevContext != curContext || m_prevReadSurf != curReadSurf ||
2668 m_prevDrawSurf != curDrawSurf) {
2669 if (!s_egl.eglMakeCurrent(m_eglDisplay, m_prevDrawSurf, m_prevReadSurf,
2670 m_prevContext)) {
2671 return false;
2672 }
2673 }
2674
2675 m_prevContext = EGL_NO_CONTEXT;
2676 m_prevReadSurf = EGL_NO_SURFACE;
2677 m_prevDrawSurf = EGL_NO_SURFACE;
2678 return true;
2679 }
2680
createTrivialContext(HandleType shared,HandleType * contextOut,HandleType * surfOut)2681 void FrameBuffer::createTrivialContext(HandleType shared,
2682 HandleType* contextOut,
2683 HandleType* surfOut) {
2684 assert(contextOut);
2685 assert(surfOut);
2686
2687 *contextOut = createRenderContext(0, shared, GLESApi_2);
2688 // Zero size is formally allowed here, but SwiftShader doesn't like it and
2689 // fails.
2690 *surfOut = createWindowSurface(0, 1, 1);
2691 }
2692
createSharedTrivialContext(EGLContext * contextOut,EGLSurface * surfOut)2693 void FrameBuffer::createSharedTrivialContext(EGLContext* contextOut,
2694 EGLSurface* surfOut) {
2695 assert(contextOut);
2696 assert(surfOut);
2697
2698 const FbConfig* config = getConfigs()->get(0 /* p_config */);
2699 if (!config) return;
2700
2701 int maj, min;
2702 emugl::getGlesVersion(&maj, &min);
2703
2704 const EGLint contextAttribs[] = {
2705 EGL_CONTEXT_MAJOR_VERSION_KHR, maj,
2706 EGL_CONTEXT_MINOR_VERSION_KHR, min,
2707 EGL_NONE };
2708
2709 *contextOut = s_egl.eglCreateContext(
2710 m_eglDisplay, config->getEglConfig(), m_pbufContext, contextAttribs);
2711
2712 const EGLint pbufAttribs[] = {
2713 EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
2714
2715 *surfOut = s_egl.eglCreatePbufferSurface(m_eglDisplay, config->getEglConfig(), pbufAttribs);
2716 }
2717
destroySharedTrivialContext(EGLContext context,EGLSurface surface)2718 void FrameBuffer::destroySharedTrivialContext(EGLContext context,
2719 EGLSurface surface) {
2720 if (m_eglDisplay != EGL_NO_DISPLAY) {
2721 s_egl.eglDestroyContext(m_eglDisplay, context);
2722 s_egl.eglDestroySurface(m_eglDisplay, surface);
2723 }
2724 }
2725
post(HandleType p_colorbuffer,bool needLockAndBind)2726 bool FrameBuffer::post(HandleType p_colorbuffer, bool needLockAndBind) {
2727 if (m_guestUsesAngle) {
2728 goldfish_vk::updateColorBufferFromVkImage(p_colorbuffer);
2729 }
2730
2731 bool res = postImpl(p_colorbuffer, needLockAndBind);
2732 if (res) setGuestPostedAFrame();
2733 return res;
2734 }
2735
postImpl(HandleType p_colorbuffer,bool needLockAndBind,bool repaint)2736 bool FrameBuffer::postImpl(HandleType p_colorbuffer,
2737 bool needLockAndBind,
2738 bool repaint) {
2739 if (needLockAndBind) {
2740 m_lock.lock();
2741 }
2742 bool ret = false;
2743 ColorBufferMap::iterator c;
2744
2745 c = m_colorbuffers.find(p_colorbuffer);
2746 if (c == m_colorbuffers.end()) {
2747 goto EXIT;
2748 }
2749
2750 m_lastPostedColorBuffer = p_colorbuffer;
2751
2752 ret = true;
2753
2754 if (m_subWin) {
2755 markOpened(&c->second);
2756 c->second.cb->touch();
2757
2758 Post postCmd;
2759 postCmd.cmd = PostCmd::Post;
2760 postCmd.cb = c->second.cb.get();
2761 std::future<void> completeFuture =
2762 sendPostWorkerCmd(std::move(postCmd));
2763 completeFuture.wait();
2764 } else {
2765 markOpened(&c->second);
2766 c->second.cb->touch();
2767 c->second.cb->waitSync();
2768 c->second.cb->scale();
2769 s_gles2.glFlush();
2770
2771 // If there is no sub-window, don't display anything, the client will
2772 // rely on m_onPost to get the pixels instead.
2773 ret = true;
2774 }
2775
2776 //
2777 // output FPS and performance usage statistics
2778 //
2779 if (m_fpsStats) {
2780 long long currTime = android::base::getHighResTimeUs() / 1000;
2781 m_statsNumFrames++;
2782 if (currTime - m_statsStartTime >= 1000) {
2783 if (m_fpsStats) {
2784 float dt = (float)(currTime - m_statsStartTime) / 1000.0f;
2785 printf("FPS: %5.3f \n", (float)m_statsNumFrames / dt);
2786 m_statsNumFrames = 0;
2787 }
2788 m_statsStartTime = currTime;
2789 }
2790 }
2791
2792 //
2793 // Send framebuffer (without FPS overlay) to callback
2794 //
2795 if (m_onPost.size() == 0) {
2796 goto EXIT;
2797 }
2798 for (auto& iter : m_onPost) {
2799 ColorBufferPtr cb;
2800 if (iter.first == 0) {
2801 cb = c->second.cb;
2802 } else {
2803 uint32_t colorBuffer;
2804 if (getDisplayColorBuffer(iter.first, &colorBuffer) < 0) {
2805 ERR("Failed to get color buffer for display %d, skip onPost", iter.first);
2806 continue;
2807 }
2808 cb = findColorBuffer(colorBuffer);
2809 if (!cb) {
2810 ERR("Failed to find colorbuffer %d, skip onPost", colorBuffer);
2811 continue;
2812 }
2813 }
2814
2815 if (m_asyncReadbackSupported) {
2816 ensureReadbackWorker();
2817 m_readbackWorker->doNextReadback(iter.first, cb.get(), iter.second.img,
2818 repaint, iter.second.readBgra);
2819 } else {
2820 cb->readback(iter.second.img, iter.second.readBgra);
2821 doPostCallback(iter.second.img, iter.first);
2822 }
2823 }
2824
2825 EXIT:
2826 if (needLockAndBind) {
2827 m_lock.unlock();
2828 }
2829 return ret;
2830 }
2831
doPostCallback(void * pixels,uint32_t displayId)2832 void FrameBuffer::doPostCallback(void* pixels, uint32_t displayId) {
2833 const auto& iter = m_onPost.find(displayId);
2834 if (iter == m_onPost.end()) {
2835 ERR("Cannot find post callback function for display %d", displayId);
2836 return;
2837 }
2838 iter->second.cb(iter->second.context, displayId, iter->second.width,
2839 iter->second.height, -1, GL_RGBA, GL_UNSIGNED_BYTE,
2840 (unsigned char*)pixels);
2841 }
2842
getPixels(void * pixels,uint32_t bytes,uint32_t displayId)2843 void FrameBuffer::getPixels(void* pixels, uint32_t bytes, uint32_t displayId) {
2844 const auto& iter = m_onPost.find(displayId);
2845 if (iter == m_onPost.end()) {
2846 ERR("Display %d not configured for recording yet", displayId);
2847 return;
2848 }
2849 std::future<void> completeFuture = m_readbackThread.enqueue(
2850 {ReadbackCmd::GetPixels, displayId, 0, pixels, bytes});
2851 completeFuture.wait();
2852 }
2853
flushReadPipeline(int displayId)2854 void FrameBuffer::flushReadPipeline(int displayId) {
2855 const auto& iter = m_onPost.find(displayId);
2856 if (iter == m_onPost.end()) {
2857 ERR("Cannot find onPost pixels for display %d", displayId);
2858 return;
2859 }
2860
2861 ensureReadbackWorker();
2862 m_readbackWorker->flushPipeline(displayId);
2863 }
2864
ensureReadbackWorker()2865 void FrameBuffer::ensureReadbackWorker() {
2866 if (!m_readbackWorker) m_readbackWorker.reset(new ReadbackWorker);
2867 }
2868
sFrameBuffer_ReadPixelsCallback(void * pixels,uint32_t bytes,uint32_t displayId)2869 static void sFrameBuffer_ReadPixelsCallback(
2870 void* pixels, uint32_t bytes, uint32_t displayId) {
2871 FrameBuffer::getFB()->getPixels(pixels, bytes, displayId);
2872 }
2873
sFrameBuffer_FlushReadPixelPipeline(int displayId)2874 static void sFrameBuffer_FlushReadPixelPipeline(int displayId) {
2875 FrameBuffer::getFB()->flushReadPipeline(displayId);
2876 }
2877
asyncReadbackSupported()2878 bool FrameBuffer::asyncReadbackSupported() {
2879 return m_asyncReadbackSupported;
2880 }
2881
2882 emugl::Renderer::ReadPixelsCallback
getReadPixelsCallback()2883 FrameBuffer::getReadPixelsCallback() {
2884 return sFrameBuffer_ReadPixelsCallback;
2885 }
2886
getFlushReadPixelPipeline()2887 emugl::Renderer::FlushReadPixelPipeline FrameBuffer::getFlushReadPixelPipeline() {
2888 return sFrameBuffer_FlushReadPixelPipeline;
2889 }
2890
repost(bool needLockAndBind)2891 bool FrameBuffer::repost(bool needLockAndBind) {
2892 GL_LOG("Reposting framebuffer.");
2893 if (m_displayVk) {
2894 return true;
2895 }
2896 if (m_lastPostedColorBuffer &&
2897 sInitialized.load(std::memory_order_relaxed)) {
2898 GL_LOG("Has last posted colorbuffer and is initialized; post.");
2899 return postImpl(m_lastPostedColorBuffer, needLockAndBind,
2900 true /* need repaint */);
2901 } else {
2902 GL_LOG("No repost: no last posted color buffer");
2903 if (!sInitialized.load(std::memory_order_relaxed)) {
2904 GL_LOG("No repost: initialization is not finished.");
2905 }
2906 }
2907 return false;
2908 }
2909
2910 template <class Collection>
saveProcOwnedCollection(Stream * stream,const Collection & c)2911 static void saveProcOwnedCollection(Stream* stream, const Collection& c) {
2912 // Exclude empty handle lists from saving as they add no value but only
2913 // increase the snapshot size; keep the format compatible with
2914 // android::base::saveCollection() though.
2915 const int count =
2916 std::count_if(c.begin(), c.end(),
2917 [](const typename Collection::value_type& pair) {
2918 return !pair.second.empty();
2919 });
2920 stream->putBe32(count);
2921 for (const auto& pair : c) {
2922 if (pair.second.empty()) {
2923 continue;
2924 }
2925 stream->putBe64(pair.first);
2926 saveCollection(stream, pair.second,
2927 [](Stream* s, HandleType h) { s->putBe32(h); });
2928 }
2929 }
2930
2931 template <class Collection>
loadProcOwnedCollection(Stream * stream,Collection * c)2932 static void loadProcOwnedCollection(Stream* stream, Collection* c) {
2933 loadCollection(stream, c,
2934 [](Stream* stream) -> typename Collection::value_type {
2935 const int processId = stream->getBe64();
2936 typename Collection::mapped_type handles;
2937 loadCollection(stream, &handles, [](Stream* s) { return s->getBe32(); });
2938 return { processId, std::move(handles) };
2939 });
2940 }
2941
getScreenshot(unsigned int nChannels,unsigned int * width,unsigned int * height,std::vector<unsigned char> & pixels,int displayId,int desiredWidth,int desiredHeight,int desiredRotation)2942 void FrameBuffer::getScreenshot(unsigned int nChannels, unsigned int* width,
2943 unsigned int* height, std::vector<unsigned char>& pixels, int displayId,
2944 int desiredWidth, int desiredHeight, int desiredRotation) {
2945 AutoLock mutex(m_lock);
2946 uint32_t w, h, cb;
2947 if (!emugl::get_emugl_multi_display_operations().getMultiDisplay(displayId,
2948 nullptr,
2949 nullptr,
2950 &w,
2951 &h,
2952 nullptr,
2953 nullptr,
2954 nullptr)) {
2955 ERR("Screenshot of invalid display %d", displayId);
2956 *width = 0;
2957 *height = 0;
2958 pixels.resize(0);
2959 return;
2960 }
2961 if (nChannels != 3 && nChannels != 4) {
2962 ERR("Screenshot only support 3(RGB) or 4(RGBA) channels");
2963 *width = 0;
2964 *height = 0;
2965 pixels.resize(0);
2966 return;
2967 }
2968 emugl::get_emugl_multi_display_operations().getDisplayColorBuffer(displayId, &cb);
2969 if (displayId == 0) {
2970 cb = m_lastPostedColorBuffer;
2971 }
2972 ColorBufferMap::iterator c(m_colorbuffers.find(cb));
2973 if (c == m_colorbuffers.end()) {
2974 *width = 0;
2975 *height = 0;
2976 pixels.resize(0);
2977 return;
2978 }
2979
2980 *width = (desiredWidth == 0) ? w : desiredWidth;
2981 *height = (desiredHeight == 0) ? h : desiredHeight;
2982 if (desiredRotation == SKIN_ROTATION_90 || desiredRotation == SKIN_ROTATION_270) {
2983 std::swap(*width, *height);
2984 }
2985 pixels.resize(nChannels * (*width) * (*height));
2986
2987 GLenum format = nChannels == 3 ? GL_RGB : GL_RGBA;
2988
2989 Post scrCmd;
2990 scrCmd.cmd = PostCmd::Screenshot;
2991 scrCmd.screenshot.cb = c->second.cb.get();
2992 scrCmd.screenshot.screenwidth = *width;
2993 scrCmd.screenshot.screenheight = *height;
2994 scrCmd.screenshot.format = format;
2995 scrCmd.screenshot.type = GL_UNSIGNED_BYTE;
2996 scrCmd.screenshot.rotation = desiredRotation;
2997 scrCmd.screenshot.pixels = pixels.data();
2998
2999 std::future<void> completeFuture = sendPostWorkerCmd(std::move(scrCmd));
3000 completeFuture.wait();
3001 }
3002
onLastColorBufferRef(uint32_t handle)3003 void FrameBuffer::onLastColorBufferRef(uint32_t handle) {
3004 if (!mOutstandingColorBufferDestroys.trySend((HandleType)handle)) {
3005 ERR("warning: too many outstanding "
3006 "color buffer destroys. leaking handle 0x%x",
3007 handle);
3008 }
3009 }
3010
decColorBufferRefCountLocked(HandleType p_colorbuffer)3011 bool FrameBuffer::decColorBufferRefCountLocked(HandleType p_colorbuffer) {
3012 const auto& it = m_colorbuffers.find(p_colorbuffer);
3013 if (it != m_colorbuffers.end()) {
3014 it->second.refcount -= 1;
3015 if (it->second.refcount == 0) {
3016 m_colorbuffers.erase(p_colorbuffer);
3017 return true;
3018 }
3019 }
3020 return false;
3021 }
3022
compose(uint32_t bufferSize,void * buffer,bool needPost)3023 bool FrameBuffer::compose(uint32_t bufferSize, void* buffer, bool needPost) {
3024 std::promise<void> promise;
3025 std::future<void> completeFuture = promise.get_future();
3026 auto composeRes = composeWithCallback(
3027 bufferSize, buffer, [&](std::shared_future<void> waitForGpu) {
3028 waitForGpu.wait();
3029 promise.set_value();
3030 });
3031 if (!composeRes) {
3032 return false;
3033 }
3034 completeFuture.wait();
3035
3036 if (needPost) {
3037 ComposeDevice* composeDevice = (ComposeDevice*)buffer;
3038 AutoLock mutex(m_lock);
3039
3040 switch (composeDevice->version) {
3041 case 1: {
3042 post(composeDevice->targetHandle, false);
3043 break;
3044 }
3045 case 2: {
3046 ComposeDevice_v2* composeDeviceV2 = (ComposeDevice_v2*)buffer;
3047 if (composeDeviceV2->displayId == 0) {
3048 post(composeDeviceV2->targetHandle, false);
3049 }
3050 break;
3051 }
3052 default: {
3053 return false;
3054 }
3055 }
3056 }
3057 return true;
3058 }
3059
composeWithCallback(uint32_t bufferSize,void * buffer,Post::ComposeCallback callback)3060 bool FrameBuffer::composeWithCallback(uint32_t bufferSize, void* buffer,
3061 Post::ComposeCallback callback) {
3062 ComposeDevice* p = (ComposeDevice*)buffer;
3063 AutoLock mutex(m_lock);
3064
3065 switch (p->version) {
3066 case 1: {
3067 Post composeCmd;
3068 composeCmd.composeVersion = 1;
3069 composeCmd.composeBuffer.resize(bufferSize);
3070 memcpy(composeCmd.composeBuffer.data(), buffer, bufferSize);
3071 composeCmd.composeCallback =
3072 std::make_shared<Post::ComposeCallback>(callback);
3073 composeCmd.cmd = PostCmd::Compose;
3074 sendPostWorkerCmd(std::move(composeCmd));
3075 return true;
3076 }
3077
3078 case 2: {
3079 // support for multi-display
3080 ComposeDevice_v2* p2 = (ComposeDevice_v2*)buffer;
3081 if (p2->displayId != 0) {
3082 mutex.unlock();
3083 setDisplayColorBuffer(p2->displayId, p2->targetHandle);
3084 mutex.lock();
3085 }
3086 Post composeCmd;
3087 composeCmd.composeVersion = 2;
3088 composeCmd.composeBuffer.resize(bufferSize);
3089 memcpy(composeCmd.composeBuffer.data(), buffer, bufferSize);
3090 composeCmd.composeCallback =
3091 std::make_shared<Post::ComposeCallback>(callback);
3092 composeCmd.cmd = PostCmd::Compose;
3093 // Composition without holding the FrameBuffer lock here can lead to a
3094 // race condition, because it is possible to access
3095 // FrameBuffer::m_colorbuffers, which is a std::unordered_map, at the
3096 // same time from different threads, which may cause undefined behaviour.
3097 // TODO: Fix the potential data race on FrameBuffer::m_colorbuffers here.
3098 sendPostWorkerCmd(std::move(composeCmd));
3099 return true;
3100 }
3101
3102 default:
3103 ERR("yet to handle composition device version: %d", p->version);
3104 return false;
3105 }
3106 }
3107
onSave(Stream * stream,const android::snapshot::ITextureSaverPtr & textureSaver)3108 void FrameBuffer::onSave(Stream* stream,
3109 const android::snapshot::ITextureSaverPtr& textureSaver) {
3110 // Things we do not need to snapshot:
3111 // m_eglSurface
3112 // m_eglContext
3113 // m_pbufSurface
3114 // m_pbufContext
3115 // m_prevContext
3116 // m_prevReadSurf
3117 // m_prevDrawSurf
3118 AutoLock mutex(m_lock);
3119 // set up a context because some snapshot commands try using GL
3120 ScopedBind scopedBind(m_colorBufferHelper);
3121 // eglPreSaveContext labels all guest context textures to be saved
3122 // (textures created by the host are not saved!)
3123 // eglSaveAllImages labels all EGLImages (both host and guest) to be saved
3124 // and save all labeled textures and EGLImages.
3125 if (s_egl.eglPreSaveContext && s_egl.eglSaveAllImages) {
3126 for (const auto& ctx : m_contexts) {
3127 s_egl.eglPreSaveContext(m_eglDisplay, ctx.second->getEGLContext(),
3128 stream);
3129 }
3130 s_egl.eglSaveAllImages(m_eglDisplay, stream, &textureSaver);
3131 }
3132 // Don't save subWindow's x/y/w/h here - those are related to the current
3133 // emulator UI state, not guest state that we're saving.
3134 stream->putBe32(m_framebufferWidth);
3135 stream->putBe32(m_framebufferHeight);
3136 stream->putFloat(m_dpr);
3137
3138 stream->putBe32(m_useSubWindow);
3139 stream->putBe32(m_eglContextInitialized);
3140
3141 stream->putBe32(m_fpsStats);
3142 stream->putBe32(m_statsNumFrames);
3143 stream->putBe64(m_statsStartTime);
3144
3145 // Save all contexts.
3146 // Note: some of the contexts might not be restored yet. In such situation
3147 // we skip reading from GPU (for non-texture objects) or force a restore in
3148 // previous eglPreSaveContext and eglSaveAllImages calls (for texture
3149 // objects).
3150 // TODO: skip reading from GPU even for texture objects.
3151 saveCollection(stream, m_contexts,
3152 [](Stream* s, const RenderContextMap::value_type& pair) {
3153 pair.second->onSave(s);
3154 });
3155
3156 // We don't need to save |m_colorBufferCloseTsMap| here - there's enough
3157 // information to reconstruct it when loading.
3158 uint64_t now = android::base::getUnixTimeUs();
3159
3160 saveCollection(stream, m_colorbuffers,
3161 [now](Stream* s, const ColorBufferMap::value_type& pair) {
3162 pair.second.cb->onSave(s);
3163 s->putBe32(pair.second.refcount);
3164 s->putByte(pair.second.opened);
3165 s->putBe32(std::max<uint64_t>(0, now - pair.second.closedTs));
3166 });
3167 stream->putBe32(m_lastPostedColorBuffer);
3168 saveCollection(stream, m_windows,
3169 [](Stream* s, const WindowSurfaceMap::value_type& pair) {
3170 pair.second.first->onSave(s);
3171 s->putBe32(pair.second.second); // Color buffer handle.
3172 });
3173
3174 saveProcOwnedCollection(stream, m_procOwnedWindowSurfaces);
3175 saveProcOwnedCollection(stream, m_procOwnedColorBuffers);
3176 saveProcOwnedCollection(stream, m_procOwnedEGLImages);
3177 saveProcOwnedCollection(stream, m_procOwnedRenderContext);
3178
3179 // Save Vulkan state
3180 if (feature_is_enabled(kFeature_VulkanSnapshots) &&
3181 goldfish_vk::VkDecoderGlobalState::get()) {
3182 goldfish_vk::VkDecoderGlobalState::get()->save(stream);
3183 }
3184
3185 if (s_egl.eglPostSaveContext) {
3186 for (const auto& ctx : m_contexts) {
3187 s_egl.eglPostSaveContext(m_eglDisplay, ctx.second->getEGLContext(),
3188 stream);
3189 }
3190 // We need to run the post save step for m_eglContext and m_pbufContext
3191 // to mark their texture handles dirty
3192 if (m_eglContext != EGL_NO_CONTEXT) {
3193 s_egl.eglPostSaveContext(m_eglDisplay, m_eglContext, stream);
3194 }
3195 if (m_pbufContext != EGL_NO_CONTEXT) {
3196 s_egl.eglPostSaveContext(m_eglDisplay, m_pbufContext, stream);
3197 }
3198 }
3199
3200 }
3201
onLoad(Stream * stream,const android::snapshot::ITextureLoaderPtr & textureLoader)3202 bool FrameBuffer::onLoad(Stream* stream,
3203 const android::snapshot::ITextureLoaderPtr& textureLoader) {
3204 AutoLock lock(m_lock);
3205 // cleanups
3206 {
3207 sweepColorBuffersLocked();
3208
3209 ScopedBind scopedBind(m_colorBufferHelper);
3210 if (m_procOwnedWindowSurfaces.empty() &&
3211 m_procOwnedColorBuffers.empty() && m_procOwnedEGLImages.empty() &&
3212 m_procOwnedRenderContext.empty() &&
3213 m_procOwnedCleanupCallbacks.empty() &&
3214 (!m_contexts.empty() || !m_windows.empty() ||
3215 m_colorbuffers.size() > m_colorBufferDelayedCloseList.size())) {
3216 // we are likely on a legacy system image, which does not have
3217 // process owned objects. We need to force cleanup everything
3218 m_contexts.clear();
3219 m_windows.clear();
3220 m_colorbuffers.clear();
3221 } else {
3222 std::vector<HandleType> colorBuffersToCleanup;
3223
3224 while (m_procOwnedWindowSurfaces.size()) {
3225 auto cleanupHandles = cleanupProcGLObjects_locked(
3226 m_procOwnedWindowSurfaces.begin()->first, true);
3227 colorBuffersToCleanup.insert(colorBuffersToCleanup.end(),
3228 cleanupHandles.begin(), cleanupHandles.end());
3229 }
3230 while (m_procOwnedColorBuffers.size()) {
3231 auto cleanupHandles = cleanupProcGLObjects_locked(
3232 m_procOwnedColorBuffers.begin()->first, true);
3233 colorBuffersToCleanup.insert(colorBuffersToCleanup.end(),
3234 cleanupHandles.begin(), cleanupHandles.end());
3235 }
3236 while (m_procOwnedEGLImages.size()) {
3237 auto cleanupHandles = cleanupProcGLObjects_locked(
3238 m_procOwnedEGLImages.begin()->first, true);
3239 colorBuffersToCleanup.insert(colorBuffersToCleanup.end(),
3240 cleanupHandles.begin(), cleanupHandles.end());
3241 }
3242 while (m_procOwnedRenderContext.size()) {
3243 auto cleanupHandles = cleanupProcGLObjects_locked(
3244 m_procOwnedRenderContext.begin()->first, true);
3245 colorBuffersToCleanup.insert(colorBuffersToCleanup.end(),
3246 cleanupHandles.begin(), cleanupHandles.end());
3247 }
3248
3249 std::vector<std::function<void()>> cleanupCallbacks;
3250
3251 while (m_procOwnedCleanupCallbacks.size()) {
3252 auto it = m_procOwnedCleanupCallbacks.begin();
3253 while (it != m_procOwnedCleanupCallbacks.end()) {
3254 for (auto it2 : it->second) {
3255 cleanupCallbacks.push_back(it2.second);
3256 }
3257 it = m_procOwnedCleanupCallbacks.erase(it);
3258 }
3259 }
3260
3261 while (m_procOwnedSequenceNumbers.size()) {
3262 auto it = m_procOwnedSequenceNumbers.begin();
3263 while (it != m_procOwnedSequenceNumbers.end()) {
3264 delete it->second;
3265 it = m_procOwnedSequenceNumbers.erase(it);
3266 }
3267 }
3268
3269 performDelayedColorBufferCloseLocked(true);
3270
3271 lock.unlock();
3272
3273 for (auto colorBufferHandle : colorBuffersToCleanup) {
3274 goldfish_vk::teardownVkColorBuffer(colorBufferHandle);
3275 }
3276
3277 for (auto cb : cleanupCallbacks) {
3278 cb();
3279 }
3280
3281 lock.lock();
3282 }
3283 m_colorBufferDelayedCloseList.clear();
3284 assert(m_contexts.empty());
3285 assert(m_windows.empty());
3286 if (!m_colorbuffers.empty()) {
3287 ERR("warning: on load, stale colorbuffers: %zu", m_colorbuffers.size());
3288 m_colorbuffers.clear();
3289 }
3290 assert(m_colorbuffers.empty());
3291 #ifdef SNAPSHOT_PROFILE
3292 uint64_t texTime = android::base::getUnixTimeUs();
3293 #endif
3294 if (s_egl.eglLoadAllImages) {
3295 s_egl.eglLoadAllImages(m_eglDisplay, stream, &textureLoader);
3296 }
3297 #ifdef SNAPSHOT_PROFILE
3298 printf("Texture load time: %lld ms\n",
3299 (long long)(android::base::getUnixTimeUs() - texTime) / 1000);
3300 #endif
3301 }
3302 // See comment about subwindow position in onSave().
3303 m_framebufferWidth = stream->getBe32();
3304 m_framebufferHeight = stream->getBe32();
3305 m_dpr = stream->getFloat();
3306 // TODO: resize the window
3307 //
3308 m_useSubWindow = stream->getBe32();
3309 m_eglContextInitialized = stream->getBe32();
3310
3311 m_fpsStats = stream->getBe32();
3312 m_statsNumFrames = stream->getBe32();
3313 m_statsStartTime = stream->getBe64();
3314
3315 loadCollection(stream, &m_contexts,
3316 [this](Stream* stream) -> RenderContextMap::value_type {
3317 RenderContextPtr ctx(RenderContext::onLoad(stream, m_eglDisplay));
3318 return { ctx ? ctx->getHndl() : 0, ctx };
3319 });
3320 assert(!android::base::find(m_contexts, 0));
3321
3322 auto now = android::base::getUnixTimeUs();
3323 loadCollection(stream, &m_colorbuffers,
3324 [this, now](Stream* stream) -> ColorBufferMap::value_type {
3325 ColorBufferPtr cb(ColorBuffer::onLoad(stream, m_eglDisplay,
3326 m_colorBufferHelper,
3327 m_fastBlitSupported));
3328 const HandleType handle = cb->getHndl();
3329 const unsigned refCount = stream->getBe32();
3330 const bool opened = stream->getByte();
3331 const uint64_t closedTs = now - stream->getBe32();
3332 if (refCount == 0) {
3333 m_colorBufferDelayedCloseList.push_back({closedTs, handle});
3334 }
3335 return {handle, ColorBufferRef{std::move(cb), refCount, opened,
3336 closedTs}};
3337 });
3338 m_lastPostedColorBuffer = static_cast<HandleType>(stream->getBe32());
3339 GL_LOG("Got lasted posted color buffer from snapshot");
3340
3341 loadCollection(stream, &m_windows,
3342 [this](Stream* stream) -> WindowSurfaceMap::value_type {
3343 WindowSurfacePtr window(WindowSurface::onLoad(stream, m_eglDisplay));
3344 HandleType handle = window->getHndl();
3345 HandleType colorBufferHandle = stream->getBe32();
3346 return { handle, { std::move(window), colorBufferHandle } };
3347 });
3348
3349 loadProcOwnedCollection(stream, &m_procOwnedWindowSurfaces);
3350 loadProcOwnedCollection(stream, &m_procOwnedColorBuffers);
3351 loadProcOwnedCollection(stream, &m_procOwnedEGLImages);
3352 loadProcOwnedCollection(stream, &m_procOwnedRenderContext);
3353
3354 if (s_egl.eglPostLoadAllImages) {
3355 s_egl.eglPostLoadAllImages(m_eglDisplay, stream);
3356 }
3357
3358 registerTriggerWait();
3359
3360 {
3361 ScopedBind scopedBind(m_colorBufferHelper);
3362 for (auto& it : m_colorbuffers) {
3363 if (it.second.cb) {
3364 it.second.cb->touch();
3365 }
3366 }
3367 }
3368
3369 // Restore Vulkan state
3370 if (feature_is_enabled(kFeature_VulkanSnapshots) &&
3371 goldfish_vk::VkDecoderGlobalState::get()) {
3372
3373 lock.unlock();
3374 goldfish_vk::VkDecoderGlobalState::get()->load(stream);
3375 lock.lock();
3376
3377 }
3378
3379 return true;
3380 // TODO: restore memory management
3381 }
3382
lock()3383 void FrameBuffer::lock() {
3384 m_lock.lock();
3385 }
3386
unlock()3387 void FrameBuffer::unlock() {
3388 m_lock.unlock();
3389 }
3390
findColorBuffer(HandleType p_colorbuffer)3391 ColorBufferPtr FrameBuffer::findColorBuffer(HandleType p_colorbuffer) {
3392 ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
3393 if (c == m_colorbuffers.end()) {
3394 return nullptr;
3395 }
3396 else {
3397 return c->second.cb;
3398 }
3399 }
3400
registerProcessCleanupCallback(void * key,std::function<void ()> cb)3401 void FrameBuffer::registerProcessCleanupCallback(void* key, std::function<void()> cb) {
3402 AutoLock mutex(m_lock);
3403 RenderThreadInfo* tInfo = RenderThreadInfo::get();
3404 if (!tInfo) return;
3405
3406 auto& callbackMap = m_procOwnedCleanupCallbacks[tInfo->m_puid];
3407 callbackMap[key] = cb;
3408 }
3409
unregisterProcessCleanupCallback(void * key)3410 void FrameBuffer::unregisterProcessCleanupCallback(void* key) {
3411 AutoLock mutex(m_lock);
3412 RenderThreadInfo* tInfo = RenderThreadInfo::get();
3413 if (!tInfo) return;
3414
3415 auto& callbackMap = m_procOwnedCleanupCallbacks[tInfo->m_puid];
3416 if (callbackMap.find(key) == callbackMap.end()) {
3417 ERR("warning: tried to erase nonexistent key %p "
3418 "associated with process %llu",
3419 key, (unsigned long long)(tInfo->m_puid));
3420 }
3421 callbackMap.erase(key);
3422 }
3423
registerProcessSequenceNumberForPuid(uint64_t puid)3424 void FrameBuffer::registerProcessSequenceNumberForPuid(uint64_t puid) {
3425 AutoLock mutex(m_lock);
3426
3427 auto procIte = m_procOwnedSequenceNumbers.find(puid);
3428 if (procIte != m_procOwnedSequenceNumbers.end()) {
3429 return;
3430 }
3431 uint32_t* seqnoPtr = new uint32_t;
3432 *seqnoPtr = 0;
3433 m_procOwnedSequenceNumbers[puid] = seqnoPtr;
3434 }
3435
getProcessSequenceNumberPtr(uint64_t puid)3436 uint32_t* FrameBuffer::getProcessSequenceNumberPtr(uint64_t puid) {
3437 AutoLock mutex(m_lock);
3438
3439 auto procIte = m_procOwnedSequenceNumbers.find(puid);
3440 if (procIte != m_procOwnedSequenceNumbers.end()) {
3441 return procIte->second;
3442 }
3443 return nullptr;
3444 }
3445
createDisplay(uint32_t * displayId)3446 int FrameBuffer::createDisplay(uint32_t *displayId) {
3447 return emugl::get_emugl_multi_display_operations().createDisplay(displayId);
3448 }
3449
createDisplay(uint32_t displayId)3450 int FrameBuffer::createDisplay(uint32_t displayId) {
3451 return emugl::get_emugl_multi_display_operations().createDisplay(&displayId);
3452 }
3453
destroyDisplay(uint32_t displayId)3454 int FrameBuffer::destroyDisplay(uint32_t displayId) {
3455 return emugl::get_emugl_multi_display_operations().destroyDisplay(displayId);
3456 }
3457
setDisplayColorBuffer(uint32_t displayId,uint32_t colorBuffer)3458 int FrameBuffer::setDisplayColorBuffer(uint32_t displayId, uint32_t colorBuffer) {
3459 return emugl::get_emugl_multi_display_operations().
3460 setDisplayColorBuffer(displayId, colorBuffer);
3461 }
3462
getDisplayColorBuffer(uint32_t displayId,uint32_t * colorBuffer)3463 int FrameBuffer::getDisplayColorBuffer(uint32_t displayId, uint32_t* colorBuffer) {
3464 return emugl::get_emugl_multi_display_operations().
3465 getDisplayColorBuffer(displayId, colorBuffer);
3466 }
3467
getColorBufferDisplay(uint32_t colorBuffer,uint32_t * displayId)3468 int FrameBuffer::getColorBufferDisplay(uint32_t colorBuffer, uint32_t* displayId) {
3469 return emugl::get_emugl_multi_display_operations().
3470 getColorBufferDisplay(colorBuffer, displayId);
3471 }
3472
getDisplayPose(uint32_t displayId,int32_t * x,int32_t * y,uint32_t * w,uint32_t * h)3473 int FrameBuffer::getDisplayPose(uint32_t displayId,
3474 int32_t* x,
3475 int32_t* y,
3476 uint32_t* w,
3477 uint32_t* h) {
3478 return emugl::get_emugl_multi_display_operations().
3479 getDisplayPose(displayId, x, y, w, h);
3480 }
3481
setDisplayPose(uint32_t displayId,int32_t x,int32_t y,uint32_t w,uint32_t h,uint32_t dpi)3482 int FrameBuffer::setDisplayPose(uint32_t displayId,
3483 int32_t x,
3484 int32_t y,
3485 uint32_t w,
3486 uint32_t h,
3487 uint32_t dpi) {
3488 return emugl::get_emugl_multi_display_operations().
3489 setDisplayPose(displayId, x, y, w, h, dpi);
3490 }
3491
sweepColorBuffersLocked()3492 void FrameBuffer::sweepColorBuffersLocked() {
3493 HandleType handleToDestroy;
3494 while (mOutstandingColorBufferDestroys.tryReceive(&handleToDestroy)) {
3495 bool needCleanup = decColorBufferRefCountLocked(handleToDestroy);
3496 if (needCleanup) {
3497 m_lock.unlock();
3498 goldfish_vk::teardownVkColorBuffer(handleToDestroy);
3499 m_lock.lock();
3500 }
3501 }
3502 }
3503
waitForGpu(uint64_t eglsync)3504 void FrameBuffer::waitForGpu(uint64_t eglsync) {
3505 FenceSync* fenceSync = FenceSync::getFromHandle(eglsync);
3506
3507 if (!fenceSync) {
3508 ERR("err: fence sync 0x%llx not found", (unsigned long long)eglsync);
3509 return;
3510 }
3511
3512 SyncThread::get()->triggerBlockedWaitNoTimeline(fenceSync);
3513 }
3514
waitForGpuVulkan(uint64_t deviceHandle,uint64_t fenceHandle)3515 void FrameBuffer::waitForGpuVulkan(uint64_t deviceHandle, uint64_t fenceHandle) {
3516 (void)deviceHandle;
3517
3518 // Note: this will always be nullptr.
3519 FenceSync* fenceSync = FenceSync::getFromHandle(fenceHandle);
3520
3521 // Note: This will always signal right away.
3522 SyncThread::get()->triggerBlockedWaitNoTimeline(fenceSync);
3523 }
3524
asyncWaitForGpuWithCb(uint64_t eglsync,FenceCompletionCallback cb)3525 void FrameBuffer::asyncWaitForGpuWithCb(uint64_t eglsync, FenceCompletionCallback cb) {
3526 FenceSync* fenceSync = FenceSync::getFromHandle(eglsync);
3527
3528 if (!fenceSync) {
3529 ERR("err: fence sync 0x%llx not found", (unsigned long long)eglsync);
3530 return;
3531 }
3532
3533 SyncThread::get()->triggerWaitWithCompletionCallback(fenceSync, std::move(cb));
3534 }
3535
asyncWaitForGpuVulkanWithCb(uint64_t deviceHandle,uint64_t fenceHandle,FenceCompletionCallback cb)3536 void FrameBuffer::asyncWaitForGpuVulkanWithCb(uint64_t deviceHandle, uint64_t fenceHandle, FenceCompletionCallback cb) {
3537 (void)deviceHandle;
3538 SyncThread::get()->triggerWaitVkWithCompletionCallback((VkFence)fenceHandle, std::move(cb));
3539 }
3540
asyncWaitForGpuVulkanQsriWithCb(uint64_t image,FenceCompletionCallback cb)3541 void FrameBuffer::asyncWaitForGpuVulkanQsriWithCb(uint64_t image, FenceCompletionCallback cb) {
3542 SyncThread::get()->triggerWaitVkQsriWithCompletionCallback((VkImage)image, std::move(cb));
3543 }
3544
waitForGpuVulkanQsri(uint64_t image)3545 void FrameBuffer::waitForGpuVulkanQsri(uint64_t image) {
3546 (void)image;
3547 // Signal immediately, because this was a sync wait and it's vulkan.
3548 SyncThread::get()->triggerBlockedWaitNoTimeline(nullptr);
3549 }
3550
setGuestManagedColorBufferLifetime(bool guestManaged)3551 void FrameBuffer::setGuestManagedColorBufferLifetime(bool guestManaged) {
3552 m_guestManagedColorBufferLifetime = guestManaged;
3553 }
3554
getVkImageLayoutForComposeLayer() const3555 VkImageLayout FrameBuffer::getVkImageLayoutForComposeLayer() const {
3556 if (m_displayVk) {
3557 return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3558 }
3559 return VK_IMAGE_LAYOUT_GENERAL;
3560 }
3561
platformImportResource(uint32_t handle,uint32_t type,void * resource)3562 bool FrameBuffer::platformImportResource(uint32_t handle, uint32_t type, void* resource) {
3563 if (!resource) {
3564 ERR("Error: resource was null");
3565 }
3566
3567 AutoLock mutex(m_lock);
3568
3569 ColorBufferMap::iterator c(m_colorbuffers.find(handle));
3570 if (c == m_colorbuffers.end()) {
3571 ERR("Error: resource %u not found as a ColorBuffer", handle);
3572 return false;
3573 }
3574
3575 switch (type) {
3576 case RESOURCE_TYPE_EGL_NATIVE_PIXMAP:
3577 return (*c).second.cb->importEglNativePixmap(resource);
3578 case RESOURCE_TYPE_EGL_IMAGE:
3579 return (*c).second.cb->importEglImage(resource);
3580 default:
3581 ERR("Error: unsupported resource type: %u", type);
3582 return false;
3583 }
3584
3585 return true;
3586 }
3587
platformCreateSharedEglContext(void)3588 void* FrameBuffer::platformCreateSharedEglContext(void) {
3589 AutoLock lock(m_lock);
3590
3591 EGLContext context = 0;
3592 EGLSurface surface = 0;
3593 createSharedTrivialContext(&context, &surface);
3594
3595 void* underlyingContext = s_egl.eglGetNativeContextANDROID(m_eglDisplay, context);
3596 if (!underlyingContext) {
3597 ERR("Error: Underlying egl backend could not produce a native EGL context.");
3598 return nullptr;
3599 }
3600
3601 m_platformEglContexts[underlyingContext] = { context, surface };
3602
3603 return underlyingContext;
3604 }
3605
platformDestroySharedEglContext(void * underlyingContext)3606 bool FrameBuffer::platformDestroySharedEglContext(void* underlyingContext) {
3607 AutoLock lock(m_lock);
3608
3609 auto it = m_platformEglContexts.find(underlyingContext);
3610 if (it == m_platformEglContexts.end()) {
3611 ERR("Error: Could not find underlying egl context %p (perhaps already destroyed?)", underlyingContext);
3612 return false;
3613 }
3614
3615 destroySharedTrivialContext(it->second.context, it->second.surface);
3616
3617 m_platformEglContexts.erase(it);
3618
3619 return true;
3620 }
3621