Beispiel #1
0
/****************************************************************************
REMARKS:
Test the Direct3D8 device for "lameness" with respect to GLDirect.
This is done on per-chipset basis, as in GLD CAD driver (DGLCONTEXT.C).
If bTestForWHQL is set then the device is tested to see if it is
certified, and bIsWHQL is set to indicate TRUE or FALSE. Otherwise bIsWHQL
is not set. [WHQL = Windows Hardware Quality Labs]

NOTE: There is a one- or two-second time penalty incurred in determining
      the WHQL certification date.
****************************************************************************/
BOOL IsThisD3D8Lame(
	IDirect3D8 *pD3D,
	DWORD dwAdapter,
	BOOL bTestForWHQL,
	BOOL *bIsWHQL)
{
	DWORD					dwFlags = bTestForWHQL ? 0 : D3DENUM_NO_WHQL_LEVEL;
	D3DADAPTER_IDENTIFIER8	d3dai;
	HRESULT					hr;

	hr = IDirect3D8_GetAdapterIdentifier(pD3D, dwAdapter, dwFlags, &d3dai);
	if (FAILED(hr))
		return TRUE; // Definitely lame if adapter details can't be obtained!

	if (bTestForWHQL) {
		*bIsWHQL = d3dai.WHQLLevel ? TRUE : FALSE;
	}

	// Vendor 1: ATI
	if (d3dai.VendorId == VENDORID_ATI) {
		// Test A: ATI Rage PRO
		if (IsDevice(devATIRagePro, d3dai.DeviceId, sizeof(devATIRagePro)))
			return TRUE;	// bad mipmapping
		// Test B: ATI Rage II+
		if (IsDevice(devATIRageIIplus, d3dai.DeviceId, sizeof(devATIRageIIplus)))
			return TRUE; 	// bad HW alpha testing
	}

	return FALSE;
}
Beispiel #2
0
static HRESULT d3d_get_adapter_identifier(d3d *d3dptr, UINT adapter, DWORD flags, d3d_adapter_identifier *identifier)
{
	IDirect3D8 *d3d8 = (IDirect3D8 *)d3dptr->d3dobj;
	D3DADAPTER_IDENTIFIER8 id;
	HRESULT result = IDirect3D8_GetAdapterIdentifier(d3d8, adapter, flags, &id);
	memcpy(identifier->Driver, id.Driver, sizeof(identifier->Driver));
	memcpy(identifier->Description, id.Description, sizeof(identifier->Description));
	identifier->DriverVersion = id.DriverVersion;
	identifier->VendorId = id.VendorId;
	identifier->DeviceId = id.DeviceId;
	identifier->SubSysId = id.SubSysId;
	identifier->Revision = id.Revision;
	identifier->DeviceIdentifier = id.DeviceIdentifier;
	identifier->WHQLLevel = id.WHQLLevel;
	return result;
}
Beispiel #3
0
BOOL gldCreateDrawable_DX(
	DGL_ctx *ctx,
//	BOOL bDefaultDriver,
	BOOL bDirectDrawPersistant,
	BOOL bPersistantBuffers)
{
	//
	// bDirectDrawPersistant:	applies to IDirect3D8
	// bPersistantBuffers:		applies to IDirect3DDevice8
	//

	HRESULT					hResult;
	GLD_driver_dx8			*lpCtx = NULL;
	D3DDEVTYPE				d3dDevType;
	D3DPRESENT_PARAMETERS	d3dpp;
	D3DDISPLAYMODE			d3ddm;
	DWORD					dwBehaviourFlags;
	D3DADAPTER_IDENTIFIER8	d3dIdent;

	// Error if context is NULL.
	if (ctx == NULL)
		return FALSE;

	if (ctx->glPriv) {
		lpCtx = ctx->glPriv;
		// Release any existing interfaces
		SAFE_RELEASE(lpCtx->pDev);
		SAFE_RELEASE(lpCtx->pD3D);
	} else {
		lpCtx = (GLD_driver_dx8*)malloc(sizeof(GLD_driver_dx8));
		ZeroMemory(lpCtx, sizeof(lpCtx));
	}

	d3dDevType = (glb.dwDriver == GLDS_DRIVER_HAL) ? D3DDEVTYPE_HAL : D3DDEVTYPE_REF;
	// TODO: Check this
//	if (bDefaultDriver)
//		d3dDevType = D3DDEVTYPE_REF;

	// Use persistant interface if needed
	if (bDirectDrawPersistant && dx8Globals.bDirect3D) {
		lpCtx->pD3D = dx8Globals.pD3D;
		IDirect3D8_AddRef(lpCtx->pD3D);
		goto SkipDirectDrawCreate;
	}

	// Create Direct3D8 object
	lpCtx->pD3D = dx8Globals.fnDirect3DCreate8(D3D_SDK_VERSION_DX8_SUPPORT_WIN95);
	if (lpCtx->pD3D == NULL) {
		MessageBox(NULL, "Unable to initialize Direct3D8", "GLDirect", MB_OK);
		ddlogMessage(DDLOG_CRITICAL_OR_WARN, "Unable to create Direct3D8 interface");
        nContextError = GLDERR_D3D;
		goto return_with_error;
	}

	// Cache Direct3D interface for subsequent GLRCs
	if (bDirectDrawPersistant && !dx8Globals.bDirect3D) {
		dx8Globals.pD3D = lpCtx->pD3D;
		IDirect3D8_AddRef(dx8Globals.pD3D);
		dx8Globals.bDirect3D = TRUE;
	}
SkipDirectDrawCreate:

	// Get the display mode so we can make a compatible backbuffer
	hResult = IDirect3D8_GetAdapterDisplayMode(lpCtx->pD3D, glb.dwAdapter, &d3ddm);
	if (FAILED(hResult)) {
        nContextError = GLDERR_D3D;
		goto return_with_error;
	}

	// Get device caps
	hResult = IDirect3D8_GetDeviceCaps(lpCtx->pD3D, glb.dwAdapter, d3dDevType, &lpCtx->d3dCaps8);
	if (FAILED(hResult)) {
		ddlogError(DDLOG_CRITICAL_OR_WARN, "IDirect3D8_GetDeviceCaps failed", hResult);
        nContextError = GLDERR_D3D;
		goto return_with_error;
	}

	// Check for hardware transform & lighting
	lpCtx->bHasHWTnL = lpCtx->d3dCaps8.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ? TRUE : FALSE;

	// If this flag is present then we can't default to Mesa
	// SW rendering between BeginScene() and EndScene().
	if (lpCtx->d3dCaps8.Caps2 & D3DCAPS2_NO2DDURING3DSCENE) {
		ddlogMessage(DDLOG_WARN,
			"Warning          : No 2D allowed during 3D scene.\n");
	}

	//
	//	Create the Direct3D context
	//

	// Re-use original IDirect3DDevice if persistant buffers exist.
	// Note that we test for persistant IDirect3D8 as well
	// bDirectDrawPersistant == persistant IDirect3D8 (DirectDraw8 does not exist)
	if (bDirectDrawPersistant && bPersistantBuffers && dx8Globals.pD3D && dx8Globals.pDev) {
		lpCtx->pDev = dx8Globals.pDev;
		IDirect3DDevice8_AddRef(dx8Globals.pDev);
		goto skip_direct3ddevice_create;
	}

	// Clear the presentation parameters (sets all members to zero)
	ZeroMemory(&d3dpp, sizeof(d3dpp));

	// Recommended by MS; needed for MultiSample.
	// Be careful if altering this for FullScreenBlit
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

	d3dpp.BackBufferFormat	= d3ddm.Format;
	d3dpp.BackBufferCount	= 1;
	d3dpp.MultiSampleType	= _gldGetDeviceMultiSampleType(lpCtx->pD3D, d3ddm.Format, d3dDevType, !ctx->bFullscreen);
	d3dpp.AutoDepthStencilFormat	= ctx->lpPF->dwDriverData;
	d3dpp.EnableAutoDepthStencil	= (d3dpp.AutoDepthStencilFormat == D3DFMT_UNKNOWN) ? FALSE : TRUE;

	if (ctx->bFullscreen) {
		ddlogWarnOption(FALSE); // Don't popup any messages in fullscreen 
		d3dpp.Windowed							= FALSE;
		d3dpp.BackBufferWidth					= d3ddm.Width;
		d3dpp.BackBufferHeight					= d3ddm.Height;
		d3dpp.hDeviceWindow						= ctx->hWnd;
		d3dpp.FullScreen_RefreshRateInHz		= D3DPRESENT_RATE_DEFAULT;

		// Support for vertical retrace synchronisation.
		// Set default presentation interval in case caps bits are missing
		d3dpp.FullScreen_PresentationInterval	= D3DPRESENT_INTERVAL_DEFAULT;
		if (glb.bWaitForRetrace) {
			if (lpCtx->d3dCaps8.PresentationIntervals & D3DPRESENT_INTERVAL_ONE)
				d3dpp.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE;
		} else {
			if (lpCtx->d3dCaps8.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE)
				d3dpp.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
		}
	} else {
		ddlogWarnOption(glb.bMessageBoxWarnings); // OK to popup messages
		d3dpp.Windowed							= TRUE;
		d3dpp.BackBufferWidth					= ctx->dwWidth;
		d3dpp.BackBufferHeight					= ctx->dwHeight;
		d3dpp.hDeviceWindow						= ctx->hWnd;
		d3dpp.FullScreen_RefreshRateInHz		= 0;
		// FullScreen_PresentationInterval must be default for Windowed mode
		d3dpp.FullScreen_PresentationInterval	= D3DPRESENT_INTERVAL_DEFAULT;
	}

	// Decide if we can use hardware TnL
	dwBehaviourFlags = (lpCtx->bHasHWTnL) ?
		D3DCREATE_MIXED_VERTEXPROCESSING : D3DCREATE_SOFTWARE_VERTEXPROCESSING;
	// Add flag to tell D3D to be thread-safe
	if (glb.bMultiThreaded)
		dwBehaviourFlags |= D3DCREATE_MULTITHREADED;
	// Add flag to tell D3D to be FPU-safe
	if (!glb.bFastFPU)
		dwBehaviourFlags |= D3DCREATE_FPU_PRESERVE;
	hResult = IDirect3D8_CreateDevice(lpCtx->pD3D,
								glb.dwAdapter,
								d3dDevType,
								ctx->hWnd,
								dwBehaviourFlags,
								&d3dpp,
								&lpCtx->pDev);
    if (FAILED(hResult)) {
		ddlogError(DDLOG_CRITICAL_OR_WARN, "IDirect3D8_CreateDevice failed", hResult);
        nContextError = GLDERR_D3D;
		goto return_with_error;
	}

	if (bDirectDrawPersistant && bPersistantBuffers && dx8Globals.pD3D) {
		dx8Globals.pDev = lpCtx->pDev;
		dx8Globals.bDirect3DDevice = TRUE;
	}

/*
	// See if DDraw interfaces are available (DaveM)
	hResult = IDirect3D8_QueryInterface(lpCtx->pDev,
		&IID_IDirectDraw7, (LPVOID*)&lpOpaque1);
	if (FAILED(hResult) || lpOpaque1 == NULL) {
		ddlogMessage(DDLOG_INFO, "DirectDraw QueryInterface unavailable\n");
	}

	hResult = IDirect3DDevice8_QueryInterface(lpCtx->pDev, 
		&IID_IDirectDrawSurface7, (LPVOID*)&lpOpaque2);
	if (FAILED(hResult) || lpOpaque2 == NULL) {
		ddlogMessage(DDLOG_INFO, "DirectDrawSurface QueryInterface unavialable\n");
	}
*/	
	// Dump some useful stats
	hResult = IDirect3D8_GetAdapterIdentifier(
		lpCtx->pD3D,
		glb.dwAdapter,
		D3DENUM_NO_WHQL_LEVEL, // Avoids 1 to 2 second delay
		&d3dIdent);
	if (SUCCEEDED(hResult)) {
		ddlogPrintf(DDLOG_INFO, "[Driver Description: %s]", &d3dIdent.Description);
		ddlogPrintf(DDLOG_INFO, "[Driver file: %s %d.%d.%02d.%d]",
			d3dIdent.Driver,
			HIWORD(d3dIdent.DriverVersion.HighPart),
			LOWORD(d3dIdent.DriverVersion.HighPart),
			HIWORD(d3dIdent.DriverVersion.LowPart),
			LOWORD(d3dIdent.DriverVersion.LowPart));
		ddlogPrintf(DDLOG_INFO, "[VendorId: 0x%X, DeviceId: 0x%X, SubSysId: 0x%X, Revision: 0x%X]",
			d3dIdent.VendorId, d3dIdent.DeviceId, d3dIdent.SubSysId, d3dIdent.Revision);
	}

	// Init projection matrix for D3D TnL
	D3DXMatrixIdentity(&lpCtx->matProjection);
	lpCtx->matModelView = lpCtx->matProjection;
//		gld->bUseMesaProjection = TRUE;

skip_direct3ddevice_create:

	// Create buffers to hold primitives
	lpCtx->PB2d.dwFVF		= GLD_FVF_2D_VERTEX;
	lpCtx->PB2d.dwPool		= D3DPOOL_SYSTEMMEM;
	lpCtx->PB2d.dwStride	= sizeof(GLD_2D_VERTEX);
	lpCtx->PB2d.dwUsage		= D3DUSAGE_DONOTCLIP |
								D3DUSAGE_DYNAMIC |
								D3DUSAGE_SOFTWAREPROCESSING |
								D3DUSAGE_WRITEONLY;
	hResult = _gldCreatePrimitiveBuffer(ctx->glCtx, lpCtx, &lpCtx->PB2d);
	if (FAILED(hResult))
		goto return_with_error;

	lpCtx->PB3d.dwFVF		= GLD_FVF_3D_VERTEX;
	lpCtx->PB3d.dwPool		= D3DPOOL_DEFAULT;
	lpCtx->PB3d.dwStride	= sizeof(GLD_3D_VERTEX);
	lpCtx->PB3d.dwUsage		= D3DUSAGE_DYNAMIC |
								D3DUSAGE_SOFTWAREPROCESSING |
								D3DUSAGE_WRITEONLY;
	hResult = _gldCreatePrimitiveBuffer(ctx->glCtx, lpCtx, &lpCtx->PB3d);
	if (FAILED(hResult))
		goto return_with_error;

/*	// NOTE: A FVF code of zero indicates a non-FVF vertex buffer (for vertex shaders)
	lpCtx->PBtwosidelight.dwFVF		= 0; //GLD_FVF_TWOSIDED_VERTEX;
	lpCtx->PBtwosidelight.dwPool	= D3DPOOL_DEFAULT;
	lpCtx->PBtwosidelight.dwStride	= sizeof(GLD_TWOSIDED_VERTEX);
	lpCtx->PBtwosidelight.dwUsage	= D3DUSAGE_DONOTCLIP |
								D3DUSAGE_DYNAMIC |
								D3DUSAGE_SOFTWAREPROCESSING |
								D3DUSAGE_WRITEONLY;
	hResult = _gldCreatePrimitiveBuffer(ctx->glCtx, lpCtx, &lpCtx->PBtwosidelight);
	if (FAILED(hResult))
		goto return_with_error;*/

	// Now try and create the DX8 Vertex Shaders
//	_gldCreateVertexShaders(lpCtx);

	// Zero the pipeline usage counters
	lpCtx->PipelineUsage.qwMesa.QuadPart = 
//	lpCtx->PipelineUsage.dwD3D2SVS.QuadPart =
	lpCtx->PipelineUsage.qwD3DFVF.QuadPart = 0;

	// Assign drawable to GL private
	ctx->glPriv = lpCtx;
	return TRUE;

return_with_error:
	// Clean up and bail

//	_gldDestroyVertexShaders(lpCtx);

//	_gldDestroyPrimitiveBuffer(&lpCtx->PBtwosidelight);
	_gldDestroyPrimitiveBuffer(&lpCtx->PB3d);
	_gldDestroyPrimitiveBuffer(&lpCtx->PB2d);

	SAFE_RELEASE(lpCtx->pDev);
	SAFE_RELEASE(lpCtx->pD3D);
	return FALSE;
}
Beispiel #4
0
BOOL gldCreateDrawable_DX(
	DGL_ctx *ctx,
//	BOOL bDefaultDriver,
	BOOL bDirectDrawPersistant,
	BOOL bPersistantBuffers)
{
	//
	// bDirectDrawPersistant:	applies to IDirect3D8
	// bPersistantBuffers:		applies to IDirect3DDevice8
	//

//	D3DDEVTYPE				d3dDevType;
//	D3DPRESENT_PARAMETERS	d3dpp;
//	D3DDISPLAYMODE			d3ddm;
//	DWORD					dwBehaviourFlags;
//	D3DADAPTER_IDENTIFIER8	d3dIdent;

	HRESULT				hr;
	GLD_driver_dx7		*lpCtx = NULL;
	D3DX_VIDMODEDESC	d3ddm;

	// Parameters for D3DXCreateContextEx
	// These will be different for fullscreen and windowed
	DWORD				dwDeviceIndex;
	DWORD				dwFlags;
	HWND				hwnd;
	HWND				hwndFocus;
	DWORD				numColorBits;
	DWORD				numAlphaBits;
	DWORD				numDepthBits;
	DWORD				numStencilBits;
	DWORD				numBackBuffers;
	DWORD				dwWidth;
	DWORD				dwHeight;
	DWORD				refreshRate;

	// Error if context is NULL.
	if (ctx == NULL)
		return FALSE;

	if (ctx->glPriv) {
		lpCtx = ctx->glPriv;
		// Release any existing interfaces (in reverse order)
		SAFE_RELEASE(lpCtx->pDev);
		SAFE_RELEASE(lpCtx->pD3D);
		lpCtx->pD3DXContext->lpVtbl->Release(lpCtx->pD3DXContext);
		lpCtx->pD3DXContext = NULL;
	} else {
		lpCtx = (GLD_driver_dx7*)malloc(sizeof(GLD_driver_dx7));
		ZeroMemory(lpCtx, sizeof(lpCtx));
	}

//	d3dDevType = (glb.dwDriver == GLDS_DRIVER_HAL) ? D3DDEVTYPE_HAL : D3DDEVTYPE_REF;
	// Use REF device if requested. Otherwise D3DX_DEFAULT will choose highest level
	// of HW acceleration.
	dwDeviceIndex = (glb.dwDriver == GLDS_DRIVER_REF) ? D3DX_HWLEVEL_REFERENCE : D3DX_DEFAULT;

	// TODO: Check this
//	if (bDefaultDriver)
//		d3dDevType = D3DDEVTYPE_REF;

#ifdef _GLD_PERSISTANT
	// Use persistant interface if needed
	if (bDirectDrawPersistant && dx7Globals.bDirect3D) {
		lpCtx->pD3D = dx7Globals.pD3D;
		IDirect3D7_AddRef(lpCtx->pD3D);
		goto SkipDirectDrawCreate;
	}
#endif
/*
	// Create Direct3D7 object
	lpCtx->pD3D = dx7Globals.fnDirect3DCreate8(D3D_SDK_VERSION_DX8_SUPPORT_WIN95);
	if (lpCtx->pD3D == NULL) {
		MessageBox(NULL, "Unable to initialize Direct3D8", "GLDirect", MB_OK);
		ddlogMessage(DDLOG_CRITICAL_OR_WARN, "Unable to create Direct3D8 interface");
        nContextError = GLDERR_D3D;
		goto return_with_error;
	}
*/

#ifdef _GLD_PERSISTANT
	// Cache Direct3D interface for subsequent GLRCs
	if (bDirectDrawPersistant && !dx8Globals.bDirect3D) {
		dx7Globals.pD3D = lpCtx->pD3D;
		IDirect3D7_AddRef(dx7Globals.pD3D);
		dx7Globals.bDirect3D = TRUE;
	}
SkipDirectDrawCreate:
#endif
/*
	// Get the display mode so we can make a compatible backbuffer
	hResult = IDirect3D8_GetAdapterDisplayMode(lpCtx->pD3D, glb.dwAdapter, &d3ddm);
	if (FAILED(hResult)) {
        nContextError = GLDERR_D3D;
		goto return_with_error;
	}
*/

#if 0
	// Get device caps
	hResult = IDirect3D8_GetDeviceCaps(lpCtx->pD3D, glb.dwAdapter, d3dDevType, &lpCtx->d3dCaps8);
	if (FAILED(hResult)) {
		ddlogError(DDLOG_CRITICAL_OR_WARN, "IDirect3D8_GetDeviceCaps failed", hResult);
        nContextError = GLDERR_D3D;
		goto return_with_error;
	}

	// Check for hardware transform & lighting
	lpCtx->bHasHWTnL = lpCtx->d3dCaps8.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ? TRUE : FALSE;

	// If this flag is present then we can't default to Mesa
	// SW rendering between BeginScene() and EndScene().
	if (lpCtx->d3dCaps8.Caps2 & D3DCAPS2_NO2DDURING3DSCENE) {
		ddlogMessage(DDLOG_WARN,
			"Warning          : No 2D allowed during 3D scene.\n");
	}
#endif

	//
	//	Create the Direct3D context
	//

#ifdef _GLD_PERSISTANT
	// Re-use original IDirect3DDevice if persistant buffers exist.
	// Note that we test for persistant IDirect3D8 as well
	// bDirectDrawPersistant == persistant IDirect3D8 (DirectDraw8 does not exist)
	if (bDirectDrawPersistant && bPersistantBuffers && dx7Globals.pD3D && dx7Globals.pDev) {
		lpCtx->pDev = dx7Globals.pDev;
		IDirect3DDevice7_AddRef(dx7Globals.pDev);
		goto skip_direct3ddevice_create;
	}
#endif
/*
	// Clear the presentation parameters (sets all members to zero)
	ZeroMemory(&d3dpp, sizeof(d3dpp));

	// Recommended by MS; needed for MultiSample.
	// Be careful if altering this for FullScreenBlit
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

	d3dpp.BackBufferFormat	= d3ddm.Format;
	d3dpp.BackBufferCount	= 1;
	d3dpp.MultiSampleType	= _gldGetDeviceMultiSampleType(lpCtx->pD3D, d3ddm.Format, d3dDevType, !ctx->bFullscreen);
	d3dpp.AutoDepthStencilFormat	= ctx->lpPF->dwDriverData;
	d3dpp.EnableAutoDepthStencil	= (d3dpp.AutoDepthStencilFormat == D3DFMT_UNKNOWN) ? FALSE : TRUE;

	if (ctx->bFullscreen) {
		ddlogWarnOption(FALSE); // Don't popup any messages in fullscreen 
		d3dpp.Windowed							= FALSE;
		d3dpp.BackBufferWidth					= d3ddm.Width;
		d3dpp.BackBufferHeight					= d3ddm.Height;
		d3dpp.hDeviceWindow						= ctx->hWnd;
		d3dpp.FullScreen_RefreshRateInHz		= D3DPRESENT_RATE_DEFAULT;

		// Support for vertical retrace synchronisation.
		// Set default presentation interval in case caps bits are missing
		d3dpp.FullScreen_PresentationInterval	= D3DPRESENT_INTERVAL_DEFAULT;
		if (glb.bWaitForRetrace) {
			if (lpCtx->d3dCaps8.PresentationIntervals & D3DPRESENT_INTERVAL_ONE)
				d3dpp.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE;
		} else {
			if (lpCtx->d3dCaps8.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE)
				d3dpp.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
		}
	} else {
		ddlogWarnOption(glb.bMessageBoxWarnings); // OK to popup messages
		d3dpp.Windowed							= TRUE;
		d3dpp.BackBufferWidth					= ctx->dwWidth;
		d3dpp.BackBufferHeight					= ctx->dwHeight;
		d3dpp.hDeviceWindow						= ctx->hWnd;
		d3dpp.FullScreen_RefreshRateInHz		= 0;
		// FullScreen_PresentationInterval must be default for Windowed mode
		d3dpp.FullScreen_PresentationInterval	= D3DPRESENT_INTERVAL_DEFAULT;
	}

	// Decide if we can use hardware TnL
	dwBehaviourFlags = (lpCtx->bHasHWTnL) ?
		D3DCREATE_MIXED_VERTEXPROCESSING : D3DCREATE_SOFTWARE_VERTEXPROCESSING;
	// Add flag to tell D3D to be thread-safe
	if (glb.bMultiThreaded)
		dwBehaviourFlags |= D3DCREATE_MULTITHREADED;
	hResult = IDirect3D8_CreateDevice(lpCtx->pD3D,
								glb.dwAdapter,
								d3dDevType,
								ctx->hWnd,
								dwBehaviourFlags,
								&d3dpp,
								&lpCtx->pDev);
    if (FAILED(hResult)) {
		ddlogError(DDLOG_CRITICAL_OR_WARN, "IDirect3D8_CreateDevice failed", hResult);
        nContextError = GLDERR_D3D;
		goto return_with_error;
	}
*/

	// Create D3DX context
	if (ctx->bFullscreen) {
		//
		// FULLSCREEN
		//

		// Get display mode
		D3DXGetCurrentVideoMode(D3DX_DEFAULT, &d3ddm);

		// Fullscreen Parameters
		dwFlags			= D3DX_CONTEXT_FULLSCREEN;
		hwnd			= ctx->hWnd;
		hwndFocus		= ctx->hWnd;
		numColorBits	= ctx->lpPF->pfd.cColorBits;
		numAlphaBits	= ctx->lpPF->pfd.cAlphaBits;
		numDepthBits	= ctx->lpPF->pfd.cDepthBits + ctx->lpPF->pfd.cStencilBits;
		numStencilBits	= ctx->lpPF->pfd.cStencilBits;
		numBackBuffers	= D3DX_DEFAULT; // Default is 1 backbuffer
		dwWidth			= d3ddm.width;
		dwHeight		= d3ddm.height;
		refreshRate		= d3ddm.refreshRate; // D3DX_DEFAULT;
	} else {
		//
		// WINDOWED
		//

		// Windowed Parameters
		dwFlags			= 0; // No flags means "windowed"
		hwnd			= ctx->hWnd;
		hwndFocus		= (HWND)D3DX_DEFAULT;
		numColorBits	= D3DX_DEFAULT; // Use Desktop depth
		numAlphaBits	= ctx->lpPF->pfd.cAlphaBits;
		numDepthBits	= ctx->lpPF->pfd.cDepthBits + ctx->lpPF->pfd.cStencilBits;
		numStencilBits	= ctx->lpPF->pfd.cStencilBits;
		numBackBuffers	= D3DX_DEFAULT; // Default is 1 backbuffer
		dwWidth			= ctx->dwWidth;
		dwHeight		= ctx->dwHeight;
		refreshRate		= D3DX_DEFAULT;
	}
	hr = D3DXCreateContextEx(dwDeviceIndex, dwFlags, hwnd, hwndFocus,
							numColorBits, numAlphaBits, numDepthBits, numStencilBits,
							numBackBuffers,
							dwWidth, dwHeight, refreshRate,
							&lpCtx->pD3DXContext);
    if (FAILED(hr)) {
		ddlogError(DDLOG_CRITICAL_OR_WARN, "D3DXCreateContextEx failed", hr);
        nContextError = GLDERR_D3D;
		goto return_with_error;
	}

	// Obtain D3D7 interfaces from ID3DXContext
//	lpCtx->pDD	= ID3DXContext_GetDD(lpCtx->pD3DXContext);
	lpCtx->pDD	= lpCtx->pD3DXContext->lpVtbl->GetDD(lpCtx->pD3DXContext);
	if (lpCtx->pDD == NULL)
		goto return_with_error;
	lpCtx->pD3D	= lpCtx->pD3DXContext->lpVtbl->GetD3D(lpCtx->pD3DXContext);
	if (lpCtx->pD3D == NULL)
		goto return_with_error;
	lpCtx->pDev	= lpCtx->pD3DXContext->lpVtbl->GetD3DDevice(lpCtx->pD3DXContext);
	if (lpCtx->pDev == NULL)
		goto return_with_error;

    // Need to manage clipper manually for multiple windows
    // since DX7 D3DX utility lib does not appear to do that. (DaveM)
    if (!ctx->bFullscreen) {
        // Get primary surface too
        lpDDSPrimary = lpCtx->pD3DXContext->lpVtbl->GetPrimary(lpCtx->pD3DXContext);
	    if (lpDDSPrimary == NULL) {
		    ddlogPrintf(DDLOG_WARN, "GetPrimary");
            goto return_with_error;
	    }
	    // Create clipper for correct window updates
        if (IDirectDraw7_CreateClipper(lpCtx->pDD, 0, &lpDDClipper, NULL) != DD_OK) {
		    ddlogPrintf(DDLOG_WARN, "CreateClipper");
		    goto return_with_error;
	    }
        // Set the window that the clipper belongs to
        if (IDirectDrawClipper_SetHWnd(lpDDClipper, 0, hwnd) != DD_OK) {
		    ddlogPrintf(DDLOG_WARN, "SetHWnd");
		    goto return_with_error;
	    }
        // Attach the clipper to the primary surface
        if (IDirectDrawSurface7_SetClipper(lpDDSPrimary, lpDDClipper) != DD_OK) {
		    ddlogPrintf(DDLOG_WARN, "SetClipper");
            goto return_with_error;
	    }
    }

	// Get device caps
	IDirect3DDevice7_GetCaps(lpCtx->pDev, &lpCtx->d3dCaps);

	// Determine HW TnL
	lpCtx->bHasHWTnL = lpCtx->d3dCaps.dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ? TRUE : FALSE;

#ifdef _GLD_PERSISTANT
	if (bDirectDrawPersistant && bPersistantBuffers && dx7Globals.pD3D) {
		dx7Globals.pDev = lpCtx->pDev;
		dx7Globals.bDirect3DDevice = TRUE;
	}
#endif

#if 0
	// Dump some useful stats
	hResult = IDirect3D8_GetAdapterIdentifier(
		lpCtx->pD3D,
		glb.dwAdapter,
		D3DENUM_NO_WHQL_LEVEL, // Avoids 1 to 2 second delay
		&d3dIdent);
	if (SUCCEEDED(hResult)) {
		ddlogPrintf(DDLOG_INFO, "[Driver Description: %s]", &d3dIdent.Description);
		ddlogPrintf(DDLOG_INFO, "[Driver file: %s %d.%d.%02d.%d]",
			d3dIdent.Driver,
			HIWORD(d3dIdent.DriverVersion.HighPart),
			LOWORD(d3dIdent.DriverVersion.HighPart),
			HIWORD(d3dIdent.DriverVersion.LowPart),
			LOWORD(d3dIdent.DriverVersion.LowPart));
		ddlogPrintf(DDLOG_INFO, "[VendorId: 0x%X, DeviceId: 0x%X, SubSysId: 0x%X, Revision: 0x%X]",
			d3dIdent.VendorId, d3dIdent.DeviceId, d3dIdent.SubSysId, d3dIdent.Revision);
	}
#endif

	// Init projection matrix for D3D TnL
	D3DXMatrixIdentity((D3DXMATRIX*)&lpCtx->matProjection);
	lpCtx->matModelView = lpCtx->matProjection;
//		gld->bUseMesaProjection = TRUE;

skip_direct3ddevice_create:

	// Create buffers to hold primitives
	lpCtx->PB2d.dwFVF			= GLD_FVF_2D_VERTEX;
//	lpCtx->PB2d.dwPool			= D3DPOOL_SYSTEMMEM;
	lpCtx->PB2d.dwStride		= sizeof(GLD_2D_VERTEX);
	lpCtx->PB2d.dwCreateFlags	= D3DVBCAPS_DONOTCLIP |
									D3DVBCAPS_SYSTEMMEMORY |
									D3DVBCAPS_WRITEONLY;
	hr = _gldCreatePrimitiveBuffer(ctx->glCtx, lpCtx, &lpCtx->PB2d);
	if (FAILED(hr))
		goto return_with_error;

	lpCtx->PB3d.dwFVF			= GLD_FVF_3D_VERTEX;
//	lpCtx->PB3d.dwPool			= D3DPOOL_DEFAULT;
	lpCtx->PB3d.dwStride		= sizeof(GLD_3D_VERTEX);
	lpCtx->PB3d.dwCreateFlags	= D3DVBCAPS_WRITEONLY;

	hr = _gldCreatePrimitiveBuffer(ctx->glCtx, lpCtx, &lpCtx->PB3d);
	if (FAILED(hr))
		goto return_with_error;

	// Zero the pipeline usage counters
	lpCtx->PipelineUsage.qwMesa.QuadPart = 
//	lpCtx->PipelineUsage.dwD3D2SVS.QuadPart =
	lpCtx->PipelineUsage.qwD3DFVF.QuadPart = 0;

	// Assign drawable to GL private
	ctx->glPriv = lpCtx;
	return TRUE;

return_with_error:
	// Clean up and bail
	_gldDestroyPrimitiveBuffer(&lpCtx->PB3d);
	_gldDestroyPrimitiveBuffer(&lpCtx->PB2d);

	SAFE_RELEASE(lpCtx->pDev);
	SAFE_RELEASE(lpCtx->pD3D);
	//SAFE_RELEASE(lpCtx->pD3DXContext);
	lpCtx->pD3DXContext->lpVtbl->Release(lpCtx->pD3DXContext);
	return FALSE;
}