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