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