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