Merge "Revert "gfxstream: introduce GFXSTREAM_ENABLE_HOST_GLES compiler flag"" into main
diff --git a/Android.bp b/Android.bp
index a4ce1a4..b67833a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -123,7 +123,6 @@
         "-DUSING_ANDROID_BP",
         "-D_FILE_OFFSET_BITS=64",
         "-DVK_GFXSTREAM_STRUCTURE_TYPE_EXT",
-        "-DGFXSTREAM_ENABLE_HOST_GLES=1",
         "-Wno-unreachable-code-loop-increment",
         "-Wno-unused-parameter",
         "-Wno-unused-function",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6a29a17..b23070c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -41,8 +41,6 @@
 if(VIRGL_RENDERER_UNSTABLE_APIS)
     add_definitions(-DVIRGL_RENDERER_UNSTABLE_APIS)
 endif()
-    
-add_definitions(-DGFXSTREAM_ENABLE_HOST_GLES=1)
 
 option(ASTC_CPU_DECODING "Enable decoding ASTC textures on the CPU" OFF)
 
diff --git a/host/Buffer.cpp b/host/Buffer.cpp
index b60a1ec..1858924 100644
--- a/host/Buffer.cpp
+++ b/host/Buffer.cpp
@@ -14,10 +14,7 @@
 
 #include "Buffer.h"
 
-#if GFXSTREAM_ENABLE_HOST_GLES
 #include "gl/EmulationGl.h"
-#endif
-
 #include "vulkan/BufferVk.h"
 #include "vulkan/VkCommonOperations.h"
 
@@ -34,7 +31,6 @@
                                        uint64_t size, HandleType handle) {
     std::shared_ptr<Buffer> buffer(new Buffer(handle, size));
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (emulationGl) {
         buffer->mBufferGl = emulationGl->createBuffer(size, handle);
         if (!buffer->mBufferGl) {
@@ -42,7 +38,6 @@
             return nullptr;
         }
     }
-#endif
 
     if (emulationVk && emulationVk->live) {
         const bool vulkanOnly = emulationGl == nullptr;
@@ -54,11 +49,10 @@
         }
 
         if (!vulkanOnly) {
-#if GFXSTREAM_ENABLE_HOST_GLES
             if (!buffer->mBufferGl) {
                 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Missing BufferGl?";
             }
-#endif
+
             // TODO: external memory sharing.
         }
     }
@@ -74,7 +68,6 @@
 
     std::shared_ptr<Buffer> buffer(new Buffer(handle, size));
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (emulationGl) {
         buffer->mBufferGl = emulationGl->loadBuffer(stream);
         if (!buffer->mBufferGl) {
@@ -82,7 +75,6 @@
             return nullptr;
         }
     }
-#endif
 
     buffer->mNeedRestore = true;
 
@@ -93,11 +85,9 @@
     stream->putBe32(mHandle);
     stream->putBe64(mSize);
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (mBufferGl) {
         mBufferGl->onSave(stream);
     }
-#endif
 }
 
 void Buffer::restore() {}
@@ -105,13 +95,10 @@
 void Buffer::readToBytes(uint64_t offset, uint64_t size, void* outBytes) {
     touch();
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (mBufferGl) {
         mBufferGl->read(offset, size, outBytes);
         return;
     }
-#endif
-
     if (mBufferVk) {
         mBufferVk->readToBytes(offset, size, outBytes);
         return;
@@ -123,13 +110,10 @@
 bool Buffer::updateFromBytes(uint64_t offset, uint64_t size, const void* bytes) {
     touch();
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (mBufferGl) {
         mBufferGl->subUpdate(offset, size, bytes);
         return true;
     }
-#endif
-
     if (mBufferVk) {
         return mBufferVk->updateFromBytes(offset, size, bytes);
     }
diff --git a/host/Buffer.h b/host/Buffer.h
index 414ff05..5db0db3 100644
--- a/host/Buffer.h
+++ b/host/Buffer.h
@@ -18,11 +18,8 @@
 
 #include "Handle.h"
 #include "aemu/base/files/Stream.h"
-#include "snapshot/LazySnapshotObj.h"
-
-#if GFXSTREAM_ENABLE_HOST_GLES
 #include "gl/BufferGl.h"
-#endif
+#include "snapshot/LazySnapshotObj.h"
 
 namespace gfxstream {
 namespace gl {
@@ -64,10 +61,8 @@
     const uint64_t mSize;
     const HandleType mHandle;
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     // If GL emulation is enabled.
     std::unique_ptr<gl::BufferGl> mBufferGl;
-#endif
 
     // If Vk emulation is enabled.
     std::unique_ptr<vk::BufferVk> mBufferVk;
diff --git a/host/ColorBuffer.cpp b/host/ColorBuffer.cpp
index 3cdecbf..6a8f58d 100644
--- a/host/ColorBuffer.cpp
+++ b/host/ColorBuffer.cpp
@@ -14,10 +14,7 @@
 
 #include "ColorBuffer.h"
 
-#if GFXSTREAM_ENABLE_HOST_GLES
 #include "gl/EmulationGl.h"
-#endif
-
 #include "host-common/GfxstreamFatalError.h"
 #include "host-common/logging.h"
 #include "vulkan/ColorBufferVk.h"
@@ -58,7 +55,6 @@
     std::shared_ptr<ColorBuffer> colorBuffer(
         new ColorBuffer(handle, width, height, format, frameworkFormat));
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (emulationGl) {
         colorBuffer->mColorBufferGl =
             emulationGl->createColorBuffer(width, height, format, frameworkFormat, handle);
@@ -67,7 +63,6 @@
             return nullptr;
         }
     }
-#endif
 
     if (emulationVk && emulationVk->live) {
         const bool vulkanOnly = colorBuffer->mColorBufferGl == nullptr;
@@ -86,7 +81,6 @@
         }
     }
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     bool b271028352Workaround = emulationGl && strstr(emulationGl->getGlesRenderer().c_str(), "Intel");
 
     if (colorBuffer->mColorBufferGl && colorBuffer->mColorBufferVk &&
@@ -103,7 +97,6 @@
             }
         }
     }
-#endif
 
     return colorBuffer;
 }
@@ -120,7 +113,6 @@
     std::shared_ptr<ColorBuffer> colorBuffer(
         new ColorBuffer(handle, width, height, format, frameworkFormat));
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (emulationGl) {
         colorBuffer->mColorBufferGl = emulationGl->loadColorBuffer(stream);
         if (!colorBuffer->mColorBufferGl) {
@@ -128,7 +120,6 @@
             return nullptr;
         }
     }
-#endif
 
     colorBuffer->mNeedRestore = true;
 
@@ -142,32 +133,25 @@
     stream->putBe32(static_cast<uint32_t>(mFormat));
     stream->putBe32(static_cast<uint32_t>(mFrameworkFormat));
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (mColorBufferGl) {
         mColorBufferGl->onSave(stream);
     }
-#endif
 }
 
 void ColorBuffer::restore() {
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (mColorBufferGl) {
         mColorBufferGl->restore();
     }
-#endif
 }
 
 void ColorBuffer::readToBytes(int x, int y, int width, int height, GLenum pixelsFormat,
                               GLenum pixelsType, void* outPixels) {
     touch();
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (mColorBufferGl) {
         mColorBufferGl->readPixels(x, y, width, height, pixelsFormat, pixelsType, outPixels);
         return;
     }
-#endif
-
     if (mColorBufferVk) {
         mColorBufferVk->readToBytes(x, y, width, height, outPixels);
         return;
@@ -181,13 +165,11 @@
                                     void* outPixels) {
     touch();
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (mColorBufferGl) {
         mColorBufferGl->readPixelsScaled(pixelsWidth, pixelsHeight, pixelsFormat, pixelsType,
                                          pixelsRotation, rect, outPixels);
         return;
     }
-#endif
 
     GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Unimplemented.";
 }
@@ -196,13 +178,10 @@
                                  uint32_t pixelsSize) {
     touch();
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (mColorBufferGl) {
         mColorBufferGl->readPixelsYUVCached(x, y, width, height, outPixels, pixelsSize);
         return;
     }
-#endif
-
     if (mColorBufferVk) {
         mColorBufferVk->readToBytes(x, y, width, height, outPixels);
         return;
@@ -216,14 +195,11 @@
                                   GLenum pixelsType, const void* pixels, void* metadata) {
     touch();
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (mColorBufferGl) {
         mColorBufferGl->subUpdateFromFrameworkFormat(x, y, width, height, frameworkFormat,
                                                      pixelsFormat, pixelsType, pixels, metadata);
         return true;
     }
-#endif
-
     if (mColorBufferVk) {
         return mColorBufferVk->updateFromBytes(x, y, width, height, pixels);
     }
@@ -236,12 +212,9 @@
                                   GLenum pixelsType, const void* pixels) {
     touch();
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (mColorBufferGl) {
         return mColorBufferGl->subUpdate(x, y, width, height, pixelsFormat, pixelsType, pixels);
     }
-#endif
-
     if (mColorBufferVk) {
         return mColorBufferVk->updateFromBytes(x, y, width, height, pixels);
     }
@@ -251,13 +224,11 @@
 }
 
 bool ColorBuffer::updateGlFromBytes(const void* bytes, std::size_t bytesSize) {
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (mColorBufferGl) {
         touch();
 
         return mColorBufferGl->replaceContents(bytes, bytesSize);
     }
-#endif
 
     return true;
 }
@@ -265,12 +236,10 @@
 std::unique_ptr<BorrowedImageInfo> ColorBuffer::borrowForComposition(UsedApi api, bool isTarget) {
     switch (api) {
         case UsedApi::kGl: {
-#if GFXSTREAM_ENABLE_HOST_GLES
             if (!mColorBufferGl) {
                 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
             }
             return mColorBufferGl->getBorrowedImageInfo();
-#endif
         }
         case UsedApi::kVk: {
             if (!mColorBufferVk) {
@@ -286,12 +255,10 @@
 std::unique_ptr<BorrowedImageInfo> ColorBuffer::borrowForDisplay(UsedApi api) {
     switch (api) {
         case UsedApi::kGl: {
-#if GFXSTREAM_ENABLE_HOST_GLES
             if (!mColorBufferGl) {
                 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
             }
             return mColorBufferGl->getBorrowedImageInfo();
-#endif
         }
         case UsedApi::kVk: {
             if (!mColorBufferVk) {
@@ -326,6 +293,7 @@
     if (mGlAndVkAreSharingExternalMemory) {
         return true;
     }
+
     std::vector<uint8_t> contents;
     if (!vk::readColorBufferToBytes(mHandle, &contents)) {
         ERR("Failed to get VK contents for ColorBuffer:%d", mHandle);
@@ -336,12 +304,10 @@
         return false;
     }
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (!mColorBufferGl->replaceContents(contents.data(), contents.size())) {
         ERR("Failed to set GL contents for ColorBuffer:%d", mHandle);
         return false;
     }
-#endif
 
     return true;
 }
@@ -355,14 +321,12 @@
         return true;
     }
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (mColorBufferGl) {
         if (!mColorBufferGl->replaceContents(bytes, bytesSize)) {
             ERR("Failed to update ColorBuffer:%d GL backing from VK bytes.", mHandle);
             return false;
         }
     }
-#endif
 
     return true;
 }
@@ -390,7 +354,6 @@
         return true;
     }
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     std::size_t contentsSize = 0;
     if (!mColorBufferGl->readContents(&contentsSize, nullptr)) {
         ERR("Failed to get GL contents size for ColorBuffer:%d", mHandle);
@@ -408,7 +371,6 @@
         ERR("Failed to set VK contents for ColorBuffer:%d", mHandle);
         return false;
     }
-#endif
 
     return true;
 }
@@ -437,7 +399,6 @@
     }
 }
 
-#if GFXSTREAM_ENABLE_HOST_GLES
 bool ColorBuffer::glOpBlitFromCurrentReadBuffer() {
     if (!mColorBufferGl) {
         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
@@ -568,6 +529,5 @@
 
     mColorBufferGl->postViewportScaledWithOverlay(rotation, dx, dy);
 }
-#endif
 
 }  // namespace gfxstream
diff --git a/host/ColorBuffer.h b/host/ColorBuffer.h
index 7056267..f519fe7 100644
--- a/host/ColorBuffer.h
+++ b/host/ColorBuffer.h
@@ -21,15 +21,10 @@
 #include "Handle.h"
 #include "Hwc2.h"
 #include "aemu/base/files/Stream.h"
+#include "gl/ColorBufferGl.h"
 #include "render-utils/Renderer.h"
 #include "snapshot/LazySnapshotObj.h"
 
-#if GFXSTREAM_ENABLE_HOST_GLES
-#include "gl/ColorBufferGl.h"
-#else
-#include "GlesCompat.h"
-#endif
-
 namespace gfxstream {
 namespace gl {
 class EmulationGl;
@@ -91,7 +86,6 @@
     bool invalidateForVk();
     bool importNativeResource(void* nativeResource, uint32_t type, bool preserveContent);
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     GLuint glOpGetTexture();
     bool glOpBlitFromCurrentReadBuffer();
     bool glOpBindToTexture();
@@ -107,7 +101,6 @@
     bool glOpIsFastBlitSupported() const;
     void glOpPostLayer(const ComposeLayer& l, int frameWidth, int frameHeight);
     void glOpPostViewportScaledWithOverlay(float rotation, float dx, float dy);
-#endif
 
    private:
     ColorBuffer(HandleType, uint32_t width, uint32_t height, GLenum format,
@@ -119,12 +112,8 @@
     const GLenum mFormat;
     const FrameworkFormat mFrameworkFormat;
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     // If GL emulation is enabled.
     std::unique_ptr<gl::ColorBufferGl> mColorBufferGl;
-#else
-    std::unique_ptr<uint32_t> mColorBufferGl = nullptr;
-#endif
 
     // If Vk emulation is enabled.
     std::unique_ptr<vk::ColorBufferVk> mColorBufferVk;
diff --git a/host/FrameBuffer.cpp b/host/FrameBuffer.cpp
index 54f78b9..f7f0016 100644
--- a/host/FrameBuffer.cpp
+++ b/host/FrameBuffer.cpp
@@ -27,9 +27,15 @@
 #endif
 
 #include "ContextHelper.h"
+#include "GLESVersionDetector.h"
 #include "Hwc2.h"
 #include "NativeSubWindow.h"
+#include "OpenGLESDispatch/DispatchTables.h"
+#include "OpenGLESDispatch/EGLDispatch.h"
+#include "PostWorkerGl.h"
+#include "RenderControl.h"
 #include "RenderThreadInfo.h"
+#include "RenderThreadInfoGl.h"
 #include "SyncThread.h"
 #include "aemu/base/LayoutResolver.h"
 #include "aemu/base/Metrics.h"
@@ -40,19 +46,9 @@
 #include "aemu/base/memory/MemoryTracker.h"
 #include "aemu/base/synchronization/Lock.h"
 #include "aemu/base/system/System.h"
-
-#if GFXSTREAM_ENABLE_HOST_GLES
-#include "GLESVersionDetector.h"
-#include "OpenGLESDispatch/DispatchTables.h"
-#include "OpenGLESDispatch/EGLDispatch.h"
-#include "PostWorkerGl.h"
-#include "RenderControl.h"
-#include "RenderThreadInfoGl.h"
 #include "gl/YUVConverter.h"
 #include "gl/gles2_dec/gles2_dec.h"
 #include "gl/glestranslator/EGL/EglGlobalInfo.h"
-#endif
-
 #include "host-common/GfxstreamFatalError.h"
 #include "host-common/crash_reporter.h"
 #include "host-common/feature_control.h"
@@ -77,8 +73,6 @@
 using emugl::CreateHealthMonitor;
 using emugl::FatalError;
 using emugl::GfxApiLogger;
-
-#if GFXSTREAM_ENABLE_HOST_GLES
 using gl::DisplaySurfaceGl;
 using gl::EmulatedEglConfig;
 using gl::EmulatedEglConfigList;
@@ -101,7 +95,6 @@
 using gl::TextureDraw;
 using gl::YUVConverter;
 using gl::YUVPlane;
-#endif
 
 using gfxstream::vk::AstcEmulationMode;
 using gfxstream::vk::VkEmulationFeatures;
@@ -334,7 +327,6 @@
         }
     }
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     // Do not initialize GL emulation if the guest is using ANGLE.
     if (!feature_is_enabled(kFeature_GuestUsesAngle)) {
         fb->m_emulationGl = EmulationGl::create(width, height, useSubWindow, egl2egl);
@@ -343,7 +335,6 @@
             return false;
         }
     }
-#endif
 
     fb->m_guestUsesAngle =
         feature_is_enabled(
@@ -413,13 +404,11 @@
 
         fb->m_graphicsDeviceExtensions = deviceExtensionsStringBuilder.str();
     } else if (fb->m_emulationGl) {
-#if GFXSTREAM_ENABLE_HOST_GLES
         fb->m_graphicsAdapterVendor = fb->m_emulationGl->getGlesVendor();
         fb->m_graphicsAdapterName = fb->m_emulationGl->getGlesRenderer();
         fb->m_graphicsApiVersion = fb->m_emulationGl->getGlesVersionString();
         fb->m_graphicsApiExtensions = fb->m_emulationGl->getGlesExtensionsString();
         fb->m_graphicsDeviceExtensions = "N/A";
-#endif
     } else {
         fb->m_graphicsAdapterVendor = "N/A";
         fb->m_graphicsAdapterName = "N/A";
@@ -443,7 +432,6 @@
     if (!fb->m_emulationGl) {
         vulkanInteropSupported = false;
     } else {
-#if GFXSTREAM_ENABLE_HOST_GLES
         if (!fb->m_emulationGl->isGlesVulkanInteropSupported()) {
             vulkanInteropSupported = false;
         }
@@ -451,7 +439,6 @@
         if (!glesDeviceUuid  || glesDeviceUuid != fb->m_vulkanUUID) {
             vulkanInteropSupported = false;
         }
-#endif
     }
     // TODO: 0-copy gl interop on swiftshader vk
     if (android::base::getEnvironmentVariable("ANDROID_EMU_VK_ICD") == "swiftshader") {
@@ -462,13 +449,11 @@
     fb->m_vulkanInteropSupported = vulkanInteropSupported;
     GL_LOG("interop? %d", fb->m_vulkanInteropSupported);
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (vulkanInteropSupported && fb->m_emulationGl && fb->m_emulationGl->isMesa()) {
         // Mesa currently expects dedicated allocations for external memory sharing
         // between GL and VK. See b/265186355.
         vkEmulationFeatures->useDedicatedAllocations = true;
     }
-#endif
 
     GL_LOG("glvk interop final: %d", fb->m_vulkanInteropSupported);
     vkEmulationFeatures->glInteropSupported = fb->m_vulkanInteropSupported;
@@ -489,19 +474,15 @@
         fb->m_compositor = vkEmu->compositorVk.get();
     } else {
         GL_LOG("Performing composition using CompositorGl.");
-#if GFXSTREAM_ENABLE_HOST_GLES
         auto compositorGl = fb->m_emulationGl->getCompositor();
         fb->m_compositor = compositorGl;
-#endif
     }
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (fb->m_emulationGl) {
         auto displayGl = fb->m_emulationGl->getDisplay();
         fb->m_displayGl = displayGl;
         fb->m_displaySurfaceUsers.push_back(displayGl);
     }
-#endif
 
     INFO("Graphics Adapter Vendor %s", fb->m_graphicsAdapterVendor.c_str());
     INFO("Graphics Adapter %s", fb->m_graphicsAdapterName.c_str());
@@ -514,13 +495,11 @@
     } else {
         const bool shouldPostOnlyOnMainThread = postOnlyOnMainThread();
 
-#if GFXSTREAM_ENABLE_HOST_GLES
         PostWorkerGl* postWorkerGl =
             new PostWorkerGl(shouldPostOnlyOnMainThread, fb.get(), fb->m_compositor,
                              fb->m_displayGl, fb->m_emulationGl.get());
         fb->m_postWorker.reset(postWorkerGl);
         fb->m_displaySurfaceUsers.push_back(postWorkerGl);
-#endif
     }
 
     // Start up the single sync thread. If we are using Vulkan native
@@ -555,6 +534,12 @@
     }
 }
 
+void FrameBuffer::fillGLESUsages(android_studio::EmulatorGLESUsages* usages) {
+    if (s_egl.eglFillUsages) {
+        s_egl.eglFillUsages(usages);
+    }
+}
+
 FrameBuffer::FrameBuffer(int p_width, int p_height, bool useSubWindow)
     : m_framebufferWidth(p_width),
       m_framebufferHeight(p_height),
@@ -615,14 +600,12 @@
     }
     m_colorBufferDelayedCloseList.clear();
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     m_windows.clear();
     m_contexts.clear();
 
     for (auto it : m_platformEglContexts) {
         destroySharedTrivialContext(it.second.context, it.second.surface);
     }
-#endif
 
     vk::teardownGlobalVkEmulation();
 
@@ -939,11 +922,9 @@
                 m_displaySurface =
                     vk::createDisplaySurface(m_subWin, m_windowWidth, m_windowHeight);
             } else if (m_emulationGl) {
-#if GFXSTREAM_ENABLE_HOST_GLES
                 m_displaySurface = m_emulationGl->createWindowSurface(m_windowWidth,
                                                                       m_windowHeight,
                                                                       m_subWin);
-#endif
             } else {
                 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
                     << "Unhandled window surface creation.";
@@ -1098,10 +1079,8 @@
     HandleType id;
     do {
         id = ++s_nextHandle;
-    } while (id == 0 ||
-#if GFXSTREAM_ENABLE_HOST_GLES
-             m_contexts.find(id) != m_contexts.end() || m_windows.find(id) != m_windows.end() ||
-#endif
+    } while (id == 0 || m_contexts.find(id) != m_contexts.end() ||
+             m_windows.find(id) != m_windows.end() ||
              m_colorbuffers.find(id) != m_colorbuffers.end() ||
              m_buffers.find(id) != m_buffers.end());
 
@@ -1224,10 +1203,296 @@
     return handle;
 }
 
+HandleType FrameBuffer::createEmulatedEglContext(int config,
+                                                 HandleType shareContextHandle,
+                                                 GLESApi version) {
+    if (!m_emulationGl) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "EGL emulation unavailable.";
+    }
+
+    AutoLock mutex(m_lock);
+    android::base::AutoWriteLock contextLock(m_contextStructureLock);
+    // Hold the ColorBuffer map lock so that the new handle won't collide with a ColorBuffer handle.
+    AutoLock colorBufferMapLock(m_colorBufferMapLock);
+
+    EmulatedEglContextPtr shareContext = nullptr;
+    if (shareContextHandle != 0) {
+        auto shareContextIt = m_contexts.find(shareContextHandle);
+        if (shareContextIt == m_contexts.end()) {
+            ERR("Failed to find share EmulatedEglContext:%d", shareContextHandle);
+            return 0;
+        }
+        shareContext = shareContextIt->second;
+    }
+
+    HandleType contextHandle = genHandle_locked();
+    auto context = m_emulationGl->createEmulatedEglContext(config,
+                                                           shareContext.get(),
+                                                           version,
+                                                           contextHandle);
+    if (!context) {
+        ERR("Failed to create EmulatedEglContext.");
+        return 0;
+    }
+
+    m_contexts[contextHandle] = std::move(context);
+
+    RenderThreadInfo* tinfo = RenderThreadInfo::get();
+    uint64_t puid = tinfo->m_puid;
+    // The new emulator manages render contexts per guest process.
+    // Fall back to per-thread management if the system image does not
+    // support it.
+    if (puid) {
+        m_procOwnedEmulatedEglContexts[puid].insert(contextHandle);
+    } else { // legacy path to manage context lifetime by threads
+        if (!tinfo->m_glInfo) {
+            GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+                << "Render thread GL not available.";
+        }
+        tinfo->m_glInfo->m_contextSet.insert(contextHandle);
+    }
+
+    return contextHandle;
+}
+
+void FrameBuffer::destroyEmulatedEglContext(HandleType contextHandle) {
+    AutoLock mutex(m_lock);
+    sweepColorBuffersLocked();
+
+    android::base::AutoWriteLock contextLock(m_contextStructureLock);
+    m_contexts.erase(contextHandle);
+    RenderThreadInfo* tinfo = RenderThreadInfo::get();
+    uint64_t puid = tinfo->m_puid;
+    // The new emulator manages render contexts per guest process.
+    // Fall back to per-thread management if the system image does not
+    // support it.
+    if (puid) {
+        auto it = m_procOwnedEmulatedEglContexts.find(puid);
+        if (it != m_procOwnedEmulatedEglContexts.end()) {
+            it->second.erase(contextHandle);
+        }
+    } else {
+        if (!tinfo->m_glInfo) {
+            GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+                << "Render thread GL not available.";
+        }
+        tinfo->m_glInfo->m_contextSet.erase(contextHandle);
+    }
+}
+
+HandleType FrameBuffer::createEmulatedEglWindowSurface(int p_config,
+                                                       int p_width,
+                                                       int p_height) {
+    if (!m_emulationGl) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "EGL emulation unavailable.";
+    }
+
+    AutoLock mutex(m_lock);
+    // Hold the ColorBuffer map lock so that the new handle won't collide with a ColorBuffer handle.
+    AutoLock colorBufferMapLock(m_colorBufferMapLock);
+
+    HandleType handle = genHandle_locked();
+
+    auto window = m_emulationGl->createEmulatedEglWindowSurface(p_config,
+                                                                p_width,
+                                                                p_height,
+                                                                handle);
+    if (!window) {
+        ERR("Failed to create EmulatedEglWindowSurface.");
+        return 0;
+    }
+
+    m_windows[handle] = { std::move(window), 0 };
+
+    RenderThreadInfo* info = RenderThreadInfo::get();
+    if (!info->m_glInfo) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "RRenderThreadInfoGl not available.";
+    }
+
+    uint64_t puid = info->m_puid;
+    if (puid) {
+        m_procOwnedEmulatedEglWindowSurfaces[puid].insert(handle);
+    } else { // legacy path to manage window surface lifetime by threads
+        info->m_glInfo->m_windowSet.insert(handle);
+    }
+
+    return handle;
+}
+
+void FrameBuffer::destroyEmulatedEglWindowSurface(HandleType p_surface) {
+    if (m_shuttingDown) {
+        return;
+    }
+    AutoLock mutex(m_lock);
+    destroyEmulatedEglWindowSurfaceLocked(p_surface);
+}
+
+std::vector<HandleType> FrameBuffer::destroyEmulatedEglWindowSurfaceLocked(HandleType p_surface) {
+    std::vector<HandleType> colorBuffersToCleanUp;
+    const auto w = m_windows.find(p_surface);
+    if (w != m_windows.end()) {
+        RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper());
+        if (!m_guestManagedColorBufferLifetime) {
+            if (m_refCountPipeEnabled) {
+                if (decColorBufferRefCountLocked(w->second.second)) {
+                    colorBuffersToCleanUp.push_back(w->second.second);
+                }
+            } else {
+                if (closeColorBufferLocked(w->second.second)) {
+                    colorBuffersToCleanUp.push_back(w->second.second);
+                }
+            }
+        }
+        m_windows.erase(w);
+        RenderThreadInfo* tinfo = RenderThreadInfo::get();
+        uint64_t puid = tinfo->m_puid;
+        if (puid) {
+            auto ite = m_procOwnedEmulatedEglWindowSurfaces.find(puid);
+            if (ite != m_procOwnedEmulatedEglWindowSurfaces.end()) {
+                ite->second.erase(p_surface);
+            }
+        } else {
+            if (!tinfo->m_glInfo) {
+                GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+                    << "Render thread GL not available.";
+            }
+            tinfo->m_glInfo->m_windowSet.erase(p_surface);
+        }
+    }
+    return colorBuffersToCleanUp;
+}
+
+void FrameBuffer::createEmulatedEglFenceSync(EGLenum type,
+                                             int destroyWhenSignaled,
+                                             uint64_t* outSync,
+                                             uint64_t* outSyncThread) {
+    if (!m_emulationGl) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "GL/EGL emulation not available.";
+    }
+
+    // TODO(b/233939967): move RenderThreadInfoGl usage to EmulationGl.
+    RenderThreadInfoGl* const info = RenderThreadInfoGl::get();
+    if (!info) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "RenderThreadInfoGl not available.";
+    }
+    if (!info->currContext) {
+        auto fb = FrameBuffer::getFB();
+        uint32_t syncContext;
+        uint32_t syncSurface;
+        createTrivialContext(0, // There is no context to share.
+                             &syncContext,
+                             &syncSurface);
+        bindContext(syncContext,
+                    syncSurface,
+                    syncSurface);
+        // This context is then cleaned up when the render thread exits.
+    }
+
+    auto sync = m_emulationGl->createEmulatedEglFenceSync(type, destroyWhenSignaled);
+    if (!sync) {
+        return;
+    }
+
+    if (outSync) {
+        *outSync = (uint64_t)(uintptr_t)sync.release();
+    }
+    if (outSyncThread) {
+        *outSyncThread = reinterpret_cast<uint64_t>(SyncThread::get());
+    }
+}
+
+void FrameBuffer::drainGlRenderThreadResources() {
+    // If we're already exiting then snapshot should not contain
+    // this thread information at all.
+    if (isShuttingDown()) {
+        return;
+    }
+
+    // Release references to the current thread's context/surfaces if any
+    bindContext(0, 0, 0);
+
+    drainGlRenderThreadSurfaces();
+    drainGlRenderThreadContexts();
+
+    if (!s_egl.eglReleaseThread()) {
+        ERR("Error: RenderThread @%p failed to eglReleaseThread()", this);
+    }
+}
+
+void FrameBuffer::drainGlRenderThreadContexts() {
+    if (isShuttingDown()) {
+        return;
+    }
+
+    RenderThreadInfoGl* const tinfo = RenderThreadInfoGl::get();
+    if (!tinfo) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "Render thread GL not available.";
+    }
+
+    if (tinfo->m_contextSet.empty()) {
+        return;
+    }
+
+    AutoLock mutex(m_lock);
+    android::base::AutoWriteLock contextLock(m_contextStructureLock);
+    for (const HandleType contextHandle : tinfo->m_contextSet) {
+        m_contexts.erase(contextHandle);
+    }
+    tinfo->m_contextSet.clear();
+}
+
+void FrameBuffer::drainGlRenderThreadSurfaces() {
+    if (isShuttingDown()) {
+        return;
+    }
+
+    RenderThreadInfoGl* const tinfo = RenderThreadInfoGl::get();
+    if (!tinfo) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "Render thread GL not available.";
+    }
+
+    if (tinfo->m_windowSet.empty()) {
+        return;
+    }
+
+    std::vector<HandleType> colorBuffersToCleanup;
+
+    AutoLock mutex(m_lock);
+    RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper());
+    for (const HandleType winHandle : tinfo->m_windowSet) {
+        const auto winIt = m_windows.find(winHandle);
+        if (winIt != m_windows.end()) {
+            if (const HandleType oldColorBufferHandle = winIt->second.second) {
+                if (!m_guestManagedColorBufferLifetime) {
+                    if (m_refCountPipeEnabled) {
+                        if (decColorBufferRefCountLocked(oldColorBufferHandle)) {
+                            colorBuffersToCleanup.push_back(oldColorBufferHandle);
+                        }
+                    } else {
+                        if (closeColorBufferLocked(oldColorBufferHandle)) {
+                            colorBuffersToCleanup.push_back(oldColorBufferHandle);
+                        }
+                    }
+                }
+                m_windows.erase(winIt);
+            }
+        }
+    }
+    tinfo->m_windowSet.clear();
+}
+
 int FrameBuffer::openColorBuffer(HandleType p_colorbuffer) {
     // When guest feature flag RefCountPipe is on, no reference counting is
     // needed.
-    if (m_refCountPipeEnabled) return 0;
+    if (m_refCountPipeEnabled)
+        return 0;
 
     RenderThreadInfo* tInfo = RenderThreadInfo::get();
 
@@ -1296,7 +1561,8 @@
     m_buffers.erase(it);
 }
 
-bool FrameBuffer::closeColorBufferLocked(HandleType p_colorbuffer, bool forced) {
+bool FrameBuffer::closeColorBufferLocked(HandleType p_colorbuffer,
+                                         bool forced) {
     // When guest feature flag RefCountPipe is on, no reference counting is
     // needed.
     if (m_refCountPipeEnabled) {
@@ -1466,7 +1732,6 @@
     std::vector<HandleType> colorBuffersToCleanup;
     {
         std::unique_ptr<RecursiveScopedContextBind> bind = nullptr;
-#if GFXSTREAM_ENABLE_HOST_GLES
         if (m_emulationGl) {
             bind = std::make_unique<RecursiveScopedContextBind>(getPbufferSurfaceContextHelper());
         }
@@ -1496,8 +1761,6 @@
                 m_procOwnedEmulatedEglWindowSurfaces.erase(procIte);
             }
         }
-#endif
-
         // Clean up color buffers.
         // A color buffer needs to be closed as many times as it is opened by
         // the guest process, to give the correct reference count.
@@ -1516,7 +1779,6 @@
             }
         }
 
-#if GFXSTREAM_ENABLE_HOST_GLES
         // Clean up EGLImage handles
         if (m_emulationGl) {
             auto procImagesIt = m_procOwnedEmulatedEglImages.find(puid);
@@ -1527,10 +1789,7 @@
                 m_procOwnedEmulatedEglImages.erase(procImagesIt);
             }
         }
-#endif
     }
-
-#if GFXSTREAM_ENABLE_HOST_GLES
     // Unbind before cleaning up contexts
     // Cleanup render contexts
     if (m_emulationGl) {
@@ -1542,7 +1801,6 @@
             m_procOwnedEmulatedEglContexts.erase(procIte);
         }
     }
-#endif
 
     return colorBuffersToCleanup;
 }
@@ -1553,6 +1811,77 @@
     cbRef->closedTs = 0;
 }
 
+bool FrameBuffer::flushEmulatedEglWindowSurfaceColorBuffer(HandleType p_surface) {
+    AutoLock mutex(m_lock);
+
+    auto it = m_windows.find(p_surface);
+    if (it == m_windows.end()) {
+        ERR("FB::flushEmulatedEglWindowSurfaceColorBuffer: window handle %#x not found",
+            p_surface);
+        // bad surface handle
+        return false;
+    }
+
+    EmulatedEglWindowSurface* surface = it->second.first.get();
+    surface->flushColorBuffer();
+
+    return true;
+}
+
+HandleType FrameBuffer::getEmulatedEglWindowSurfaceColorBufferHandle(HandleType p_surface) {
+    AutoLock mutex(m_lock);
+
+    auto it = m_EmulatedEglWindowSurfaceToColorBuffer.find(p_surface);
+    if (it == m_EmulatedEglWindowSurfaceToColorBuffer.end()) {
+        return 0;
+    }
+
+    return it->second;
+}
+
+bool FrameBuffer::setEmulatedEglWindowSurfaceColorBuffer(HandleType p_surface,
+                                                         HandleType p_colorbuffer) {
+    AutoLock mutex(m_lock);
+
+    EmulatedEglWindowSurfaceMap::iterator w(m_windows.find(p_surface));
+    if (w == m_windows.end()) {
+        // bad surface handle
+        ERR("bad window surface handle %#x", p_surface);
+        return false;
+    }
+
+    {
+        AutoLock colorBufferMapLock(m_colorBufferMapLock);
+        ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
+        if (c == m_colorbuffers.end()) {
+            ERR("bad color buffer handle %#x", p_colorbuffer);
+            // bad colorbuffer handle
+            return false;
+        }
+
+        (*w).second.first->setColorBuffer((*c).second.cb);
+        markOpened(&c->second);
+        if (!m_guestManagedColorBufferLifetime) {
+            c->second.refcount++;
+        }
+    }
+    if (w->second.second) {
+        if (!m_guestManagedColorBufferLifetime) {
+            if (m_refCountPipeEnabled) {
+                decColorBufferRefCountLocked(w->second.second);
+            } else {
+                closeColorBufferLocked(w->second.second);
+            }
+        }
+    }
+
+    (*w).second.second = p_colorbuffer;
+
+    m_EmulatedEglWindowSurfaceToColorBuffer[p_surface] = p_colorbuffer;
+
+    return true;
+}
+
 void FrameBuffer::readBuffer(HandleType handle, uint64_t offset, uint64_t size, void* bytes) {
     AutoLock mutex(m_lock);
 
@@ -1591,6 +1920,92 @@
     colorBuffer->readYuvToBytes(x, y, width, height, pixels, pixels_size);
 }
 
+void FrameBuffer::createYUVTextures(uint32_t type,
+                                    uint32_t count,
+                                    int width,
+                                    int height,
+                                    uint32_t* output) {
+    FrameworkFormat format = static_cast<FrameworkFormat>(type);
+    AutoLock mutex(m_lock);
+    RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper());
+    for (uint32_t i = 0; i < count; ++i) {
+        if (format == FRAMEWORK_FORMAT_NV12) {
+            YUVConverter::createYUVGLTex(GL_TEXTURE0, width, height,
+                                         format, YUVPlane::Y, &output[2 * i]);
+            YUVConverter::createYUVGLTex(GL_TEXTURE1, width / 2, height / 2,
+                                         format, YUVPlane::UV, &output[2 * i + 1]);
+        } else if (format == FRAMEWORK_FORMAT_YUV_420_888) {
+            YUVConverter::createYUVGLTex(GL_TEXTURE0, width, height,
+                                         format, YUVPlane::Y, &output[3 * i]);
+            YUVConverter::createYUVGLTex(GL_TEXTURE1, width / 2, height / 2,
+                                         format, YUVPlane::U, &output[3 * i + 1]);
+            YUVConverter::createYUVGLTex(GL_TEXTURE2, width / 2, height / 2,
+                                         format, YUVPlane::V, &output[3 * i + 2]);
+        }
+    }
+}
+
+void FrameBuffer::destroyYUVTextures(uint32_t type,
+                                     uint32_t count,
+                                     uint32_t* textures) {
+    AutoLock mutex(m_lock);
+    RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper());
+    if (type == FRAMEWORK_FORMAT_NV12) {
+        s_gles2.glDeleteTextures(2 * count, textures);
+    } else if (type == FRAMEWORK_FORMAT_YUV_420_888) {
+        s_gles2.glDeleteTextures(3 * count, textures);
+    }
+}
+
+void FrameBuffer::updateYUVTextures(uint32_t type,
+                                    uint32_t* textures,
+                                    void* privData,
+                                    void* func) {
+    AutoLock mutex(m_lock);
+    RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper());
+
+    yuv_updater_t updater = (yuv_updater_t)func;
+    uint32_t gtextures[3] = {0, 0, 0};
+
+    if (type == FRAMEWORK_FORMAT_NV12) {
+        gtextures[0] = s_gles2.glGetGlobalTexName(textures[0]);
+        gtextures[1] = s_gles2.glGetGlobalTexName(textures[1]);
+    } else if (type == FRAMEWORK_FORMAT_YUV_420_888) {
+        gtextures[0] = s_gles2.glGetGlobalTexName(textures[0]);
+        gtextures[1] = s_gles2.glGetGlobalTexName(textures[1]);
+        gtextures[2] = s_gles2.glGetGlobalTexName(textures[2]);
+    }
+
+#ifdef __APPLE__
+    EGLContext prevContext = s_egl.eglGetCurrentContext();
+    auto mydisp = EglGlobalInfo::getInstance()->getDisplayFromDisplayType(EGL_DEFAULT_DISPLAY);
+    void* nativecontext = mydisp->getLowLevelContext(prevContext);
+    struct MediaNativeCallerData callerdata;
+    callerdata.ctx = nativecontext;
+    callerdata.converter = nsConvertVideoFrameToNV12Textures;
+    void* pcallerdata = &callerdata;
+#else
+    void* pcallerdata = nullptr;
+#endif
+
+    updater(privData, type, gtextures, pcallerdata);
+}
+
+void FrameBuffer::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) {
+    {
+        AutoLock mutex(m_lock);
+        ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer);
+        if (!colorBuffer) {
+            // bad colorbuffer handle
+            return;
+        }
+        colorBuffer->glOpSwapYuvTexturesAndUpdate(
+            format, type, static_cast<FrameworkFormat>(texture_type), textures);
+    }
+}
+
 bool FrameBuffer::updateBuffer(HandleType p_buffer, uint64_t offset, uint64_t size, void* bytes) {
     AutoLock mutex(m_lock);
 
@@ -1648,6 +2063,20 @@
     return true;
 }
 
+bool FrameBuffer::readColorBufferContents(
+    HandleType p_colorbuffer, size_t* numBytes, void* pixels) {
+
+    AutoLock mutex(m_lock);
+
+    ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer);
+    if (!colorBuffer) {
+        // bad colorbuffer handle
+        return false;
+    }
+
+    return colorBuffer->glOpReadContents(numBytes, pixels);
+}
+
 bool FrameBuffer::getColorBufferInfo(
     HandleType p_colorbuffer, int* width, int* height, GLint* internalformat,
     FrameworkFormat* frameworkFormat) {
@@ -1684,12 +2113,272 @@
     return true;
 }
 
+bool FrameBuffer::bindColorBufferToTexture(HandleType p_colorbuffer) {
+    AutoLock mutex(m_lock);
+
+    ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer);
+    if (!colorBuffer) {
+        // bad colorbuffer handle
+        return false;
+    }
+
+    return colorBuffer->glOpBindToTexture();
+}
+
+bool FrameBuffer::bindColorBufferToTexture2(HandleType p_colorbuffer) {
+    // This is only called when using multi window display
+    // It will deadlock when posting from main thread.
+    std::unique_ptr<AutoLock> mutex;
+    if (!postOnlyOnMainThread()) {
+        mutex = std::make_unique<AutoLock>(m_lock);
+    }
+
+    ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer);
+    if (!colorBuffer) {
+        // bad colorbuffer handle
+        return false;
+    }
+
+    return colorBuffer->glOpBindToTexture2();
+}
+
+bool FrameBuffer::bindColorBufferToRenderbuffer(HandleType p_colorbuffer) {
+    AutoLock mutex(m_lock);
+
+    ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer);
+    if (!colorBuffer) {
+        // bad colorbuffer handle
+        return false;
+    }
+
+    return colorBuffer->glOpBindToRenderbuffer();
+}
+
+bool FrameBuffer::bindContext(HandleType p_context,
+                              HandleType p_drawSurface,
+                              HandleType p_readSurface) {
+    if (m_shuttingDown) {
+        return false;
+    }
+
+    AutoLock mutex(m_lock);
+
+    EmulatedEglWindowSurfacePtr draw, read;
+    EmulatedEglContextPtr ctx;
+
+    //
+    // if this is not an unbind operation - make sure all handles are good
+    //
+    if (p_context || p_drawSurface || p_readSurface) {
+        ctx = getContext_locked(p_context);
+        if (!ctx)
+            return false;
+        EmulatedEglWindowSurfaceMap::iterator w(m_windows.find(p_drawSurface));
+        if (w == m_windows.end()) {
+            // bad surface handle
+            return false;
+        }
+        draw = (*w).second.first;
+
+        if (p_readSurface != p_drawSurface) {
+            EmulatedEglWindowSurfaceMap::iterator w(m_windows.find(p_readSurface));
+            if (w == m_windows.end()) {
+                // bad surface handle
+                return false;
+            }
+            read = (*w).second.first;
+        } else {
+            read = draw;
+        }
+    } else {
+        // if unbind operation, sweep color buffers
+        sweepColorBuffersLocked();
+    }
+
+    if (!s_egl.eglMakeCurrent(getDisplay(),
+                              draw ? draw->getEGLSurface() : EGL_NO_SURFACE,
+                              read ? read->getEGLSurface() : EGL_NO_SURFACE,
+                              ctx ? ctx->getEGLContext() : EGL_NO_CONTEXT)) {
+        ERR("eglMakeCurrent failed");
+        return false;
+    }
+
+    //
+    // Bind the surface(s) to the context
+    //
+    RenderThreadInfoGl* const tinfo = RenderThreadInfoGl::get();
+    if (!tinfo) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "Render thread GL not available.";
+    }
+
+    EmulatedEglWindowSurfacePtr bindDraw, bindRead;
+    if (draw.get() == NULL && read.get() == NULL) {
+        // Unbind the current read and draw surfaces from the context
+        bindDraw = tinfo->currDrawSurf;
+        bindRead = tinfo->currReadSurf;
+    } else {
+        bindDraw = draw;
+        bindRead = read;
+    }
+
+    if (bindDraw.get() != NULL && bindRead.get() != NULL) {
+        if (bindDraw.get() != bindRead.get()) {
+            bindDraw->bind(ctx, EmulatedEglWindowSurface::BIND_DRAW);
+            bindRead->bind(ctx, EmulatedEglWindowSurface::BIND_READ);
+        } else {
+            bindDraw->bind(ctx, EmulatedEglWindowSurface::BIND_READDRAW);
+        }
+    }
+
+    //
+    // update thread info with current bound context
+    //
+    tinfo->currContext = ctx;
+    tinfo->currDrawSurf = draw;
+    tinfo->currReadSurf = read;
+    if (ctx) {
+        if (ctx->clientVersion() > GLESApi_CM)
+            tinfo->m_gl2Dec.setContextData(&ctx->decoderContextData());
+        else
+            tinfo->m_glDec.setContextData(&ctx->decoderContextData());
+    } else {
+        tinfo->m_glDec.setContextData(NULL);
+        tinfo->m_gl2Dec.setContextData(NULL);
+    }
+    return true;
+}
+
+EmulatedEglContextPtr FrameBuffer::getContext_locked(HandleType p_context) {
+    return android::base::findOrDefault(m_contexts, p_context);
+}
+
+EmulatedEglWindowSurfacePtr FrameBuffer::getWindowSurface_locked(HandleType p_windowsurface) {
+    return android::base::findOrDefault(m_windows, p_windowsurface).first;
+}
+
+HandleType FrameBuffer::createEmulatedEglImage(HandleType contextHandle,
+                                               EGLenum target,
+                                               GLuint buffer) {
+    if (!m_emulationGl) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "GL/EGL emulation not enabled.";
+    }
+
+    AutoLock mutex(m_lock);
+
+    EmulatedEglContext* context = nullptr;
+    if (contextHandle) {
+        android::base::AutoWriteLock contextLock(m_contextStructureLock);
+
+        auto it = m_contexts.find(contextHandle);
+        if (it == m_contexts.end()) {
+            ERR("Failed to find EmulatedEglContext:%d", contextHandle);
+            return false;
+        }
+
+        context = it->second.get();
+    }
+
+    auto image = m_emulationGl->createEmulatedEglImage(context,
+                                                       target,
+                                                       reinterpret_cast<EGLClientBuffer>(buffer));
+    if (!image) {
+        ERR("Failed to create EmulatedEglImage");
+        return false;
+    }
+
+    HandleType imageHandle = image->getHandle();
+
+    m_images[imageHandle] = std::move(image);
+
+    RenderThreadInfo* tInfo = RenderThreadInfo::get();
+    uint64_t puid = tInfo->m_puid;
+    if (puid) {
+        m_procOwnedEmulatedEglImages[puid].insert(imageHandle);
+    }
+    return imageHandle;
+}
+
+EGLBoolean FrameBuffer::destroyEmulatedEglImage(HandleType imageHandle) {
+    if (!m_emulationGl) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "GL/EGL emulation not enabled.";
+    }
+
+    AutoLock mutex(m_lock);
+
+    auto imageIt = m_images.find(imageHandle);
+    if (imageIt == m_images.end()) {
+        ERR("Failed to find EmulatedEglImage:%d", imageHandle);
+        return false;
+    }
+    auto& image = imageIt->second;
+
+    EGLBoolean success = image->destroy();
+    m_images.erase(imageIt);
+
+    RenderThreadInfo* tInfo = RenderThreadInfo::get();
+    uint64_t puid = tInfo->m_puid;
+    if (puid) {
+        m_procOwnedEmulatedEglImages[puid].erase(imageHandle);
+        // We don't explicitly call m_procOwnedEmulatedEglImages.erase(puid) when the
+        // size reaches 0, since it could go between zero and one many times in
+        // the lifetime of a process. It will be cleaned up by
+        // cleanupProcGLObjects(puid) when the process is dead.
+    }
+    return success;
+}
+
+void FrameBuffer::createTrivialContext(HandleType shared,
+                                       HandleType* contextOut,
+                                       HandleType* surfOut) {
+    assert(contextOut);
+    assert(surfOut);
+
+    *contextOut = createEmulatedEglContext(0, shared, GLESApi_2);
+    // Zero size is formally allowed here, but SwiftShader doesn't like it and
+    // fails.
+    *surfOut = createEmulatedEglWindowSurface(0, 1, 1);
+}
+
+void FrameBuffer::createSharedTrivialContext(EGLContext* contextOut,
+                                             EGLSurface* surfOut) {
+    assert(contextOut);
+    assert(surfOut);
+
+    const EmulatedEglConfig* config = getConfigs()->get(0 /* p_config */);
+    if (!config) return;
+
+    int maj, min;
+    emugl::getGlesVersion(&maj, &min);
+
+    const EGLint contextAttribs[] = {
+        EGL_CONTEXT_MAJOR_VERSION_KHR, maj,
+        EGL_CONTEXT_MINOR_VERSION_KHR, min,
+        EGL_NONE };
+
+    *contextOut = s_egl.eglCreateContext(
+            getDisplay(), config->getHostEglConfig(), getGlobalEGLContext(), contextAttribs);
+
+    const EGLint pbufAttribs[] = {
+        EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
+
+    *surfOut = s_egl.eglCreatePbufferSurface(getDisplay(), config->getHostEglConfig(), pbufAttribs);
+}
+
+void FrameBuffer::destroySharedTrivialContext(EGLContext context,
+                                              EGLSurface surface) {
+    if (getDisplay() != EGL_NO_DISPLAY) {
+        s_egl.eglDestroyContext(getDisplay(), context);
+        s_egl.eglDestroySurface(getDisplay(), surface);
+    }
+}
+
 bool FrameBuffer::post(HandleType p_colorbuffer, bool needLockAndBind) {
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (m_guestUsesAngle) {
         flushColorBufferFromGl(p_colorbuffer);
     }
-#endif
 
     auto res = postImplSync(p_colorbuffer, needLockAndBind);
     if (res) setGuestPostedAFrame();
@@ -1698,11 +2387,9 @@
 
 void FrameBuffer::postWithCallback(HandleType p_colorbuffer, Post::CompletionCallback callback,
                                    bool needLockAndBind) {
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (m_guestUsesAngle) {
         flushColorBufferFromGl(p_colorbuffer);
     }
-#endif
 
     AsyncResult res = postImpl(p_colorbuffer, callback, needLockAndBind);
     if (res.Succeeded()) {
@@ -1717,7 +2404,9 @@
     }
 }
 
-bool FrameBuffer::postImplSync(HandleType p_colorbuffer, bool needLockAndBind, bool repaint) {
+bool FrameBuffer::postImplSync(HandleType p_colorbuffer,
+    bool needLockAndBind,
+    bool repaint) {
     std::promise<void> promise;
     std::future<void> completeFuture = promise.get_future();
     auto posted = postImpl(
@@ -1734,16 +2423,16 @@
     return posted.Succeeded();
 }
 
-AsyncResult FrameBuffer::postImpl(HandleType p_colorbuffer, Post::CompletionCallback callback,
-                                  bool needLockAndBind, bool repaint) {
+AsyncResult FrameBuffer::postImpl(HandleType p_colorbuffer,
+                           Post::CompletionCallback callback,
+                           bool needLockAndBind,
+                           bool repaint) {
     std::unique_ptr<RecursiveScopedContextBind> bind;
     if (needLockAndBind) {
         m_lock.lock();
-#if GFXSTREAM_ENABLE_HOST_GLES
         if (m_emulationGl) {
             bind = std::make_unique<RecursiveScopedContextBind>(getPbufferSurfaceContextHelper());
         }
-#endif
     }
     AsyncResult ret = AsyncResult::FAIL_AND_CALLBACK_NOT_SCHEDULED;
 
@@ -1820,20 +2509,21 @@
 
         if (asyncReadbackSupported()) {
             ensureReadbackWorker();
-            const auto status = m_readbackWorker->doNextReadback(
-                iter.first, cb.get(), iter.second.img, repaint, iter.second.readBgra);
+            const auto status = m_readbackWorker->doNextReadback(iter.first,
+                                                                 cb.get(),
+                                                                 iter.second.img,
+                                                                 repaint,
+                                                                 iter.second.readBgra);
             if (status == ReadbackWorker::DoNextReadbackResult::OK_READY_FOR_READ) {
                 doPostCallback(iter.second.img, iter.first);
             }
         } else {
-#if GFXSTREAM_ENABLE_HOST_GLES
             cb->glOpReadback(iter.second.img, iter.second.readBgra);
-#endif
             doPostCallback(iter.second.img, iter.first);
         }
     }
 DEC_REFCOUNT_AND_EXIT:
-    if (!m_subWin) {  // m_subWin is supposed to be false
+    if (!m_subWin) { // m_subWin is supposed to be false
         decColorBufferRefCountLocked(p_colorbuffer);
     }
 
@@ -1851,8 +2541,9 @@
         ERR("Cannot find post callback function for display %d", displayId);
         return;
     }
-    iter->second.cb(iter->second.context, displayId, iter->second.width, iter->second.height, -1,
-                    GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char*)pixels);
+    iter->second.cb(iter->second.context, displayId, iter->second.width,
+                    iter->second.height, -1, GL_RGBA, GL_UNSIGNED_BYTE,
+                    (unsigned char*)pixels);
 }
 
 void FrameBuffer::getPixels(void* pixels, uint32_t bytes, uint32_t displayId) {
@@ -1861,8 +2552,8 @@
         ERR("Display %d not configured for recording yet", displayId);
         return;
     }
-    std::future<void> completeFuture =
-        m_readbackThread.enqueue({ReadbackCmd::GetPixels, displayId, pixels, bytes});
+    std::future<void> completeFuture = m_readbackThread.enqueue(
+        {ReadbackCmd::GetPixels, displayId, pixels, bytes});
     completeFuture.wait();
 }
 
@@ -1882,17 +2573,17 @@
 }
 
 void FrameBuffer::ensureReadbackWorker() {
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (!m_readbackWorker) {
         if (!m_emulationGl) {
-            GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "GL/EGL emulation not enabled.";
+            GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+                << "GL/EGL emulation not enabled.";
         }
         m_readbackWorker = m_emulationGl->getReadbackWorker();
     }
-#endif
 }
 
-static void sFrameBuffer_ReadPixelsCallback(void* pixels, uint32_t bytes, uint32_t displayId) {
+static void sFrameBuffer_ReadPixelsCallback(
+    void* pixels, uint32_t bytes, uint32_t displayId) {
     FrameBuffer::getFB()->getPixels(pixels, bytes, displayId);
 }
 
@@ -1901,11 +2592,7 @@
 }
 
 bool FrameBuffer::asyncReadbackSupported() {
-#if GFXSTREAM_ENABLE_HOST_GLES
     return m_emulationGl && m_emulationGl->isAsyncReadbackSupported();
-#else
-    return false;
-#endif
 }
 
 Renderer::ReadPixelsCallback FrameBuffer::getReadPixelsCallback() {
@@ -1921,7 +2608,8 @@
     if (m_displayVk) {
         return true;
     }
-    if (m_lastPostedColorBuffer && sInitialized.load(std::memory_order_relaxed)) {
+    if (m_lastPostedColorBuffer &&
+        sInitialized.load(std::memory_order_relaxed)) {
         GL_LOG("Has last posted colorbuffer and is initialized; post.");
         return postImplSync(m_lastPostedColorBuffer, needLockAndBind, true);
     } else {
@@ -1938,26 +2626,30 @@
     // Exclude empty handle lists from saving as they add no value but only
     // increase the snapshot size; keep the format compatible with
     // android::base::saveCollection() though.
-    const int count = std::count_if(
-        c.begin(), c.end(),
-        [](const typename Collection::value_type& pair) { return !pair.second.empty(); });
+    const int count =
+            std::count_if(c.begin(), c.end(),
+                          [](const typename Collection::value_type& pair) {
+                              return !pair.second.empty();
+                          });
     stream->putBe32(count);
     for (const auto& pair : c) {
         if (pair.second.empty()) {
             continue;
         }
         stream->putBe64(pair.first);
-        saveCollection(stream, pair.second, [](Stream* s, HandleType h) { s->putBe32(h); });
+        saveCollection(stream, pair.second,
+                       [](Stream* s, HandleType h) { s->putBe32(h); });
     }
 }
 
 template <class Collection>
 static void loadProcOwnedCollection(Stream* stream, Collection* c) {
-    loadCollection(stream, c, [](Stream* stream) -> typename Collection::value_type {
+    loadCollection(stream, c,
+                   [](Stream* stream) -> typename Collection::value_type {
         const int processId = stream->getBe64();
         typename Collection::mapped_type handles;
         loadCollection(stream, &handles, [](Stream* s) { return s->getBe32(); });
-        return {processId, std::move(handles)};
+        return { processId, std::move(handles) };
     });
 }
 
@@ -1966,8 +2658,14 @@
                                int desiredHeight, int desiredRotation, Rect rect) {
     AutoLock mutex(m_lock);
     uint32_t w, h, cb, screenWidth, screenHeight;
-    if (!emugl::get_emugl_multi_display_operations().getMultiDisplay(
-            displayId, nullptr, nullptr, &w, &h, nullptr, nullptr, nullptr)) {
+    if (!emugl::get_emugl_multi_display_operations().getMultiDisplay(displayId,
+                                                                     nullptr,
+                                                                     nullptr,
+                                                                     &w,
+                                                                     &h,
+                                                                     nullptr,
+                                                                     nullptr,
+                                                                     nullptr)) {
         ERR("Screenshot of invalid display %d", displayId);
         *width = 0;
         *height = 0;
@@ -2007,7 +2705,8 @@
             return -1;
         }
         if ((rect.pos.x < 0 || rect.pos.y < 0) ||
-            (desiredWidth < rect.pos.x + rect.size.w || desiredHeight < rect.pos.y + rect.size.h)) {
+            (desiredWidth < rect.pos.x + rect.size.w ||
+             desiredHeight < rect.pos.y + rect.size.h)) {
             return -1;
         }
     }
@@ -2020,8 +2719,8 @@
         *height = screenHeight;
     }
 
-    int needed =
-        useSnipping ? (nChannels * rect.size.w * rect.size.h) : (nChannels * (*width) * (*height));
+    int needed = useSnipping ? (nChannels * rect.size.w * rect.size.h)
+                             : (nChannels * (*width) * (*height));
 
     if (*cPixels < needed) {
         *cPixels = needed;
@@ -2102,8 +2801,8 @@
 bool FrameBuffer::compose(uint32_t bufferSize, void* buffer, bool needPost) {
     std::promise<void> promise;
     std::future<void> completeFuture = promise.get_future();
-    auto composeRes =
-        composeWithCallback(bufferSize, buffer, [&](std::shared_future<void> waitForGpu) {
+    auto composeRes = composeWithCallback(
+        bufferSize, buffer, [&](std::shared_future<void> waitForGpu) {
             waitForGpu.wait();
             promise.set_value();
         });
@@ -2142,47 +2841,48 @@
 }
 
 AsyncResult FrameBuffer::composeWithCallback(uint32_t bufferSize, void* buffer,
-                                             Post::CompletionCallback callback) {
+                                      Post::CompletionCallback callback) {
     ComposeDevice* p = (ComposeDevice*)buffer;
     AutoLock mutex(m_lock);
 
     switch (p->version) {
-        case 1: {
-            Post composeCmd;
-            composeCmd.composeVersion = 1;
-            composeCmd.composeBuffer.resize(bufferSize);
-            memcpy(composeCmd.composeBuffer.data(), buffer, bufferSize);
-            composeCmd.completionCallback = std::make_unique<Post::CompletionCallback>(callback);
-            composeCmd.cmd = PostCmd::Compose;
-            sendPostWorkerCmd(std::move(composeCmd));
-            return AsyncResult::OK_AND_CALLBACK_SCHEDULED;
-        }
+    case 1: {
+        Post composeCmd;
+        composeCmd.composeVersion = 1;
+        composeCmd.composeBuffer.resize(bufferSize);
+        memcpy(composeCmd.composeBuffer.data(), buffer, bufferSize);
+        composeCmd.completionCallback = std::make_unique<Post::CompletionCallback>(callback);
+        composeCmd.cmd = PostCmd::Compose;
+        sendPostWorkerCmd(std::move(composeCmd));
+        return AsyncResult::OK_AND_CALLBACK_SCHEDULED;
+    }
 
-        case 2: {
-            // support for multi-display
-            ComposeDevice_v2* p2 = (ComposeDevice_v2*)buffer;
-            if (p2->displayId != 0) {
-                mutex.unlock();
-                setDisplayColorBuffer(p2->displayId, p2->targetHandle);
-                mutex.lock();
-            }
-            Post composeCmd;
-            composeCmd.composeVersion = 2;
-            composeCmd.composeBuffer.resize(bufferSize);
-            memcpy(composeCmd.composeBuffer.data(), buffer, bufferSize);
-            composeCmd.completionCallback = std::make_unique<Post::CompletionCallback>(callback);
-            composeCmd.cmd = PostCmd::Compose;
-            sendPostWorkerCmd(std::move(composeCmd));
-            return AsyncResult::OK_AND_CALLBACK_SCHEDULED;
+    case 2: {
+        // support for multi-display
+        ComposeDevice_v2* p2 = (ComposeDevice_v2*)buffer;
+        if (p2->displayId != 0) {
+            mutex.unlock();
+            setDisplayColorBuffer(p2->displayId, p2->targetHandle);
+            mutex.lock();
         }
+        Post composeCmd;
+        composeCmd.composeVersion = 2;
+        composeCmd.composeBuffer.resize(bufferSize);
+        memcpy(composeCmd.composeBuffer.data(), buffer, bufferSize);
+        composeCmd.completionCallback = std::make_unique<Post::CompletionCallback>(callback);
+        composeCmd.cmd = PostCmd::Compose;
+        sendPostWorkerCmd(std::move(composeCmd));
+        return AsyncResult::OK_AND_CALLBACK_SCHEDULED;
+    }
 
-        default:
-            ERR("yet to handle composition device version: %d", p->version);
-            return AsyncResult::FAIL_AND_CALLBACK_NOT_SCHEDULED;
+    default:
+       ERR("yet to handle composition device version: %d", p->version);
+        return AsyncResult::FAIL_AND_CALLBACK_NOT_SCHEDULED;
     }
 }
 
-void FrameBuffer::onSave(Stream* stream, const android::snapshot::ITextureSaverPtr& textureSaver) {
+void FrameBuffer::onSave(Stream* stream,
+                         const android::snapshot::ITextureSaverPtr& textureSaver) {
     // Things we do not need to snapshot:
     //     m_eglSurface
     //     m_eglContext
@@ -2194,7 +2894,6 @@
     AutoLock mutex(m_lock);
 
     std::unique_ptr<RecursiveScopedContextBind> bind;
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (m_emulationGl) {
         // Some snapshot commands try using GL.
         bind = std::make_unique<RecursiveScopedContextBind>(getPbufferSurfaceContextHelper());
@@ -2208,12 +2907,12 @@
         // and save all labeled textures and EGLImages.
         if (s_egl.eglPreSaveContext && s_egl.eglSaveAllImages) {
             for (const auto& ctx : m_contexts) {
-                s_egl.eglPreSaveContext(getDisplay(), ctx.second->getEGLContext(), stream);
+                s_egl.eglPreSaveContext(getDisplay(), ctx.second->getEGLContext(),
+                        stream);
             }
             s_egl.eglSaveAllImages(getDisplay(), stream, &textureSaver);
         }
     }
-#endif
 
     // Don't save subWindow's x/y/w/h here - those are related to the current
     // emulator UI state, not guest state that we're saving.
@@ -2243,11 +2942,10 @@
     // previous eglPreSaveContext and eglSaveAllImages calls (for texture
     // objects).
     // TODO: skip reading from GPU even for texture objects.
-#if GFXSTREAM_ENABLE_HOST_GLES
-    saveCollection(
-        stream, m_contexts,
-        [](Stream* s, const EmulatedEglContextMap::value_type& pair) { pair.second->onSave(s); });
-#endif
+    saveCollection(stream, m_contexts,
+                   [](Stream* s, const EmulatedEglContextMap::value_type& pair) {
+        pair.second->onSave(s);
+    });
 
     // We don't need to save |m_colorBufferCloseTsMap| here - there's enough
     // information to reconstruct it when loading.
@@ -2265,23 +2963,16 @@
                        });
     }
     stream->putBe32(m_lastPostedColorBuffer);
-#if GFXSTREAM_ENABLE_HOST_GLES
     saveCollection(stream, m_windows,
                    [](Stream* s, const EmulatedEglWindowSurfaceMap::value_type& pair) {
-                       pair.second.first->onSave(s);
-                       s->putBe32(pair.second.second);  // Color buffer handle.
-                   });
-#endif
+        pair.second.first->onSave(s);
+        s->putBe32(pair.second.second); // Color buffer handle.
+    });
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     saveProcOwnedCollection(stream, m_procOwnedEmulatedEglWindowSurfaces);
-#endif
     saveProcOwnedCollection(stream, m_procOwnedColorBuffers);
-#if GFXSTREAM_ENABLE_HOST_GLES
     saveProcOwnedCollection(stream, m_procOwnedEmulatedEglImages);
     saveProcOwnedCollection(stream, m_procOwnedEmulatedEglContexts);
-#endif
-
     // TODO(b/309858017): remove if when ready to bump snapshot version
     if (feature_is_enabled(kFeature_VulkanSnapshots)) {
         stream->putBe64(m_procOwnedResources.size());
@@ -2296,11 +2987,11 @@
         vk::VkDecoderGlobalState::get()->save(stream);
     }
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (m_emulationGl) {
         if (s_egl.eglPostSaveContext) {
             for (const auto& ctx : m_contexts) {
-                s_egl.eglPostSaveContext(getDisplay(), ctx.second->getEGLContext(), stream);
+                s_egl.eglPostSaveContext(getDisplay(), ctx.second->getEGLContext(),
+                        stream);
             }
             // We need to run the post save step for m_eglContext
             // to mark their texture handles dirty
@@ -2311,7 +3002,6 @@
 
         EmulatedEglFenceSync::onSave(stream);
     }
-#endif
 }
 
 bool FrameBuffer::onLoad(Stream* stream,
@@ -2322,7 +3012,6 @@
         sweepColorBuffersLocked();
 
         std::unique_ptr<RecursiveScopedContextBind> bind;
-#if GFXSTREAM_ENABLE_HOST_GLES
         if (m_emulationGl) {
             // Some snapshot commands try using GL.
             bind = std::make_unique<RecursiveScopedContextBind>(getPbufferSurfaceContextHelper());
@@ -2330,27 +3019,21 @@
                 ERR("Failed to make context current for loading snapshot.");
             }
         }
-#endif
 
         bool cleanupComplete = false;
         {
             AutoLock colorBufferMapLock(m_colorBufferMapLock);
-            if (m_procOwnedCleanupCallbacks.empty() && m_procOwnedColorBuffers.empty() &&
-#if GFXSTREAM_ENABLE_HOST_GLES
-                m_procOwnedEmulatedEglContexts.empty() && m_procOwnedEmulatedEglImages.empty() &&
+            if (m_procOwnedCleanupCallbacks.empty() &&
+                m_procOwnedColorBuffers.empty() &&
+                m_procOwnedEmulatedEglContexts.empty() &&
+                m_procOwnedEmulatedEglImages.empty() &&
                 m_procOwnedEmulatedEglWindowSurfaces.empty() &&
-#endif
-                (
-#if GFXSTREAM_ENABLE_HOST_GLES
-                    !m_contexts.empty() || !m_windows.empty() ||
-#endif
-                    m_colorbuffers.size() > m_colorBufferDelayedCloseList.size())) {
+                (!m_contexts.empty() || !m_windows.empty() ||
+                 m_colorbuffers.size() > m_colorBufferDelayedCloseList.size())) {
                 // we are likely on a legacy system image, which does not have
                 // process owned objects. We need to force cleanup everything
-#if GFXSTREAM_ENABLE_HOST_GLES
                 m_contexts.clear();
                 m_windows.clear();
-#endif
                 m_colorbuffers.clear();
                 cleanupComplete = true;
             }
@@ -2358,34 +3041,30 @@
         if (!cleanupComplete) {
             std::vector<HandleType> colorBuffersToCleanup;
 
-#if GFXSTREAM_ENABLE_HOST_GLES
             while (m_procOwnedEmulatedEglWindowSurfaces.size()) {
                 auto cleanupHandles = cleanupProcGLObjects_locked(
-                    m_procOwnedEmulatedEglWindowSurfaces.begin()->first, true);
-                colorBuffersToCleanup.insert(colorBuffersToCleanup.end(), cleanupHandles.begin(),
-                                             cleanupHandles.end());
+                        m_procOwnedEmulatedEglWindowSurfaces.begin()->first, true);
+                colorBuffersToCleanup.insert(colorBuffersToCleanup.end(),
+                    cleanupHandles.begin(), cleanupHandles.end());
             }
-#endif
             while (m_procOwnedColorBuffers.size()) {
-                auto cleanupHandles =
-                    cleanupProcGLObjects_locked(m_procOwnedColorBuffers.begin()->first, true);
-                colorBuffersToCleanup.insert(colorBuffersToCleanup.end(), cleanupHandles.begin(),
-                                             cleanupHandles.end());
+                auto cleanupHandles = cleanupProcGLObjects_locked(
+                        m_procOwnedColorBuffers.begin()->first, true);
+                colorBuffersToCleanup.insert(colorBuffersToCleanup.end(),
+                    cleanupHandles.begin(), cleanupHandles.end());
             }
-#if GFXSTREAM_ENABLE_HOST_GLES
             while (m_procOwnedEmulatedEglImages.size()) {
-                auto cleanupHandles =
-                    cleanupProcGLObjects_locked(m_procOwnedEmulatedEglImages.begin()->first, true);
-                colorBuffersToCleanup.insert(colorBuffersToCleanup.end(), cleanupHandles.begin(),
-                                             cleanupHandles.end());
+                auto cleanupHandles = cleanupProcGLObjects_locked(
+                        m_procOwnedEmulatedEglImages.begin()->first, true);
+                colorBuffersToCleanup.insert(colorBuffersToCleanup.end(),
+                    cleanupHandles.begin(), cleanupHandles.end());
             }
             while (m_procOwnedEmulatedEglContexts.size()) {
                 auto cleanupHandles = cleanupProcGLObjects_locked(
-                    m_procOwnedEmulatedEglContexts.begin()->first, true);
-                colorBuffersToCleanup.insert(colorBuffersToCleanup.end(), cleanupHandles.begin(),
-                                             cleanupHandles.end());
+                        m_procOwnedEmulatedEglContexts.begin()->first, true);
+                colorBuffersToCleanup.insert(colorBuffersToCleanup.end(),
+                    cleanupHandles.begin(), cleanupHandles.end());
             }
-#endif
 
             std::vector<std::function<void()>> cleanupCallbacks;
 
@@ -2413,10 +3092,8 @@
             cleanupComplete = true;
         }
         m_colorBufferDelayedCloseList.clear();
-#if GFXSTREAM_ENABLE_HOST_GLES
         assert(m_contexts.empty());
         assert(m_windows.empty());
-#endif
         {
             AutoLock colorBufferMapLock(m_colorBufferMapLock);
             if (!m_colorbuffers.empty()) {
@@ -2428,13 +3105,11 @@
 #ifdef SNAPSHOT_PROFILE
         uint64_t texTime = android::base::getUnixTimeUs();
 #endif
-#if GFXSTREAM_ENABLE_HOST_GLES
         if (m_emulationGl) {
             if (s_egl.eglLoadAllImages) {
                 s_egl.eglLoadAllImages(getDisplay(), stream, &textureLoader);
             }
         }
-#endif
 #ifdef SNAPSHOT_PROFILE
         printf("Texture load time: %lld ms\n",
                (long long)(android::base::getUnixTimeUs() - texTime) / 1000);
@@ -2450,7 +3125,7 @@
                        int idx = static_cast<int>(s->getBe32());
                        int w = static_cast<int>(s->getBe32());
                        int h = static_cast<int>(s->getBe32());
-                       int dpiX = static_cast<int>(s->getBe32());
+                       int dpiX =  static_cast<int>(s->getBe32());
                        int dpiY = static_cast<int>(s->getBe32());
                        return {idx, {w, h, dpiX, dpiY}};
                    });
@@ -2464,19 +3139,18 @@
     m_statsNumFrames = stream->getBe32();
     m_statsStartTime = stream->getBe64();
 
-#if GFXSTREAM_ENABLE_HOST_GLES
-    loadCollection(
-        stream, &m_contexts, [this](Stream* stream) -> EmulatedEglContextMap::value_type {
-            if (!m_emulationGl) {
-                GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "GL/EGL emulation not enabled.";
-            }
+    loadCollection(stream, &m_contexts,
+                   [this](Stream* stream) -> EmulatedEglContextMap::value_type {
+                        if (!m_emulationGl) {
+                            GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+                                << "GL/EGL emulation not enabled.";
+                        }
 
-            auto context = m_emulationGl->loadEmulatedEglContext(stream);
-            auto contextHandle = context ? context->getHndl() : 0;
-            return {contextHandle, std::move(context)};
-        });
+                        auto context = m_emulationGl->loadEmulatedEglContext(stream);
+                        auto contextHandle = context ? context->getHndl() : 0;
+                        return { contextHandle, std::move(context) };
+                   });
     assert(!android::base::find(m_contexts, 0));
-#endif
 
     auto now = android::base::getUnixTimeUs();
     {
@@ -2500,32 +3174,28 @@
 
     {
         AutoLock colorBufferMapLock(m_colorBufferMapLock);
-#if GFXSTREAM_ENABLE_HOST_GLES
-        loadCollection(
-            stream, &m_windows, [this](Stream* stream) -> EmulatedEglWindowSurfaceMap::value_type {
-                if (!m_emulationGl) {
-                    GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
-                        << "GL/EGL emulation not enabled.";
-                }
+        loadCollection(stream, &m_windows,
+                       [this](Stream* stream) -> EmulatedEglWindowSurfaceMap::value_type {
+                            if (!m_emulationGl) {
+                                GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+                                    << "GL/EGL emulation not enabled.";
+                            }
 
-                auto window =
-                    m_emulationGl->loadEmulatedEglWindowSurface(stream, m_colorbuffers, m_contexts);
+                            auto window = m_emulationGl->loadEmulatedEglWindowSurface(
+                                stream,
+                                m_colorbuffers,
+                                m_contexts);
 
-                HandleType handle = window->getHndl();
-                HandleType colorBufferHandle = stream->getBe32();
-                return {handle, {std::move(window), colorBufferHandle}};
-            });
-#endif
+                            HandleType handle = window->getHndl();
+                            HandleType colorBufferHandle = stream->getBe32();
+                            return { handle, { std::move(window), colorBufferHandle } };
+                        });
     }
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     loadProcOwnedCollection(stream, &m_procOwnedEmulatedEglWindowSurfaces);
-#endif
     loadProcOwnedCollection(stream, &m_procOwnedColorBuffers);
-#if GFXSTREAM_ENABLE_HOST_GLES
     loadProcOwnedCollection(stream, &m_procOwnedEmulatedEglImages);
     loadProcOwnedCollection(stream, &m_procOwnedEmulatedEglContexts);
-#endif
     // TODO(b/309858017): remove if when ready to bump snapshot version
     if (feature_is_enabled(kFeature_VulkanSnapshots)) {
         size_t resourceCount = stream->getBe64();
@@ -2538,7 +3208,6 @@
         }
     }
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (m_emulationGl) {
         if (s_egl.eglPostLoadAllImages) {
             s_egl.eglPostLoadAllImages(getDisplay(), stream);
@@ -2546,11 +3215,9 @@
     }
 
     registerTriggerWait();
-#endif
 
     {
         std::unique_ptr<RecursiveScopedContextBind> bind;
-#if GFXSTREAM_ENABLE_HOST_GLES
         if (m_emulationGl) {
             // Some snapshot commands try using GL.
             bind = std::make_unique<RecursiveScopedContextBind>(getPbufferSurfaceContextHelper());
@@ -2558,7 +3225,6 @@
                 ERR("Failed to make context current for loading snapshot.");
             }
         }
-#endif
 
         AutoLock colorBufferMapLock(m_colorBufferMapLock);
         for (auto& it : m_colorbuffers) {
@@ -2578,26 +3244,36 @@
 
     repost(false);
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (m_emulationGl) {
         EmulatedEglFenceSync::onLoad(stream);
     }
-#endif
 
     return true;
     // TODO: restore memory management
 }
 
-void FrameBuffer::lock() { m_lock.lock(); }
+void FrameBuffer::lock() {
+    m_lock.lock();
+}
 
-void FrameBuffer::unlock() { m_lock.unlock(); }
+void FrameBuffer::unlock() {
+    m_lock.unlock();
+}
+
+GLESDispatchMaxVersion FrameBuffer::getMaxGLESVersion() {
+    if (!m_emulationGl) {
+        return GLES_DISPATCH_MAX_VERSION_2;
+    }
+    return m_emulationGl->getGlesMaxDispatchVersion();
+}
 
 ColorBufferPtr FrameBuffer::findColorBuffer(HandleType p_colorbuffer) {
     AutoLock colorBufferMapLock(m_colorBufferMapLock);
     ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
     if (c == m_colorbuffers.end()) {
         return nullptr;
-    } else {
+    }
+    else {
         return c->second.cb;
     }
 }
@@ -2645,7 +3321,7 @@
     return i->second.get();
 }
 
-int FrameBuffer::createDisplay(uint32_t* displayId) {
+int FrameBuffer::createDisplay(uint32_t *displayId) {
     return emugl::get_emugl_multi_display_operations().createDisplay(displayId);
 }
 
@@ -2658,28 +3334,37 @@
 }
 
 int FrameBuffer::setDisplayColorBuffer(uint32_t displayId, uint32_t colorBuffer) {
-    return emugl::get_emugl_multi_display_operations().setDisplayColorBuffer(displayId,
-                                                                             colorBuffer);
+    return emugl::get_emugl_multi_display_operations().
+        setDisplayColorBuffer(displayId, colorBuffer);
 }
 
 int FrameBuffer::getDisplayColorBuffer(uint32_t displayId, uint32_t* colorBuffer) {
-    return emugl::get_emugl_multi_display_operations().getDisplayColorBuffer(displayId,
-                                                                             colorBuffer);
+    return emugl::get_emugl_multi_display_operations().
+        getDisplayColorBuffer(displayId, colorBuffer);
 }
 
 int FrameBuffer::getColorBufferDisplay(uint32_t colorBuffer, uint32_t* displayId) {
-    return emugl::get_emugl_multi_display_operations().getColorBufferDisplay(colorBuffer,
-                                                                             displayId);
+    return emugl::get_emugl_multi_display_operations().
+        getColorBufferDisplay(colorBuffer, displayId);
 }
 
-int FrameBuffer::getDisplayPose(uint32_t displayId, int32_t* x, int32_t* y, uint32_t* w,
+int FrameBuffer::getDisplayPose(uint32_t displayId,
+                                int32_t* x,
+                                int32_t* y,
+                                uint32_t* w,
                                 uint32_t* h) {
-    return emugl::get_emugl_multi_display_operations().getDisplayPose(displayId, x, y, w, h);
+    return emugl::get_emugl_multi_display_operations().
+        getDisplayPose(displayId, x, y, w, h);
 }
 
-int FrameBuffer::setDisplayPose(uint32_t displayId, int32_t x, int32_t y, uint32_t w, uint32_t h,
+int FrameBuffer::setDisplayPose(uint32_t displayId,
+                                int32_t x,
+                                int32_t y,
+                                uint32_t w,
+                                uint32_t h,
                                 uint32_t dpi) {
-    return emugl::get_emugl_multi_display_operations().setDisplayPose(displayId, x, y, w, h, dpi);
+    return emugl::get_emugl_multi_display_operations().
+        setDisplayPose(displayId, x, y, w, h, dpi);
 }
 
 void FrameBuffer::sweepColorBuffersLocked() {
@@ -2703,25 +3388,44 @@
     return scheduledFuture;
 }
 
-void FrameBuffer::waitForGpuVulkan(uint64_t deviceHandle, uint64_t fenceHandle) {
-    (void)deviceHandle;
-    if (!m_emulationGl) {
-        // Guest ANGLE should always use the asyncWaitForGpuVulkanWithCb call. EmulatedEglFenceSync
-        // is a wrapper over EGLSyncKHR and should not be used for pure Vulkan environment.
+void FrameBuffer::waitForGpu(uint64_t eglsync) {
+    EmulatedEglFenceSync* fenceSync = EmulatedEglFenceSync::getFromHandle(eglsync);
+
+    if (!fenceSync) {
+        ERR("err: fence sync 0x%llx not found", (unsigned long long)eglsync);
         return;
     }
 
-#if GFXSTREAM_ENABLE_HOST_GLES
+    SyncThread::get()->triggerBlockedWaitNoTimeline(fenceSync);
+}
+
+void FrameBuffer::waitForGpuVulkan(uint64_t deviceHandle, uint64_t fenceHandle) {
+    (void)deviceHandle;
+    if (!m_emulationGl) {
+        // Guest ANGLE should always use the asyncWaitForGpuVulkanWithCb call. EmulatedEglFenceSync is a
+        // wrapper over EGLSyncKHR and should not be used for pure Vulkan environment.
+        return;
+    }
+
     // Note: this will always be nullptr.
     EmulatedEglFenceSync* fenceSync = EmulatedEglFenceSync::getFromHandle(fenceHandle);
 
     // Note: This will always signal right away.
     SyncThread::get()->triggerBlockedWaitNoTimeline(fenceSync);
-#endif
 }
 
-void FrameBuffer::asyncWaitForGpuVulkanWithCb(uint64_t deviceHandle, uint64_t fenceHandle,
-                                              FenceCompletionCallback cb) {
+void FrameBuffer::asyncWaitForGpuWithCb(uint64_t eglsync, FenceCompletionCallback cb) {
+    EmulatedEglFenceSync* fenceSync = EmulatedEglFenceSync::getFromHandle(eglsync);
+
+    if (!fenceSync) {
+        ERR("err: fence sync 0x%llx not found", (unsigned long long)eglsync);
+        return;
+    }
+
+    SyncThread::get()->triggerWaitWithCompletionCallback(fenceSync, std::move(cb));
+}
+
+void FrameBuffer::asyncWaitForGpuVulkanWithCb(uint64_t deviceHandle, uint64_t fenceHandle, FenceCompletionCallback cb) {
     (void)deviceHandle;
     SyncThread::get()->triggerWaitVkWithCompletionCallback((VkFence)fenceHandle, std::move(cb));
 }
@@ -2733,9 +3437,7 @@
 void FrameBuffer::waitForGpuVulkanQsri(uint64_t image) {
     (void)image;
     // Signal immediately, because this was a sync wait and it's vulkan.
-#if GFXSTREAM_ENABLE_HOST_GLES
     SyncThread::get()->triggerBlockedWaitNoTimeline(nullptr);
-#endif
 }
 
 void FrameBuffer::setGuestManagedColorBufferLifetime(bool guestManaged) {
@@ -2759,12 +3461,11 @@
     bool preserveContent = (info & RESOURCE_USE_PRESERVE);
 
     switch (type) {
-#if GFXSTREAM_ENABLE_HOST_GLES
         case RESOURCE_TYPE_EGL_NATIVE_PIXMAP:
             return colorBuffer->glOpImportEglNativePixmap(resource, preserveContent);
         case RESOURCE_TYPE_EGL_IMAGE:
             return colorBuffer->glOpImportEglImage(resource, preserveContent);
-#endif
+
         // Note: Additional non-EGL resource-types can be added here, and will
         // be propagated through color-buffer import functionality
         case RESOURCE_TYPE_VK_EXT_MEMORY_HANDLE:
@@ -2777,6 +3478,51 @@
     return true;
 }
 
+void* FrameBuffer::platformCreateSharedEglContext(void) {
+    AutoLock lock(m_lock);
+
+    EGLContext context = 0;
+    EGLSurface surface = 0;
+    createSharedTrivialContext(&context, &surface);
+
+    void* underlyingContext = s_egl.eglGetNativeContextANDROID(getDisplay(), context);
+    if (!underlyingContext) {
+        ERR("Error: Underlying egl backend could not produce a native EGL context.");
+        return nullptr;
+    }
+
+    m_platformEglContexts[underlyingContext] = { context, surface };
+
+#if defined(__QNX__)
+    EGLDisplay currDisplay = eglGetCurrentDisplay();
+    EGLSurface currRead = eglGetCurrentSurface(EGL_READ);
+    EGLSurface currDraw = eglGetCurrentSurface(EGL_DRAW);
+    EGLSurface currContext = eglGetCurrentContext();
+    // Make this context current to ensure thread-state is initialized
+    s_egl.eglMakeCurrent(getDisplay(), surface, surface, context);
+    // Revert back to original state
+    s_egl.eglMakeCurrent(currDisplay, currRead, currDraw, currContext);
+#endif
+
+    return underlyingContext;
+}
+
+bool FrameBuffer::platformDestroySharedEglContext(void* underlyingContext) {
+    AutoLock lock(m_lock);
+
+    auto it = m_platformEglContexts.find(underlyingContext);
+    if (it == m_platformEglContexts.end()) {
+        ERR("Error: Could not find underlying egl context %p (perhaps already destroyed?)", underlyingContext);
+        return false;
+    }
+
+    destroySharedTrivialContext(it->second.context, it->second.surface);
+
+    m_platformEglContexts.erase(it);
+
+    return true;
+}
+
 std::unique_ptr<BorrowedImageInfo> FrameBuffer::borrowColorBufferForComposition(
     uint32_t colorBufferHandle, bool colorBufferIsTarget) {
     ColorBufferPtr colorBufferPtr = findColorBuffer(colorBufferHandle);
@@ -2788,9 +3534,7 @@
     if (m_useVulkanComposition) {
         invalidateColorBufferForVk(colorBufferHandle);
     } else {
-#if GFXSTREAM_ENABLE_HOST_GLES
         invalidateColorBufferForGl(colorBufferHandle);
-#endif
     }
 
     const auto api = m_useVulkanComposition ? ColorBuffer::UsedApi::kVk : ColorBuffer::UsedApi::kGl;
@@ -2808,17 +3552,96 @@
     if (m_useVulkanComposition) {
         invalidateColorBufferForVk(colorBufferHandle);
     } else {
-#if GFXSTREAM_ENABLE_HOST_GLES
         invalidateColorBufferForGl(colorBufferHandle);
-#else
-        ERR("Failed to invalidate ColorBuffer:%d", colorBufferHandle);
-#endif
     }
 
     const auto api = m_useVulkanComposition ? ColorBuffer::UsedApi::kVk : ColorBuffer::UsedApi::kGl;
     return colorBufferPtr->borrowForDisplay(api);
 }
 
+EmulationGl& FrameBuffer::getEmulationGl() {
+    if (!m_emulationGl) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "GL/EGL emulation not enabled.";
+    }
+    return *m_emulationGl;
+}
+
+EGLDisplay FrameBuffer::getDisplay() const {
+    if (!m_emulationGl) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "EGL emulation not enabled.";
+    }
+    return m_emulationGl->mEglDisplay;
+}
+
+EGLSurface FrameBuffer::getWindowSurface() const {
+    if (!m_emulationGl) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "EGL emulation not enabled.";
+    }
+
+    if (!m_emulationGl->mWindowSurface) {
+        return EGL_NO_SURFACE;
+    }
+
+    const auto* displaySurfaceGl =
+        reinterpret_cast<const DisplaySurfaceGl*>(
+            m_emulationGl->mWindowSurface->getImpl());
+
+    return displaySurfaceGl->getSurface();
+}
+
+EGLContext FrameBuffer::getContext() const {
+    if (!m_emulationGl) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "EGL emulation not enabled.";
+    }
+    return m_emulationGl->mEglContext;
+}
+
+EGLContext FrameBuffer::getConfig() const {
+    if (!m_emulationGl) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "EGL emulation not enabled.";
+    }
+    return m_emulationGl->mEglConfig;
+}
+
+EGLContext FrameBuffer::getGlobalEGLContext() const {
+    if (!m_emulationGl) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "EGL emulation not enabled.";
+    }
+
+    if (!m_emulationGl->mPbufferSurface) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "FrameBuffer pbuffer surface not available.";
+    }
+
+    const auto* displaySurfaceGl =
+        reinterpret_cast<const DisplaySurfaceGl*>(
+            m_emulationGl->mPbufferSurface->getImpl());
+
+    return displaySurfaceGl->getContextForShareContext();
+}
+
+ContextHelper* FrameBuffer::getPbufferSurfaceContextHelper() const {
+    if (!m_emulationGl) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "EGL emulation not enabled.";
+    }
+    if (!m_emulationGl->mPbufferSurface) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "EGL emulation pbuffer surface not available.";
+    }
+    const auto* displaySurfaceGl =
+        reinterpret_cast<const DisplaySurfaceGl*>(
+            m_emulationGl->mPbufferSurface->getImpl());
+
+    return displaySurfaceGl->getContextHelper();
+}
+
 void FrameBuffer::logVulkanOutOfMemory(VkResult result, const char* function, int line,
                                        std::optional<uint64_t> allocationSize) {
     m_logger->logMetricEvent(MetricEventVulkanOutOfMemory{
@@ -2829,6 +3652,42 @@
     });
 }
 
+const EmulatedEglConfigList* FrameBuffer::getConfigs() const {
+    if (!m_emulationGl) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "EGL emulation not enabled.";
+    }
+
+    return &m_emulationGl->getEmulationEglConfigs();
+}
+
+TextureDraw* FrameBuffer::getTextureDraw() const {
+    if (!m_emulationGl) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "EGL emulation not enabled.";
+    }
+
+    return m_emulationGl->mTextureDraw.get();
+}
+
+bool FrameBuffer::isFastBlitSupported() const {
+    if (!m_emulationGl) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "EGL emulation not enabled.";
+    }
+
+    return m_emulationGl->isFastBlitSupported();
+}
+
+void FrameBuffer::disableFastBlitForTesting() {
+    if (!m_emulationGl) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "EGL emulation not enabled.";
+    }
+
+    m_emulationGl->disableFastBlitForTesting();
+}
+
 void FrameBuffer::setVsyncHz(int vsyncHz) {
     const uint64_t kOneSecondNs = 1000000000ULL;
     m_vsyncHz = vsyncHz;
@@ -2847,7 +3706,8 @@
     m_vsyncThread->schedule(task);
 }
 
-void FrameBuffer::setDisplayConfigs(int configId, int w, int h, int dpiX, int dpiY) {
+void FrameBuffer::setDisplayConfigs(int configId, int w, int h,
+                                    int dpiX, int dpiY) {
     AutoLock mutex(m_lock);
     mDisplayConfigs[configId] = {w, h, dpiX, dpiY};
     INFO("setDisplayConfigs w %d h %d dpiX %d dpiY %d", w, h, dpiX, dpiY);
@@ -2901,6 +3761,15 @@
     return mDisplayActiveConfigId >= 0 ? mDisplayActiveConfigId : -1;
 }
 
+bool FrameBuffer::flushColorBufferFromGl(HandleType colorBufferHandle) {
+    auto colorBuffer = findColorBuffer(colorBufferHandle);
+    if (!colorBuffer) {
+        ERR("Failed to find ColorBuffer:%d", colorBufferHandle);
+        return false;
+    }
+    return colorBuffer->flushFromGl();
+}
+
 bool FrameBuffer::flushColorBufferFromVk(HandleType colorBufferHandle) {
     auto colorBuffer = findColorBuffer(colorBufferHandle);
     if (!colorBuffer) {
@@ -2910,8 +3779,7 @@
     return colorBuffer->flushFromVk();
 }
 
-bool FrameBuffer::flushColorBufferFromVkBytes(HandleType colorBufferHandle, const void* bytes,
-                                              size_t bytesSize) {
+bool FrameBuffer::flushColorBufferFromVkBytes(HandleType colorBufferHandle, const void* bytes, size_t bytesSize) {
     AutoLock mutex(m_lock);
 
     auto colorBuffer = findColorBuffer(colorBufferHandle);
@@ -2922,6 +3790,15 @@
     return colorBuffer->flushFromVkBytes(bytes, bytesSize);
 }
 
+bool FrameBuffer::invalidateColorBufferForGl(HandleType colorBufferHandle) {
+    auto colorBuffer = findColorBuffer(colorBufferHandle);
+    if (!colorBuffer) {
+        ERR("Failed to find ColorBuffer:%d", colorBufferHandle);
+        return false;
+    }
+    return colorBuffer->invalidateForGl();
+}
+
 bool FrameBuffer::invalidateColorBufferForVk(HandleType colorBufferHandle) {
     // It reads contents from GL, which requires a context lock.
     // Also we should not do this in PostWorkerGl, otherwise it will deadlock.
@@ -2937,900 +3814,22 @@
     return colorBuffer->invalidateForVk();
 }
 
-#if GFXSTREAM_ENABLE_HOST_GLES
-HandleType FrameBuffer::getEmulatedEglWindowSurfaceColorBufferHandle(HandleType p_surface) {
-    AutoLock mutex(m_lock);
-
-    auto it = m_EmulatedEglWindowSurfaceToColorBuffer.find(p_surface);
-    if (it == m_EmulatedEglWindowSurfaceToColorBuffer.end()) {
-        return 0;
-    }
-
-    return it->second;
-}
-
-void FrameBuffer::createTrivialContext(HandleType shared, HandleType* contextOut,
-                                       HandleType* surfOut) {
-    assert(contextOut);
-    assert(surfOut);
-
-    *contextOut = createEmulatedEglContext(0, shared, GLESApi_2);
-    // Zero size is formally allowed here, but SwiftShader doesn't like it and
-    // fails.
-    *surfOut = createEmulatedEglWindowSurface(0, 1, 1);
-}
-
-void FrameBuffer::createSharedTrivialContext(EGLContext* contextOut, EGLSurface* surfOut) {
-    assert(contextOut);
-    assert(surfOut);
-
-    const EmulatedEglConfig* config = getConfigs()->get(0 /* p_config */);
-    if (!config) return;
-
-    int maj, min;
-    emugl::getGlesVersion(&maj, &min);
-
-    const EGLint contextAttribs[] = {EGL_CONTEXT_MAJOR_VERSION_KHR, maj,
-                                     EGL_CONTEXT_MINOR_VERSION_KHR, min, EGL_NONE};
-
-    *contextOut = s_egl.eglCreateContext(getDisplay(), config->getHostEglConfig(),
-                                         getGlobalEGLContext(), contextAttribs);
-
-    const EGLint pbufAttribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
-
-    *surfOut = s_egl.eglCreatePbufferSurface(getDisplay(), config->getHostEglConfig(), pbufAttribs);
-}
-
-void FrameBuffer::destroySharedTrivialContext(EGLContext context, EGLSurface surface) {
-    if (getDisplay() != EGL_NO_DISPLAY) {
-        s_egl.eglDestroyContext(getDisplay(), context);
-        s_egl.eglDestroySurface(getDisplay(), surface);
-    }
-}
-
-const EmulatedEglConfigList* FrameBuffer::getConfigs() const {
-    if (!m_emulationGl) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "EGL emulation not enabled.";
-    }
-
-    return &m_emulationGl->getEmulationEglConfigs();
-}
-
-bool FrameBuffer::setEmulatedEglWindowSurfaceColorBuffer(HandleType p_surface,
-                                                         HandleType p_colorbuffer) {
-    AutoLock mutex(m_lock);
-
-    EmulatedEglWindowSurfaceMap::iterator w(m_windows.find(p_surface));
-    if (w == m_windows.end()) {
-        // bad surface handle
-        ERR("bad window surface handle %#x", p_surface);
-        return false;
-    }
-
-    {
-        AutoLock colorBufferMapLock(m_colorBufferMapLock);
-        ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
-        if (c == m_colorbuffers.end()) {
-            ERR("bad color buffer handle %#x", p_colorbuffer);
-            // bad colorbuffer handle
-            return false;
-        }
-
-        (*w).second.first->setColorBuffer((*c).second.cb);
-        markOpened(&c->second);
-        if (!m_guestManagedColorBufferLifetime) {
-            c->second.refcount++;
-        }
-    }
-    if (w->second.second) {
-        if (!m_guestManagedColorBufferLifetime) {
-            if (m_refCountPipeEnabled) {
-                decColorBufferRefCountLocked(w->second.second);
-            } else {
-                closeColorBufferLocked(w->second.second);
-            }
-        }
-    }
-
-    (*w).second.second = p_colorbuffer;
-
-    m_EmulatedEglWindowSurfaceToColorBuffer[p_surface] = p_colorbuffer;
-
-    return true;
-}
-
-HandleType FrameBuffer::createEmulatedEglContext(int config, HandleType shareContextHandle,
-                                                 GLESApi version) {
-    if (!m_emulationGl) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "EGL emulation unavailable.";
-    }
-
-    AutoLock mutex(m_lock);
-    android::base::AutoWriteLock contextLock(m_contextStructureLock);
-    // Hold the ColorBuffer map lock so that the new handle won't collide with a ColorBuffer handle.
-    AutoLock colorBufferMapLock(m_colorBufferMapLock);
-
-    EmulatedEglContextPtr shareContext = nullptr;
-    if (shareContextHandle != 0) {
-        auto shareContextIt = m_contexts.find(shareContextHandle);
-        if (shareContextIt == m_contexts.end()) {
-            ERR("Failed to find share EmulatedEglContext:%d", shareContextHandle);
-            return 0;
-        }
-        shareContext = shareContextIt->second;
-    }
-
-    HandleType contextHandle = genHandle_locked();
-    auto context =
-        m_emulationGl->createEmulatedEglContext(config, shareContext.get(), version, contextHandle);
-    if (!context) {
-        ERR("Failed to create EmulatedEglContext.");
-        return 0;
-    }
-
-    m_contexts[contextHandle] = std::move(context);
-
-    RenderThreadInfo* tinfo = RenderThreadInfo::get();
-    uint64_t puid = tinfo->m_puid;
-    // The new emulator manages render contexts per guest process.
-    // Fall back to per-thread management if the system image does not
-    // support it.
-    if (puid) {
-        m_procOwnedEmulatedEglContexts[puid].insert(contextHandle);
-    } else {  // legacy path to manage context lifetime by threads
-        if (!tinfo->m_glInfo) {
-            GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Render thread GL not available.";
-        }
-        tinfo->m_glInfo->m_contextSet.insert(contextHandle);
-    }
-
-    return contextHandle;
-}
-
-void FrameBuffer::destroyEmulatedEglContext(HandleType contextHandle) {
-    AutoLock mutex(m_lock);
-    sweepColorBuffersLocked();
-
-    android::base::AutoWriteLock contextLock(m_contextStructureLock);
-    m_contexts.erase(contextHandle);
-    RenderThreadInfo* tinfo = RenderThreadInfo::get();
-    uint64_t puid = tinfo->m_puid;
-    // The new emulator manages render contexts per guest process.
-    // Fall back to per-thread management if the system image does not
-    // support it.
-    if (puid) {
-        auto it = m_procOwnedEmulatedEglContexts.find(puid);
-        if (it != m_procOwnedEmulatedEglContexts.end()) {
-            it->second.erase(contextHandle);
-        }
-    } else {
-        if (!tinfo->m_glInfo) {
-            GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Render thread GL not available.";
-        }
-        tinfo->m_glInfo->m_contextSet.erase(contextHandle);
-    }
-}
-
-HandleType FrameBuffer::createEmulatedEglWindowSurface(int p_config, int p_width, int p_height) {
-    if (!m_emulationGl) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "EGL emulation unavailable.";
-    }
-
-    AutoLock mutex(m_lock);
-    // Hold the ColorBuffer map lock so that the new handle won't collide with a ColorBuffer handle.
-    AutoLock colorBufferMapLock(m_colorBufferMapLock);
-
-    HandleType handle = genHandle_locked();
-
-    auto window =
-        m_emulationGl->createEmulatedEglWindowSurface(p_config, p_width, p_height, handle);
-    if (!window) {
-        ERR("Failed to create EmulatedEglWindowSurface.");
-        return 0;
-    }
-
-    m_windows[handle] = {std::move(window), 0};
-
-    RenderThreadInfo* info = RenderThreadInfo::get();
-    if (!info->m_glInfo) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "RRenderThreadInfoGl not available.";
-    }
-
-    uint64_t puid = info->m_puid;
-    if (puid) {
-        m_procOwnedEmulatedEglWindowSurfaces[puid].insert(handle);
-    } else {  // legacy path to manage window surface lifetime by threads
-        info->m_glInfo->m_windowSet.insert(handle);
-    }
-
-    return handle;
-}
-
-void FrameBuffer::destroyEmulatedEglWindowSurface(HandleType p_surface) {
-    if (m_shuttingDown) {
-        return;
-    }
-    AutoLock mutex(m_lock);
-    destroyEmulatedEglWindowSurfaceLocked(p_surface);
-}
-
-std::vector<HandleType> FrameBuffer::destroyEmulatedEglWindowSurfaceLocked(HandleType p_surface) {
-    std::vector<HandleType> colorBuffersToCleanUp;
-    const auto w = m_windows.find(p_surface);
-    if (w != m_windows.end()) {
-        RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper());
-        if (!m_guestManagedColorBufferLifetime) {
-            if (m_refCountPipeEnabled) {
-                if (decColorBufferRefCountLocked(w->second.second)) {
-                    colorBuffersToCleanUp.push_back(w->second.second);
-                }
-            } else {
-                if (closeColorBufferLocked(w->second.second)) {
-                    colorBuffersToCleanUp.push_back(w->second.second);
-                }
-            }
-        }
-        m_windows.erase(w);
-        RenderThreadInfo* tinfo = RenderThreadInfo::get();
-        uint64_t puid = tinfo->m_puid;
-        if (puid) {
-            auto ite = m_procOwnedEmulatedEglWindowSurfaces.find(puid);
-            if (ite != m_procOwnedEmulatedEglWindowSurfaces.end()) {
-                ite->second.erase(p_surface);
-            }
-        } else {
-            if (!tinfo->m_glInfo) {
-                GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
-                    << "Render thread GL not available.";
-            }
-            tinfo->m_glInfo->m_windowSet.erase(p_surface);
-        }
-    }
-    return colorBuffersToCleanUp;
-}
-
-void FrameBuffer::createEmulatedEglFenceSync(EGLenum type, int destroyWhenSignaled,
-                                             uint64_t* outSync, uint64_t* outSyncThread) {
-    if (!m_emulationGl) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "GL/EGL emulation not available.";
-    }
-
-    // TODO(b/233939967): move RenderThreadInfoGl usage to EmulationGl.
-    RenderThreadInfoGl* const info = RenderThreadInfoGl::get();
-    if (!info) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "RenderThreadInfoGl not available.";
-    }
-    if (!info->currContext) {
-        auto fb = FrameBuffer::getFB();
-        uint32_t syncContext;
-        uint32_t syncSurface;
-        createTrivialContext(0,  // There is no context to share.
-                             &syncContext, &syncSurface);
-        bindContext(syncContext, syncSurface, syncSurface);
-        // This context is then cleaned up when the render thread exits.
-    }
-
-    auto sync = m_emulationGl->createEmulatedEglFenceSync(type, destroyWhenSignaled);
-    if (!sync) {
-        return;
-    }
-
-    if (outSync) {
-        *outSync = (uint64_t)(uintptr_t)sync.release();
-    }
-    if (outSyncThread) {
-        *outSyncThread = reinterpret_cast<uint64_t>(SyncThread::get());
-    }
-}
-
-void FrameBuffer::drainGlRenderThreadResources() {
-    // If we're already exiting then snapshot should not contain
-    // this thread information at all.
-    if (isShuttingDown()) {
-        return;
-    }
-
-    // Release references to the current thread's context/surfaces if any
-    bindContext(0, 0, 0);
-
-    drainGlRenderThreadSurfaces();
-    drainGlRenderThreadContexts();
-
-    if (!s_egl.eglReleaseThread()) {
-        ERR("Error: RenderThread @%p failed to eglReleaseThread()", this);
-    }
-}
-
-void FrameBuffer::drainGlRenderThreadContexts() {
-    if (isShuttingDown()) {
-        return;
-    }
-
-    RenderThreadInfoGl* const tinfo = RenderThreadInfoGl::get();
-    if (!tinfo) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Render thread GL not available.";
-    }
-
-    if (tinfo->m_contextSet.empty()) {
-        return;
-    }
-
-    AutoLock mutex(m_lock);
-    android::base::AutoWriteLock contextLock(m_contextStructureLock);
-    for (const HandleType contextHandle : tinfo->m_contextSet) {
-        m_contexts.erase(contextHandle);
-    }
-    tinfo->m_contextSet.clear();
-}
-
-void FrameBuffer::drainGlRenderThreadSurfaces() {
-    if (isShuttingDown()) {
-        return;
-    }
-
-    RenderThreadInfoGl* const tinfo = RenderThreadInfoGl::get();
-    if (!tinfo) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Render thread GL not available.";
-    }
-
-    if (tinfo->m_windowSet.empty()) {
-        return;
-    }
-
-    std::vector<HandleType> colorBuffersToCleanup;
-
-    AutoLock mutex(m_lock);
-    RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper());
-    for (const HandleType winHandle : tinfo->m_windowSet) {
-        const auto winIt = m_windows.find(winHandle);
-        if (winIt != m_windows.end()) {
-            if (const HandleType oldColorBufferHandle = winIt->second.second) {
-                if (!m_guestManagedColorBufferLifetime) {
-                    if (m_refCountPipeEnabled) {
-                        if (decColorBufferRefCountLocked(oldColorBufferHandle)) {
-                            colorBuffersToCleanup.push_back(oldColorBufferHandle);
-                        }
-                    } else {
-                        if (closeColorBufferLocked(oldColorBufferHandle)) {
-                            colorBuffersToCleanup.push_back(oldColorBufferHandle);
-                        }
-                    }
-                }
-                m_windows.erase(winIt);
-            }
-        }
-    }
-    tinfo->m_windowSet.clear();
-}
-
-EmulationGl& FrameBuffer::getEmulationGl() {
-    if (!m_emulationGl) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "GL/EGL emulation not enabled.";
-    }
-    return *m_emulationGl;
-}
-
-EGLDisplay FrameBuffer::getDisplay() const {
-    if (!m_emulationGl) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "EGL emulation not enabled.";
-    }
-    return m_emulationGl->mEglDisplay;
-}
-
-EGLSurface FrameBuffer::getWindowSurface() const {
-    if (!m_emulationGl) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "EGL emulation not enabled.";
-    }
-
-    if (!m_emulationGl->mWindowSurface) {
-        return EGL_NO_SURFACE;
-    }
-
-    const auto* displaySurfaceGl =
-        reinterpret_cast<const DisplaySurfaceGl*>(m_emulationGl->mWindowSurface->getImpl());
-
-    return displaySurfaceGl->getSurface();
-}
-
-EGLContext FrameBuffer::getContext() const {
-    if (!m_emulationGl) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "EGL emulation not enabled.";
-    }
-    return m_emulationGl->mEglContext;
-}
-
-EGLContext FrameBuffer::getConfig() const {
-    if (!m_emulationGl) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "EGL emulation not enabled.";
-    }
-    return m_emulationGl->mEglConfig;
-}
-
-EGLContext FrameBuffer::getGlobalEGLContext() const {
-    if (!m_emulationGl) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "EGL emulation not enabled.";
-    }
-
-    if (!m_emulationGl->mPbufferSurface) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
-            << "FrameBuffer pbuffer surface not available.";
-    }
-
-    const auto* displaySurfaceGl =
-        reinterpret_cast<const DisplaySurfaceGl*>(m_emulationGl->mPbufferSurface->getImpl());
-
-    return displaySurfaceGl->getContextForShareContext();
-}
-
-EmulatedEglContextPtr FrameBuffer::getContext_locked(HandleType p_context) {
-    return android::base::findOrDefault(m_contexts, p_context);
-}
-
-EmulatedEglWindowSurfacePtr FrameBuffer::getWindowSurface_locked(HandleType p_windowsurface) {
-    return android::base::findOrDefault(m_windows, p_windowsurface).first;
-}
-
-TextureDraw* FrameBuffer::getTextureDraw() const {
-    if (!m_emulationGl) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "EGL emulation not enabled.";
-    }
-
-    return m_emulationGl->mTextureDraw.get();
-}
-
-bool FrameBuffer::isFastBlitSupported() const {
-    if (!m_emulationGl) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "EGL emulation not enabled.";
-    }
-
-    return m_emulationGl->isFastBlitSupported();
-}
-
-void FrameBuffer::disableFastBlitForTesting() {
-    if (!m_emulationGl) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "EGL emulation not enabled.";
-    }
-
-    m_emulationGl->disableFastBlitForTesting();
-}
-
-HandleType FrameBuffer::createEmulatedEglImage(HandleType contextHandle, EGLenum target,
-                                               GLuint buffer) {
-    if (!m_emulationGl) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "GL/EGL emulation not enabled.";
-    }
-
-    AutoLock mutex(m_lock);
-
-    EmulatedEglContext* context = nullptr;
-    if (contextHandle) {
-        android::base::AutoWriteLock contextLock(m_contextStructureLock);
-
-        auto it = m_contexts.find(contextHandle);
-        if (it == m_contexts.end()) {
-            ERR("Failed to find EmulatedEglContext:%d", contextHandle);
-            return false;
-        }
-
-        context = it->second.get();
-    }
-
-    auto image = m_emulationGl->createEmulatedEglImage(context, target,
-                                                       reinterpret_cast<EGLClientBuffer>(buffer));
-    if (!image) {
-        ERR("Failed to create EmulatedEglImage");
-        return false;
-    }
-
-    HandleType imageHandle = image->getHandle();
-
-    m_images[imageHandle] = std::move(image);
-
-    RenderThreadInfo* tInfo = RenderThreadInfo::get();
-    uint64_t puid = tInfo->m_puid;
-    if (puid) {
-        m_procOwnedEmulatedEglImages[puid].insert(imageHandle);
-    }
-    return imageHandle;
-}
-
-EGLBoolean FrameBuffer::destroyEmulatedEglImage(HandleType imageHandle) {
-    if (!m_emulationGl) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "GL/EGL emulation not enabled.";
-    }
-
-    AutoLock mutex(m_lock);
-
-    auto imageIt = m_images.find(imageHandle);
-    if (imageIt == m_images.end()) {
-        ERR("Failed to find EmulatedEglImage:%d", imageHandle);
-        return false;
-    }
-    auto& image = imageIt->second;
-
-    EGLBoolean success = image->destroy();
-    m_images.erase(imageIt);
-
-    RenderThreadInfo* tInfo = RenderThreadInfo::get();
-    uint64_t puid = tInfo->m_puid;
-    if (puid) {
-        m_procOwnedEmulatedEglImages[puid].erase(imageHandle);
-        // We don't explicitly call m_procOwnedEmulatedEglImages.erase(puid) when the
-        // size reaches 0, since it could go between zero and one many times in
-        // the lifetime of a process. It will be cleaned up by
-        // cleanupProcGLObjects(puid) when the process is dead.
-    }
-    return success;
-}
-
-bool FrameBuffer::flushEmulatedEglWindowSurfaceColorBuffer(HandleType p_surface) {
-    AutoLock mutex(m_lock);
-
-    auto it = m_windows.find(p_surface);
-    if (it == m_windows.end()) {
-        ERR("FB::flushEmulatedEglWindowSurfaceColorBuffer: window handle %#x not found", p_surface);
-        // bad surface handle
-        return false;
-    }
-
-    EmulatedEglWindowSurface* surface = it->second.first.get();
-    surface->flushColorBuffer();
-
-    return true;
-}
-
-GLESDispatchMaxVersion FrameBuffer::getMaxGLESVersion() {
-    if (!m_emulationGl) {
-        return GLES_DISPATCH_MAX_VERSION_2;
-    }
-    return m_emulationGl->getGlesMaxDispatchVersion();
-}
-
-void FrameBuffer::fillGLESUsages(android_studio::EmulatorGLESUsages* usages) {
-    if (s_egl.eglFillUsages) {
-        s_egl.eglFillUsages(usages);
-    }
-}
-
-void* FrameBuffer::platformCreateSharedEglContext(void) {
-    AutoLock lock(m_lock);
-
-    EGLContext context = 0;
-    EGLSurface surface = 0;
-    createSharedTrivialContext(&context, &surface);
-
-    void* underlyingContext = s_egl.eglGetNativeContextANDROID(getDisplay(), context);
-    if (!underlyingContext) {
-        ERR("Error: Underlying egl backend could not produce a native EGL context.");
-        return nullptr;
-    }
-
-    m_platformEglContexts[underlyingContext] = {context, surface};
-
-#if defined(__QNX__)
-    EGLDisplay currDisplay = eglGetCurrentDisplay();
-    EGLSurface currRead = eglGetCurrentSurface(EGL_READ);
-    EGLSurface currDraw = eglGetCurrentSurface(EGL_DRAW);
-    EGLSurface currContext = eglGetCurrentContext();
-    // Make this context current to ensure thread-state is initialized
-    s_egl.eglMakeCurrent(getDisplay(), surface, surface, context);
-    // Revert back to original state
-    s_egl.eglMakeCurrent(currDisplay, currRead, currDraw, currContext);
-#endif
-
-    return underlyingContext;
-}
-
-bool FrameBuffer::platformDestroySharedEglContext(void* underlyingContext) {
-    AutoLock lock(m_lock);
-
-    auto it = m_platformEglContexts.find(underlyingContext);
-    if (it == m_platformEglContexts.end()) {
-        ERR("Error: Could not find underlying egl context %p (perhaps already destroyed?)",
-            underlyingContext);
-        return false;
-    }
-
-    destroySharedTrivialContext(it->second.context, it->second.surface);
-
-    m_platformEglContexts.erase(it);
-
-    return true;
-}
-
-bool FrameBuffer::flushColorBufferFromGl(HandleType colorBufferHandle) {
-    auto colorBuffer = findColorBuffer(colorBufferHandle);
-    if (!colorBuffer) {
-        ERR("Failed to find ColorBuffer:%d", colorBufferHandle);
-        return false;
-    }
-    return colorBuffer->flushFromGl();
-}
-
-bool FrameBuffer::invalidateColorBufferForGl(HandleType colorBufferHandle) {
-    auto colorBuffer = findColorBuffer(colorBufferHandle);
-    if (!colorBuffer) {
-        ERR("Failed to find ColorBuffer:%d", colorBufferHandle);
-        return false;
-    }
-    return colorBuffer->invalidateForGl();
-}
-
-ContextHelper* FrameBuffer::getPbufferSurfaceContextHelper() const {
-    if (!m_emulationGl) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "EGL emulation not enabled.";
-    }
-    if (!m_emulationGl->mPbufferSurface) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
-            << "EGL emulation pbuffer surface not available.";
-    }
-    const auto* displaySurfaceGl =
-        reinterpret_cast<const DisplaySurfaceGl*>(m_emulationGl->mPbufferSurface->getImpl());
-
-    return displaySurfaceGl->getContextHelper();
-}
-
-bool FrameBuffer::bindColorBufferToTexture(HandleType p_colorbuffer) {
-    AutoLock mutex(m_lock);
-
-    ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer);
-    if (!colorBuffer) {
-        // bad colorbuffer handle
-        return false;
-    }
-
-    return colorBuffer->glOpBindToTexture();
-}
-
-bool FrameBuffer::bindColorBufferToTexture2(HandleType p_colorbuffer) {
-    // This is only called when using multi window display
-    // It will deadlock when posting from main thread.
-    std::unique_ptr<AutoLock> mutex;
-    if (!postOnlyOnMainThread()) {
-        mutex = std::make_unique<AutoLock>(m_lock);
-    }
-
-    ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer);
-    if (!colorBuffer) {
-        // bad colorbuffer handle
-        return false;
-    }
-
-    return colorBuffer->glOpBindToTexture2();
-}
-
-bool FrameBuffer::bindColorBufferToRenderbuffer(HandleType p_colorbuffer) {
-    AutoLock mutex(m_lock);
-
-    ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer);
-    if (!colorBuffer) {
-        // bad colorbuffer handle
-        return false;
-    }
-
-    return colorBuffer->glOpBindToRenderbuffer();
-}
-
-bool FrameBuffer::bindContext(HandleType p_context, HandleType p_drawSurface,
-                              HandleType p_readSurface) {
-    if (m_shuttingDown) {
-        return false;
-    }
-
-    AutoLock mutex(m_lock);
-
-    EmulatedEglWindowSurfacePtr draw, read;
-    EmulatedEglContextPtr ctx;
-
-    //
-    // if this is not an unbind operation - make sure all handles are good
-    //
-    if (p_context || p_drawSurface || p_readSurface) {
-        ctx = getContext_locked(p_context);
-        if (!ctx) return false;
-        EmulatedEglWindowSurfaceMap::iterator w(m_windows.find(p_drawSurface));
-        if (w == m_windows.end()) {
-            // bad surface handle
-            return false;
-        }
-        draw = (*w).second.first;
-
-        if (p_readSurface != p_drawSurface) {
-            EmulatedEglWindowSurfaceMap::iterator w(m_windows.find(p_readSurface));
-            if (w == m_windows.end()) {
-                // bad surface handle
-                return false;
-            }
-            read = (*w).second.first;
-        } else {
-            read = draw;
-        }
-    } else {
-        // if unbind operation, sweep color buffers
-        sweepColorBuffersLocked();
-    }
-
-    if (!s_egl.eglMakeCurrent(getDisplay(), draw ? draw->getEGLSurface() : EGL_NO_SURFACE,
-                              read ? read->getEGLSurface() : EGL_NO_SURFACE,
-                              ctx ? ctx->getEGLContext() : EGL_NO_CONTEXT)) {
-        ERR("eglMakeCurrent failed");
-        return false;
-    }
-
-    //
-    // Bind the surface(s) to the context
-    //
-    RenderThreadInfoGl* const tinfo = RenderThreadInfoGl::get();
-    if (!tinfo) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Render thread GL not available.";
-    }
-
-    EmulatedEglWindowSurfacePtr bindDraw, bindRead;
-    if (draw.get() == NULL && read.get() == NULL) {
-        // Unbind the current read and draw surfaces from the context
-        bindDraw = tinfo->currDrawSurf;
-        bindRead = tinfo->currReadSurf;
-    } else {
-        bindDraw = draw;
-        bindRead = read;
-    }
-
-    if (bindDraw.get() != NULL && bindRead.get() != NULL) {
-        if (bindDraw.get() != bindRead.get()) {
-            bindDraw->bind(ctx, EmulatedEglWindowSurface::BIND_DRAW);
-            bindRead->bind(ctx, EmulatedEglWindowSurface::BIND_READ);
-        } else {
-            bindDraw->bind(ctx, EmulatedEglWindowSurface::BIND_READDRAW);
-        }
-    }
-
-    //
-    // update thread info with current bound context
-    //
-    tinfo->currContext = ctx;
-    tinfo->currDrawSurf = draw;
-    tinfo->currReadSurf = read;
-    if (ctx) {
-        if (ctx->clientVersion() > GLESApi_CM)
-            tinfo->m_gl2Dec.setContextData(&ctx->decoderContextData());
-        else
-            tinfo->m_glDec.setContextData(&ctx->decoderContextData());
-    } else {
-        tinfo->m_glDec.setContextData(NULL);
-        tinfo->m_gl2Dec.setContextData(NULL);
-    }
-    return true;
-}
-
-void FrameBuffer::createYUVTextures(uint32_t type, uint32_t count, int width, int height,
-                                    uint32_t* output) {
-    FrameworkFormat format = static_cast<FrameworkFormat>(type);
-    AutoLock mutex(m_lock);
-    RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper());
-    for (uint32_t i = 0; i < count; ++i) {
-        if (format == FRAMEWORK_FORMAT_NV12) {
-            YUVConverter::createYUVGLTex(GL_TEXTURE0, width, height, format, YUVPlane::Y,
-                                         &output[2 * i]);
-            YUVConverter::createYUVGLTex(GL_TEXTURE1, width / 2, height / 2, format, YUVPlane::UV,
-                                         &output[2 * i + 1]);
-        } else if (format == FRAMEWORK_FORMAT_YUV_420_888) {
-            YUVConverter::createYUVGLTex(GL_TEXTURE0, width, height, format, YUVPlane::Y,
-                                         &output[3 * i]);
-            YUVConverter::createYUVGLTex(GL_TEXTURE1, width / 2, height / 2, format, YUVPlane::U,
-                                         &output[3 * i + 1]);
-            YUVConverter::createYUVGLTex(GL_TEXTURE2, width / 2, height / 2, format, YUVPlane::V,
-                                         &output[3 * i + 2]);
-        }
-    }
-}
-
-void FrameBuffer::destroyYUVTextures(uint32_t type, uint32_t count, uint32_t* textures) {
-    AutoLock mutex(m_lock);
-    RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper());
-    if (type == FRAMEWORK_FORMAT_NV12) {
-        s_gles2.glDeleteTextures(2 * count, textures);
-    } else if (type == FRAMEWORK_FORMAT_YUV_420_888) {
-        s_gles2.glDeleteTextures(3 * count, textures);
-    }
-}
-
-void FrameBuffer::updateYUVTextures(uint32_t type, uint32_t* textures, void* privData, void* func) {
-    AutoLock mutex(m_lock);
-    RecursiveScopedContextBind bind(getPbufferSurfaceContextHelper());
-
-    yuv_updater_t updater = (yuv_updater_t)func;
-    uint32_t gtextures[3] = {0, 0, 0};
-
-    if (type == FRAMEWORK_FORMAT_NV12) {
-        gtextures[0] = s_gles2.glGetGlobalTexName(textures[0]);
-        gtextures[1] = s_gles2.glGetGlobalTexName(textures[1]);
-    } else if (type == FRAMEWORK_FORMAT_YUV_420_888) {
-        gtextures[0] = s_gles2.glGetGlobalTexName(textures[0]);
-        gtextures[1] = s_gles2.glGetGlobalTexName(textures[1]);
-        gtextures[2] = s_gles2.glGetGlobalTexName(textures[2]);
-    }
-
-#ifdef __APPLE__
-    EGLContext prevContext = s_egl.eglGetCurrentContext();
-    auto mydisp = EglGlobalInfo::getInstance()->getDisplayFromDisplayType(EGL_DEFAULT_DISPLAY);
-    void* nativecontext = mydisp->getLowLevelContext(prevContext);
-    struct MediaNativeCallerData callerdata;
-    callerdata.ctx = nativecontext;
-    callerdata.converter = nsConvertVideoFrameToNV12Textures;
-    void* pcallerdata = &callerdata;
-#else
-    void* pcallerdata = nullptr;
-#endif
-
-    updater(privData, type, gtextures, pcallerdata);
-}
-
-void FrameBuffer::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) {
-    {
-        AutoLock mutex(m_lock);
-        ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer);
-        if (!colorBuffer) {
-            // bad colorbuffer handle
-            return;
-        }
-        colorBuffer->glOpSwapYuvTexturesAndUpdate(
-            format, type, static_cast<FrameworkFormat>(texture_type), textures);
-    }
-}
-
-bool FrameBuffer::readColorBufferContents(HandleType p_colorbuffer, size_t* numBytes,
-                                          void* pixels) {
-    AutoLock mutex(m_lock);
-
-    ColorBufferPtr colorBuffer = findColorBuffer(p_colorbuffer);
-    if (!colorBuffer) {
-        // bad colorbuffer handle
-        return false;
-    }
-
-    return colorBuffer->glOpReadContents(numBytes, pixels);
-}
-
-void FrameBuffer::waitForGpu(uint64_t eglsync) {
-    EmulatedEglFenceSync* fenceSync = EmulatedEglFenceSync::getFromHandle(eglsync);
-
-    if (!fenceSync) {
-        ERR("err: fence sync 0x%llx not found", (unsigned long long)eglsync);
-        return;
-    }
-
-    SyncThread::get()->triggerBlockedWaitNoTimeline(fenceSync);
-}
-
-void FrameBuffer::asyncWaitForGpuWithCb(uint64_t eglsync, FenceCompletionCallback cb) {
-    EmulatedEglFenceSync* fenceSync = EmulatedEglFenceSync::getFromHandle(eglsync);
-
-    if (!fenceSync) {
-        ERR("err: fence sync 0x%llx not found", (unsigned long long)eglsync);
-        return;
-    }
-
-    SyncThread::get()->triggerWaitWithCompletionCallback(fenceSync, std::move(cb));
-}
-
-const gl::GLESv2Dispatch* FrameBuffer::getGles2Dispatch() {
-    if (!m_emulationGl) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "EGL emulation not enabled.";
-    }
-
-    return m_emulationGl->getGles2Dispatch();
-}
-
 const gl::EGLDispatch* FrameBuffer::getEglDispatch() {
     if (!m_emulationGl) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "EGL emulation not enabled.";
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "EGL emulation not enabled.";
     }
 
     return m_emulationGl->getEglDispatch();
 }
 
-#endif
+const gl::GLESv2Dispatch* FrameBuffer::getGles2Dispatch() {
+    if (!m_emulationGl) {
+        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+            << "EGL emulation not enabled.";
+    }
+
+    return m_emulationGl->getGles2Dispatch();
+}
 
 }  // namespace gfxstream
diff --git a/host/FrameBuffer.h b/host/FrameBuffer.h
index ecb28a9..60a6a35 100644
--- a/host/FrameBuffer.h
+++ b/host/FrameBuffer.h
@@ -16,6 +16,9 @@
 #ifndef _LIBRENDER_FRAMEBUFFER_H
 #define _LIBRENDER_FRAMEBUFFER_H
 
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
 #include <stdint.h>
 
 #include <array>
@@ -27,7 +30,6 @@
 #include <unordered_set>
 
 #include "Buffer.h"
-#include "ColorBuffer.h"
 #include "Compositor.h"
 #include "Display.h"
 #include "DisplaySurface.h"
@@ -46,13 +48,6 @@
 #include "aemu/base/synchronization/MessageChannel.h"
 #include "aemu/base/threads/Thread.h"
 #include "aemu/base/threads/WorkerThread.h"
-
-#if GFXSTREAM_ENABLE_HOST_GLES
-
-#include <EGL/egl.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
 #include "gl/BufferGl.h"
 #include "gl/ColorBufferGl.h"
 #include "gl/CompositorGl.h"
@@ -64,19 +59,6 @@
 #include "gl/EmulationGl.h"
 #include "gl/GLESVersionDetector.h"
 #include "gl/TextureDraw.h"
-#else
-#include "GlesCompat.h"
-#endif
-
-// values for 'param' argument of rcGetFBParam
-#define FB_WIDTH 1
-#define FB_HEIGHT 2
-#define FB_XDPI 3
-#define FB_YDPI 4
-#define FB_FPS 5
-#define FB_MIN_SWAP_INTERVAL 6
-#define FB_MAX_SWAP_INTERVAL 7
-
 #include "render-utils/Renderer.h"
 #include "render-utils/virtio_gpu_ops.h"
 #include "render-utils/render_api.h"
@@ -119,13 +101,10 @@
     mutable std::atomic<uint32_t> mSequenceNumber;
 };
 
-#if GFXSTREAM_ENABLE_HOST_GLES
 typedef std::unordered_map<uint64_t, gl::EmulatedEglWindowSurfaceSet>
     ProcOwnedEmulatedEglWindowSurfaces;
 
 typedef std::unordered_map<uint64_t, gl::EmulatedEglContextSet> ProcOwnedEmulatedEglContexts;
-typedef std::unordered_map<uint64_t, gl::EmulatedEglImageSet> ProcOwnedEmulatedEGLImages;
-#endif
 
 typedef std::unordered_map<uint64_t, ColorBufferSet> ProcOwnedColorBuffers;
 
@@ -133,6 +112,8 @@
 typedef std::unordered_multiset<HandleType> BufferSet;
 typedef std::unordered_map<uint64_t, BufferSet> ProcOwnedBuffers;
 
+typedef std::unordered_map<uint64_t, gl::EmulatedEglImageSet> ProcOwnedEmulatedEGLImages;
+
 typedef std::unordered_map<void*, std::function<void()>> CallbackMap;
 typedef std::unordered_map<uint64_t, CallbackMap> ProcOwnedCleanupCallbacks;
 
@@ -199,12 +180,55 @@
     // Return the emulated GPU display height in pixels.
     int getHeight() const { return m_framebufferHeight; }
 
+    // Return the list of configs available from this display.
+    const gl::EmulatedEglConfigList* getConfigs() const;
+
     // Set a callback that will be called each time the emulated GPU content
     // is updated. This can be relatively slow with host-based GPU emulation,
     // so only do this when you need to.
     void setPostCallback(Renderer::OnPostCallback onPost, void* onPostContext, uint32_t displayId,
                          bool useBgraReadback = false);
 
+    // Retrieve the GL strings of the underlying EGL/GLES implementation.
+    // On return, |*vendor|, |*renderer| and |*version| will point to strings
+    // that are owned by the instance (and must not be freed by the caller).
+    void getGLStrings(const char** vendor, const char** renderer,
+                      const char** version) const {
+        *vendor = m_graphicsAdapterVendor.c_str();
+        *renderer = m_graphicsAdapterName.c_str();
+        *version = m_graphicsApiVersion.c_str();
+    }
+
+    // Create a new EmulatedEglContext instance for this display instance.
+    // |p_config| is the index of one of the configs returned by getConfigs().
+    // |p_share| is either EGL_NO_CONTEXT or the handle of a shared context.
+    // |version| specifies the GLES version as a GLESApi enum.
+    // Return a new handle value, which will be 0 in case of error.
+    HandleType createEmulatedEglContext(int p_config, HandleType p_share,
+                                        gl::GLESApi version = gl::GLESApi_CM);
+
+    // Destroy a given EmulatedEglContext instance. |p_context| is its handle
+    // value as returned by createEmulatedEglContext().
+    void destroyEmulatedEglContext(HandleType p_context);
+
+    // Create a new EmulatedEglWindowSurface instance from this display instance.
+    // |p_config| is the index of one of the configs returned by getConfigs().
+    // |p_width| and |p_height| are the window dimensions in pixels.
+    // Return a new handle value, or 0 in case of error.
+    HandleType createEmulatedEglWindowSurface(int p_config, int p_width, int p_height);
+
+    // Destroy a given EmulatedEglWindowSurface instance. |p_surcace| is its
+    // handle value as returned by createEmulatedEglWindowSurface().
+    void destroyEmulatedEglWindowSurface(HandleType p_surface);
+
+    // Returns the set of ColorBuffers destroyed (for further cleanup)
+    std::vector<HandleType> destroyEmulatedEglWindowSurfaceLocked(HandleType p_surface);
+
+    void createEmulatedEglFenceSync(EGLenum type,
+                                    int destroyWhenSignaled,
+                                    uint64_t* outSync = nullptr,
+                                    uint64_t* outSyncThread = nullptr);
+
     // Create a new ColorBuffer instance from this display instance.
     // |p_width| and |p_height| are its dimensions in pixels.
     // |p_internalFormat| is the OpenGL format of this color buffer.
@@ -236,6 +260,21 @@
     // virtio-gpu's RESOURCE_CREATE ioctl for BLOB resources.
     void createBufferWithHandle(uint64_t size, HandleType handle);
 
+    // Call this function when a render thread terminates to destroy all
+    // resources it created. Necessary to avoid leaking host resources
+    // when a guest application crashes, for example.
+    void drainGlRenderThreadResources();
+
+    // Call this function when a render thread terminates to destroy all
+    // the remaining contexts it created. Necessary to avoid leaking host
+    // contexts when a guest application crashes, for example.
+    void drainGlRenderThreadContexts();
+
+    // Call this function when a render thread terminates to destroy all
+    // remaining window surface it created. Necessary to avoid leaking
+    // host buffers when a guest application crashes, for example.
+    void drainGlRenderThreadSurfaces();
+
     // Increment the reference count associated with a given ColorBuffer
     // instance. |p_colorbuffer| is its handle value as returned by
     // createColorBuffer().
@@ -259,6 +298,54 @@
     // TODO(kaiyili): retire cleanupProcGLObjects in favor of removeGraphicsProcessResources.
     void cleanupProcGLObjects(uint64_t puid);
 
+    // Equivalent for eglMakeCurrent() for the current display.
+    // |p_context|, |p_drawSurface| and |p_readSurface| are the handle values
+    // of the context, the draw surface and the read surface, respectively.
+    // Returns true on success, false on failure.
+    // Note: if all handle values are 0, this is an unbind operation.
+    bool bindContext(HandleType p_context, HandleType p_drawSurface,
+                     HandleType p_readSurface);
+
+    // Return a render context pointer from its handle
+    gl::EmulatedEglContextPtr getContext_locked(HandleType p_context);
+
+    // Return a color buffer pointer from its handle
+    gl::EmulatedEglWindowSurfacePtr getWindowSurface_locked(HandleType p_windowsurface);
+
+    // Attach a ColorBuffer to a EmulatedEglWindowSurface instance.
+    // See the documentation for EmulatedEglWindowSurface::setColorBuffer().
+    // |p_surface| is the target EmulatedEglWindowSurface's handle value.
+    // |p_colorbuffer| is the ColorBuffer handle value.
+    // Returns true on success, false otherwise.
+    bool setEmulatedEglWindowSurfaceColorBuffer(HandleType p_surface,
+                                                HandleType p_colorbuffer);
+
+    // Copy the content of a EmulatedEglWindowSurface's Pbuffer to its attached
+    // ColorBuffer. See the documentation for
+    // EmulatedEglWindowSurface::flushColorBuffer().
+    // |p_surface| is the target WindowSurface's handle value.
+    // Returns true on success, false on failure.
+    bool flushEmulatedEglWindowSurfaceColorBuffer(HandleType p_surface);
+
+    // Retrieves the color buffer handle associated with |p_surface|.
+    // Returns 0 if there is no such handle.
+    HandleType getEmulatedEglWindowSurfaceColorBufferHandle(HandleType p_surface);
+
+    // Bind the current context's EGL_TEXTURE_2D texture to a ColorBuffer
+    // instance's EGLImage. This is intended to implement
+    // glEGLImageTargetTexture2DOES() for all GLES versions.
+    // |p_colorbuffer| is the ColorBuffer's handle value.
+    // Returns true on success, false on failure.
+    bool bindColorBufferToTexture(HandleType p_colorbuffer);
+    bool bindColorBufferToTexture2(HandleType p_colorbuffer);
+
+    // Bind the current context's EGL_RENDERBUFFER_OES render buffer to this
+    // ColorBuffer's EGLImage. This is intended to implement
+    // glEGLImageTargetRenderbufferStorageOES() for all GLES versions.
+    // |p_colorbuffer| is the ColorBuffer's handle value.
+    // Returns true on success, false on failure.
+    bool bindColorBufferToRenderbuffer(HandleType p_colorbuffer);
+
     // Read the content of a given Buffer into client memory.
     // |p_buffer| is the Buffer's handle value.
     // |offset| and |size| are the position and size of a slice of the buffer
@@ -290,6 +377,17 @@
     void readColorBufferYUV(HandleType p_colorbuffer, int x, int y, int width,
                             int height, void* pixels, uint32_t pixels_size);
 
+    // create a Y texture and a UV texture with width and height, the created
+    // texture ids are stored in textures respectively
+    void createYUVTextures(uint32_t type, uint32_t count, int width, int height,
+                           uint32_t* output);
+    void destroyYUVTextures(uint32_t type, uint32_t count, uint32_t* textures);
+    void updateYUVTextures(uint32_t type, uint32_t* textures, void* privData,
+                           void* func);
+    void swapTexturesAndUpdateColorBuffer(uint32_t colorbufferhandle, int x, int y, int width,
+                                          int height, uint32_t format, uint32_t type,
+                                          uint32_t texture_type, uint32_t* textures);
+
     // Update the content of a given Buffer from client data.
     // |p_buffer| is the Buffer's handle value.
     // |offset| and |size| are the position and size of a slice of the buffer
@@ -317,6 +415,17 @@
                                               int height, FrameworkFormat fwkFormat, GLenum format,
                                               GLenum type, void* pixels, void* metadata = nullptr);
 
+    // Reads back the raw color buffer to |pixels|
+    // if |pixels| is not null.
+    // Always returns in |numBytes| how many bytes were
+    // planned to be transmitted.
+    // |numBytes| is not an input parameter;
+    // fewer or more bytes cannot be specified.
+    // If the framework format is YUV, it will read
+    // back as raw YUV data.
+    bool readColorBufferContents(HandleType p_colorbuffer, size_t* numBytes,
+                                 void* pixels);
+
     bool getColorBufferInfo(HandleType p_colorbuffer, int* width, int* height,
                             GLint* internalformat,
                             FrameworkFormat* frameworkFormat = nullptr);
@@ -352,6 +461,16 @@
     // be re-displayed for any reason.
     bool repost(bool needLockAndBind = true);
 
+    gl::EmulationGl& getEmulationGl();
+    bool hasEmulationGl() const { return m_emulationGl != nullptr; }
+
+    // Return the host EGLDisplay used by this instance.
+    EGLDisplay getDisplay() const;
+    EGLSurface getWindowSurface() const;
+    EGLContext getContext() const;
+    EGLConfig getConfig() const;
+    ContextHelper* getPbufferSurfaceContextHelper() const;
+
     // Change the rotation of the displayed GPU sub-window.
     void setDisplayRotation(float zRot) {
         if (zRot != m_zRot) {
@@ -377,6 +496,19 @@
         }
     }
 
+    // Return a TextureDraw instance that can be used with this surfaces
+    // and windows created by this instance.
+    gl::TextureDraw* getTextureDraw() const;
+
+    // Create an eglImage and return its handle.  Reference:
+    // https://www.khronos.org/registry/egl/extensions/KHR/EGL_KHR_image_base.txt
+    HandleType createEmulatedEglImage(HandleType context, EGLenum target,
+                                      GLuint buffer);
+    // Call the implementation of eglDestroyImageKHR, return if succeeds or
+    // not. Reference:
+    // https://www.khronos.org/registry/egl/extensions/KHR/EGL_KHR_image_base.txt
+    EGLBoolean destroyEmulatedEglImage(HandleType image);
+
     void lockContextStructureRead() { m_contextStructureLock.lockRead(); }
     void unlockContextStructureRead() { m_contextStructureLock.unlockRead(); }
 
@@ -385,7 +517,12 @@
     // GL state.
     // It can be unsafe / leaky to change the structure of contexts
     // outside the facilities the FrameBuffer class provides.
-    void createTrivialContext(HandleType shared, HandleType* contextOut, HandleType* surfOut);
+    void createTrivialContext(HandleType shared, HandleType* contextOut,
+                              HandleType* surfOut);
+    // createTrivialContext(), but with a m_pbufContext
+    // as shared, and not adding itself to the context map at all.
+    void createSharedTrivialContext(EGLContext* contextOut, EGLSurface* surfOut);
+    void destroySharedTrivialContext(EGLContext context, EGLSurface surf);
 
     void setShuttingDown() { m_shuttingDown = true; }
     bool isShuttingDown() const { return m_shuttingDown; }
@@ -406,6 +543,8 @@
     void lock();
     void unlock();
 
+    gl::GLESDispatchMaxVersion getMaxGLESVersion();
+
     float getDpr() const { return m_dpr; }
     int windowWidth() const { return m_windowWidth; }
     int windowHeight() const { return m_windowHeight; }
@@ -413,9 +552,15 @@
     float getPy() const { return m_py; }
     int getZrot() const { return m_zRot; }
 
+    bool isFastBlitSupported() const;
+    void disableFastBlitForTesting();
+
     bool isVulkanInteropSupported() const { return m_vulkanInteropSupported; }
     bool isVulkanEnabled() const { return m_vulkanEnabled; }
 
+    // Fill GLES usage protobuf
+    void fillGLESUsages(android_studio::EmulatorGLESUsages*);
+
     // Saves a screenshot of the previous frame.
     // nChannels should be 3 (RGB) or 4 (RGBA).
     // You must provide a pre-allocated buffer of sufficient
@@ -477,13 +622,18 @@
     static const uint32_t s_invalidIdMultiDisplay = 0xFFFFFFAB;
     static const uint32_t s_maxNumMultiDisplay = 11;
 
+    EGLContext getGlobalEGLContext() const;
     HandleType getLastPostedColorBuffer() { return m_lastPostedColorBuffer; }
+    void waitForGpu(uint64_t eglsync);
     void waitForGpuVulkan(uint64_t deviceHandle, uint64_t fenceHandle);
+    void asyncWaitForGpuWithCb(uint64_t eglsync, FenceCompletionCallback cb);
     void asyncWaitForGpuVulkanWithCb(uint64_t deviceHandle, uint64_t fenceHandle, FenceCompletionCallback cb);
     void asyncWaitForGpuVulkanQsriWithCb(uint64_t image, FenceCompletionCallback cb);
     void waitForGpuVulkanQsri(uint64_t image);
 
     bool platformImportResource(uint32_t handle, uint32_t info, void* resource);
+    void* platformCreateSharedEglContext(void);
+    bool platformDestroySharedEglContext(void* context);
 
     void setGuestManagedColorBufferLifetime(bool guestManaged);
 
@@ -508,182 +658,14 @@
     const int getDisplayConfigsParam(int configId, EGLint param);
     const int getDisplayActiveConfig();
 
-    bool flushColorBufferFromVk(HandleType colorBufferHandle);
-    bool flushColorBufferFromVkBytes(HandleType colorBufferHandle, const void* bytes,
-                                     size_t bytesSize);
-    bool invalidateColorBufferForVk(HandleType colorBufferHandle);
-
-#if GFXSTREAM_ENABLE_HOST_GLES
-    // Retrieves the color buffer handle associated with |p_surface|.
-    // Returns 0 if there is no such handle.
-    HandleType getEmulatedEglWindowSurfaceColorBufferHandle(HandleType p_surface);
-
-    // createTrivialContext(), but with a m_pbufContext
-    // as shared, and not adding itself to the context map at all.
-    void createSharedTrivialContext(EGLContext* contextOut, EGLSurface* surfOut);
-    void destroySharedTrivialContext(EGLContext context, EGLSurface surf);
-
-    // Attach a ColorBuffer to a EmulatedEglWindowSurface instance.
-    // See the documentation for EmulatedEglWindowSurface::setColorBuffer().
-    // |p_surface| is the target EmulatedEglWindowSurface's handle value.
-    // |p_colorbuffer| is the ColorBuffer handle value.
-    // Returns true on success, false otherwise.
-
-    bool setEmulatedEglWindowSurfaceColorBuffer(HandleType p_surface, HandleType p_colorbuffer);
-    // Return the list of configs available from this display.
-    const gl::EmulatedEglConfigList* getConfigs() const;
-
-    // Retrieve the GL strings of the underlying EGL/GLES implementation.
-    // On return, |*vendor|, |*renderer| and |*version| will point to strings
-    // that are owned by the instance (and must not be freed by the caller).
-    void getGLStrings(const char** vendor, const char** renderer, const char** version) const {
-        *vendor = m_graphicsAdapterVendor.c_str();
-        *renderer = m_graphicsAdapterName.c_str();
-        *version = m_graphicsApiVersion.c_str();
-    }
-
-    // Create a new EmulatedEglContext instance for this display instance.
-    // |p_config| is the index of one of the configs returned by getConfigs().
-    // |p_share| is either EGL_NO_CONTEXT or the handle of a shared context.
-    // |version| specifies the GLES version as a GLESApi enum.
-    // Return a new handle value, which will be 0 in case of error.
-    HandleType createEmulatedEglContext(int p_config, HandleType p_share,
-                                        gl::GLESApi version = gl::GLESApi_CM);
-
-    // Destroy a given EmulatedEglContext instance. |p_context| is its handle
-    // value as returned by createEmulatedEglContext().
-    void destroyEmulatedEglContext(HandleType p_context);
-
-    // Create a new EmulatedEglWindowSurface instance from this display instance.
-    // |p_config| is the index of one of the configs returned by getConfigs().
-    // |p_width| and |p_height| are the window dimensions in pixels.
-    // Return a new handle value, or 0 in case of error.
-    HandleType createEmulatedEglWindowSurface(int p_config, int p_width, int p_height);
-
-    // Destroy a given EmulatedEglWindowSurface instance. |p_surcace| is its
-    // handle value as returned by createEmulatedEglWindowSurface().
-    void destroyEmulatedEglWindowSurface(HandleType p_surface);
-
-    // Returns the set of ColorBuffers destroyed (for further cleanup)
-    std::vector<HandleType> destroyEmulatedEglWindowSurfaceLocked(HandleType p_surface);
-
-    void createEmulatedEglFenceSync(EGLenum type, int destroyWhenSignaled,
-                                    uint64_t* outSync = nullptr, uint64_t* outSyncThread = nullptr);
-
-    // Call this function when a render thread terminates to destroy all
-    // resources it created. Necessary to avoid leaking host resources
-    // when a guest application crashes, for example.
-    void drainGlRenderThreadResources();
-
-    // Call this function when a render thread terminates to destroy all
-    // the remaining contexts it created. Necessary to avoid leaking host
-    // contexts when a guest application crashes, for example.
-    void drainGlRenderThreadContexts();
-
-    // Call this function when a render thread terminates to destroy all
-    // remaining window surface it created. Necessary to avoid leaking
-    // host buffers when a guest application crashes, for example.
-    void drainGlRenderThreadSurfaces();
-
-    gl::EmulationGl& getEmulationGl();
-    bool hasEmulationGl() const { return m_emulationGl != nullptr; }
-
-    // Return the host EGLDisplay used by this instance.
-    EGLDisplay getDisplay() const;
-    EGLSurface getWindowSurface() const;
-    EGLContext getContext() const;
-    EGLConfig getConfig() const;
-
-    EGLContext getGlobalEGLContext() const;
-
-    // Return a render context pointer from its handle
-    gl::EmulatedEglContextPtr getContext_locked(HandleType p_context);
-
-    // Return a color buffer pointer from its handle
-    gl::EmulatedEglWindowSurfacePtr getWindowSurface_locked(HandleType p_windowsurface);
-
-    // Return a TextureDraw instance that can be used with this surfaces
-    // and windows created by this instance.
-    gl::TextureDraw* getTextureDraw() const;
-
-    bool isFastBlitSupported() const;
-    void disableFastBlitForTesting();
-
-    // Create an eglImage and return its handle.  Reference:
-    // https://www.khronos.org/registry/egl/extensions/KHR/EGL_KHR_image_base.txt
-    HandleType createEmulatedEglImage(HandleType context, EGLenum target, GLuint buffer);
-    // Call the implementation of eglDestroyImageKHR, return if succeeds or
-    // not. Reference:
-    // https://www.khronos.org/registry/egl/extensions/KHR/EGL_KHR_image_base.txt
-    EGLBoolean destroyEmulatedEglImage(HandleType image);
-    // Copy the content of a EmulatedEglWindowSurface's Pbuffer to its attached
-    // ColorBuffer. See the documentation for
-    // EmulatedEglWindowSurface::flushColorBuffer().
-    // |p_surface| is the target WindowSurface's handle value.
-    // Returns true on success, false on failure.
-    bool flushEmulatedEglWindowSurfaceColorBuffer(HandleType p_surface);
-
-    gl::GLESDispatchMaxVersion getMaxGLESVersion();
-
-    // Fill GLES usage protobuf
-    void fillGLESUsages(android_studio::EmulatorGLESUsages*);
-
-    void* platformCreateSharedEglContext(void);
-    bool platformDestroySharedEglContext(void* context);
-
     bool flushColorBufferFromGl(HandleType colorBufferHandle);
-
+    bool flushColorBufferFromVk(HandleType colorBufferHandle);
+    bool flushColorBufferFromVkBytes(HandleType colorBufferHandle, const void* bytes, size_t bytesSize);
     bool invalidateColorBufferForGl(HandleType colorBufferHandle);
-
-    ContextHelper* getPbufferSurfaceContextHelper() const;
-
-    // Bind the current context's EGL_TEXTURE_2D texture to a ColorBuffer
-    // instance's EGLImage. This is intended to implement
-    // glEGLImageTargetTexture2DOES() for all GLES versions.
-    // |p_colorbuffer| is the ColorBuffer's handle value.
-    // Returns true on success, false on failure.
-    bool bindColorBufferToTexture(HandleType p_colorbuffer);
-    bool bindColorBufferToTexture2(HandleType p_colorbuffer);
-
-    // Bind the current context's EGL_RENDERBUFFER_OES render buffer to this
-    // ColorBuffer's EGLImage. This is intended to implement
-    // glEGLImageTargetRenderbufferStorageOES() for all GLES versions.
-    // |p_colorbuffer| is the ColorBuffer's handle value.
-    // Returns true on success, false on failure.
-    bool bindColorBufferToRenderbuffer(HandleType p_colorbuffer);
-
-    // Equivalent for eglMakeCurrent() for the current display.
-    // |p_context|, |p_drawSurface| and |p_readSurface| are the handle values
-    // of the context, the draw surface and the read surface, respectively.
-    // Returns true on success, false on failure.
-    // Note: if all handle values are 0, this is an unbind operation.
-    bool bindContext(HandleType p_context, HandleType p_drawSurface, HandleType p_readSurface);
-
-    // create a Y texture and a UV texture with width and height, the created
-    // texture ids are stored in textures respectively
-    void createYUVTextures(uint32_t type, uint32_t count, int width, int height, uint32_t* output);
-    void destroyYUVTextures(uint32_t type, uint32_t count, uint32_t* textures);
-    void updateYUVTextures(uint32_t type, uint32_t* textures, void* privData, void* func);
-    void swapTexturesAndUpdateColorBuffer(uint32_t colorbufferhandle, int x, int y, int width,
-                                          int height, uint32_t format, uint32_t type,
-                                          uint32_t texture_type, uint32_t* textures);
-
-    // Reads back the raw color buffer to |pixels|
-    // if |pixels| is not null.
-    // Always returns in |numBytes| how many bytes were
-    // planned to be transmitted.
-    // |numBytes| is not an input parameter;
-    // fewer or more bytes cannot be specified.
-    // If the framework format is YUV, it will read
-    // back as raw YUV data.
-    bool readColorBufferContents(HandleType p_colorbuffer, size_t* numBytes, void* pixels);
-
-    void waitForGpu(uint64_t eglsync);
-    void asyncWaitForGpuWithCb(uint64_t eglsync, FenceCompletionCallback cb);
+    bool invalidateColorBufferForVk(HandleType colorBufferHandle);
 
     const gl::EGLDispatch* getEglDispatch();
     const gl::GLESv2Dispatch* getGles2Dispatch();
-#endif
 
    private:
     FrameBuffer(int p_width, int p_height, bool useSubWindow);
@@ -756,9 +738,12 @@
     android::base::Lock m_colorBufferMapLock;
     uint64_t mFrameNumber;
     FBNativeWindowType m_nativeWindow = 0;
-
+    gl::EmulatedEglContextMap m_contexts;
+    gl::EmulatedEglImageMap m_images;
+    gl::EmulatedEglWindowSurfaceMap m_windows;
     ColorBufferMap m_colorbuffers;
     BufferMap m_buffers;
+    std::unordered_map<HandleType, HandleType> m_EmulatedEglWindowSurfaceToColorBuffer;
 
     // A collection of color buffers that were closed without any usages
     // (|opened| == false).
@@ -828,6 +813,15 @@
     std::string m_graphicsApiVersion;
     std::string m_graphicsApiExtensions;
     std::string m_graphicsDeviceExtensions;
+
+    // The host associates color buffers with guest processes for memory
+    // cleanup. Guest processes are identified with a host generated unique ID.
+    // TODO(kaiyili): move all those resources to the ProcessResources struct.
+    ProcOwnedColorBuffers m_procOwnedColorBuffers;
+    ProcOwnedEmulatedEGLImages m_procOwnedEmulatedEglImages;
+    ProcOwnedEmulatedEglContexts m_procOwnedEmulatedEglContexts;
+    ProcOwnedEmulatedEglWindowSurfaces m_procOwnedEmulatedEglWindowSurfaces;
+    ProcOwnedCleanupCallbacks m_procOwnedCleanupCallbacks;
     std::unordered_map<uint64_t, std::unique_ptr<ProcessResources>> m_procOwnedResources;
 
     // Flag set when emulator is shutting down.
@@ -863,6 +857,9 @@
     android::base::MessageChannel<HandleType, 1024>
         mOutstandingColorBufferDestroys;
 
+    std::unique_ptr<gl::EmulationGl> m_emulationGl;
+    gl::DisplayGl* m_displayGl = nullptr;
+
     Compositor* m_compositor = nullptr;
     bool m_useVulkanComposition = false;
 
@@ -886,9 +883,15 @@
     // cases, this determines whether we can support zero-copy interop.
     using VkUuid = std::array<uint8_t, VK_UUID_SIZE>;
     VkUuid m_vulkanUUID{};
+    static_assert(VK_UUID_SIZE == GL_UUID_SIZE_EXT);
 
     // Tracks platform EGL contexts that have been handed out to other users,
     // indexed by underlying native EGL context object.
+    struct PlatformEglContextInfo {
+        EGLContext context;
+        EGLSurface surface;
+    };
+    std::unordered_map<void*, PlatformEglContextInfo> m_platformEglContexts;
 
     std::unique_ptr<MetricsLogger> m_logger;
     std::unique_ptr<HealthMonitor<>> m_healthMonitor;
@@ -909,34 +912,6 @@
     };
     std::map<int, DisplayConfig> mDisplayConfigs;
     int mDisplayActiveConfigId = -1;
-
-    std::unique_ptr<gl::EmulationGl> m_emulationGl;
-
-    // The host associates color buffers with guest processes for memory
-    // cleanup. Guest processes are identified with a host generated unique ID.
-    // TODO(kaiyili): move all those resources to the ProcessResources struct.
-    ProcOwnedColorBuffers m_procOwnedColorBuffers;
-    ProcOwnedCleanupCallbacks m_procOwnedCleanupCallbacks;
-
-#if GFXSTREAM_ENABLE_HOST_GLES
-    gl::EmulatedEglContextMap m_contexts;
-    gl::EmulatedEglImageMap m_images;
-    gl::EmulatedEglWindowSurfaceMap m_windows;
-
-    std::unordered_map<HandleType, HandleType> m_EmulatedEglWindowSurfaceToColorBuffer;
-
-    ProcOwnedEmulatedEGLImages m_procOwnedEmulatedEglImages;
-    ProcOwnedEmulatedEglContexts m_procOwnedEmulatedEglContexts;
-    ProcOwnedEmulatedEglWindowSurfaces m_procOwnedEmulatedEglWindowSurfaces;
-    gl::DisplayGl* m_displayGl = nullptr;
-
-    struct PlatformEglContextInfo {
-        EGLContext context;
-        EGLSurface surface;
-    };
-
-    std::unordered_map<void*, PlatformEglContextInfo> m_platformEglContexts;
-#endif
 };
 
 }  // namespace gfxstream
diff --git a/host/GlesCompat.h b/host/GlesCompat.h
deleted file mode 100644
index 3c57028..0000000
--- a/host/GlesCompat.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2024 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef GLES_COMPAT_H
-#define GLES_COMPAT_H
-
-#include <cstdint>
-
-typedef unsigned int GLenum;
-typedef int32_t EGLint;
-// typedef void *EGLNativeDisplayType;
-typedef unsigned int EGLNativeWindowType;
-
-namespace gfxstream {
-namespace gl {
-class EmulationGl {
-   public:
-    EmulationGl() {}
-    ~EmulationGl() {}
-
-   private:
-    uint32_t payload;
-};
-}  // namespace gl
-}  // namespace gfxstream
-
-#endif
diff --git a/host/NativeSubWindow.h b/host/NativeSubWindow.h
index aff117c..07dec0e 100644
--- a/host/NativeSubWindow.h
+++ b/host/NativeSubWindow.h
@@ -18,11 +18,7 @@
 
 #include "render-utils/render_api_platform_types.h"
 
-#if GFXSTREAM_ENABLE_HOST_GLES
 #include <EGL/egl.h>
-#else
-#include "GlesCompat.h"
-#endif
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/host/NativeSubWindow_stub.cpp b/host/NativeSubWindow_stub.cpp
deleted file mode 100644
index 75a1ea8..0000000
--- a/host/NativeSubWindow_stub.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "GlesCompat.h"
-#include "NativeSubWindow.h"
-
-EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, int x, int y, int width,
-                                    int height, float dpr,
-                                    SubWindowRepaintCallback repaint_callback,
-                                    void* repaint_callback_param, int hideWindow) {
-    return 0;
-}
-
-void destroySubWindow(EGLNativeWindowType win) { return; }
-
-int moveSubWindow(FBNativeWindowType p_parent_window, EGLNativeWindowType p_sub_window, int x,
-                  int y, int width, int height) {
-    return 0;
-}
diff --git a/host/RenderControl.cpp b/host/RenderControl.cpp
index 698914c..2c84d45 100644
--- a/host/RenderControl.cpp
+++ b/host/RenderControl.cpp
@@ -1636,4 +1636,4 @@
     dec->rcGetHostExtensionsString = rcGetHostExtensionsString;
 }
 
-}  // namespace gfxstream
+}  // namespace gfxstream
\ No newline at end of file
diff --git a/host/RenderLibImpl.cpp b/host/RenderLibImpl.cpp
index 8f695e6..cd1dffe 100644
--- a/host/RenderLibImpl.cpp
+++ b/host/RenderLibImpl.cpp
@@ -14,6 +14,8 @@
 #include "RenderLibImpl.h"
 
 #include "FrameBuffer.h"
+#include "OpenGLESDispatch/EGLDispatch.h"
+#include "OpenGLESDispatch/DispatchTables.h"
 #include "RendererImpl.h"
 #include "aemu/base/files/Stream.h"
 #include "host-common/address_space_device_control_ops.h"
@@ -25,11 +27,6 @@
 #include "host-common/opengl/misc.h"
 #include "host-common/sync_device.h"
 
-#if GFXSTREAM_ENABLE_HOST_GLES
-#include "OpenGLESDispatch/DispatchTables.h"
-#include "OpenGLESDispatch/EGLDispatch.h"
-#endif
-
 namespace gfxstream {
 
 void RenderLibImpl::setRenderer(SelectedRenderer renderer) {
@@ -114,11 +111,10 @@
         return false;
     }
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     opt->display = fb->getDisplay();
     opt->surface = fb->getWindowSurface();
     opt->config = fb->getConfig();
-#endif
+
     return (opt->display && opt->surface  && opt->config);
 }
 
diff --git a/host/RenderThread.cpp b/host/RenderThread.cpp
index d1d34ea..abe4fcc 100644
--- a/host/RenderThread.cpp
+++ b/host/RenderThread.cpp
@@ -19,24 +19,21 @@
 #include "FrameBuffer.h"
 #include "ReadBuffer.h"
 #include "RenderChannelImpl.h"
+#include "RenderControl.h"
 #include "RenderThreadInfo.h"
 #include "RingStream.h"
 #include "VkDecoderContext.h"
+#include "apigen-codec-common/ChecksumCalculatorThreadInfo.h"
 #include "aemu/base/HealthMonitor.h"
-#include "aemu/base/Metrics.h"
-#include "aemu/base/files/StreamSerializing.h"
 #include "aemu/base/synchronization/Lock.h"
 #include "aemu/base/synchronization/MessageChannel.h"
+#include "aemu/base/Metrics.h"
+#include "aemu/base/files/StreamSerializing.h"
 #include "aemu/base/system/System.h"
-#include "apigen-codec-common/ChecksumCalculatorThreadInfo.h"
 #include "host-common/feature_control.h"
 #include "host-common/logging.h"
 #include "vulkan/VkCommonOperations.h"
 
-#if GFXSTREAM_ENABLE_HOST_GLES
-#include "RenderControl.h"
-#endif
-
 #define EMUGL_DEBUG_LEVEL 0
 #include "host-common/debug.h"
 
@@ -273,13 +270,12 @@
 
     //
     // initialize decoders
-#if GFXSTREAM_ENABLE_HOST_GLES
+    //
     if (!feature_is_enabled(kFeature_GuestUsesAngle)) {
         tInfo.initGl();
     }
 
     initRenderControlContext(&tInfo.m_rcDec);
-#endif
 
     if (!mChannel && !mRingStream) {
         GL_LOG("Exited a loader RenderThread @%p", this);
@@ -527,7 +523,6 @@
                 FrameBuffer::getFB()->lockContextStructureRead();
             }
 
-#if GFXSTREAM_ENABLE_HOST_GLES
             if (tInfo.m_glInfo) {
                 {
                     last = tInfo.m_glInfo->m_glDec.decode(
@@ -552,14 +547,12 @@
                     }
                 }
             }
-#endif
 
             FrameBuffer::getFB()->unlockContextStructureRead();
             //
             // try to process some of the command buffer using the
             // renderControl decoder
             //
-#if GFXSTREAM_ENABLE_HOST_GLES
             {
                 last = tInfo.m_rcDec.decode(readBuf.buf(), readBuf.validData(),
                                             ioStream, &checksumCalc);
@@ -568,7 +561,6 @@
                     progress = true;
                 }
             }
-#endif
 
             //
             // try to process some of the command buffer using the Magma
@@ -597,11 +589,9 @@
         fclose(dumpFP);
     }
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (tInfo.m_glInfo) {
         FrameBuffer::getFB()->drainGlRenderThreadResources();
     }
-#endif
 
     setFinished();
 
diff --git a/host/RenderThreadInfo.cpp b/host/RenderThreadInfo.cpp
index b3cab71..fdbbfc8 100644
--- a/host/RenderThreadInfo.cpp
+++ b/host/RenderThreadInfo.cpp
@@ -61,21 +61,16 @@
     }
 }
 
-#if GFXSTREAM_ENABLE_HOST_GLES
 void RenderThreadInfo::initGl() {
     m_glInfo.emplace();
 }
-#endif
 
 void RenderThreadInfo::onSave(Stream* stream) {
     // TODO(b/309858017): remove if when ready to bump snapshot version
     if (feature_is_enabled(kFeature_VulkanSnapshots)) {
         stream->putBe64(m_puid);
     }
-
-#if GFXSTREAM_ENABLE_HOST_GLES
     m_glInfo->onSave(stream);
-#endif
 }
 
 bool RenderThreadInfo::onLoad(Stream* stream) {
@@ -83,19 +78,11 @@
     if (feature_is_enabled(kFeature_VulkanSnapshots)) {
         m_puid = stream->getBe64();
     }
-
-#if GFXSTREAM_ENABLE_HOST_GLES
     return m_glInfo->onLoad(stream);
-#else
-    // Functions only work with GLES for now.
-    return false;
-#endif
 }
 
 void RenderThreadInfo::postLoadRefreshCurrentContextSurfacePtrs() {
-#if GFXSTREAM_ENABLE_HOST_GLES
     return m_glInfo->postLoadRefreshCurrentContextSurfacePtrs();
-#endif
 }
 
 }  // namespace gfxstream
diff --git a/host/RenderThreadInfo.h b/host/RenderThreadInfo.h
index 5e20d8a..636421e 100644
--- a/host/RenderThreadInfo.h
+++ b/host/RenderThreadInfo.h
@@ -21,12 +21,8 @@
 #include <unordered_set>
 
 #include "aemu/base/files/Stream.h"
-
-#if GFXSTREAM_ENABLE_HOST_GLES
 #include "renderControl_dec/renderControl_dec.h"
 #include "RenderThreadInfoGl.h"
-#endif
-
 #include "RenderThreadInfoVk.h"
 
 #if GFXSTREAM_ENABLE_HOST_MAGMA
@@ -51,19 +47,15 @@
     // Loop over all active render thread infos
     static void forAllRenderThreadInfos(std::function<void(RenderThreadInfo*)>);
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     void initGl();
-#endif
+
+    renderControl_decoder_context_t m_rcDec;
 
     // The unique id of owner guest process of this render thread
     uint64_t                        m_puid = 0;
     std::optional<std::string>      m_processName;
 
-#if GFXSTREAM_ENABLE_HOST_GLES
-    renderControl_decoder_context_t m_rcDec;
     std::optional<gl::RenderThreadInfoGl> m_glInfo;
-#endif
-
     std::optional<vk::RenderThreadInfoVk> m_vkInfo;
 
 #if GFXSTREAM_ENABLE_HOST_MAGMA
diff --git a/host/RenderWindow.cpp b/host/RenderWindow.cpp
index ace6114..58c374e 100644
--- a/host/RenderWindow.cpp
+++ b/host/RenderWindow.cpp
@@ -498,16 +498,11 @@
         D("No framebuffer!\n");
         return false;
     }
-
-#if GFXSTREAM_ENABLE_HOST_GLES
     fb->getGLStrings(vendor, renderer, version);
     D("Exiting vendor=[%s] renderer=[%s] version=[%s]\n",
       *vendor, *renderer, *version);
 
     return true;
-#else
-    return false;
-#endif
 }
 
 void RenderWindow::setPostCallback(Renderer::OnPostCallback onPost, void* onPostContext,
@@ -615,11 +610,11 @@
 
 void RenderWindow::setScreenMask(int width, int height, const unsigned char* rgbaData) {
     if (FrameBuffer* fb = FrameBuffer::getFB()) {
-#if GFXSTREAM_ENABLE_HOST_GLES
         if (fb->hasEmulationGl()) {
             fb->getTextureDraw()->setScreenMask(width, height, rgbaData);
+        } else {
+            ERR("RenderWindow::setScreenMask() not supported without GL emulation.");
         }
-#endif
     }
 }
 
@@ -695,4 +690,4 @@
     }
 }
 
-}  // namespace gfxstream
+}  // namespace gfxstream
\ No newline at end of file
diff --git a/host/RendererImpl.cpp b/host/RendererImpl.cpp
index 33972b4..c1fb7dd 100644
--- a/host/RendererImpl.cpp
+++ b/host/RendererImpl.cpp
@@ -24,13 +24,10 @@
 #include "RenderThread.h"
 #include "aemu/base/system/System.h"
 #include "aemu/base/threads/WorkerThread.h"
+#include "gl/EmulatedEglFenceSync.h"
 #include "host-common/logging.h"
 #include "snapshot/common.h"
 
-#if GFXSTREAM_ENABLE_HOST_GLES
-#include "gl/EmulatedEglFenceSync.h"
-#endif
-
 namespace gfxstream {
 
 // kUseSubwindowThread is used to determine whether the RenderWindow should use
@@ -392,18 +389,14 @@
     bool res = true;
 
     res = fb->onLoad(stream, textureLoader);
-#if GFXSTREAM_ENABLE_HOST_GLES
     gl::EmulatedEglFenceSync::onLoad(stream);
-#endif
 
     return res;
 }
 
 void RendererImpl::fillGLESUsages(android_studio::EmulatorGLESUsages* usages) {
     auto fb = FrameBuffer::getFB();
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (fb) fb->fillGLESUsages(usages);
-#endif
 }
 
 int RendererImpl::getScreenshot(unsigned int nChannels, unsigned int* width, unsigned int* height,
@@ -595,7 +588,6 @@
             FrameBuffer::getFB()->postWithCallback(handle, cb);
         },
     .repost = []() { FrameBuffer::getFB()->repost(); },
-#if GFXSTREAM_ENABLE_HOST_GLES
     .create_yuv_textures =
         [](uint32_t type, uint32_t count, int width, int height, uint32_t* output) {
             FrameBuffer::getFB()->createYUVTextures(type, count, width, height, output);
@@ -614,15 +606,12 @@
             FrameBuffer::getFB()->swapTexturesAndUpdateColorBuffer(
                 colorbufferhandle, x, y, width, height, format, type, texture_type, textures);
         },
-#endif
     .get_last_posted_color_buffer =
         []() { return FrameBuffer::getFB()->getLastPostedColorBuffer(); },
-#if GFXSTREAM_ENABLE_HOST_GLES
     .bind_color_buffer_to_texture =
         [](uint32_t handle) { FrameBuffer::getFB()->bindColorBufferToTexture2(handle); },
     .get_global_egl_context = []() { return FrameBuffer::getFB()->getGlobalEGLContext(); },
     .wait_for_gpu = [](uint64_t eglsync) { FrameBuffer::getFB()->waitForGpu(eglsync); },
-#endif
     .wait_for_gpu_vulkan =
         [](uint64_t device, uint64_t fence) {
             FrameBuffer::getFB()->waitForGpuVulkan(device, fence);
@@ -631,12 +620,10 @@
         [](bool guestManaged) {
             FrameBuffer::getFB()->setGuestManagedColorBufferLifetime(guestManaged);
         },
-#if GFXSTREAM_ENABLE_HOST_GLES
     .async_wait_for_gpu_with_cb =
         [](uint64_t eglsync, FenceCompletionCallback cb) {
             FrameBuffer::getFB()->asyncWaitForGpuWithCb(eglsync, cb);
         },
-#endif
     .async_wait_for_gpu_vulkan_with_cb =
         [](uint64_t device, uint64_t fence, FenceCompletionCallback cb) {
             FrameBuffer::getFB()->asyncWaitForGpuVulkanWithCb(device, fence, cb);
@@ -662,14 +649,12 @@
         [](uint32_t handle, int32_t* width, int32_t* height, int32_t* internal_format) {
             return FrameBuffer::getFB()->getColorBufferInfo(handle, width, height, internal_format);
         },
-#if GFXSTREAM_ENABLE_HOST_GLES
     .platform_create_shared_egl_context =
         []() { return FrameBuffer::getFB()->platformCreateSharedEglContext(); },
     .platform_destroy_shared_egl_context =
         [](void* context) {
             return FrameBuffer::getFB()->platformDestroySharedEglContext(context);
         },
-#endif
 };
 
 struct AndroidVirtioGpuOps* RendererImpl::getVirtioGpuOps() {
@@ -724,19 +709,11 @@
 }
 
 const void* RendererImpl::getEglDispatch() {
-#if GFXSTREAM_ENABLE_HOST_GLES
     return FrameBuffer::getFB()->getEglDispatch();
-#else
-    return nullptr;
-#endif
 }
 
 const void* RendererImpl::getGles2Dispatch() {
-#if GFXSTREAM_ENABLE_HOST_GLES
     return FrameBuffer::getFB()->getGles2Dispatch();
-#else
-    return nullptr;
-#endif
 }
 
 }  // namespace gfxstream
diff --git a/host/SyncThread.cpp b/host/SyncThread.cpp
index 5b1d1c1..5835387 100644
--- a/host/SyncThread.cpp
+++ b/host/SyncThread.cpp
@@ -16,10 +16,7 @@
 
 #include "SyncThread.h"
 
-#if GFXSTREAM_ENABLE_HOST_GLES
 #include "OpenGLESDispatch/OpenGLDispatchLoader.h"
-#endif
-
 #include "aemu/base/Metrics.h"
 #include "aemu/base/system/System.h"
 #include "aemu/base/threads/Thread.h"
@@ -38,11 +35,8 @@
 using android::base::EventHangMetadata;
 using emugl::ABORT_REASON_OTHER;
 using emugl::FatalError;
-
-#if GFXSTREAM_ENABLE_HOST_GLES
 using gl::EGLDispatch;
 using gl::EmulatedEglFenceSync;
-#endif
 
 #define DEBUG 0
 
@@ -118,18 +112,15 @@
       mHealthMonitor(healthMonitor) {
     this->start();
     mWorkerThreadPool.start();
-#if GFXSTREAM_ENABLE_HOST_GLES
     if (hasGl) {
         initSyncEGLContext();
     }
-#endif
 }
 
 SyncThread::~SyncThread() {
     cleanup();
 }
 
-#if GFXSTREAM_ENABLE_HOST_GLES
 void SyncThread::triggerWait(EmulatedEglFenceSync* fenceSync,
                              uint64_t timeline) {
     std::stringstream ss;
@@ -145,6 +136,20 @@
         ss.str());
 }
 
+void SyncThread::triggerWaitVk(VkFence vkFence, uint64_t timeline) {
+    std::stringstream ss;
+    ss << "triggerWaitVk vkFence=0x" << std::hex << reinterpret_cast<uintptr_t>(vkFence)
+       << " timeline=0x" << std::hex << timeline;
+    sendAsync(
+        [vkFence, timeline](WorkerId) {
+            doSyncWaitVk(vkFence, [timeline] {
+                DPRINT("vk wait done, use goldfish sync timeline inc");
+                emugl::emugl_sync_timeline_inc(timeline, kTimelineInterval);
+            });
+        },
+        ss.str());
+}
+
 void SyncThread::triggerBlockedWaitNoTimeline(EmulatedEglFenceSync* fenceSync) {
     std::stringstream ss;
     ss << "triggerBlockedWaitNoTimeline fenceSyncInfo=0x" << std::hex
@@ -166,6 +171,137 @@
         ss.str());
 }
 
+
+void SyncThread::triggerWaitVkWithCompletionCallback(VkFence vkFence, FenceCompletionCallback cb) {
+    std::stringstream ss;
+    ss << "triggerWaitVkWithCompletionCallback vkFence=0x" << std::hex
+       << reinterpret_cast<uintptr_t>(vkFence);
+    sendAsync([vkFence, cb = std::move(cb)](WorkerId) { doSyncWaitVk(vkFence, std::move(cb)); },
+              ss.str());
+}
+
+void SyncThread::triggerWaitVkQsriWithCompletionCallback(VkImage vkImage, FenceCompletionCallback cb) {
+    std::stringstream ss;
+    ss << "triggerWaitVkQsriWithCompletionCallback vkImage=0x"
+       << reinterpret_cast<uintptr_t>(vkImage);
+    sendAsync(
+        [vkImage, cb = std::move(cb)](WorkerId) {
+            auto decoder = vk::VkDecoderGlobalState::get();
+            auto res = decoder->registerQsriCallback(vkImage, cb);
+            // If registerQsriCallback does not schedule the callback, we still need to complete
+            // the task, otherwise we may hit deadlocks on tasks on the same ring.
+            if (!res.CallbackScheduledOrFired()) {
+                cb();
+            }
+        },
+        ss.str());
+}
+
+void SyncThread::triggerWaitVkQsri(VkImage vkImage, uint64_t timeline) {
+     std::stringstream ss;
+    ss << "triggerWaitVkQsri vkImage=0x" << std::hex << vkImage
+       << " timeline=0x" << std::hex << timeline;
+    sendAsync(
+        [vkImage, timeline](WorkerId) {
+            auto decoder = vk::VkDecoderGlobalState::get();
+            auto res = decoder->registerQsriCallback(vkImage, [timeline](){
+                 emugl::emugl_sync_timeline_inc(timeline, kTimelineInterval);
+            });
+            // If registerQsriCallback does not schedule the callback, we still need to complete
+            // the task, otherwise we may hit deadlocks on tasks on the same ring.
+            if (!res.CallbackScheduledOrFired()) {
+                emugl::emugl_sync_timeline_inc(timeline, kTimelineInterval);
+            }
+        },
+        ss.str());
+}
+
+void SyncThread::triggerGeneral(FenceCompletionCallback cb, std::string description) {
+    std::stringstream ss;
+    ss << "triggerGeneral: " << description;
+    sendAsync(std::bind(std::move(cb)), ss.str());
+}
+
+void SyncThread::cleanup() {
+    sendAndWaitForResult(
+        [this](WorkerId workerId) {
+            if (mHasGl) {
+                const EGLDispatch* egl = gl::LazyLoadedEGLDispatch::get();
+
+                egl->eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+                egl->eglDestroyContext(mDisplay, mContext[workerId]);
+                egl->eglDestroySurface(mDisplay, mSurface[workerId]);
+                mContext[workerId] = EGL_NO_CONTEXT;
+                mSurface[workerId] = EGL_NO_SURFACE;
+            }
+            return 0;
+        },
+        "cleanup");
+    DPRINT("signal");
+    mLock.lock();
+    mExiting = true;
+    mCv.signalAndUnlock(&mLock);
+    DPRINT("exit");
+    // Wait for the control thread to exit. We can't destroy the SyncThread
+    // before we wait the control thread.
+    if (!wait(nullptr)) {
+        ERR("Fail to wait the control thread of the SyncThread to exit.");
+    }
+}
+
+// Private methods below////////////////////////////////////////////////////////
+
+intptr_t SyncThread::main() {
+    DPRINT("in sync thread");
+    mLock.lock();
+    mCv.wait(&mLock, [this] { return mExiting; });
+
+    mWorkerThreadPool.done();
+    mWorkerThreadPool.join();
+    DPRINT("exited sync thread");
+    return 0;
+}
+
+int SyncThread::sendAndWaitForResult(std::function<int(WorkerId)> job, std::string description) {
+    DPRINT("sendAndWaitForResult task(%s)", description.c_str());
+    std::packaged_task<int(WorkerId)> task(std::move(job));
+    std::future<int> resFuture = task.get_future();
+    Command command = {
+        .mTask = std::move(task),
+        .mDescription = std::move(description),
+    };
+
+    mWorkerThreadPool.enqueue(std::move(command));
+    auto res = resFuture.get();
+    DPRINT("exit");
+    return res;
+}
+
+void SyncThread::sendAsync(std::function<void(WorkerId)> job, std::string description) {
+    DPRINT("send task(%s)", description.c_str());
+    mWorkerThreadPool.enqueue(Command{
+        .mTask =
+            std::packaged_task<int(WorkerId)>([job = std::move(job)](WorkerId workerId) mutable {
+                job(workerId);
+                return 0;
+            }),
+        .mDescription = std::move(description),
+    });
+    DPRINT("exit");
+}
+
+void SyncThread::doSyncThreadCmd(Command&& command, WorkerId workerId) {
+    std::unique_ptr<std::unordered_map<std::string, std::string>> syncThreadData =
+        std::make_unique<std::unordered_map<std::string, std::string>>();
+    syncThreadData->insert({{"syncthread_cmd_desc", command.mDescription}});
+    auto watchdog = WATCHDOG_BUILDER(mHealthMonitor, "SyncThread task execution")
+                        .setHangType(EventHangMetadata::HangType::kSyncThread)
+                        .setAnnotations(std::move(syncThreadData))
+                        .build();
+    command.mTask(workerId);
+}
+
 void SyncThread::initSyncEGLContext() {
     mWorkerThreadPool.broadcast([this] {
         return Command{
@@ -238,10 +374,9 @@
     DPRINT("wait on sync obj: %p", fenceSync);
     wait_result = fenceSync->wait(kDefaultTimeoutNsecs);
 
-    DPRINT(
-        "done waiting, with wait result=0x%x. "
-        "increment timeline (and signal fence)",
-        wait_result);
+    DPRINT("done waiting, with wait result=0x%x. "
+           "increment timeline (and signal fence)",
+           wait_result);
 
     if (wait_result != EGL_CONDITION_SATISFIED_KHR) {
         EGLint error = gl::s_egl.eglGetError();
@@ -286,154 +421,6 @@
     DPRINT("exit");
 }
 
-#endif
-
-void SyncThread::triggerWaitVk(VkFence vkFence, uint64_t timeline) {
-    std::stringstream ss;
-    ss << "triggerWaitVk vkFence=0x" << std::hex << reinterpret_cast<uintptr_t>(vkFence)
-       << " timeline=0x" << std::hex << timeline;
-    sendAsync(
-        [vkFence, timeline](WorkerId) {
-            doSyncWaitVk(vkFence, [timeline] {
-                DPRINT("vk wait done, use goldfish sync timeline inc");
-                emugl::emugl_sync_timeline_inc(timeline, kTimelineInterval);
-            });
-        },
-        ss.str());
-}
-
-void SyncThread::triggerWaitVkWithCompletionCallback(VkFence vkFence, FenceCompletionCallback cb) {
-    std::stringstream ss;
-    ss << "triggerWaitVkWithCompletionCallback vkFence=0x" << std::hex
-       << reinterpret_cast<uintptr_t>(vkFence);
-    sendAsync([vkFence, cb = std::move(cb)](WorkerId) { doSyncWaitVk(vkFence, std::move(cb)); },
-              ss.str());
-}
-
-void SyncThread::triggerWaitVkQsriWithCompletionCallback(VkImage vkImage, FenceCompletionCallback cb) {
-    std::stringstream ss;
-    ss << "triggerWaitVkQsriWithCompletionCallback vkImage=0x"
-       << reinterpret_cast<uintptr_t>(vkImage);
-    sendAsync(
-        [vkImage, cb = std::move(cb)](WorkerId) {
-            auto decoder = vk::VkDecoderGlobalState::get();
-            auto res = decoder->registerQsriCallback(vkImage, cb);
-            // If registerQsriCallback does not schedule the callback, we still need to complete
-            // the task, otherwise we may hit deadlocks on tasks on the same ring.
-            if (!res.CallbackScheduledOrFired()) {
-                cb();
-            }
-        },
-        ss.str());
-}
-
-void SyncThread::triggerWaitVkQsri(VkImage vkImage, uint64_t timeline) {
-     std::stringstream ss;
-    ss << "triggerWaitVkQsri vkImage=0x" << std::hex << vkImage
-       << " timeline=0x" << std::hex << timeline;
-    sendAsync(
-        [vkImage, timeline](WorkerId) {
-            auto decoder = vk::VkDecoderGlobalState::get();
-            auto res = decoder->registerQsriCallback(vkImage, [timeline](){
-                 emugl::emugl_sync_timeline_inc(timeline, kTimelineInterval);
-            });
-            // If registerQsriCallback does not schedule the callback, we still need to complete
-            // the task, otherwise we may hit deadlocks on tasks on the same ring.
-            if (!res.CallbackScheduledOrFired()) {
-                emugl::emugl_sync_timeline_inc(timeline, kTimelineInterval);
-            }
-        },
-        ss.str());
-}
-
-void SyncThread::triggerGeneral(FenceCompletionCallback cb, std::string description) {
-    std::stringstream ss;
-    ss << "triggerGeneral: " << description;
-    sendAsync(std::bind(std::move(cb)), ss.str());
-}
-
-void SyncThread::cleanup() {
-    sendAndWaitForResult(
-        [this](WorkerId workerId) {
-#if GFXSTREAM_ENABLE_HOST_GLES
-            if (mHasGl) {
-                const EGLDispatch* egl = gl::LazyLoadedEGLDispatch::get();
-
-                egl->eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-
-                egl->eglDestroyContext(mDisplay, mContext[workerId]);
-                egl->eglDestroySurface(mDisplay, mSurface[workerId]);
-                mContext[workerId] = EGL_NO_CONTEXT;
-                mSurface[workerId] = EGL_NO_SURFACE;
-            }
-#endif
-            return 0;
-        },
-        "cleanup");
-    DPRINT("signal");
-    mLock.lock();
-    mExiting = true;
-    mCv.signalAndUnlock(&mLock);
-    DPRINT("exit");
-    // Wait for the control thread to exit. We can't destroy the SyncThread
-    // before we wait the control thread.
-    if (!wait(nullptr)) {
-        ERR("Fail to wait the control thread of the SyncThread to exit.");
-    }
-}
-
-// Private methods below////////////////////////////////////////////////////////
-
-intptr_t SyncThread::main() {
-    DPRINT("in sync thread");
-    mLock.lock();
-    mCv.wait(&mLock, [this] { return mExiting; });
-
-    mWorkerThreadPool.done();
-    mWorkerThreadPool.join();
-    DPRINT("exited sync thread");
-    return 0;
-}
-
-int SyncThread::sendAndWaitForResult(std::function<int(WorkerId)> job, std::string description) {
-    DPRINT("sendAndWaitForResult task(%s)", description.c_str());
-    std::packaged_task<int(WorkerId)> task(std::move(job));
-    std::future<int> resFuture = task.get_future();
-    Command command = {
-        .mTask = std::move(task),
-        .mDescription = std::move(description),
-    };
-
-    mWorkerThreadPool.enqueue(std::move(command));
-    auto res = resFuture.get();
-    DPRINT("exit");
-    return res;
-}
-
-void SyncThread::sendAsync(std::function<void(WorkerId)> job, std::string description) {
-    DPRINT("send task(%s)", description.c_str());
-    mWorkerThreadPool.enqueue(Command{
-        .mTask =
-            std::packaged_task<int(WorkerId)>([job = std::move(job)](WorkerId workerId) mutable {
-                job(workerId);
-                return 0;
-            }),
-        .mDescription = std::move(description),
-    });
-    DPRINT("exit");
-}
-
-void SyncThread::doSyncThreadCmd(Command&& command, WorkerId workerId) {
-    std::unique_ptr<std::unordered_map<std::string, std::string>> syncThreadData =
-        std::make_unique<std::unordered_map<std::string, std::string>>();
-    syncThreadData->insert({{"syncthread_cmd_desc", command.mDescription}});
-    auto watchdog = WATCHDOG_BUILDER(mHealthMonitor, "SyncThread task execution")
-                        .setHangType(EventHangMetadata::HangType::kSyncThread)
-                        .setAnnotations(std::move(syncThreadData))
-                        .build();
-    command.mTask(workerId);
-}
-
 int SyncThread::doSyncWaitVk(VkFence vkFence, std::function<void()> onComplete) {
     DPRINT("enter");
 
@@ -473,4 +460,4 @@
 
 void SyncThread::destroy() { sGlobalSyncThread()->destroy(); }
 
-}  // namespace gfxstream
+}  // namespace gfxstream
\ No newline at end of file
diff --git a/host/SyncThread.h b/host/SyncThread.h
index 1c84301..2710222 100644
--- a/host/SyncThread.h
+++ b/host/SyncThread.h
@@ -16,26 +16,23 @@
 
 #pragma once
 
-#if GFXSTREAM_ENABLE_HOST_GLES
 #include <EGL/egl.h>
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
-#include "gl/EmulatedEglFenceSync.h"
-#endif
-
 #include <functional>
 #include <future>
 #include <string>
 #include <type_traits>
 
-#include "aemu/base/HealthMonitor.h"
-#include "aemu/base/Optional.h"
 #include "aemu/base/synchronization/ConditionVariable.h"
+#include "aemu/base/HealthMonitor.h"
 #include "aemu/base/synchronization/Lock.h"
 #include "aemu/base/synchronization/MessageChannel.h"
+#include "aemu/base/Optional.h"
 #include "aemu/base/threads/Thread.h"
 #include "aemu/base/threads/ThreadPool.h"
+#include "gl/EmulatedEglFenceSync.h"
 #include "render-utils/virtio_gpu_ops.h"
 #include "vulkan/VkDecoderGlobalState.h"
 
@@ -57,6 +54,14 @@
     SyncThread(bool hasGl, HealthMonitor<>* healthMonitor);
     ~SyncThread();
 
+    // |triggerWait|: async wait with a given EmulatedEglFenceSync object.
+    // We use the wait() method to do a eglClientWaitSyncKHR.
+    // After wait is over, the timeline will be incremented,
+    // which should signal the guest-side fence FD.
+    // This method is how the goldfish sync virtual device
+    // knows when to increment timelines / signal native fence FD's.
+    void triggerWait(gl::EmulatedEglFenceSync* fenceSync, uint64_t timeline);
+
     // |triggerWaitVk|: async wait with a given VkFence object.
     // The |vkFence| argument is a *boxed* host Vulkan handle of the fence.
     //
@@ -67,36 +72,17 @@
     // knows when to increment timelines / signal native fence FD's.
     void triggerWaitVk(VkFence vkFence, uint64_t timeline);
 
-#if GFXSTREAM_ENABLE_HOST_GLES
-    // |triggerWait|: async wait with a given EmulatedEglFenceSync object.
-    // We use the wait() method to do a eglClientWaitSyncKHR.
-    // After wait is over, the timeline will be incremented,
-    // which should signal the guest-side fence FD.
-    // This method is how the goldfish sync virtual device
-    // knows when to increment timelines / signal native fence FD's.
-    void triggerWait(gl::EmulatedEglFenceSync* fenceSync, uint64_t timeline);
-
     // for use with the virtio-gpu path; is meant to have a current context
     // while waiting.
     void triggerBlockedWaitNoTimeline(gl::EmulatedEglFenceSync* fenceSync);
+    
+    // This increments the timeline after the QSRI completes.
+    void triggerWaitVkQsri(VkImage vkImage, uint64_t timeline);
 
     // For use with virtio-gpu and async fence completion callback. This is async like triggerWait,
     // but takes a fence completion callback instead of incrementing some timeline directly.
     void triggerWaitWithCompletionCallback(gl::EmulatedEglFenceSync* fenceSync,
                                            FenceCompletionCallback);
-
-    // |initSyncContext| creates an EGL context expressly for calling
-    // eglClientWaitSyncKHR in the processing caused by |triggerWait|.
-    // This is used by the constructor only. It is non-blocking.
-    // - Triggers a |SyncThreadCmd| with op code |SYNC_THREAD_EGL_INIT|
-    void initSyncEGLContext();
-
-    void doSyncWait(gl::EmulatedEglFenceSync* fenceSync, std::function<void()> onComplete);
-#endif
-
-    // This increments the timeline after the QSRI completes.
-    void triggerWaitVkQsri(VkImage vkImage, uint64_t timeline);
-
     void triggerWaitVkWithCompletionCallback(VkFence fenceHandle, FenceCompletionCallback);
     void triggerWaitVkQsriWithCompletionCallback(VkImage image, FenceCompletionCallback);
     void triggerGeneral(FenceCompletionCallback, std::string description);
@@ -125,6 +111,12 @@
     };
     using ThreadPool = android::base::ThreadPool<Command>;
 
+    // |initSyncContext| creates an EGL context expressly for calling
+    // eglClientWaitSyncKHR in the processing caused by |triggerWait|.
+    // This is used by the constructor only. It is non-blocking.
+    // - Triggers a |SyncThreadCmd| with op code |SYNC_THREAD_EGL_INIT|
+    void initSyncEGLContext();
+
     // Thread function.
     // It keeps the workers runner until |mExiting| is set.
     virtual intptr_t main() override final;
@@ -140,17 +132,16 @@
     // |doSyncThreadCmd| execute the actual task. These run on the sync thread.
     void doSyncThreadCmd(Command&& command, ThreadPool::WorkerId);
 
+    void doSyncWait(gl::EmulatedEglFenceSync* fenceSync, std::function<void()> onComplete);
     static int doSyncWaitVk(VkFence, std::function<void()> onComplete);
 
     // EGL objects / object handles specific to
     // a sync thread.
     static const uint32_t kNumWorkerThreads = 4u;
 
-#if GFXSTREAM_ENABLE_HOST_GLES
     EGLDisplay mDisplay = EGL_NO_DISPLAY;
     EGLSurface mSurface[kNumWorkerThreads];
     EGLContext mContext[kNumWorkerThreads];
-#endif
 
     bool mExiting = false;
     android::base::Lock mLock;
diff --git a/host/meson.build b/host/meson.build
index 9a35912..1d9b4c8 100644
--- a/host/meson.build
+++ b/host/meson.build
@@ -94,14 +94,6 @@
   use_magma = host_machine.system() == 'linux'
 endif
 
-gfxstream_host_args += '-DGFXSTREAM_ENABLE_HOST_GLES=@0@'.format(use_gles ? '1' : '0')
-if use_magma
-  gfxstream_host_args += '-DUSE_MAGMA=1'
-  drm_dep = dependency('libdrm')
-else
-  gfxstream_host_args += '-DUSE_MAGMA=0'
-endif
-
 if use_magma
   gfxstream_host_args += '-DGFXSTREAM_ENABLE_HOST_GLES=1'
   drm_dep = dependency('libdrm')
@@ -155,7 +147,7 @@
 inc_gfxstream_backend = [inc_root, inc_include, inc_apigen_codec, inc_utils,
                          inc_gl_host_common, inc_host_include]
 
-link_gfxstream_backend = [lib_gl_host_common, lib_apigen_codec]
+link_gfxstream_backend = [lib_gl_host_common]
 
 files_lib_gfxstream_backend = files(
   'Buffer.cpp',
@@ -173,6 +165,7 @@
   'RenderThreadInfo.cpp',
   'RingStream.cpp',
   'SyncThread.cpp',
+  'RenderControl.cpp',
   'RenderWindow.cpp',
   'RenderLibImpl.cpp',
   'RendererImpl.cpp',
@@ -192,7 +185,6 @@
 
   files_lib_gfxstream_backend += files('PostWorkerGl.cpp')
   files_lib_gfxstream_backend += files('RenderThreadInfoGl.cpp')
-  files_lib_gfxstream_backend += files('RenderControl.cpp')
 
   inc_gfxstream_backend += [inc_gl_server, inc_gl_snapshot, inc_gles_translator]
   link_gfxstream_backend += lib_gl_server
@@ -217,13 +209,11 @@
   link_gfxstream_backend += lib_magma_server
 endif
 
-if not use_gles
-  files_lib_gfxstream_backend += files('NativeSubWindow_stub.cpp')
-elif host_machine.system() == 'darwin'
+if host_machine.system() == 'darwin'
   files_lib_gfxstream_backend += files('NativeSubWindow_cocoa.m')
 elif host_machine.system() == 'windows'
   files_lib_gfxstream_backend += files('NativeSubWindow_win32.cpp')
-elif host_machine.system() == 'linux' and use_gles
+elif host_machine.system() == 'linux'
   files_lib_gfxstream_backend += files('NativeSubWindow_x11.cpp')
 elif host_machine.system() == 'qnx'
   files_lib_gfxstream_backend += files(
diff --git a/host/renderControl_dec/renderControl_types.h b/host/renderControl_dec/renderControl_types.h
index f265e06..fb5ced9 100644
--- a/host/renderControl_dec/renderControl_types.h
+++ b/host/renderControl_dec/renderControl_types.h
@@ -18,4 +18,13 @@
 #include <EGL/egl.h>
 #include "glUtils.h"
 
+// values for 'param' argument of rcGetFBParam
+#define FB_WIDTH    1
+#define FB_HEIGHT   2
+#define FB_XDPI     3
+#define FB_YDPI     4
+#define FB_FPS      5
+#define FB_MIN_SWAP_INTERVAL 6
+#define FB_MAX_SWAP_INTERVAL 7
+
 using RenderControlByte = char;
diff --git a/host/vulkan/emulated_textures/meson.build b/host/vulkan/emulated_textures/meson.build
index d3e6f45..06f8181 100644
--- a/host/vulkan/emulated_textures/meson.build
+++ b/host/vulkan/emulated_textures/meson.build
@@ -17,6 +17,5 @@
   cpp_args: emulated_texture_args + gfxstream_host_args,
   include_directories: [inc_utils, inc_root, inc_vulkan_headers, inc_vulkan_server,
                         inc_include, inc_cereal_common, inc_stream_servers],
-  link_with: [lib_compressed_textures],
   dependencies: [aemu_base_dep, aemu_common_dep]
 )