/* DirectDraw Base Functions * * Copyright 1997-1999 Marcus Meissner * Copyright 1998 Lionel Ulmer (most of Direct3D stuff) * Copyright 2000 TransGaming Technologies Inc. * * This file contains the (internal) driver registration functions, * driver enumeration APIs and DirectDraw creation functions. */ #include "config.h" #include #include #include #include "winerror.h" #include "debugtools.h" #include "heap.h" #include "ddraw.h" #include "d3d.h" /* This for all the enumeration and creation of D3D-related objects */ #include "ddraw_private.h" #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; DEFAULT_DEBUG_CHANNEL(ddraw); /**********************************************************************/ typedef struct { LPVOID lpCallback; LPVOID lpContext; } DirectDrawEnumerateProcData; /*********************************************************************** * 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)) { DPRINTF(" Flags : "); if (dwFlags & DDENUM_ATTACHEDSECONDARYDEVICES) DPRINTF("DDENUM_ATTACHEDSECONDARYDEVICES "); if (dwFlags & DDENUM_DETACHEDSECONDARYDEVICES) DPRINTF("DDENUM_DETACHEDSECONDARYDEVICES "); if (dwFlags & DDENUM_NONDISPLAYDEVICES) DPRINTF("DDENUM_NONDISPLAYDEVICES "); DPRINTF("\n"); } for (i=0; iinfo->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) { DirectDrawEnumerateProcData *pEPD = (DirectDrawEnumerateProcData*)lpContext; LPWSTR lpDriverDescriptionW = HEAP_strdupAtoW(GetProcessHeap(), 0, lpDriverDescription); LPWSTR lpDriverNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, lpDriverName); BOOL 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 */ 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; 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; TRACE("(%s,%p,%p)\n",debugstr_guid(lpGUID),lplpDD,pUnkOuter); 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 * * Only creates legacy IDirectDraw interfaces. * Cannot create IDirectDraw7 interfaces. * In theory. */ HRESULT WINAPI DirectDrawCreate( LPGUID lpGUID, LPDIRECTDRAW* lplpDD, LPUNKNOWN pUnkOuter ) { return DDRAW_Create(lpGUID,(LPVOID*)lplpDD,pUnkOuter,&IID_IDirectDraw,FALSE); } /*********************************************************************** * DirectDrawCreateEx * * 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 ) { 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; hr = Uninit_DirectDraw_Create(NULL, &pDD, pUnkOuter, TRUE); /* 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); 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); return ++(This->ref); } static ULONG WINAPI DDCF_Release(LPCLASSFACTORY iface) { ICOM_THIS(IClassFactoryImpl,iface); ULONG ref = --This->ref; if (ref == 0) HeapFree(GetProcessHeap(), 0, This); return 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.13] * 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) { int i; IClassFactoryImpl *factory; TRACE("(%p,%p,%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.12] 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 DDRAW_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_User_Init(hInstDLL, fdwReason, lpv); #ifdef HAVE_LIBXXF86VM DDRAW_XVidMode_Init(hInstDLL, fdwReason, lpv); #endif #ifdef HAVE_LIBXXF86DGA2 DDRAW_XF86DGA2_Init(hInstDLL, fdwReason, lpv); #endif 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; }