diff options
author | Alan Hourihane <[email protected]> | 2004-04-20 11:13:11 +0000 |
---|---|---|
committer | Alan Hourihane <[email protected]> | 2004-04-20 11:13:11 +0000 |
commit | 485438e2be08c6d57110101f76dd41a5f484a4ee (patch) | |
tree | 1d36515d92b864caddfa1d7bb05a9e235ef218a9 /src/mesa/drivers/windows/gldirect/dx7/gld_wgl_dx7.c | |
parent | 319f5fd5ec85b4ca845028e6cdb94cca0a00d3d5 (diff) |
add SciTech's GLDirect driver for Windows.
This code is donated to Mesa which allows the usage of
a Direct3D layer (DX7, DX8, DX9 or complete software fallback).
No build system exists for this code yet, that will come.....
Diffstat (limited to 'src/mesa/drivers/windows/gldirect/dx7/gld_wgl_dx7.c')
-rw-r--r-- | src/mesa/drivers/windows/gldirect/dx7/gld_wgl_dx7.c | 1611 |
1 files changed, 1611 insertions, 0 deletions
diff --git a/src/mesa/drivers/windows/gldirect/dx7/gld_wgl_dx7.c b/src/mesa/drivers/windows/gldirect/dx7/gld_wgl_dx7.c new file mode 100644 index 00000000000..80395130805 --- /dev/null +++ b/src/mesa/drivers/windows/gldirect/dx7/gld_wgl_dx7.c @@ -0,0 +1,1611 @@ +/**************************************************************************** +* +* Mesa 3-D graphics library +* Direct3D Driver Interface +* +* ======================================================================== +* +* Copyright (C) 1991-2004 SciTech Software, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* SCITECH SOFTWARE INC BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* ====================================================================== +* +* Language: ANSI C +* Environment: Windows 9x/2000/XP/XBox (Win32) +* +* Description: GLDirect Direct3D 8.x WGL (WindowsGL) +* +****************************************************************************/ + +#include "dglcontext.h" +#include "gld_driver.h" +//#include "gld_dxerr8.h" +#include "gld_dx7.h" + +#include "tnl/tnl.h" +#include "tnl/t_context.h" + +// Copied from dglcontect.c +#define GLDERR_NONE 0 +#define GLDERR_MEM 1 +#define GLDERR_DDRAW 2 +#define GLDERR_D3D 3 +#define GLDERR_BPP 4 +#define GLDERR_DDS 5 +// This external var keeps track of any error +extern int nContextError; + +// Uncomment this for persistant resources +//#define _GLD_PERSISTANT + +#define DDLOG_CRITICAL_OR_WARN DDLOG_CRITICAL + +extern void _gld_mesa_warning(GLcontext *, char *); +extern void _gld_mesa_fatal(GLcontext *, char *); + +//--------------------------------------------------------------------------- + +static char szColorDepthWarning[] = +"GLDirect does not support the current desktop\n\ +color depth.\n\n\ +You may need to change the display resolution to\n\ +16 bits per pixel or higher color depth using\n\ +the Windows Display Settings control panel\n\ +before running this OpenGL application.\n"; + +// The only depth-stencil formats currently supported by Direct3D +// Surface Format Depth Stencil Total Bits +// D3DFMT_D32 32 - 32 +// D3DFMT_D15S1 15 1 16 +// D3DFMT_D24S8 24 8 32 +// D3DFMT_D16 16 - 16 +// D3DFMT_D24X8 24 - 32 +// D3DFMT_D24X4S4 24 4 32 + +// This pixel format will be used as a template when compiling the list +// of pixel formats supported by the hardware. Many fields will be +// filled in at runtime. +// PFD flag defaults are upgraded to match ChoosePixelFormat() -- DaveM +static DGL_pixelFormat pfTemplateHW = +{ + { + sizeof(PIXELFORMATDESCRIPTOR), // Size of the data structure + 1, // Structure version - should be 1 + // Flags: + PFD_DRAW_TO_WINDOW | // The buffer can draw to a window or device surface. + PFD_DRAW_TO_BITMAP | // The buffer can draw to a bitmap. (DaveM) + PFD_SUPPORT_GDI | // The buffer supports GDI drawing. (DaveM) + PFD_SUPPORT_OPENGL | // The buffer supports OpenGL drawing. + PFD_DOUBLEBUFFER | // The buffer is double-buffered. + 0, // Placeholder for easy commenting of above flags + PFD_TYPE_RGBA, // Pixel type RGBA. + 16, // Total colour bitplanes (excluding alpha bitplanes) + 5, 0, // Red bits, shift + 5, 0, // Green bits, shift + 5, 0, // Blue bits, shift + 0, 0, // Alpha bits, shift (destination alpha) + 0, // Accumulator bits (total) + 0, 0, 0, 0, // Accumulator bits: Red, Green, Blue, Alpha + 0, // Depth bits + 0, // Stencil bits + 0, // Number of auxiliary buffers + 0, // Layer type + 0, // Specifies the number of overlay and underlay planes. + 0, // Layer mask + 0, // Specifies the transparent color or index of an underlay plane. + 0 // Damage mask + }, + D3DX_SF_UNKNOWN, // No depth/stencil buffer +}; + +//--------------------------------------------------------------------------- +// Vertex Shaders +//--------------------------------------------------------------------------- +/* +// Vertex Shader Declaration +static DWORD dwTwoSidedLightingDecl[] = +{ + D3DVSD_STREAM(0), + D3DVSD_REG(0, D3DVSDT_FLOAT3), // XYZ position + D3DVSD_REG(1, D3DVSDT_FLOAT3), // XYZ normal + D3DVSD_REG(2, D3DVSDT_D3DCOLOR), // Diffuse color + D3DVSD_REG(3, D3DVSDT_D3DCOLOR), // Specular color + D3DVSD_REG(4, D3DVSDT_FLOAT2), // 2D texture unit 0 + D3DVSD_REG(5, D3DVSDT_FLOAT2), // 2D texture unit 1 + D3DVSD_END() +}; + +// Vertex Shader for two-sided lighting +static char *szTwoSidedLightingVS = +// This is a test shader! +"vs.1.0\n" +"m4x4 oPos,v0,c0\n" +"mov oD0,v2\n" +"mov oD1,v3\n" +"mov oT0,v4\n" +"mov oT1,v5\n" +; +*/ +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- + +typedef struct { +// HINSTANCE hD3D8DLL; // Handle to d3d8.dll +// FNDIRECT3DCREATE7 fnDirect3DCreate7; // Direct3DCreate8 function prototype +// BOOL bDirect3D; // Persistant Direct3D7 exists +// BOOL bDirect3DDevice; // Persistant Direct3DDevice7 exists +// IDirect3D7 *pD3D; // Persistant Direct3D7 +// IDirect3DDevice7 *pDev; // Persistant Direct3DDevice7 + BOOL bD3DXStarted; +} GLD_dx7_globals; + +// These are "global" to all DX7 contexts. KeithH +static GLD_dx7_globals dx7Globals; + +// Added for correct clipping of multiple open windows. (DaveM) +LPDIRECTDRAWSURFACE7 lpDDSPrimary = NULL; +LPDIRECTDRAWCLIPPER lpDDClipper = NULL; + +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- + +BOOL gldGetDXErrorString_DX( + HRESULT hr, + char *buf, + int nBufSize) +{ + // + // Return a string describing the input HRESULT error code + // + + D3DXGetErrorString(hr, nBufSize, buf); + return TRUE; +} + +//--------------------------------------------------------------------------- +// +// DX7 does not support multisample +/* +static D3DMULTISAMPLE_TYPE _gldGetDeviceMultiSampleType( + IDirect3D8 *pD3D8, + D3DFORMAT SurfaceFormat, + D3DDEVTYPE d3dDevType, + BOOL Windowed) +{ + int i; + HRESULT hr; + + if (glb.dwMultisample == GLDS_MULTISAMPLE_NONE) + return D3DMULTISAMPLE_NONE; + + if (glb.dwMultisample == GLDS_MULTISAMPLE_FASTEST) { + // Find fastest multisample + for (i=2; i<17; i++) { + hr = IDirect3D8_CheckDeviceMultiSampleType( + pD3D8, + glb.dwAdapter, + d3dDevType, + SurfaceFormat, + Windowed, + (D3DMULTISAMPLE_TYPE)i); + if (SUCCEEDED(hr)) { + return (D3DMULTISAMPLE_TYPE)i; + } + } + } else { + // Find nicest multisample + for (i=16; i>1; i--) { + hr = IDirect3D8_CheckDeviceMultiSampleType( + pD3D8, + glb.dwAdapter, + d3dDevType, + SurfaceFormat, + Windowed, + (D3DMULTISAMPLE_TYPE)i); + if (SUCCEEDED(hr)) { + return (D3DMULTISAMPLE_TYPE)i; + } + } + } + + // Nothing found - return default + return D3DMULTISAMPLE_NONE; +} +*/ +//--------------------------------------------------------------------------- + +void _gldDestroyPrimitiveBuffer( + GLD_pb_dx7 *gldVB) +{ + SAFE_RELEASE(gldVB->pVB); + + // Sanity check... + gldVB->nLines = gldVB->nPoints = gldVB->nTriangles = 0; +} + +//--------------------------------------------------------------------------- + +HRESULT _gldCreatePrimitiveBuffer( + GLcontext *ctx, + GLD_driver_dx7 *lpCtx, + GLD_pb_dx7 *gldVB) +{ + HRESULT hResult; + char *szCreateVertexBufferFailed = "CreateVertexBuffer failed"; + DWORD dwMaxVertices; // Max number of vertices in vertex buffer + DWORD dwVBSize; // Total size of vertex buffer + D3DVERTEXBUFFERDESC vbdesc; + + // If CVA (Compiled Vertex Array) is used by an OpenGL app, then we + // will need enough vertices to cater for Mesa::Const.MaxArrayLockSize. + // We'll use IMM_SIZE if it's larger (which it should not be). + dwMaxVertices = (IMM_SIZE < MAX_ARRAY_LOCK_SIZE) ? MAX_ARRAY_LOCK_SIZE : IMM_SIZE; + + // Max vertex buffer size limited in DX7. (DaveM) + if (dwMaxVertices*9 > D3DMAXNUMVERTICES) + dwMaxVertices = D3DMAXNUMVERTICES/9; + + // Now calculate how many vertices to allow for in total + // 1 per point, 2 per line, 6 per quad = 9 + dwVBSize = dwMaxVertices * 9 * gldVB->dwStride; + + vbdesc.dwSize = sizeof(vbdesc); + vbdesc.dwCaps = gldVB->dwCreateFlags; + vbdesc.dwFVF = gldVB->dwFVF; + vbdesc.dwNumVertices = dwMaxVertices * 9; + +/* hResult = IDirect3DDevice8_CreateVertexBuffer( + lpCtx->pDev, + dwVBSize, +RAgldVB->dwUsage, + gldVB->dwFVF, + gldVB->dwPool, + &gldVB->pVB);*/ + hResult = IDirect3D7_CreateVertexBuffer( + lpCtx->pD3D, + &vbdesc, + &gldVB->pVB, + 0); + if (FAILED(hResult)) { + ddlogMessage(DDLOG_CRITICAL_OR_WARN, szCreateVertexBufferFailed); + return hResult; + } + + gldVB->nLines = gldVB->nPoints = gldVB->nTriangles = 0; + gldVB->pPoints = gldVB->pLines = gldVB->pTriangles = NULL; + gldVB->iFirstLine = dwMaxVertices; // Index of first line in VB + gldVB->iFirstTriangle = dwMaxVertices*3; // Index of first triangle in VB + + return S_OK; +} + +//--------------------------------------------------------------------------- +// Function: _gldCreateVertexShaders +// Create DX8 Vertex Shaders. +//--------------------------------------------------------------------------- +/* +void _gldCreateVertexShaders( + GLD_driver_dx8 *gld) +{ + DWORD dwFlags; + LPD3DXBUFFER pVSOpcodeBuffer; // Vertex Shader opcode buffer + HRESULT hr; + +#ifdef _DEBUG + dwFlags = D3DXASM_DEBUG; +#else + dwFlags = 0; // D3DXASM_SKIPVALIDATION; +#endif + + ddlogMessage(DDLOG_INFO, "Creating shaders...\n"); + + // Init the shader handle + gld->VStwosidelight.hShader = 0; + + if (gld->d3dCaps8.MaxStreams == 0) { + // Lame DX8 driver doesn't support streams + // Not fatal, as defaults will be used + ddlogMessage(DDLOG_WARN, "Driver doesn't support Vertex Shaders (MaxStreams==0)\n"); + return; + } + + // ** THIS DISABLES VERTEX SHADER SUPPORT ** +// return; + // ** THIS DISABLES VERTEX SHADER SUPPORT ** + + // + // Two-sided lighting + // + +#if 0 + // + // DEBUGGING: Load shader from a text file + // + { + LPD3DXBUFFER pVSErrorBuffer; // Vertex Shader error buffer + hr = D3DXAssembleShaderFromFile( + "twoside.vsh", + dwFlags, + NULL, // No constants + &pVSOpcodeBuffer, + &pVSErrorBuffer); + if (pVSErrorBuffer && pVSErrorBuffer->lpVtbl->GetBufferPointer(pVSErrorBuffer)) + ddlogMessage(DDLOG_INFO, pVSErrorBuffer->lpVtbl->GetBufferPointer(pVSErrorBuffer)); + SAFE_RELEASE(pVSErrorBuffer); + } +#else + { + LPD3DXBUFFER pVSErrorBuffer; // Vertex Shader error buffer + // Assemble ascii shader text into shader opcodes + hr = D3DXAssembleShader( + szTwoSidedLightingVS, + strlen(szTwoSidedLightingVS), + dwFlags, + NULL, // No constants + &pVSOpcodeBuffer, + &pVSErrorBuffer); + if (pVSErrorBuffer && pVSErrorBuffer->lpVtbl->GetBufferPointer(pVSErrorBuffer)) + ddlogMessage(DDLOG_INFO, pVSErrorBuffer->lpVtbl->GetBufferPointer(pVSErrorBuffer)); + SAFE_RELEASE(pVSErrorBuffer); + } +#endif + if (FAILED(hr)) { + ddlogError(DDLOG_WARN, "AssembleShader failed", hr); + SAFE_RELEASE(pVSOpcodeBuffer); + return; + } + +// This is for debugging. Remove to enable vertex shaders in HW +#define _GLD_FORCE_SW_VS 0 + + if (_GLD_FORCE_SW_VS) { + // _GLD_FORCE_SW_VS should be disabled for Final Release + ddlogMessage(DDLOG_SYSTEM, "[Forcing shaders in SW]\n"); + } + + // Try and create shader in hardware. + // NOTE: The D3D Ref device appears to succeed when trying to + // create the device in hardware, but later complains + // when trying to set it with SetVertexShader(). Go figure. + if (_GLD_FORCE_SW_VS || glb.dwDriver == GLDS_DRIVER_REF) { + // Don't try and create a hardware shader with the Ref device + hr = E_FAIL; // COM error/fail result + } else { + gld->VStwosidelight.bHardware = TRUE; + hr = IDirect3DDevice8_CreateVertexShader( + gld->pDev, + dwTwoSidedLightingDecl, + pVSOpcodeBuffer->lpVtbl->GetBufferPointer(pVSOpcodeBuffer), + &gld->VStwosidelight.hShader, + 0); + } + if (FAILED(hr)) { + ddlogMessage(DDLOG_INFO, "... HW failed, trying SW...\n"); + // Failed. Try and create shader for software processing + hr = IDirect3DDevice8_CreateVertexShader( + gld->pDev, + dwTwoSidedLightingDecl, + pVSOpcodeBuffer->lpVtbl->GetBufferPointer(pVSOpcodeBuffer), + &gld->VStwosidelight.hShader, + D3DUSAGE_SOFTWAREPROCESSING); + if (FAILED(hr)) { + gld->VStwosidelight.hShader = 0; // Sanity check + ddlogError(DDLOG_WARN, "CreateVertexShader failed", hr); + return; + } + // Succeeded, but for software processing + gld->VStwosidelight.bHardware = FALSE; + } + + SAFE_RELEASE(pVSOpcodeBuffer); + + ddlogMessage(DDLOG_INFO, "... OK\n"); +} + +//--------------------------------------------------------------------------- + +void _gldDestroyVertexShaders( + GLD_driver_dx8 *gld) +{ + if (gld->VStwosidelight.hShader) { + IDirect3DDevice8_DeleteVertexShader(gld->pDev, gld->VStwosidelight.hShader); + gld->VStwosidelight.hShader = 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; +} + +//--------------------------------------------------------------------------- + +BOOL gldResizeDrawable_DX( + DGL_ctx *ctx, + BOOL bDefaultDriver, + BOOL bPersistantInterface, + BOOL bPersistantBuffers) +{ + GLD_driver_dx7 *gld = NULL; +// D3DDEVTYPE d3dDevType; +// D3DPRESENT_PARAMETERS d3dpp; +// D3DDISPLAYMODE d3ddm; + D3DX_VIDMODEDESC d3ddm; + HRESULT hr; + DWORD dwWidth, dwHeight; + + // Error if context is NULL. + if (ctx == NULL) + return FALSE; + + gld = ctx->glPriv; + if (gld == NULL) + return FALSE; + + if (ctx->bSceneStarted) { + IDirect3DDevice7_EndScene(gld->pDev); + ctx->bSceneStarted = FALSE; + } +/* + d3dDevType = (glb.dwDriver == GLDS_DRIVER_HAL) ? D3DDEVTYPE_HAL : D3DDEVTYPE_REF; + if (!bDefaultDriver) + d3dDevType = D3DDEVTYPE_REF; // Force Direct3D Reference Rasterise (software) + + // Get the display mode so we can make a compatible backbuffer + hResult = IDirect3D8_GetAdapterDisplayMode(gld->pD3D, glb.dwAdapter, &d3ddm); + if (FAILED(hResult)) { + nContextError = GLDERR_D3D; +// goto return_with_error; + return FALSE; + } +*/ + // Release objects before Reset() + _gldDestroyPrimitiveBuffer(&gld->PB3d); + _gldDestroyPrimitiveBuffer(&gld->PB2d); + +/* + // 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(gld->pD3D, d3ddm.Format, d3dDevType, !ctx->bFullscreen); + d3dpp.AutoDepthStencilFormat = ctx->lpPF->dwDriverData; + d3dpp.EnableAutoDepthStencil = (d3dpp.AutoDepthStencilFormat == D3DFMT_UNKNOWN) ? FALSE : TRUE; + + // TODO: Sync to refresh + + 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; + d3dpp.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; + // Get better benchmark results? KeithH +// d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_UNLIMITED; + } 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; + d3dpp.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; + } + hResult = IDirect3DDevice8_Reset(gld->pDev, &d3dpp); + if (FAILED(hResult)) { + ddlogError(DDLOG_CRITICAL_OR_WARN, "dglResize: Reset failed", hResult); + return FALSE; + //goto cleanup_and_return_with_error; + } +*/ + // Obtain dimensions of 'window' + if (ctx->bFullscreen) { + D3DXGetCurrentVideoMode(D3DX_DEFAULT, &d3ddm); + dwWidth = d3ddm.width; + dwHeight = d3ddm.height; + } else { + dwWidth = ctx->dwWidth; + dwHeight = ctx->dwHeight; + } + + // Resize context + hr = gld->pD3DXContext->lpVtbl->Resize(gld->pD3DXContext, dwWidth, dwHeight); + if (FAILED(hr)) { + ddlogError(DDLOG_CRITICAL_OR_WARN, "gldResizeDrawable_DX: Resize failed", hr); + return FALSE; + } + + // Clear the resized surface (DaveM) + { + D3DVIEWPORT7 vp1, vp2; + IDirect3DDevice7_GetViewport(gld->pDev, &vp1); + IDirect3DDevice7_GetViewport(gld->pDev, &vp2); + vp2.dwX = 0; + vp2.dwY = 0; + vp2.dwWidth = dwWidth; + vp2.dwHeight = dwHeight; + IDirect3DDevice7_SetViewport(gld->pDev, &vp2); + hr = gld->pD3DXContext->lpVtbl->Clear(gld->pD3DXContext, D3DCLEAR_TARGET); + if (FAILED(hr)) + ddlogError(DDLOG_WARN, "gldResizeDrawable_DX: Clear failed", hr); + IDirect3DDevice7_SetViewport(gld->pDev, &vp1); + } + + // + // Recreate objects + // + _gldCreatePrimitiveBuffer(ctx->glCtx, gld, &gld->PB2d); + _gldCreatePrimitiveBuffer(ctx->glCtx, gld, &gld->PB3d); + + // Signal a complete state update + ctx->glCtx->Driver.UpdateState(ctx->glCtx, _NEW_ALL); + + // Begin a new scene + IDirect3DDevice7_BeginScene(gld->pDev); + ctx->bSceneStarted = TRUE; + + return TRUE; +} + +//--------------------------------------------------------------------------- + +BOOL gldDestroyDrawable_DX( + DGL_ctx *ctx) +{ + GLD_driver_dx7 *lpCtx = NULL; + + // Error if context is NULL. + if (!ctx) + return FALSE; + + // Error if the drawable does not exist. + if (!ctx->glPriv) + return FALSE; + + lpCtx = ctx->glPriv; + +#ifdef _DEBUG + // Dump out stats + ddlogPrintf(DDLOG_SYSTEM, "Usage: M:0x%X%X, D:0x%X%X", + lpCtx->PipelineUsage.qwMesa.HighPart, + lpCtx->PipelineUsage.qwMesa.LowPart, + lpCtx->PipelineUsage.qwD3DFVF.HighPart, + lpCtx->PipelineUsage.qwD3DFVF.LowPart); +#endif + + // Destroy Primtive Buffers + _gldDestroyPrimitiveBuffer(&lpCtx->PB3d); + _gldDestroyPrimitiveBuffer(&lpCtx->PB2d); + + // Release DX interfaces (in reverse order) + SAFE_RELEASE(lpCtx->pDev); + SAFE_RELEASE(lpCtx->pD3D); + //SAFE_RELEASE(lpCtx->pD3DXContext); + lpCtx->pD3DXContext->lpVtbl->Release(lpCtx->pD3DXContext); + + // Free the private drawable data + free(ctx->glPriv); + ctx->glPriv = NULL; + + return TRUE; +} + +//--------------------------------------------------------------------------- + +BOOL gldCreatePrivateGlobals_DX(void) +{ +/* + ZeroMemory(&dx7Globals, sizeof(dx7Globals)); + + // Load d3d8.dll + dx8Globals.hD3D8DLL = LoadLibrary("D3D8.DLL"); + if (dx8Globals.hD3D8DLL == NULL) + return FALSE; + + // Now try and obtain Direct3DCreate8 + dx8Globals.fnDirect3DCreate8 = (FNDIRECT3DCREATE8)GetProcAddress(dx8Globals.hD3D8DLL, "Direct3DCreate8"); + if (dx8Globals.fnDirect3DCreate8 == NULL) { + FreeLibrary(dx8Globals.hD3D8DLL); + return FALSE; + } +*/ + + // Initialise D3DX + return FAILED(D3DXInitialize()) ? FALSE : TRUE; +} + +//--------------------------------------------------------------------------- + +BOOL gldDestroyPrivateGlobals_DX(void) +{ +/* + if (dx7Globals.bDirect3DDevice) { + SAFE_RELEASE(dx7Globals.pDev); + dx7Globals.bDirect3DDevice = FALSE; + } + if (dx7Globals.bDirect3D) { + SAFE_RELEASE(dx7Globals.pD3D); + dx7Globals.bDirect3D = FALSE; + } + + FreeLibrary(dx8Globals.hD3D8DLL); + dx8Globals.hD3D8DLL = NULL; + dx8Globals.fnDirect3DCreate8 = NULL; +*/ + return FAILED(D3DXUninitialize()) ? FALSE : TRUE; +} + +//--------------------------------------------------------------------------- + +static void _BitsFromDisplayFormat( + D3DX_SURFACEFORMAT fmt, + BYTE *cColorBits, + BYTE *cRedBits, + BYTE *cGreenBits, + BYTE *cBlueBits, + BYTE *cAlphaBits) +{ + switch (fmt) { +/* case D3DX_SF_X1R5G5B5: + *cColorBits = 16; + *cRedBits = 5; + *cGreenBits = 5; + *cBlueBits = 5; + *cAlphaBits = 0; + return;*/ + case D3DX_SF_R5G5B5: + *cColorBits = 16; + *cRedBits = 5; + *cGreenBits = 5; + *cBlueBits = 5; + *cAlphaBits = 0; + return; + case D3DX_SF_R5G6B5: + *cColorBits = 16; + *cRedBits = 5; + *cGreenBits = 6; + *cBlueBits = 5; + *cAlphaBits = 0; + return; + case D3DX_SF_X8R8G8B8: + *cColorBits = 32; + *cRedBits = 8; + *cGreenBits = 8; + *cBlueBits = 8; + *cAlphaBits = 0; + return; + case D3DX_SF_A8R8G8B8: + *cColorBits = 32; + *cRedBits = 8; + *cGreenBits = 8; + *cBlueBits = 8; + *cAlphaBits = 8; + return; + } + + // Should not get here! + *cColorBits = 32; + *cRedBits = 8; + *cGreenBits = 8; + *cBlueBits = 8; + *cAlphaBits = 0; +} + +//--------------------------------------------------------------------------- + +static void _BitsFromDepthStencilFormat( + D3DX_SURFACEFORMAT fmt, + BYTE *cDepthBits, + BYTE *cStencilBits) +{ + // NOTE: GL expects either 32 or 16 as depth bits. + switch (fmt) { + case D3DX_SF_Z16S0: + *cDepthBits = 16; + *cStencilBits = 0; + return; + case D3DX_SF_Z32S0: + *cDepthBits = 32; + *cStencilBits = 0; + return; + case D3DX_SF_Z15S1: + *cDepthBits = 15; + *cStencilBits = 1; + return; + case D3DX_SF_Z24S8: + *cDepthBits = 24; + *cStencilBits = 8; + return; + case D3DX_SF_S1Z15: + *cDepthBits = 15; + *cStencilBits = 1; + return; + case D3DX_SF_S8Z24: + *cDepthBits = 24; + *cStencilBits = 8; + return; + } +} + +//--------------------------------------------------------------------------- +/* +BOOL GLD_CheckDepthStencilMatch( + DWORD dwDeviceIndex, + D3DX_SURFACEFORMAT sfWant) +{ + // Emulate function built in to DX9 + D3DX_SURFACEFORMAT sfFound; + int i; + int nFormats = D3DXGetMaxSurfaceFormats(dwDeviceIndex, NULL, D3DX_SC_DEPTHBUFFER); + if (nFormats) { + for (i=0; i<nFormats; i++) { + D3DXGetSurfaceFormat(dwDeviceIndex, NULL, D3DX_SC_DEPTHBUFFER, i, &sfFound); } + if (sfFound == sfWant) + return TRUE; + } + + return FALSE; +} +*/ +//--------------------------------------------------------------------------- + +D3DX_SURFACEFORMAT _gldFindCompatibleDepthStencilFormat( + DWORD dwDeviceIndex) +{ + // Jump through some hoops... + + ID3DXContext *pD3DXContext = NULL; + IDirectDrawSurface7 *pZBuffer = NULL; + DDPIXELFORMAT ddpf; + HWND hWnd; + + // Get an HWND - use Desktop's + hWnd = GetDesktopWindow(); + + // Create a fully specified default context. + D3DXCreateContextEx(dwDeviceIndex, 0, hWnd, (HWND)D3DX_DEFAULT, + D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, + D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, + &pD3DXContext); + + // Obtain depth buffer that was created in context + pZBuffer = pD3DXContext->lpVtbl->GetZBuffer(pD3DXContext); + + // Get pixel format of depth buffer + ddpf.dwSize = sizeof(ddpf); + pZBuffer->lpVtbl->GetPixelFormat(pZBuffer, &ddpf); + // Done with surface - release it + pZBuffer->lpVtbl->Release(pZBuffer); + + // Done with D3DX context + pD3DXContext->lpVtbl->Release(pD3DXContext); + + // Convert and return + return D3DXMakeSurfaceFormat(&ddpf); +} + +//--------------------------------------------------------------------------- + +BOOL gldBuildPixelformatList_DX(void) +{ + D3DX_DEVICEDESC d3dxdd; + D3DX_VIDMODEDESC d3ddm; + D3DX_SURFACEFORMAT fmt[64]; // 64 should be enough... + DWORD dwDeviceIndex; + DWORD surfClassFlags; +// IDirect3D7 *pD3D = NULL; + HRESULT hr; + int nSupportedFormats = 0; // Total formats + int nDepthOnlyFormats = 0; + int nDepthStencilFormats = 0; + int i; + DGL_pixelFormat *pPF; + BYTE cColorBits, cRedBits, cGreenBits, cBlueBits, cAlphaBits; +// char buf[128]; +// char cat[8]; + + // Direct3D (SW or HW) + // These are arranged so that 'best' pixelformat + // is higher in the list (for ChoosePixelFormat). +/* const D3DFORMAT DepthStencil[4] = { + D3DX_SF_Z16S0, //D3DX_SF_D16, + D3DX_SF_Z15S1, //D3DX_SF_D15S1, + D3DX_SF_Z32S0, //D3DX_SF_D32, + D3DX_SF_Z24S8, //D3DX_SF_D24S8, + //D3DX_SF_D24X8, + //D3DX_SF_D24X4S4, + };*/ + + // Dump DX version + ddlogMessage(GLDLOG_SYSTEM, "DirectX Version : 7.0\n"); + + // Release any existing pixelformat list + if (glb.lpPF) { + free(glb.lpPF); + } + + glb.nPixelFormatCount = 0; + glb.lpPF = NULL; + + // + // Pixelformats for Direct3D (SW or HW) rendering + // + + dwDeviceIndex = (glb.dwDriver == GLDS_DRIVER_REF) ? D3DX_HWLEVEL_REFERENCE : D3DX_DEFAULT; + + // Dump description + D3DXGetDeviceDescription(dwDeviceIndex, &d3dxdd); + ddlogPrintf(GLDLOG_SYSTEM, "Device: %s", d3dxdd.driverDesc); + + // Get display mode + D3DXGetCurrentVideoMode(D3DX_DEFAULT, &d3ddm); + +#if 0 + // Phooey - this don't work... +/* + // Since D3DXGetMaxSurfaceFormats() can lie to us, we'll need a workaround. + // Explicitly test for matching depth/stencil to display bpp. + if (d3ddm.bpp <= 16) { + if (GLD_CheckDepthStencilMatch(dwDeviceIndex, D3DX_SF_Z16S0)) + fmt[nSupportedFormats++] = D3DX_SF_Z16S0; + if (GLD_CheckDepthStencilMatch(dwDeviceIndex, D3DX_SF_Z15S1)) + fmt[nSupportedFormats++] = D3DX_SF_Z15S1; + if (GLD_CheckDepthStencilMatch(dwDeviceIndex, D3DX_SF_S1Z15)) + fmt[nSupportedFormats++] = D3DX_SF_S1Z15; + // Didn't find anything? Try default + if (nSupportedFormats == 0) { + if (GLD_CheckDepthStencilMatch(dwDeviceIndex, D3DX_SF_Z32S0)) + fmt[nSupportedFormats++] = D3DX_SF_Z32S0; + } + } else { + if (GLD_CheckDepthStencilMatch(dwDeviceIndex, D3DX_SF_Z32S0)) + fmt[nSupportedFormats++] = D3DX_SF_Z32S0; + if (GLD_CheckDepthStencilMatch(dwDeviceIndex, D3DX_SF_Z24S8)) + fmt[nSupportedFormats++] = D3DX_SF_Z24S8; + if (GLD_CheckDepthStencilMatch(dwDeviceIndex, D3DX_SF_S8Z24)) + fmt[nSupportedFormats++] = D3DX_SF_S8Z24; + // Didn't find anything? Try default + if (nSupportedFormats == 0) { + if (GLD_CheckDepthStencilMatch(dwDeviceIndex, D3DX_SF_Z16S0)) + fmt[nSupportedFormats++] = D3DX_SF_Z16S0; + } + } +*/ + // Go the Whole Hog... + fmt[nSupportedFormats++] = _gldFindCompatibleDepthStencilFormat(dwDeviceIndex); +#else + // + // Depth buffer formats WITHOUT stencil + // + surfClassFlags = D3DX_SC_DEPTHBUFFER; + nDepthOnlyFormats = D3DXGetMaxSurfaceFormats(dwDeviceIndex, NULL, surfClassFlags); + // + // Depth buffer formats WITH stencil + // + surfClassFlags = D3DX_SC_DEPTHBUFFER | D3DX_SC_STENCILBUFFER; + nDepthStencilFormats = D3DXGetMaxSurfaceFormats(dwDeviceIndex, NULL, surfClassFlags); + + // Work out how many formats we have in total + if ((nDepthOnlyFormats + nDepthStencilFormats) == 0) + return FALSE; // Bail: no compliant pixelformats + + // Get depth buffer formats WITHOUT stencil + surfClassFlags = D3DX_SC_DEPTHBUFFER; + for (i=0; i<nDepthOnlyFormats; i++) { + D3DXGetSurfaceFormat(dwDeviceIndex, NULL, surfClassFlags, i, &fmt[nSupportedFormats++]); + } + // NOTE: For some reason we already get stencil formats when only specifying D3DX_SC_DEPTHBUFFER + /* + // Get depth buffer formats WITH stencil + surfClassFlags = D3DX_SC_DEPTHBUFFER | D3DX_SC_STENCILBUFFER; + for (i=0; i<nDepthStencilFormats; i++) { + D3DXGetSurfaceFormat(dwDeviceIndex, NULL, surfClassFlags, i, &fmt[nSupportedFormats++]); + } + */ +#endif + + // Total count of pixelformats is: + // (nSupportedFormats+1)*2 + glb.lpPF = (DGL_pixelFormat *)calloc((nSupportedFormats)*2, sizeof(DGL_pixelFormat)); + glb.nPixelFormatCount = (nSupportedFormats)*2; + if (glb.lpPF == NULL) { + glb.nPixelFormatCount = 0; + return FALSE; + } + + // Get a copy of pointer that we can alter + pPF = glb.lpPF; + + // Cache colour bits from display format +// _BitsFromDisplayFormat(d3ddm.Format, &cColorBits, &cRedBits, &cGreenBits, &cBlueBits, &cAlphaBits); + // Get display mode + D3DXGetCurrentVideoMode(D3DX_DEFAULT, &d3ddm); + cColorBits = d3ddm.bpp; + cAlphaBits = 0; + switch (d3ddm.bpp) { + case 15: + cRedBits = 5; cGreenBits = 5; cBlueBits = 5; + break; + case 16: + cRedBits = 5; cGreenBits = 6; cBlueBits = 5; + break; + case 24: + case 32: + cRedBits = 8; cGreenBits = 8; cBlueBits = 8; + break; + default: + cRedBits = 5; cGreenBits = 5; cBlueBits = 5; + } + + // + // Add single-buffer formats + // + +/* // Single-buffer, no depth-stencil buffer + memcpy(pPF, &pfTemplateHW, sizeof(DGL_pixelFormat)); + pPF->pfd.dwFlags &= ~PFD_DOUBLEBUFFER; // Remove doublebuffer flag + pPF->pfd.cColorBits = cColorBits; + pPF->pfd.cRedBits = cRedBits; + pPF->pfd.cGreenBits = cGreenBits; + pPF->pfd.cBlueBits = cBlueBits; + pPF->pfd.cAlphaBits = cAlphaBits; + pPF->pfd.cDepthBits = 0; + pPF->pfd.cStencilBits = 0; + pPF->dwDriverData = D3DX_SF_UNKNOWN; + pPF++;*/ + + for (i=0; i<nSupportedFormats; i++, pPF++) { + memcpy(pPF, &pfTemplateHW, sizeof(DGL_pixelFormat)); + pPF->pfd.dwFlags &= ~PFD_DOUBLEBUFFER; // Remove doublebuffer flag + pPF->pfd.cColorBits = cColorBits; + pPF->pfd.cRedBits = cRedBits; + pPF->pfd.cGreenBits = cGreenBits; + pPF->pfd.cBlueBits = cBlueBits; + pPF->pfd.cAlphaBits = cAlphaBits; + _BitsFromDepthStencilFormat(fmt[i], &pPF->pfd.cDepthBits, &pPF->pfd.cStencilBits); + pPF->dwDriverData = fmt[i]; + } + + // + // Add double-buffer formats + // + +/* memcpy(pPF, &pfTemplateHW, sizeof(DGL_pixelFormat)); + pPF->pfd.cColorBits = cColorBits; + pPF->pfd.cRedBits = cRedBits; + pPF->pfd.cGreenBits = cGreenBits; + pPF->pfd.cBlueBits = cBlueBits; + pPF->pfd.cAlphaBits = cAlphaBits; + pPF->pfd.cDepthBits = 0; + pPF->pfd.cStencilBits = 0; + pPF->dwDriverData = D3DX_SF_UNKNOWN; + pPF++;*/ + + for (i=0; i<nSupportedFormats; i++, pPF++) { + memcpy(pPF, &pfTemplateHW, sizeof(DGL_pixelFormat)); + pPF->pfd.cColorBits = cColorBits; + pPF->pfd.cRedBits = cRedBits; + pPF->pfd.cGreenBits = cGreenBits; + pPF->pfd.cBlueBits = cBlueBits; + pPF->pfd.cAlphaBits = cAlphaBits; + _BitsFromDepthStencilFormat(fmt[i], &pPF->pfd.cDepthBits, &pPF->pfd.cStencilBits); + pPF->dwDriverData = fmt[i]; + } + + // Popup warning message if non RGB color mode + { + // This is a hack. KeithH + HDC hdcDesktop = GetDC(NULL); + DWORD dwDisplayBitDepth = GetDeviceCaps(hdcDesktop, BITSPIXEL); + ReleaseDC(0, hdcDesktop); + if (dwDisplayBitDepth <= 8) { + ddlogPrintf(DDLOG_WARN, "Current Color Depth %d bpp is not supported", dwDisplayBitDepth); + MessageBox(NULL, szColorDepthWarning, "GLDirect", MB_OK | MB_ICONWARNING); + } + } + + // Mark list as 'current' + glb.bPixelformatsDirty = FALSE; + + return TRUE; +} + +//--------------------------------------------------------------------------- + +BOOL gldInitialiseMesa_DX( + DGL_ctx *lpCtx) +{ + GLD_driver_dx7 *gld = NULL; + int MaxTextureSize, TextureLevels; + BOOL bSoftwareTnL; + + if (lpCtx == NULL) + return FALSE; + + gld = lpCtx->glPriv; + if (gld == NULL) + return FALSE; + + if (glb.bMultitexture) { + lpCtx->glCtx->Const.MaxTextureUnits = gld->d3dCaps.wMaxSimultaneousTextures; + // Only support MAX_TEXTURE_UNITS texture units. + // ** If this is altered then the FVF formats must be reviewed **. + if (lpCtx->glCtx->Const.MaxTextureUnits > GLD_MAX_TEXTURE_UNITS_DX7) + lpCtx->glCtx->Const.MaxTextureUnits = GLD_MAX_TEXTURE_UNITS_DX7; + } else { + // Multitexture override + lpCtx->glCtx->Const.MaxTextureUnits = 1; + } + + // max texture size +// MaxTextureSize = min(gld->d3dCaps8.MaxTextureHeight, gld->d3dCaps8.MaxTextureWidth); + MaxTextureSize = min(gld->d3dCaps.dwMaxTextureHeight, gld->d3dCaps.dwMaxTextureWidth); + if (MaxTextureSize == 0) + MaxTextureSize = 256; // Sanity check + + // + // HACK!! + if (MaxTextureSize > 1024) + MaxTextureSize = 1024; // HACK - CLAMP TO 1024 + // HACK!! + // + + // TODO: Check this again for Mesa 5 + // Got to set MAX_TEXTURE_SIZE as max levels. + // Who thought this stupid idea up? ;) + TextureLevels = 0; + // Calculate power-of-two. + while (MaxTextureSize) { + TextureLevels++; + MaxTextureSize >>= 1; + } + lpCtx->glCtx->Const.MaxTextureLevels = (TextureLevels) ? TextureLevels : 8; + + // Defaults + IDirect3DDevice7_SetRenderState(gld->pDev, D3DRENDERSTATE_LIGHTING, FALSE); + IDirect3DDevice7_SetRenderState(gld->pDev, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE); + IDirect3DDevice7_SetRenderState(gld->pDev, D3DRENDERSTATE_DITHERENABLE, TRUE); + IDirect3DDevice7_SetRenderState(gld->pDev, D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD); + + // Set texture coord set to be used with each stage + IDirect3DDevice7_SetTextureStageState(gld->pDev, 0, D3DTSS_TEXCOORDINDEX, 0); + IDirect3DDevice7_SetTextureStageState(gld->pDev, 1, D3DTSS_TEXCOORDINDEX, 1); + + // Set up Depth buffer + IDirect3DDevice7_SetRenderState(gld->pDev, D3DRENDERSTATE_ZENABLE, + (lpCtx->lpPF->dwDriverData!=D3DX_SF_UNKNOWN) ? D3DZB_TRUE : D3DZB_FALSE); + + // Set the view matrix + { + D3DXMATRIX vm; +#if 1 + D3DXMatrixIdentity(&vm); +#else + D3DXVECTOR3 Eye(0.0f, 0.0f, 0.0f); + D3DXVECTOR3 At(0.0f, 0.0f, -1.0f); + D3DXVECTOR3 Up(0.0f, 1.0f, 0.0f); + D3DXMatrixLookAtRH(&vm, &Eye, &At, &Up); + vm._31 = -vm._31; + vm._32 = -vm._32; + vm._33 = -vm._33; + vm._34 = -vm._34; +#endif + IDirect3DDevice7_SetTransform(gld->pDev, D3DTRANSFORMSTATE_VIEW, &vm); + } + +// DX7 does not support D3DRS_SOFTWAREVERTEXPROCESSING +/* + if (gld->bHasHWTnL) { + if (glb.dwTnL == GLDS_TNL_DEFAULT) + bSoftwareTnL = FALSE; // HW TnL + else { + bSoftwareTnL = ((glb.dwTnL == GLDS_TNL_MESA) || (glb.dwTnL == GLDS_TNL_D3DSW)) ? TRUE : FALSE; + } + } else { + // No HW TnL, so no choice possible + bSoftwareTnL = TRUE; + } + IDirect3DDevice8_SetRenderState(gld->pDev, D3DRS_SOFTWAREVERTEXPROCESSING, bSoftwareTnL); +*/ + +// Dump this in a Release build as well, now. +//#ifdef _DEBUG + ddlogPrintf(DDLOG_INFO, "HW TnL: %s", +// gld->bHasHWTnL ? (bSoftwareTnL ? "Disabled" : "Enabled") : "Unavailable"); + gld->bHasHWTnL ? "Enabled" : "Unavailable"); +//#endif + + // Set up interfaces to Mesa + gldEnableExtensions_DX7(lpCtx->glCtx); + gldInstallPipeline_DX7(lpCtx->glCtx); + gldSetupDriverPointers_DX7(lpCtx->glCtx); + + // Signal a complete state update + lpCtx->glCtx->Driver.UpdateState(lpCtx->glCtx, _NEW_ALL); + + // Start a scene + IDirect3DDevice7_BeginScene(gld->pDev); + lpCtx->bSceneStarted = TRUE; + + return TRUE; +} + +//--------------------------------------------------------------------------- + +BOOL gldSwapBuffers_DX( + DGL_ctx *ctx, + HDC hDC, + HWND hWnd) +{ + HRESULT hr; + GLD_driver_dx7 *gld = NULL; + DWORD dwFlags; + + if (ctx == NULL) + return FALSE; + + gld = ctx->glPriv; + if (gld == NULL) + return FALSE; + + + // End the scene if one is started + if (ctx->bSceneStarted) { + IDirect3DDevice7_EndScene(gld->pDev); + ctx->bSceneStarted = FALSE; + } + + // Needed by D3DX for MDI multi-window apps (DaveM) + if (lpDDClipper) + IDirectDrawClipper_SetHWnd(lpDDClipper, 0, hWnd); + + // Swap the buffers. hWnd may override the hWnd used for CreateDevice() +// hr = IDirect3DDevice8_Present(gld->pDev, NULL, NULL, hWnd, NULL); + + // Set refresh sync flag + dwFlags = glb.bWaitForRetrace ? 0 : D3DX_UPDATE_NOVSYNC; + // Render and show frame + hr = gld->pD3DXContext->lpVtbl->UpdateFrame(gld->pD3DXContext, dwFlags); + if (FAILED(hr)) + ddlogError(DDLOG_WARN, "gldSwapBuffers_DX: UpdateFrame", hr); + + if (hr == DDERR_SURFACELOST) { + hr = gld->pD3DXContext->lpVtbl->RestoreSurfaces(gld->pD3DXContext); + if (FAILED(hr)) + ddlogError(DDLOG_WARN, "gldSwapBuffers_DX: RestoreSurfaces", hr); + } + +exit_swap: + // Begin a new scene + IDirect3DDevice7_BeginScene(gld->pDev); + ctx->bSceneStarted = TRUE; + + return (FAILED(hr)) ? FALSE : TRUE; +} + +//--------------------------------------------------------------------------- + +BOOL gldGetDisplayMode_DX( + DGL_ctx *ctx, + GLD_displayMode *glddm) +{ +// D3DDISPLAYMODE d3ddm; + D3DX_VIDMODEDESC d3ddm; + HRESULT hr; + GLD_driver_dx7 *lpCtx = NULL; + BYTE cColorBits, cRedBits, cGreenBits, cBlueBits, cAlphaBits; + + if ((glddm == NULL) || (ctx == NULL)) + return FALSE; + + lpCtx = ctx->glPriv; + if (lpCtx == NULL) + return FALSE; + + if (lpCtx->pD3D == NULL) + return FALSE; + +// hr = IDirect3D8_GetAdapterDisplayMode(lpCtx->pD3D, glb.dwAdapter, &d3ddm); + hr = D3DXGetCurrentVideoMode(D3DX_DEFAULT, &d3ddm); + if (FAILED(hr)) + return FALSE; + + // Get info from the display format +// _BitsFromDisplayFormat(d3ddm.Format, +// &cColorBits, &cRedBits, &cGreenBits, &cBlueBits, &cAlphaBits); + + glddm->Width = d3ddm.width; + glddm->Height = d3ddm.height; + glddm->BPP = d3ddm.bpp; + glddm->Refresh = d3ddm.refreshRate; + + return TRUE; +} + +//--------------------------------------------------------------------------- + |