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