wine/dlls/ddraw/main.c
Alexandre Julliard c3116c5e61 Renamed ttydrv and x11drv to winetty.drv and winex11.drv respectively
to follow the namespace conventions and make it clear that they are
drivers and not dlls.
Moved the graphics driver configuration to HKLM\Software\Wine\Drivers.
2005-05-06 19:38:50 +00:00

710 lines
19 KiB
C

/* 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 "wine/port.h"
#include <assert.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#define COBJMACROS
#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 "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 )
{
const char *glname = SONAME_LIBGL;
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 */
return d3ddevice_init_at_startup(gl_handle);
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 */
BOOL s3tc_initialized = 0;
static void *s3tc_handle = NULL;
FUNC_FETCH_2D_TEXEL_RGBA_DXT1 fetch_2d_texel_rgba_dxt1;
FUNC_FETCH_2D_TEXEL_RGBA_DXT3 fetch_2d_texel_rgba_dxt3;
FUNC_FETCH_2D_TEXEL_RGBA_DXT5 fetch_2d_texel_rgba_dxt5;
#ifndef SONAME_LIBTXC_DXTN
#define SONAME_LIBTXC_DXTN "libtxc_dxtn.so"
#endif
static BOOL DDRAW_bind_to_s3tc( void )
{
const char * const s3tcname = SONAME_LIBTXC_DXTN;
s3tc_handle = wine_dlopen(s3tcname, RTLD_NOW, NULL, 0);
if (!s3tc_handle) {
TRACE("No S3TC software decompression library seems to be present (%s).\n",s3tcname);
return FALSE;
}
TRACE("Found S3TC software decompression library (%s).\n",s3tcname);
#define API_FUNCTION(f) \
if((f = wine_dlsym(s3tc_handle, #f, NULL, 0)) == NULL) \
{ \
WARN("Can't find symbol %s\n", #f); \
goto sym_not_found; \
}
API_FUNCTION(fetch_2d_texel_rgba_dxt1);
API_FUNCTION(fetch_2d_texel_rgba_dxt3);
API_FUNCTION(fetch_2d_texel_rgba_dxt5);
#undef API_FUNCTION
return TRUE;
sym_not_found:
WARN("Wine cannot find functions that are necessary for S3TC software decompression\n");
wine_dlclose(s3tc_handle, NULL, 0);
s3tc_handle = NULL;
return FALSE;
}
/*******************************************************************************
* DirectDrawEnumerateExA (DDRAW.@)
*
* Enumerates all DirectDraw devices installed on the system.
*
* PARAMS
* lpCallback [I] DDEnumCallbackEx function to be called with a description of
* each enumerated HAL.
* lpContext [I] application-defined value to be passed to the callback.
* dwFlags [I] Specifies the enumeration scope. see msdn.
*
* RETURNS
* Success: DD_OK.
* Failure: DDERR_INVALIDPARAMS
*/
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)
{
IClassFactoryImpl *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)
{
IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
ULONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p)->() incrementing from %ld.\n", This, ref - 1);
return ref;
}
static ULONG WINAPI DDCF_Release(LPCLASSFACTORY iface)
{
IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
ULONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p)->() decrementing from %ld.\n", This, ref+1);
if (ref == 0)
HeapFree(GetProcessHeap(), 0, This);
return ref;
}
static HRESULT WINAPI DDCF_CreateInstance(
LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
)
{
IClassFactoryImpl *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)
{
IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
FIXME("(%p)->(%d),stub!\n",This,dolock);
return S_OK;
}
static IClassFactoryVtbl DDCF_Vtbl =
{
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;
}
/***********************************************************************
* DllMain (DDRAW.0)
*/
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( "winex11.drv" );
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 */
s3tc_initialized = DDRAW_bind_to_s3tc();
}
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;
}