Add EGL GGP extensions.

This CL adds two new extensions:

 * EGL_ANGLE_ggp_stream_descriptor:
    Introduces a new attribute to CreateWindowSurface. Allows the app
    to pass in a stream descriptor to VkCreateSurfaceKHR.
    Mirrors VK_GGP_stream_descriptor_surface.

 * EGL_ANGLE_swap_with_frame_token:
    Introduces a new function 'eglSwapBuffersWithFrameTokenANGLE'. This
    allows the app to pass a GGP frame token down to vkQueuePresentKHR.
    Mirrors VK_GGP_frame_token.

Bug: angleproject:4078
Change-Id: I4313ac4c264e68999905049f661bc64b44f72fab
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1897315
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Cody Northrop <cnorthrop@google.com>
diff --git a/extensions/EGL_ANGLE_ggp_stream_descriptor.txt b/extensions/EGL_ANGLE_ggp_stream_descriptor.txt
new file mode 100644
index 0000000..843d9b2
--- /dev/null
+++ b/extensions/EGL_ANGLE_ggp_stream_descriptor.txt
@@ -0,0 +1,73 @@
+Name
+
+    ANGLE_ggp_stream_descriptor
+
+Name Strings
+
+    EGL_ANGLE_ggp_stream_descriptor
+
+Contributors
+
+    Jamie Madill
+
+Contacts
+
+    Jamie Madill, Google Inc. (jmadill 'at' google.com)
+
+Status
+
+    Draft
+
+Version
+
+    Version 1, November 3, 2019
+
+Number
+
+    EGL Extension #??
+
+Dependencies
+
+    This extension is written against the wording of the EGL 1.5
+    Specification.
+
+Overview
+
+    This extension allows initializing an EGL Window surface backed by a
+    VkSurfaceKHR with a Google Games Platform GgpStreamDescriptor.
+
+    It is based on the Vulkan extension VK_GGP_stream_descriptor_surface.
+
+New Types
+
+    None
+
+New Procedures and Functions
+
+    None
+
+New Tokens
+
+    Accepted as an attribute name in the <attrib_list> argument to
+    eglCreateSurfaceKHR:
+
+        EGL_GGP_STREAM_DESCRIPTOR_ANGLE  0x348B
+
+Additions to the EGL 1.5 Specification
+
+    Add the following to section 3.5.1 "Creating On-Screen Rendering Surfaces":
+
+    EGL_GGP_STREAM_DESCRIPTOR_ANGLE indicates a GgpStreamDescriptor referring
+    to the GGP stream descriptor to associate with the surface. If
+    EGL_GGP_STREAM_DESCRIPTOR_ANGLE is not specified a default stream
+    descriptor will be used.
+
+Issues
+
+    None yet.
+
+Revision History
+
+    Rev.    Date         Author     Changes
+    ----  -------------  ---------  ----------------------------------------
+      1   Nov 3, 2019    jmadill    Initial version
diff --git a/extensions/EGL_ANGLE_swap_with_frame_token.txt b/extensions/EGL_ANGLE_swap_with_frame_token.txt
new file mode 100644
index 0000000..f58b7c7
--- /dev/null
+++ b/extensions/EGL_ANGLE_swap_with_frame_token.txt
@@ -0,0 +1,83 @@
+Name
+
+    ANGLE_swap_with_frame_token
+
+Name Strings
+
+    EGL_ANGLE_swap_with_frame_token
+
+Contributors
+
+    Jamie Madill
+
+Contacts
+
+    Jamie Madill, Google Inc. (jmadill 'at' google.com)
+
+Status
+
+    Draft
+
+Version
+
+    Version 1, November 3, 2019
+
+Number
+
+    EGL Extension #??
+
+Dependencies
+
+    This extension is written against the wording of the EGL 1.5
+    Specification.
+
+Overview
+
+    This extension allows an application that uses a Google Games
+    Platform surface to associate a Google Games Platform frame token
+    with an eglSwapBuffers operation.
+
+    It is based on the Vulkan extension VK_GGP_frame_token.
+
+New Types
+
+    This is a 64-bit unsigned type that represents a GGP frame token.
+
+    typedef khronos_uint64_t EGLFrameTokenANGLE;
+
+New Procedures and Functions
+
+    EGLBoolean eglSwapBuffersWithFrameTokenANGLE(
+        EGLDisplay dpy,
+        EGLSurface surface,
+        EGLFrameTokenANGLE frametoken);
+
+New Tokens
+
+    None
+
+Additions to the EGL 1.5 Specification
+
+    Add the following to section 3.10.1 "Posting to a Window":
+
+    A Google Games Platform frame token can be specified when posting a color
+    buffer to a window by calling
+
+        EGLBoolean eglSwapBuffersWithFrameTokenANGLE(
+            EGLDisplay dpy,
+            EGLSurface surface,
+            EGLFrameTokenANGLE frametoken);
+
+    The behaviour of eglSwapBuffersWithFrameTokenANGLE is identical to that
+    of eglSwapBuffers except that the behaviour is undefined when <frametoken>
+    is not a valid GgpFrameToken.
+
+Issues
+
+    None yet.
+
+Revision History
+
+    Rev.    Date         Author     Changes
+    ----  -------------  ---------  ----------------------------------------
+      1   Nov 3, 2019    jmadill    Initial version
diff --git a/gni/angle.gni b/gni/angle.gni
index e5452b3..5659633 100644
--- a/gni/angle.gni
+++ b/gni/angle.gni
@@ -4,6 +4,10 @@
 
 import("//build_overrides/angle.gni")
 
+declare_args() {
+  is_ggp = false
+}
+
 if (angle_has_build) {
   import("//build/config/dcheck_always_on.gni")
   import("//build/config/sanitizers/sanitizers.gni")
diff --git a/include/EGL/eglext_angle.h b/include/EGL/eglext_angle.h
index ab5cb8d..20d3b50 100644
--- a/include/EGL/eglext_angle.h
+++ b/include/EGL/eglext_angle.h
@@ -259,6 +259,20 @@
 #define EGL_CGL_PIXEL_FORMAT_ANGLE 0x3486
 #endif
 
+#ifndef EGL_ANGLE_ggp_stream_descriptor
+#define EGL_ANGLE_ggp_stream_descriptor 1
+#define EGL_GGP_STREAM_DESCRIPTOR_ANGLE 0x348B
+#endif /* EGL_ANGLE_ggp_stream_descriptor */
+
+#ifndef EGL_ANGLE_swap_with_frame_token
+#define EGL_ANGLE_swap_with_frame_token 1
+typedef khronos_uint64_t EGLFrameTokenANGLE;
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHFRAMETOKENANGLEPROC)(EGLDisplay dpy, EGLSurface surface, EGLFrameTokenANGLE frametoken);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLBoolean EGLAPIENTRY eglSwapBuffersWithFrameTokenANGLE(EGLDisplay dpy, EGLSurface surface, EGLFrameTokenANGLE frametoken);
+#endif
+#endif /* EGL_ANGLE_swap_with_frame_token */
+
 // clang-format on
 
 #endif  // INCLUDE_EGL_EGLEXT_ANGLE_
diff --git a/include/EGL/eglplatform.h b/include/EGL/eglplatform.h
index bfd9bd6..d1cae17 100644
--- a/include/EGL/eglplatform.h
+++ b/include/EGL/eglplatform.h
@@ -116,6 +116,12 @@
 typedef intptr_t EGLNativePixmapType;
 typedef intptr_t EGLNativeWindowType;
 
+#elif defined(__ggp__)
+
+typedef intptr_t EGLNativeDisplayType;
+typedef intptr_t EGLNativePixmapType;
+typedef intptr_t EGLNativeWindowType;
+
 #elif defined(__unix__) || defined(USE_X11)
 
 /* X11 (tentative)  */
diff --git a/scripts/code_generation_hashes/GL_EGL_WGL_loader.json b/scripts/code_generation_hashes/GL_EGL_WGL_loader.json
index d0c3080..b810ea0 100644
--- a/scripts/code_generation_hashes/GL_EGL_WGL_loader.json
+++ b/scripts/code_generation_hashes/GL_EGL_WGL_loader.json
@@ -2,21 +2,21 @@
   "scripts/egl.xml":
     "842e24514c4cfe09fba703c17a0fd292",
   "scripts/egl_angle_ext.xml":
-    "fc2e249239fb1365f6d145cdf1a3cfcf",
+    "24d4348e6c064b6837f46c955cc219a8",
   "scripts/generate_loader.py":
     "48c60c668bec42a80378179aae2acc61",
   "scripts/registry_xml.py":
-    "fad2f8068a585ee2e6a66dd604fe93e1",
+    "f5fe888247ca4da9df81266a0123f7de",
   "scripts/wgl.xml":
     "aa96419c582af2f6673430e2847693f4",
   "src/libEGL/egl_loader_autogen.cpp":
-    "01d20878ff5644bb9ee9e22ec95c3587",
+    "83b3307f377e3ead495cdb9eb53460ab",
   "src/libEGL/egl_loader_autogen.h":
-    "a9d4b21e3a74565a6710c76c4f3bcbdc",
+    "5504e375372f2f116fc8c192753a923f",
   "util/egl_loader_autogen.cpp":
-    "b9a444da4142a12a9fe6b7a9d33a4ea8",
+    "22c6cdfa133c449e3b046075254841c5",
   "util/egl_loader_autogen.h":
-    "bc2c62ff42604977ac2240591ee8ba6a",
+    "6349dd7847bd72466919816befb6841d",
   "util/gles_loader_autogen.cpp":
     "8f5e1cd93093e54d3287609680cae33c",
   "util/gles_loader_autogen.h":
diff --git a/scripts/code_generation_hashes/GL_EGL_entry_points.json b/scripts/code_generation_hashes/GL_EGL_entry_points.json
index dc9b12b..ba8b0e8 100644
--- a/scripts/code_generation_hashes/GL_EGL_entry_points.json
+++ b/scripts/code_generation_hashes/GL_EGL_entry_points.json
@@ -2,7 +2,7 @@
   "scripts/egl.xml":
     "842e24514c4cfe09fba703c17a0fd292",
   "scripts/egl_angle_ext.xml":
-    "fc2e249239fb1365f6d145cdf1a3cfcf",
+    "24d4348e6c064b6837f46c955cc219a8",
   "scripts/entry_point_packed_gl_enums.json":
     "3b72a1d43df45cf53784b2a0002b93e5",
   "scripts/generate_entry_points.py":
@@ -12,7 +12,7 @@
   "scripts/gl_angle_ext.xml":
     "d6907cd84d95ac0b32a164194eadcf53",
   "scripts/registry_xml.py":
-    "fad2f8068a585ee2e6a66dd604fe93e1",
+    "f5fe888247ca4da9df81266a0123f7de",
   "scripts/wgl.xml":
     "aa96419c582af2f6673430e2847693f4",
   "src/libANGLE/Context_gl_1_0_autogen.h":
@@ -256,9 +256,9 @@
   "src/libGLESv2/libGLESv2_autogen.cpp":
     "7b0682a27fa050660b54ae73063f3b2d",
   "src/libGLESv2/libGLESv2_autogen.def":
-    "567d8736cd2b27581fffe17fa9e3a60f",
+    "cfa8370ea276c98b9bb3752bf75cb5d8",
   "src/libGLESv2/libGLESv2_no_capture_autogen.def":
-    "436bb9ba6826889ce7b61daf4c3faa03",
+    "a932f323fa7cfc13b4099f1741b5dc65",
   "src/libGLESv2/libGLESv2_with_capture_autogen.def":
-    "6d440d92cb9aedb3fee6b18610d86742"
+    "bd52aea6901faff81f0b0cb5f706528b"
 }
\ No newline at end of file
diff --git a/scripts/code_generation_hashes/GLenum_value_to_string_map.json b/scripts/code_generation_hashes/GLenum_value_to_string_map.json
index 6bdcc98..640edd5 100644
--- a/scripts/code_generation_hashes/GLenum_value_to_string_map.json
+++ b/scripts/code_generation_hashes/GLenum_value_to_string_map.json
@@ -6,7 +6,7 @@
   "scripts/gl_angle_ext.xml":
     "d6907cd84d95ac0b32a164194eadcf53",
   "scripts/registry_xml.py":
-    "fad2f8068a585ee2e6a66dd604fe93e1",
+    "f5fe888247ca4da9df81266a0123f7de",
   "src/libANGLE/gl_enum_utils_autogen.cpp":
     "3178466fb9ef26a3349fe59a76295dc3",
   "src/libANGLE/gl_enum_utils_autogen.h":
diff --git a/scripts/code_generation_hashes/proc_table.json b/scripts/code_generation_hashes/proc_table.json
index b0e0ee0..d3a45317 100644
--- a/scripts/code_generation_hashes/proc_table.json
+++ b/scripts/code_generation_hashes/proc_table.json
@@ -2,7 +2,7 @@
   "scripts/egl.xml":
     "842e24514c4cfe09fba703c17a0fd292",
   "scripts/egl_angle_ext.xml":
-    "fc2e249239fb1365f6d145cdf1a3cfcf",
+    "24d4348e6c064b6837f46c955cc219a8",
   "scripts/gen_proc_table.py":
     "24dbcc78fd3f000f58ca98237ccc0da4",
   "scripts/gl.xml":
@@ -10,11 +10,11 @@
   "scripts/gl_angle_ext.xml":
     "d6907cd84d95ac0b32a164194eadcf53",
   "scripts/registry_xml.py":
-    "fad2f8068a585ee2e6a66dd604fe93e1",
+    "f5fe888247ca4da9df81266a0123f7de",
   "scripts/wgl.xml":
     "aa96419c582af2f6673430e2847693f4",
   "src/libGL/proc_table_wgl_autogen.cpp":
     "6844abf06aa6fb7a26878acb0d69df07",
   "src/libGLESv2/proc_table_egl_autogen.cpp":
-    "e03b5d92d618b83b37036c5af16fc0cd"
+    "24f519e153ade8e0fdc3bff3ae05954d"
 }
\ No newline at end of file
diff --git a/scripts/egl_angle_ext.xml b/scripts/egl_angle_ext.xml
index 8ab84fb..877d4d0 100644
--- a/scripts/egl_angle_ext.xml
+++ b/scripts/egl_angle_ext.xml
@@ -81,6 +81,12 @@
             <param><ptype>EGLint</ptype> <name>attribute</name></param>
             <param><ptype>EGLAttrib *</ptype> <name>value</name></param>
         </command>
+        <command>
+            <proto><pytpe>EGLBoolean</pytpe> <name>eglSwapBuffersWithFrameTokenANGLE</name></proto>
+            <param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
+            <param><ptype>EGLSurface</ptype> <name>surface</name></param>
+            <param><ptype>EGLFrameTokenANGLE</ptype> <name>frametoken</name></param>
+        </command>
     </commands>
     <!-- SECTION: ANGLE extension interface definitions -->
     <extensions>
@@ -115,5 +121,10 @@
                 <command name="eglProgramCacheResizeANGLE"/>
             </require>
         </extension>
+        <extension name="EGL_ANGLE_swap_with_frame_token" supported="egl">
+            <require>
+                <command name="eglSwapBuffersWithFrameTokenANGLE"/>
+            </require>
+        </extension>
     </extensions>
 </registry>
diff --git a/scripts/export_targets.py b/scripts/export_targets.py
index 47eb67c..25c4817 100755
--- a/scripts/export_targets.py
+++ b/scripts/export_targets.py
@@ -190,6 +190,7 @@
     b'libANGLE/renderer/null/DisplayNULL.h',
     b'libANGLE/renderer/vulkan/android/DisplayVkAndroid.h',
     b'libANGLE/renderer/vulkan/fuchsia/DisplayVkFuchsia.h',
+    b'libANGLE/renderer/vulkan/ggp/DisplayVkGGP.h',
     b'libANGLE/renderer/vulkan/win32/DisplayVkWin32.h',
     b'libANGLE/renderer/vulkan/xcb/DisplayVkXcb.h',
     b'kernel/image.h',
diff --git a/scripts/registry_xml.py b/scripts/registry_xml.py
index f79fae2..f093a69 100644
--- a/scripts/registry_xml.py
+++ b/scripts/registry_xml.py
@@ -102,10 +102,12 @@
     "EGL_ANGLE_device_creation",
     "EGL_ANGLE_device_d3d",
     "EGL_ANGLE_feature_control",
+    "EGL_ANGLE_ggp_stream_descriptor",
     "EGL_ANGLE_program_cache_control",
     "EGL_ANGLE_query_surface_pointer",
     "EGL_ANGLE_stream_producer_d3d_texture",
     "EGL_ANGLE_surface_d3d_texture_2d_share_handle",
+    "EGL_ANGLE_swap_with_frame_token",
     "EGL_ANGLE_window_fixed_size",
     "EGL_CHROMIUM_get_sync_values",
     "EGL_EXT_create_context_robustness",
diff --git a/src/common/platform.h b/src/common/platform.h
index 9603be4..c981f9c 100644
--- a/src/common/platform.h
+++ b/src/common/platform.h
@@ -20,6 +20,9 @@
 #elif defined(ANDROID)
 #    define ANGLE_PLATFORM_ANDROID 1
 #    define ANGLE_PLATFORM_POSIX 1
+#elif defined(__ggp__)
+#    define ANGLE_PLATFORM_GGP 1
+#    define ANGLE_PLATFORM_POSIX 1
 #elif defined(__linux__) || defined(EMSCRIPTEN)
 #    define ANGLE_PLATFORM_LINUX 1
 #    define ANGLE_PLATFORM_POSIX 1
diff --git a/src/libANGLE/Caps.h b/src/libANGLE/Caps.h
index 18ca5c6..e33e8c3 100644
--- a/src/libANGLE/Caps.h
+++ b/src/libANGLE/Caps.h
@@ -944,6 +944,12 @@
 
     // EGL_KHR_no_config_context
     bool noConfigContext = false;
+
+    // EGL_ANGLE_ggp_stream_descriptor
+    bool ggpStreamDescriptor = false;
+
+    // EGL_ANGLE_swap_with_frame_token
+    bool swapWithFrameToken = false;
 };
 
 struct DeviceExtensions
diff --git a/src/libANGLE/Display.cpp b/src/libANGLE/Display.cpp
index 1e91006..cad46a2 100644
--- a/src/libANGLE/Display.cpp
+++ b/src/libANGLE/Display.cpp
@@ -76,6 +76,8 @@
 #        include "libANGLE/renderer/vulkan/android/DisplayVkAndroid.h"
 #    elif defined(ANGLE_PLATFORM_FUCHSIA)
 #        include "libANGLE/renderer/vulkan/fuchsia/DisplayVkFuchsia.h"
+#    elif defined(ANGLE_PLATFORM_GGP)
+#        include "libANGLE/renderer/vulkan/ggp/DisplayVkGGP.h"
 #    else
 #        error Unsupported Vulkan platform.
 #    endif
@@ -294,6 +296,8 @@
             impl = new rx::DisplayVkAndroid(state);
 #    elif defined(ANGLE_PLATFORM_FUCHSIA)
             impl = new rx::DisplayVkFuchsia(state);
+#    elif defined(ANGLE_PLATFORM_GGP)
+            impl = new rx::DisplayVkGGP(state);
 #    else
 #        error Unsupported Vulkan platform.
 #    endif
diff --git a/src/libANGLE/Surface.cpp b/src/libANGLE/Surface.cpp
index ad13509..aef38aa 100644
--- a/src/libANGLE/Surface.cpp
+++ b/src/libANGLE/Surface.cpp
@@ -251,6 +251,15 @@
     return NoError();
 }
 
+Error Surface::swapWithFrameToken(const gl::Context *context, EGLFrameTokenANGLE frameToken)
+{
+    context->getState().getOverlay()->onSwap();
+
+    ANGLE_TRY(mImplementation->swapWithFrameToken(context, frameToken));
+    postSwap(context);
+    return NoError();
+}
+
 Error Surface::postSubBuffer(const gl::Context *context,
                              EGLint x,
                              EGLint y,
diff --git a/src/libANGLE/Surface.h b/src/libANGLE/Surface.h
index 7ae480e..8901f8a 100644
--- a/src/libANGLE/Surface.h
+++ b/src/libANGLE/Surface.h
@@ -72,6 +72,7 @@
     Error unMakeCurrent(const gl::Context *context);
     Error swap(const gl::Context *context);
     Error swapWithDamage(const gl::Context *context, EGLint *rects, EGLint n_rects);
+    Error swapWithFrameToken(const gl::Context *context, EGLFrameTokenANGLE frameToken);
     Error postSubBuffer(const gl::Context *context,
                         EGLint x,
                         EGLint y,
diff --git a/src/libANGLE/renderer/SurfaceImpl.cpp b/src/libANGLE/renderer/SurfaceImpl.cpp
index e9932c5..b5b8520 100644
--- a/src/libANGLE/renderer/SurfaceImpl.cpp
+++ b/src/libANGLE/renderer/SurfaceImpl.cpp
@@ -93,4 +93,10 @@
     return egl::EglBadDisplay();
 }
 
+egl::Error SurfaceImpl::swapWithFrameToken(const gl::Context *context,
+                                           EGLFrameTokenANGLE frameToken)
+{
+    UNREACHABLE();
+    return egl::EglBadDisplay();
+}
 }  // namespace rx
diff --git a/src/libANGLE/renderer/SurfaceImpl.h b/src/libANGLE/renderer/SurfaceImpl.h
index 1077393..6588a98 100644
--- a/src/libANGLE/renderer/SurfaceImpl.h
+++ b/src/libANGLE/renderer/SurfaceImpl.h
@@ -57,6 +57,8 @@
     virtual egl::Error unMakeCurrent(const gl::Context *context);
     virtual egl::Error swap(const gl::Context *context) = 0;
     virtual egl::Error swapWithDamage(const gl::Context *context, EGLint *rects, EGLint n_rects);
+    virtual egl::Error swapWithFrameToken(const gl::Context *context,
+                                          EGLFrameTokenANGLE frameToken);
     virtual egl::Error postSubBuffer(const gl::Context *context,
                                      EGLint x,
                                      EGLint y,
diff --git a/src/libANGLE/renderer/vulkan/BUILD.gn b/src/libANGLE/renderer/vulkan/BUILD.gn
index f8de33f..9f105c8 100644
--- a/src/libANGLE/renderer/vulkan/BUILD.gn
+++ b/src/libANGLE/renderer/vulkan/BUILD.gn
@@ -137,6 +137,15 @@
   ]
 }
 
+if (is_ggp) {
+  _vulkan_backend_sources += [
+    "ggp/DisplayVkGGP.cpp",
+    "ggp/DisplayVkGGP.h",
+    "ggp/WindowSurfaceVkGGP.cpp",
+    "ggp/WindowSurfaceVkGGP.h",
+  ]
+}
+
 config("vulkan_config") {
   _sws_icd = "./libvk_swiftshader_icd.json"
   if (is_win) {
diff --git a/src/libANGLE/renderer/vulkan/DisplayVk.cpp b/src/libANGLE/renderer/vulkan/DisplayVk.cpp
index ed98324..76cf756 100644
--- a/src/libANGLE/renderer/vulkan/DisplayVk.cpp
+++ b/src/libANGLE/renderer/vulkan/DisplayVk.cpp
@@ -192,6 +192,11 @@
     outExtensions->surfacelessContext = true;
 
     outExtensions->noConfigContext = true;
+
+#if defined(ANGLE_PLATFORM_GGP)
+    outExtensions->ggpStreamDescriptor = true;
+    outExtensions->swapWithFrameToken  = true;
+#endif  // defined(ANGLE_PLATFORM_GGP)
 }
 
 void DisplayVk::generateCaps(egl::Caps *outCaps) const
diff --git a/src/libANGLE/renderer/vulkan/RendererVk.cpp b/src/libANGLE/renderer/vulkan/RendererVk.cpp
index 9121a7f..e2fe035 100644
--- a/src/libANGLE/renderer/vulkan/RendererVk.cpp
+++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp
@@ -364,7 +364,8 @@
 // Changing CWD and setting environment variables makes no sense on Android,
 // since this code is a part of Java application there.
 // Android Vulkan loader doesn't need this either.
-#if !defined(ANGLE_PLATFORM_ANDROID) && !defined(ANGLE_PLATFORM_FUCHSIA)
+#if !defined(ANGLE_PLATFORM_ANDROID) && !defined(ANGLE_PLATFORM_FUCHSIA) && \
+    !defined(ANGLE_PLATFORM_GGP)
         if (icd == vk::ICD::Mock)
         {
             if (!setICDEnvironment(ANGLE_VK_MOCK_ICD_JSON))
diff --git a/src/libANGLE/renderer/vulkan/SurfaceVk.cpp b/src/libANGLE/renderer/vulkan/SurfaceVk.cpp
index 2496126..5e26217 100644
--- a/src/libANGLE/renderer/vulkan/SurfaceVk.cpp
+++ b/src/libANGLE/renderer/vulkan/SurfaceVk.cpp
@@ -391,7 +391,6 @@
     : SurfaceVk(surfaceState),
       mNativeWindowType(window),
       mSurface(VK_NULL_HANDLE),
-      mInstance(VK_NULL_HANDLE),
       mSwapchain(VK_NULL_HANDLE),
       mSwapchainPresentMode(VK_PRESENT_MODE_FIFO_KHR),
       mDesiredSwapchainPresentMode(VK_PRESENT_MODE_FIFO_KHR),
@@ -954,20 +953,21 @@
                                            EGLint n_rects)
 {
     DisplayVk *displayVk = vk::GetImpl(context->getDisplay());
-    angle::Result result = swapImpl(context, rects, n_rects);
+    angle::Result result = swapImpl(context, rects, n_rects, nullptr);
     return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
 }
 
 egl::Error WindowSurfaceVk::swap(const gl::Context *context)
 {
     DisplayVk *displayVk = vk::GetImpl(context->getDisplay());
-    angle::Result result = swapImpl(context, nullptr, 0);
+    angle::Result result = swapImpl(context, nullptr, 0, nullptr);
     return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
 }
 
 angle::Result WindowSurfaceVk::present(ContextVk *contextVk,
                                        EGLint *rects,
                                        EGLint n_rects,
+                                       const void *pNextChain,
                                        bool *presentOutOfDate)
 {
     ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::present");
@@ -1045,6 +1045,7 @@
 
     VkPresentInfoKHR presentInfo   = {};
     presentInfo.sType              = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
+    presentInfo.pNext              = pNextChain;
     presentInfo.waitSemaphoreCount = 1;
     presentInfo.pWaitSemaphores    = presentSemaphore->ptr();
     presentInfo.swapchainCount     = 1;
@@ -1109,7 +1110,10 @@
     return angle::Result::Continue;
 }
 
-angle::Result WindowSurfaceVk::swapImpl(const gl::Context *context, EGLint *rects, EGLint n_rects)
+angle::Result WindowSurfaceVk::swapImpl(const gl::Context *context,
+                                        EGLint *rects,
+                                        EGLint n_rects,
+                                        const void *pNextChain)
 {
     ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::swapImpl");
 
@@ -1120,7 +1124,7 @@
     // Save this now, since present() will increment the value.
     uint32_t currentSwapHistoryIndex = static_cast<uint32_t>(mCurrentSwapHistoryIndex);
 
-    ANGLE_TRY(present(contextVk, rects, n_rects, &presentOutOfDate));
+    ANGLE_TRY(present(contextVk, rects, n_rects, pNextChain, &presentOutOfDate));
 
     ANGLE_TRY(checkForOutOfDateSwapchain(contextVk, currentSwapHistoryIndex, presentOutOfDate));
 
diff --git a/src/libANGLE/renderer/vulkan/SurfaceVk.h b/src/libANGLE/renderer/vulkan/SurfaceVk.h
index 7f3f85a..d1b1769 100644
--- a/src/libANGLE/renderer/vulkan/SurfaceVk.h
+++ b/src/libANGLE/renderer/vulkan/SurfaceVk.h
@@ -215,9 +215,14 @@
     vk::Semaphore getAcquireImageSemaphore();
 
   protected:
+    angle::Result swapImpl(const gl::Context *context,
+                           EGLint *rects,
+                           EGLint n_rects,
+                           const void *pNextChain);
+
     EGLNativeWindowType mNativeWindowType;
     VkSurfaceKHR mSurface;
-    VkInstance mInstance;
+    VkSurfaceCapabilitiesKHR mSurfaceCaps;
 
   private:
     virtual angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut)      = 0;
@@ -240,17 +245,15 @@
     angle::Result present(ContextVk *contextVk,
                           EGLint *rects,
                           EGLint n_rects,
+                          const void *pNextChain,
                           bool *presentOutOfDate);
 
     angle::Result updateAndDrawOverlay(ContextVk *contextVk, impl::SwapchainImage *image) const;
 
-    angle::Result swapImpl(const gl::Context *context, EGLint *rects, EGLint n_rects);
-
     angle::Result newPresentSemaphore(vk::Context *context, vk::Semaphore *semaphoreOut);
 
     bool isMultiSampled() const;
 
-    VkSurfaceCapabilitiesKHR mSurfaceCaps;
     std::vector<VkPresentModeKHR> mPresentModes;
 
     VkSwapchainKHR mSwapchain;
diff --git a/src/libANGLE/renderer/vulkan/ggp/DisplayVkGGP.cpp b/src/libANGLE/renderer/vulkan/ggp/DisplayVkGGP.cpp
new file mode 100644
index 0000000..d8889df
--- /dev/null
+++ b/src/libANGLE/renderer/vulkan/ggp/DisplayVkGGP.cpp
@@ -0,0 +1,47 @@
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// DisplayVkGGP.cpp:
+//    Implements the class methods for DisplayVkGGP.
+//
+
+#include "libANGLE/renderer/vulkan/ggp/DisplayVkGGP.h"
+
+#include "libANGLE/renderer/vulkan/ggp/WindowSurfaceVkGGP.h"
+#include "libANGLE/renderer/vulkan/vk_caps_utils.h"
+
+namespace rx
+{
+DisplayVkGGP::DisplayVkGGP(const egl::DisplayState &state) : DisplayVk(state) {}
+
+bool DisplayVkGGP::isValidNativeWindow(EGLNativeWindowType window) const
+{
+    // GGP doesn't use window handles.
+    return true;
+}
+
+SurfaceImpl *DisplayVkGGP::createWindowSurfaceVk(const egl::SurfaceState &state,
+                                                 EGLNativeWindowType window)
+{
+    return new WindowSurfaceVkGGP(state, window);
+}
+
+egl::ConfigSet DisplayVkGGP::generateConfigs()
+{
+    // Not entirely sure what backbuffer formats GGP supports.
+    constexpr GLenum kColorFormats[] = {GL_BGRA8_EXT, GL_BGRX8_ANGLEX};
+    return egl_vk::GenerateConfigs(kColorFormats, egl_vk::kConfigDepthStencilFormats, this);
+}
+
+bool DisplayVkGGP::checkConfigSupport(egl::Config *config)
+{
+    return true;
+}
+
+const char *DisplayVkGGP::getWSIExtension() const
+{
+    return VK_GGP_STREAM_DESCRIPTOR_SURFACE_EXTENSION_NAME;
+}
+}  // namespace rx
diff --git a/src/libANGLE/renderer/vulkan/ggp/DisplayVkGGP.h b/src/libANGLE/renderer/vulkan/ggp/DisplayVkGGP.h
new file mode 100644
index 0000000..04920dd
--- /dev/null
+++ b/src/libANGLE/renderer/vulkan/ggp/DisplayVkGGP.h
@@ -0,0 +1,34 @@
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// DisplayVkGGP.h:
+//    Google Game Platform implementation of DisplayVk.
+//
+
+#ifndef LIBANGLE_RENDERER_VULKAN_GGP_DISPLAYVKGGP_H_
+#define LIBANGLE_RENDERER_VULKAN_GGP_DISPLAYVKGGP_H_
+
+#include "libANGLE/renderer/vulkan/DisplayVk.h"
+
+namespace rx
+{
+class DisplayVkGGP : public DisplayVk
+{
+  public:
+    DisplayVkGGP(const egl::DisplayState &state);
+
+    bool isValidNativeWindow(EGLNativeWindowType window) const override;
+
+    SurfaceImpl *createWindowSurfaceVk(const egl::SurfaceState &state,
+                                       EGLNativeWindowType window) override;
+
+    egl::ConfigSet generateConfigs() override;
+    bool checkConfigSupport(egl::Config *config) override;
+
+    const char *getWSIExtension() const override;
+};
+}  // namespace rx
+
+#endif  // LIBANGLE_RENDERER_VULKAN_GGP_DISPLAYVKGGP_H_
diff --git a/src/libANGLE/renderer/vulkan/ggp/WindowSurfaceVkGGP.cpp b/src/libANGLE/renderer/vulkan/ggp/WindowSurfaceVkGGP.cpp
new file mode 100644
index 0000000..8b222ba
--- /dev/null
+++ b/src/libANGLE/renderer/vulkan/ggp/WindowSurfaceVkGGP.cpp
@@ -0,0 +1,76 @@
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// WindowSurfaceVkGGP.cpp:
+//    Implements the class methods for WindowSurfaceVkGGP.
+//
+
+#include "libANGLE/renderer/vulkan/ggp/WindowSurfaceVkGGP.h"
+
+#include "libANGLE/Context.h"
+#include "libANGLE/Display.h"
+#include "libANGLE/Surface.h"
+#include "libANGLE/renderer/vulkan/DisplayVk.h"
+#include "libANGLE/renderer/vulkan/RendererVk.h"
+
+namespace rx
+{
+namespace
+{
+constexpr EGLAttrib kDefaultStreamDescriptor = static_cast<EGLAttrib>(kGgpPrimaryStreamDescriptor);
+}  // namespace
+
+WindowSurfaceVkGGP::WindowSurfaceVkGGP(const egl::SurfaceState &surfaceState,
+                                       EGLNativeWindowType window)
+    : WindowSurfaceVk(surfaceState, window)
+{}
+
+angle::Result WindowSurfaceVkGGP::createSurfaceVk(vk::Context *context, gl::Extents *extentsOut)
+{
+    RendererVk *renderer = context->getRenderer();
+
+    InitGGPStreamDescriptorSurfaceFunctions(renderer->getInstance());
+
+    // Get the stream descriptor if specified. Default is kGgpPrimaryStreamDescriptor.
+    EGLAttrib streamDescriptor =
+        mState.attributes.get(EGL_GGP_STREAM_DESCRIPTOR_ANGLE, kDefaultStreamDescriptor);
+
+    VkStreamDescriptorSurfaceCreateInfoGGP createInfo = {};
+    createInfo.sType            = VK_STRUCTURE_TYPE_STREAM_DESCRIPTOR_SURFACE_CREATE_INFO_GGP;
+    createInfo.streamDescriptor = static_cast<GgpStreamDescriptor>(streamDescriptor);
+
+    ANGLE_VK_TRY(context, vkCreateStreamDescriptorSurfaceGGP(renderer->getInstance(), &createInfo,
+                                                             nullptr, &mSurface));
+
+    return getCurrentWindowSize(context, extentsOut);
+}
+
+angle::Result WindowSurfaceVkGGP::getCurrentWindowSize(vk::Context *context,
+                                                       gl::Extents *extentsOut)
+{
+    RendererVk *renderer                   = context->getRenderer();
+    const VkPhysicalDevice &physicalDevice = renderer->getPhysicalDevice();
+
+    ANGLE_VK_TRY(context, vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, mSurface,
+                                                                    &mSurfaceCaps));
+
+    *extentsOut =
+        gl::Extents(mSurfaceCaps.currentExtent.width, mSurfaceCaps.currentExtent.height, 1);
+    return angle::Result::Continue;
+}
+
+egl::Error WindowSurfaceVkGGP::swapWithFrameToken(const gl::Context *context,
+                                                  EGLFrameTokenANGLE frameToken)
+{
+    DisplayVk *displayVk = vk::GetImpl(context->getDisplay());
+
+    VkPresentFrameTokenGGP frameTokenData = {};
+    frameTokenData.sType                  = VK_STRUCTURE_TYPE_PRESENT_FRAME_TOKEN_GGP;
+    frameTokenData.frameToken             = static_cast<GgpFrameToken>(frameToken);
+
+    angle::Result result = swapImpl(context, nullptr, 0, &frameTokenData);
+    return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
+}
+}  // namespace rx
diff --git a/src/libANGLE/renderer/vulkan/ggp/WindowSurfaceVkGGP.h b/src/libANGLE/renderer/vulkan/ggp/WindowSurfaceVkGGP.h
new file mode 100644
index 0000000..6581d6f
--- /dev/null
+++ b/src/libANGLE/renderer/vulkan/ggp/WindowSurfaceVkGGP.h
@@ -0,0 +1,32 @@
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// WindowSurfaceVkGGP.h:
+//    Google Game Platform implementation of WindowSurfaceVk.
+//
+
+#ifndef LIBANGLE_RENDERER_VULKAN_GGP_WINDOWSURFACEVKGGP_H_
+#define LIBANGLE_RENDERER_VULKAN_GGP_WINDOWSURFACEVKGGP_H_
+
+#include "libANGLE/renderer/vulkan/SurfaceVk.h"
+
+namespace rx
+{
+
+class WindowSurfaceVkGGP : public WindowSurfaceVk
+{
+  public:
+    WindowSurfaceVkGGP(const egl::SurfaceState &surfaceState, EGLNativeWindowType window);
+
+  private:
+    egl::Error swapWithFrameToken(const gl::Context *context,
+                                  EGLFrameTokenANGLE frameToken) override;
+    angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) override;
+    angle::Result getCurrentWindowSize(vk::Context *context, gl::Extents *extentsOut) override;
+};
+
+}  // namespace rx
+
+#endif  // LIBANGLE_RENDERER_VULKAN_GGP_WINDOWSURFACEVKGGP_H_
diff --git a/src/libANGLE/renderer/vulkan/vk_utils.cpp b/src/libANGLE/renderer/vulkan/vk_utils.cpp
index 1fcffc0..594239b 100644
--- a/src/libANGLE/renderer/vulkan/vk_utils.cpp
+++ b/src/libANGLE/renderer/vulkan/vk_utils.cpp
@@ -624,6 +624,15 @@
 }
 #endif
 
+#if defined(ANGLE_PLATFORM_GGP)
+PFN_vkCreateStreamDescriptorSurfaceGGP vkCreateStreamDescriptorSurfaceGGP = nullptr;
+
+void InitGGPStreamDescriptorSurfaceFunctions(VkInstance instance)
+{
+    GET_FUNC(vkCreateStreamDescriptorSurfaceGGP);
+}
+#endif  // defined(ANGLE_PLATFORM_GGP)
+
 void InitExternalSemaphoreFdFunctions(VkInstance instance)
 {
     GET_FUNC(vkImportSemaphoreFdKHR);
diff --git a/src/libANGLE/renderer/vulkan/vk_utils.h b/src/libANGLE/renderer/vulkan/vk_utils.h
index 6c39957..4923145 100644
--- a/src/libANGLE/renderer/vulkan/vk_utils.h
+++ b/src/libANGLE/renderer/vulkan/vk_utils.h
@@ -640,6 +640,12 @@
 void InitExternalMemoryHardwareBufferANDROIDFunctions(VkInstance instance);
 #endif
 
+#if defined(ANGLE_PLATFORM_GGP)
+// VK_GGP_stream_descriptor_surface
+extern PFN_vkCreateStreamDescriptorSurfaceGGP vkCreateStreamDescriptorSurfaceGGP;
+void InitGGPStreamDescriptorSurfaceFunctions(VkInstance instance);
+#endif  // defined(ANGLE_PLATFORM_GGP)
+
 void InitExternalSemaphoreFdFunctions(VkInstance instance);
 
 namespace gl_vk
diff --git a/src/libANGLE/validationEGL.cpp b/src/libANGLE/validationEGL.cpp
index 76512c2..83fb975 100644
--- a/src/libANGLE/validationEGL.cpp
+++ b/src/libANGLE/validationEGL.cpp
@@ -1436,6 +1436,14 @@
                 }
                 break;
 
+            case EGL_GGP_STREAM_DESCRIPTOR_ANGLE:
+                if (!display->getExtensions().ggpStreamDescriptor)
+                {
+                    return EglBadAttribute() << "EGL_GGP_STREAM_DESCRIPTOR_ANGLE requires "
+                                                "EGL_ANGLE_ggp_stream_descriptor.";
+                }
+                break;
+
             default:
                 return EglBadAttribute();
         }
@@ -4073,4 +4081,19 @@
     return NoError();
 }
 
+Error ValidateSwapBuffersWithFrameTokenANGLE(const Display *display,
+                                             const Surface *surface,
+                                             EGLFrameTokenANGLE frametoken)
+{
+    ANGLE_TRY(ValidateDisplay(display));
+
+    if (!display->getExtensions().swapWithFrameToken)
+    {
+        return EglBadDisplay() << "EGL_ANGLE_swap_buffers_with_frame_token is not available.";
+    }
+
+    ANGLE_TRY(ValidateSurface(display, surface));
+
+    return NoError();
+}
 }  // namespace egl
diff --git a/src/libANGLE/validationEGL.h b/src/libANGLE/validationEGL.h
index e2c39db..57b4558 100644
--- a/src/libANGLE/validationEGL.h
+++ b/src/libANGLE/validationEGL.h
@@ -330,6 +330,11 @@
 // EGL_ANDROID_native_fence_sync
 Error ValidateDupNativeFenceFDANDROID(const Display *display, const Sync *sync);
 
+// EGL_ANGLE_swap_with_frame_token
+Error ValidateSwapBuffersWithFrameTokenANGLE(const Display *display,
+                                             const Surface *surface,
+                                             EGLFrameTokenANGLE frametoken);
+
 }  // namespace egl
 
 #define ANGLE_EGL_TRY(THREAD, EXPR, FUNCNAME, LABELOBJECT)                               \
diff --git a/src/libEGL/egl_loader_autogen.cpp b/src/libEGL/egl_loader_autogen.cpp
index 0e622e6..15e4dd5 100644
--- a/src/libEGL/egl_loader_autogen.cpp
+++ b/src/libEGL/egl_loader_autogen.cpp
@@ -74,6 +74,7 @@
 PFNEGLQUERYSURFACEPOINTERANGLEPROC EGL_QuerySurfacePointerANGLE;
 PFNEGLCREATESTREAMPRODUCERD3DTEXTUREANGLEPROC EGL_CreateStreamProducerD3DTextureANGLE;
 PFNEGLSTREAMPOSTD3DTEXTUREANGLEPROC EGL_StreamPostD3DTextureANGLE;
+PFNEGLSWAPBUFFERSWITHFRAMETOKENANGLEPROC EGL_SwapBuffersWithFrameTokenANGLE;
 PFNEGLGETSYNCVALUESCHROMIUMPROC EGL_GetSyncValuesCHROMIUM;
 PFNEGLQUERYDEVICEATTRIBEXTPROC EGL_QueryDeviceAttribEXT;
 PFNEGLQUERYDEVICESTRINGEXTPROC EGL_QueryDeviceStringEXT;
@@ -206,6 +207,8 @@
             loadProc("EGL_CreateStreamProducerD3DTextureANGLE"));
     EGL_StreamPostD3DTextureANGLE = reinterpret_cast<PFNEGLSTREAMPOSTD3DTEXTUREANGLEPROC>(
         loadProc("EGL_StreamPostD3DTextureANGLE"));
+    EGL_SwapBuffersWithFrameTokenANGLE = reinterpret_cast<PFNEGLSWAPBUFFERSWITHFRAMETOKENANGLEPROC>(
+        loadProc("EGL_SwapBuffersWithFrameTokenANGLE"));
     EGL_GetSyncValuesCHROMIUM =
         reinterpret_cast<PFNEGLGETSYNCVALUESCHROMIUMPROC>(loadProc("EGL_GetSyncValuesCHROMIUM"));
     EGL_QueryDeviceAttribEXT =
diff --git a/src/libEGL/egl_loader_autogen.h b/src/libEGL/egl_loader_autogen.h
index 0e10ae4..671126e 100644
--- a/src/libEGL/egl_loader_autogen.h
+++ b/src/libEGL/egl_loader_autogen.h
@@ -82,6 +82,7 @@
 ANGLE_NO_EXPORT extern PFNEGLCREATESTREAMPRODUCERD3DTEXTUREANGLEPROC
     EGL_CreateStreamProducerD3DTextureANGLE;
 ANGLE_NO_EXPORT extern PFNEGLSTREAMPOSTD3DTEXTUREANGLEPROC EGL_StreamPostD3DTextureANGLE;
+ANGLE_NO_EXPORT extern PFNEGLSWAPBUFFERSWITHFRAMETOKENANGLEPROC EGL_SwapBuffersWithFrameTokenANGLE;
 ANGLE_NO_EXPORT extern PFNEGLGETSYNCVALUESCHROMIUMPROC EGL_GetSyncValuesCHROMIUM;
 ANGLE_NO_EXPORT extern PFNEGLQUERYDEVICEATTRIBEXTPROC EGL_QueryDeviceAttribEXT;
 ANGLE_NO_EXPORT extern PFNEGLQUERYDEVICESTRINGEXTPROC EGL_QueryDeviceStringEXT;
diff --git a/src/libEGL/libEGL.cpp b/src/libEGL/libEGL.cpp
index a7c42f2..d1c4bae 100644
--- a/src/libEGL/libEGL.cpp
+++ b/src/libEGL/libEGL.cpp
@@ -712,4 +712,11 @@
     return EGL_DupNativeFenceFDANDROID(dpy, sync);
 }
 
+EGLBoolean EGLAPIENTRY eglSwapBuffersWithFrameTokenANGLE(EGLDisplay dpy,
+                                                         EGLSurface surface,
+                                                         EGLFrameTokenANGLE frametoken)
+{
+    EnsureEGLLoaded();
+    return EGL_SwapBuffersWithFrameTokenANGLE(dpy, surface, frametoken);
+}
 }  // extern "C"
diff --git a/src/libGLESv2/entry_points_egl_ext.cpp b/src/libGLESv2/entry_points_egl_ext.cpp
index 64142da..ce660db 100644
--- a/src/libGLESv2/entry_points_egl_ext.cpp
+++ b/src/libGLESv2/entry_points_egl_ext.cpp
@@ -1491,4 +1491,28 @@
     return result;
 }
 
+EGLBoolean EGLAPIENTRY EGL_SwapBuffersWithFrameTokenANGLE(EGLDisplay dpy,
+                                                          EGLSurface surface,
+                                                          EGLFrameTokenANGLE frametoken)
+{
+    ANGLE_SCOPED_GLOBAL_LOCK();
+    FUNC_EVENT("EGLDisplay dpy = 0x%016" PRIxPTR ", EGLSurface surface = 0x%016" PRIxPTR
+               ", EGLFrameTokenANGLE frametoken = 0x%llX",
+               (uintptr_t)dpy, (uintptr_t)surface, (unsigned long long)frametoken);
+
+    egl::Display *display    = static_cast<egl::Display *>(dpy);
+    egl::Surface *eglSurface = static_cast<egl::Surface *>(surface);
+    Thread *thread           = egl::GetCurrentThread();
+
+    ANGLE_EGL_TRY_RETURN(
+        thread, ValidateSwapBuffersWithFrameTokenANGLE(display, eglSurface, frametoken),
+        "eglSwapBuffersWithFrameTokenANGLE", GetDisplayIfValid(display), EGL_FALSE);
+
+    ANGLE_EGL_TRY_RETURN(thread, eglSurface->swapWithFrameToken(thread->getContext(), frametoken),
+                         "eglSwapBuffersWithFrameTokenANGLE", GetDisplayIfValid(display),
+                         EGL_FALSE);
+
+    thread->setSuccess();
+    return EGL_TRUE;
+}
 }  // extern "C"
diff --git a/src/libGLESv2/entry_points_egl_ext.h b/src/libGLESv2/entry_points_egl_ext.h
index 45ad216..7e8de1e 100644
--- a/src/libGLESv2/entry_points_egl_ext.h
+++ b/src/libGLESv2/entry_points_egl_ext.h
@@ -217,6 +217,12 @@
 // EGL_ANDROID_native_fence_sync
 ANGLE_EXPORT EGLint EGLAPIENTRY EGL_DupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync);
 
+// EGL_ANGLE_swap_with_frame_token
+ANGLE_EXPORT EGLBoolean EGLAPIENTRY
+EGL_SwapBuffersWithFrameTokenANGLE(EGLDisplay dpy,
+                                   EGLSurface surface,
+                                   EGLFrameTokenANGLE frametoken);
+
 }  // extern "C"
 
 #endif  // LIBGLESV2_ENTRYPOINTSEGLEXT_H_
diff --git a/src/libGLESv2/libGLESv2_autogen.def b/src/libGLESv2/libGLESv2_autogen.def
index 84cac49..b8a2aa7 100644
--- a/src/libGLESv2/libGLESv2_autogen.def
+++ b/src/libGLESv2/libGLESv2_autogen.def
@@ -1635,6 +1635,9 @@
     EGL_CreateStreamProducerD3DTextureANGLE
     EGL_StreamPostD3DTextureANGLE
 
+    ; EGL_ANGLE_swap_with_frame_token
+    EGL_SwapBuffersWithFrameTokenANGLE
+
     ; EGL_CHROMIUM_get_sync_values
     EGL_GetSyncValuesCHROMIUM
 
diff --git a/src/libGLESv2/libGLESv2_no_capture_autogen.def b/src/libGLESv2/libGLESv2_no_capture_autogen.def
index 8c1a2e8..658b99c 100644
--- a/src/libGLESv2/libGLESv2_no_capture_autogen.def
+++ b/src/libGLESv2/libGLESv2_no_capture_autogen.def
@@ -1635,6 +1635,9 @@
     EGL_CreateStreamProducerD3DTextureANGLE
     EGL_StreamPostD3DTextureANGLE
 
+    ; EGL_ANGLE_swap_with_frame_token
+    EGL_SwapBuffersWithFrameTokenANGLE
+
     ; EGL_CHROMIUM_get_sync_values
     EGL_GetSyncValuesCHROMIUM
 
diff --git a/src/libGLESv2/libGLESv2_with_capture_autogen.def b/src/libGLESv2/libGLESv2_with_capture_autogen.def
index 2b8a1a8..4694f2e 100644
--- a/src/libGLESv2/libGLESv2_with_capture_autogen.def
+++ b/src/libGLESv2/libGLESv2_with_capture_autogen.def
@@ -1635,6 +1635,9 @@
     EGL_CreateStreamProducerD3DTextureANGLE
     EGL_StreamPostD3DTextureANGLE
 
+    ; EGL_ANGLE_swap_with_frame_token
+    EGL_SwapBuffersWithFrameTokenANGLE
+
     ; EGL_CHROMIUM_get_sync_values
     EGL_GetSyncValuesCHROMIUM
 
diff --git a/src/libGLESv2/proc_table_egl_autogen.cpp b/src/libGLESv2/proc_table_egl_autogen.cpp
index ecee574..bee7b76 100644
--- a/src/libGLESv2/proc_table_egl_autogen.cpp
+++ b/src/libGLESv2/proc_table_egl_autogen.cpp
@@ -115,6 +115,7 @@
     {"eglSurfaceAttrib", P(EGL_SurfaceAttrib)},
     {"eglSwapBuffers", P(EGL_SwapBuffers)},
     {"eglSwapBuffersWithDamageKHR", P(EGL_SwapBuffersWithDamageKHR)},
+    {"eglSwapBuffersWithFrameTokenANGLE", P(EGL_SwapBuffersWithFrameTokenANGLE)},
     {"eglSwapInterval", P(EGL_SwapInterval)},
     {"eglTerminate", P(EGL_Terminate)},
     {"eglWaitClient", P(EGL_WaitClient)},
@@ -1519,5 +1520,5 @@
     {"glWeightPointerOES", P(gl::WeightPointerOES)},
     {"glWeightPointerOESContextANGLE", P(gl::WeightPointerOESContextANGLE)}};
 
-size_t g_numProcs = 1420;
+size_t g_numProcs = 1421;
 }  // namespace egl
diff --git a/util/egl_loader_autogen.cpp b/util/egl_loader_autogen.cpp
index 45f4be3..bb9457d 100644
--- a/util/egl_loader_autogen.cpp
+++ b/util/egl_loader_autogen.cpp
@@ -76,6 +76,7 @@
 ANGLE_UTIL_EXPORT PFNEGLCREATESTREAMPRODUCERD3DTEXTUREANGLEPROC
     eglCreateStreamProducerD3DTextureANGLE;
 ANGLE_UTIL_EXPORT PFNEGLSTREAMPOSTD3DTEXTUREANGLEPROC eglStreamPostD3DTextureANGLE;
+ANGLE_UTIL_EXPORT PFNEGLSWAPBUFFERSWITHFRAMETOKENANGLEPROC eglSwapBuffersWithFrameTokenANGLE;
 ANGLE_UTIL_EXPORT PFNEGLGETSYNCVALUESCHROMIUMPROC eglGetSyncValuesCHROMIUM;
 ANGLE_UTIL_EXPORT PFNEGLQUERYDEVICEATTRIBEXTPROC eglQueryDeviceAttribEXT;
 ANGLE_UTIL_EXPORT PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT;
@@ -210,6 +211,8 @@
             loadProc("eglCreateStreamProducerD3DTextureANGLE"));
     eglStreamPostD3DTextureANGLE = reinterpret_cast<PFNEGLSTREAMPOSTD3DTEXTUREANGLEPROC>(
         loadProc("eglStreamPostD3DTextureANGLE"));
+    eglSwapBuffersWithFrameTokenANGLE = reinterpret_cast<PFNEGLSWAPBUFFERSWITHFRAMETOKENANGLEPROC>(
+        loadProc("eglSwapBuffersWithFrameTokenANGLE"));
     eglGetSyncValuesCHROMIUM =
         reinterpret_cast<PFNEGLGETSYNCVALUESCHROMIUMPROC>(loadProc("eglGetSyncValuesCHROMIUM"));
     eglQueryDeviceAttribEXT =
diff --git a/util/egl_loader_autogen.h b/util/egl_loader_autogen.h
index a21ee1f..2946a94 100644
--- a/util/egl_loader_autogen.h
+++ b/util/egl_loader_autogen.h
@@ -83,6 +83,7 @@
 ANGLE_UTIL_EXPORT extern PFNEGLCREATESTREAMPRODUCERD3DTEXTUREANGLEPROC
     eglCreateStreamProducerD3DTextureANGLE;
 ANGLE_UTIL_EXPORT extern PFNEGLSTREAMPOSTD3DTEXTUREANGLEPROC eglStreamPostD3DTextureANGLE;
+ANGLE_UTIL_EXPORT extern PFNEGLSWAPBUFFERSWITHFRAMETOKENANGLEPROC eglSwapBuffersWithFrameTokenANGLE;
 ANGLE_UTIL_EXPORT extern PFNEGLGETSYNCVALUESCHROMIUMPROC eglGetSyncValuesCHROMIUM;
 ANGLE_UTIL_EXPORT extern PFNEGLQUERYDEVICEATTRIBEXTPROC eglQueryDeviceAttribEXT;
 ANGLE_UTIL_EXPORT extern PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT;