| /* DirectDraw Base Functions |
| * |
| * Copyright 1997-1999 Marcus Meissner |
| * Copyright 1998 Lionel Ulmer (most of Direct3D stuff) |
| * Copyright 2000-2001 TransGaming Technologies Inc. |
| * |
| * This file contains the (internal) driver registration functions, |
| * driver enumeration APIs and DirectDraw creation functions. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| #define GLPRIVATE_NO_REDEFINE |
| |
| #include "config.h" |
| |
| #include <assert.h> |
| #include <stdarg.h> |
| #include <string.h> |
| #include <stdlib.h> |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winnls.h" |
| #include "winerror.h" |
| #include "wingdi.h" |
| |
| #include "ddraw.h" |
| #include "d3d.h" |
| |
| /* This for all the enumeration and creation of D3D-related objects */ |
| #include "ddraw_private.h" |
| #include "wine/debug.h" |
| #include "wine/library.h" |
| #include "wine/port.h" |
| |
| #include "gl_private.h" |
| |
| #undef GLPRIVATE_NO_REDEFINE |
| |
| #define MAX_DDRAW_DRIVERS 3 |
| static const ddraw_driver* DDRAW_drivers[MAX_DDRAW_DRIVERS]; |
| static int DDRAW_num_drivers; /* = 0 */ |
| static int DDRAW_default_driver; |
| |
| void (*wine_tsx11_lock_ptr)(void) = NULL; |
| void (*wine_tsx11_unlock_ptr)(void) = NULL; |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(ddraw); |
| |
| /**********************************************************************/ |
| |
| typedef struct { |
| LPVOID lpCallback; |
| LPVOID lpContext; |
| } DirectDrawEnumerateProcData; |
| |
| BOOL opengl_initialized = 0; |
| |
| #ifdef HAVE_OPENGL |
| |
| #include "mesa_private.h" |
| |
| static void *gl_handle = NULL; |
| |
| #define GL_API_FUNCTION(f) typeof(f) * p##f; |
| #include "gl_api.h" |
| #undef GL_API_FUNCTION |
| |
| #ifndef SONAME_LIBGL |
| #define SONAME_LIBGL "libGL.so" |
| #endif |
| |
| static BOOL DDRAW_bind_to_opengl( void ) |
| { |
| char *glname = SONAME_LIBGL; |
| BOOL ret_value; |
| |
| gl_handle = wine_dlopen(glname, RTLD_NOW, NULL, 0); |
| if (!gl_handle) { |
| WARN("Wine cannot find the OpenGL graphics library (%s).\n",glname); |
| return FALSE; |
| } |
| |
| #define GL_API_FUNCTION(f) \ |
| if((p##f = wine_dlsym(gl_handle, #f, NULL, 0)) == NULL) \ |
| { \ |
| WARN("Can't find symbol %s\n", #f); \ |
| goto sym_not_found; \ |
| } |
| #include "gl_api.h" |
| #undef GL_API_FUNCTION |
| |
| /* And now calls the function to initialize the various fields for the rendering devices */ |
| ret_value = d3ddevice_init_at_startup(gl_handle); |
| |
| wine_dlclose(gl_handle, NULL, 0); |
| gl_handle = NULL; |
| return ret_value; |
| |
| sym_not_found: |
| WARN("Wine cannot find certain functions that it needs inside the OpenGL\n" |
| "graphics library. To enable Wine to use OpenGL please upgrade\n" |
| "your OpenGL libraries\n"); |
| wine_dlclose(gl_handle, NULL, 0); |
| gl_handle = NULL; |
| return FALSE; |
| } |
| |
| #endif /* HAVE_OPENGL */ |
| |
| /*********************************************************************** |
| * DirectDrawEnumerateExA (DDRAW.@) |
| */ |
| HRESULT WINAPI DirectDrawEnumerateExA( |
| LPDDENUMCALLBACKEXA lpCallback, LPVOID lpContext, DWORD dwFlags) |
| { |
| int i; |
| TRACE("(%p,%p, %08lx)\n", lpCallback, lpContext, dwFlags); |
| |
| if (TRACE_ON(ddraw)) { |
| TRACE(" Flags : "); |
| if (dwFlags & DDENUM_ATTACHEDSECONDARYDEVICES) |
| TRACE("DDENUM_ATTACHEDSECONDARYDEVICES "); |
| if (dwFlags & DDENUM_DETACHEDSECONDARYDEVICES) |
| TRACE("DDENUM_DETACHEDSECONDARYDEVICES "); |
| if (dwFlags & DDENUM_NONDISPLAYDEVICES) |
| TRACE("DDENUM_NONDISPLAYDEVICES "); |
| TRACE("\n"); |
| } |
| |
| for (i=0; i<DDRAW_num_drivers; i++) |
| { |
| TRACE("Enumerating %s/%s interface\n", |
| DDRAW_drivers[i]->info->szDriver, |
| DDRAW_drivers[i]->info->szDescription); |
| |
| /* We have to pass NULL from the primary display device. |
| * RoadRage chapter 6's enumeration routine expects it. */ |
| if (!lpCallback((DDRAW_default_driver == i) ? NULL |
| :(LPGUID)&DDRAW_drivers[i]->info->guidDeviceIdentifier, |
| (LPSTR)DDRAW_drivers[i]->info->szDescription, |
| (LPSTR)DDRAW_drivers[i]->info->szDriver, |
| lpContext, 0)) |
| return DD_OK; |
| } |
| |
| /* Unsupported flags */ |
| if (dwFlags & DDENUM_NONDISPLAYDEVICES) { |
| FIXME("no non-display devices supported.\n"); |
| } |
| if (dwFlags & DDENUM_DETACHEDSECONDARYDEVICES) { |
| FIXME("no detached secondary devices supported.\n"); |
| } |
| |
| return DD_OK; |
| } |
| |
| /*********************************************************************** |
| * DirectDrawEnumerateExW (DDRAW.@) |
| */ |
| |
| static BOOL CALLBACK DirectDrawEnumerateExProcW( |
| GUID *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, |
| LPVOID lpContext, HMONITOR hm) |
| { |
| INT len; |
| BOOL bResult; |
| LPWSTR lpDriverDescriptionW, lpDriverNameW; |
| DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext; |
| |
| len = MultiByteToWideChar( CP_ACP, 0, lpDriverDescription, -1, NULL, 0 ); |
| lpDriverDescriptionW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); |
| MultiByteToWideChar( CP_ACP, 0, lpDriverDescription, -1, lpDriverDescriptionW, len ); |
| |
| len = MultiByteToWideChar( CP_ACP, 0, lpDriverName, -1, NULL, 0 ); |
| lpDriverNameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); |
| MultiByteToWideChar( CP_ACP, 0, lpDriverName, -1, lpDriverNameW, len ); |
| |
| bResult = (*(LPDDENUMCALLBACKEXW *) pEPD->lpCallback)(lpGUID, lpDriverDescriptionW, |
| lpDriverNameW, pEPD->lpContext, hm); |
| |
| HeapFree(GetProcessHeap(), 0, lpDriverDescriptionW); |
| HeapFree(GetProcessHeap(), 0, lpDriverNameW); |
| return bResult; |
| } |
| |
| HRESULT WINAPI DirectDrawEnumerateExW( |
| LPDDENUMCALLBACKEXW lpCallback, LPVOID lpContext, DWORD dwFlags) |
| { |
| DirectDrawEnumerateProcData epd; |
| epd.lpCallback = (LPVOID) lpCallback; |
| epd.lpContext = lpContext; |
| |
| return DirectDrawEnumerateExA(DirectDrawEnumerateExProcW, (LPVOID) &epd, 0); |
| } |
| |
| /*********************************************************************** |
| * DirectDrawEnumerateA (DDRAW.@) |
| */ |
| |
| static BOOL CALLBACK DirectDrawEnumerateProcA( |
| GUID *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, |
| LPVOID lpContext, HMONITOR hm) |
| { |
| DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext; |
| |
| return ((LPDDENUMCALLBACKA) pEPD->lpCallback)( |
| lpGUID, lpDriverDescription, lpDriverName, pEPD->lpContext); |
| } |
| |
| HRESULT WINAPI DirectDrawEnumerateA( |
| LPDDENUMCALLBACKA lpCallback, LPVOID lpContext) |
| { |
| DirectDrawEnumerateProcData epd; |
| epd.lpCallback = (LPVOID) lpCallback; |
| epd.lpContext = lpContext; |
| |
| return DirectDrawEnumerateExA(DirectDrawEnumerateProcA, (LPVOID) &epd, 0); |
| } |
| |
| /*********************************************************************** |
| * DirectDrawEnumerateW (DDRAW.@) |
| */ |
| |
| static BOOL WINAPI DirectDrawEnumerateProcW( |
| GUID *lpGUID, LPWSTR lpDriverDescription, LPWSTR lpDriverName, |
| LPVOID lpContext, HMONITOR hm) |
| { |
| DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext; |
| |
| return ((LPDDENUMCALLBACKW) pEPD->lpCallback)( |
| lpGUID, lpDriverDescription, lpDriverName, pEPD->lpContext); |
| } |
| |
| HRESULT WINAPI DirectDrawEnumerateW( |
| LPDDENUMCALLBACKW lpCallback, LPVOID lpContext) |
| { |
| DirectDrawEnumerateProcData epd; |
| epd.lpCallback = (LPVOID) lpCallback; |
| epd.lpContext = lpContext; |
| |
| return DirectDrawEnumerateExW(DirectDrawEnumerateProcW, (LPVOID) &epd, 0); |
| } |
| |
| /*********************************************************************** |
| * DirectDrawCreate (DDRAW.@) |
| */ |
| |
| const ddraw_driver* DDRAW_FindDriver(const GUID* pGUID) |
| { |
| static const GUID zeroGUID; /* gets zero-inited */ |
| |
| TRACE("(%s)\n", pGUID ? debugstr_guid(pGUID) : "(null)"); |
| |
| if (DDRAW_num_drivers == 0) return NULL; |
| |
| if (pGUID == (LPGUID)DDCREATE_EMULATIONONLY |
| || pGUID == (LPGUID)DDCREATE_HARDWAREONLY) |
| pGUID = NULL; |
| |
| if (pGUID == NULL || memcmp(pGUID, &zeroGUID, sizeof(GUID)) == 0) |
| { |
| /* Use the default driver. */ |
| return DDRAW_drivers[DDRAW_default_driver]; |
| } |
| else |
| { |
| /* Look for a matching GUID. */ |
| |
| int i; |
| for (i=0; i < DDRAW_num_drivers; i++) |
| { |
| if (IsEqualGUID(pGUID, |
| &DDRAW_drivers[i]->info->guidDeviceIdentifier)) |
| break; |
| } |
| |
| if (i < DDRAW_num_drivers) |
| { |
| return DDRAW_drivers[i]; |
| } |
| else |
| { |
| ERR("(%s): did not recognize requested GUID.\n",debugstr_guid(pGUID)); |
| return NULL; |
| } |
| } |
| } |
| |
| static HRESULT DDRAW_Create( |
| LPGUID lpGUID, LPVOID *lplpDD, LPUNKNOWN pUnkOuter, REFIID iid, BOOL ex |
| ) { |
| const ddraw_driver* driver; |
| LPDIRECTDRAW7 pDD; |
| HRESULT hr; |
| |
| TRACE("(%s,%p,%p,%d)\n", debugstr_guid(lpGUID), lplpDD, pUnkOuter, ex); |
| |
| if (DDRAW_num_drivers == 0) |
| { |
| WARN("no DirectDraw drivers registered\n"); |
| return DDERR_INVALIDDIRECTDRAWGUID; |
| } |
| |
| if (lpGUID == (LPGUID)DDCREATE_EMULATIONONLY |
| || lpGUID == (LPGUID)DDCREATE_HARDWAREONLY) |
| lpGUID = NULL; |
| |
| if (pUnkOuter != NULL) |
| return DDERR_INVALIDPARAMS; /* CLASS_E_NOAGGREGATION? */ |
| |
| driver = DDRAW_FindDriver(lpGUID); |
| if (driver == NULL) return DDERR_INVALIDDIRECTDRAWGUID; |
| |
| hr = driver->create(lpGUID, &pDD, pUnkOuter, ex); |
| if (FAILED(hr)) return hr; |
| |
| hr = IDirectDraw7_QueryInterface(pDD, iid, lplpDD); |
| IDirectDraw7_Release(pDD); |
| return hr; |
| } |
| |
| /*********************************************************************** |
| * DirectDrawCreate (DDRAW.@) |
| * |
| * Only creates legacy IDirectDraw interfaces. |
| * Cannot create IDirectDraw7 interfaces. |
| * In theory. |
| */ |
| HRESULT WINAPI DirectDrawCreate( |
| LPGUID lpGUID, LPDIRECTDRAW* lplpDD, LPUNKNOWN pUnkOuter |
| ) { |
| TRACE("(%s,%p,%p)\n", debugstr_guid(lpGUID), lplpDD, pUnkOuter); |
| return DDRAW_Create(lpGUID, (LPVOID*) lplpDD, pUnkOuter, &IID_IDirectDraw, FALSE); |
| } |
| |
| /*********************************************************************** |
| * DirectDrawCreateEx (DDRAW.@) |
| * |
| * Only creates new IDirectDraw7 interfaces. |
| * Supposed to fail if legacy interfaces are requested. |
| * In theory. |
| */ |
| HRESULT WINAPI DirectDrawCreateEx( |
| LPGUID lpGUID, LPVOID* lplpDD, REFIID iid, LPUNKNOWN pUnkOuter |
| ) { |
| TRACE("(%s,%p,%s,%p)\n", debugstr_guid(lpGUID), lplpDD, debugstr_guid(iid), pUnkOuter); |
| |
| if (!IsEqualGUID(iid, &IID_IDirectDraw7)) |
| return DDERR_INVALIDPARAMS; |
| |
| return DDRAW_Create(lpGUID, lplpDD, pUnkOuter, iid, TRUE); |
| } |
| |
| extern HRESULT Uninit_DirectDraw_Create(const GUID*, LPDIRECTDRAW7*, |
| LPUNKNOWN, BOOL); |
| |
| /* This is for the class factory. */ |
| static HRESULT DDRAW_CreateDirectDraw(IUnknown* pUnkOuter, REFIID iid, |
| LPVOID* ppObj) |
| { |
| LPDIRECTDRAW7 pDD; |
| HRESULT hr; |
| BOOL ex; |
| |
| TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppObj); |
| |
| /* This is a mighty hack :-) */ |
| if (IsEqualGUID(iid, &IID_IDirectDraw7)) |
| ex = TRUE; |
| else |
| ex = FALSE; |
| |
| hr = Uninit_DirectDraw_Create(NULL, &pDD, pUnkOuter, ex); |
| if (FAILED(hr)) return hr; |
| |
| hr = IDirectDraw7_QueryInterface(pDD, iid, ppObj); |
| IDirectDraw_Release(pDD); |
| return hr; |
| } |
| |
| /****************************************************************************** |
| * DirectDraw ClassFactory |
| */ |
| typedef struct { |
| ICOM_VFIELD_MULTI(IClassFactory); |
| |
| DWORD ref; |
| HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, REFIID iid, |
| LPVOID *ppObj); |
| } IClassFactoryImpl; |
| |
| struct object_creation_info |
| { |
| const CLSID *clsid; |
| HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, REFIID riid, |
| LPVOID *ppObj); |
| }; |
| |
| /* There should be more, but these are the only ones listed in the header |
| * file. */ |
| extern HRESULT DDRAW_CreateDirectDrawClipper(IUnknown *pUnkOuter, REFIID riid, |
| LPVOID *ppObj); |
| |
| static const struct object_creation_info object_creation[] = |
| { |
| { &CLSID_DirectDraw, DDRAW_CreateDirectDraw }, |
| { &CLSID_DirectDraw7, DDRAW_CreateDirectDraw }, |
| { &CLSID_DirectDrawClipper, DDRAW_CreateDirectDrawClipper } |
| }; |
| |
| static HRESULT WINAPI |
| DDCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) |
| { |
| ICOM_THIS(IClassFactoryImpl,iface); |
| |
| TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppobj); |
| |
| if (IsEqualGUID(riid, &IID_IUnknown) |
| || IsEqualGUID(riid, &IID_IClassFactory)) |
| { |
| IClassFactory_AddRef(iface); |
| *ppobj = This; |
| return S_OK; |
| } |
| |
| WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj); |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI DDCF_AddRef(LPCLASSFACTORY iface) { |
| ICOM_THIS(IClassFactoryImpl,iface); |
| |
| TRACE("(%p)->() incrementing from %ld.\n", This, This->ref); |
| |
| return ++(This->ref); |
| } |
| |
| static ULONG WINAPI DDCF_Release(LPCLASSFACTORY iface) { |
| ICOM_THIS(IClassFactoryImpl,iface); |
| |
| TRACE("(%p)->() decrementing from %ld.\n", This, This->ref); |
| |
| if (--This->ref == 0) |
| HeapFree(GetProcessHeap(), 0, This); |
| |
| return This->ref; |
| } |
| |
| |
| static HRESULT WINAPI DDCF_CreateInstance( |
| LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj |
| ) { |
| ICOM_THIS(IClassFactoryImpl,iface); |
| |
| TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj); |
| |
| return This->pfnCreateInstance(pOuter, riid, ppobj); |
| } |
| |
| static HRESULT WINAPI DDCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { |
| ICOM_THIS(IClassFactoryImpl,iface); |
| FIXME("(%p)->(%d),stub!\n",This,dolock); |
| return S_OK; |
| } |
| |
| static ICOM_VTABLE(IClassFactory) DDCF_Vtbl = |
| { |
| ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE |
| DDCF_QueryInterface, |
| DDCF_AddRef, |
| DDCF_Release, |
| DDCF_CreateInstance, |
| DDCF_LockServer |
| }; |
| |
| /******************************************************************************* |
| * DllGetClassObject [DDRAW.@] |
| * Retrieves class object from a DLL object |
| * |
| * NOTES |
| * Docs say returns STDAPI |
| * |
| * PARAMS |
| * rclsid [I] CLSID for the class object |
| * riid [I] Reference to identifier of interface for class object |
| * ppv [O] Address of variable to receive interface pointer for riid |
| * |
| * RETURNS |
| * Success: S_OK |
| * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG, |
| * E_UNEXPECTED |
| */ |
| DWORD WINAPI DDRAW_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv) |
| { |
| unsigned int i; |
| IClassFactoryImpl *factory; |
| |
| TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); |
| |
| if ( !IsEqualGUID( &IID_IClassFactory, riid ) |
| && ! IsEqualGUID( &IID_IUnknown, riid) ) |
| return E_NOINTERFACE; |
| |
| for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++) |
| { |
| if (IsEqualGUID(object_creation[i].clsid, rclsid)) |
| break; |
| } |
| |
| if (i == sizeof(object_creation)/sizeof(object_creation[0])) |
| { |
| FIXME("%s: no class found.\n", debugstr_guid(rclsid)); |
| return CLASS_E_CLASSNOTAVAILABLE; |
| } |
| |
| factory = HeapAlloc(GetProcessHeap(), 0, sizeof(*factory)); |
| if (factory == NULL) return E_OUTOFMEMORY; |
| |
| ICOM_INIT_INTERFACE(factory, IClassFactory, DDCF_Vtbl); |
| factory->ref = 1; |
| |
| factory->pfnCreateInstance = object_creation[i].pfnCreateInstance; |
| |
| *ppv = ICOM_INTERFACE(factory, IClassFactory); |
| return S_OK; |
| } |
| |
| |
| /******************************************************************************* |
| * DllCanUnloadNow [DDRAW.@] Determines whether the DLL is in use. |
| * |
| * RETURNS |
| * Success: S_OK |
| * Failure: S_FALSE |
| */ |
| DWORD WINAPI DDRAW_DllCanUnloadNow(void) { |
| FIXME("(void): stub\n"); |
| return S_FALSE; |
| } |
| |
| /****************************************************************************** |
| * Initialisation |
| */ |
| |
| /* Choose which driver is considered the primary display driver. It will |
| * be created when we get a NULL guid for the DirectDrawCreate(Ex). */ |
| static int DDRAW_ChooseDefaultDriver(void) |
| { |
| int i; |
| int best = 0; |
| int best_score = 0; |
| |
| assert(DDRAW_num_drivers > 0); |
| |
| /* This algorithm is really stupid. */ |
| for (i=0; i < DDRAW_num_drivers; i++) |
| { |
| if (DDRAW_drivers[i]->preference > best_score) |
| { |
| best_score = DDRAW_drivers[i]->preference; |
| best = i; |
| } |
| } |
| |
| assert(best_score > 0); |
| |
| return best; |
| } |
| |
| BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) |
| { |
| /* If we were sufficiently cool, DDraw drivers would just be COM |
| * objects, registered with a particular component category. */ |
| |
| DDRAW_HAL_Init(hInstDLL, fdwReason, lpv); |
| DDRAW_User_Init(hInstDLL, fdwReason, lpv); |
| |
| if (fdwReason == DLL_PROCESS_ATTACH) |
| { |
| HMODULE mod; |
| |
| DisableThreadLibraryCalls(hInstDLL); |
| |
| mod = GetModuleHandleA( "x11drv.dll" ); |
| if (mod) |
| { |
| wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" ); |
| wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" ); |
| } |
| #ifdef HAVE_OPENGL |
| opengl_initialized = DDRAW_bind_to_opengl(); |
| #endif /* HAVE_OPENGL */ |
| } |
| |
| if (DDRAW_num_drivers > 0) |
| DDRAW_default_driver = DDRAW_ChooseDefaultDriver(); |
| |
| return TRUE; |
| } |
| |
| /* Register a direct draw driver. This should be called from your init |
| * function. (That's why there is no locking: your init func is called from |
| * our DllInit, which is serialised.) */ |
| void DDRAW_register_driver(const ddraw_driver *driver) |
| { |
| int i; |
| |
| for (i = 0; i < DDRAW_num_drivers; i++) |
| { |
| if (DDRAW_drivers[i] == driver) |
| { |
| ERR("Driver reregistering %p\n", driver); |
| return; |
| } |
| } |
| |
| if (DDRAW_num_drivers == sizeof(DDRAW_drivers)/sizeof(DDRAW_drivers[0])) |
| { |
| ERR("too many DDRAW drivers\n"); |
| return; |
| } |
| |
| DDRAW_drivers[DDRAW_num_drivers++] = driver; |
| } |
| |
| /* This totally doesn't belong here. */ |
| LONG DDRAW_width_bpp_to_pitch(DWORD width, DWORD bpp) |
| { |
| LONG pitch; |
| |
| assert(bpp != 0); /* keeps happening... */ |
| |
| if (bpp == 15) bpp = 16; |
| pitch = width * (bpp / 8); |
| return pitch + (8 - (pitch % 8)) % 8; |
| } |