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