Edit

kc3-lang/angle/src/libGLESv2/global_state.h

Branch :

  • Show log

    Commit

  • Author : Yuxin Hu
    Date : 2024-10-15 18:27:00
    Hash : e5619a5c
    Message : Use EGL sync global lock for all EGL*sync entrypoint calls To free EGL sync operations from waiting for other EGL calls to finish, we use a separate global lock for EGL*sync entrypoints. Below angle::SimpleMutex are added to protect resources that may have race condition due to being accessed by EGL*sync calls and non EGL*sync calls at the same time: 1. Display::mContextMapMutex that protects Display::mState.contextMap 2. static angle::base::NoDestructor<angle::SimpleMutex> anglePlatformDisplayMapMutex that protects static angle::base::NoDestructor<ANGLEPlatformDisplayMap> displays 3. static angle::base::NoDestructor<angle::SimpleMutex> devicePlatformDisplayMapMutex that protects static angle::base::NoDestructor<DevicePlatformDisplayMap> displays EGL_Terminate() entry point takes both global lock and global egl sync lock. This is to protect Display::mSyncMap, Display::mSyncPools, and Display::mSyncHandleAllocator being get cleared by thread 1 calling eglTerminate, while they are still accessed by thread 2 through a call such as eglCreateSync. So that we won't have thread 2 finish validating the sync object with syncID exists in Display::mSyncMap, but then find the mSyncMap.find(syncID) returns a nullptr due to the mSyncMap is cleared by thread 1. Same applies to EGL_LabelObjectKHR(), EGL_ReleaseThread(), ThreadCleanupCallback(). EGL_Initialize() writes to Display::mInitialized. This is read by EGL Sync API validation functions. EGL_Initialize() also takes both global lock and global sync lock to prevent race conditions between EGL_Initialize() and EGL Sync APIs. When ANGLE_CAPTURE_ENABLED is enabled, fall back to global lock, as the CaptureEGLCallToFrameCapture() touches many resources (e.g. mMaxAccessedResourceIDs, mFrameCalls) that could lead to race conditions without a global lock. Bug: b/362604439 Change-Id: Ic0d54a4cd66743bcd0f48f41f247dd223cff2f5e Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5933570 Reviewed-by: Roman Lavrov <romanl@google.com> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Igor Nazarov <i.nazarov@samsung.com> Commit-Queue: Yuxin Hu <yuxinhu@google.com>

  • src/libGLESv2/global_state.h
  • //
    // Copyright 2014 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    
    // global_state.h : Defines functions for querying the thread-local GL and EGL state.
    
    #ifndef LIBGLESV2_GLOBALSTATE_H_
    #define LIBGLESV2_GLOBALSTATE_H_
    
    #include "libANGLE/Context.h"
    #include "libANGLE/Debug.h"
    #include "libANGLE/Display.h"
    #include "libANGLE/GlobalMutex.h"
    #include "libANGLE/Thread.h"
    #include "libANGLE/features.h"
    #include "libANGLE/validationEGL.h"
    
    #if defined(ANGLE_PLATFORM_APPLE) || (ANGLE_PLATFORM_ANDROID) || defined(ANGLE_USE_ANDROID_TLS_SLOT)
    #    include "common/tls.h"
    #endif
    
    #include <mutex>
    
    namespace egl
    {
    class Debug;
    class Thread;
    
    #if defined(ANGLE_PLATFORM_APPLE) || defined(ANGLE_USE_STATIC_THREAD_LOCAL_VARIABLES)
    extern Thread *GetCurrentThreadTLS();
    extern void SetCurrentThreadTLS(Thread *thread);
    #else
    extern thread_local Thread *gCurrentThread;
    #endif
    
    gl::Context *GetGlobalLastContext();
    void SetGlobalLastContext(gl::Context *context);
    Thread *GetCurrentThread();
    Debug *GetDebug();
    
    void SetEGLValidationEnabled(bool enabled);
    bool IsEGLValidationEnabled();
    
    // Sync the current context from Thread to global state.
    class [[nodiscard]] ScopedSyncCurrentContextFromThread
    {
      public:
        ScopedSyncCurrentContextFromThread(egl::Thread *thread);
        ~ScopedSyncCurrentContextFromThread();
    
      private:
        egl::Thread *const mThread;
    };
    
    // Tries to lock "ContextMutex" of the Context current to the "thread".
    ANGLE_INLINE ScopedContextMutexLock TryLockCurrentContext(Thread *thread)
    {
        ASSERT(kIsContextMutexEnabled);
        gl::Context *context = thread->getContext();
        return context != nullptr ? ScopedContextMutexLock(context->getContextMutex())
                                  : ScopedContextMutexLock();
    }
    
    // Tries to lock "ContextMutex" of the Context with "contextID" if it is valid.
    ANGLE_INLINE ScopedContextMutexLock TryLockContext(Display *display, gl::ContextID contextID)
    {
        ASSERT(kIsContextMutexEnabled);
        gl::Context *context = GetContextIfValid(display, contextID);
        return context != nullptr ? ScopedContextMutexLock(context->getContextMutex())
                                  : ScopedContextMutexLock();
    }
    
    // Locks "ContextMutex" of the "context" and then tries to merge it with the "ContextMutex" of the
    // Image with "imageID" if it is valid.
    ANGLE_INLINE ScopedContextMutexLock LockAndTryMergeContextMutexes(gl::Context *context,
                                                                      ImageID imageID)
    {
        ASSERT(kIsContextMutexEnabled);
        ASSERT(context->getDisplay() != nullptr);
        ScopedContextMutexLock lock(context->getContextMutex());
        const Image *image = context->getDisplay()->getImage(imageID);
        if (image != nullptr)
        {
            ContextMutex *imageMutex = image->getContextMutex();
            if (imageMutex != nullptr)
            {
                ContextMutex::Merge(&context->getContextMutex(), imageMutex);
            }
        }
        return lock;
    }
    
    #if !defined(ANGLE_ENABLE_CONTEXT_MUTEX)
    #    define ANGLE_EGL_SCOPED_CONTEXT_LOCK(EP, THREAD, ...)
    #else
    #    define ANGLE_EGL_SCOPED_CONTEXT_LOCK(EP, THREAD, ...) \
            egl::ScopedContextMutexLock shareContextLock = GetContextLock_##EP(THREAD, ##__VA_ARGS__)
    #endif
    
    }  // namespace egl
    
    #define ANGLE_SCOPED_GLOBAL_LOCK() egl::ScopedGlobalEGLMutexLock globalMutexLock
    #if ANGLE_CAPTURE_ENABLED
    #    define ANGLE_SCOPED_GLOBAL_EGL_AND_EGL_SYNC_LOCK() \
            egl::ScopedGlobalEGLMutexLock globalMutexLock
    #else
    #    define ANGLE_SCOPED_GLOBAL_EGL_AND_EGL_SYNC_LOCK() \
            egl::ScopedGlobalEGLMutexLock globalMutexLock;  \
            egl::ScopedGlobalEGLSyncObjectMutexLock globalEGLSyncObjectMutexLock
    #endif
    
    #if ANGLE_CAPTURE_ENABLED
    #    define ANGLE_SCOPED_GLOBAL_EGL_SYNC_LOCK() egl::ScopedGlobalEGLMutexLock globalMutexLock
    #else
    #    define ANGLE_SCOPED_GLOBAL_EGL_SYNC_LOCK() \
            egl::ScopedGlobalEGLSyncObjectMutexLock globalEGLSyncObjectMutexLock
    #endif
    
    namespace gl
    {
    ANGLE_INLINE Context *GetGlobalContext()
    {
    #if defined(ANGLE_PLATFORM_APPLE) || defined(ANGLE_USE_STATIC_THREAD_LOCAL_VARIABLES)
        egl::Thread *currentThread = egl::GetCurrentThreadTLS();
    #else
        egl::Thread *currentThread = egl::gCurrentThread;
    #endif
        ASSERT(currentThread);
        return currentThread->getContext();
    }
    
    ANGLE_INLINE Context *GetValidGlobalContext()
    {
    #if defined(ANGLE_USE_ANDROID_TLS_SLOT)
        // TODO: Replace this branch with a compile time flag (http://anglebug.com/42263361)
        if (angle::gUseAndroidOpenGLTlsSlot)
        {
            return static_cast<gl::Context *>(ANGLE_ANDROID_GET_GL_TLS()[angle::kAndroidOpenGLTlsSlot]);
        }
    #endif
    
    #if defined(ANGLE_PLATFORM_APPLE) || defined(ANGLE_USE_STATIC_THREAD_LOCAL_VARIABLES)
        return GetCurrentValidContextTLS();
    #else
        return gCurrentValidContext;
    #endif
    }
    
    // Generate a context lost error on the context if it is non-null and lost.
    void GenerateContextLostErrorOnContext(Context *context);
    void GenerateContextLostErrorOnCurrentGlobalContext();
    
    #if defined(ANGLE_FORCE_CONTEXT_CHECK_EVERY_CALL)
    // TODO(b/177574181): This should be handled in a backend-specific way.
    // if previous context different from current context, dirty all state
    static ANGLE_INLINE void DirtyContextIfNeeded(Context *context)
    {
        if (context && context != egl::GetGlobalLastContext())
        {
            context->dirtyAllState();
            SetGlobalLastContext(context);
        }
    }
    
    #endif
    
    #if !defined(ANGLE_ENABLE_SHARE_CONTEXT_LOCK)
    #    define SCOPED_SHARE_CONTEXT_LOCK(context)
    #    define SCOPED_EGL_IMAGE_SHARE_CONTEXT_LOCK(context, imageID) ANGLE_SCOPED_GLOBAL_LOCK()
    #else
    #    if defined(ANGLE_FORCE_CONTEXT_CHECK_EVERY_CALL)
    #        define SCOPED_SHARE_CONTEXT_LOCK(context)          \
                egl::ScopedGlobalEGLMutexLock shareContextLock; \
                DirtyContextIfNeeded(context)
    #        define SCOPED_EGL_IMAGE_SHARE_CONTEXT_LOCK(context, imageID) \
                SCOPED_SHARE_CONTEXT_LOCK(context)
    #    elif !defined(ANGLE_ENABLE_CONTEXT_MUTEX)
    #        define SCOPED_SHARE_CONTEXT_LOCK(context) \
                egl::ScopedOptionalGlobalMutexLock shareContextLock(context->isShared())
    #        define SCOPED_EGL_IMAGE_SHARE_CONTEXT_LOCK(context, imageID) ANGLE_SCOPED_GLOBAL_LOCK()
    #    else
    #        define SCOPED_SHARE_CONTEXT_LOCK(context) \
                egl::ScopedContextMutexLock shareContextLock(context->getContextMutex())
    #        define SCOPED_EGL_IMAGE_SHARE_CONTEXT_LOCK(context, imageID) \
                ANGLE_SCOPED_GLOBAL_LOCK();                               \
                egl::ScopedContextMutexLock shareContextLock =            \
                    egl::LockAndTryMergeContextMutexes(context, imageID)
    #    endif
    #endif
    
    }  // namespace gl
    
    #endif  // LIBGLESV2_GLOBALSTATE_H_