Merge "Move Buffer to the new "gl" subdirectory"
diff --git a/stream-servers/Android.bp b/stream-servers/Android.bp
index 1b6a8e4..2a90b3a 100644
--- a/stream-servers/Android.bp
+++ b/stream-servers/Android.bp
@@ -57,7 +57,6 @@
         "Debug.cpp",
         "DisplaySurface.cpp",
         "DisplaySurfaceUser.cpp",
-        "FenceSync.cpp",
         "Hwc2.cpp",
         "PostWorker.cpp",
         "ReadbackWorker.cpp",
diff --git a/stream-servers/CMakeLists.txt b/stream-servers/CMakeLists.txt
index 05ab846..aa65183 100644
--- a/stream-servers/CMakeLists.txt
+++ b/stream-servers/CMakeLists.txt
@@ -19,7 +19,6 @@
     Debug.cpp
     DisplaySurface.cpp
     DisplaySurfaceUser.cpp
-    FenceSync.cpp
     Hwc2.cpp
     PostWorker.cpp
     ReadbackWorker.cpp
diff --git a/stream-servers/FenceSync.cpp b/stream-servers/FenceSync.cpp
deleted file mode 100644
index 678d432..0000000
--- a/stream-servers/FenceSync.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
-* Copyright (C) 2016 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 "FenceSync.h"
-
-#include <unordered_set>
-
-#include "FrameBuffer.h"
-#include "OpenGLESDispatch/DispatchTables.h"
-#include "OpenGLESDispatch/EGLDispatch.h"
-#include "RenderThreadInfo.h"
-#include "StalePtrRegistry.h"
-
-#include "aemu/base/containers/Lookup.h"
-#include "aemu/base/containers/StaticMap.h"
-#include "aemu/base/files/StreamSerializing.h"
-#include "aemu/base/synchronization/Lock.h"
-
-using android::base::AutoLock;
-using android::base::Lock;
-using android::base::StaticMap;
-
-// Timeline class is meant to delete native fences after the
-// sync device has incremented the timeline.  We assume a
-// maximum number of outstanding timelines in the guest (16) in
-// order to derive when a native fence is definitely safe to
-// delete. After at least that many timeline increments have
-// happened, we sweep away the remaining native fences.
-// The function that performs the deleting,
-// incrementTimelineAndDeleteOldFences(), happens on the SyncThread.
-
-class Timeline {
-public:
-    Timeline() = default;
-
-    static constexpr int kMaxGuestTimelines = 16;
-    void addFence(FenceSync* fence) {
-        mFences.set(fence, mTime.load() + kMaxGuestTimelines);
-    }
-
-    void incrementTimelineAndDeleteOldFences() {
-        ++mTime;
-        sweep();
-    }
-
-    void sweep() {
-        mFences.eraseIf([time = mTime.load()](FenceSync* fence, int fenceTime) {
-            FenceSync* actual = FenceSync::getFromHandle((uint64_t)(uintptr_t)fence);
-            if (!actual) return true;
-
-            bool shouldErase = fenceTime <= time;
-            if (shouldErase) {
-                if (!actual->decRef() &&
-                    actual->shouldDestroyWhenSignaled()) {
-                    actual->decRef();
-                }
-            }
-            return shouldErase;
-        });
-    }
-
-private:
-    std::atomic<int> mTime {0};
-    StaticMap<FenceSync*, int> mFences;
-};
-
-static Timeline* sTimeline() {
-    static Timeline* t = new Timeline;
-    return t;
-}
-
-// static
-void FenceSync::incrementTimelineAndDeleteOldFences() {
-    sTimeline()->incrementTimelineAndDeleteOldFences();
-}
-
-FenceSync::FenceSync(bool hasNativeFence,
-                     bool destroyWhenSignaled) :
-    mDestroyWhenSignaled(destroyWhenSignaled) {
-
-    addToRegistry();
-
-    assert(mCount == 1);
-    if (hasNativeFence) {
-        incRef();
-        sTimeline()->addFence(this);
-    }
-
-    // assumes that there is a valid + current OpenGL context
-    assert(RenderThreadInfo::get());
-
-    mDisplay = FrameBuffer::getFB()->getDisplay();
-    mSync = s_egl.eglCreateSyncKHR(mDisplay,
-                                   EGL_SYNC_FENCE_KHR,
-                                   NULL);
-}
-
-FenceSync::~FenceSync() {
-    removeFromRegistry();
-}
-
-EGLint FenceSync::wait(uint64_t timeout) {
-    incRef();
-    EGLint wait_res =
-        s_egl.eglClientWaitSyncKHR(mDisplay, mSync,
-                                   EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
-                                   timeout);
-    decRef();
-    return wait_res;
-}
-
-void FenceSync::waitAsync() {
-    s_egl.eglWaitSyncKHR(mDisplay, mSync, 0);
-}
-
-bool FenceSync::isSignaled() {
-    EGLint val;
-    if (EGL_TRUE ==
-            s_egl.eglGetSyncAttribKHR(
-                mDisplay, mSync, EGL_SYNC_STATUS_KHR, &val))
-        return val == EGL_SIGNALED_KHR;
-
-    return true; // if invalid, treat as signaled
-}
-
-void FenceSync::destroy() {
-    s_egl.eglDestroySyncKHR(mDisplay, mSync);
-}
-
-// Snapshots for FenceSync//////////////////////////////////////////////////////
-// It's possible, though it does not happen often, that a fence
-// can be created but not yet waited on by the guest, which
-// needs careful handling:
-//
-// 1. Avoid manipulating garbage memory on snapshot restore;
-// rcCreateSyncKHR *creates new fence in valid memory*
-// --snapshot--
-// rcClientWaitSyncKHR *refers to uninitialized memory*
-// rcDestroySyncKHR *refers to uninitialized memory*
-// 2. Make rcCreateSyncKHR/rcDestroySyncKHR implementations return
-// the "signaled" status if referring to previous snapshot fences. It's
-// assumed that the GPU is long done with them.
-// 3. Avoid name collisions where a new FenceSync object is created
-// that has the same uint64_t casting as a FenceSync object from a previous
-// snapshot.
-
-// Maintain a StalePtrRegistry<FenceSync>:
-static StalePtrRegistry<FenceSync>* sFenceRegistry() {
-    static StalePtrRegistry<FenceSync>* s = new StalePtrRegistry<FenceSync>;
-    return s;
-}
-
-// static
-void FenceSync::addToRegistry() {
-    sFenceRegistry()->addPtr(this);
-}
-
-// static
-void FenceSync::removeFromRegistry() {
-    sFenceRegistry()->removePtr(this);
-}
-
-// static
-void FenceSync::onSave(android::base::Stream* stream) {
-    sFenceRegistry()->makeCurrentPtrsStale();
-    sFenceRegistry()->onSave(stream);
-}
-
-// static
-void FenceSync::onLoad(android::base::Stream* stream) {
-    sFenceRegistry()->onLoad(stream);
-}
-
-// static
-FenceSync* FenceSync::getFromHandle(uint64_t handle) {
-    return sFenceRegistry()->getPtr(handle);
-}
diff --git a/stream-servers/FrameBuffer.cpp b/stream-servers/FrameBuffer.cpp
index d56d3f7..004bb53 100644
--- a/stream-servers/FrameBuffer.cpp
+++ b/stream-servers/FrameBuffer.cpp
@@ -64,6 +64,7 @@
 using gfxstream::EmulatedEglContext;
 using gfxstream::EmulatedEglContextMap;
 using gfxstream::EmulatedEglContextPtr;
+using gfxstream::EmulatedEglFenceSync;
 using gfxstream::EmulatedEglWindowSurface;
 using gfxstream::EmulatedEglWindowSurfaceMap;
 using gfxstream::EmulatedEglWindowSurfacePtr;
@@ -1467,6 +1468,47 @@
     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.
@@ -2982,6 +3024,7 @@
         }
     }
 
+    EmulatedEglFenceSync::onSave(stream);
 }
 
 bool FrameBuffer::onLoad(Stream* stream,
@@ -3189,6 +3232,9 @@
     }
 
     repost(false);
+
+    EmulatedEglFenceSync::onLoad(stream);
+
     return true;
     // TODO: restore memory management
 }
@@ -3335,7 +3381,7 @@
 }
 
 void FrameBuffer::waitForGpu(uint64_t eglsync) {
-    FenceSync* fenceSync = FenceSync::getFromHandle(eglsync);
+    EmulatedEglFenceSync* fenceSync = EmulatedEglFenceSync::getFromHandle(eglsync);
 
     if (!fenceSync) {
         ERR("err: fence sync 0x%llx not found", (unsigned long long)eglsync);
@@ -3348,20 +3394,20 @@
 void FrameBuffer::waitForGpuVulkan(uint64_t deviceHandle, uint64_t fenceHandle) {
     (void)deviceHandle;
     if (!m_emulationGl) {
-        // Guest ANGLE should always use the asyncWaitForGpuVulkanWithCb call. FenceSync is a
+        // 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.
-    FenceSync* fenceSync = FenceSync::getFromHandle(fenceHandle);
+    EmulatedEglFenceSync* fenceSync = EmulatedEglFenceSync::getFromHandle(fenceHandle);
 
     // Note: This will always signal right away.
     SyncThread::get()->triggerBlockedWaitNoTimeline(fenceSync);
 }
 
 void FrameBuffer::asyncWaitForGpuWithCb(uint64_t eglsync, FenceCompletionCallback cb) {
-    FenceSync* fenceSync = FenceSync::getFromHandle(eglsync);
+    EmulatedEglFenceSync* fenceSync = EmulatedEglFenceSync::getFromHandle(eglsync);
 
     if (!fenceSync) {
         ERR("err: fence sync 0x%llx not found", (unsigned long long)eglsync);
diff --git a/stream-servers/FrameBuffer.h b/stream-servers/FrameBuffer.h
index da3575d..ce08e03 100644
--- a/stream-servers/FrameBuffer.h
+++ b/stream-servers/FrameBuffer.h
@@ -216,6 +216,11 @@
     // 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.
diff --git a/stream-servers/RenderControl.cpp b/stream-servers/RenderControl.cpp
index 2d44259..20803e2 100644
--- a/stream-servers/RenderControl.cpp
+++ b/stream-servers/RenderControl.cpp
@@ -23,7 +23,6 @@
 #include <memory>
 
 #include "ChecksumCalculatorThreadInfo.h"
-#include "FenceSync.h"
 #include "FrameBuffer.h"
 #include "GLESVersionDetector.h"
 #include "OpenGLESDispatch/DispatchTables.h"
@@ -46,6 +45,7 @@
 using emugl::emugl_sync_register_trigger_wait;
 using gfxstream::GLESApi;
 using gfxstream::GLESApi_CM;
+using gfxstream::EmulatedEglFenceSync;
 
 #define DEBUG_GRALLOC_SYNC 0
 #define DEBUG_EGL_SYNC 0
@@ -1111,7 +1111,7 @@
         SyncThread::get()->triggerWaitVk(reinterpret_cast<VkFence>(eglsync_ptr),
                                          timeline);
     } else {
-        FenceSync* fenceSync = reinterpret_cast<FenceSync*>(eglsync_ptr);
+        EmulatedEglFenceSync* fenceSync = reinterpret_cast<EmulatedEglFenceSync*>(eglsync_ptr);
         EGLSYNC_DPRINT(
                 "eglsync=0x%llx fenceSync=%p thread_ptr=0x%llx "
                 "timeline=0x%llx",
@@ -1127,15 +1127,9 @@
 static void rcCreateSyncKHR(EGLenum type,
                             EGLint* attribs,
                             uint32_t num_attribs,
-                            int destroy_when_signaled,
-                            uint64_t* eglsync_out,
-                            uint64_t* syncthread_out) {
-    EGLSYNC_DPRINT("type=0x%x num_attribs=%d",
-            type, num_attribs);
-
-    bool hasNativeFence =
-        type == EGL_SYNC_NATIVE_FENCE_ANDROID;
-
+                            int destroyWhenSignaled,
+                            uint64_t* outSync,
+                            uint64_t* outSyncThread) {
     // Usually we expect rcTriggerWait to be registered
     // at the beginning in rcGetRendererVersion, called
     // on init for all contexts.
@@ -1144,44 +1138,16 @@
     // rcTriggerWait is registered.
     emugl_sync_register_trigger_wait(rcTriggerWait);
 
-    RenderThreadInfoGl* const tInfo = RenderThreadInfoGl::get();
-    if (!tInfo) {
-        GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
-            << "Render thread GL not available.";
-    }
-
-    if (!tInfo->currContext) {
-        auto fb = FrameBuffer::getFB();
-        uint32_t create_sync_cxt, create_sync_surf;
-        fb->createTrivialContext(0, // There is no context to share.
-                                 &create_sync_cxt,
-                                 &create_sync_surf);
-        fb->bindContext(create_sync_cxt,
-                        create_sync_surf,
-                        create_sync_surf);
-        // This context is then cleaned up when the render thread exits.
-    }
-
-    FenceSync* fenceSync = new FenceSync(hasNativeFence,
-                                         destroy_when_signaled);
-
-    // This MUST be present, or we get a deadlock effect.
-    s_gles2.glFlush();
-
-    if (syncthread_out) *syncthread_out =
-        reinterpret_cast<uint64_t>(SyncThread::get());
-
-    if (eglsync_out) {
-        uint64_t res = (uint64_t)(uintptr_t)fenceSync;
-        *eglsync_out = res;
-        EGLSYNC_DPRINT("send out eglsync 0x%llx", res);
-    }
+    FrameBuffer::getFB()->createEmulatedEglFenceSync(type,
+                                                     destroyWhenSignaled,
+                                                     outSync,
+                                                     outSyncThread);
 }
 
 // |rcClientWaitSyncKHR| implements |eglClientWaitSyncKHR|
 // on the guest through using the host's existing
 // |eglClientWaitSyncKHR| implementation, which is done
-// through the FenceSync object.
+// through the EmulatedEglFenceSync object.
 static EGLint rcClientWaitSyncKHR(uint64_t handle,
                                   EGLint flags,
                                   uint64_t timeout) {
@@ -1196,7 +1162,7 @@
     EGLSYNC_DPRINT("handle=0x%lx flags=0x%x timeout=%" PRIu64,
                 handle, flags, timeout);
 
-    FenceSync* fenceSync = FenceSync::getFromHandle(handle);
+    EmulatedEglFenceSync* fenceSync = EmulatedEglFenceSync::getFromHandle(handle);
 
     if (!fenceSync) {
         EGLSYNC_DPRINT("fenceSync null, return condition satisfied");
@@ -1232,7 +1198,7 @@
 
     EGLSYNC_DPRINT("handle=0x%lx flags=0x%x", handle, flags);
 
-    FenceSync* fenceSync = FenceSync::getFromHandle(handle);
+    EmulatedEglFenceSync* fenceSync = EmulatedEglFenceSync::getFromHandle(handle);
 
     if (!fenceSync) { return; }
 
@@ -1254,7 +1220,7 @@
 }
 
 static int rcDestroySyncKHR(uint64_t handle) {
-    FenceSync* fenceSync = FenceSync::getFromHandle(handle);
+    EmulatedEglFenceSync* fenceSync = EmulatedEglFenceSync::getFromHandle(handle);
     if (!fenceSync) return 0;
     fenceSync->decRef();
     return 0;
@@ -1391,7 +1357,7 @@
 }
 
 static int rcIsSyncSignaled(uint64_t handle) {
-    FenceSync* fenceSync = FenceSync::getFromHandle(handle);
+    EmulatedEglFenceSync* fenceSync = EmulatedEglFenceSync::getFromHandle(handle);
     if (!fenceSync) return 1; // assume destroyed => signaled
     return fenceSync->isSignaled() ? 1 : 0;
 }
@@ -1529,7 +1495,7 @@
 }
 
 static void rcDestroySyncKHRAsync(uint64_t handle) {
-    FenceSync* fenceSync = FenceSync::getFromHandle(handle);
+    EmulatedEglFenceSync* fenceSync = EmulatedEglFenceSync::getFromHandle(handle);
     if (!fenceSync) return;
     fenceSync->decRef();
 }
diff --git a/stream-servers/RendererImpl.cpp b/stream-servers/RendererImpl.cpp
index d56f28b..3309cd7 100644
--- a/stream-servers/RendererImpl.cpp
+++ b/stream-servers/RendererImpl.cpp
@@ -19,7 +19,6 @@
 #include <utility>
 #include <variant>
 
-#include "FenceSync.h"
 #include "FrameBuffer.h"
 #include "RenderChannelImpl.h"
 #include "RenderThread.h"
@@ -337,8 +336,6 @@
     auto fb = FrameBuffer::getFB();
     assert(fb);
     fb->onSave(stream, textureSaver);
-
-    FenceSync::onSave(stream);
 }
 
 bool RendererImpl::load(android::base::Stream* stream,
@@ -366,9 +363,6 @@
 
     bool res = true;
 
-    res = fb->onLoad(stream, textureLoader);
-    FenceSync::onLoad(stream);
-
     return res;
 }
 
diff --git a/stream-servers/SyncThread.cpp b/stream-servers/SyncThread.cpp
index 0042973..e348ff5 100644
--- a/stream-servers/SyncThread.cpp
+++ b/stream-servers/SyncThread.cpp
@@ -33,6 +33,7 @@
 using android::base::EventHangMetadata;
 using emugl::ABORT_REASON_OTHER;
 using emugl::FatalError;
+using gfxstream::EmulatedEglFenceSync;
 
 #define DEBUG 0
 
@@ -117,7 +118,7 @@
     cleanup();
 }
 
-void SyncThread::triggerWait(FenceSync* fenceSync,
+void SyncThread::triggerWait(EmulatedEglFenceSync* fenceSync,
                              uint64_t timeline) {
     std::stringstream ss;
     ss << "triggerWait fenceSyncInfo=0x" << std::hex << reinterpret_cast<uintptr_t>(fenceSync)
@@ -146,7 +147,7 @@
         ss.str());
 }
 
-void SyncThread::triggerBlockedWaitNoTimeline(FenceSync* fenceSync) {
+void SyncThread::triggerBlockedWaitNoTimeline(EmulatedEglFenceSync* fenceSync) {
     std::stringstream ss;
     ss << "triggerBlockedWaitNoTimeline fenceSyncInfo=0x" << std::hex
        << reinterpret_cast<uintptr_t>(fenceSync);
@@ -158,7 +159,7 @@
         ss.str());
 }
 
-void SyncThread::triggerWaitWithCompletionCallback(FenceSync* fenceSync, FenceCompletionCallback cb) {
+void SyncThread::triggerWaitWithCompletionCallback(EmulatedEglFenceSync* fenceSync, FenceCompletionCallback cb) {
     std::stringstream ss;
     ss << "triggerWaitWithCompletionCallback fenceSyncInfo=0x" << std::hex
        << reinterpret_cast<uintptr_t>(fenceSync);
@@ -333,17 +334,17 @@
     mWorkerThreadPool.waitAllItems();
 }
 
-void SyncThread::doSyncWait(FenceSync* fenceSync, std::function<void()> onComplete) {
+void SyncThread::doSyncWait(EmulatedEglFenceSync* fenceSync, std::function<void()> onComplete) {
     DPRINT("enter");
 
-    if (!FenceSync::getFromHandle((uint64_t)(uintptr_t)fenceSync)) {
+    if (!EmulatedEglFenceSync::getFromHandle((uint64_t)(uintptr_t)fenceSync)) {
         if (onComplete) {
             onComplete();
         }
         return;
     }
-    // We shouldn't use FenceSync to wait, when SyncThread is initialized
-    // without GL enabled, because FenceSync uses EGL/GLES.
+    // We shouldn't use EmulatedEglFenceSync to wait, when SyncThread is initialized
+    // without GL enabled, because EmulatedEglFenceSync uses EGL/GLES.
     SYNC_THREAD_CHECK(!mNoGL);
 
     EGLint wait_result = 0x0;
@@ -391,7 +392,7 @@
     if (onComplete) {
         onComplete();
     }
-    FenceSync::incrementTimelineAndDeleteOldFences();
+    EmulatedEglFenceSync::incrementTimelineAndDeleteOldFences();
 
     DPRINT("done timeline increment");
 
diff --git a/stream-servers/SyncThread.h b/stream-servers/SyncThread.h
index 59be896..dd3aa11 100644
--- a/stream-servers/SyncThread.h
+++ b/stream-servers/SyncThread.h
@@ -25,7 +25,6 @@
 #include <string>
 #include <type_traits>
 
-#include "FenceSync.h"
 #include "aemu/base/synchronization/ConditionVariable.h"
 #include "aemu/base/HealthMonitor.h"
 #include "aemu/base/synchronization/Lock.h"
@@ -33,6 +32,7 @@
 #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"
 
@@ -52,13 +52,13 @@
     SyncThread(bool noGL, HealthMonitor<>& healthMonitor);
     ~SyncThread();
 
-    // |triggerWait|: async wait with a given FenceSync object.
+    // |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(FenceSync* fenceSync, uint64_t timeline);
+    void triggerWait(gfxstream::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.
@@ -72,11 +72,12 @@
 
     // for use with the virtio-gpu path; is meant to have a current context
     // while waiting.
-    void triggerBlockedWaitNoTimeline(FenceSync* fenceSync);
+    void triggerBlockedWaitNoTimeline(gfxstream::EmulatedEglFenceSync* fenceSync);
 
     // 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(FenceSync* fenceSync, FenceCompletionCallback);
+    void triggerWaitWithCompletionCallback(gfxstream::EmulatedEglFenceSync* fenceSync,
+                                           FenceCompletionCallback);
     void triggerWaitVkWithCompletionCallback(VkFence fenceHandle, FenceCompletionCallback);
     void triggerWaitVkQsriWithCompletionCallback(VkImage image, FenceCompletionCallback);
     void triggerGeneral(FenceCompletionCallback, std::string description);
@@ -126,7 +127,8 @@
     // |doSyncThreadCmd| execute the actual task. These run on the sync thread.
     void doSyncThreadCmd(Command&& command, ThreadPool::WorkerId);
 
-    void doSyncWait(FenceSync* fenceSync, std::function<void()> onComplete);
+    void doSyncWait(gfxstream::EmulatedEglFenceSync* fenceSync,
+                    std::function<void()> onComplete);
     static int doSyncWaitVk(VkFence, std::function<void()> onComplete);
 
     // EGL objects / object handles specific to
diff --git a/stream-servers/gl/Android.bp b/stream-servers/gl/Android.bp
index bc76f78..0ddae14 100644
--- a/stream-servers/gl/Android.bp
+++ b/stream-servers/gl/Android.bp
@@ -19,6 +19,7 @@
         "DisplaySurfaceGl.cpp",
         "EmulatedEglConfig.cpp",
         "EmulatedEglContext.cpp",
+        "EmulatedEglFenceSync.cpp",
         "EmulatedEglImage.cpp",
         "EmulatedEglWindowSurface.cpp",
         "EmulationGl.cpp",
diff --git a/stream-servers/gl/CMakeLists.txt b/stream-servers/gl/CMakeLists.txt
index 76eb44c..711f768 100644
--- a/stream-servers/gl/CMakeLists.txt
+++ b/stream-servers/gl/CMakeLists.txt
@@ -17,6 +17,7 @@
             DisplaySurfaceGl.cpp
             EmulatedEglConfig.cpp
             EmulatedEglContext.cpp
+            EmulatedEglFenceSync.cpp
             EmulatedEglImage.cpp
             EmulatedEglWindowSurface.cpp
             EmulationGl.cpp
diff --git a/stream-servers/gl/EmulatedEglFenceSync.cpp b/stream-servers/gl/EmulatedEglFenceSync.cpp
new file mode 100644
index 0000000..8ac94da
--- /dev/null
+++ b/stream-servers/gl/EmulatedEglFenceSync.cpp
@@ -0,0 +1,215 @@
+/*
+* Copyright (C) 2016 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 "EmulatedEglFenceSync.h"
+
+#include <unordered_set>
+
+#include "OpenGLESDispatch/DispatchTables.h"
+#include "OpenGLESDispatch/EGLDispatch.h"
+#include "RenderThreadInfoGl.h"
+#include "StalePtrRegistry.h"
+#include "aemu/base/containers/Lookup.h"
+#include "aemu/base/containers/StaticMap.h"
+#include "aemu/base/files/StreamSerializing.h"
+#include "aemu/base/synchronization/Lock.h"
+
+namespace gfxstream {
+namespace {
+
+using android::base::AutoLock;
+using android::base::Lock;
+using android::base::StaticMap;
+
+// Timeline class is meant to delete native fences after the
+// sync device has incremented the timeline.  We assume a
+// maximum number of outstanding timelines in the guest (16) in
+// order to derive when a native fence is definitely safe to
+// delete. After at least that many timeline increments have
+// happened, we sweep away the remaining native fences.
+// The function that performs the deleting,
+// incrementTimelineAndDeleteOldFences(), happens on the SyncThread.
+
+class Timeline {
+  public:
+    Timeline() = default;
+
+    static constexpr int kMaxGuestTimelines = 16;
+    void addFence(EmulatedEglFenceSync* fence) {
+        mFences.set(fence, mTime.load() + kMaxGuestTimelines);
+    }
+
+    void incrementTimelineAndDeleteOldFences() {
+        ++mTime;
+        sweep();
+    }
+
+    void sweep() {
+        mFences.eraseIf([time = mTime.load()](EmulatedEglFenceSync* fence, int fenceTime) {
+            EmulatedEglFenceSync* actual = EmulatedEglFenceSync::getFromHandle((uint64_t)(uintptr_t)fence);
+            if (!actual) return true;
+
+            bool shouldErase = fenceTime <= time;
+            if (shouldErase) {
+                if (!actual->decRef() &&
+                    actual->shouldDestroyWhenSignaled()) {
+                    actual->decRef();
+                }
+            }
+            return shouldErase;
+        });
+    }
+
+  private:
+    std::atomic<int> mTime {0};
+    StaticMap<EmulatedEglFenceSync*, int> mFences;
+};
+
+static Timeline* sTimeline() {
+    static Timeline* t = new Timeline;
+    return t;
+}
+
+}  // namespace
+
+// static
+void EmulatedEglFenceSync::incrementTimelineAndDeleteOldFences() {
+    sTimeline()->incrementTimelineAndDeleteOldFences();
+}
+
+// static
+std::unique_ptr<EmulatedEglFenceSync> EmulatedEglFenceSync::create(
+        EGLDisplay display,
+        bool hasNativeFence,
+        bool destroyWhenSignaled) {
+    auto sync = s_egl.eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
+    if (sync == EGL_NO_SYNC_KHR) {
+        ERR("Failed to create EGL fence sync: %d", s_egl.eglGetError());
+        return nullptr;
+    }
+
+    // This MUST be present, or we get a deadlock effect.
+    s_gles2.glFlush();
+
+    return std::unique_ptr<EmulatedEglFenceSync>(
+        new EmulatedEglFenceSync(display,
+                                 sync,
+                                 hasNativeFence,
+                                 destroyWhenSignaled));
+}
+
+EmulatedEglFenceSync::EmulatedEglFenceSync(EGLDisplay display,
+                                           EGLSyncKHR sync,
+                                           bool hasNativeFence,
+                                           bool destroyWhenSignaled)
+    : mDestroyWhenSignaled(destroyWhenSignaled),
+      mDisplay(display),
+      mSync(sync) {
+
+    addToRegistry();
+
+    assert(mCount == 1);
+    if (hasNativeFence) {
+        incRef();
+        sTimeline()->addFence(this);
+    }
+
+    // Assumes that there is a valid + current OpenGL context
+    assert(RenderThreadInfoGl::get());
+}
+
+EmulatedEglFenceSync::~EmulatedEglFenceSync() {
+    removeFromRegistry();
+}
+
+EGLint EmulatedEglFenceSync::wait(uint64_t timeout) {
+    incRef();
+    EGLint wait_res =
+        s_egl.eglClientWaitSyncKHR(mDisplay, mSync,
+                                   EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
+                                   timeout);
+    decRef();
+    return wait_res;
+}
+
+void EmulatedEglFenceSync::waitAsync() {
+    s_egl.eglWaitSyncKHR(mDisplay, mSync, 0);
+}
+
+bool EmulatedEglFenceSync::isSignaled() {
+    EGLint val;
+    if (EGL_TRUE ==
+            s_egl.eglGetSyncAttribKHR(
+                mDisplay, mSync, EGL_SYNC_STATUS_KHR, &val))
+        return val == EGL_SIGNALED_KHR;
+
+    return true; // if invalid, treat as signaled
+}
+
+void EmulatedEglFenceSync::destroy() {
+    s_egl.eglDestroySyncKHR(mDisplay, mSync);
+}
+
+// Snapshots for EmulatedEglFenceSync//////////////////////////////////////////////////////
+// It's possible, though it does not happen often, that a fence
+// can be created but not yet waited on by the guest, which
+// needs careful handling:
+//
+// 1. Avoid manipulating garbage memory on snapshot restore;
+// rcCreateSyncKHR *creates new fence in valid memory*
+// --snapshot--
+// rcClientWaitSyncKHR *refers to uninitialized memory*
+// rcDestroySyncKHR *refers to uninitialized memory*
+// 2. Make rcCreateSyncKHR/rcDestroySyncKHR implementations return
+// the "signaled" status if referring to previous snapshot fences. It's
+// assumed that the GPU is long done with them.
+// 3. Avoid name collisions where a new EmulatedEglFenceSync object is created
+// that has the same uint64_t casting as a EmulatedEglFenceSync object from a previous
+// snapshot.
+
+// Maintain a StalePtrRegistry<EmulatedEglFenceSync>:
+static StalePtrRegistry<EmulatedEglFenceSync>* sFenceRegistry() {
+    static StalePtrRegistry<EmulatedEglFenceSync>* s = new StalePtrRegistry<EmulatedEglFenceSync>;
+    return s;
+}
+
+// static
+void EmulatedEglFenceSync::addToRegistry() {
+    sFenceRegistry()->addPtr(this);
+}
+
+// static
+void EmulatedEglFenceSync::removeFromRegistry() {
+    sFenceRegistry()->removePtr(this);
+}
+
+// static
+void EmulatedEglFenceSync::onSave(android::base::Stream* stream) {
+    sFenceRegistry()->makeCurrentPtrsStale();
+    sFenceRegistry()->onSave(stream);
+}
+
+// static
+void EmulatedEglFenceSync::onLoad(android::base::Stream* stream) {
+    sFenceRegistry()->onLoad(stream);
+}
+
+// static
+EmulatedEglFenceSync* EmulatedEglFenceSync::getFromHandle(uint64_t handle) {
+    return sFenceRegistry()->getPtr(handle);
+}
+
+}  // namespace gfxstream
diff --git a/stream-servers/FenceSync.h b/stream-servers/gl/EmulatedEglFenceSync.h
similarity index 87%
rename from stream-servers/FenceSync.h
rename to stream-servers/gl/EmulatedEglFenceSync.h
index e301f7c..f53374a 100644
--- a/stream-servers/FenceSync.h
+++ b/stream-servers/gl/EmulatedEglFenceSync.h
@@ -16,16 +16,19 @@
 
 #pragma once
 
-#include "aemu/base/Compiler.h"
-#include "aemu/base/files/Stream.h"
-#include "aemu/base/synchronization/Lock.h"
+#include <atomic>
+#include <memory>
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 
-#include <atomic>
+#include "aemu/base/Compiler.h"
+#include "aemu/base/files/Stream.h"
+#include "aemu/base/synchronization/Lock.h"
 
-// The FenceSync class wraps actual EGLSyncKHR objects
+namespace gfxstream {
+
+// The EmulatedEglFenceSync class wraps actual EGLSyncKHR objects
 // and issues calls to eglCreateSyncKHR, eglClientWaitSyncKHR,
 // and eglDestroySyncKHR.
 //
@@ -53,16 +56,19 @@
 //     those on the guest, as that would require starting up another guest
 //     thread and OpenGL context (complete with host connection)
 //     to destroy it.
-class FenceSync {
-public:
+class EmulatedEglFenceSync {
+  public:
     // The constructor wraps eglCreateSyncKHR on the host OpenGL driver.
     // |hasNativeFence| specifies whether this sync object
     // is of EGL_SYNC_NATIVE_FENCE_ANDROID nature (2), and
     // |destroyWhenSignaled| specifies whether or not to destroy
     // the sync object when the native fence FD becomes signaled (3).
-    FenceSync(bool hasNativeFence,
-              bool destroyWhenSignaled);
-    ~FenceSync();
+    static std::unique_ptr<EmulatedEglFenceSync> create(
+        EGLSyncKHR sync,
+        bool hasNativeFence,
+        bool destroyWhenSignaled);
+
+    ~EmulatedEglFenceSync();
 
     // wait() wraps eglClientWaitSyncKHR. During such a wait, we need
     // to increment the reference count while the wait is active,
@@ -80,7 +86,7 @@
     }
 
     // When a native fence gets signaled, this function is called to update the
-    // timeline counter in the FenceSync internal timeline and delete old
+    // timeline counter in the EmulatedEglFenceSync internal timeline and delete old
     // fences.
     static void incrementTimelineAndDeleteOldFences();
 
@@ -118,12 +124,18 @@
     void addToRegistry();
     void removeFromRegistry();
 
-    static FenceSync* getFromHandle(uint64_t handle);
+    static EmulatedEglFenceSync* getFromHandle(uint64_t handle);
 
     // Functions for snapshotting all fence state at once
     static void onSave(android::base::Stream* stream);
     static void onLoad(android::base::Stream* stream);
-private:
+
+  private:
+    EmulatedEglFenceSync(EGLDisplay display,
+                         EGLSyncKHR sync,
+                         bool hasNativeFence,
+                         bool destroyWhenSignaled);
+
     bool mDestroyWhenSignaled;
     std::atomic<int> mCount {1};
 
@@ -135,5 +147,7 @@
     // careful control of when eglDestroySyncKHR is actually called.
     void destroy();
 
-    DISALLOW_COPY_AND_ASSIGN(FenceSync);
+    DISALLOW_COPY_AND_ASSIGN(EmulatedEglFenceSync);
 };
+
+}  // namespace gfxstream
diff --git a/stream-servers/gl/EmulationGl.cpp b/stream-servers/gl/EmulationGl.cpp
index 0c0f5ec..351dc52 100644
--- a/stream-servers/gl/EmulationGl.cpp
+++ b/stream-servers/gl/EmulationGl.cpp
@@ -591,6 +591,16 @@
     return EmulatedEglContext::onLoad(stream, mEglDisplay);
 }
 
+std::unique_ptr<EmulatedEglFenceSync> EmulationGl::createEmulatedEglFenceSync(
+        EGLenum type,
+        int destroyWhenSignaled) {
+    const bool hasNativeFence = type == EGL_SYNC_NATIVE_FENCE_ANDROID;
+    return EmulatedEglFenceSync::create(mEglDisplay,
+                                        hasNativeFence,
+                                        destroyWhenSignaled);
+
+}
+
 std::unique_ptr<EmulatedEglImage> EmulationGl::createEmulatedEglImage(
         EmulatedEglContext* context,
         EGLenum target,
diff --git a/stream-servers/gl/EmulationGl.h b/stream-servers/gl/EmulationGl.h
index 91ee41a..f3b750b 100644
--- a/stream-servers/gl/EmulationGl.h
+++ b/stream-servers/gl/EmulationGl.h
@@ -34,6 +34,7 @@
 #include "EmulatedEglContext.h"
 #include "EmulatedEglConfig.h"
 #include "EmulatedEglContext.h"
+#include "EmulatedEglFenceSync.h"
 #include "EmulatedEglImage.h"
 #include "EmulatedEglWindowSurface.h"
 #include "OpenGLESDispatch/GLESv2Dispatch.h"
@@ -98,6 +99,10 @@
     std::unique_ptr<EmulatedEglContext> loadEmulatedEglContext(
         android::base::Stream* stream);
 
+    std::unique_ptr<EmulatedEglFenceSync> createEmulatedEglFenceSync(
+        EGLenum type,
+        int destroyWhenSignaled);
+
     std::unique_ptr<EmulatedEglImage> createEmulatedEglImage(
         EmulatedEglContext* context,
         EGLenum target,
diff --git a/stream-servers/gl/glestranslator/GLES_V2/ANGLEShaderParser.cpp b/stream-servers/gl/glestranslator/GLES_V2/ANGLEShaderParser.cpp
index b2c7cb1..5a0cd78 100644
--- a/stream-servers/gl/glestranslator/GLES_V2/ANGLEShaderParser.cpp
+++ b/stream-servers/gl/glestranslator/GLES_V2/ANGLEShaderParser.cpp
@@ -17,7 +17,9 @@
 #include "ANGLEShaderParser.h"
 #include "ShaderTranslator.h"
 
+#include "aemu/base/SharedLibrary.h"
 #include "aemu/base/synchronization/Lock.h"
+#include "host-common/logging.h"
 
 #include <map>
 #include <string>
@@ -32,6 +34,80 @@
 bool kInitialized = false;
 bool sIsGles2Gles = false;
 
+class LazyLoadedSTDispatch {
+public:
+    LazyLoadedSTDispatch() {
+        memset(&mDispatch, 0, sizeof(STDispatch));
+
+#ifdef __APPLE__
+        const char kLibName[] = "libshadertranslator.dylib";
+#elif defined(_WIN32)
+        const char kLibName[] = "libshadertranslator.dll";
+#else
+        const char kLibName[] = "libshadertranslator.so";
+#endif
+        char error[256];
+        mLib = android::base::SharedLibrary::open(kLibName, error, sizeof(error));
+        if (!mLib) {
+            ERR("%s: Could not open shader translator library %s [%s]\n",
+                __func__, kLibName, error);
+            return;
+        }
+
+        mDispatch.initialize =
+            (STInitialize_t)mLib->findSymbol("STInitialize");
+        mDispatch.finalize =
+            (STFinalize_t)mLib->findSymbol("STFinalize");
+        mDispatch.generateResources =
+            (STGenerateResources_t)mLib->findSymbol("STGenerateResources");
+        mDispatch.compileAndResolve =
+            (STCompileAndResolve_t)mLib->findSymbol("STCompileAndResolve");
+        mDispatch.freeShaderResolveState =
+            (STFreeShaderResolveState_t)mLib->findSymbol("STFreeShaderResolveState");
+        mDispatch.copyVariable =
+            (STCopyVariable_t)mLib->findSymbol("STCopyVariable");
+        mDispatch.copyInterfaceBlock =
+            (STCopyInterfaceBlock_t)mLib->findSymbol("STCopyInterfaceBlock");
+        mDispatch.destroyVariable =
+            (STDestroyVariable_t)mLib->findSymbol("STDestroyVariable");
+        mDispatch.destroyInterfaceBlock =
+            (STDestroyInterfaceBlock_t)mLib->findSymbol("STDestroyInterfaceBlock");
+
+        mValid = dispatchValid();
+
+        if (!mValid) {
+            ERR("%s: error, shader translator dispatch not valid\n", __func__);
+        }
+    }
+
+    STDispatch* getDispatch() {
+        if (!mValid) return nullptr;
+        return &mDispatch;
+    }
+
+private:
+    bool dispatchValid() {
+        return (nullptr != mDispatch.initialize) &&
+               (nullptr != mDispatch.finalize) &&
+               (nullptr != mDispatch.generateResources) &&
+               (nullptr != mDispatch.compileAndResolve) &&
+               (nullptr != mDispatch.copyVariable) &&
+               (nullptr != mDispatch.copyInterfaceBlock) &&
+               (nullptr != mDispatch.destroyVariable) &&
+               (nullptr != mDispatch.destroyInterfaceBlock);
+    }
+
+    android::base::SharedLibrary* mLib = nullptr;
+    bool mValid = false;
+    STDispatch mDispatch;
+};
+
+
+static STDispatch* getSTDispatch() {
+    static LazyLoadedSTDispatch* dispatch = new LazyLoadedSTDispatch;
+    return dispatch->getDispatch();
+}
+
 ShaderLinkInfo::ShaderLinkInfo() = default;
 ShaderLinkInfo::ShaderLinkInfo(const ShaderLinkInfo& other) {
     clear();
@@ -70,11 +146,12 @@
     esslVersion = other.esslVersion;
 
     if (!sIsGles2Gles) {
-        for (const auto& var: other.uniforms) { uniforms.push_back(STCopyVariable(&var)); }
-        for (const auto& var: other.varyings) { varyings.push_back(STCopyVariable(&var)); }
-        for (const auto& var: other.attributes) { attributes.push_back(STCopyVariable(&var)); }
-        for (const auto& var: other.outputVars) { outputVars.push_back(STCopyVariable(&var)); }
-        for (const auto& var: other.interfaceBlocks) { interfaceBlocks.push_back(STCopyInterfaceBlock(&var)); }
+        auto dispatch = getSTDispatch();
+        for (const auto& var: other.uniforms) { uniforms.push_back(dispatch->copyVariable(&var)); }
+        for (const auto& var: other.varyings) { varyings.push_back(dispatch->copyVariable(&var)); }
+        for (const auto& var: other.attributes) { attributes.push_back(dispatch->copyVariable(&var)); }
+        for (const auto& var: other.outputVars) { outputVars.push_back(dispatch->copyVariable(&var)); }
+        for (const auto& var: other.interfaceBlocks) { interfaceBlocks.push_back(dispatch->copyInterfaceBlock(&var)); }
     }
 
     nameMap = other.nameMap;
@@ -84,11 +161,12 @@
 void ShaderLinkInfo::clear() {
 
     if (!sIsGles2Gles) {
-        for (auto& var: uniforms) { STDestroyVariable(&var); }
-        for (auto& var: varyings) { STDestroyVariable(&var); }
-        for (auto& var: attributes) { STDestroyVariable(&var); }
-        for (auto& var: outputVars) { STDestroyVariable(&var); }
-        for (auto& var: interfaceBlocks) { STDestroyInterfaceBlock(&var); }
+        auto dispatch = getSTDispatch();
+        for (auto& var: uniforms) { dispatch->destroyVariable(&var); }
+        for (auto& var: varyings) { dispatch->destroyVariable(&var); }
+        for (auto& var: attributes) { dispatch->destroyVariable(&var); }
+        for (auto& var: outputVars) { dispatch->destroyVariable(&var); }
+        for (auto& var: interfaceBlocks) { dispatch->destroyInterfaceBlock(&var); }
     }
 
     uniforms.clear();
@@ -166,7 +244,7 @@
     BuiltinResourcesEditCallback callback) {
 
     if (!sIsGles2Gles) {
-        STGenerateResources(&kResources);
+        getSTDispatch()->generateResources(&kResources);
     }
 
     callback(kResources);
@@ -179,7 +257,7 @@
     sIsGles2Gles = isGles2Gles;
 
     if (!sIsGles2Gles) {
-        STInitialize();
+        getSTDispatch()->initialize();
     }
 
     initializeResources(editCallback);
@@ -217,19 +295,23 @@
         linkInfo->nameMapReverse[elt.second] = elt.first;
     }
 
+    auto st = getSTDispatch();
+    auto stCopyVariable = st->copyVariable;
+    auto stCopyInterfaceBlock = st->copyInterfaceBlock;
+
     linkInfo->uniforms = convertArrayToVecWithCopy(
         compileResult->uniformsCount,
         compileResult->pUniforms,
-        STCopyVariable);
+        stCopyVariable);
 
     std::vector<ST_ShaderVariable> inputVaryings =
         convertArrayToVecWithCopy(
             compileResult->inputVaryingsCount, compileResult->pInputVaryings,
-            STCopyVariable);
+            stCopyVariable);
     std::vector<ST_ShaderVariable> outputVaryings =
         convertArrayToVecWithCopy(
             compileResult->outputVaryingsCount, compileResult->pOutputVaryings,
-            STCopyVariable);
+            stCopyVariable);
 
     linkInfo->varyings.clear();
     linkInfo->varyings.insert(
@@ -245,19 +327,19 @@
         convertArrayToVecWithCopy(
             compileResult->allAttributesCount,
             compileResult->pAllAttributes,
-            STCopyVariable);
+            stCopyVariable);
 
     linkInfo->outputVars =
         convertArrayToVecWithCopy(
             compileResult->activeOutputVariablesCount,
             compileResult->pActiveOutputVariables,
-            STCopyVariable);
+            stCopyVariable);
 
     linkInfo->interfaceBlocks =
         convertArrayToVecWithCopy(
             compileResult->uniformBlocksCount,
             compileResult->pUniformBlocks,
-            STCopyInterfaceBlock);
+            stCopyInterfaceBlock);
     // todo: split to uniform and ssbo
 }
 
@@ -338,7 +420,8 @@
 
     ST_ShaderCompileResult* res = nullptr;
 
-    STCompileAndResolve(&ci, &res);
+    auto st = getSTDispatch();
+    st->compileAndResolve(&ci, &res);
 
     sCompilerMap()->emplace(key, res->outputHandle);
     *outInfolog = std::string(res->infoLog);
@@ -348,7 +431,7 @@
 
     bool ret = res->compileStatus == 1;
 
-    STFreeShaderResolveState(res);
+    st->freeShaderResolveState(res);
     return ret;
 }
 
diff --git a/stream-servers/gl/glestranslator/GLES_V2/ANGLEShaderParser.h b/stream-servers/gl/glestranslator/GLES_V2/ANGLEShaderParser.h
index 187764f..9d9f742 100644
--- a/stream-servers/gl/glestranslator/GLES_V2/ANGLEShaderParser.h
+++ b/stream-servers/gl/glestranslator/GLES_V2/ANGLEShaderParser.h
@@ -30,8 +30,6 @@
 // Convenient to query those
 extern ST_BuiltInResources kResources;
 
-STDispatch* getSTDispatch();
-
 // For performing link-time validation of shader programs.
 struct ShaderLinkInfo {
     int esslVersion;
diff --git a/stream-servers/gl/glestranslator/GLES_V2/CMakeLists.txt b/stream-servers/gl/glestranslator/GLES_V2/CMakeLists.txt
index 550ed00..5aee5c5 100644
--- a/stream-servers/gl/glestranslator/GLES_V2/CMakeLists.txt
+++ b/stream-servers/gl/glestranslator/GLES_V2/CMakeLists.txt
@@ -19,9 +19,3 @@
     apigen-codec-common
     aemu-base.headers
     aemu-host-common.headers)
-
-if(USE_ANGLE_SHADER_PARSER)
-    target_link_libraries(
-       GLES_V2_translator_static PRIVATE
-       angle_shader_translator)
-endif ()
diff --git a/stream-servers/tests/SampleApplication.cpp b/stream-servers/tests/SampleApplication.cpp
index 0067d03..cbb1e74 100644
--- a/stream-servers/tests/SampleApplication.cpp
+++ b/stream-servers/tests/SampleApplication.cpp
@@ -35,6 +35,7 @@
 using android::base::Lock;
 using android::base::MessageChannel;
 using android::base::TestSystem;
+using gfxstream::EmulatedEglFenceSync;
 using gfxstream::GLESApi;
 using gfxstream::GLESApi_3_0;
 using gfxstream::GLESApi_CM;
@@ -166,13 +167,14 @@
 class ColorBufferQueue { // Note: we could have called this BufferQueue but there is another
                          // class of name BufferQueue that does something totally different
 
-public:
+  public:
     static constexpr int kCapacity = 3;
     class Item {
-    public:
-        Item(unsigned int cb = 0, FenceSync* s = nullptr) : colorBuffer(cb), sync(s) { }
+      public:
+        Item(unsigned int cb = 0, EmulatedEglFenceSync* s = nullptr)
+            : colorBuffer(cb), sync(s) { }
         unsigned int colorBuffer = 0;
-        FenceSync* sync = nullptr;
+        EmulatedEglFenceSync* sync = nullptr;
     };
 
     ColorBufferQueue() = default;
@@ -185,7 +187,7 @@
         mQueue.receive(outItem);
     }
 
-private:
+  private:
     MessageChannel<Item, kCapacity> mQueue;
 };
 
@@ -316,11 +318,10 @@
     }
 }
 
-FenceSync* SampleApplication::getFenceSync() {
-    auto gl = getGlDispatch();
-    FenceSync* sync = new FenceSync(false, false);
-    gl->glFlush();
-    return sync;
+EmulatedEglFenceSync* SampleApplication::getFenceSync() {
+    uint64_t sync;
+    mFb->createEmulatedEglFenceSync(EGL_SYNC_FENCE_KHR, false, &sync);
+    return EmulatedEglFenceSync::getFromHandle(sync);
 }
 
 void SampleApplication::drawWorkerWithCompose(ColorBufferQueue& app2sfQueue,
diff --git a/stream-servers/tests/SampleApplication.h b/stream-servers/tests/SampleApplication.h
index b7c8e81..73cb716 100644
--- a/stream-servers/tests/SampleApplication.h
+++ b/stream-servers/tests/SampleApplication.h
@@ -18,11 +18,11 @@
 #include <functional>
 #include <memory>
 
-#include "FenceSync.h"
 #include "Hwc2.h"
 #include "OpenGLESDispatch/GLESv2Dispatch.h"
 #include "aemu/base/Compiler.h"
 #include "gl/EmulatedEglContext.h"
+#include "gl/EmulatedEglFenceSync.h"
 
 class FrameBuffer;
 class OSWindow;
@@ -84,7 +84,7 @@
     void drawWorkerWithCompose(ColorBufferQueue& app2sfQueue, ColorBufferQueue& sf2appQueue);
     void drawWorker(ColorBufferQueue& app2sfQueue, ColorBufferQueue& sf2appQueue,
                 ColorBufferQueue& sf2hwcQueue, ColorBufferQueue& hwc2sfQueue);
-    FenceSync* getFenceSync();
+    gfxstream::EmulatedEglFenceSync* getFenceSync();
 
 protected:
     virtual void initialize() = 0;
diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt
index f4fb8e0..c0824fd 100644
--- a/third-party/CMakeLists.txt
+++ b/third-party/CMakeLists.txt
@@ -209,6 +209,3 @@
 if(NOT TARGET flatbuffers)
     message(FATAL_ERROR "The dependency flatbuffers not found.")
 endif()
-if(USE_ANGLE_SHADER_PARSER AND NOT TARGET angle_shader_translator)
-    message(FATAL_ERROR "The dependency angle_shader_translator not found.")
-endif()
\ No newline at end of file