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