Пример #1
0
static HRESULT d3d_get_caps_dword(d3d *d3dptr, UINT adapter, D3DDEVTYPE devtype, d3d_caps_index which, DWORD *value)
{
	IDirect3D8 *d3d8 = (IDirect3D8 *)d3dptr->d3dobj;
	D3DCAPS8 caps;
	HRESULT result = IDirect3D8_GetDeviceCaps(d3d8, adapter, devtype, &caps);
	switch (which)
	{
		case CAPS_PRESENTATION_INTERVALS:	*value = caps.PresentationIntervals;	break;
		case CAPS_CAPS2:					*value = caps.DevCaps;					break;
		case CAPS_DEV_CAPS:					*value = caps.DevCaps;					break;
		case CAPS_SRCBLEND_CAPS:			*value = caps.SrcBlendCaps;				break;
		case CAPS_DSTBLEND_CAPS:			*value = caps.DestBlendCaps;			break;
		case CAPS_TEXTURE_CAPS:				*value = caps.TextureCaps;				break;
		case CAPS_TEXTURE_FILTER_CAPS:		*value = caps.TextureFilterCaps;		break;
		case CAPS_TEXTURE_ADDRESS_CAPS:		*value = caps.TextureAddressCaps;		break;
		case CAPS_TEXTURE_OP_CAPS:			*value = caps.TextureOpCaps;			break;
		case CAPS_MAX_TEXTURE_ASPECT:		*value = caps.MaxTextureAspectRatio;	break;
		case CAPS_MAX_TEXTURE_WIDTH:		*value = caps.MaxTextureWidth;			break;
		case CAPS_MAX_TEXTURE_HEIGHT:		*value = caps.MaxTextureHeight;			break;
		case CAPS_STRETCH_RECT_FILTER:		*value = 0;								break;
	}
	return result;
}
Пример #2
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;
}
Пример #3
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;
}