crypt32: Fix compilation on systems that don't support nameless unions.
[wine] / dlls / wined3d / wined3d_main.c
1 /*
2  * Direct3D wine internal interface main
3  *
4  * Copyright 2002-2003 The wine-d3d team
5  * Copyright 2002-2003 Raphael Junqueira
6  * Copyright 2004      Jason Edmeades
7  * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
8  * Copyright 2009 Henri Verbeet for CodeWeavers
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24
25 #include "config.h"
26
27 #include "initguid.h"
28 #include "wined3d_private.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
31
32 int num_lock = 0;
33 void (*CDECL wine_tsx11_lock_ptr)(void) = NULL;
34 void (*CDECL wine_tsx11_unlock_ptr)(void) = NULL;
35
36 static CRITICAL_SECTION wined3d_cs;
37 static CRITICAL_SECTION_DEBUG wined3d_cs_debug =
38 {
39     0, 0, &wined3d_cs,
40     {&wined3d_cs_debug.ProcessLocksList,
41     &wined3d_cs_debug.ProcessLocksList},
42     0, 0, {(DWORD_PTR)(__FILE__ ": wined3d_cs")}
43 };
44 static CRITICAL_SECTION wined3d_cs = {&wined3d_cs_debug, -1, 0, 0, 0, 0};
45
46 /* When updating default value here, make sure to update winecfg as well,
47  * where appropriate. */
48 wined3d_settings_t wined3d_settings =
49 {
50     VS_HW,          /* Hardware by default */
51     PS_HW,          /* Hardware by default */
52     TRUE,           /* Use of GLSL enabled by default */
53     ORM_FBO,        /* Use FBOs to do offscreen rendering */
54     RTL_READTEX,    /* Default render target locking method */
55     PCI_VENDOR_NONE,/* PCI Vendor ID */
56     PCI_DEVICE_NONE,/* PCI Device ID */
57     0,              /* The default of memory is set in FillGLCaps */
58     NULL,           /* No wine logo by default */
59     FALSE           /* Disable multisampling for now due to Nvidia driver bugs which happens for some users */
60 };
61
62 IWineD3D* WINAPI WineDirect3DCreate(UINT dxVersion, IUnknown *parent) {
63     IWineD3DImpl* object;
64
65     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DImpl));
66     object->lpVtbl = &IWineD3D_Vtbl;
67     object->dxVersion = dxVersion;
68     object->ref = 1;
69     object->parent = parent;
70
71     if (!InitAdapters(object))
72     {
73         WARN("Failed to initialize direct3d adapters, Direct3D will not be available\n");
74         if (dxVersion > 7)
75         {
76             ERR("Direct3D%d is not available without opengl\n", dxVersion);
77             HeapFree(GetProcessHeap(), 0, object);
78             return NULL;
79         }
80     }
81
82     TRACE("Created WineD3D object @ %p for d3d%d support\n", object, dxVersion);
83
84     return (IWineD3D *)object;
85 }
86
87 static inline DWORD get_config_key(HKEY defkey, HKEY appkey, const char* name, char* buffer, DWORD size)
88 {
89     if (0 != appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE) buffer, &size )) return 0;
90     if (0 != defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE) buffer, &size )) return 0;
91     return ERROR_FILE_NOT_FOUND;
92 }
93
94 static inline DWORD get_config_key_dword(HKEY defkey, HKEY appkey, const char* name, DWORD *data)
95 {
96     DWORD type;
97     DWORD size = sizeof(DWORD);
98     if (0 != appkey && !RegQueryValueExA( appkey, name, 0, &type, (LPBYTE) data, &size ) && (type == REG_DWORD)) return 0;
99     if (0 != defkey && !RegQueryValueExA( defkey, name, 0, &type, (LPBYTE) data, &size ) && (type == REG_DWORD)) return 0;
100     return ERROR_FILE_NOT_FOUND;
101 }
102
103 static void CDECL wined3d_do_nothing(void)
104 {
105 }
106
107 static BOOL wined3d_init(HINSTANCE hInstDLL)
108 {
109     DWORD wined3d_context_tls_idx;
110     HMODULE mod;
111     char buffer[MAX_PATH+10];
112     DWORD size = sizeof(buffer);
113     HKEY hkey = 0;
114     HKEY appkey = 0;
115     DWORD len, tmpvalue;
116     WNDCLASSA wc;
117
118     wined3d_context_tls_idx = TlsAlloc();
119     if (wined3d_context_tls_idx == TLS_OUT_OF_INDEXES)
120     {
121         DWORD err = GetLastError();
122         ERR("Failed to allocate context TLS index, err %#x.\n", err);
123         return FALSE;
124     }
125     context_set_tls_idx(wined3d_context_tls_idx);
126
127     /* We need our own window class for a fake window which we use to retrieve GL capabilities */
128     /* We might need CS_OWNDC in the future if we notice strange things on Windows.
129      * Various articles/posts about OpenGL problems on Windows recommend this. */
130     wc.style                = CS_HREDRAW | CS_VREDRAW;
131     wc.lpfnWndProc          = DefWindowProcA;
132     wc.cbClsExtra           = 0;
133     wc.cbWndExtra           = 0;
134     wc.hInstance            = hInstDLL;
135     wc.hIcon                = LoadIconA(NULL, (LPCSTR)IDI_WINLOGO);
136     wc.hCursor              = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
137     wc.hbrBackground        = NULL;
138     wc.lpszMenuName         = NULL;
139     wc.lpszClassName        = WINED3D_OPENGL_WINDOW_CLASS_NAME;
140
141     if (!RegisterClassA(&wc))
142     {
143         ERR("Failed to register window class 'WineD3D_OpenGL'!\n");
144         if (!TlsFree(wined3d_context_tls_idx))
145         {
146             DWORD err = GetLastError();
147             ERR("Failed to free context TLS index, err %#x.\n", err);
148         }
149         return FALSE;
150     }
151
152     DisableThreadLibraryCalls(hInstDLL);
153
154     mod = GetModuleHandleA( "winex11.drv" );
155     if (mod)
156     {
157         wine_tsx11_lock_ptr   = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
158         wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
159     }
160     else /* We are most likely on Windows */
161     {
162         wine_tsx11_lock_ptr   = wined3d_do_nothing;
163         wine_tsx11_unlock_ptr = wined3d_do_nothing;
164     }
165     /* @@ Wine registry key: HKCU\Software\Wine\Direct3D */
166     if ( RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Direct3D", &hkey ) ) hkey = 0;
167
168     len = GetModuleFileNameA( 0, buffer, MAX_PATH );
169     if (len && len < MAX_PATH)
170     {
171         HKEY tmpkey;
172         /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\Direct3D */
173         if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey ))
174         {
175             char *p, *appname = buffer;
176             if ((p = strrchr( appname, '/' ))) appname = p + 1;
177             if ((p = strrchr( appname, '\\' ))) appname = p + 1;
178             strcat( appname, "\\Direct3D" );
179             TRACE("appname = [%s]\n", appname);
180             if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
181             RegCloseKey( tmpkey );
182         }
183     }
184
185     if ( 0 != hkey || 0 != appkey )
186     {
187         if ( !get_config_key( hkey, appkey, "VertexShaderMode", buffer, size) )
188         {
189             if (!strcmp(buffer,"none"))
190             {
191                 TRACE("Disable vertex shaders\n");
192                 wined3d_settings.vs_mode = VS_NONE;
193             }
194         }
195         if ( !get_config_key( hkey, appkey, "PixelShaderMode", buffer, size) )
196         {
197             if (!strcmp(buffer,"enabled"))
198             {
199                 TRACE("Allow pixel shaders\n");
200                 wined3d_settings.ps_mode = PS_HW;
201             }
202             if (!strcmp(buffer,"disabled"))
203             {
204                 TRACE("Disable pixel shaders\n");
205                 wined3d_settings.ps_mode = PS_NONE;
206             }
207         }
208         if ( !get_config_key( hkey, appkey, "UseGLSL", buffer, size) )
209         {
210             if (!strcmp(buffer,"disabled"))
211             {
212                 TRACE("Use of GL Shading Language disabled\n");
213                 wined3d_settings.glslRequested = FALSE;
214             }
215         }
216         if ( !get_config_key( hkey, appkey, "OffscreenRenderingMode", buffer, size) )
217         {
218             if (!strcmp(buffer,"backbuffer"))
219             {
220                 TRACE("Using the backbuffer for offscreen rendering\n");
221                 wined3d_settings.offscreen_rendering_mode = ORM_BACKBUFFER;
222             }
223             else if (!strcmp(buffer,"pbuffer"))
224             {
225                 TRACE("Using PBuffers for offscreen rendering\n");
226                 wined3d_settings.offscreen_rendering_mode = ORM_PBUFFER;
227             }
228             else if (!strcmp(buffer,"fbo"))
229             {
230                 TRACE("Using FBOs for offscreen rendering\n");
231                 wined3d_settings.offscreen_rendering_mode = ORM_FBO;
232             }
233         }
234         if ( !get_config_key( hkey, appkey, "RenderTargetLockMode", buffer, size) )
235         {
236             if (!strcmp(buffer,"disabled"))
237             {
238                 TRACE("Disabling render target locking\n");
239                 wined3d_settings.rendertargetlock_mode = RTL_DISABLE;
240             }
241             else if (!strcmp(buffer,"readdraw"))
242             {
243                 TRACE("Using glReadPixels for render target reading and glDrawPixels for writing\n");
244                 wined3d_settings.rendertargetlock_mode = RTL_READDRAW;
245             }
246             else if (!strcmp(buffer,"readtex"))
247             {
248                 TRACE("Using glReadPixels for render target reading and textures for writing\n");
249                 wined3d_settings.rendertargetlock_mode = RTL_READTEX;
250             }
251         }
252         if ( !get_config_key_dword( hkey, appkey, "VideoPciDeviceID", &tmpvalue) )
253         {
254             int pci_device_id = tmpvalue;
255
256             /* A pci device id is 16-bit */
257             if(pci_device_id > 0xffff)
258             {
259                 ERR("Invalid value for VideoPciDeviceID. The value should be smaller or equal to 65535 or 0xffff\n");
260             }
261             else
262             {
263                 TRACE("Using PCI Device ID %04x\n", pci_device_id);
264                 wined3d_settings.pci_device_id = pci_device_id;
265             }
266         }
267         if ( !get_config_key_dword( hkey, appkey, "VideoPciVendorID", &tmpvalue) )
268         {
269             int pci_vendor_id = tmpvalue;
270
271             /* A pci device id is 16-bit */
272             if(pci_vendor_id > 0xffff)
273             {
274                 ERR("Invalid value for VideoPciVendorID. The value should be smaller or equal to 65535 or 0xffff\n");
275             }
276             else
277             {
278                 TRACE("Using PCI Vendor ID %04x\n", pci_vendor_id);
279                 wined3d_settings.pci_vendor_id = pci_vendor_id;
280             }
281         }
282         if ( !get_config_key( hkey, appkey, "VideoMemorySize", buffer, size) )
283         {
284             int TmpVideoMemorySize = atoi(buffer);
285             if(TmpVideoMemorySize > 0)
286             {
287                 wined3d_settings.emulated_textureram = TmpVideoMemorySize *1024*1024;
288                 TRACE("Use %iMB = %d byte for emulated_textureram\n",
289                         TmpVideoMemorySize,
290                         wined3d_settings.emulated_textureram);
291             }
292             else
293                 ERR("VideoMemorySize is %i but must be >0\n", TmpVideoMemorySize);
294         }
295         if ( !get_config_key( hkey, appkey, "WineLogo", buffer, size) )
296         {
297             size_t len = strlen(buffer) + 1;
298
299             wined3d_settings.logo = HeapAlloc(GetProcessHeap(), 0, len);
300             if (!wined3d_settings.logo) ERR("Failed to allocate logo path memory.\n");
301             else memcpy(wined3d_settings.logo, buffer, len);
302         }
303         if ( !get_config_key( hkey, appkey, "Multisampling", buffer, size) )
304         {
305             if (!strcmp(buffer,"enabled"))
306             {
307                 TRACE("Allow multisampling\n");
308                 wined3d_settings.allow_multisampling = TRUE;
309             }
310         }
311     }
312     if (wined3d_settings.vs_mode == VS_HW)
313         TRACE("Allow HW vertex shaders\n");
314     if (wined3d_settings.ps_mode == PS_NONE)
315         TRACE("Disable pixel shaders\n");
316     if (wined3d_settings.glslRequested)
317         TRACE("If supported by your system, GL Shading Language will be used\n");
318
319     if (appkey) RegCloseKey( appkey );
320     if (hkey) RegCloseKey( hkey );
321
322     return TRUE;
323 }
324
325 static BOOL wined3d_destroy(HINSTANCE hInstDLL)
326 {
327     DWORD wined3d_context_tls_idx = context_get_tls_idx();
328
329     if (!TlsFree(wined3d_context_tls_idx))
330     {
331         DWORD err = GetLastError();
332         ERR("Failed to free context TLS index, err %#x.\n", err);
333     }
334
335     HeapFree(GetProcessHeap(), 0, wined3d_settings.logo);
336     UnregisterClassA(WINED3D_OPENGL_WINDOW_CLASS_NAME, hInstDLL);
337
338     return TRUE;
339 }
340
341 void WINAPI wined3d_mutex_lock(void)
342 {
343     EnterCriticalSection(&wined3d_cs);
344 }
345
346 void WINAPI wined3d_mutex_unlock(void)
347 {
348     LeaveCriticalSection(&wined3d_cs);
349 }
350
351 /* At process attach */
352 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
353 {
354     TRACE("WineD3D DLLMain Reason=%u\n", fdwReason);
355
356     switch (fdwReason)
357     {
358         case DLL_PROCESS_ATTACH:
359             return wined3d_init(hInstDLL);
360
361         case DLL_PROCESS_DETACH:
362             return wined3d_destroy(hInstDLL);
363
364         case DLL_THREAD_DETACH:
365         {
366             if (!context_set_current(NULL))
367             {
368                 ERR("Failed to clear current context.\n");
369             }
370             return TRUE;
371         }
372
373         default:
374             return TRUE;
375     }
376 }