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