summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/libGLESv2/global_state.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/libGLESv2/global_state.cpp')
-rw-r--r--gfx/angle/checkout/src/libGLESv2/global_state.cpp373
1 files changed, 373 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libGLESv2/global_state.cpp b/gfx/angle/checkout/src/libGLESv2/global_state.cpp
new file mode 100644
index 0000000000..c776980524
--- /dev/null
+++ b/gfx/angle/checkout/src/libGLESv2/global_state.cpp
@@ -0,0 +1,373 @@
+//
+// 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.cpp : Implements functions for querying the thread-local GL and EGL state.
+
+#include "libGLESv2/global_state.h"
+
+#include "common/debug.h"
+#include "common/platform.h"
+#include "common/system_utils.h"
+#include "libANGLE/ErrorStrings.h"
+#include "libANGLE/Thread.h"
+#include "libGLESv2/resource.h"
+
+#include <atomic>
+#if defined(ANGLE_PLATFORM_APPLE)
+# include <dispatch/dispatch.h>
+#endif
+namespace egl
+{
+namespace
+{
+ANGLE_REQUIRE_CONSTANT_INIT std::atomic<angle::GlobalMutex *> g_Mutex{};
+static_assert(std::is_trivially_destructible<decltype(g_Mutex)>::value,
+ "global mutex is not trivially destructible");
+ANGLE_REQUIRE_CONSTANT_INIT std::atomic<angle::GlobalMutex *> g_SurfaceMutex{};
+static_assert(std::is_trivially_destructible<decltype(g_SurfaceMutex)>::value,
+ "global mutex is not trivially destructible");
+
+ANGLE_REQUIRE_CONSTANT_INIT gl::Context *g_LastContext(nullptr);
+static_assert(std::is_trivially_destructible<decltype(g_LastContext)>::value,
+ "global last context is not trivially destructible");
+
+void SetContextToAndroidOpenGLTLSSlot(gl::Context *value)
+{
+#if defined(ANGLE_USE_ANDROID_TLS_SLOT)
+ if (angle::gUseAndroidOpenGLTlsSlot)
+ {
+ ANGLE_ANDROID_GET_GL_TLS()[angle::kAndroidOpenGLTlsSlot] = static_cast<void *>(value);
+ }
+#endif
+}
+
+// Called only on Android platform
+[[maybe_unused]] void ThreadCleanupCallback(void *ptr)
+{
+ ANGLE_SCOPED_GLOBAL_LOCK();
+ angle::PthreadKeyDestructorCallback(ptr);
+}
+
+Thread *AllocateCurrentThread()
+{
+ Thread *thread;
+ {
+ // Global thread intentionally leaked
+ ANGLE_SCOPED_DISABLE_LSAN();
+ thread = new Thread();
+#if defined(ANGLE_PLATFORM_APPLE)
+ SetCurrentThreadTLS(thread);
+#else
+ gCurrentThread = thread;
+#endif
+ }
+
+ // Initialize fast TLS slot
+ SetContextToAndroidOpenGLTLSSlot(nullptr);
+
+#if defined(ANGLE_PLATFORM_APPLE)
+ gl::SetCurrentValidContextTLS(nullptr);
+#else
+ gl::gCurrentValidContext = nullptr;
+#endif
+
+#if defined(ANGLE_PLATFORM_ANDROID)
+ static pthread_once_t keyOnce = PTHREAD_ONCE_INIT;
+ static TLSIndex gThreadCleanupTLSIndex = TLS_INVALID_INDEX;
+
+ // Create thread cleanup TLS slot
+ auto CreateThreadCleanupTLSIndex = []() {
+ gThreadCleanupTLSIndex = CreateTLSIndex(ThreadCleanupCallback);
+ };
+ pthread_once(&keyOnce, CreateThreadCleanupTLSIndex);
+ ASSERT(gThreadCleanupTLSIndex != TLS_INVALID_INDEX);
+
+ // Initialize thread cleanup TLS slot
+ SetTLSValue(gThreadCleanupTLSIndex, thread);
+#endif // ANGLE_PLATFORM_ANDROID
+
+ ASSERT(thread);
+ return thread;
+}
+
+void AllocateGlobalMutex(std::atomic<angle::GlobalMutex *> &mutex)
+{
+ if (mutex == nullptr)
+ {
+ std::unique_ptr<angle::GlobalMutex> newMutex(new angle::GlobalMutex());
+ angle::GlobalMutex *expected = nullptr;
+ if (mutex.compare_exchange_strong(expected, newMutex.get()))
+ {
+ newMutex.release();
+ }
+ }
+}
+
+void AllocateMutex()
+{
+ AllocateGlobalMutex(g_Mutex);
+}
+
+void AllocateSurfaceMutex()
+{
+ AllocateGlobalMutex(g_SurfaceMutex);
+}
+
+} // anonymous namespace
+
+#if defined(ANGLE_PLATFORM_APPLE)
+// TODO(angleproject:6479): Due to a bug in Apple's dyld loader, `thread_local` will cause
+// excessive memory use. Temporarily avoid it by using pthread's thread
+// local storage instead.
+// https://bugs.webkit.org/show_bug.cgi?id=228240
+
+static TLSIndex GetCurrentThreadTLSIndex()
+{
+ static TLSIndex CurrentThreadIndex = TLS_INVALID_INDEX;
+ static dispatch_once_t once;
+ dispatch_once(&once, ^{
+ ASSERT(CurrentThreadIndex == TLS_INVALID_INDEX);
+ CurrentThreadIndex = CreateTLSIndex(nullptr);
+ });
+ return CurrentThreadIndex;
+}
+Thread *GetCurrentThreadTLS()
+{
+ TLSIndex CurrentThreadIndex = GetCurrentThreadTLSIndex();
+ ASSERT(CurrentThreadIndex != TLS_INVALID_INDEX);
+ return static_cast<Thread *>(GetTLSValue(CurrentThreadIndex));
+}
+void SetCurrentThreadTLS(Thread *thread)
+{
+ TLSIndex CurrentThreadIndex = GetCurrentThreadTLSIndex();
+ ASSERT(CurrentThreadIndex != TLS_INVALID_INDEX);
+ SetTLSValue(CurrentThreadIndex, thread);
+}
+#else
+thread_local Thread *gCurrentThread = nullptr;
+#endif
+
+angle::GlobalMutex &GetGlobalMutex()
+{
+ AllocateMutex();
+ return *g_Mutex;
+}
+
+angle::GlobalMutex &GetGlobalSurfaceMutex()
+{
+ AllocateSurfaceMutex();
+ return *g_SurfaceMutex;
+}
+
+gl::Context *GetGlobalLastContext()
+{
+ return g_LastContext;
+}
+
+void SetGlobalLastContext(gl::Context *context)
+{
+ g_LastContext = context;
+}
+
+// This function causes an MSAN false positive, which is muted. See https://crbug.com/1211047
+// It also causes a flaky false positive in TSAN. http://crbug.com/1223970
+ANGLE_NO_SANITIZE_MEMORY ANGLE_NO_SANITIZE_THREAD Thread *GetCurrentThread()
+{
+#if defined(ANGLE_PLATFORM_APPLE)
+ Thread *current = GetCurrentThreadTLS();
+#else
+ Thread *current = gCurrentThread;
+#endif
+ return (current ? current : AllocateCurrentThread());
+}
+
+void SetContextCurrent(Thread *thread, gl::Context *context)
+{
+#if defined(ANGLE_PLATFORM_APPLE)
+ Thread *currentThread = GetCurrentThreadTLS();
+#else
+ Thread *currentThread = gCurrentThread;
+#endif
+ ASSERT(currentThread);
+ currentThread->setCurrent(context);
+ SetContextToAndroidOpenGLTLSSlot(context);
+
+#if defined(ANGLE_PLATFORM_APPLE)
+ gl::SetCurrentValidContextTLS(context);
+#else
+ gl::gCurrentValidContext = context;
+#endif
+
+#if defined(ANGLE_FORCE_CONTEXT_CHECK_EVERY_CALL)
+ DirtyContextIfNeeded(context);
+#endif
+}
+
+ScopedSyncCurrentContextFromThread::ScopedSyncCurrentContextFromThread(egl::Thread *thread)
+ : mThread(thread)
+{
+ ASSERT(mThread);
+}
+
+ScopedSyncCurrentContextFromThread::~ScopedSyncCurrentContextFromThread()
+{
+ SetContextCurrent(mThread, mThread->getContext());
+}
+
+} // namespace egl
+
+namespace gl
+{
+void GenerateContextLostErrorOnContext(Context *context)
+{
+ if (context && context->isContextLost())
+ {
+ context->validationError(angle::EntryPoint::GLInvalid, GL_CONTEXT_LOST, err::kContextLost);
+ }
+}
+
+void GenerateContextLostErrorOnCurrentGlobalContext()
+{
+ // If the client starts issuing GL calls before ANGLE has had a chance to initialize,
+ // GenerateContextLostErrorOnCurrentGlobalContext can be called before AllocateCurrentThread has
+ // had a chance to run. Calling GetCurrentThread() ensures that TLS thread state is set up.
+ egl::GetCurrentThread();
+
+ GenerateContextLostErrorOnContext(GetGlobalContext());
+}
+} // namespace gl
+
+#if defined(ANGLE_PLATFORM_WINDOWS) && !defined(ANGLE_STATIC)
+namespace egl
+{
+
+namespace
+{
+
+void DeallocateGlobalMutex(std::atomic<angle::GlobalMutex *> &mutex)
+{
+ angle::GlobalMutex *toDelete = mutex.exchange(nullptr);
+ if (!mutex)
+ return;
+ {
+ // Wait for toDelete to become released by other threads before deleting.
+ std::lock_guard<angle::GlobalMutex> lock(*toDelete);
+ }
+ SafeDelete(toDelete);
+}
+
+void DeallocateCurrentThread()
+{
+ SafeDelete(gCurrentThread);
+}
+
+void DeallocateMutex()
+{
+ DeallocateGlobalMutex(g_Mutex);
+}
+
+void DeallocateSurfaceMutex()
+{
+ DeallocateGlobalMutex(g_SurfaceMutex);
+}
+
+bool InitializeProcess()
+{
+ EnsureDebugAllocated();
+ AllocateMutex();
+ return AllocateCurrentThread() != nullptr;
+}
+
+void TerminateProcess()
+{
+ DeallocateDebug();
+ DeallocateSurfaceMutex();
+ DeallocateMutex();
+ DeallocateCurrentThread();
+}
+
+} // anonymous namespace
+
+} // namespace egl
+
+namespace
+{
+// The following WaitForDebugger code is based on SwiftShader. See:
+// https://cs.chromium.org/chromium/src/third_party/swiftshader/src/Vulkan/main.cpp
+# if defined(ANGLE_ENABLE_ASSERTS) && !defined(ANGLE_ENABLE_WINDOWS_UWP)
+INT_PTR CALLBACK DebuggerWaitDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ RECT rect;
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ ::GetWindowRect(GetDesktopWindow(), &rect);
+ ::SetWindowPos(hwnd, HWND_TOP, rect.right / 2, rect.bottom / 2, 0, 0, SWP_NOSIZE);
+ ::SetTimer(hwnd, 1, 100, NULL);
+ return TRUE;
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDCANCEL)
+ {
+ ::EndDialog(hwnd, 0);
+ }
+ break;
+ case WM_TIMER:
+ if (angle::IsDebuggerAttached())
+ {
+ ::EndDialog(hwnd, 0);
+ }
+ }
+
+ return FALSE;
+}
+
+void WaitForDebugger(HINSTANCE instance)
+{
+ if (angle::IsDebuggerAttached())
+ return;
+
+ HRSRC dialog = ::FindResourceA(instance, MAKEINTRESOURCEA(IDD_DIALOG1), MAKEINTRESOURCEA(5));
+ if (!dialog)
+ {
+ printf("Error finding wait for debugger dialog. Error %lu.\n", ::GetLastError());
+ return;
+ }
+
+ DLGTEMPLATE *dialogTemplate = reinterpret_cast<DLGTEMPLATE *>(::LoadResource(instance, dialog));
+ ::DialogBoxIndirectA(instance, dialogTemplate, NULL, DebuggerWaitDialogProc);
+}
+# else
+void WaitForDebugger(HINSTANCE instance) {}
+# endif // defined(ANGLE_ENABLE_ASSERTS) && !defined(ANGLE_ENABLE_WINDOWS_UWP)
+} // namespace
+
+extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID)
+{
+ switch (reason)
+ {
+ case DLL_PROCESS_ATTACH:
+ if (angle::GetEnvironmentVar("ANGLE_WAIT_FOR_DEBUGGER") == "1")
+ {
+ WaitForDebugger(instance);
+ }
+ return static_cast<BOOL>(egl::InitializeProcess());
+
+ case DLL_THREAD_ATTACH:
+ return static_cast<BOOL>(egl::AllocateCurrentThread() != nullptr);
+
+ case DLL_THREAD_DETACH:
+ egl::DeallocateCurrentThread();
+ break;
+
+ case DLL_PROCESS_DETACH:
+ egl::TerminateProcess();
+ break;
+ }
+
+ return TRUE;
+}
+#endif // defined(ANGLE_PLATFORM_WINDOWS) && !defined(ANGLE_STATIC)