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