#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/egl_stubs_autogen.h"
#include "libGLESv2/resource.h"
#include <atomic>
#if defined(ANGLE_PLATFORM_APPLE)
# include <dispatch/dispatch.h>
#endif
namespace egl
{
namespace
{
ANGLE_REQUIRE_CONSTANT_INIT gl::Context *g_LastContext(nullptr);
static_assert …;
bool g_EGLValidationEnabled = …;
[[maybe_unused]] void ThreadCleanupCallback(void *ptr)
{ … }
Thread *AllocateCurrentThread()
{ … }
}
#if defined(ANGLE_PLATFORM_APPLE)
static angle::TLSIndex GetCurrentThreadTLSIndex()
{
static angle::TLSIndex CurrentThreadIndex = TLS_INVALID_INDEX;
static dispatch_once_t once;
dispatch_once(&once, ^{
ASSERT(CurrentThreadIndex == TLS_INVALID_INDEX);
CurrentThreadIndex = angle::CreateTLSIndex(nullptr);
});
return CurrentThreadIndex;
}
Thread *GetCurrentThreadTLS()
{
angle::TLSIndex CurrentThreadIndex = GetCurrentThreadTLSIndex();
ASSERT(CurrentThreadIndex != TLS_INVALID_INDEX);
return static_cast<Thread *>(angle::GetTLSValue(CurrentThreadIndex));
}
void SetCurrentThreadTLS(Thread *thread)
{
angle::TLSIndex CurrentThreadIndex = GetCurrentThreadTLSIndex();
ASSERT(CurrentThreadIndex != TLS_INVALID_INDEX);
angle::SetTLSValue(CurrentThreadIndex, thread);
}
#elif defined(ANGLE_USE_STATIC_THREAD_LOCAL_VARIABLES)
static thread_local Thread *gCurrentThread = nullptr;
Thread *GetCurrentThreadTLS()
{
return gCurrentThread;
}
void SetCurrentThreadTLS(Thread *thread)
{
gCurrentThread = thread;
}
#else
thread_local Thread *gCurrentThread = …;
#endif
gl::Context *GetGlobalLastContext()
{ … }
void SetGlobalLastContext(gl::Context *context)
{ … }
ANGLE_NO_SANITIZE_MEMORY ANGLE_NO_SANITIZE_THREAD Thread *GetCurrentThread()
{ … }
void SetContextCurrent(Thread *thread, gl::Context *context)
{ … }
ScopedSyncCurrentContextFromThread::ScopedSyncCurrentContextFromThread(egl::Thread *thread)
: … { … }
ScopedSyncCurrentContextFromThread::~ScopedSyncCurrentContextFromThread()
{ … }
void SetEGLValidationEnabled(bool enabled)
{ … }
bool IsEGLValidationEnabled()
{ … }
}
namespace gl
{
void GenerateContextLostErrorOnContext(Context *context)
{ … }
void GenerateContextLostErrorOnCurrentGlobalContext()
{ … }
}
#if defined(ANGLE_PLATFORM_WINDOWS) && !defined(ANGLE_STATIC)
namespace egl
{
namespace
{
void DeallocateCurrentThread()
{
SafeDelete(gCurrentThread);
}
bool InitializeProcess()
{
EnsureDebugAllocated();
AllocateGlobalMutex();
return AllocateCurrentThread() != nullptr;
}
void TerminateProcess()
{
DeallocateDebug();
DeallocateGlobalMutex();
DeallocateCurrentThread();
}
}
}
namespace
{
# 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
}
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