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