Added Norwegian translations.
[wine] / dlls / ddraw / main.c
1 /*              DirectDraw Base Functions
2  *
3  * Copyright 1997-1999 Marcus Meissner
4  * Copyright 1998 Lionel Ulmer (most of Direct3D stuff)
5  * Copyright 2000-2001 TransGaming Technologies Inc.
6  *
7  * This file contains the (internal) driver registration functions,
8  * driver enumeration APIs and DirectDraw creation functions.
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  */
24
25 #define GLPRIVATE_NO_REDEFINE
26
27 #include "config.h"
28 #include "wine/port.h"
29
30 #include <assert.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <stdlib.h>
34
35 #define COBJMACROS
36
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winnls.h"
40 #include "winerror.h"
41 #include "wingdi.h"
42
43 #include "ddraw.h"
44 #include "d3d.h"
45
46 /* This for all the enumeration and creation of D3D-related objects */
47 #include "ddraw_private.h"
48 #include "wine/debug.h"
49 #include "wine/library.h"
50
51 #include "gl_private.h"
52
53 #undef GLPRIVATE_NO_REDEFINE
54
55 #define MAX_DDRAW_DRIVERS 3
56 static const ddraw_driver* DDRAW_drivers[MAX_DDRAW_DRIVERS];
57 static int DDRAW_num_drivers; /* = 0 */
58 static int DDRAW_default_driver;
59
60 void (*wine_tsx11_lock_ptr)(void) = NULL;
61 void (*wine_tsx11_unlock_ptr)(void) = NULL;
62
63 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
64
65 /**********************************************************************/
66
67 typedef struct {
68     LPVOID lpCallback;
69     LPVOID lpContext;
70 } DirectDrawEnumerateProcData;
71
72 BOOL opengl_initialized = 0;
73
74 #ifdef HAVE_OPENGL
75
76 #include "opengl_private.h"
77
78 static void *gl_handle = NULL;
79
80 #define GL_API_FUNCTION(f) typeof(f) * p##f;
81 #include "gl_api.h"
82 #undef GL_API_FUNCTION
83
84 #ifndef SONAME_LIBGL
85 #define SONAME_LIBGL "libGL.so"
86 #endif
87
88 static BOOL DDRAW_bind_to_opengl( void )
89 {
90     const char *glname = SONAME_LIBGL;
91
92     gl_handle = wine_dlopen(glname, RTLD_NOW, NULL, 0);
93     if (!gl_handle) {
94         WARN("Wine cannot find the OpenGL graphics library (%s).\n",glname);
95         return FALSE;
96     }
97
98 #define GL_API_FUNCTION(f)  \
99     if((p##f = wine_dlsym(gl_handle, #f, NULL, 0)) == NULL) \
100     { \
101         WARN("Can't find symbol %s\n", #f); \
102         goto sym_not_found; \
103     }
104 #include "gl_api.h"
105 #undef GL_API_FUNCTION
106
107     /* And now calls the function to initialize the various fields for the rendering devices */
108     return d3ddevice_init_at_startup(gl_handle);
109     
110 sym_not_found:
111     WARN("Wine cannot find certain functions that it needs inside the OpenGL\n"
112          "graphics library.  To enable Wine to use OpenGL please upgrade\n"
113          "your OpenGL libraries\n");
114     wine_dlclose(gl_handle, NULL, 0);
115     gl_handle = NULL;
116     return FALSE;
117 }
118
119 #endif /* HAVE_OPENGL */
120
121 BOOL s3tc_initialized = 0;
122
123 static void *s3tc_handle = NULL;
124
125 FUNC_FETCH_2D_TEXEL_RGBA_DXT1 fetch_2d_texel_rgba_dxt1;
126 FUNC_FETCH_2D_TEXEL_RGBA_DXT3 fetch_2d_texel_rgba_dxt3;
127 FUNC_FETCH_2D_TEXEL_RGBA_DXT5 fetch_2d_texel_rgba_dxt5;
128
129 #ifndef SONAME_LIBTXC_DXTN
130 #define SONAME_LIBTXC_DXTN "libtxc_dxtn.so"
131 #endif
132
133 static BOOL DDRAW_bind_to_s3tc( void )
134 {
135     const char * const s3tcname = SONAME_LIBTXC_DXTN;
136
137     s3tc_handle = wine_dlopen(s3tcname, RTLD_NOW, NULL, 0);
138     if (!s3tc_handle) {
139         TRACE("No S3TC software decompression library seems to be present (%s).\n",s3tcname);
140         return FALSE;
141     }
142     TRACE("Found S3TC software decompression library (%s).\n",s3tcname);
143
144 #define API_FUNCTION(f)  \
145     if((f = wine_dlsym(s3tc_handle, #f, NULL, 0)) == NULL) \
146     { \
147         WARN("Can't find symbol %s\n", #f); \
148         goto sym_not_found; \
149     }
150     API_FUNCTION(fetch_2d_texel_rgba_dxt1);
151     API_FUNCTION(fetch_2d_texel_rgba_dxt3);
152     API_FUNCTION(fetch_2d_texel_rgba_dxt5);
153 #undef API_FUNCTION
154
155     return TRUE;
156     
157 sym_not_found:
158     WARN("Wine cannot find functions that are necessary for S3TC software decompression\n");
159     wine_dlclose(s3tc_handle, NULL, 0);
160     s3tc_handle = NULL;
161     return FALSE;
162 }
163
164 /*******************************************************************************
165  * DirectDrawEnumerateExA (DDRAW.@)
166  *
167  * Enumerates all DirectDraw devices installed on the system.
168  *
169  * PARAMS
170  *  lpCallback [I] DDEnumCallbackEx function to be called with a description of 
171  *                 each enumerated HAL.
172  *  lpContext  [I] application-defined value to be passed to the callback.
173  *  dwFlags    [I] Specifies the enumeration scope. see msdn.
174  *
175  * RETURNS
176  *  Success: DD_OK.
177  *  Failure: DDERR_INVALIDPARAMS
178  */
179 HRESULT WINAPI DirectDrawEnumerateExA(
180     LPDDENUMCALLBACKEXA lpCallback, LPVOID lpContext, DWORD dwFlags)
181 {
182     int i;
183     TRACE("(%p,%p, %08lx)\n", lpCallback, lpContext, dwFlags);
184
185     if (TRACE_ON(ddraw)) {
186         TRACE("  Flags : ");
187         if (dwFlags & DDENUM_ATTACHEDSECONDARYDEVICES)
188             TRACE("DDENUM_ATTACHEDSECONDARYDEVICES ");
189         if (dwFlags & DDENUM_DETACHEDSECONDARYDEVICES)
190             TRACE("DDENUM_DETACHEDSECONDARYDEVICES ");
191         if (dwFlags & DDENUM_NONDISPLAYDEVICES)
192             TRACE("DDENUM_NONDISPLAYDEVICES ");
193         TRACE("\n");
194     }
195
196     for (i=0; i<DDRAW_num_drivers; i++)
197     {
198         TRACE("Enumerating %s/%s interface\n",
199               DDRAW_drivers[i]->info->szDriver,
200               DDRAW_drivers[i]->info->szDescription);
201
202         /* We have to pass NULL from the primary display device.
203          * RoadRage chapter 6's enumeration routine expects it. */
204         if (!lpCallback((DDRAW_default_driver == i) ? NULL
205                         :(LPGUID)&DDRAW_drivers[i]->info->guidDeviceIdentifier,
206                         (LPSTR)DDRAW_drivers[i]->info->szDescription,
207                         (LPSTR)DDRAW_drivers[i]->info->szDriver,
208                         lpContext, 0))
209             return DD_OK;
210     }
211
212     /* Unsupported flags */
213     if (dwFlags & DDENUM_NONDISPLAYDEVICES) {
214         FIXME("no non-display devices supported.\n");
215     }
216     if (dwFlags & DDENUM_DETACHEDSECONDARYDEVICES) {
217         FIXME("no detached secondary devices supported.\n");
218     }
219
220     return DD_OK;
221 }
222
223 /*******************************************************************************
224  * DirectDrawEnumerateExW (DDRAW.@)
225  */
226
227 static BOOL CALLBACK DirectDrawEnumerateExProcW(
228     GUID *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName,
229     LPVOID lpContext, HMONITOR hm)
230 {
231     INT len;
232     BOOL bResult;
233     LPWSTR lpDriverDescriptionW, lpDriverNameW;
234     DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext;
235
236     len = MultiByteToWideChar( CP_ACP, 0, lpDriverDescription, -1, NULL, 0 );
237     lpDriverDescriptionW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
238     MultiByteToWideChar( CP_ACP, 0, lpDriverDescription, -1, lpDriverDescriptionW, len );
239
240     len = MultiByteToWideChar( CP_ACP, 0, lpDriverName, -1, NULL, 0 );
241     lpDriverNameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
242     MultiByteToWideChar( CP_ACP, 0, lpDriverName, -1, lpDriverNameW, len );
243
244     bResult = (*(LPDDENUMCALLBACKEXW *) pEPD->lpCallback)(lpGUID, lpDriverDescriptionW,
245                                                           lpDriverNameW, pEPD->lpContext, hm);
246
247     HeapFree(GetProcessHeap(), 0, lpDriverDescriptionW);
248     HeapFree(GetProcessHeap(), 0, lpDriverNameW);
249     return bResult;
250 }
251
252 HRESULT WINAPI DirectDrawEnumerateExW(
253   LPDDENUMCALLBACKEXW lpCallback, LPVOID lpContext, DWORD dwFlags)
254 {
255     DirectDrawEnumerateProcData epd;
256     epd.lpCallback = (LPVOID) lpCallback;
257     epd.lpContext = lpContext;
258
259     return DirectDrawEnumerateExA(DirectDrawEnumerateExProcW, (LPVOID) &epd, 0);
260 }
261
262 /***********************************************************************
263  *              DirectDrawEnumerateA (DDRAW.@)
264  */
265
266 static BOOL CALLBACK DirectDrawEnumerateProcA(
267         GUID *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName,
268         LPVOID lpContext, HMONITOR hm)
269 {
270     DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext;
271
272     return ((LPDDENUMCALLBACKA) pEPD->lpCallback)(
273         lpGUID, lpDriverDescription, lpDriverName, pEPD->lpContext);
274 }
275
276 HRESULT WINAPI DirectDrawEnumerateA(
277   LPDDENUMCALLBACKA lpCallback, LPVOID lpContext)
278 {
279     DirectDrawEnumerateProcData epd;
280     epd.lpCallback = (LPVOID) lpCallback;
281     epd.lpContext = lpContext;
282
283     return DirectDrawEnumerateExA(DirectDrawEnumerateProcA, (LPVOID) &epd, 0);
284 }
285
286 /***********************************************************************
287  *              DirectDrawEnumerateW (DDRAW.@)
288  */
289
290 static BOOL WINAPI DirectDrawEnumerateProcW(
291   GUID *lpGUID, LPWSTR lpDriverDescription, LPWSTR lpDriverName,
292   LPVOID lpContext, HMONITOR hm)
293 {
294     DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext;
295
296     return ((LPDDENUMCALLBACKW) pEPD->lpCallback)(
297         lpGUID, lpDriverDescription, lpDriverName, pEPD->lpContext);
298 }
299
300 HRESULT WINAPI DirectDrawEnumerateW(
301   LPDDENUMCALLBACKW lpCallback, LPVOID lpContext)
302 {
303     DirectDrawEnumerateProcData epd;
304     epd.lpCallback = (LPVOID) lpCallback;
305     epd.lpContext = lpContext;
306
307     return DirectDrawEnumerateExW(DirectDrawEnumerateProcW, (LPVOID) &epd, 0);
308 }
309
310 /***********************************************************************
311  *              DirectDrawCreate (DDRAW.@)
312  */
313
314 const ddraw_driver* DDRAW_FindDriver(const GUID* pGUID)
315 {
316     static const GUID zeroGUID; /* gets zero-inited */
317
318     TRACE("(%s)\n", pGUID ? debugstr_guid(pGUID) : "(null)");
319
320     if (DDRAW_num_drivers == 0) return NULL;
321
322     if (pGUID == (LPGUID)DDCREATE_EMULATIONONLY
323         || pGUID == (LPGUID)DDCREATE_HARDWAREONLY)
324         pGUID = NULL;
325
326     if (pGUID == NULL || memcmp(pGUID, &zeroGUID, sizeof(GUID)) == 0)
327     {
328         /* Use the default driver. */
329         return DDRAW_drivers[DDRAW_default_driver];
330     }
331     else
332     {
333         /* Look for a matching GUID. */
334
335         int i;
336         for (i=0; i < DDRAW_num_drivers; i++)
337         {
338             if (IsEqualGUID(pGUID,
339                             &DDRAW_drivers[i]->info->guidDeviceIdentifier))
340                 break;
341         }
342
343         if (i < DDRAW_num_drivers)
344         {
345             return DDRAW_drivers[i];
346         }
347         else
348         {
349             ERR("(%s): did not recognize requested GUID.\n",debugstr_guid(pGUID));
350             return NULL;
351         }
352     }
353 }
354
355 static HRESULT DDRAW_Create(
356         LPGUID lpGUID, LPVOID *lplpDD, LPUNKNOWN pUnkOuter, REFIID iid, BOOL ex
357 ) {
358     const ddraw_driver* driver;
359     LPDIRECTDRAW7 pDD;
360     HRESULT hr;
361
362     TRACE("(%s,%p,%p,%d)\n", debugstr_guid(lpGUID), lplpDD, pUnkOuter, ex);
363
364     if (DDRAW_num_drivers == 0)
365     {
366         WARN("no DirectDraw drivers registered\n");
367         return DDERR_INVALIDDIRECTDRAWGUID;
368     }
369
370     if (lpGUID == (LPGUID)DDCREATE_EMULATIONONLY
371         || lpGUID == (LPGUID)DDCREATE_HARDWAREONLY)
372         lpGUID = NULL;
373
374     if (pUnkOuter != NULL)
375         return DDERR_INVALIDPARAMS; /* CLASS_E_NOAGGREGATION? */
376
377     driver = DDRAW_FindDriver(lpGUID);
378     if (driver == NULL) return DDERR_INVALIDDIRECTDRAWGUID;
379
380     hr = driver->create(lpGUID, &pDD, pUnkOuter, ex);
381     if (FAILED(hr)) return hr;
382
383     hr = IDirectDraw7_QueryInterface(pDD, iid, lplpDD);
384     IDirectDraw7_Release(pDD);
385     return hr;
386 }
387
388 /***********************************************************************
389  *              DirectDrawCreate (DDRAW.@)
390  *
391  * Only creates legacy IDirectDraw interfaces.
392  * Cannot create IDirectDraw7 interfaces.
393  * In theory.
394  */
395 HRESULT WINAPI DirectDrawCreate(
396         LPGUID lpGUID, LPDIRECTDRAW* lplpDD, LPUNKNOWN pUnkOuter
397 ) {
398     TRACE("(%s,%p,%p)\n", debugstr_guid(lpGUID), lplpDD, pUnkOuter);
399     return DDRAW_Create(lpGUID, (LPVOID*) lplpDD, pUnkOuter, &IID_IDirectDraw, FALSE);
400 }
401
402 /***********************************************************************
403  *              DirectDrawCreateEx (DDRAW.@)
404  *
405  * Only creates new IDirectDraw7 interfaces.
406  * Supposed to fail if legacy interfaces are requested.
407  * In theory.
408  */
409 HRESULT WINAPI DirectDrawCreateEx(
410         LPGUID lpGUID, LPVOID* lplpDD, REFIID iid, LPUNKNOWN pUnkOuter
411 ) {
412     TRACE("(%s,%p,%s,%p)\n", debugstr_guid(lpGUID), lplpDD, debugstr_guid(iid), pUnkOuter);
413
414     if (!IsEqualGUID(iid, &IID_IDirectDraw7))
415         return DDERR_INVALIDPARAMS;
416
417     return DDRAW_Create(lpGUID, lplpDD, pUnkOuter, iid, TRUE);
418 }
419
420 extern HRESULT Uninit_DirectDraw_Create(const GUID*, LPDIRECTDRAW7*,
421                                         LPUNKNOWN, BOOL);
422
423 /* This is for the class factory. */
424 static HRESULT DDRAW_CreateDirectDraw(IUnknown* pUnkOuter, REFIID iid,
425                                       LPVOID* ppObj)
426 {
427     LPDIRECTDRAW7 pDD;
428     HRESULT hr;
429     BOOL ex;
430
431     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppObj);
432     
433     /* This is a mighty hack :-) */
434     if (IsEqualGUID(iid, &IID_IDirectDraw7))
435         ex = TRUE;
436     else
437         ex = FALSE;
438     
439     hr = Uninit_DirectDraw_Create(NULL, &pDD, pUnkOuter, ex);
440     if (FAILED(hr)) return hr;
441
442     hr = IDirectDraw7_QueryInterface(pDD, iid, ppObj);
443     IDirectDraw_Release(pDD);
444     return hr;
445 }
446
447 /******************************************************************************
448  * DirectDraw ClassFactory
449  */
450 typedef struct {
451     ICOM_VFIELD_MULTI(IClassFactory);
452
453     LONG ref;
454     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, REFIID iid,
455                                  LPVOID *ppObj);
456 } IClassFactoryImpl;
457
458 struct object_creation_info
459 {
460     const CLSID *clsid;
461     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, REFIID riid,
462                                  LPVOID *ppObj);
463 };
464
465 /* There should be more, but these are the only ones listed in the header
466  * file. */
467 extern HRESULT DDRAW_CreateDirectDrawClipper(IUnknown *pUnkOuter, REFIID riid,
468                                              LPVOID *ppObj);
469
470 static const struct object_creation_info object_creation[] =
471 {
472     { &CLSID_DirectDraw,        DDRAW_CreateDirectDraw },
473     { &CLSID_DirectDraw7,       DDRAW_CreateDirectDraw },
474     { &CLSID_DirectDrawClipper, DDRAW_CreateDirectDrawClipper }
475 };
476
477 static HRESULT WINAPI
478 DDCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
479 {
480     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
481
482     TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppobj);
483     
484     if (IsEqualGUID(riid, &IID_IUnknown)
485         || IsEqualGUID(riid, &IID_IClassFactory))
486     {
487         IClassFactory_AddRef(iface);
488         *ppobj = This;
489         return S_OK;
490     }
491
492     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
493     return E_NOINTERFACE;
494 }
495
496 static ULONG WINAPI DDCF_AddRef(LPCLASSFACTORY iface)
497 {
498     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
499     ULONG ref = InterlockedIncrement(&This->ref);
500
501     TRACE("(%p)->() incrementing from %ld.\n", This, ref - 1);
502     
503     return ref;
504 }
505
506 static ULONG WINAPI DDCF_Release(LPCLASSFACTORY iface)
507 {
508     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
509     ULONG ref = InterlockedDecrement(&This->ref);
510     TRACE("(%p)->() decrementing from %ld.\n", This, ref+1);
511
512     if (ref == 0)
513         HeapFree(GetProcessHeap(), 0, This);
514
515     return ref;
516 }
517
518
519 static HRESULT WINAPI DDCF_CreateInstance(
520         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
521 )
522 {
523     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
524
525     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
526
527     return This->pfnCreateInstance(pOuter, riid, ppobj);
528 }
529
530 static HRESULT WINAPI DDCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
531 {
532     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
533     FIXME("(%p)->(%d),stub!\n",This,dolock);
534     return S_OK;
535 }
536
537 static const IClassFactoryVtbl DDCF_Vtbl =
538 {
539     DDCF_QueryInterface,
540     DDCF_AddRef,
541     DDCF_Release,
542     DDCF_CreateInstance,
543     DDCF_LockServer
544 };
545
546 /*******************************************************************************
547  * DllGetClassObject [DDRAW.@]
548  * Retrieves class object from a DLL object
549  *
550  * NOTES
551  *    Docs say returns STDAPI
552  *
553  * PARAMS
554  *    rclsid [I] CLSID for the class object
555  *    riid   [I] Reference to identifier of interface for class object
556  *    ppv    [O] Address of variable to receive interface pointer for riid
557  *
558  * RETURNS
559  *    Success: S_OK
560  *    Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
561  *             E_UNEXPECTED
562  */
563 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
564 {
565     unsigned int i;
566     IClassFactoryImpl *factory;
567
568     TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
569
570     if ( !IsEqualGUID( &IID_IClassFactory, riid )
571          && ! IsEqualGUID( &IID_IUnknown, riid) )
572         return E_NOINTERFACE;
573
574     for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
575     {
576         if (IsEqualGUID(object_creation[i].clsid, rclsid))
577             break;
578     }
579
580     if (i == sizeof(object_creation)/sizeof(object_creation[0]))
581     {
582         FIXME("%s: no class found.\n", debugstr_guid(rclsid));
583         return CLASS_E_CLASSNOTAVAILABLE;
584     }
585
586     factory = HeapAlloc(GetProcessHeap(), 0, sizeof(*factory));
587     if (factory == NULL) return E_OUTOFMEMORY;
588
589     ICOM_INIT_INTERFACE(factory, IClassFactory, DDCF_Vtbl);
590     factory->ref = 1;
591
592     factory->pfnCreateInstance = object_creation[i].pfnCreateInstance;
593
594     *ppv = ICOM_INTERFACE(factory, IClassFactory);
595     return S_OK;
596 }
597
598
599 /*******************************************************************************
600  * DllCanUnloadNow [DDRAW.@]  Determines whether the DLL is in use.
601  *
602  * RETURNS
603  *    Success: S_OK
604  *    Failure: S_FALSE
605  */
606 HRESULT WINAPI DllCanUnloadNow(void)
607 {
608     FIXME("(void): stub\n");
609     return S_FALSE;
610 }
611
612 /******************************************************************************
613  * Initialisation
614  */
615
616 /* Choose which driver is considered the primary display driver. It will
617  * be created when we get a NULL guid for the DirectDrawCreate(Ex). */
618 static int DDRAW_ChooseDefaultDriver(void)
619 {
620     int i;
621     int best = 0;
622     int best_score = 0;
623
624     assert(DDRAW_num_drivers > 0);
625
626     /* This algorithm is really stupid. */
627     for (i=0; i < DDRAW_num_drivers; i++)
628     {
629         if (DDRAW_drivers[i]->preference > best_score)
630         {
631             best_score = DDRAW_drivers[i]->preference;
632             best = i;
633         }
634     }
635
636     assert(best_score > 0);
637
638     return best;
639 }
640
641 /***********************************************************************
642  *              DllMain (DDRAW.0)
643  */
644 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
645 {
646     /* If we were sufficiently cool, DDraw drivers would just be COM
647      * objects, registered with a particular component category. */
648
649     DDRAW_HAL_Init(hInstDLL, fdwReason, lpv);
650     DDRAW_User_Init(hInstDLL, fdwReason, lpv);
651
652     if (fdwReason == DLL_PROCESS_ATTACH)
653     {
654         HMODULE mod;
655
656         DisableThreadLibraryCalls(hInstDLL);
657
658         mod = GetModuleHandleA( "winex11.drv" );
659         if (mod)
660         {
661             wine_tsx11_lock_ptr   = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
662             wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
663         }
664 #ifdef HAVE_OPENGL
665         opengl_initialized = DDRAW_bind_to_opengl();
666 #endif /* HAVE_OPENGL */
667         s3tc_initialized = DDRAW_bind_to_s3tc();
668     }
669
670     if (DDRAW_num_drivers > 0)
671         DDRAW_default_driver = DDRAW_ChooseDefaultDriver();
672
673     return TRUE;
674 }
675
676 /* Register a direct draw driver. This should be called from your init
677  * function. (That's why there is no locking: your init func is called from
678  * our DllInit, which is serialised.) */
679 void DDRAW_register_driver(const ddraw_driver *driver)
680 {
681     int i;
682
683     for (i = 0; i < DDRAW_num_drivers; i++)
684     {
685         if (DDRAW_drivers[i] == driver)
686         {
687             ERR("Driver reregistering %p\n", driver);
688             return;
689         }
690     }
691
692     if (DDRAW_num_drivers == sizeof(DDRAW_drivers)/sizeof(DDRAW_drivers[0]))
693     {
694         ERR("too many DDRAW drivers\n");
695         return;
696     }
697
698     DDRAW_drivers[DDRAW_num_drivers++] = driver;
699 }
700
701 /* This totally doesn't belong here. */
702 LONG DDRAW_width_bpp_to_pitch(DWORD width, DWORD bpp)
703 {
704     LONG pitch;
705
706     assert(bpp != 0); /* keeps happening... */
707
708     if (bpp == 15) bpp = 16;
709     pitch = width * (bpp / 8);
710     return pitch + (8 - (pitch % 8)) % 8;
711 }