Title: [267869] trunk
Revision
267869
Author
[email protected]
Date
2020-10-02 00:05:42 -0700 (Fri, 02 Oct 2020)

Log Message

[iOS WK1] Crashes when using ANGLE WebGL from another thread
https://bugs.webkit.org/show_bug.cgi?id=216106
<rdar://problem/68602452>

Patch by Kimmo Kinnunen <[email protected]> on 2020-10-02
Reviewed by Kenneth Russell.

Source/ThirdParty/ANGLE:

Add two extensions for EAGL and CGL backends to declare the
underlying platform context being "volatile". It means that
the thread-global current context is being modified behind
ANGLE. If ANGLE context is marked volatile for a particular
API, it will sync the underlying context for every EGL
function that needs the context. Most intuitive use is
for the client to call eglMakeCurrent before calling any
gl function if the client knowns the platform state might
be dirty.

Implement eglReleaseThread for EAGL and CGL backends.
Releasing thread will unset the platform current context.

Fix a bug of omitting EGL_ANGLE_device_eagl from being
advertised.

* extensions/EGL_ANGLE_platform_angle_device_context_volatile_cgl.txt: Added.
* extensions/EGL_ANGLE_platform_angle_device_context_volatile_eagl.txt: Added.
* include/EGL/eglext_angle.h:
* src/libANGLE/Caps.cpp:
(egl::DeviceExtensions::getStrings const):
(egl::ClientExtensions::getStrings const):
* src/libANGLE/Caps.h:
* src/libANGLE/Display.cpp:
(egl::Display::prepareForCall):
(egl::Display::releaseThread):
(egl::GenerateClientExtensions):
* src/libANGLE/Display.h:
* src/libANGLE/renderer/DisplayImpl.cpp:
(rx::DisplayImpl::prepareForCall):
(rx::DisplayImpl::releaseThread):
* src/libANGLE/renderer/DisplayImpl.h:
* src/libANGLE/renderer/gl/cgl/DisplayCGL.h:
* src/libANGLE/renderer/gl/cgl/DisplayCGL.mm:
(rx::DisplayCGL::initialize):
(rx::DisplayCGL::terminate):
(rx::DisplayCGL::prepareForCall):
(rx::DisplayCGL::releaseThread):
(rx::DisplayCGL::makeCurrent):
* src/libANGLE/renderer/gl/eagl/DisplayEAGL.h:
* src/libANGLE/renderer/gl/eagl/DisplayEAGL.mm:
(rx::DisplayEAGL::initialize):
(rx::DisplayEAGL::terminate):
(rx::DisplayEAGL::prepareForCall):
(rx::DisplayEAGL::releaseThread):
* src/libANGLE/validationEGL.cpp:
* src/libGLESv2/entry_points_egl.cpp:
* src/libGLESv2/entry_points_egl_ext.cpp:

Source/WebCore:

Source of the bug comes from following:
  - WK1 might run WebKit code in client main thread.
  - WK1 might run Webkit code in web thread.
  - WebKit code might run WebGL payload, notably access
    GraphicsContextGL classes.
    Client is able to modify EAGL/CGL current context.

The change to ANGLE incurred two distinct behavior changes
compared to raw EAGL / CGL:
1) Before: context was set current before any GL call
After: context was set current only if EGL current context
had been changed. (Explicit code as well as ANGLE implementation
optimization.)

2) Before: context being used was able to be current in
multiple threads at the same time. (EAGL/CGL feature)
After: context cannot be current in multiple threads
at the same time. (EGL feature)

Change in behavior 1) caused ANGLE to sometimes use
the EAGL/CGL context of the client instead of
the real context that ANGLE created.
Fix this by introducing
EGL_ANGLE_platform_angle_device_context_volatile_eagl
and
EGL_ANGLE_platform_angle_device_context_volatile_cgl
which make ANGLE sync the context on each eglMakeCurrent
eglReleaseThread and eglTerminate.

Change in behavior 2) caused ANGLE to use uninitialized
context object from one thread, if the real context object
was current in another thread.
Fix this by considering "GraphicsContextGLOpenGL current context"
as part of "data that is owned by WebCoreThread lock".
The current context is set with lock held, implicitly.
The current context is released when lock is released.
When the lock is not held, GraphicsContextGLOpenGL current context
is nullptr.

Adds soft linking for EAGL for the purpose of testing this in
TestWebKitAPI. The case of Apple Silicon Mac may sometimes
use CGL and sometimes EAGL, and the test should test that
client overriding both contexts will not cause problems.

Fix ANGLE header include path:
 - Do not include ANGLE in the path, as files are included with ANGLE/
 - Add WK_ALTERNATE_FRAMEWORKS_DIR so that SDK_VARIANT=iosmac
   e.g. maccatalyst builds work
Previously the ANGLE was not included from ThirdParty/ANGLE, rather
"WebKit SDK".

* Configurations/WebCore.xcconfig:
* platform/graphics/cocoa/GraphicsContextGLOpenGLCocoa.mm:
(WebCore::GraphicsContextGLOpenGL::GraphicsContextGLOpenGL):
(WebCore::GraphicsContextGLOpenGL::~GraphicsContextGLOpenGL):
(WebCore::GraphicsContextGLOpenGL::makeContextCurrent):
(WebCore::GraphicsContextGLOpenGL::releaseCurrentContext):
(WebCore::GraphicsContextGLOpenGL::checkGPUStatus):
(WebCore::GraphicsContextGLOpenGL::allowOfflineRenderers const):
* platform/graphics/opengl/GraphicsContextGLOpenGL.h:
* platform/ios/wak/WebCoreThread.mm:
(WebThreadUnlockFromAnyThread):
(_WebThreadUnlock):

Tools:

Add a WK1 test which runs WebGL code both in
client main thread and in web thread.
This tests the case where ANGLE EGL context is
not being held current in one thread while the
other thread runs WebGL and thus ANGLE EGL code.

* TestWebKitAPI/Configurations/TestWebKitAPI.xcconfig:
* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitLegacy/ios/WebGLNoCrashOnOtherThreadAccess.mm: Added.
(-[WebGLNoCrashOnOtherThreadAccessWebViewDelegate webViewDidFinishLoad:]):
(-[WebGLNoCrashOnOtherThreadAccessWebViewDelegate webView:shouldStartLoadWithRequest:navigationType:]):
(TestWebKitAPI::TEST):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/ThirdParty/ANGLE/ChangeLog (267868 => 267869)


--- trunk/Source/ThirdParty/ANGLE/ChangeLog	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Source/ThirdParty/ANGLE/ChangeLog	2020-10-02 07:05:42 UTC (rev 267869)
@@ -1,3 +1,60 @@
+2020-10-02  Kimmo Kinnunen  <[email protected]>
+
+        [iOS WK1] Crashes when using ANGLE WebGL from another thread
+        https://bugs.webkit.org/show_bug.cgi?id=216106
+        <rdar://problem/68602452>
+
+        Reviewed by Kenneth Russell.
+
+        Add two extensions for EAGL and CGL backends to declare the
+        underlying platform context being "volatile". It means that
+        the thread-global current context is being modified behind
+        ANGLE. If ANGLE context is marked volatile for a particular
+        API, it will sync the underlying context for every EGL
+        function that needs the context. Most intuitive use is
+        for the client to call eglMakeCurrent before calling any
+        gl function if the client knowns the platform state might
+        be dirty.
+
+        Implement eglReleaseThread for EAGL and CGL backends.
+        Releasing thread will unset the platform current context.
+
+        Fix a bug of omitting EGL_ANGLE_device_eagl from being
+        advertised.
+
+        * extensions/EGL_ANGLE_platform_angle_device_context_volatile_cgl.txt: Added.
+        * extensions/EGL_ANGLE_platform_angle_device_context_volatile_eagl.txt: Added.
+        * include/EGL/eglext_angle.h:
+        * src/libANGLE/Caps.cpp:
+        (egl::DeviceExtensions::getStrings const):
+        (egl::ClientExtensions::getStrings const):
+        * src/libANGLE/Caps.h:
+        * src/libANGLE/Display.cpp:
+        (egl::Display::prepareForCall):
+        (egl::Display::releaseThread):
+        (egl::GenerateClientExtensions):
+        * src/libANGLE/Display.h:
+        * src/libANGLE/renderer/DisplayImpl.cpp:
+        (rx::DisplayImpl::prepareForCall):
+        (rx::DisplayImpl::releaseThread):
+        * src/libANGLE/renderer/DisplayImpl.h:
+        * src/libANGLE/renderer/gl/cgl/DisplayCGL.h:
+        * src/libANGLE/renderer/gl/cgl/DisplayCGL.mm:
+        (rx::DisplayCGL::initialize):
+        (rx::DisplayCGL::terminate):
+        (rx::DisplayCGL::prepareForCall):
+        (rx::DisplayCGL::releaseThread):
+        (rx::DisplayCGL::makeCurrent):
+        * src/libANGLE/renderer/gl/eagl/DisplayEAGL.h:
+        * src/libANGLE/renderer/gl/eagl/DisplayEAGL.mm:
+        (rx::DisplayEAGL::initialize):
+        (rx::DisplayEAGL::terminate):
+        (rx::DisplayEAGL::prepareForCall):
+        (rx::DisplayEAGL::releaseThread):
+        * src/libANGLE/validationEGL.cpp:
+        * src/libGLESv2/entry_points_egl.cpp:
+        * src/libGLESv2/entry_points_egl_ext.cpp:
+
 2020-09-29  James Darpinian  <[email protected]>
 
         Fix EXT_color_buffer_half_float on iOS

Added: trunk/Source/ThirdParty/ANGLE/extensions/EGL_ANGLE_platform_angle_device_context_volatile_cgl.txt (0 => 267869)


--- trunk/Source/ThirdParty/ANGLE/extensions/EGL_ANGLE_platform_angle_device_context_volatile_cgl.txt	                        (rev 0)
+++ trunk/Source/ThirdParty/ANGLE/extensions/EGL_ANGLE_platform_angle_device_context_volatile_cgl.txt	2020-10-02 07:05:42 UTC (rev 267869)
@@ -0,0 +1,90 @@
+Name
+
+    ANGLE_platform_angle_device_context_volatile_cgl
+
+Name Strings
+
+    EGL_ANGLE_platform_angle_device_context_volatile_cgl
+
+Contributors
+    Kimmo Kinnunen, Apple
+    Kenneth Russell, Google
+
+Contacts
+    Kimmo Kinnunen, Apple (kkinnunen 'at' apple 'dot' org)
+    Kenneth Russell, Google (kbr 'at' chromium 'dot' org)
+
+Status
+
+    Draft
+
+Version
+
+    Version 1, 2020-09-30
+
+Number
+
+    EGL Extension XXX
+
+Extension Type
+
+    EGL client extension
+
+Dependencies
+
+    Requires ANGLE_platform_angle.
+
+Overview
+
+    This extension allows the client to request a Display that internally
+    is able to function even if client changes current CGL context of the
+    thread. Requesting a volatile device context contexts may impact performance.
+    The extension is useful for using EGL in a library that cannot guarantee
+    which platform APIs its clients will use.
+
+New Types
+
+    None
+
+New Procedures and Functions
+
+    None
+
+New Tokens
+
+    Accepted as an attribute name in the <attrib_list> argument of
+    eglGetPlatformDisplayEXT:
+
+        EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_CGL_ANGLE    0x34A3
+
+Additions to the EGL Specification
+
+    None.
+
+New Behavior
+
+    To request a display that internally supports the feature,
+    use the attribute EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_CGL_ANGLE.
+    EGL_TRUE enables volatile CGL device context and EGL_FALSE disables it.
+    Any value other than these will result in an error.
+    The default value for EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_CGL_ANGLE
+    is EGL_FALSE.
+
+    When the device context of the display is set as volatile CGL, then
+    each EGL function will change the current CGL context state accordingly
+    to use the internal device context, if needed. If the internal device context
+    is not using CGL, the property has no effect.
+
+    Calls to OpenGL or OpenGL ES functions will not ensure the underlying device
+    context is correct. If the state of the current CGL context is unknown,
+    clients should call MakeCurrent to ensure that the internal device
+    context is made current.
+
+Issues
+
+    None
+
+Revision History
+
+    Version 1, 2020-09-30 (Kimmo Kinnunen)
+      - Initial draft

Added: trunk/Source/ThirdParty/ANGLE/extensions/EGL_ANGLE_platform_angle_device_context_volatile_eagl.txt (0 => 267869)


--- trunk/Source/ThirdParty/ANGLE/extensions/EGL_ANGLE_platform_angle_device_context_volatile_eagl.txt	                        (rev 0)
+++ trunk/Source/ThirdParty/ANGLE/extensions/EGL_ANGLE_platform_angle_device_context_volatile_eagl.txt	2020-10-02 07:05:42 UTC (rev 267869)
@@ -0,0 +1,90 @@
+Name
+
+    ANGLE_platform_angle_device_context_volatile_eagl
+
+Name Strings
+
+    EGL_ANGLE_platform_angle_device_context_volatile_eagl
+
+Contributors
+    Kimmo Kinnunen, Apple
+    Kenneth Russell, Google
+
+Contacts
+    Kimmo Kinnunen, Apple (kkinnunen 'at' apple 'dot' org)
+    Kenneth Russell, Google (kbr 'at' chromium 'dot' org)
+
+Status
+
+    Draft
+
+Version
+
+    Version 1, 2020-09-30
+
+Number
+
+    EGL Extension XXX
+
+Extension Type
+
+    EGL client extension
+
+Dependencies
+
+    Requires ANGLE_platform_angle.
+
+Overview
+
+    This extension allows the client to request a Display that internally
+    is able to function even if client changes current EAGL context of the
+    thread. Requesting a volatile device context contexts may impact performance.
+    The extension is useful for using EGL in a library that cannot guarantee
+    which platform APIs its clients will use.
+
+New Types
+
+    None
+
+New Procedures and Functions
+
+    None
+
+New Tokens
+
+    Accepted as an attribute name in the <attrib_list> argument of
+    eglGetPlatformDisplayEXT:
+
+        EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_EAGL_ANGLE    0x34A2
+
+Additions to the EGL Specification
+
+    None.
+
+New Behavior
+
+    To request a display that internally supports the feature,
+    use the attribute EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_EAGL_ANGLE.
+    EGL_TRUE enables volatile EAGL device context and EGL_FALSE disables it.
+    Any value other than these will result in an error.
+    The default value for EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_EAGL_ANGLE
+    is EGL_FALSE.
+
+    When the device context of the display is set as volatile EAGL, then
+    each EGL function will change the current EAGL context state accordingly
+    to use the internal device context, if needed. If the internal device context
+    is not using EAGL, the property has no effect.
+
+    Calls to OpenGL or OpenGL ES functions will not ensure the underlying device
+    context is correct. If the state of the current EAGL context is unknown,
+    clients should call MakeCurrent to ensure that the internal device
+    context is made current.
+
+Issues
+
+    None
+
+Revision History
+
+    Version 1, 2020-09-30 (Kimmo Kinnunen)
+      - Initial draft

Modified: trunk/Source/ThirdParty/ANGLE/include/EGL/eglext_angle.h (267868 => 267869)


--- trunk/Source/ThirdParty/ANGLE/include/EGL/eglext_angle.h	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Source/ThirdParty/ANGLE/include/EGL/eglext_angle.h	2020-10-02 07:05:42 UTC (rev 267869)
@@ -116,6 +116,16 @@
 #define EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE 0x3481
 #endif /* EGL_ANGLE_platform_angle_context_virtualization */
 
+#ifndef EGL_ANGLE_platform_angle_device_context_volatile_eagl
+#define EGL_ANGLE_platform_angle_device_context_volatile_eagl 1
+#define EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_EAGL_ANGLE 0x34A2
+#endif /* EGL_ANGLE_platform_angle_device_context_volatile_eagl */
+
+#ifndef EGL_ANGLE_platform_angle_device_context_volatile_cgl
+#define EGL_ANGLE_platform_angle_device_context_volatile_cgl 1
+#define EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_CGL_ANGLE 0x34A3
+#endif /* EGL_ANGLE_platform_angle_device_context_volatile_cgl */
+
 #ifndef EGL_ANGLE_x11_visual
 #define EGL_ANGLE_x11_visual
 #define EGL_X11_VISUAL_ID_ANGLE 0x33A3

Modified: trunk/Source/ThirdParty/ANGLE/src/libANGLE/Caps.cpp (267868 => 267869)


--- trunk/Source/ThirdParty/ANGLE/src/libANGLE/Caps.cpp	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Source/ThirdParty/ANGLE/src/libANGLE/Caps.cpp	2020-10-02 07:05:42 UTC (rev 267869)
@@ -1418,6 +1418,8 @@
     //                   | Extension name                                 | Supported flag                | Output vector   |
     InsertExtensionString("EGL_ANGLE_device_d3d",                          deviceD3D,                      &extensionStrings);
     InsertExtensionString("EGL_ANGLE_device_cgl",                          deviceCGL,                      &extensionStrings);
+    InsertExtensionString("EGL_ANGLE_device_eagl",                         deviceEAGL,                     &extensionStrings);
+
     // clang-format on
 
     return extensionStrings;
@@ -1445,6 +1447,8 @@
     InsertExtensionString("EGL_ANGLE_platform_angle_vulkan",                  platformANGLEVulkan,                &extensionStrings);
     InsertExtensionString("EGL_ANGLE_platform_angle_metal",                   platformANGLEMetal,                 &extensionStrings);
     InsertExtensionString("EGL_ANGLE_platform_angle_context_virtualization",  platformANGLEContextVirtualization, &extensionStrings);
+    InsertExtensionString("EGL_ANGLE_platform_device_context_volatile_eagl",  platformANGLEDeviceContextVolatileEagl, &extensionStrings);
+    InsertExtensionString("EGL_ANGLE_platform_device_context_volatile_cgl",   platformANGLEDeviceContextVolatileCgl, &extensionStrings);
     InsertExtensionString("EGL_ANGLE_device_creation",                        deviceCreation,                     &extensionStrings);
     InsertExtensionString("EGL_ANGLE_device_creation_d3d11",                  deviceCreationD3D11,                &extensionStrings);
     InsertExtensionString("EGL_ANGLE_x11_visual",                             x11Visual,                          &extensionStrings);

Modified: trunk/Source/ThirdParty/ANGLE/src/libANGLE/Caps.h (267868 => 267869)


--- trunk/Source/ThirdParty/ANGLE/src/libANGLE/Caps.h	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Source/ThirdParty/ANGLE/src/libANGLE/Caps.h	2020-10-02 07:05:42 UTC (rev 267869)
@@ -1145,6 +1145,12 @@
     // EGL_ANGLE_platform_angle_context_virtualization
     bool platformANGLEContextVirtualization = false;
 
+    // EGL_ANGLE_platform_angle_device_context_volatile_eagl
+    bool platformANGLEDeviceContextVolatileEagl = false;
+
+    // EGL_ANGLE_platform_angle_device_context_volatile_cgl
+    bool platformANGLEDeviceContextVolatileCgl = false;
+
     // EGL_ANGLE_device_creation
     bool deviceCreation = false;
 

Modified: trunk/Source/ThirdParty/ANGLE/src/libANGLE/Display.cpp (267868 => 267869)


--- trunk/Source/ThirdParty/ANGLE/src/libANGLE/Display.cpp	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Source/ThirdParty/ANGLE/src/libANGLE/Display.cpp	2020-10-02 07:05:42 UTC (rev 267869)
@@ -955,6 +955,16 @@
     return NoError();
 }
 
+Error Display::prepareForCall()
+{
+    return mImplementation->prepareForCall();
+}
+
+Error Display::releaseThread()
+{
+    return mImplementation->releaseThread();
+}
+
 std::vector<const Config *> Display::getConfigs(const egl::AttributeMap &attribs) const
 {
     return mConfigSet.filter(attribs);
@@ -1544,6 +1554,14 @@
     extensions.platformANGLEDeviceTypeEGLANGLE = true;
 #endif
 
+#if (defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)) || (defined(ANGLE_PLATFORM_MACCATALYST) && defined(ANGLE_CPU_ARM64))
+    extensions.platformANGLEDeviceContextVolatileEagl = true;
+#endif
+
+#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
+    extensions.platformANGLEDeviceContextVolatileCgl = true;
+#endif
+
     extensions.clientGetAllProcAddresses = true;
     extensions.debug                     = true;
     extensions.explicitContext           = true;

Modified: trunk/Source/ThirdParty/ANGLE/src/libANGLE/Display.h (267868 => 267869)


--- trunk/Source/ThirdParty/ANGLE/src/libANGLE/Display.h	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Source/ThirdParty/ANGLE/src/libANGLE/Display.h	2020-10-02 07:05:42 UTC (rev 267869)
@@ -102,6 +102,13 @@
 
     Error initialize();
     Error terminate(const Thread *thread);
+    // Called before all display state dependent EGL functions. Backends can set up, for example,
+    // thread-specific backend state through this function. Not called for functions that do not
+    // need the state.
+    Error prepareForCall();
+    // Called on eglReleaseThread. Backends can tear down thread-specific backend state through
+    // this function.
+    Error releaseThread();
 
     static Display *GetDisplayFromDevice(Device *device, const AttributeMap &attribMap);
     static Display *GetDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay,

Modified: trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/DisplayImpl.cpp (267868 => 267869)


--- trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/DisplayImpl.cpp	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/DisplayImpl.cpp	2020-10-02 07:05:42 UTC (rev 267869)
@@ -23,6 +23,16 @@
     ASSERT(mState.surfaceSet.empty());
 }
 
+egl::Error DisplayImpl::prepareForCall()
+{
+    return egl::NoError();
+}
+
+egl::Error DisplayImpl::releaseThread()
+{
+    return egl::NoError();
+}
+
 const egl::DisplayExtensions &DisplayImpl::getExtensions() const
 {
     if (!mExtensionsInitialized)

Modified: trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/DisplayImpl.h (267868 => 267869)


--- trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/DisplayImpl.h	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/DisplayImpl.h	2020-10-02 07:05:42 UTC (rev 267869)
@@ -67,11 +67,14 @@
 
     virtual egl::Error initialize(egl::Display *display) = 0;
     virtual void terminate()                             = 0;
+    virtual egl::Error prepareForCall();
+    virtual egl::Error releaseThread();
 
     virtual egl::Error makeCurrent(egl::Surface *drawSurface,
                                    egl::Surface *readSurface,
                                    gl::Context *context) = 0;
 
+
     virtual egl::ConfigSet generateConfigs() = 0;
 
     virtual bool testDeviceLost()                                     = 0;

Modified: trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/cgl/DisplayCGL.h (267868 => 267869)


--- trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/cgl/DisplayCGL.h	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/cgl/DisplayCGL.h	2020-10-02 07:05:42 UTC (rev 267869)
@@ -10,6 +10,7 @@
 #define LIBANGLE_RENDERER_GL_CGL_DISPLAYCGL_H_
 
 #include <thread>
+#include <unordered_set>
 
 #include "libANGLE/renderer/gl/DisplayGL.h"
 
@@ -32,6 +33,8 @@
 
     egl::Error initialize(egl::Display *display) override;
     void terminate() override;
+    egl::Error prepareForCall() override;
+    egl::Error releaseThread() override;
 
     egl::Error makeCurrent(egl::Surface *drawSurface,
                            egl::Surface *readSurface,
@@ -103,7 +106,7 @@
 
     egl::Display *mEGLDisplay;
     CGLContextObj mContext;
-    std::unordered_map<std::thread::id, CGLContextObj> mCurrentContexts;
+    std::unordered_set<std::thread::id> mThreadsWithCurrentContext;
     CGLPixelFormatObj mPixelFormat;
     bool mSupportsGPUSwitching;
     uint64_t mCurrentGPUID;
@@ -113,6 +116,7 @@
     // is unref'd for the last time, this is set to the time of that last unref. If it isn't
     // activated again in 10 seconds, the discrete GPU pixel format is deleted.
     double mLastDiscreteGPUUnrefTime;
+    bool mDeviceContextIsVolatile = false;
 };
 
 }  // namespace rx

Modified: trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/cgl/DisplayCGL.mm (267868 => 267869)


--- trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/cgl/DisplayCGL.mm	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/cgl/DisplayCGL.mm	2020-10-02 07:05:42 UTC (rev 267869)
@@ -184,10 +184,12 @@
         mCurrentGPUID = angle::GetGpuIDFromDisplayID(kCGDirectMainDisplay);
     }
 
-    CGLSetCurrentContext(mContext);
+    if (CGLSetCurrentContext(mContext) != kCGLNoError)
+    {
+        return egl::EglNotInitialized() << "Could not make the CGL context current.";
+    }
+    mThreadsWithCurrentContext.insert(std::this_thread::get_id());
 
-    mCurrentContexts[std::this_thread::get_id()] = mContext;
-
     // There is no equivalent getProcAddress in CGL so we open the dylib directly
     void *handle = dlopen(kDefaultOpenGLDylibName, RTLD_NOW);
     if (!handle)
@@ -210,6 +212,9 @@
         return egl::EglNotInitialized() << "OpenGL ES 2.0 is not supportable.";
     }
 
+    auto &attributes = display->getAttributeMap();
+    mDeviceContextIsVolatile = attributes.get(EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_CGL_ANGLE, GL_FALSE);
+
     return DisplayGL::initialize(display);
 }
 
@@ -223,12 +228,12 @@
         CGLDestroyPixelFormat(mPixelFormat);
         mPixelFormat = nullptr;
     }
-    mCurrentContexts.clear();
     if (mContext != nullptr)
     {
         CGLSetCurrentContext(nullptr);
         CGLDestroyContext(mContext);
         mContext = nullptr;
+        mThreadsWithCurrentContext.clear();
     }
     if (mDiscreteGPUPixelFormat != nullptr)
     {
@@ -238,23 +243,41 @@
     }
 }
 
+egl::Error DisplayCGL::prepareForCall()
+{
+    ASSERT(mContext);
+    auto threadId = std::this_thread::get_id();
+    if (mDeviceContextIsVolatile || mThreadsWithCurrentContext.find(threadId) == mThreadsWithCurrentContext.end())
+    {
+        if (CGLSetCurrentContext(mContext) != kCGLNoError)
+        {
+            return egl::EglBadAlloc() << "Could not make device CGL context current.";
+        }
+        mThreadsWithCurrentContext.insert(threadId);
+    }
+    return egl::NoError();
+}
+
+egl::Error DisplayCGL::releaseThread()
+{
+    ASSERT(mContext);
+    auto threadId = std::this_thread::get_id();
+    if (mThreadsWithCurrentContext.find(threadId) != mThreadsWithCurrentContext.end())
+    {
+        if (CGLSetCurrentContext(nullptr) != kCGLNoError)
+        {
+            return egl::EglBadAlloc() << "Could not release device CGL context.";
+        }
+        mThreadsWithCurrentContext.erase(threadId);
+    }
+    return egl::NoError();
+}
+
 egl::Error DisplayCGL::makeCurrent(egl::Surface *drawSurface,
                                    egl::Surface *readSurface,
                                    gl::Context *context)
 {
     checkDiscreteGPUStatus();
-    // If the thread that's calling makeCurrent does not have the correct
-    // context current (either mContext or 0), we need to set it current.
-    CGLContextObj newContext = 0;
-    if (context)
-    {
-        newContext = mContext;
-    }
-    if (newContext != mCurrentContexts[std::this_thread::get_id()])
-    {
-        CGLSetCurrentContext(newContext);
-        mCurrentContexts[std::this_thread::get_id()] = newContext;
-    }
     return DisplayGL::makeCurrent(drawSurface, readSurface, context);
 }
 

Modified: trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/eagl/DisplayEAGL.h (267868 => 267869)


--- trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/eagl/DisplayEAGL.h	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/eagl/DisplayEAGL.h	2020-10-02 07:05:42 UTC (rev 267869)
@@ -13,6 +13,9 @@
 
 #if (defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)) || (defined(ANGLE_PLATFORM_MACCATALYST) && defined(ANGLE_CPU_ARM64))
 
+#include <thread>
+#include <unordered_set>
+
 #include "libANGLE/renderer/gl/DisplayGL.h"
 
 #ifdef __OBJC__
@@ -35,6 +38,8 @@
 
     egl::Error initialize(egl::Display *display) override;
     void terminate() override;
+    egl::Error prepareForCall() override;
+    egl::Error releaseThread() override;
 
     SurfaceImpl *createWindowSurface(const egl::SurfaceState &state,
                                      EGLNativeWindowType window,
@@ -93,6 +98,8 @@
 
     egl::Display *mEGLDisplay;
     EAGLContextObj mContext;
+    std::unordered_set<std::thread::id> mThreadsWithContextCurrent;
+    bool mDeviceContextIsVolatile = false;
 };
 
 }  // namespace rx

Modified: trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/eagl/DisplayEAGL.mm (267868 => 267869)


--- trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/eagl/DisplayEAGL.mm	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/eagl/DisplayEAGL.mm	2020-10-02 07:05:42 UTC (rev 267869)
@@ -75,8 +75,12 @@
     {
         return egl::EglNotInitialized() << "Could not create the EAGL context.";
     }
-    [getEAGLContextClass() setCurrentContext:mContext];
 
+    if (![getEAGLContextClass() setCurrentContext:mContext]) {
+        return egl::EglNotInitialized() << "Could set the EAGL context current.";
+    }
+    mThreadsWithContextCurrent.insert(std::this_thread::get_id());
+
     // There is no equivalent getProcAddress in EAGL so we open the dylib directly
     void *handle = dlopen(kOpenGLESDylibName, RTLD_NOW);
     if (!handle)
@@ -95,6 +99,9 @@
         return egl::EglNotInitialized() << "OpenGL ES 2.0 is not supportable.";
     }
 
+    auto &attributes = display->getAttributeMap();
+    mDeviceContextIsVolatile = attributes.get(EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_EAGL_ANGLE, GL_FALSE);
+
     return DisplayGL::initialize(display);
 }
 
@@ -108,9 +115,38 @@
         [getEAGLContextClass() setCurrentContext:nil];
         [mContext release];
         mContext = nullptr;
+        mThreadsWithContextCurrent.clear();
     }
 }
 
+egl::Error DisplayEAGL::prepareForCall()
+{
+    auto threadId = std::this_thread::get_id();
+    if (mDeviceContextIsVolatile || mThreadsWithContextCurrent.find(threadId) == mThreadsWithContextCurrent.end())
+    {
+        if (![getEAGLContextClass() setCurrentContext:mContext])
+        {
+            return egl::EglBadAlloc() << "Could not make device EAGL context current.";
+        }
+        mThreadsWithContextCurrent.insert(threadId);
+    }
+    return egl::NoError();
+}
+
+egl::Error DisplayEAGL::releaseThread()
+{
+    auto threadId = std::this_thread::get_id();
+    if (mThreadsWithContextCurrent.find(threadId) != mThreadsWithContextCurrent.end())
+    {
+        if (![getEAGLContextClass() setCurrentContext:nil])
+        {
+            return egl::EglBadAlloc() << "Could not release device EAGL context.";
+        }
+        mThreadsWithContextCurrent.erase(threadId);
+    }
+    return egl::NoError();
+}
+
 SurfaceImpl *DisplayEAGL::createWindowSurface(const egl::SurfaceState &state,
                                               EGLNativeWindowType window,
                                               const egl::AttributeMap &attribs)

Modified: trunk/Source/ThirdParty/ANGLE/src/libANGLE/validationEGL.cpp (267868 => 267869)


--- trunk/Source/ThirdParty/ANGLE/src/libANGLE/validationEGL.cpp	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Source/ThirdParty/ANGLE/src/libANGLE/validationEGL.cpp	2020-10-02 07:05:42 UTC (rev 267869)
@@ -643,6 +643,34 @@
                 case EGL_PLATFORM_ANGLE_D3D_LUID_LOW_ANGLE:
                     luidSpecified = true;
                     break;
+                case EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_EAGL_ANGLE:
+                    // The property does not have an effect if it's not active, so do not check
+                    // for non-support.
+                    switch (value)
+                    {
+                        case EGL_FALSE:
+                        case EGL_TRUE:
+                            break;
+                        default:
+                            return EglBadAttribute() << "Invalid value for "
+                                                        "EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_"
+                                                        "EAGL_ANGLE attrib";
+                    }
+                    break;
+                case EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_CGL_ANGLE:
+                    // The property does not have an effect if it's not active, so do not check
+                    // for non-support.
+                    switch (value)
+                    {
+                        case EGL_FALSE:
+                        case EGL_TRUE:
+                            break;
+                        default:
+                            return EglBadAttribute() << "Invalid value for "
+                                                        "EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_"
+                                                        "CGL_ANGLE attrib";
+                    }
+                    break;
                 default:
                     break;
             }

Modified: trunk/Source/ThirdParty/ANGLE/src/libGLESv2/entry_points_egl.cpp (267868 => 267869)


--- trunk/Source/ThirdParty/ANGLE/src/libGLESv2/entry_points_egl.cpp	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Source/ThirdParty/ANGLE/src/libGLESv2/entry_points_egl.cpp	2020-10-02 07:05:42 UTC (rev 267869)
@@ -105,7 +105,8 @@
     egl::Display *display = static_cast<egl::Display *>(dpy);
     ANGLE_EGL_TRY_RETURN(thread, ValidateTerminate(display), "eglTerminate",
                          GetDisplayIfValid(display), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglTerminate",
+                         GetDisplayIfValid(display), EGL_FALSE);
     ANGLE_EGL_TRY_RETURN(thread, display->makeCurrent(thread, nullptr, nullptr, nullptr),
                          "eglTerminate", GetDisplayIfValid(display), EGL_FALSE);
     SetContextCurrent(thread, nullptr);
@@ -127,6 +128,8 @@
     {
         ANGLE_EGL_TRY_RETURN(thread, ValidateDisplay(display), "eglQueryString",
                              GetDisplayIfValid(display), nullptr);
+        ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglQueryString",
+                             GetDisplayIfValid(display), nullptr);
     }
 
     const char *result;
@@ -255,6 +258,8 @@
     ANGLE_EGL_TRY_RETURN(thread,
                          ValidateCreateWindowSurface(display, configuration, win, attributes),
                          "eglCreateWindowSurface", GetDisplayIfValid(display), EGL_NO_SURFACE);
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreateWindowSurface",
+                         GetDisplayIfValid(display), EGL_NO_SURFACE);
 
     egl::Surface *surface = nullptr;
     ANGLE_EGL_TRY_RETURN(thread,
@@ -281,7 +286,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateCreatePbufferSurface(display, configuration, attributes),
                          "eglCreatePbufferSurface", GetDisplayIfValid(display), EGL_NO_SURFACE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreatePbufferSurface",
+                         GetDisplayIfValid(display), EGL_NO_SURFACE);
     egl::Surface *surface = nullptr;
     ANGLE_EGL_TRY_RETURN(thread, display->createPbufferSurface(configuration, attributes, &surface),
                          "eglCreatePbufferSurface", GetDisplayIfValid(display), EGL_NO_SURFACE);
@@ -310,7 +316,8 @@
     ANGLE_EGL_TRY_RETURN(thread,
                          ValidateCreatePixmapSurface(display, configuration, pixmap, attributes),
                          "eglCreatePixmapSurface", GetDisplayIfValid(display), EGL_NO_SURFACE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreatePixmapSurface",
+                         GetDisplayIfValid(display), EGL_NO_SURFACE);
     egl::Surface *surface = nullptr;
     ANGLE_EGL_TRY_RETURN(thread,
                          display->createPixmapSurface(configuration, pixmap, attributes, &surface),
@@ -332,7 +339,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateDestroySurface(display, eglSurface, surface),
                          "eglDestroySurface", GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglDestroySurface",
+                         GetDisplayIfValid(display), EGL_FALSE);
     ANGLE_EGL_TRY_RETURN(thread, display->destroySurface(eglSurface), "eglDestroySurface",
                          GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
 
@@ -352,12 +360,13 @@
                (uintptr_t)dpy, (uintptr_t)surface, attribute, (uintptr_t)value);
     Thread *thread = egl::GetCurrentThread();
 
-    const egl::Display *display = static_cast<const egl::Display *>(dpy);
+    egl::Display *display = static_cast<egl::Display *>(dpy);
     const Surface *eglSurface   = static_cast<const Surface *>(surface);
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateQuerySurface(display, eglSurface, attribute, value),
                          "eglQuerySurface", GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglQuerySurface",
+                         GetDisplayIfValid(display), EGL_FALSE);
     ANGLE_EGL_TRY_RETURN(thread, QuerySurfaceAttrib(display, eglSurface, attribute, value),
                          "eglQuerySurface", GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
 
@@ -385,7 +394,8 @@
     ANGLE_EGL_TRY_RETURN(thread,
                          ValidateCreateContext(display, configuration, sharedGLContext, attributes),
                          "eglCreateContext", GetDisplayIfValid(display), EGL_NO_CONTEXT);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreateContext",
+                         GetDisplayIfValid(display), EGL_NO_CONTEXT);
     gl::Context *context = nullptr;
     ANGLE_EGL_TRY_RETURN(thread,
                          display->createContext(configuration, sharedGLContext, thread->getAPI(),
@@ -408,7 +418,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateDestroyContext(display, context, ctx), "eglDestroyContext",
                          GetContextIfValid(display, context), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglDestroyContext",
+                         GetDisplayIfValid(display), EGL_FALSE);
     bool contextWasCurrent = context == thread->getContext();
 
     ANGLE_EGL_TRY_RETURN(thread, display->destroyContext(thread, context), "eglDestroyContext",
@@ -443,7 +454,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateMakeCurrent(display, drawSurface, readSurface, context),
                          "eglMakeCurrent", GetContextIfValid(display, context), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglMakeCurrent",
+                         GetDisplayIfValid(display), EGL_FALSE);
     Surface *previousDraw        = thread->getCurrentDrawSurface();
     Surface *previousRead        = thread->getCurrentReadSurface();
     gl::Context *previousContext = thread->getContext();
@@ -517,7 +529,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateQueryContext(display, context, attribute, value),
                          "eglQueryContext", GetContextIfValid(display, context), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglQueryContext",
+                         GetDisplayIfValid(display), EGL_FALSE);
     QueryContextAttrib(context, attribute, value);
 
     thread->setSuccess();
@@ -534,6 +547,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateDisplay(display), "eglWaitGL", GetDisplayIfValid(display),
                          EGL_FALSE);
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglWaitGL",
+                         GetDisplayIfValid(display), EGL_FALSE);
 
     // eglWaitGL like calling eglWaitClient with the OpenGL ES API bound. Since we only implement
     // OpenGL ES we can do the call directly.
@@ -554,6 +569,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateWaitNative(display, engine), "eglWaitNative",
                          GetThreadIfValid(thread), EGL_FALSE);
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglWaitNative",
+                         GetDisplayIfValid(display), EGL_FALSE);
 
     ANGLE_EGL_TRY_RETURN(thread, display->waitNative(thread->getContext(), engine), "eglWaitNative",
                          GetThreadIfValid(thread), EGL_FALSE);
@@ -574,6 +591,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateSwapBuffers(thread, display, eglSurface), "eglSwapBuffers",
                          GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglSwapBuffers",
+                         GetDisplayIfValid(display), EGL_FALSE);
 
     ANGLE_EGL_TRY_RETURN(thread, eglSurface->swap(thread->getContext()), "eglSwapBuffers",
                          GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
@@ -598,7 +617,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateCopyBuffers(display, eglSurface), "eglCopyBuffers",
                          GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCopyBuffers",
+                         GetDisplayIfValid(display), EGL_FALSE);
     UNIMPLEMENTED();  // FIXME
 
     thread->setSuccess();
@@ -622,7 +642,8 @@
     ANGLE_EGL_TRY_RETURN(
         thread, ValidateBindTexImage(display, eglSurface, surface, buffer, context, &textureObject),
         "eglBindTexImage", GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglBindTexImage",
+                         GetDisplayIfValid(display), EGL_FALSE);
     if (context)
     {
         ANGLE_EGL_TRY_RETURN(thread, eglSurface->bindTexImage(context, textureObject, buffer),
@@ -650,7 +671,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateSurfaceAttrib(display, eglSurface, attribute, value),
                          "eglSurfaceAttrib", GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglSurfaceAttrib",
+                         GetDisplayIfValid(display), EGL_FALSE);
     SetSurfaceAttrib(eglSurface, attribute, value);
 
     thread->setSuccess();
@@ -671,6 +693,8 @@
     ANGLE_EGL_TRY_RETURN(thread, ValidateReleaseTexImage(display, eglSurface, surface, buffer),
                          "eglReleaseTexImage", GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
 
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglReleaseTexImage",
+                         GetDisplayIfValid(display), EGL_FALSE);
     gl::Texture *texture = eglSurface->getBoundTexture();
 
     if (texture)
@@ -697,7 +721,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateSwapInterval(display, draw_surface, context),
                          "eglSwapInterval", GetDisplayIfValid(display), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglSwapInterval",
+                         GetDisplayIfValid(display), EGL_FALSE);
     const egl::Config *surfaceConfig = draw_surface->getConfig();
     EGLint clampedInterval           = std::min(std::max(interval, surfaceConfig->minSwapInterval),
                                       surfaceConfig->maxSwapInterval);
@@ -759,7 +784,8 @@
         thread,
         ValidateCreatePbufferFromClientBuffer(display, buftype, buffer, configuration, attributes),
         "eglCreatePbufferFromClientBuffer", GetDisplayIfValid(display), EGL_NO_SURFACE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreatePbufferFromClientBuffer",
+                         GetDisplayIfValid(display), EGL_NO_SURFACE);
     egl::Surface *surface = nullptr;
     ANGLE_EGL_TRY_RETURN(thread,
                          display->createPbufferFromClientBuffer(configuration, buftype, buffer,
@@ -781,16 +807,19 @@
     gl::Context *previousContext  = thread->getContext();
     egl::Display *previousDisplay = thread->getDisplay();
 
-    // Only call makeCurrent if the context or surfaces have changed.
-    if (previousDraw != EGL_NO_SURFACE || previousRead != EGL_NO_SURFACE ||
-        previousContext != EGL_NO_CONTEXT)
-    {
-        if (previousDisplay != EGL_NO_DISPLAY)
+    if (previousDisplay != EGL_NO_DISPLAY) {
+        ANGLE_EGL_TRY_RETURN(thread, previousDisplay->prepareForCall(), "eglReleaseThread",
+                             GetDisplayIfValid(previousDisplay), EGL_FALSE);
+        // Only call makeCurrent if the context or surfaces have changed.
+        if (previousDraw != EGL_NO_SURFACE || previousRead != EGL_NO_SURFACE ||
+            previousContext != EGL_NO_CONTEXT)
         {
             ANGLE_EGL_TRY_RETURN(thread,
                                  previousDisplay->makeCurrent(thread, nullptr, nullptr, nullptr),
                                  "eglReleaseThread", nullptr, EGL_FALSE);
         }
+        ANGLE_EGL_TRY_RETURN(thread, previousDisplay->releaseThread(), "eglReleaseThread",
+                             GetDisplayIfValid(previousDisplay), EGL_FALSE);
 
         SetContextCurrent(thread, nullptr);
     }
@@ -810,7 +839,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateDisplay(display), "eglWaitClient",
                          GetContextIfValid(display, context), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglWaitClient",
+                         GetDisplayIfValid(display), EGL_FALSE);
     ANGLE_EGL_TRY_RETURN(thread, display->waitClient(context), "eglWaitClient",
                          GetContextIfValid(display, context), EGL_FALSE);
 
@@ -849,7 +879,8 @@
     ANGLE_EGL_TRY_RETURN(
         thread, ValidateCreateSync(display, type, attributes, currentDisplay, currentContext),
         "eglCreateSync", GetDisplayIfValid(display), EGL_NO_SYNC);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreateSync",
+                         GetDisplayIfValid(display), EGL_FALSE);
     egl::Sync *syncObject = nullptr;
     ANGLE_EGL_TRY_RETURN(thread, display->createSync(currentContext, type, attributes, &syncObject),
                          "eglCreateSync", GetDisplayIfValid(display), EGL_NO_SYNC);
@@ -870,7 +901,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateDestroySync(display, syncObject), "eglDestroySync",
                          GetDisplayIfValid(display), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglDestroySync",
+                         GetDisplayIfValid(display), EGL_FALSE);
     display->destroySync(syncObject);
 
     thread->setSuccess();
@@ -891,7 +923,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateClientWaitSync(display, syncObject, flags, timeout),
                          "eglClientWaitSync", GetSyncIfValid(display, syncObject), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglClientWaitSync",
+                         GetDisplayIfValid(display), EGL_FALSE);
     gl::Context *currentContext = thread->getContext();
     EGLint syncStatus           = EGL_FALSE;
     ANGLE_EGL_TRY_RETURN(
@@ -954,6 +987,8 @@
         thread->setError(error, GetDebug(), "eglCreateImage", GetDisplayIfValid(display));
         return EGL_NO_IMAGE;
     }
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreateImage",
+                         GetDisplayIfValid(display), EGL_FALSE);
 
     Image *image = nullptr;
     error        = display->createImage(context, target, buffer, attributes, &image);
@@ -982,7 +1017,8 @@
         thread->setError(error, GetDebug(), "eglDestroyImage", GetImageIfValid(display, img));
         return EGL_FALSE;
     }
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglDestroyImage",
+                         GetDisplayIfValid(display), EGL_FALSE);
     display->destroyImage(img);
 
     thread->setSuccess();
@@ -1043,12 +1079,13 @@
 
     ANGLE_EGL_TRY_RETURN(thread,
                          ValidateCreateWindowSurface(display, configuration, win, attributes),
-                         "eglCreateWindowSurface", GetDisplayIfValid(display), EGL_NO_SURFACE);
-
+                         "eglPlatformCreateWindowSurface", GetDisplayIfValid(display), EGL_NO_SURFACE);
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreateWindowSurface",
+                         GetDisplayIfValid(display), EGL_NO_SURFACE);
     egl::Surface *surface = nullptr;
     ANGLE_EGL_TRY_RETURN(thread,
                          display->createWindowSurface(configuration, win, attributes, &surface),
-                         "eglCreateWindowSurface", GetDisplayIfValid(display), EGL_NO_SURFACE);
+                         "eglPlatformCreateWindowSurface", GetDisplayIfValid(display), EGL_NO_SURFACE);
 
     return static_cast<EGLSurface>(surface);
 }
@@ -1075,7 +1112,8 @@
     ANGLE_EGL_TRY_RETURN(
         thread, ValidateCreatePixmapSurface(display, configuration, pixmap, attributes),
         "eglCreatePlatformPixmapSurface", GetDisplayIfValid(display), EGL_NO_SURFACE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreatePlatformPixmapSurface",
+                         GetDisplayIfValid(display), EGL_NO_SURFACE);
     egl::Surface *surface = nullptr;
     ANGLE_EGL_TRY_RETURN(
         thread, display->createPixmapSurface(configuration, pixmap, attributes, &surface),
@@ -1099,7 +1137,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateWaitSync(display, context, syncObject, flags),
                          "eglWaitSync", GetSyncIfValid(display, syncObject), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglWaitSync",
+                         GetDisplayIfValid(display), EGL_FALSE);
     gl::Context *currentContext = thread->getContext();
     ANGLE_EGL_TRY_RETURN(thread, syncObject->serverWait(display, currentContext, flags),
                          "eglWaitSync", GetSyncIfValid(display, syncObject), EGL_FALSE);

Modified: trunk/Source/ThirdParty/ANGLE/src/libGLESv2/entry_points_egl_ext.cpp (267868 => 267869)


--- trunk/Source/ThirdParty/ANGLE/src/libGLESv2/entry_points_egl_ext.cpp	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Source/ThirdParty/ANGLE/src/libGLESv2/entry_points_egl_ext.cpp	2020-10-02 07:05:42 UTC (rev 267869)
@@ -86,7 +86,8 @@
                              GetSurfaceIfValid(display, eglSurface));
             return EGL_FALSE;
     }
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglQuerySurfacePointerANGLE",
+                         GetDisplayIfValid(display), EGL_FALSE);
     error = eglSurface->querySurfacePointerANGLE(attribute, value);
     if (error.isError())
     {
@@ -151,7 +152,8 @@
         thread->setSuccess();
         return EGL_TRUE;
     }
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglPostSubBufferNV",
+                         GetDisplayIfValid(display), EGL_FALSE);
     // TODO(jmadill): Validate Surface is bound to the thread.
     error = eglSurface->postSubBuffer(thread->getContext(), x, y, width, height);
     if (error.isError())
@@ -223,7 +225,8 @@
         thread,
         ValidateCreatePlatformWindowSurfaceEXT(display, configuration, native_window, attributes),
         "eglCreatePlatformWindowSurfaceEXT", GetDisplayIfValid(display), EGL_NO_SURFACE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreatePlatformWindowSurfaceEXT",
+                         GetDisplayIfValid(display), EGL_NO_SURFACE);
     thread->setError(EglBadDisplay() << "CreatePlatformWindowSurfaceEXT unimplemented.", GetDebug(),
                      "eglCreatePlatformWindowSurfaceEXT", GetDisplayIfValid(display));
     return EGL_NO_SURFACE;
@@ -250,7 +253,8 @@
         thread,
         ValidateCreatePlatformPixmapSurfaceEXT(display, configuration, native_pixmap, attributes),
         "eglCreatePlatformPixmapSurfaceEXT", GetDisplayIfValid(display), EGL_NO_SURFACE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreatePlatformPixmapSurfaceEXT",
+                         GetDisplayIfValid(display), EGL_NO_SURFACE);
     thread->setError(EglBadDisplay() << "CreatePlatformPixmapSurfaceEXT unimplemented.", GetDebug(),
                      "eglCreatePlatformPixmapSurfaceEXT", GetDisplayIfValid(display));
     return EGL_NO_SURFACE;
@@ -275,10 +279,11 @@
         thread->setError(error, GetDebug(), "eglQueryDeviceAttribEXT", GetDeviceIfValid(dev));
         return EGL_FALSE;
     }
-
+    egl::Display *owningDisplay = dev->getOwningDisplay();
+    ANGLE_EGL_TRY_RETURN(thread, owningDisplay->prepareForCall(), "eglQueryDeviceAttribEXT",
+                         GetDisplayIfValid(owningDisplay), EGL_FALSE);
     // If the device was created by (and is owned by) a display, and that display doesn't support
     // device querying, then this call should fail
-    egl::Display *owningDisplay = dev->getOwningDisplay();
     if (owningDisplay != nullptr && !owningDisplay->getExtensions().deviceQuery)
     {
         thread->setError(EglBadAccess() << "Device wasn't created using eglCreateDeviceANGLE, "
@@ -351,7 +356,9 @@
         thread->setError(error, GetDebug(), "eglQueryDeviceStringEXT", GetDeviceIfValid(dev));
         return EGL_FALSE;
     }
-
+    egl::Display *owningDisplay = dev->getOwningDisplay();
+    ANGLE_EGL_TRY_RETURN(thread, owningDisplay->prepareForCall(), "eglQueryDeviceStringEXT",
+                         GetDisplayIfValid(owningDisplay), EGL_FALSE);
     const char *result;
     switch (name)
     {
@@ -381,7 +388,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateQueryDisplayAttribEXT(display, attribute),
                          "eglQueryDisplayAttribEXT", GetDisplayIfValid(display), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglQueryDisplayAttribEXT",
+                         GetDisplayIfValid(display), EGL_FALSE);
     *value = display->queryAttrib(attribute);
     thread->setSuccess();
     return EGL_TRUE;
@@ -402,7 +410,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateQueryDisplayAttribANGLE(display, attribute),
                          "eglQueryDisplayAttribANGLE", GetDisplayIfValid(display), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglQueryDisplayAttribANGLE",
+                         GetDisplayIfValid(display), EGL_FALSE);
     *value = display->queryAttrib(attribute);
     thread->setSuccess();
     return EGL_TRUE;
@@ -433,7 +442,8 @@
         thread->setError(error, GetDebug(), "eglCreateImageKHR", GetDisplayIfValid(display));
         return EGL_NO_IMAGE;
     }
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreateImageKHR",
+                         GetDisplayIfValid(display), EGL_NO_IMAGE);
     Image *image = nullptr;
     error        = display->createImage(context, target, buffer, attributes, &image);
     if (error.isError())
@@ -462,7 +472,8 @@
         thread->setError(error, GetDebug(), "eglDestroyImageKHR", GetImageIfValid(display, img));
         return EGL_FALSE;
     }
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglDestroyImageKHR",
+                         GetDisplayIfValid(display), EGL_FALSE);
     display->destroyImage(img);
 
     thread->setSuccess();
@@ -538,7 +549,8 @@
         thread->setError(error, GetDebug(), "eglCreateStreamKHR", GetDisplayIfValid(display));
         return EGL_NO_STREAM_KHR;
     }
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreateStreamKHR",
+                         GetDisplayIfValid(display), EGL_NO_STREAM_KHR);
     Stream *stream;
     error = display->createStream(attributes, &stream);
     if (error.isError())
@@ -568,7 +580,8 @@
                          GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglDestroyStreamKHR",
+                         GetDisplayIfValid(display), EGL_FALSE);
     display->destroyStream(streamObject);
 
     thread->setSuccess();
@@ -597,7 +610,8 @@
                          GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglStreamAttribKHR",
+                         GetDisplayIfValid(display), EGL_FALSE);
     switch (attribute)
     {
         case EGL_CONSUMER_LATENCY_USEC_KHR:
@@ -636,7 +650,8 @@
                          GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglQueryStreamKHR",
+                         GetDisplayIfValid(display), EGL_FALSE);
     switch (attribute)
     {
         case EGL_STREAM_STATE_KHR:
@@ -678,7 +693,8 @@
                          GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglQueryStreamu64KHR",
+                         GetDisplayIfValid(display), EGL_FALSE);
     switch (attribute)
     {
         case EGL_PRODUCER_FRAME_KHR:
@@ -713,7 +729,8 @@
                          GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglStreamConsumerGLTextureExternalKHR",
+                         GetDisplayIfValid(display), EGL_FALSE);
     error = streamObject->createConsumerGLTextureExternal(AttributeMap(), context);
     if (error.isError())
     {
@@ -744,7 +761,8 @@
                          GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglStreamConsumerAcquireKHR",
+                         GetDisplayIfValid(display), EGL_FALSE);
     error = streamObject->consumerAcquire(context);
     if (error.isError())
     {
@@ -775,7 +793,8 @@
                          GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglStreamConsumerReleaseKHR",
+                         GetDisplayIfValid(display), EGL_FALSE);
     error = streamObject->consumerRelease(context);
     if (error.isError())
     {
@@ -811,7 +830,8 @@
                          GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglStreamConsumerGLTextureExternalAttribsNV",
+                         GetDisplayIfValid(display), EGL_FALSE);
     error = streamObject->createConsumerGLTextureExternal(attributes, context);
     if (error.isError())
     {
@@ -845,7 +865,8 @@
                          GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreateStreamProducerD3DTextureANGLE",
+                         GetDisplayIfValid(display), EGL_FALSE);
     error = streamObject->createProducerD3D11Texture(attributes);
     if (error.isError())
     {
@@ -882,7 +903,8 @@
                          GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglStreamPostD3DTextureANGLE",
+                         GetDisplayIfValid(display), EGL_FALSE);
     error = streamObject->postD3D11Texture(texture, attributes);
     if (error.isError())
     {
@@ -915,7 +937,8 @@
     ANGLE_EGL_TRY_RETURN(
         thread, ValidateCreateSyncKHR(display, type, attributes, currentDisplay, currentContext),
         "eglCreateSync", GetDisplayIfValid(display), EGL_NO_SYNC);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglCreateSync",
+                         GetDisplayIfValid(display), EGL_NO_SYNC);
     egl::Sync *syncObject = nullptr;
     ANGLE_EGL_TRY_RETURN(thread, display->createSync(currentContext, type, attributes, &syncObject),
                          "eglCreateSync", GetDisplayIfValid(display), EGL_NO_SYNC);
@@ -936,7 +959,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateDestroySync(display, syncObject), "eglDestroySync",
                          GetDisplayIfValid(display), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglDestroySync",
+                         GetDisplayIfValid(display), EGL_FALSE);
     display->destroySync(syncObject);
 
     thread->setSuccess();
@@ -960,7 +984,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateClientWaitSync(display, syncObject, flags, timeout),
                          "eglClientWaitSync", GetSyncIfValid(display, syncObject), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglClientWaitSync",
+                         GetDisplayIfValid(display), EGL_FALSE);
     gl::Context *currentContext = thread->getContext();
     EGLint syncStatus           = EGL_FALSE;
     ANGLE_EGL_TRY_RETURN(
@@ -988,7 +1013,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateGetSyncAttribKHR(display, syncObject, attribute, value),
                          "eglGetSyncAttrib", GetSyncIfValid(display, syncObject), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglGetSyncAttrib",
+                         GetDisplayIfValid(display), EGL_FALSE);
     ANGLE_EGL_TRY_RETURN(thread, GetSyncAttrib(display, syncObject, attribute, value),
                          "eglGetSyncAttrib", GetSyncIfValid(display, syncObject), EGL_FALSE);
 
@@ -1011,7 +1037,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateWaitSync(display, context, syncObject, flags),
                          "eglWaitSync", GetSyncIfValid(display, syncObject), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglWaitSync",
+                         GetDisplayIfValid(display), EGL_FALSE);
     gl::Context *currentContext = thread->getContext();
     ANGLE_EGL_TRY_RETURN(thread, syncObject->serverWait(display, currentContext, flags),
                          "eglWaitSync", GetSyncIfValid(display, syncObject), EGL_FALSE);
@@ -1043,7 +1070,8 @@
                          GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglGetMscRateANGLE",
+                         GetDisplayIfValid(display), EGL_FALSE);
     error = eglSurface->getMscRate(numerator, denominator);
     if (error.isError())
     {
@@ -1080,7 +1108,8 @@
                          GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglGetSyncValuesCHROMIUM",
+                         GetDisplayIfValid(display), EGL_FALSE);
     error = eglSurface->getSyncValues(ust, msc, sbc);
     if (error.isError())
     {
@@ -1116,7 +1145,8 @@
                          GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglSwapBuffersWithDamageEXT",
+                         GetDisplayIfValid(display), EGL_FALSE);
     error = eglSurface->swapWithDamage(thread->getContext(), rects, n_rects);
     if (error.isError())
     {
@@ -1145,6 +1175,8 @@
     ANGLE_EGL_TRY_RETURN(thread, ValidatePresentationTimeANDROID(display, eglSurface, time),
                          "eglPresentationTimeANDROID", GetSurfaceIfValid(display, eglSurface),
                          EGL_FALSE);
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglPresentationTimeANDROID",
+                         GetDisplayIfValid(display), EGL_FALSE);
     ANGLE_EGL_TRY_RETURN(thread, eglSurface->setPresentationTime(time),
                          "eglPresentationTimeANDROID", GetSurfaceIfValid(display, eglSurface),
                          EGL_FALSE);
@@ -1166,7 +1198,8 @@
 
     ANGLE_EGL_TRY(thread, ValidateSetBlobCacheANDROID(display, set, get),
                   "eglSetBlobCacheFuncsANDROID", GetDisplayIfValid(display));
-
+    ANGLE_EGL_TRY(thread, display->prepareForCall(), "eglSetBlobCacheFuncsANDROID",
+                  GetDisplayIfValid(display));
     thread->setSuccess();
     display->setBlobCacheFuncs(set, get);
 }
@@ -1181,7 +1214,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateProgramCacheGetAttribANGLE(display, attrib),
                          "eglProgramCacheGetAttribANGLE", GetDisplayIfValid(display), 0);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglProgramCacheGetAttribANGLE",
+                         GetDisplayIfValid(display), 0);
     thread->setSuccess();
     return display->programCacheGetAttrib(attrib);
 }
@@ -1206,7 +1240,8 @@
     ANGLE_EGL_TRY(thread,
                   ValidateProgramCacheQueryANGLE(display, index, key, keysize, binary, binarysize),
                   "eglProgramCacheQueryANGLE", GetDisplayIfValid(display));
-
+    ANGLE_EGL_TRY(thread, display->prepareForCall(), "eglProgramCacheQueryANGLE",
+                  GetDisplayIfValid(display));
     ANGLE_EGL_TRY(thread, display->programCacheQuery(index, key, keysize, binary, binarysize),
                   "eglProgramCacheQueryANGLE", GetDisplayIfValid(display));
 
@@ -1231,7 +1266,8 @@
     ANGLE_EGL_TRY(thread,
                   ValidateProgramCachePopulateANGLE(display, key, keysize, binary, binarysize),
                   "eglProgramCachePopulateANGLE", GetDisplayIfValid(display));
-
+    ANGLE_EGL_TRY(thread, display->prepareForCall(), "eglProgramCachePopulateANGLE",
+                  GetDisplayIfValid(display));
     ANGLE_EGL_TRY(thread, display->programCachePopulate(key, keysize, binary, binarysize),
                   "eglProgramCachePopulateANGLE", GetDisplayIfValid(display));
 
@@ -1249,7 +1285,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateProgramCacheResizeANGLE(display, limit, mode),
                          "eglProgramCacheResizeANGLE", GetDisplayIfValid(display), 0);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglProgramCacheResizeANGLE",
+                  GetDisplayIfValid(display), 0);
     thread->setSuccess();
     return display->programCacheResize(limit, mode);
 }
@@ -1340,7 +1377,13 @@
                          GetLabeledObjectIfValid(thread, display, objectTypePacked, object));
         return error.getCode();
     }
-
+    error = display->prepareForCall();
+    if (error.isError())
+    {
+        thread->setError(error, GetDebug(), "eglLabelObjectKHR",
+                         GetDisplayIfValid(display));
+        return error.getCode();
+    }
     LabeledObject *labeledObject =
         GetLabeledObjectIfValid(thread, display, objectTypePacked, object);
     ASSERT(labeledObject != nullptr);
@@ -1394,6 +1437,8 @@
         thread,
         ValidateGetCompositorTimingANDROID(display, eglSurface, numTimestamps, names, values),
         "eglGetCompositorTimingANDROIDD", GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglGetCompositorTimingANDROIDD",
+                  GetDisplayIfValid(display), EGL_FALSE);
     ANGLE_EGL_TRY_RETURN(thread, eglSurface->getCompositorTiming(numTimestamps, names, values),
                          "eglGetCompositorTimingANDROIDD", GetSurfaceIfValid(display, eglSurface),
                          EGL_FALSE);
@@ -1418,6 +1463,8 @@
     ANGLE_EGL_TRY_RETURN(thread, ValidateGetNextFrameIdANDROID(display, eglSurface, frameId),
                          "eglGetNextFrameIdANDROID", GetSurfaceIfValid(display, eglSurface),
                          EGL_FALSE);
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglGetNextFrameIdANDROID",
+                  GetDisplayIfValid(display), EGL_FALSE);
     ANGLE_EGL_TRY_RETURN(thread, eglSurface->getNextFrameId(frameId), "eglGetNextFrameIdANDROID",
                          GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
 
@@ -1443,7 +1490,8 @@
     ANGLE_EGL_TRY_RETURN(
         thread, ValidateGetFrameTimestampSupportedANDROID(display, eglSurface, timestampInternal),
         "eglQueryTimestampSupportedANDROID", GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglQueryTimestampSupportedANDROID",
+                  GetDisplayIfValid(display), EGL_FALSE);
     thread->setSuccess();
     return eglSurface->getSupportedTimestamps().test(timestampInternal);
 }
@@ -1472,6 +1520,8 @@
                                                            numTimestamps, timestamps, values),
                          "eglGetFrameTimestampsANDROID", GetSurfaceIfValid(display, eglSurface),
                          EGL_FALSE);
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglGetFrameTimestampsANDROID",
+                  GetDisplayIfValid(display), EGL_FALSE);
     ANGLE_EGL_TRY_RETURN(
         thread, eglSurface->getFrameTimestamps(frameId, numTimestamps, timestamps, values),
         "eglGetFrameTimestampsANDROID", GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
@@ -1494,7 +1544,8 @@
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateQueryStringiANGLE(display, name, index),
                          "eglQueryStringiANGLE", GetDisplayIfValid(display), nullptr);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglQueryStringiANGLE",
+                  GetDisplayIfValid(display), nullptr);
     thread->setSuccess();
     return display->queryStringi(name, index);
 }
@@ -1526,7 +1577,8 @@
     ANGLE_EGL_TRY_RETURN(thread, ValidateDupNativeFenceFDANDROID(display, syncObject),
                          "eglDupNativeFenceFDANDROID", GetSyncIfValid(display, syncObject),
                          EGL_NO_NATIVE_FENCE_FD_ANDROID);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglDupNativeFenceFDANDROID",
+                         GetDisplayIfValid(display), EGL_NO_NATIVE_FENCE_FD_ANDROID);
     EGLint result = EGL_NO_NATIVE_FENCE_FD_ANDROID;
     ANGLE_EGL_TRY_RETURN(thread, syncObject->dupNativeFenceFD(display, &result),
                          "eglDupNativeFenceFDANDROID", GetSyncIfValid(display, syncObject),
@@ -1552,7 +1604,8 @@
     ANGLE_EGL_TRY_RETURN(
         thread, ValidateSwapBuffersWithFrameTokenANGLE(display, eglSurface, frametoken),
         "eglSwapBuffersWithFrameTokenANGLE", GetDisplayIfValid(display), EGL_FALSE);
-
+    ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglSwapBuffersWithFrameTokenANGLE",
+                         GetDisplayIfValid(display), EGL_FALSE);
     ANGLE_EGL_TRY_RETURN(thread, eglSurface->swapWithFrameToken(thread->getContext(), frametoken),
                          "eglSwapBuffersWithFrameTokenANGLE", GetDisplayIfValid(display),
                          EGL_FALSE);
@@ -1573,6 +1626,8 @@
 
     ANGLE_EGL_TRY(thread, ValidateContext(display, context), "eglReleaseHighPowerGPUANGLE",
                   GetDisplayIfValid(display));
+    ANGLE_EGL_TRY(thread, display->prepareForCall(), "eglReleaseHighPowerGPUANGLE",
+                  GetDisplayIfValid(display));
     ANGLE_EGL_TRY(thread, context->releaseHighPowerGPU(), "eglReleaseHighPowerGPUANGLE",
                   GetDisplayIfValid(display));
 
@@ -1591,6 +1646,8 @@
 
     ANGLE_EGL_TRY(thread, ValidateContext(display, context), "eglReacquireHighPowerGPUANGLE",
                   GetDisplayIfValid(display));
+    ANGLE_EGL_TRY(thread, display->prepareForCall(), "eglReacquireHighPowerGPUANGLE",
+                  GetDisplayIfValid(display));
     ANGLE_EGL_TRY(thread, context->reacquireHighPowerGPU(), "eglReacquireHighPowerGPUANGLE",
                   GetDisplayIfValid(display));
 
@@ -1607,6 +1664,8 @@
 
     ANGLE_EGL_TRY(thread, ValidateDisplay(display), "eglHandleGPUSwitchANGLE",
                   GetDisplayIfValid(display));
+    ANGLE_EGL_TRY(thread, display->prepareForCall(), "eglHandleGPUSwitchANGLE",
+                  GetDisplayIfValid(display));
     ANGLE_EGL_TRY(thread, display->handleGPUSwitch(), "eglHandleGPUSwitchANGLE",
                   GetDisplayIfValid(display));
 

Modified: trunk/Source/WebCore/ChangeLog (267868 => 267869)


--- trunk/Source/WebCore/ChangeLog	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Source/WebCore/ChangeLog	2020-10-02 07:05:42 UTC (rev 267869)
@@ -1,3 +1,75 @@
+2020-10-02  Kimmo Kinnunen  <[email protected]>
+
+        [iOS WK1] Crashes when using ANGLE WebGL from another thread
+        https://bugs.webkit.org/show_bug.cgi?id=216106
+        <rdar://problem/68602452>
+
+        Reviewed by Kenneth Russell.
+
+        Source of the bug comes from following:
+          - WK1 might run WebKit code in client main thread.
+          - WK1 might run Webkit code in web thread.
+          - WebKit code might run WebGL payload, notably access
+            GraphicsContextGL classes.
+            Client is able to modify EAGL/CGL current context.
+
+        The change to ANGLE incurred two distinct behavior changes
+        compared to raw EAGL / CGL:
+        1) Before: context was set current before any GL call
+        After: context was set current only if EGL current context
+        had been changed. (Explicit code as well as ANGLE implementation
+        optimization.)
+
+        2) Before: context being used was able to be current in
+        multiple threads at the same time. (EAGL/CGL feature)
+        After: context cannot be current in multiple threads
+        at the same time. (EGL feature)
+
+        Change in behavior 1) caused ANGLE to sometimes use
+        the EAGL/CGL context of the client instead of
+        the real context that ANGLE created.
+        Fix this by introducing
+        EGL_ANGLE_platform_angle_device_context_volatile_eagl
+        and
+        EGL_ANGLE_platform_angle_device_context_volatile_cgl
+        which make ANGLE sync the context on each eglMakeCurrent
+        eglReleaseThread and eglTerminate.
+
+        Change in behavior 2) caused ANGLE to use uninitialized
+        context object from one thread, if the real context object
+        was current in another thread.
+        Fix this by considering "GraphicsContextGLOpenGL current context"
+        as part of "data that is owned by WebCoreThread lock".
+        The current context is set with lock held, implicitly.
+        The current context is released when lock is released.
+        When the lock is not held, GraphicsContextGLOpenGL current context
+        is nullptr.
+
+        Adds soft linking for EAGL for the purpose of testing this in
+        TestWebKitAPI. The case of Apple Silicon Mac may sometimes
+        use CGL and sometimes EAGL, and the test should test that
+        client overriding both contexts will not cause problems.
+
+        Fix ANGLE header include path:
+         - Do not include ANGLE in the path, as files are included with ANGLE/
+         - Add WK_ALTERNATE_FRAMEWORKS_DIR so that SDK_VARIANT=iosmac
+           e.g. maccatalyst builds work
+        Previously the ANGLE was not included from ThirdParty/ANGLE, rather
+        "WebKit SDK".
+
+        * Configurations/WebCore.xcconfig:
+        * platform/graphics/cocoa/GraphicsContextGLOpenGLCocoa.mm:
+        (WebCore::GraphicsContextGLOpenGL::GraphicsContextGLOpenGL):
+        (WebCore::GraphicsContextGLOpenGL::~GraphicsContextGLOpenGL):
+        (WebCore::GraphicsContextGLOpenGL::makeContextCurrent):
+        (WebCore::GraphicsContextGLOpenGL::releaseCurrentContext):
+        (WebCore::GraphicsContextGLOpenGL::checkGPUStatus):
+        (WebCore::GraphicsContextGLOpenGL::allowOfflineRenderers const):
+        * platform/graphics/opengl/GraphicsContextGLOpenGL.h:
+        * platform/ios/wak/WebCoreThread.mm:
+        (WebThreadUnlockFromAnyThread):
+        (_WebThreadUnlock):
+
 2020-10-01  Rob Buis  <[email protected]>
 
         update FormData to latest spec webidl

Modified: trunk/Source/WebCore/Configurations/WebCore.xcconfig (267868 => 267869)


--- trunk/Source/WebCore/Configurations/WebCore.xcconfig	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Source/WebCore/Configurations/WebCore.xcconfig	2020-10-02 07:05:42 UTC (rev 267869)
@@ -48,7 +48,7 @@
 LIBRARY_SEARCH_PATHS = $(inherited) "$(WK_LIBWEBRTC_LIBRARY_DIR)";
 
 WEBKITADDITIONS_HEADER_SEARCH_PATHS = $(BUILT_PRODUCTS_DIR)/usr/local/include/WebKitAdditions $(SDKROOT)/usr/local/include/WebKitAdditions;
-ANGLE_HEADER_SEARCH_PATHS = $(BUILT_PRODUCTS_DIR)/usr/local/include/ANGLE $(SDKROOT)/usr/local/include/ANGLE;
+ANGLE_HEADER_SEARCH_PATHS = $(BUILT_PRODUCTS_DIR)$(WK_ALTERNATE_FRAMEWORKS_DIR)/usr/local/include/ $(SDKROOT)$(WK_ALTERNATE_WEBKIT_SDK_PATH)/usr/local/include/;
 LIBWEBRTC_HEADER_SEARCH_PATHS = $(BUILT_PRODUCTS_DIR)/usr/local/include/webrtc $(SDKROOT)/usr/local/include/webrtc $(BUILT_PRODUCTS_DIR)/usr/local/include/webrtc/sdk/objc/Framework/Headers $(SDKROOT)/usr/local/include/webrtc/sdk/objc/Framework/Headers;
 
 HEADER_SEARCH_PATHS = PAL ForwardingHeaders /usr/include/libxslt /usr/include/libxml2 "$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore" "$(BUILT_PRODUCTS_DIR)/usr/local/include" $(WEBKITADDITIONS_HEADER_SEARCH_PATHS) $(ANGLE_HEADER_SEARCH_PATHS) $(LIBWEBRTC_HEADER_SEARCH_PATHS) $(HEADER_SEARCH_PATHS) $(SRCROOT);

Modified: trunk/Source/WebCore/platform/graphics/cocoa/GraphicsContextGLOpenGLCocoa.mm (267868 => 267869)


--- trunk/Source/WebCore/platform/graphics/cocoa/GraphicsContextGLOpenGLCocoa.mm	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Source/WebCore/platform/graphics/cocoa/GraphicsContextGLOpenGLCocoa.mm	2020-10-02 07:05:42 UTC (rev 267869)
@@ -80,6 +80,8 @@
 #import "ExtensionsGLOpenGL.h"
 #elif USE(ANGLE)
 #import "ExtensionsGLANGLE.h"
+#import "RuntimeApplicationChecks.h"
+#import "WebCoreThread.h"
 #endif
 
 #if PLATFORM(MAC)
@@ -91,6 +93,69 @@
 
 namespace WebCore {
 
+namespace {
+
+#if USE(ANGLE)
+
+#if ASSERT_ENABLED
+// Returns true if we have volatile context extension for the particular API or
+// if the particular API is not used.
+bool checkVolatileContextSupportIfDeviceExists(EGLDisplay display, const char* deviceContextVolatileExtension,
+    const char* deviceContextExtension, EGLint deviceContextType)
+{
+    const char *clientExtensions = EGL_QueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+    if (clientExtensions && strstr(clientExtensions, deviceContextVolatileExtension))
+        return true;
+    EGLDeviceEXT device = EGL_NO_DEVICE_EXT;
+    if (!EGL_QueryDisplayAttribEXT(display, EGL_DEVICE_EXT, reinterpret_cast<EGLAttrib*>(&device)))
+        return true;
+    if (device == EGL_NO_DEVICE_EXT)
+        return true;
+    const char* deviceExtensions = EGL_QueryDeviceStringEXT(device, EGL_EXTENSIONS);
+    if (!deviceExtensions || !strstr(deviceExtensions, deviceContextExtension))
+        return true;
+    void* deviceContext = nullptr;
+    if (!EGL_QueryDeviceAttribEXT(device, deviceContextType, reinterpret_cast<EGLAttrib*>(&deviceContext)))
+        return true;
+    return !deviceContext;
+}
+#endif
+
+EGLDisplay InitializeEGLDisplay()
+{
+    EGLint majorVersion = 0;
+    EGLint minorVersion = 0;
+    EGLDisplay display;
+    bool shouldInitializeWithVolatileContextSupport = !isInWebProcess();
+    if (shouldInitializeWithVolatileContextSupport) {
+        // For WK1 type APIs we need to set "volatile platform context" for specific
+        // APIs, since client code will be able to override the thread-global context
+        // that ANGLE expects.
+        EGLint displayAttributes[] = {
+            EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_EAGL_ANGLE, EGL_TRUE,
+            EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_CGL_ANGLE, EGL_TRUE,
+            EGL_NONE
+        };
+        display = EGL_GetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), displayAttributes);
+    } else
+        display = EGL_GetDisplay(EGL_DEFAULT_DISPLAY);
+
+    if (EGL_Initialize(display, &majorVersion, &minorVersion) == EGL_FALSE) {
+        LOG(WebGL, "EGLDisplay Initialization failed.");
+        return EGL_NO_DISPLAY;
+    }
+    LOG(WebGL, "ANGLE initialised Major: %d Minor: %d", majorVersion, minorVersion);
+    if (shouldInitializeWithVolatileContextSupport) {
+        // After initialization, EGL_DEFAULT_DISPLAY will return the platform-customized display.
+        ASSERT(display == EGL_GetDisplay(EGL_DEFAULT_DISPLAY));
+        ASSERT(checkVolatileContextSupportIfDeviceExists(display, "EGL_ANGLE_platform_device_context_volatile_eagl", "EGL_ANGLE_device_eagl", EGL_EAGL_CONTEXT_ANGLE));
+        ASSERT(checkVolatileContextSupportIfDeviceExists(display, "EGL_ANGLE_platform_device_context_volatile_cgl", "EGL_ANGLE_device_cgl", EGL_CGL_CONTEXT_ANGLE));
+    }
+    return display;
+}
+#endif
+}
+
 static const unsigned statusCheckThreshold = 5;
 
 // FIXME: This class is currently empty on Mac, but will get populated as
@@ -316,16 +381,9 @@
         ::glEnable(GraphicsContextGL::PRIMITIVE_RESTART);
 
 #elif USE(ANGLE)
-
-    m_displayObj = EGL_GetDisplay(EGL_DEFAULT_DISPLAY);
+    m_displayObj = InitializeEGLDisplay();
     if (m_displayObj == EGL_NO_DISPLAY)
         return;
-    EGLint majorVersion, minorVersion;
-    if (EGL_Initialize(m_displayObj, &majorVersion, &minorVersion) == EGL_FALSE) {
-        LOG(WebGL, "EGLDisplay Initialization failed.");
-        return;
-    }
-    LOG(WebGL, "ANGLE initialised Major: %d Minor: %d", majorVersion, minorVersion);
     const char *displayExtensions = EGL_QueryString(m_displayObj, EGL_EXTENSIONS);
     LOG(WebGL, "Extensions: %s", displayExtensions);
 
@@ -578,17 +636,13 @@
 
     if (m_contextObj) {
         GraphicsContextGLAttributes attrs = contextAttributes();
-
+        makeContextCurrent(); // TODO: check result.
 #if USE(OPENGL_ES)
-        makeContextCurrent();
         [static_cast<EAGLContext *>(m_contextObj) renderbufferStorage:GL_RENDERBUFFER fromDrawable:nil];
         ::glDeleteRenderbuffers(1, &m_texture);
 #elif USE(OPENGL)
-        CGLContextObj cglContext = static_cast<CGLContextObj>(m_contextObj);
-        CGLSetCurrentContext(cglContext);
         ::glDeleteTextures(1, &m_texture);
 #elif USE(ANGLE)
-        EGL_MakeCurrent(m_displayObj, EGL_NO_SURFACE, EGL_NO_SURFACE, m_contextObj);
         gl::DeleteTextures(1, &m_texture);
 #endif
 
@@ -707,12 +761,50 @@
     if (currentContext != m_contextObj)
         return CGLSetCurrentContext(static_cast<CGLContextObj>(m_contextObj)) == kCGLNoError;
 #elif USE(ANGLE)
-    if (EGL_GetCurrentContext() != m_contextObj)
-        return EGL_MakeCurrent(m_displayObj, EGL_NO_SURFACE, EGL_NO_SURFACE, m_contextObj);
+    // ANGLE has an early out for case where nothing changes. Calling MakeCurrent
+    // is important to set volatile platform context. See InitializeEGLDisplay().
+    if (!EGL_MakeCurrent(m_displayObj, EGL_NO_SURFACE, EGL_NO_SURFACE, m_contextObj))
+        return false;
 #endif
     return true;
 }
 
+#if PLATFORM(IOS_FAMILY) && USE(ANGLE)
+bool GraphicsContextGLOpenGL::releaseCurrentContext(ReleaseBehavior releaseBehavior)
+{
+    // At the moment this function is relevant only when web thread lock owns the GraphicsContextGLOpenGL current context.
+    ASSERT(!WebCore::isInWebProcess());
+
+    if (!EGL_BindAPI(EGL_OPENGL_ES_API))
+        return false;
+    if (EGL_GetCurrentContext() == EGL_NO_CONTEXT)
+        return true;
+
+    // At the time of writing, ANGLE does not flush on MakeCurrent. Since we are
+    // potentially switching threads, we should flush.
+    // Note: Here we assume also that ANGLE has only one platform context -- otherwise
+    // we would need to flush each EGL context that has been used.
+    gl::Flush();
+
+    // Unset the EGL current context, since the next access might be from another thread, and the
+    // context cannot be current on multiple threads.
+
+    if (releaseBehavior == ReleaseBehavior::ReleaseThreadResources) {
+        // Called when we do not know if we will ever see another call from this thread again.
+        // Unset the EGL current context by releasing whole EGL thread state.
+        // Theoretically ReleaseThread can reset the bound API, so the rest of the code mentions BindAPI/QueryAPI.
+        return EGL_ReleaseThread();
+    }
+    // On WebKit owned threads, WebKit is able to choose the time for the EGL cleanup.
+    // This is why we only unset the context.
+    // Note: At the time of writing the EGL cleanup is chosen to be not done at all.
+    EGLDisplay display = EGL_GetDisplay(EGL_DEFAULT_DISPLAY);
+    if (display == EGL_NO_DISPLAY)
+        return false;
+    return EGL_MakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+}
+#endif
+
 void GraphicsContextGLOpenGL::checkGPUStatus()
 {
     if (m_failNextStatusCheck) {
@@ -724,6 +816,7 @@
 #elif USE(OPENGL_ES)
         [EAGLContext setCurrentContext:0];
 #elif USE(ANGLE)
+        EGL_BindAPI(EGL_OPENGL_ES_API);
         EGL_MakeCurrent(m_displayObj, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
 #endif
         return;

Modified: trunk/Source/WebCore/platform/graphics/opengl/GraphicsContextGLOpenGL.h (267868 => 267869)


--- trunk/Source/WebCore/platform/graphics/opengl/GraphicsContextGLOpenGL.h	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Source/WebCore/platform/graphics/opengl/GraphicsContextGLOpenGL.h	2020-10-02 07:05:42 UTC (rev 267869)
@@ -119,6 +119,13 @@
 #endif
 
     bool makeContextCurrent();
+#if PLATFORM(IOS_FAMILY) && USE(ANGLE)
+    enum class ReleaseBehavior {
+        PreserveThreadResources,
+        ReleaseThreadResources
+    };
+    static bool releaseCurrentContext(ReleaseBehavior);
+#endif
 
     void addClient(Client& client) { m_clients.add(&client); }
     void removeClient(Client& client) { m_clients.remove(&client); }

Modified: trunk/Source/WebCore/platform/ios/wak/WebCoreThread.mm (267868 => 267869)


--- trunk/Source/WebCore/platform/ios/wak/WebCoreThread.mm	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Source/WebCore/platform/ios/wak/WebCoreThread.mm	2020-10-02 07:05:42 UTC (rev 267869)
@@ -30,6 +30,7 @@
 
 #import "CommonVM.h"
 #import "FloatingPointEnvironment.h"
+#import "GraphicsContextGLOpenGL.h"
 #import "Logging.h"
 #import "RuntimeApplicationChecks.h"
 #import "ThreadGlobalData.h"
@@ -59,6 +60,26 @@
 
 #define DistantFuture   (86400.0 * 2000 * 365.2425 + 86400.0)   // same as +[NSDate distantFuture]
 
+namespace {
+// Release global state that is accessed from both web thread as well
+// as any client thread that calls into WebKit.
+void ReleaseWebThreadGlobalState()
+{
+    // GraphicsContextGLOpenGL current context is owned by the web thread lock. Release the context
+    // before the lock is released.
+
+    // In single-threaded environments we do not need to unset the context, as there should not be access from
+    // multiple threads.
+    ASSERT(WebThreadIsEnabled());
+    using ReleaseBehavior = WebCore::GraphicsContextGLOpenGL::ReleaseBehavior;
+    // For non-web threads, we don't know if we ever see another call from the thread.
+    ReleaseBehavior releaseBehavior =
+        WebThreadIsCurrent() ? ReleaseBehavior::PreserveThreadResources : ReleaseBehavior::ReleaseThreadResources;
+    WebCore::GraphicsContextGLOpenGL::releaseCurrentContext(releaseBehavior);
+}
+
+}
+
 static const constexpr Seconds DelegateWaitInterval { 10_s };
 
 static void _WebThreadAutoLock();
@@ -778,6 +799,8 @@
     if (!webThreadStarted)
         return;
     ASSERT(!WebThreadIsCurrent());
+    ReleaseWebThreadGlobalState();
+
     // No-op except from a secondary thread.
     if (pthread_main_np())
         return;
@@ -799,6 +822,8 @@
 
 void _WebThreadUnlock()
 {
+    ReleaseWebThreadGlobalState();
+
 #if LOG_WEB_LOCK || LOG_MAIN_THREAD_LOCKING
     lockCount--;
 #if LOG_WEB_LOCK

Modified: trunk/Tools/ChangeLog (267868 => 267869)


--- trunk/Tools/ChangeLog	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Tools/ChangeLog	2020-10-02 07:05:42 UTC (rev 267869)
@@ -1,3 +1,24 @@
+2020-10-02  Kimmo Kinnunen  <[email protected]>
+
+        [iOS WK1] Crashes when using ANGLE WebGL from another thread
+        https://bugs.webkit.org/show_bug.cgi?id=216106
+        <rdar://problem/68602452>
+
+        Reviewed by Kenneth Russell.
+
+        Add a WK1 test which runs WebGL code both in
+        client main thread and in web thread.
+        This tests the case where ANGLE EGL context is
+        not being held current in one thread while the
+        other thread runs WebGL and thus ANGLE EGL code.
+
+        * TestWebKitAPI/Configurations/TestWebKitAPI.xcconfig:
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKitLegacy/ios/WebGLNoCrashOnOtherThreadAccess.mm: Added.
+        (-[WebGLNoCrashOnOtherThreadAccessWebViewDelegate webViewDidFinishLoad:]):
+        (-[WebGLNoCrashOnOtherThreadAccessWebViewDelegate webView:shouldStartLoadWithRequest:navigationType:]):
+        (TestWebKitAPI::TEST):
+
 2020-10-01  Aakash Jain  <[email protected]>
 
         Limit number of tests to log in case of large number of API test failures

Modified: trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI.xcconfig (267868 => 267869)


--- trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI.xcconfig	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI.xcconfig	2020-10-02 07:05:42 UTC (rev 267869)
@@ -61,7 +61,17 @@
 
 OTHER_CPLUSPLUSFLAGS = $(inherited) -isystem $(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders;
 
-OTHER_LDFLAGS = $(inherited) $(UNEXPORTED_SYMBOL_LDFLAGS) -lgtest -force_load $(BUILT_PRODUCTS_DIR)/libTestWebKitAPI.a -framework _javascript_Core -framework WebKit -lWebCoreTestSupport $(WK_AUTHKIT_LDFLAGS) -framework Network $(WK_PDFKIT_LDFLAGS) $(WK_HID_LDFLAGS) $(OTHER_LDFLAGS_PLATFORM_$(WK_COCOA_TOUCH));
+WK_OPENGL_LDFLAGS = $(WK_OPENGL_LDFLAGS_$(WK_PLATFORM_NAME));
+WK_OPENGL_LDFLAGS_iphoneos = -framework OpenGLES;
+WK_OPENGL_LDFLAGS_maccatalyst = -framework OpenGL;
+WK_OPENGL_LDFLAGS_iphonesimulator = -framework OpenGLES;
+WK_OPENGL_LDFLAGS_watchos = $(WK_OPENGL_LDFLAGS_iphoneos);
+WK_OPENGL_LDFLAGS_watchsimulator = $(WK_OPENGL_LDFLAGS_iphonesimulator);
+WK_OPENGL_LDFLAGS_appletvos = $(WK_OPENGL_LDFLAGS_iphoneos);
+WK_OPENGL_LDFLAGS_appletvsimulator = $(WK_OPENGL_LDFLAGS_iphonesimulator);
+WK_OPENGL_LDFLAGS_macosx = -framework OpenGL;
+
+OTHER_LDFLAGS = $(inherited) $(UNEXPORTED_SYMBOL_LDFLAGS) -lgtest -force_load $(BUILT_PRODUCTS_DIR)/libTestWebKitAPI.a -framework _javascript_Core -framework WebKit -lWebCoreTestSupport $(WK_AUTHKIT_LDFLAGS) -framework Network $(WK_PDFKIT_LDFLAGS) $(WK_HID_LDFLAGS) $(WK_OPENGL_LDFLAGS) $(OTHER_LDFLAGS_PLATFORM_$(WK_COCOA_TOUCH));
 OTHER_LDFLAGS_PLATFORM_ = -framework Cocoa -framework Carbon;
 
 // FIXME: This should not be built on iOS. Instead we should create and use a TestWebKitAPI application.

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (267868 => 267869)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2020-10-02 06:47:42 UTC (rev 267868)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2020-10-02 07:05:42 UTC (rev 267869)
@@ -547,6 +547,7 @@
 		7AE9E5091AE5AE8B00CF874B /* test.pdf in Copy Resources */ = {isa = PBXBuildFile; fileRef = 7AE9E5081AE5AE8B00CF874B /* test.pdf */; };
 		7AEAD47F1E20116C00416EFE /* CrossPartitionFileSchemeAccess.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7AEAD47C1E20113800416EFE /* CrossPartitionFileSchemeAccess.mm */; };
 		7AEAD4811E20122700416EFE /* CrossPartitionFileSchemeAccess.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 7AEAD47D1E20114E00416EFE /* CrossPartitionFileSchemeAccess.html */; };
+		7B7D096A2519F8F90017A078 /* WebGLNoCrashOnOtherThreadAccess.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7B7D09692519F8F90017A078 /* WebGLNoCrashOnOtherThreadAccess.mm */; };
 		7C1AF7951E8DCBAB002645B9 /* PrepareForMoveToWindow.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7C1AF7931E8DCBAB002645B9 /* PrepareForMoveToWindow.mm */; };
 		7C3965061CDD74F90094DBB8 /* ColorTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C3965051CDD74F90094DBB8 /* ColorTests.cpp */; };
 		7C3DB8E41D12129B00AE8CC3 /* CommandBackForward.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7C3DB8E21D12129B00AE8CC3 /* CommandBackForward.mm */; };
@@ -2309,6 +2310,7 @@
 		7AE9E5081AE5AE8B00CF874B /* test.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = test.pdf; sourceTree = "<group>"; };
 		7AEAD47C1E20113800416EFE /* CrossPartitionFileSchemeAccess.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CrossPartitionFileSchemeAccess.mm; sourceTree = "<group>"; };
 		7AEAD47D1E20114E00416EFE /* CrossPartitionFileSchemeAccess.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = CrossPartitionFileSchemeAccess.html; path = Tests/mac/CrossPartitionFileSchemeAccess.html; sourceTree = SOURCE_ROOT; };
+		7B7D09692519F8F90017A078 /* WebGLNoCrashOnOtherThreadAccess.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = WebGLNoCrashOnOtherThreadAccess.mm; sourceTree = "<group>"; };
 		7C1AF7931E8DCBAB002645B9 /* PrepareForMoveToWindow.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PrepareForMoveToWindow.mm; sourceTree = "<group>"; };
 		7C3965051CDD74F90094DBB8 /* ColorTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ColorTests.cpp; sourceTree = "<group>"; };
 		7C3DB8E21D12129B00AE8CC3 /* CommandBackForward.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CommandBackForward.mm; sourceTree = "<group>"; };
@@ -4605,6 +4607,7 @@
 				CDC0932A21C872C10030C4B0 /* ScrollingDoesNotPauseMedia.mm */,
 				F434CA1922E65BCA005DDB26 /* ScrollToRevealSelection.mm */,
 				0F4FFA9D1ED3AA8500F7111F /* SnapshotViaRenderInContext.mm */,
+				7B7D09692519F8F90017A078 /* WebGLNoCrashOnOtherThreadAccess.mm */,
 				31E9BDA0247F4C62002E51A2 /* WebGLPrepareDisplayOnWebThread.mm */,
 				2DC9451624D8AC0200430376 /* WebThreadLock.mm */,
 			);
@@ -5479,6 +5482,7 @@
 				7C83E04C1D0A641800FEBCF3 /* WebCoreNSURLSession.mm in Sources */,
 				57A79857224AB34E00A7F6F1 /* WebCryptoMasterKey.mm in Sources */,
 				C1FF9EDB244644F000839AE4 /* WebFilter.mm in Sources */,
+				7B7D096A2519F8F90017A078 /* WebGLNoCrashOnOtherThreadAccess.mm in Sources */,
 				5C973F5C1F58EF8B00359C27 /* WebGLPolicy.mm in Sources */,
 				31E9BDA1247F4C62002E51A2 /* WebGLPrepareDisplayOnWebThread.mm in Sources */,
 				7CCE7EAB1A411A2400447C4C /* WebKitAgnosticTest.mm in Sources */,

Added: trunk/Tools/TestWebKitAPI/Tests/WebKitLegacy/ios/WebGLNoCrashOnOtherThreadAccess.mm (0 => 267869)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitLegacy/ios/WebGLNoCrashOnOtherThreadAccess.mm	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitLegacy/ios/WebGLNoCrashOnOtherThreadAccess.mm	2020-10-02 07:05:42 UTC (rev 267869)
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+
+#if HAVE(UIWEBVIEW)
+
+#import "PlatformUtilities.h"
+#import <_javascript_Core/JSVirtualMachine.h>
+#import <_javascript_Core/JSVirtualMachineInternal.h>
+#import <UIKit/UIKit.h>
+#import <WebCore/WebCoreThread.h>
+#import <stdlib.h>
+#import <wtf/RetainPtr.h>
+
+#if PLATFORM(MAC) || PLATFORM(MACCATALYST)
+#import <OpenGL/OpenGL.h>
+#elif PLATFORM(IOS)
+#import <OpenGLES/EAGL.h>
+#endif
+
+namespace {
+bool didFinishLoad;
+bool didFinishTest;
+
+#if PLATFORM(MAC) || PLATFORM(MACCATALYST)
+class SetContextCGL {
+    SetContextCGL()
+    {
+        // TODO: implement properly. Skipped due to complicated instantiation.
+        // instead, just clobber the current context with nullptr.
+        CGLSetCurrentContext(nullptr);
+    }
+    ~SetContextCGL()
+    {
+        CGLSetCurrentContext(nullptr);
+    }
+};
+#else
+class SetContextCGL {
+
+};
+#endif
+
+#if PLATFORM(IOS)
+class SetContextEAGL {
+public:
+    SetContextEAGL()
+    {
+        m_eaglContext = adoptNS([[EAGLContext alloc] initWithAPI: kEAGLRenderingAPIOpenGLES3]);
+        auto r = [EAGLContext setCurrentContext: m_eaglContext.get()];
+        ASSERT(r);
+        UNUSED_VARIABLE(r);
+    }
+    ~SetContextEAGL()
+    {
+        [EAGLContext setCurrentContext: nil];
+    }
+
+private:
+    RetainPtr<EAGLContext> m_eaglContext;
+};
+#else
+class SetContextEAGL {
+
+};
+#endif
+
+}
+
+@interface WebGLNoCrashOnOtherThreadAccessWebViewDelegate : NSObject <UIWebViewDelegate>
+@end
+
+@implementation WebGLNoCrashOnOtherThreadAccessWebViewDelegate
+
+IGNORE_WARNINGS_BEGIN("deprecated-implementations")
+- (void)webViewDidFinishLoad:(UIWebView *)webView
+{
+    didFinishLoad = true;
+}
+
+- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
+{
+    if ([request.URL.scheme isEqualToString:@"callback"]) {
+        if ([request.URL.resourceSpecifier isEqualToString:@"didFinishTest"])
+            didFinishTest = true;
+        else
+            EXPECT_TRUE(false) << [request.URL.resourceSpecifier UTF8String];
+        return NO;
+    }
+
+    return YES;
+}
+IGNORE_WARNINGS_END
+
+@end
+
+namespace TestWebKitAPI {
+
+// Test that tests behavior of UIWebView API with regards to WebGL:
+// 1) WebGL can be run on web thread.
+// 2) WebGL can be run on client main thread.
+// 3) WebGL run on client thread is not affected by client changing
+//    the EAGL/CGL context.
+TEST(WebKitLegacy, WebGLNoCrashOnOtherThreadAccess)
+{
+    const unsigned testIterations = 10;
+
+    RetainPtr<UIWindow> uiWindow = adoptNS([[UIWindow alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
+    RetainPtr<UIWebView> uiWebView = adoptNS([[UIWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
+    [uiWindow addSubview:uiWebView.get()];
+
+    ASSERT_TRUE(WebThreadIsEnabled());
+    SetContextCGL clientContextCGL1;
+    SetContextEAGL clientContextEAGL1;
+    UNUSED_VARIABLE(clientContextCGL1);
+    UNUSED_VARIABLE(clientContextEAGL1);
+
+    RetainPtr<WebGLNoCrashOnOtherThreadAccessWebViewDelegate> uiDelegate =
+        adoptNS([[WebGLNoCrashOnOtherThreadAccessWebViewDelegate alloc] init]);
+    uiWebView.get().delegate = uiDelegate.get();
+    NSString* testHtml = @R"HTML(<body>NOLINT(readability/multiline_string)
+<script>
+function runTest()
+{
+    let w = 100;
+    let h = 100;
+    let canvas = document.createElement("canvas");
+    canvas.width = w;
+    canvas.height = h;
+    let gl = canvas.getContext("webgl");
+    gl.clearColor(0, 0, 1, 1);
+    gl.clear(gl.COLOR_BUFFER_BIT);
+    let expected = 255 << 24 | 255 << 16;
+    let ps = new Uint8Array(w * h * 4);
+    gl.readPixels(0, 0, w, h, gl.RGBA, gl.UNSIGNED_BYTE, ps);
+    for (let i = 0; i < ps.length; i += 4) {
+        let got = ps[i] | ps[i+1] << 8 | ps[i+2] << 16 | ps[i+3] << 24;
+        if (got != expected)
+            return `${got} != ${expected}`; // NOLINT
+    }
+    return "didFinishTest";
+}
+function runTestAsync()
+{
+    setTimeout(() => { window.location = 'callback:' + runTest(); }, 10); // NOLINT
+}
+</script>)HTML"; // NOLINT(readability/multiline_string)
+    [uiWebView loadHTMLString:testHtml baseURL:nil];
+
+    Util::run(&didFinishLoad);
+
+    RetainPtr<JSContext> jsContext = [uiWebView valueForKeyPath:@"documentView.webView.mainFrame._javascript_Context"];
+    RetainPtr<JSVirtualMachine> jsVM = [jsContext virtualMachine];
+    EXPECT_TRUE([jsVM isWebThreadAware]);
+
+    // Start to run WebGL on web thread.
+    [uiWebView stringByEvaluatingJavaScriptFromString:@"runTestAsync();"];
+    EXPECT_FALSE(didFinishTest); // The pattern runs the test on web thread.
+
+    for (unsigned i = 0; i < testIterations; i++) {
+        // Run WebGL on client main thread.
+        NSString* result = [[jsContext evaluateScript: @"runTest();"] toString];
+        EXPECT_TRUE([@"didFinishTest" isEqualToString: result]);
+
+        // Client clobbers EAGLContext between calls that run WebGL on main thread.
+        SetContextCGL clientContextCGL2;
+        SetContextEAGL clientContextEAGL2;
+        UNUSED_VARIABLE(clientContextCGL2);
+        UNUSED_VARIABLE(clientContextEAGL2);
+
+        result = [[jsContext evaluateScript: @"runTest();"] toString];
+        EXPECT_TRUE([@"didFinishTest" isEqualToString: result]);
+
+        // Wait until the previous WebGL test run has finished.
+        Util::run(&didFinishTest);
+        didFinishTest = false;
+        // Start to run WebGL on web thread.
+        [uiWebView stringByEvaluatingJavaScriptFromString:@"runTestAsync();"];
+        EXPECT_FALSE(didFinishTest);
+    }
+
+    Util::run(&didFinishTest);
+}
+
+}
+
+#endif
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to