1// Copyright 2016 The SwiftShader Authors. All Rights Reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15// main.cpp: DLL entry point and management of thread-local data. 16 17#include "main.h" 18 19#include "resource.h" 20#include "Framebuffer.h" 21#include "Surface.h" 22#include "Common/Thread.hpp" 23#include "common/debug.h" 24 25static sw::Thread::LocalStorageKey currentTLS = TLS_OUT_OF_INDEXES; 26 27#if !defined(_MSC_VER) 28#define CONSTRUCTOR __attribute__((constructor)) 29#define DESTRUCTOR __attribute__((destructor)) 30#else 31#define CONSTRUCTOR 32#define DESTRUCTOR 33#endif 34 35static void glAttachThread() 36{ 37 TRACE("()"); 38 39 gl::Current *current = (gl::Current*)sw::Thread::allocateLocalStorage(currentTLS, sizeof(gl::Current)); 40 41 if(current) 42 { 43 current->context = nullptr; 44 current->display = nullptr; 45 current->drawSurface = nullptr; 46 current->readSurface = nullptr; 47 } 48} 49 50static void glDetachThread() 51{ 52 TRACE("()"); 53 54 wglMakeCurrent(NULL, NULL); 55 56 sw::Thread::freeLocalStorage(currentTLS); 57} 58 59CONSTRUCTOR static bool glAttachProcess() 60{ 61 TRACE("()"); 62 63 #if !(ANGLE_DISABLE_TRACE) 64 FILE *debug = fopen(TRACE_OUTPUT_FILE, "rt"); 65 66 if(debug) 67 { 68 fclose(debug); 69 debug = fopen(TRACE_OUTPUT_FILE, "wt"); // Erase 70 fclose(debug); 71 } 72 #endif 73 74 currentTLS = sw::Thread::allocateLocalStorageKey(); 75 76 if(currentTLS == TLS_OUT_OF_INDEXES) 77 { 78 return false; 79 } 80 81 glAttachThread(); 82 83 return true; 84} 85 86DESTRUCTOR static void glDetachProcess() 87{ 88 TRACE("()"); 89 90 glDetachThread(); 91 92 sw::Thread::freeLocalStorageKey(currentTLS); 93} 94 95#if defined(_WIN32) 96static INT_PTR CALLBACK DebuggerWaitDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 97{ 98 RECT rect; 99 100 switch(uMsg) 101 { 102 case WM_INITDIALOG: 103 GetWindowRect(GetDesktopWindow(), &rect); 104 SetWindowPos(hwnd, HWND_TOP, rect.right / 2, rect.bottom / 2, 0, 0, SWP_NOSIZE); 105 SetTimer(hwnd, 1, 100, NULL); 106 return TRUE; 107 case WM_COMMAND: 108 if(LOWORD(wParam) == IDCANCEL) 109 { 110 EndDialog(hwnd, 0); 111 } 112 break; 113 case WM_TIMER: 114 if(IsDebuggerPresent()) 115 { 116 EndDialog(hwnd, 0); 117 } 118 } 119 120 return FALSE; 121} 122 123static void WaitForDebugger(HINSTANCE instance) 124{ 125 if(!IsDebuggerPresent()) 126 { 127 HRSRC dialog = FindResource(instance, MAKEINTRESOURCE(IDD_DIALOG1), RT_DIALOG); 128 DLGTEMPLATE *dialogTemplate = (DLGTEMPLATE*)LoadResource(instance, dialog); 129 DialogBoxIndirect(instance, dialogTemplate, NULL, DebuggerWaitDialogProc); 130 } 131} 132 133extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) 134{ 135 switch(reason) 136 { 137 case DLL_PROCESS_ATTACH: 138 #ifndef NDEBUG 139 WaitForDebugger(instance); 140 #endif 141 return glAttachProcess(); 142 break; 143 case DLL_THREAD_ATTACH: 144 glAttachThread(); 145 break; 146 case DLL_THREAD_DETACH: 147 glDetachThread(); 148 break; 149 case DLL_PROCESS_DETACH: 150 glDetachProcess(); 151 break; 152 default: 153 break; 154 } 155 156 return TRUE; 157} 158#endif 159 160namespace gl 161{ 162static gl::Current *getCurrent(void) 163{ 164 Current *current = (Current*)sw::Thread::getLocalStorage(currentTLS); 165 166 if(!current) 167 { 168 glAttachThread(); 169 } 170 171 return (Current*)sw::Thread::getLocalStorage(currentTLS); 172} 173 174void makeCurrent(Context *context, Display *display, Surface *surface) 175{ 176 Current *current = getCurrent(); 177 178 current->context = context; 179 current->display = display; 180 181 if(context && display && surface) 182 { 183 context->makeCurrent(surface); 184 } 185} 186 187Context *getContext() 188{ 189 Current *current = getCurrent(); 190 191 return current->context; 192} 193 194Display *getDisplay() 195{ 196 Current *current = getCurrent(); 197 198 return current->display; 199} 200 201Device *getDevice() 202{ 203 Context *context = getContext(); 204 205 return context ? context->getDevice() : nullptr; 206} 207 208void setCurrentDisplay(Display *dpy) 209{ 210 Current *current = getCurrent(); 211 212 current->display = dpy; 213} 214 215void setCurrentContext(gl::Context *ctx) 216{ 217 Current *current = getCurrent(); 218 219 current->context = ctx; 220} 221 222void setCurrentDrawSurface(Surface *surface) 223{ 224 Current *current = getCurrent(); 225 226 current->drawSurface = surface; 227} 228 229Surface *getCurrentDrawSurface() 230{ 231 Current *current = getCurrent(); 232 233 return current->drawSurface; 234} 235 236void setCurrentReadSurface(Surface *surface) 237{ 238 Current *current = getCurrent(); 239 240 current->readSurface = surface; 241} 242 243Surface *getCurrentReadSurface() 244{ 245 Current *current = getCurrent(); 246 247 return current->readSurface; 248} 249} 250 251// Records an error code 252void error(GLenum errorCode) 253{ 254 gl::Context *context = gl::getContext(); 255 256 if(context) 257 { 258 switch(errorCode) 259 { 260 case GL_INVALID_ENUM: 261 context->recordInvalidEnum(); 262 TRACE("\t! Error generated: invalid enum\n"); 263 break; 264 case GL_INVALID_VALUE: 265 context->recordInvalidValue(); 266 TRACE("\t! Error generated: invalid value\n"); 267 break; 268 case GL_INVALID_OPERATION: 269 context->recordInvalidOperation(); 270 TRACE("\t! Error generated: invalid operation\n"); 271 break; 272 case GL_OUT_OF_MEMORY: 273 context->recordOutOfMemory(); 274 TRACE("\t! Error generated: out of memory\n"); 275 break; 276 case GL_INVALID_FRAMEBUFFER_OPERATION: 277 context->recordInvalidFramebufferOperation(); 278 TRACE("\t! Error generated: invalid framebuffer operation\n"); 279 break; 280 default: UNREACHABLE(errorCode); 281 } 282 } 283} 284