You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3241 lines
109 KiB
3241 lines
109 KiB
/*==========================================================================;
|
|
*
|
|
* Copyright (C) 1998 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: d3ddev.cpp
|
|
* Content: Direct3D device implementation
|
|
*@@BEGIN_MSINTERNAL
|
|
*
|
|
* $Id: device.c,v 1.26 1995/12/04 11:29:47 sjl Exp $
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 05/11/95 stevela Initial rev with this header.
|
|
* 11/11/95 stevela Light code changed.
|
|
* 23/11/95 colinmc Modifications to support aggregatable interfaces
|
|
* 07/12/95 stevela Merged Colin's changes.
|
|
* 10/12/95 stevela Removed AGGREGATE_D3D.
|
|
* 18/12/95 stevela Added GetMatrix, GetState.
|
|
* 15/07/96 andyhird Initialise Render state on devices
|
|
* 13/08/96 andyhird Check surface and device are compatible
|
|
* 18/08/96 colinmc Fixed z-buffer leak
|
|
*@@END_MSINTERNAL
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
|
|
/*
|
|
* Create an api for the Direct3DDevice object
|
|
*/
|
|
extern "C" {
|
|
#define this _this
|
|
#include "ddrawpr.h"
|
|
#undef this
|
|
}
|
|
#include "commdrv.hpp"
|
|
#include "drawprim.hpp"
|
|
|
|
//#ifdef DEBUG_PIPELINE
|
|
#include "testprov.h"
|
|
//#endif //DEBUG_PIPELINE
|
|
|
|
// Remove DDraw's type unsafe definition and replace with our C++ friendly def
|
|
#ifdef VALIDEX_CODE_PTR
|
|
#undef VALIDEX_CODE_PTR
|
|
#endif
|
|
#define VALIDEX_CODE_PTR( ptr ) \
|
|
(!IsBadCodePtr( (FARPROC) ptr ) )
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DDevice"
|
|
|
|
extern BOOL isMMXprocessor(void);
|
|
extern HRESULT GenGetPickRecords(LPDIRECT3DDEVICEI, D3DI_PICKDATA *);
|
|
extern BOOL IsValidD3DDeviceGuid(REFCLSID riid);
|
|
|
|
BOOL D3DI_isHALValid(LPD3DHAL_CALLBACKS halTable)
|
|
{
|
|
if(halTable==NULL) {
|
|
D3D_WARN(0, "HAL callbacks is NULL. HAL will not be enumerated.");
|
|
return FALSE;
|
|
}
|
|
|
|
if (halTable->dwSize != D3DHAL_SIZE_V1) {
|
|
D3D_WARN(0, "HAL callbacks invalid - size = %d, wanted %d. HAL will not be enumerated.",
|
|
halTable->dwSize, D3DHAL_SIZE_V1);
|
|
return FALSE;
|
|
}
|
|
if (halTable->dwReserved ||
|
|
halTable->dwReserved0 ||
|
|
halTable->dwReserved1 ||
|
|
halTable->dwReserved2 ||
|
|
halTable->dwReserved3 ||
|
|
halTable->dwReserved4 ||
|
|
halTable->dwReserved5 ||
|
|
halTable->dwReserved6 ||
|
|
halTable->dwReserved7 ||
|
|
halTable->dwReserved8 ||
|
|
halTable->dwReserved9 ||
|
|
halTable->lpReserved10 ||
|
|
halTable->lpReserved11 ||
|
|
halTable->lpReserved12 ||
|
|
halTable->lpReserved13 ||
|
|
halTable->lpReserved14 ||
|
|
halTable->lpReserved15 ||
|
|
halTable->lpReserved16 ||
|
|
halTable->lpReserved17 ||
|
|
halTable->lpReserved18 ||
|
|
halTable->lpReserved19 ||
|
|
halTable->lpReserved20 ||
|
|
halTable->lpReserved21) {
|
|
D3D_WARN(0, "HAL callbacks invalid - has non-zero reserved fields, HAL will not be enumerated.");
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
HRESULT DIRECT3DDEVICEI::stateInitialize(BOOL bZEnable)
|
|
{
|
|
D3DDEVICEDESC hwDesc, helDesc;
|
|
D3DLINEPATTERN defLPat;
|
|
HRESULT ret;
|
|
float tmpval;
|
|
BOOL ckeyenable = FALSE;
|
|
|
|
/* Get the device caps for MONOENABLE */
|
|
memset(&hwDesc, 0, sizeof(D3DDEVICEDESC));
|
|
hwDesc.dwSize = sizeof(D3DDEVICEDESC);
|
|
memset(&helDesc, 0, sizeof(D3DDEVICEDESC));
|
|
helDesc.dwSize = sizeof(D3DDEVICEDESC);
|
|
|
|
ret = GetCapsI(&hwDesc, &helDesc);
|
|
if (FAILED(ret)) {
|
|
D3D_ERR("stateInitialise: GetCaps failed");
|
|
return(ret);
|
|
}
|
|
|
|
/* If we run on (HAL OR RefRast) AND this is a DX3 app
|
|
then we need to initialize colorkey to TRUE so that the old HW driver (except s3 virge) behavior
|
|
is exhibited. */
|
|
if ( (this->dwVersion < 2) &&
|
|
( (IS_HW_DEVICE(this)) || (IsEqualIID(this->guid, IID_IDirect3DRefDevice)) ) )
|
|
{
|
|
ckeyenable = TRUE;
|
|
}
|
|
|
|
// Obviate SetRenderState filtering 'redundant' render state settings
|
|
// since this is the init step.
|
|
memset( this->rstates, 0xff, sizeof(DWORD)*D3DHAL_MAX_RSTATES );
|
|
this->rstates[D3DRENDERSTATE_PLANEMASK] = 0;
|
|
this->rstates[D3DRENDERSTATE_STENCILMASK] = 0;
|
|
this->rstates[D3DRENDERSTATE_STENCILWRITEMASK] = 0;
|
|
this->rstates[D3DRENDERSTATE_PLANEMASK] = 0;
|
|
|
|
SetRenderState( D3DRENDERSTATE_TEXTUREHANDLE, (DWORD)NULL);
|
|
SetRenderState( D3DRENDERSTATE_ANTIALIAS, FALSE);
|
|
SetRenderState( D3DRENDERSTATE_TEXTUREADDRESS, D3DTADDRESS_WRAP);
|
|
if (this->dwVersion <= 2)
|
|
{
|
|
SetRenderState( D3DRENDERSTATE_TEXTUREPERSPECTIVE, FALSE);
|
|
SetRenderState( D3DRENDERSTATE_SPECULARENABLE, TRUE);
|
|
}
|
|
else
|
|
{
|
|
// perspective enabled by default for Device3 and later
|
|
SetRenderState( D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE);
|
|
// specular disabled by default for Device3 and later
|
|
SetRenderState( D3DRENDERSTATE_SPECULARENABLE, FALSE);
|
|
}
|
|
SetRenderState( D3DRENDERSTATE_WRAPU, FALSE);
|
|
SetRenderState( D3DRENDERSTATE_WRAPV, FALSE);
|
|
SetRenderState( D3DRENDERSTATE_ZENABLE, bZEnable);
|
|
SetRenderState( D3DRENDERSTATE_FILLMODE, D3DFILL_SOLID);
|
|
SetRenderState( D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD);
|
|
|
|
defLPat.wRepeatFactor = 0;
|
|
defLPat.wLinePattern = 0;
|
|
|
|
SetRenderState( D3DRENDERSTATE_LINEPATTERN, *((LPDWORD)&defLPat)); /* 10 */
|
|
/*
|
|
((LPD3DSTATE)lpPointer)->drstRenderStateType =
|
|
(D3DRENDERSTATETYPE)D3DRENDERSTATE_LINEPATTERN;
|
|
memcpy(&(((LPD3DSTATE)lpPointer)->dwArg[0]), &defLPat, sizeof(DWORD));
|
|
lpPointer = (void *)(((LPD3DSTATE)lpPointer) + 1);*/
|
|
|
|
SetRenderState( D3DRENDERSTATE_ROP2, R2_COPYPEN);
|
|
SetRenderState( D3DRENDERSTATE_PLANEMASK, (DWORD)~0);
|
|
SetRenderState( D3DRENDERSTATE_ZWRITEENABLE, TRUE);
|
|
SetRenderState( D3DRENDERSTATE_ALPHATESTENABLE, FALSE);
|
|
SetRenderState( D3DRENDERSTATE_LASTPIXEL, TRUE);
|
|
SetRenderState( D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE);
|
|
SetRenderState( D3DRENDERSTATE_DESTBLEND, D3DBLEND_ZERO);
|
|
SetRenderState( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW); /* 21 */
|
|
SetRenderState( D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL);
|
|
SetRenderState( D3DRENDERSTATE_ALPHAREF, 0);
|
|
SetRenderState( D3DRENDERSTATE_ALPHAFUNC, D3DCMP_ALWAYS);
|
|
SetRenderState( D3DRENDERSTATE_DITHERENABLE, FALSE);
|
|
SetRenderState( D3DRENDERSTATE_BLENDENABLE, FALSE);
|
|
SetRenderState( D3DRENDERSTATE_FOGENABLE, FALSE);
|
|
SetRenderState( D3DRENDERSTATE_ZVISIBLE, FALSE);
|
|
SetRenderState( D3DRENDERSTATE_SUBPIXEL, FALSE); /* 30 */
|
|
SetRenderState( D3DRENDERSTATE_SUBPIXELX, FALSE);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEDALPHA, FALSE);
|
|
SetRenderState( D3DRENDERSTATE_FOGCOLOR, 0);
|
|
SetRenderState( D3DRENDERSTATE_FOGTABLEMODE, D3DFOG_NONE);
|
|
|
|
/* Initialise these - although they may not need doing */
|
|
tmpval = 0.0f;
|
|
SetRenderState( D3DRENDERSTATE_FOGTABLESTART, *((DWORD *)&tmpval));
|
|
tmpval = 1.0f;
|
|
SetRenderState( D3DRENDERSTATE_FOGTABLEEND, *((DWORD *)&tmpval));
|
|
tmpval = 1.0f;
|
|
SetRenderState( D3DRENDERSTATE_FOGTABLEDENSITY, *((DWORD *)&tmpval));
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEENABLE, FALSE);
|
|
SetRenderState( D3DRENDERSTATE_EDGEANTIALIAS, FALSE);
|
|
SetRenderState( D3DRENDERSTATE_COLORKEYENABLE, ckeyenable);
|
|
SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE, FALSE);
|
|
SetRenderState( D3DRENDERSTATE_BORDERCOLOR, 0);
|
|
SetRenderState( D3DRENDERSTATE_TEXTUREADDRESSU, D3DTADDRESS_WRAP);
|
|
SetRenderState( D3DRENDERSTATE_TEXTUREADDRESSV, D3DTADDRESS_WRAP);
|
|
SetRenderState( D3DRENDERSTATE_MIPMAPLODBIAS, 0);
|
|
SetRenderState( D3DRENDERSTATE_ZBIAS, 0);
|
|
SetRenderState( D3DRENDERSTATE_RANGEFOGENABLE, FALSE);
|
|
SetRenderState( D3DRENDERSTATE_ANISOTROPY, 1);
|
|
|
|
/* Again - all these probably don't need doing */
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN00, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN01, 0); /* 40 */
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN02, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN03, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN04, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN05, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN06, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN07, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN08, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN09, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN10, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN11, 0); /* 50 */
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN12, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN13, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN14, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN15, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN16, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN17, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN18, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN19, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN20, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN21, 0); /* 60 */
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN22, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN23, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN24, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN25, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN26, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN27, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN28, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN29, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN30, 0);
|
|
SetRenderState( D3DRENDERSTATE_STIPPLEPATTERN31, 0); /* 70 */
|
|
|
|
// init stencil states to something reasonable
|
|
// stencil enable is OFF by default since stenciling rasterizers will be
|
|
// faster with it disabled, even if stencil states are benign
|
|
SetRenderState( D3DRENDERSTATE_STENCILENABLE, FALSE);
|
|
SetRenderState( D3DRENDERSTATE_STENCILFAIL, D3DSTENCILOP_KEEP);
|
|
SetRenderState( D3DRENDERSTATE_STENCILZFAIL, D3DSTENCILOP_KEEP);
|
|
SetRenderState( D3DRENDERSTATE_STENCILPASS, D3DSTENCILOP_KEEP);
|
|
SetRenderState( D3DRENDERSTATE_STENCILFUNC, D3DCMP_ALWAYS);
|
|
SetRenderState( D3DRENDERSTATE_STENCILREF, 0);
|
|
SetRenderState( D3DRENDERSTATE_STENCILMASK, 0xFFFFFFFF);
|
|
SetRenderState( D3DRENDERSTATE_STENCILWRITEMASK,0xFFFFFFFF);
|
|
|
|
// don't forget about texturefactor (like we did in DX6.0...)
|
|
SetRenderState( D3DRENDERSTATE_TEXTUREFACTOR, 0xFFFFFFFF);
|
|
|
|
/* Check to see if the driver can do RGB - if not set MONOENABLE to
|
|
true otherwise false (ie. RGB) by default */
|
|
if (hwDesc.dwFlags & D3DDD_COLORMODEL) {
|
|
if ((hwDesc.dcmColorModel & D3DCOLOR_RGB)) {
|
|
D3D_INFO(3, "hw and RGB. MONOENABLE = FALSE");
|
|
SetRenderState( D3DRENDERSTATE_MONOENABLE, FALSE);
|
|
} else {
|
|
D3D_INFO(3, "hw and !RGB. MONOENABLE = TRUE");
|
|
SetRenderState( D3DRENDERSTATE_MONOENABLE, TRUE);
|
|
}
|
|
} else if (helDesc.dwFlags & D3DDD_COLORMODEL) {
|
|
if ((helDesc.dcmColorModel & D3DCOLOR_RGB)) {
|
|
D3D_INFO(3, "hel and RGB. MONOENABLE = FALSE");
|
|
SetRenderState( D3DRENDERSTATE_MONOENABLE, FALSE);
|
|
} else {
|
|
D3D_INFO(3, "hel and !RGB. MONOENABLE = TRUE");
|
|
SetRenderState( D3DRENDERSTATE_MONOENABLE, TRUE);
|
|
}
|
|
} else {
|
|
/* Hmm, something bad has happened if we get here! */
|
|
D3D_ERR("stateInitialise: neither hw or hel caps set");
|
|
return(DDERR_GENERIC);
|
|
}
|
|
|
|
for (unsigned i = 0; i < 8; i++)
|
|
{
|
|
SetRenderState( (D3DRENDERSTATETYPE)
|
|
(D3DRENDERSTATE_WRAPBIAS + i), FALSE );
|
|
}
|
|
for (i = 0; i < D3DHAL_TSS_MAXSTAGES; i++)
|
|
{
|
|
lpD3DMappedTexI[i] = NULL;
|
|
lpD3DMappedBlock[i] = NULL;
|
|
}
|
|
SetLightState( D3DLIGHTSTATE_COLORVERTEX, TRUE);
|
|
|
|
// Obviate SetTextureStageState/Settexture filtering 'redundant' render state
|
|
// settings since this is the init step.
|
|
memset( this->tsstates, 0xff, sizeof(DWORD)*D3DHAL_TSS_MAXSTAGES*D3DHAL_TSS_STATESPERSTAGE );
|
|
for (i = 0; i < D3DHAL_TSS_MAXSTAGES; i++)
|
|
{
|
|
SetTexture(i, NULL);
|
|
if(i == 0)
|
|
SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
|
else
|
|
SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
|
|
SetTextureStageState(i, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
|
SetTextureStageState(i, D3DTSS_COLORARG2, D3DTA_CURRENT);
|
|
if(i == 0)
|
|
SetTextureStageState(i, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
|
|
else
|
|
SetTextureStageState(i, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
|
|
SetTextureStageState(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
|
SetTextureStageState(i, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
|
|
SetTextureStageState(i, D3DTSS_BUMPENVMAT00, 0);
|
|
SetTextureStageState(i, D3DTSS_BUMPENVMAT01, 0);
|
|
SetTextureStageState(i, D3DTSS_BUMPENVMAT10, 0);
|
|
SetTextureStageState(i, D3DTSS_BUMPENVMAT11, 0);
|
|
SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, 0);
|
|
SetTextureStageState(i, D3DTSS_ADDRESS, D3DTADDRESS_WRAP);
|
|
SetTextureStageState(i, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP);
|
|
SetTextureStageState(i, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP);
|
|
SetTextureStageState(i, D3DTSS_BORDERCOLOR, 0x00000000);
|
|
SetTextureStageState(i, D3DTSS_MAGFILTER, D3DTFG_POINT);
|
|
SetTextureStageState(i, D3DTSS_MINFILTER, D3DTFN_POINT);
|
|
SetTextureStageState(i, D3DTSS_MIPFILTER, D3DTFP_NONE);
|
|
SetTextureStageState(i, D3DTSS_MIPMAPLODBIAS, 0);
|
|
SetTextureStageState(i, D3DTSS_MAXMIPLEVEL, 0);
|
|
SetTextureStageState(i, D3DTSS_MAXANISOTROPY, 1);
|
|
SetTextureStageState(i, D3DTSS_BUMPENVLSCALE, 0);
|
|
SetTextureStageState(i, D3DTSS_BUMPENVLOFFSET, 0);
|
|
}
|
|
|
|
// need to set legacy blend and filtering states after per-stage initialization
|
|
// to properly set defaults in device
|
|
SetRenderState( D3DRENDERSTATE_TEXTUREMAG, D3DFILTER_NEAREST);
|
|
SetRenderState( D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_NEAREST);
|
|
SetRenderState( D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE);
|
|
|
|
// Reset request bit as legacy renderstates have been already initialized
|
|
// and no mapping is needed
|
|
this->dwFEFlags &= ~D3DFE_MAP_TSS_TO_RS;
|
|
|
|
return(D3D_OK);
|
|
}
|
|
|
|
DWORD BitDepthToDDBD(int bpp)
|
|
{
|
|
switch(bpp)
|
|
{
|
|
case 1:
|
|
return DDBD_1;
|
|
case 2:
|
|
return DDBD_2;
|
|
case 4:
|
|
return DDBD_4;
|
|
case 8:
|
|
return DDBD_8;
|
|
case 16:
|
|
return DDBD_16;
|
|
case 24:
|
|
return DDBD_24;
|
|
case 32:
|
|
return DDBD_32;
|
|
default:
|
|
D3D_ERR("Invalid bit depth");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
HRESULT DIRECT3DDEVICEI::checkDeviceSurface(LPDIRECTDRAWSURFACE lpDDS, LPDIRECTDRAWSURFACE lpZbuffer, LPGUID pGuid)
|
|
{
|
|
D3DDEVICEDESC hwDesc, helDesc;
|
|
DDPIXELFORMAT surfPF;
|
|
DDSCAPS surfCaps;
|
|
HRESULT ret;
|
|
DWORD bpp;
|
|
|
|
/* Get caps bits - check whether device and surface are:
|
|
- video/system memory and depth compatible */
|
|
|
|
if (FAILED(ret = lpDDS->GetCaps(&surfCaps))) {
|
|
D3D_ERR("Failed to get render-target surface caps");
|
|
return(ret);
|
|
}
|
|
|
|
memset(&surfPF, 0, sizeof(DDPIXELFORMAT));
|
|
surfPF.dwSize = sizeof(DDPIXELFORMAT);
|
|
|
|
if (FAILED(ret = lpDDS->GetPixelFormat(&surfPF))) {
|
|
D3D_ERR("Failed to get render-target surface pixel format");
|
|
return(ret);
|
|
}
|
|
|
|
memset(&hwDesc, 0, sizeof(D3DDEVICEDESC));
|
|
hwDesc.dwSize = sizeof(D3DDEVICEDESC);
|
|
memset(&helDesc, 0, sizeof(D3DDEVICEDESC));
|
|
helDesc.dwSize = sizeof(D3DDEVICEDESC);
|
|
|
|
// ATTENTION - Why doesn't this just look at the DEVICEI fields?
|
|
ret = GetCapsI(&hwDesc, &helDesc);
|
|
if (FAILED(ret)) {
|
|
D3D_ERR("GetCaps failed");
|
|
return(ret);
|
|
}
|
|
|
|
if (hwDesc.dwFlags) {
|
|
/* I'm taking this as evidence that its running on hardware - therefore
|
|
the surface should be in video memory */
|
|
D3D_INFO(3, "Hardware device being used");
|
|
|
|
if (!(surfCaps.dwCaps & DDSCAPS_VIDEOMEMORY)) {
|
|
D3D_ERR("Render-target surface not in video memory for hw device");
|
|
return(D3DERR_SURFACENOTINVIDMEM);
|
|
}
|
|
}
|
|
|
|
/* A surface can only have one bit depth - whereas a device can support
|
|
multiple bit depths */
|
|
if (surfPF.dwFlags & DDPF_RGB) {
|
|
D3D_INFO(3, "Render-target surface is RGB");
|
|
|
|
bpp = BitDepthToDDBD(surfPF.dwRGBBitCount);
|
|
if (!bpp) {
|
|
D3D_ERR("Bogus render-target surface pixel depth");
|
|
return(DDERR_INVALIDPIXELFORMAT);
|
|
}
|
|
|
|
if((surfPF.dwRGBBitCount<16) && (IsEqualIID(*pGuid, IID_IDirect3DRefDevice) || IsEqualIID(*pGuid, IID_IDirect3DNullDevice))) {
|
|
// this is actually subsumed by the following test, but whatever
|
|
D3D_ERR("Reference rasterizer and null device dont support render targets with bitdepth < 16");
|
|
return(DDERR_INVALIDPIXELFORMAT);
|
|
}
|
|
|
|
if (!(bpp & helDesc.dwDeviceRenderBitDepth) &&
|
|
!(bpp & hwDesc.dwDeviceRenderBitDepth)) {
|
|
D3D_ERR("Render-target surface bitdepth is not supported by HEL or HW for this device");
|
|
return(DDERR_INVALIDPIXELFORMAT);
|
|
}
|
|
}
|
|
|
|
if(lpZbuffer==NULL)
|
|
return D3D_OK;
|
|
|
|
memset(&surfPF, 0, sizeof(DDPIXELFORMAT));
|
|
surfPF.dwSize = sizeof(DDPIXELFORMAT);
|
|
|
|
if (FAILED(ret = lpZbuffer->GetPixelFormat(&surfPF))) {
|
|
D3D_ERR("Failed to get zbuffer pixel format");
|
|
return(ret);
|
|
}
|
|
|
|
if (FAILED(ret = lpZbuffer->GetCaps(&surfCaps))) {
|
|
D3D_ERR("Failed to get Zbuffer caps");
|
|
return(ret);
|
|
}
|
|
|
|
if (hwDesc.dwFlags) {
|
|
if (!(surfCaps.dwCaps & DDSCAPS_VIDEOMEMORY)) {
|
|
D3D_ERR("Zbuffer not in video memory for hw device");
|
|
return(D3DERR_ZBUFF_NEEDS_VIDEOMEMORY);
|
|
}
|
|
D3D_INFO(3, "Hw device, zbuffer in video memory");
|
|
} else if (helDesc.dwFlags) {
|
|
if (!(surfCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)) {
|
|
D3D_ERR("Zbuffer not in system memory for HEL device");
|
|
return(D3DERR_ZBUFF_NEEDS_SYSTEMMEMORY);
|
|
}
|
|
D3D_INFO(3, "Hel device, zbuffer in system memory");
|
|
|
|
// have to hack in a check to make sure ramp isn't used with stencil zbuffer
|
|
// cant do this validation until device creation time (instead of at zbuffer creation in
|
|
// ddhel.c) because rgb vs. ramp isn't known until now
|
|
if(IsEqualIID(*pGuid, IID_IDirect3DRampDevice)) {
|
|
if(surfPF.dwFlags & DDPF_STENCILBUFFER) {
|
|
D3D_ERR("Z-Buffer with stencil is invalid with RAMP software rasterizer");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (surfPF.dwFlags & DDPF_ZBUFFER) {
|
|
bpp = BitDepthToDDBD(surfPF.dwZBufferBitDepth);
|
|
if (!bpp) {
|
|
D3D_ERR("Bogus Zbuffer surface pixel depth");
|
|
return(DDERR_INVALIDPIXELFORMAT);
|
|
}
|
|
}
|
|
|
|
return(D3D_OK);
|
|
}
|
|
|
|
|
|
/*
|
|
* Initialisation - class part and device part
|
|
*/
|
|
|
|
/*
|
|
* Generic class part initialisation
|
|
*/
|
|
HRESULT InitDeviceI(LPDIRECT3DDEVICEI lpDevI, LPDIRECT3DI lpD3DI)
|
|
{
|
|
LPDDRAWI_DIRECTDRAW_GBL lpDDI;
|
|
HRESULT error;
|
|
|
|
lpDDI = ((LPDDRAWI_DIRECTDRAW_INT)lpD3DI->lpDD)->lpLcl->lpGbl;
|
|
|
|
//
|
|
// Retrieve HAL information from provider.
|
|
//
|
|
|
|
error = lpDevI->pHalProv->GetCaps(lpDDI,
|
|
&lpDevI->d3dHWDevDesc,
|
|
&lpDevI->d3dHELDevDesc,
|
|
lpDevI->dwVersion);
|
|
if (error != S_OK)
|
|
{
|
|
return (error);
|
|
}
|
|
D3DHALPROVIDER_INTERFACEDATA HalProviderIData;
|
|
memset(&HalProviderIData,0,sizeof(HalProviderIData));
|
|
HalProviderIData.dwSize = sizeof(HalProviderIData);
|
|
if ((error = lpDevI->pHalProv->GetInterface(lpDDI,
|
|
&HalProviderIData,
|
|
lpDevI->dwVersion)) != S_OK)
|
|
{
|
|
return error;
|
|
}
|
|
// interface data for <=DX5 HAL
|
|
lpDevI->lpD3DHALGlobalDriverData = HalProviderIData.pGlobalData;
|
|
lpDevI->lpD3DExtendedCaps = HalProviderIData.pExtCaps;
|
|
lpDevI->lpD3DHALCallbacks = HalProviderIData.pCallbacks;
|
|
lpDevI->lpD3DHALCallbacks2 = HalProviderIData.pCallbacks2;
|
|
// interface data for DX6 HAL
|
|
lpDevI->lpD3DHALCallbacks3 = HalProviderIData.pCallbacks3;
|
|
|
|
lpDevI->pfnRampService = HalProviderIData.pfnRampService;
|
|
lpDevI->pfnRastService = HalProviderIData.pfnRastService;
|
|
lpDevI->dwHintFlags = 0;
|
|
|
|
// Zero out 8 bpp render target caps for real hardware.
|
|
if (lpDevI->d3dHWDevDesc.dwFlags != 0)
|
|
{
|
|
lpDevI->lpD3DHALGlobalDriverData->hwCaps.dwDeviceRenderBitDepth &=
|
|
(~DDBD_8);
|
|
}
|
|
|
|
if (!D3DI_isHALValid(lpDevI->lpD3DHALCallbacks))
|
|
{
|
|
return D3DERR_INITFAILED;
|
|
}
|
|
|
|
if (lpDevI->lpD3DExtendedCaps && lpDevI->lpD3DExtendedCaps->dwFVFCaps)
|
|
{
|
|
lpDevI->dwMaxTextureIndices =
|
|
lpDevI->lpD3DExtendedCaps->dwFVFCaps & D3DFVFCAPS_TEXCOORDCOUNTMASK;
|
|
lpDevI->dwMaxTextureBlendStages =
|
|
lpDevI->lpD3DExtendedCaps->wMaxTextureBlendStages;
|
|
lpDevI->dwDeviceFlags |= D3DDEV_FVF;
|
|
if (lpDevI->lpD3DExtendedCaps->dwFVFCaps & D3DFVFCAPS_DONOTSTRIPELEMENTS)
|
|
lpDevI->dwDeviceFlags |= D3DDEV_DONOTSTRIPELEMENTS;
|
|
|
|
DWORD value;
|
|
if ((lpDevI->dwDebugFlags & D3DDEBUG_DISABLEDP ||
|
|
lpDevI->dwDebugFlags & D3DDEBUG_DISABLEDP2 ||
|
|
(GetD3DRegValue(REG_DWORD, "DisableFVF", &value, 4) &&
|
|
value != 0)) &&
|
|
FVF_DRIVERSUPPORTED(lpDevI))
|
|
{
|
|
lpDevI->dwMaxTextureIndices = 1;
|
|
lpDevI->dwMaxTextureBlendStages = 1;
|
|
lpDevI->dwDeviceFlags &= ~D3DDEV_FVF;
|
|
lpDevI->dwDebugFlags |= D3DDEBUG_DISABLEFVF;
|
|
}
|
|
if ((GetD3DRegValue(REG_DWORD, "DisableStripFVF", &value, 4) &&
|
|
value != 0))
|
|
{
|
|
lpDevI->dwDeviceFlags |= D3DDEV_DONOTSTRIPELEMENTS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lpDevI->dwMaxTextureIndices = 1;
|
|
lpDevI->dwMaxTextureBlendStages = 1;
|
|
}
|
|
|
|
lpDevI->pfnDrawPrim = &DIRECT3DDEVICEI::DrawPrim;
|
|
lpDevI->pfnDrawIndexedPrim = &DIRECT3DDEVICEI::DrawIndexPrim;
|
|
#if DBG
|
|
lpDevI->dwCaller=0;
|
|
memset(lpDevI->dwPrimitiveType,0,sizeof(lpDevI->dwPrimitiveType));
|
|
memset(lpDevI->dwVertexType1,0,sizeof(lpDevI->dwVertexType1));
|
|
memset(lpDevI->dwVertexType2,0,sizeof(lpDevI->dwVertexType2));
|
|
#endif
|
|
return D3D_OK;
|
|
}
|
|
|
|
HRESULT D3DMallocBucket(LPDIRECT3DI lpD3DI, LPD3DBUCKET *lplpBucket)
|
|
{
|
|
if (lpD3DI->lpFreeList == NULL ){
|
|
lpD3DI->lpTextureManager->cleanup(); //free unused nodes it may have
|
|
if (lpD3DI->lpFreeList == NULL )
|
|
{
|
|
LPD3DBUCKET lpBufferList;
|
|
LPVOID lpBuffer;
|
|
int i;
|
|
*lplpBucket=NULL;
|
|
if (D3DMalloc(&lpBuffer, D3DBUCKETBUFFERSIZE*sizeof(D3DBUCKET)) != D3D_OK)
|
|
return DDERR_OUTOFMEMORY;
|
|
D3D_INFO(9, "D3DMallocBucket %d Bytes allocated for %d free Buckets",
|
|
D3DBUCKETBUFFERSIZE*sizeof(D3DBUCKET),D3DBUCKETBUFFERSIZE-1);
|
|
lpBufferList=(LPD3DBUCKET)lpBuffer;
|
|
for (i=0;i<D3DBUCKETBUFFERSIZE-2;i++)
|
|
lpBufferList[i].next=&lpBufferList[i+1];
|
|
lpBufferList[D3DBUCKETBUFFERSIZE-2].next=NULL;
|
|
lpD3DI->lpFreeList=(LPD3DBUCKET)lpBuffer; //new free list
|
|
lpBufferList[D3DBUCKETBUFFERSIZE-1].next=lpD3DI->lpBufferList;//add to lpBufferList
|
|
lpBufferList[D3DBUCKETBUFFERSIZE-1].lpBuffer=lpBuffer;
|
|
lpD3DI->lpBufferList=&lpBufferList[D3DBUCKETBUFFERSIZE-1];
|
|
}
|
|
}
|
|
*lplpBucket=lpD3DI->lpFreeList;
|
|
lpD3DI->lpFreeList=lpD3DI->lpFreeList->next;
|
|
return D3D_OK;
|
|
}
|
|
|
|
void D3DFreeBucket(LPDIRECT3DI lpD3DI, LPD3DBUCKET lpBucket)
|
|
{
|
|
lpBucket->next=lpD3DI->lpFreeList;
|
|
lpD3DI->lpFreeList=lpBucket;
|
|
}
|
|
|
|
/*
|
|
* Generic device part destroy
|
|
*/
|
|
void DIRECT3DDEVICEI::DestroyDevice()
|
|
{
|
|
LPDIRECT3DVIEWPORTI lpViewI;
|
|
LPDIRECTDRAWSURFACE lpDDS=NULL, lpDDSZ=NULL;
|
|
LPDIRECTDRAWSURFACE4 lpDDS_DDS4=NULL;
|
|
LPDIRECTDRAWPALETTE lpDDPal=NULL;
|
|
BOOL bIsDX3Device;
|
|
|
|
/* Clear flags that could prohibit cleanup */
|
|
this->dwHintFlags &= ~(D3DDEVBOOL_HINTFLAGS_INBEGIN_ALL | D3DDEVBOOL_HINTFLAGS_INSCENE);
|
|
|
|
/*
|
|
* Remove all viewports attached to this device.
|
|
*/
|
|
while ((lpViewI = CIRCLE_QUEUE_FIRST(&this->viewports)) &&
|
|
(lpViewI != (LPDIRECT3DVIEWPORTI)&this->viewports)) {
|
|
DeleteViewport((LPDIRECT3DVIEWPORT3)lpViewI);
|
|
}
|
|
|
|
/*
|
|
* free up all textures created by this object - this also frees up Textures
|
|
* We need to do this backwards because we cannot have a texture bound to
|
|
* stage i + 1 when there is a texture bound to stage i.
|
|
*/
|
|
for (int i = D3DHAL_TSS_MAXSTAGES - 1; i >= 0; --i)
|
|
{
|
|
if (lpD3DMappedTexI[i])
|
|
{
|
|
lpD3DMappedTexI[i]->Release();
|
|
lpD3DMappedTexI[i] = NULL;
|
|
lpD3DMappedBlock[i] = NULL;
|
|
}
|
|
}
|
|
// The following code can result in D3DHAL_TextureDestroy() being called.
|
|
// This BATCHES NEW INSTRUCTIONS in the instruction stream. So we must
|
|
// make sure that at this point, the device is still able to accept
|
|
// instructions.
|
|
while (LIST_FIRST(&this->texBlocks)) {
|
|
LPD3DI_TEXTUREBLOCK tBlock = LIST_FIRST(&this->texBlocks);
|
|
D3DI_RemoveTextureHandle(tBlock);
|
|
// Remove from device
|
|
LIST_DELETE(tBlock, devList);
|
|
// Remove from texture
|
|
LIST_DELETE(tBlock, list);
|
|
D3DFree(tBlock);
|
|
}
|
|
|
|
/*
|
|
* free up all execute buffers created by this object
|
|
*/
|
|
while (LIST_FIRST(&this->buffers)) {
|
|
LPDIRECT3DEXECUTEBUFFERI lpBufI =
|
|
LIST_FIRST(&this->buffers);
|
|
lpBufI->Release();
|
|
}
|
|
|
|
/*
|
|
* All materials associated with this device must be disassocited
|
|
*/
|
|
while (LIST_FIRST(&this->matBlocks)) {
|
|
LPD3DI_MATERIALBLOCK mBlock =
|
|
LIST_FIRST(&this->matBlocks);
|
|
D3DI_RemoveMaterialBlock(mBlock);
|
|
}
|
|
|
|
// In DX3, d3d device is aggregated and doesnt keep references to
|
|
// rendertarget surfaces, so they shouldnt be "released"
|
|
|
|
bIsDX3Device=(this->lpDDSTarget == (LPDIRECTDRAWSURFACE)(this->lpOwningIUnknown));
|
|
|
|
if(!bIsDX3Device)
|
|
{
|
|
// Hold pointers into ddraw object for release after driver is destroyed
|
|
lpDDSZ = this->lpDDSZBuffer;
|
|
lpDDPal = this->lpDDPalTarget;
|
|
if (this->dwVersion == 2)
|
|
lpDDS = this->lpDDSTarget;
|
|
else
|
|
lpDDS_DDS4 = this->lpDDSTarget_DDS4;
|
|
}
|
|
|
|
//Unhook so that DDRAW surfaces won't try to flush the dead device
|
|
if (this->lpDDSTarget)
|
|
UnHookD3DDeviceFromSurface(this,((LPDDRAWI_DDRAWSURFACE_INT) this->lpDDSTarget)->lpLcl);
|
|
if (this->lpDDSZBuffer)
|
|
UnHookD3DDeviceFromSurface(this,((LPDDRAWI_DDRAWSURFACE_INT) this->lpDDSZBuffer)->lpLcl);
|
|
|
|
if (pGeometryFuncs != &GeometryFuncsGuaranteed)
|
|
delete pGeometryFuncs;
|
|
|
|
D3DFE_Destroy(this);
|
|
|
|
if (this->lpDirect3DI)
|
|
unhookDeviceFromD3D();
|
|
|
|
if (this->wTriIndex)
|
|
D3DFree(this->wTriIndex);
|
|
|
|
// Free the rstates that was allocated
|
|
if(!(IS_HW_DEVICE(this) && IS_DP2HAL_DEVICE(this)))
|
|
{
|
|
delete rstates;
|
|
}
|
|
|
|
if (this->lpwDPBufferAlloced)
|
|
D3DFree(this->lpwDPBufferAlloced);
|
|
if (this->lpvVertexBatch)
|
|
D3DFree(this->lpvVertexBatch);
|
|
if (this->lpIndexBatch)
|
|
D3DFree(this->lpIndexBatch);
|
|
if (this->lpHWCounts)
|
|
D3DFree(this->lpHWCounts);
|
|
if (this->lpHWTris)
|
|
D3DFree(this->lpHWTris);
|
|
DeleteCriticalSection(&this->BeginEndCSect);
|
|
|
|
if (this->pHalProv != NULL)
|
|
{
|
|
this->pHalProv->Release();
|
|
}
|
|
if (this->hDllProv != NULL)
|
|
{
|
|
FreeLibrary(this->hDllProv);
|
|
}
|
|
|
|
/* Now that the class has been destroyed, we should be able to release
|
|
any DDraw object that might need to be released */
|
|
|
|
if(!bIsDX3Device) {
|
|
if (lpDDS)
|
|
lpDDS->Release();
|
|
if (lpDDSZ)
|
|
lpDDSZ->Release();
|
|
if (lpDDPal)
|
|
lpDDPal->Release();
|
|
if (lpDDS_DDS4)
|
|
lpDDS_DDS4->Release();
|
|
}
|
|
}
|
|
|
|
HRESULT DIRECT3DDEVICEI::hookDeviceToD3D(LPDIRECT3DI lpD3DI)
|
|
{
|
|
|
|
LIST_INSERT_ROOT(&lpD3DI->devices, this, list);
|
|
this->lpDirect3DI = lpD3DI;
|
|
|
|
lpD3DI->numDevs++;
|
|
|
|
return (D3D_OK);
|
|
}
|
|
|
|
HRESULT DIRECT3DDEVICEI::unhookDeviceFromD3D()
|
|
{
|
|
LIST_DELETE(this, list);
|
|
this->lpDirect3DI->numDevs--;
|
|
this->lpDirect3DI = NULL;
|
|
|
|
return (D3D_OK);
|
|
}
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::Initialize(LPDIRECT3D lpD3D, LPGUID lpGuid, LPD3DDEVICEDESC lpD3Ddd)
|
|
{
|
|
return DDERR_ALREADYINITIALIZED;
|
|
}
|
|
|
|
|
|
HRESULT HookD3DDeviceToSurface( LPDIRECT3DDEVICEI pd3ddev,
|
|
LPDDRAWI_DDRAWSURFACE_LCL lpLcl)
|
|
{
|
|
LPD3DBUCKET lpD3DDevIList;
|
|
LPDDRAWI_DDRAWSURFACE_MORE this_more;
|
|
// we only batch with DRAWPRIMITIVE aware HAL, so don't bother otherwise
|
|
if (!lpLcl) return DDERR_ALREADYINITIALIZED;
|
|
this_more = lpLcl->lpSurfMore;
|
|
for(lpD3DDevIList=(LPD3DBUCKET)this_more->lpD3DDevIList;
|
|
lpD3DDevIList;lpD3DDevIList=lpD3DDevIList->next) {
|
|
if ((LPDIRECT3DDEVICEI)lpD3DDevIList->lpD3DDevI==pd3ddev)
|
|
return DDERR_ALREADYINITIALIZED; // this device is already hooked to the surface
|
|
}
|
|
if (D3DMallocBucket(pd3ddev->lpDirect3DI,&lpD3DDevIList) != D3D_OK) {
|
|
D3D_ERR("HookD3DDeviceToSurface: Out of memory");
|
|
return DDERR_OUTOFMEMORY;
|
|
}
|
|
D3D_INFO(8,"adding lpd3ddev=%08lx to surface %08lx",pd3ddev,lpLcl);
|
|
//Link a node to the DDRAW surface
|
|
lpD3DDevIList->lpD3DDevI=(LPVOID)pd3ddev;
|
|
lpD3DDevIList->next=(LPD3DBUCKET)this_more->lpD3DDevIList;
|
|
this_more->lpD3DDevIList=lpD3DDevIList;
|
|
if (DDSCAPS_ZBUFFER & lpLcl->ddsCaps.dwCaps)
|
|
{
|
|
if (pd3ddev->dwVersion==1)
|
|
{
|
|
lpD3DDevIList->lplpDDSZBuffer=(LPDIRECTDRAWSURFACE*)&pd3ddev->lpDDSZBuffer_DDS4;
|
|
}
|
|
else
|
|
{
|
|
lpD3DDevIList->lplpDDSZBuffer=NULL;
|
|
}
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
|
|
void UnHookD3DDeviceFromSurface( LPDIRECT3DDEVICEI pd3ddev,
|
|
LPDDRAWI_DDRAWSURFACE_LCL lpLcl)
|
|
{
|
|
LPD3DBUCKET last,current,temp;
|
|
LPDDRAWI_DDRAWSURFACE_MORE this_more;
|
|
// we only batch with DRAWPRIMITIVE aware HAL, so don't bother otherwise
|
|
if (!lpLcl) return;
|
|
this_more = lpLcl->lpSurfMore;
|
|
|
|
last=NULL;
|
|
current=(LPD3DBUCKET)this_more->lpD3DDevIList;
|
|
while(current){
|
|
if ((LPDIRECT3DDEVICEI)current->lpD3DDevI==pd3ddev){
|
|
temp=current;
|
|
current=current->next;
|
|
if (last)
|
|
last->next=current;
|
|
else
|
|
this_more->lpD3DDevIList=current;
|
|
D3DFreeBucket(pd3ddev->lpDirect3DI,temp);
|
|
D3D_INFO(8,"removed lpd3ddev=%08lx from surface %08lx",pd3ddev,lpLcl);
|
|
return; // end of search as this is only one pd3ddev in the list
|
|
}
|
|
else{
|
|
last=current;
|
|
current=current->next;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
HRESULT D3DFlushStates(LPDIRECT3DDEVICEI lpDevI)
|
|
{
|
|
return lpDevI->FlushStates();
|
|
}
|
|
|
|
/*
|
|
* Create a device.
|
|
*
|
|
* NOTE: Radical modifications to support the aggregatable device
|
|
* interface (so devices can be queried off DirectDraw surfaces):
|
|
*
|
|
* 1) This call is no longer a member of the Direct3D device interface.
|
|
* It is now an API function exported from the Direct3D DLL. Its
|
|
* a hidden API function - only DirectDraw will ever invoke it.
|
|
*
|
|
* 2) This call is, in effect, the class factory for Direct3DDevice
|
|
* objects. This function will be invoked to create the aggregated
|
|
* device object hanging off the DirectDraw surface.
|
|
*
|
|
* NOTE: So the Direct3DDevice knows which DirectDraw surface is
|
|
* its rendering target this function is passed an interface pointer
|
|
* for that DirectDraw surface. I suspect this blows a nice big
|
|
* hole in the COM model as the DirectDraw surface is also the
|
|
* owning interface of the device and I don't think aggregated
|
|
* objects should know about thier owning interfaces. However, to
|
|
* make this thing work this is what we have to do.
|
|
*
|
|
* EXTRA BIG NOTE: Because of the above don't take a reference to
|
|
* the DirectDraw surface passed in. If you do you will get a circular
|
|
* reference and the bloody thing will never die. When aggregated
|
|
* the device interface's lifetime is entirely defined by the
|
|
* lifetime of its owning interface (the DirectDraw surface) so the
|
|
* DirectDraw surface can never go away before the texture.
|
|
*
|
|
* EXTRA EXTRA BIG NOTE: No device description is passed in any more.
|
|
* The only things that can get passed in are things that DirectDraw
|
|
* knows about (which does not include stuff like dither and color
|
|
* model). Therefore, any input parameters must come in via a
|
|
* different IID for the device. The data returned by the device
|
|
* description must now be retrieved by another call.
|
|
*/
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DCreateDevice"
|
|
|
|
HRESULT WINAPI Direct3DCreateDevice(REFCLSID riid,
|
|
LPUNKNOWN lpDirect3D,
|
|
LPDIRECTDRAWSURFACE lpDDSTarget,
|
|
LPUNKNOWN* lplpD3DDevice,
|
|
IUnknown* pUnkOuter,
|
|
DWORD dwVersion)
|
|
{
|
|
LPDIRECT3DI lpD3DI;
|
|
LPDIRECT3DDEVICEI pd3ddev;
|
|
D3DCOLORMODEL cm = D3DCOLOR_MONO;
|
|
HRESULT ret = D3D_OK;
|
|
HKEY hKey = (HKEY) NULL;
|
|
bool bDisableDP = false;
|
|
bool bDisableST = false;
|
|
bool bDisableDP2 = false;
|
|
#if _D3D_FORCEDOUBLE
|
|
bool bForceDouble = true;
|
|
#endif //_D3D_FORCEDOUBLE
|
|
/* No need to validate params as they are passed to us by DirectDraw */
|
|
|
|
/* CreateDevice member of IDirect3D2 will cause this function to be called
|
|
* from within Direct3D. The parameters from the application level must be
|
|
* validated. Need a way to validate the surface pointer from outside DDraw.
|
|
*/
|
|
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
TRY
|
|
{
|
|
if( ! VALID_PTR_PTR( lplpD3DDevice) )
|
|
{
|
|
D3D_ERR( "Invalid ptr to device pointer in Direct3DCreateDevice" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
if(!IsValidD3DDeviceGuid(riid)) {
|
|
D3D_ERR( "Unrecognized Device GUID!");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
D3D_ERR( "Exception encountered validating parameters in Direct3DCreateDevice" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
*lplpD3DDevice = NULL;
|
|
|
|
// Might be safer to use dynamic_cast<> if RTTI is enabled
|
|
lpD3DI = reinterpret_cast<CDirect3DUnk*>(lpDirect3D)->pD3DI;
|
|
|
|
#ifndef _X86_
|
|
if(IsEqualIID(riid, IID_IDirect3DRampDevice)) {
|
|
// quietly fail if trying to create a RampDevice on a non-x86 platform
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
#endif
|
|
|
|
if((dwVersion>=3) && IsEqualIID(riid, IID_IDirect3DRampDevice)) {
|
|
// Ramp not available in Device3. No more old-style texture handles.
|
|
D3D_ERR( "RAMP Device is incompatible with IDirect3DDevice3 and so cannot be created from IDirect3D3");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
if (IsEqualIID(riid, IID_IDirect3DMMXDevice) && !isMMXprocessor()) {
|
|
D3D_ERR("Can't create MMX Device on non-MMX machine");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, RESPATH_D3D, &hKey) )
|
|
{
|
|
DWORD dwType;
|
|
DWORD dwValue;
|
|
DWORD dwSize = 4;
|
|
#ifdef WIN95
|
|
if ( ERROR_SUCCESS == RegQueryValueEx( hKey, "DisableDP", NULL, &dwType, (LPBYTE) &dwValue, &dwSize) &&
|
|
dwType == REG_DWORD &&
|
|
dwValue != 0)
|
|
{
|
|
bDisableDP = true;
|
|
bDisableDP2 = true;
|
|
}
|
|
#endif //WIN95
|
|
if ( ERROR_SUCCESS == RegQueryValueEx( hKey, "DisableST", NULL, &dwType, (LPBYTE) &dwValue, &dwSize) &&
|
|
dwType == REG_DWORD &&
|
|
dwValue != 0)
|
|
{
|
|
bDisableST = true;
|
|
}
|
|
#ifdef WIN95
|
|
if ( ERROR_SUCCESS == RegQueryValueEx( hKey, "DisableDP2", NULL, &dwType, (LPBYTE) &dwValue, &dwSize) &&
|
|
dwType == REG_DWORD &&
|
|
dwValue != 0)
|
|
{
|
|
bDisableDP2 = true;
|
|
}
|
|
#endif //WIN95
|
|
|
|
D3D_INFO(2,"EnableDP2: %d",!bDisableDP2);
|
|
#if _D3D_FORCEDOUBLE
|
|
if ( ERROR_SUCCESS == RegQueryValueEx( hKey, "ForceDouble", NULL, &dwType, (LPBYTE) &dwValue, &dwSize) &&
|
|
dwType == REG_DWORD &&
|
|
dwValue == 0)
|
|
{
|
|
bForceDouble = false;
|
|
}
|
|
D3D_INFO(2,"ForceDouble: %d",bForceDouble);
|
|
#endif //_D3D_FORCEDOUBLE
|
|
RegCloseKey( hKey );
|
|
}
|
|
LPD3DHAL_GLOBALDRIVERDATA lpD3DHALGlobalDriverData=((LPDDRAWI_DIRECTDRAW_INT)lpD3DI->lpDD)->lpLcl->lpGbl->lpD3DGlobalDriverData;
|
|
#ifdef WIN95
|
|
/* Test for presence of CB HAL */
|
|
if (IsEqualIID(riid, IID_IDirect3DHALDevice) )
|
|
{
|
|
/* Test for presence of DP2 DDI */
|
|
if ((lpD3DHALGlobalDriverData)
|
|
&& (lpD3DHALGlobalDriverData->hwCaps.dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX)
|
|
)
|
|
{
|
|
pd3ddev = static_cast<LPDIRECT3DDEVICEI>(new CDirect3DDeviceIDP2());
|
|
if (pd3ddev) pd3ddev->deviceType = D3DDEVTYPE_DX7HAL;
|
|
}
|
|
else if ((!bDisableDP2) &&
|
|
((LPDDRAWI_DIRECTDRAW_INT)lpD3DI->lpDD)->lpLcl->lpGbl->lpD3DHALCallbacks3 &&
|
|
((LPD3DHAL_CALLBACKS3)((LPDDRAWI_DIRECTDRAW_INT)lpD3DI->lpDD)->lpLcl->lpGbl->lpD3DHALCallbacks3)->DrawPrimitives2)
|
|
{
|
|
pd3ddev = static_cast<LPDIRECT3DDEVICEI>(new CDirect3DDeviceIDP2());
|
|
}
|
|
/* Test for presence DP HAL */
|
|
else if ((!bDisableDP) &&
|
|
((LPDDRAWI_DIRECTDRAW_INT)lpD3DI->lpDD)->lpLcl->lpGbl->lpD3DHALCallbacks2 &&
|
|
((LPD3DHAL_CALLBACKS2)((LPDDRAWI_DIRECTDRAW_INT)lpD3DI->lpDD)->lpLcl->lpGbl->lpD3DHALCallbacks2)->DrawOnePrimitive)
|
|
{
|
|
pd3ddev = static_cast<LPDIRECT3DDEVICEI>(new CDirect3DDeviceIDP());
|
|
}
|
|
else
|
|
{
|
|
pd3ddev = static_cast<LPDIRECT3DDEVICEI>(new CDirect3DDeviceIHW());
|
|
}
|
|
}
|
|
else // all software rasterizers are DP-enabled
|
|
#endif // WIN95
|
|
if (!bDisableDP2)
|
|
{
|
|
if ((lpD3DHALGlobalDriverData)
|
|
&& (IsEqualIID(riid, IID_IDirect3DHALDevice) )
|
|
&& (lpD3DHALGlobalDriverData->hwCaps.dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX)
|
|
)
|
|
{
|
|
pd3ddev = static_cast<LPDIRECT3DDEVICEI>(new CDirect3DDeviceIDP2());
|
|
if (pd3ddev) pd3ddev->deviceType = D3DDEVTYPE_DX7HAL;
|
|
}
|
|
else
|
|
{
|
|
pd3ddev = static_cast<LPDIRECT3DDEVICEI>(new CDirect3DDeviceIDP2());
|
|
}
|
|
}
|
|
else if (!bDisableDP)
|
|
pd3ddev = static_cast<LPDIRECT3DDEVICEI>(new CDirect3DDeviceIDP());
|
|
else
|
|
pd3ddev = static_cast<LPDIRECT3DDEVICEI>(new CDirect3DDeviceIHW());
|
|
|
|
if (!pd3ddev) {
|
|
D3D_ERR("Failed to allocate space for D3DDevice. Quitting.");
|
|
return (DDERR_OUTOFMEMORY);
|
|
}
|
|
|
|
// If we have lost managed textures, we need to cleanup
|
|
// since CheckSurfaces() would fail which would cause
|
|
// FlushStates() to fail, which would result in the
|
|
// current batch being abandoned (along with any device initialization)
|
|
if(lpD3DI->lpTextureManager->CheckIfLost())
|
|
{
|
|
D3D_INFO(2, "Found lost managed textures. Evicting...");
|
|
lpD3DI->lpTextureManager->EvictTextures();
|
|
}
|
|
|
|
if (bDisableDP)
|
|
pd3ddev->dwDebugFlags |= D3DDEBUG_DISABLEDP;
|
|
if (bDisableDP2)
|
|
pd3ddev->dwDebugFlags |= D3DDEBUG_DISABLEDP2;
|
|
|
|
ret = pd3ddev->Init(riid, lpD3DI, lpDDSTarget, pUnkOuter, lplpD3DDevice, dwVersion);
|
|
if (ret!=D3D_OK)
|
|
{
|
|
delete pd3ddev;
|
|
D3D_ERR("Failed to intilialize D3DDevice");
|
|
return ret;
|
|
}
|
|
|
|
if (bDisableST)
|
|
pd3ddev->dwHintFlags |= D3DDEVBOOL_HINTFLAGS_MULTITHREADED;
|
|
|
|
#ifdef _X86_
|
|
if (((LPDDRAWI_DIRECTDRAW_INT)lpD3DI->lpDD)->lpLcl->dwLocalFlags & DDRAWILCL_FPUSETUP &&
|
|
IS_DP2HAL_DEVICE(pd3ddev))
|
|
{
|
|
WORD wSave, wTemp;
|
|
__asm {
|
|
fstcw wSave
|
|
mov ax, wSave
|
|
and ax, not 300h ;; single mode
|
|
or ax, 3fh ;; disable all exceptions
|
|
and ax, not 0C00h ;; round to nearest mode
|
|
mov wTemp, ax
|
|
fldcw wTemp
|
|
}
|
|
}
|
|
#if _D3D_FORCEDOUBLE
|
|
if (bForceDouble && (pd3ddev->deviceType <= D3DDEVTYPE_DPHAL))
|
|
{
|
|
pd3ddev->dwDebugFlags |= D3DDEBUG_FORCEDOUBLE;
|
|
}
|
|
else
|
|
{
|
|
pd3ddev->dwDebugFlags &= ~D3DDEBUG_FORCEDOUBLE;
|
|
}
|
|
#endif //_D3D_FORCEDOUBLE
|
|
#endif
|
|
|
|
return (ret);
|
|
}
|
|
|
|
HRESULT DIRECT3DDEVICEI::Init(REFCLSID riid, LPDIRECT3DI lpD3DI, LPDIRECTDRAWSURFACE lpDDS,
|
|
IUnknown* pUnkOuter, LPUNKNOWN* lplpD3DDevice, DWORD dwVersion)
|
|
{
|
|
DDSCAPS ddscaps;
|
|
DDSURFACEDESC ddsd;
|
|
HRESULT ret, ddrval;
|
|
LPDIRECTDRAWSURFACE lpDDSZ=NULL;
|
|
LPDIRECTDRAWPALETTE lpDDPal=NULL;
|
|
LPGUID pGuid;
|
|
BOOL bIsDX3Device;
|
|
DDSCAPS surfCaps;
|
|
|
|
this->dwFVFLastIn = this->dwFVFLastOut = 0;
|
|
this->mDevUnk.refCnt = 1;
|
|
this->dwVersion = dwVersion;
|
|
this->mDevUnk.pDevI = this;
|
|
pD3DMappedTexI = (LPVOID*)(this->lpD3DMappedTexI);
|
|
pfnFlushStates = D3DFlushStates;
|
|
this->dwFEFlags |= D3DFE_TSSINDEX_DIRTY;
|
|
|
|
/* Single threaded or Multi threaded app ? */
|
|
if (((LPDDRAWI_DIRECTDRAW_INT)lpD3DI->lpDD)->lpLcl->dwLocalFlags & DDRAWILCL_MULTITHREADED)
|
|
this->dwHintFlags |= D3DDEVBOOL_HINTFLAGS_MULTITHREADED;
|
|
|
|
/*
|
|
* Are we really being aggregated?
|
|
*/
|
|
|
|
bIsDX3Device=(pUnkOuter!=NULL);
|
|
|
|
if (bIsDX3Device)
|
|
{
|
|
/*
|
|
* Yup - we are being aggregated. Store the supplied
|
|
* IUnknown so we can punt to that.
|
|
* NOTE: We explicitly DO NOT AddRef here.
|
|
*/
|
|
this->lpOwningIUnknown = pUnkOuter;
|
|
DDASSERT(dwVersion==1);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Nope - but we pretend we are anyway by storing our
|
|
* own IUnknown as the parent IUnknown. This makes the
|
|
* code much neater.
|
|
*/
|
|
this->lpOwningIUnknown = (LPUNKNOWN)&this->mDevUnk;
|
|
}
|
|
|
|
// create the begin/end critical section
|
|
InitializeCriticalSection(&this->BeginEndCSect);
|
|
|
|
/*
|
|
* Initialise textures
|
|
*/
|
|
LIST_INITIALIZE(&this->texBlocks);
|
|
|
|
/*
|
|
* Initialise buffers
|
|
*/
|
|
LIST_INITIALIZE(&this->buffers);
|
|
|
|
/*
|
|
* Initialise viewports
|
|
*/
|
|
CIRCLE_QUEUE_INITIALIZE(&this->viewports, DIRECT3DVIEWPORTI);
|
|
|
|
this->lpCurrentViewport = NULL;
|
|
this->v_id = 0;
|
|
|
|
/*
|
|
* Initialise materials
|
|
*/
|
|
LIST_INITIALIZE(&this->matBlocks);
|
|
|
|
this->lpvVertexBatch = this->lpIndexBatch = NULL;
|
|
this->dwHWNumCounts = 0;
|
|
this->dwHWOffset = 0;
|
|
this->dwHWTriIndex = 0;
|
|
this->lpTextureBatched = NULL;
|
|
this->dwVertexBase = 0;
|
|
pGeometryFuncs = &GeometryFuncsGuaranteed;
|
|
|
|
/*-----------------------------------------------------------------------------------------
|
|
* Up till now we have done the easy part of the initialization. This is the stuff that
|
|
* cannot fail. It initializes the object so that the destructor can be safely called if
|
|
* any of the further initialization does not succeed.
|
|
*---------------------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
* Ensure the riid is one we understand.
|
|
*
|
|
* Query the registry.
|
|
*/
|
|
pGuid = (GUID *)&riid;
|
|
|
|
#if DBG
|
|
if (IsEqualIID(*pGuid, IID_IDirect3DRampDevice))
|
|
{
|
|
D3D_INFO(1, "======================= Ramp device selected");
|
|
}
|
|
if (IsEqualIID(*pGuid, IID_IDirect3DRGBDevice))
|
|
{
|
|
D3D_INFO(1, "======================= RGB device selected");
|
|
}
|
|
if (IsEqualIID(*pGuid, IID_IDirect3DMMXDevice))
|
|
{
|
|
D3D_INFO(1, "======================= RGB(MMX) device selected");
|
|
}
|
|
if (IsEqualIID(*pGuid, IID_IDirect3DHALDevice))
|
|
{
|
|
D3D_INFO(1, "======================= HAL device selected");
|
|
}
|
|
if (IsEqualIID(*pGuid, IID_IDirect3DRefDevice))
|
|
{
|
|
D3D_INFO(1, "======================= Reference Rasterizer device selected");
|
|
}
|
|
if (IsEqualIID(*pGuid, IID_IDirect3DNullDevice))
|
|
{
|
|
D3D_INFO(1, "======================= Null device selected");
|
|
}
|
|
if (IsEqualIID(*pGuid, IID_IDirect3DNewRGBDevice))
|
|
{
|
|
D3D_INFO(1, "======================= New RGB device selected");
|
|
}
|
|
D3D_INFO(1,"with HAL deviceType=%d",deviceType);
|
|
#endif
|
|
|
|
// set up flag to use MMX when requested RGB
|
|
BOOL bUseMMXAsRGBDevice = FALSE;
|
|
if (IsEqualIID(*pGuid, IID_IDirect3DRGBDevice) && isMMXprocessor())
|
|
{
|
|
bUseMMXAsRGBDevice = TRUE;
|
|
// read reg key to override use of MMX for RGB
|
|
HKEY hKey = (HKEY) NULL;
|
|
if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, RESPATH, &hKey) )
|
|
{
|
|
DWORD dwType;
|
|
DWORD dwValue;
|
|
DWORD dwSize = 4;
|
|
|
|
if ( ERROR_SUCCESS == RegQueryValueEx( hKey, "UseMMXForRGB", NULL, &dwType, (LPBYTE) &dwValue, &dwSize) &&
|
|
dwType == REG_DWORD &&
|
|
dwValue == 0)
|
|
{
|
|
bUseMMXAsRGBDevice = FALSE;
|
|
}
|
|
RegCloseKey( hKey );
|
|
}
|
|
if (bUseMMXAsRGBDevice)
|
|
{
|
|
D3D_INFO(1, " using MMX in RGB device");
|
|
}
|
|
}
|
|
|
|
BOOL bIsRamp = FALSE;
|
|
if (IsEqualIID(*pGuid, IID_IDirect3DRampDevice))
|
|
{
|
|
bIsRamp = TRUE;
|
|
}
|
|
|
|
if (IsEqualIID(*pGuid, IID_IDirect3DRGBDevice) &&
|
|
isMMXprocessor())
|
|
{
|
|
// Check for whether this app is one of the Intel ones
|
|
// that want the MMX rasterizer
|
|
LPDDRAWI_DIRECTDRAW_LCL lpDDLcl = ((LPDDRAWI_DIRECTDRAW_INT)lpD3DI->lpDD)->lpLcl;
|
|
|
|
// 0x4 corresponds to the "Intel app that wants MMX"
|
|
// flag defined in ddrawpr.h
|
|
if ( lpDDLcl->dwAppHackFlags & 0x4 )
|
|
{
|
|
pGuid = (GUID *)&IID_IDirect3DMMXDevice;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check if the 3D cap is set on the surface.
|
|
*/
|
|
memset(&ddsd, 0, sizeof ddsd);
|
|
ddsd.dwSize = sizeof ddsd;
|
|
ddrval = lpDDS->GetSurfaceDesc(&ddsd);
|
|
if (ddrval != DD_OK) {
|
|
D3D_ERR("Failed to get surface description of device's surface.");
|
|
return (ddrval);
|
|
}
|
|
|
|
if (!(ddsd.ddsCaps.dwCaps & DDSCAPS_3DDEVICE)) {
|
|
D3D_ERR("**** The DDSCAPS_3DDEVICE is not set on this surface.");
|
|
D3D_ERR("**** You need to add DDSCAPS_3DDEVICE to ddsCaps.dwCaps");
|
|
D3D_ERR("**** when creating the surface.");
|
|
return (DDERR_INVALIDCAPS);
|
|
}
|
|
|
|
if (ddsd.ddsCaps.dwCaps & DDSCAPS_ZBUFFER) {
|
|
D3D_ERR("**** DDSCAPS_ZBUFFER is set on this surface.");
|
|
D3D_ERR("**** Rendering into Z buffer surfaces is not");
|
|
D3D_ERR("**** currently supported by Direct3D.");
|
|
return (DDERR_INVALIDCAPS);
|
|
}
|
|
|
|
if (ddsd.dwWidth > 2048 || ddsd.dwHeight > 2048)
|
|
{
|
|
D3D_ERR("**** Surface too large - must be <= 2048 in width & height.");
|
|
return (DDERR_INVALIDOBJECT);
|
|
}
|
|
|
|
/* Check for palette... */
|
|
ret = lpDDS->GetPalette(&lpDDPal);
|
|
if ((ret != DD_OK) && (ret != DDERR_NOPALETTEATTACHED))
|
|
{
|
|
/*
|
|
* NOTE: Again, not an error (yet) if there is no palette attached.
|
|
* But if there is palette and we can't get at it for some reason
|
|
* - fail.
|
|
*/
|
|
D3D_ERR("Supplied DirectDraw Palette is invalid - can't create device");
|
|
return (DDERR_INVALIDPARAMS);
|
|
}
|
|
|
|
/*
|
|
* We're going to check now whether we should have got a palette.
|
|
*/
|
|
if (ret == DDERR_NOPALETTEATTACHED) {
|
|
if (ddsd.ddpfPixelFormat.dwRGBBitCount < 16) {
|
|
D3D_ERR("No palette supplied for palettized surface - can't create device");
|
|
return (DDERR_NOPALETTEATTACHED);
|
|
}
|
|
}
|
|
|
|
// For DX3, we must not keep references to Palette and ZBuffer to avoid
|
|
// circular references in the aggregation model. But for DX5+, we want
|
|
// to keep references to both to ensure they dont disappear.
|
|
|
|
if(bIsDX3Device && (lpDDPal != NULL))
|
|
lpDDPal->Release(); // release the reference GetPalette created
|
|
this->lpDDPalTarget = lpDDPal;
|
|
|
|
// Check for ZBuffer
|
|
|
|
memset(&surfCaps, 0, sizeof(DDSCAPS));
|
|
surfCaps.dwCaps = DDSCAPS_ZBUFFER;
|
|
|
|
if (FAILED(ret = lpDDS->GetAttachedSurface(&surfCaps, &lpDDSZ))) {
|
|
if (ret != DDERR_NOTFOUND) {
|
|
D3D_ERR("Failed GetAttachedSurface for ZBuffer");
|
|
goto handle_err;
|
|
}
|
|
D3D_INFO(2, "No zbuffer is attached to rendertarget surface (which is OK)");
|
|
}
|
|
|
|
if(bIsDX3Device && (lpDDSZ != NULL))
|
|
lpDDSZ->Release(); // release the reference GetAttachedSurface created
|
|
this->lpDDSZBuffer = lpDDSZ;
|
|
|
|
this->guid = *pGuid;
|
|
|
|
// Try to get a HAL provider for this driver (may need to use MMX guid if
|
|
// using MMX for RGB requested device)
|
|
ret = GetSwHalProvider(
|
|
bUseMMXAsRGBDevice ? IID_IDirect3DMMXAsRGBDevice : riid,
|
|
&this->pHalProv, &this->hDllProv);
|
|
|
|
if (ret == S_OK)
|
|
{
|
|
// Got a software provider.
|
|
}
|
|
else if (ret == E_NOINTERFACE &&
|
|
((ret = GetHwHalProvider(riid, &this->pHalProv,
|
|
&this->hDllProv,
|
|
((LPDDRAWI_DIRECTDRAW_INT)lpD3DI->lpDD)->lpLcl->lpGbl)) == S_OK))
|
|
{
|
|
// Got a hardware provider.
|
|
}
|
|
else
|
|
{
|
|
if(IsEqualIID(riid, IID_IDirect3DHALDevice)) {
|
|
D3D_ERR("Requested HAL Device non-existent or invalid");
|
|
} else {
|
|
D3D_ERR("Unable to get D3D Device provider for requested GUID");
|
|
}
|
|
goto handle_err;
|
|
}
|
|
|
|
{
|
|
// Initialize test HAL provider to drop HAL calls (sort of a Null device)
|
|
//
|
|
DWORD value = 0;
|
|
if (GetD3DRegValue(REG_DWORD, "DisableRendering", &value, sizeof(DWORD)) &&
|
|
value != 0)
|
|
{
|
|
ret = GetTestHalProvider(
|
|
riid, ((LPDDRAWI_DIRECTDRAW_INT)lpD3DI->lpDD)->lpLcl->lpGbl,
|
|
&this->pHalProv, this->pHalProv, 0);
|
|
if (ret != D3D_OK)
|
|
{
|
|
D3D_ERR("Unable to set up 'DisableRendering' mode");
|
|
goto handle_err;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Initialise general DEVICEI information.
|
|
if ((ret = InitDeviceI(this, lpD3DI)) != D3D_OK)
|
|
{
|
|
D3D_ERR("Failed to initialise device");
|
|
goto handle_err;
|
|
}
|
|
|
|
// Check the surface and device to see if they're compatible
|
|
if (FAILED(ret = checkDeviceSurface(lpDDS,lpDDSZ,pGuid))) {
|
|
D3D_ERR("Device and surface aren't compatible");
|
|
goto handle_err;
|
|
}
|
|
|
|
// Create front-end support structures.
|
|
// ATTENTION - We probably want to avoid doing this if the driver
|
|
// does its own front end. Software fallbacks complicate the issue,
|
|
// though.
|
|
ret = D3DFE_Create(this, lpD3DI->lpDD, lpDDS, lpDDSZ, lpDDPal);
|
|
if (ret != D3D_OK)
|
|
{
|
|
D3D_ERR("Failed to create front-end data-structures.");
|
|
goto handle_err;
|
|
}
|
|
|
|
// Figure out place for rstates
|
|
if (IS_HW_DEVICE(this) && IS_DP2HAL_DEVICE(this))
|
|
{
|
|
// In case of HW DP2 HAL we reuse the kernel allocated
|
|
// memory for RStates since we need the driver to update
|
|
// it
|
|
rstates = (LPDWORD)lpwDPBuffer;
|
|
}
|
|
else
|
|
{
|
|
// In all other cases we simply allocate memory for rstates
|
|
rstates = new DWORD[D3DHAL_MAX_RSTATES];
|
|
}
|
|
D3DFE_PROCESSVERTICES::lpdwRStates = this->rstates;
|
|
|
|
// Check if we have a processor specific implementation available
|
|
// only use if DisablePSGP is not in registry or set to zero
|
|
DWORD value;
|
|
if (!GetD3DRegValue(REG_DWORD, "DisablePSGP", &value, sizeof(DWORD)))
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
#ifdef _X86_
|
|
extern HRESULT D3DAPI pii_FEContextCreate(DWORD dwFlags, LPD3DFE_PVFUNCS *lpLeafFuncs);
|
|
if (pfnFEContextCreate == pii_FEContextCreate)
|
|
{
|
|
// here if this is PentiumII PSGP
|
|
|
|
// regkey disable for PII PSGP - default is ENABLED
|
|
DWORD dwValue2; // disable if this is TRUE
|
|
if (!GetD3DRegValue(REG_DWORD, "DisablePIIPSGP", &dwValue2, sizeof(DWORD)))
|
|
{
|
|
dwValue2 = 0;
|
|
}
|
|
else
|
|
{
|
|
D3D_INFO(2, "DisablePIIPSGP %d",dwValue2);
|
|
}
|
|
|
|
// do disable
|
|
if ( dwValue2 )
|
|
{
|
|
pfnFEContextCreate = NULL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (pfnFEContextCreate && ( value == 0) && (!bIsRamp) )
|
|
{
|
|
D3D_INFO(2, "PSGP enabled for device");
|
|
// Ask the PV implementation to create a device specific "context"
|
|
LPD3DFE_PVFUNCS pOptGeoFuncs = pGeometryFuncs;
|
|
ret = pfnFEContextCreate(dwDeviceFlags, &pOptGeoFuncs);
|
|
if ((ret == D3D_OK) && pOptGeoFuncs)
|
|
{
|
|
D3D_INFO(2, "using PSGP");
|
|
pGeometryFuncs = pOptGeoFuncs;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* put this device in the list of those owned by the Direct3D object
|
|
*/
|
|
ret = hookDeviceToD3D(lpD3DI);
|
|
if (ret != D3D_OK)
|
|
{
|
|
D3D_ERR("Failed to associate device with Direct3D");
|
|
goto handle_err;
|
|
}
|
|
{
|
|
if(lpD3DHALGlobalDriverData->hwCaps.dwMaxVertexCount == 0)
|
|
{
|
|
lpD3DHALGlobalDriverData->hwCaps.dwMaxVertexCount = __INIT_VERTEX_NUMBER;
|
|
}
|
|
if (TLVbuf.Grow(this, (__INIT_VERTEX_NUMBER*2)*sizeof(D3DTLVERTEX)) != DD_OK)
|
|
{
|
|
D3D_ERR( "Out of memory in DeviceCreate (TLVbuf)" );
|
|
ret = DDERR_OUTOFMEMORY;
|
|
goto handle_err;
|
|
}
|
|
if (HVbuf.Grow((__INIT_VERTEX_NUMBER*2)*sizeof(D3DFE_CLIPCODE)) != DD_OK)
|
|
{
|
|
D3D_ERR( "Out of memory in DeviceCreate (HVBuf)" );
|
|
ret = DDERR_OUTOFMEMORY;
|
|
goto handle_err;
|
|
}
|
|
ret = this->ClipperState.clipBuf.Grow
|
|
(this, MAX_CLIP_VERTICES*__MAX_VERTEX_SIZE);
|
|
if (ret != D3D_OK)
|
|
{
|
|
D3D_ERR( "Out of memory in DeviceCreate (ClipBuf)" );
|
|
ret = DDERR_OUTOFMEMORY;
|
|
goto handle_err;
|
|
}
|
|
ret = this->ClipperState.clipBufPrim.Grow
|
|
(this, MAX_CLIP_TRIANGLES*sizeof(D3DTRIANGLE));
|
|
if (ret != D3D_OK)
|
|
{
|
|
D3D_ERR( "Out of memory in DeviceCreate (ClipBufPrim)" );
|
|
ret = DDERR_OUTOFMEMORY;
|
|
goto handle_err;
|
|
}
|
|
|
|
}
|
|
/*
|
|
* IDirect3DDevice2 specific initialization
|
|
*/
|
|
if (D3DMalloc((void**)&this->wTriIndex, dwD3DTriBatchSize*4*sizeof(WORD)) != DD_OK) {
|
|
D3D_ERR( "Out of memory in DeviceCreate (wTriIndex)" );
|
|
ret = DDERR_OUTOFMEMORY;
|
|
goto handle_err;
|
|
}
|
|
|
|
if (D3DMalloc((void**)&this->lpHWCounts, dwHWBufferSize*sizeof(D3DI_HWCOUNTS)/32 ) != DD_OK)
|
|
{
|
|
D3D_ERR( "Out of memory in DeviceCreate (HWCounts)" );
|
|
ret = DDERR_OUTOFMEMORY;
|
|
goto handle_err;
|
|
}
|
|
memset(this->lpHWCounts, 0, sizeof(D3DI_HWCOUNTS) );
|
|
this->lpHWVertices = (LPD3DTLVERTEX) this->lpwDPBuffer;
|
|
if (D3DMalloc((void**)&this->lpHWTris, dwHWMaxTris*sizeof(D3DTRIANGLE) ) != DD_OK)
|
|
{
|
|
D3D_ERR( "Out of memory in DeviceCreate (HWVertices)" );
|
|
ret = DDERR_OUTOFMEMORY;
|
|
goto handle_err;
|
|
}
|
|
|
|
if (DDERR_OUTOFMEMORY == (ret=HookD3DDeviceToSurface(this, ((LPDDRAWI_DDRAWSURFACE_INT) lpDDS)->lpLcl)))
|
|
goto handle_err;
|
|
if (lpDDSZ && (DDERR_OUTOFMEMORY == (ret=HookD3DDeviceToSurface(this, ((LPDDRAWI_DDRAWSURFACE_INT) lpDDSZ)->lpLcl))))
|
|
{
|
|
UnHookD3DDeviceFromSurface(this, ((LPDDRAWI_DDRAWSURFACE_INT) lpDDS)->lpLcl);
|
|
goto handle_err;
|
|
}
|
|
|
|
/* Set the initial render state of the device */
|
|
if (FAILED(ret = stateInitialize(lpDDSZ!=NULL))) {
|
|
D3D_ERR("Failed to set initial state for device");
|
|
goto handle_err;
|
|
}
|
|
|
|
/*
|
|
* NOTE: We don't return the actual device interface. We
|
|
* return the device's special IUnknown interface which
|
|
* will be used in a QueryInterface to get the actual
|
|
* Direct3D device interface.
|
|
*/
|
|
*lplpD3DDevice = static_cast<LPUNKNOWN>(&(this->mDevUnk));
|
|
|
|
|
|
return (D3D_OK);
|
|
handle_err:
|
|
// might be able to simplify if this fn and not D3DFE_Create sets this->lpDDSZBuffer/this->lpDDPalette
|
|
if(lpDDSZ!=NULL) {
|
|
if(!bIsDX3Device) {
|
|
lpDDSZ->Release(); // release the reference GetAttachedSurface created
|
|
}
|
|
this->lpDDSZBuffer=NULL; // make sure the device destructor doesn't try to re-release this
|
|
// I'd let device destructor handle this, but errors can occur before D3DFE_Create is called
|
|
}
|
|
|
|
if(lpDDPal!=NULL) {
|
|
if(!bIsDX3Device) {
|
|
lpDDPal->Release(); // release the reference GetPalette created
|
|
}
|
|
this->lpDDPalTarget=NULL; // make sure the device destructor doesn't try to re-release this
|
|
}
|
|
|
|
D3D_ERR("Device creation failed!!");
|
|
return(ret);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DIRECT3DDEVICEI::GetStats"
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::GetStats(LPD3DSTATS lpStats)
|
|
{
|
|
// not implemented for Device3 (and newer) interfaces
|
|
if (this->dwVersion >= 3)
|
|
{
|
|
D3D_INFO(3, "GetStats not implemented for Device3 interface");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
D3DSTATS stats;
|
|
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
/*
|
|
* validate parms
|
|
*/
|
|
TRY
|
|
{
|
|
if (!VALID_D3DSTATS_PTR(lpStats)) {
|
|
D3D_ERR( "Invalid D3DSTATS pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
D3D_ERR( "Exception encountered validating parameters in GetStats" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
stats = this->D3DStats;
|
|
|
|
*lpStats = stats;
|
|
lpStats->dwSize = sizeof(D3DSTATS);
|
|
|
|
return DD_OK;
|
|
}
|
|
|
|
/**
|
|
** Viewport Management
|
|
**/
|
|
HRESULT DIRECT3DDEVICEI::hookViewportToDevice(LPDIRECT3DVIEWPORTI lpD3DView)
|
|
{
|
|
|
|
CIRCLE_QUEUE_INSERT_END(&this->viewports, DIRECT3DVIEWPORTI,
|
|
lpD3DView, vw_list);
|
|
lpD3DView->lpDevI = this;
|
|
|
|
this->numViewports++;
|
|
|
|
return (D3D_OK);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DIRECT3DDEVICEI::AddViewport"
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::AddViewport(LPDIRECT3DVIEWPORT lpD3DView)
|
|
{
|
|
return AddViewport((LPDIRECT3DVIEWPORT3)lpD3DView);
|
|
}
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::AddViewport(LPDIRECT3DVIEWPORT2 lpD3DView)
|
|
{
|
|
return AddViewport((LPDIRECT3DVIEWPORT3)lpD3DView);
|
|
}
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::AddViewport(LPDIRECT3DVIEWPORT3 lpD3DView)
|
|
{
|
|
LPDIRECT3DVIEWPORTI lpViewI;
|
|
HRESULT err = D3D_OK;
|
|
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
lpViewI = (LPDIRECT3DVIEWPORTI)lpD3DView;
|
|
|
|
if (lpViewI->lpDevI) {
|
|
D3D_ERR("viewport already associated with a device");
|
|
return (DDERR_INVALIDPARAMS);
|
|
}
|
|
|
|
err = hookViewportToDevice(lpViewI);
|
|
|
|
/*
|
|
* AddRef the viewport.
|
|
*/
|
|
lpD3DView->AddRef();
|
|
|
|
return (err);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DDevice::DeleteViewport"
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::DeleteViewport(LPDIRECT3DVIEWPORT lpD3DView)
|
|
{
|
|
return DeleteViewport((LPDIRECT3DVIEWPORT3)lpD3DView);
|
|
}
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::DeleteViewport(LPDIRECT3DVIEWPORT2 lpD3DView)
|
|
{
|
|
return DeleteViewport((LPDIRECT3DVIEWPORT3)lpD3DView);
|
|
}
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::DeleteViewport(LPDIRECT3DVIEWPORT3 lpD3DView)
|
|
{
|
|
LPDIRECT3DVIEWPORTI lpViewI;
|
|
HRESULT err = D3D_OK;
|
|
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
/*
|
|
* validate parms
|
|
*/
|
|
TRY
|
|
{
|
|
if (!VALID_DIRECT3DVIEWPORT3_PTR(lpD3DView)) {
|
|
D3D_ERR( "Invalid Direct3DViewport pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
D3D_ERR( "Exception encountered validating parameters in DeleteViewport" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (this->dwHintFlags & D3DDEVBOOL_HINTFLAGS_INBEGIN)
|
|
{
|
|
D3D_ERR( "DeleteViewport in Begin" );
|
|
return D3DERR_INBEGIN;
|
|
}
|
|
lpViewI = (LPDIRECT3DVIEWPORTI)lpD3DView;
|
|
|
|
if (lpViewI->lpDevI != this) {
|
|
D3D_ERR("This Viewport is not associated with this device");
|
|
return (DDERR_INVALIDPARAMS);
|
|
}
|
|
|
|
/*
|
|
* Remove this viewport from the device.
|
|
*/
|
|
CIRCLE_QUEUE_DELETE(&this->viewports, lpViewI, vw_list);
|
|
this->numViewports--;
|
|
|
|
lpViewI->lpDevI = NULL;
|
|
if (lpViewI == lpCurrentViewport)
|
|
{
|
|
// AnanKan (6/10/98):
|
|
// Apparently this release needs to be done for proper COM
|
|
// implementation, since we do lpCurrentViewport->AddRef() when
|
|
// we make a viewport the current viewport of the device. But this
|
|
// breaks some old apps (pplane.exe)
|
|
if(!(this->dwDeviceFlags & D3DDEV_PREDX6DEVICE))
|
|
lpCurrentViewport->Release();
|
|
lpCurrentViewport = NULL;
|
|
v_id = 0;
|
|
}
|
|
|
|
/*
|
|
* Release the viewport.
|
|
*/
|
|
lpD3DView->Release();
|
|
|
|
return (err);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DDevice::NextViewport"
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::NextViewport(LPDIRECT3DVIEWPORT lpD3DView,
|
|
LPDIRECT3DVIEWPORT* lplpView,
|
|
DWORD dwFlags)
|
|
{
|
|
return NextViewport((LPDIRECT3DVIEWPORT3)lpD3DView,
|
|
(LPDIRECT3DVIEWPORT3*)lplpView, dwFlags);
|
|
}
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::NextViewport(LPDIRECT3DVIEWPORT2 lpD3DView,
|
|
LPDIRECT3DVIEWPORT2* lplpView,
|
|
DWORD dwFlags)
|
|
{
|
|
return NextViewport((LPDIRECT3DVIEWPORT3)lpD3DView,
|
|
(LPDIRECT3DVIEWPORT3*)lplpView, dwFlags);
|
|
}
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::NextViewport(LPDIRECT3DVIEWPORT3 lpD3DView,
|
|
LPDIRECT3DVIEWPORT3* lplpView,
|
|
DWORD dwFlags)
|
|
{
|
|
LPDIRECT3DVIEWPORTI lpViewI;
|
|
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
/*
|
|
* validate parms
|
|
*/
|
|
TRY
|
|
{
|
|
if (!VALID_OUTPTR(lplpView)) {
|
|
D3D_ERR( "Invalid pointer to viewport object pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
*lplpView = NULL;
|
|
|
|
if (!VALID_DIRECT3DDEVICE3_PTR(this)) {
|
|
D3D_ERR( "Invalid Direct3DDevice pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
if (dwFlags == D3DNEXT_NEXT) {
|
|
if (!VALID_DIRECT3DVIEWPORT3_PTR(lpD3DView)) {
|
|
D3D_ERR( "Invalid Direct3DViewport pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
lpViewI = (LPDIRECT3DVIEWPORTI)lpD3DView;
|
|
if (lpViewI->lpDevI != this) {
|
|
D3D_ERR("This Viewport is not associated with this device");
|
|
return (DDERR_INVALIDPARAMS);
|
|
}
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
D3D_ERR("Exception encountered validating parameters in NextViewport");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
if (this->numViewports <= 0) {
|
|
D3D_ERR( "No viewport has been added to the device yet." );
|
|
return D3DERR_NOVIEWPORTS;
|
|
}
|
|
|
|
if (this->dwHintFlags & D3DDEVBOOL_HINTFLAGS_INBEGIN)
|
|
{
|
|
D3D_ERR( "NextViewport called in Begin" );
|
|
return D3DERR_INBEGIN;
|
|
}
|
|
switch (dwFlags) {
|
|
case D3DNEXT_NEXT:
|
|
*lplpView = (LPDIRECT3DVIEWPORT3)
|
|
CIRCLE_QUEUE_NEXT(&this->viewports,lpViewI,vw_list);
|
|
break;
|
|
case D3DNEXT_HEAD:
|
|
*lplpView = (LPDIRECT3DVIEWPORT3)
|
|
CIRCLE_QUEUE_FIRST(&this->viewports);
|
|
break;
|
|
case D3DNEXT_TAIL:
|
|
*lplpView = (LPDIRECT3DVIEWPORT3)
|
|
CIRCLE_QUEUE_LAST(&this->viewports);
|
|
break;
|
|
default:
|
|
D3D_ERR("invalid dwFlags in NextViewport");
|
|
return (DDERR_INVALIDPARAMS);
|
|
}
|
|
if (*lplpView == (LPDIRECT3DVIEWPORT3)&this->viewports) {
|
|
*lplpView = NULL;
|
|
}
|
|
|
|
/*
|
|
* Must AddRef the returned object
|
|
*/
|
|
if (*lplpView) {
|
|
(*lplpView)->AddRef();
|
|
}
|
|
|
|
return (D3D_OK);
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DIRECT3DDEVICEI::Execute"
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::Execute(LPDIRECT3DEXECUTEBUFFER lpBuffer,
|
|
LPDIRECT3DVIEWPORT lpD3DView,
|
|
DWORD dwInpFlags)
|
|
{
|
|
HRESULT ret;
|
|
LPDIRECT3DVIEWPORTI lpD3DViewI;
|
|
LPDIRECT3DVIEWPORTI lpD3DOldViewI;
|
|
BOOL viewportChanged;
|
|
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
/*
|
|
* validate parms
|
|
*/
|
|
TRY
|
|
{
|
|
if (!VALID_DIRECT3DDEVICE3_PTR(this))
|
|
{
|
|
D3D_ERR( "Invalid Direct3DDevice pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
if (!VALID_DIRECT3DEXECUTEBUFFER_PTR(lpBuffer))
|
|
{
|
|
D3D_ERR( "Invalid Direct3DExecuteBuffer pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
if (lpD3DView && (!VALID_DIRECT3DVIEWPORT_PTR(lpD3DView)) )
|
|
{
|
|
D3D_ERR( "Invalid Direct3DViewport pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
D3D_ERR( "Exception encountered validating parameters in Execute" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
lpD3DOldViewI = lpCurrentViewport;
|
|
if (lpD3DView)
|
|
lpD3DViewI = (LPDIRECT3DVIEWPORTI)lpD3DView;
|
|
else
|
|
lpD3DViewI = lpCurrentViewport;
|
|
|
|
// The viewport must be associated with lpDev device
|
|
//
|
|
if (lpD3DViewI->lpDevI != this)
|
|
{
|
|
return (DDERR_INVALIDPARAMS);
|
|
}
|
|
|
|
lpCurrentViewport = lpD3DViewI;
|
|
|
|
ret = CheckDeviceSettings(this);
|
|
if (ret != D3D_OK)
|
|
{
|
|
lpCurrentViewport = lpD3DOldViewI;
|
|
D3D_ERR("Bad Device settings");
|
|
return (ret);
|
|
}
|
|
|
|
/*
|
|
* Save existing fp state and then disable divide-by-zero exceptions.
|
|
* XXX need a better way for non-intel platforms.
|
|
*/
|
|
|
|
LPDIRECT3DEXECUTEBUFFERI lpBufferI;
|
|
D3DI_EXECUTEDATA exData;
|
|
|
|
lpBufferI = (LPDIRECT3DEXECUTEBUFFERI)lpBuffer;
|
|
|
|
/* Make sure this buffer is associated with the correct device */
|
|
if (lpBufferI->lpDevI != this)
|
|
{
|
|
D3D_ERR("Exe-buffer not associated with this device");
|
|
return (DDERR_INVALIDPARAMS);
|
|
}
|
|
|
|
if (lpBufferI->locked)
|
|
{
|
|
D3D_ERR("Exe-buffer is locked");
|
|
return (D3DERR_EXECUTE_LOCKED);
|
|
}
|
|
|
|
/* Apply any cached render states */
|
|
if ((ret=this->FlushStates()) != D3D_OK)
|
|
{
|
|
D3D_ERR("Error trying to flush batched commands");
|
|
return ret;
|
|
}
|
|
/*
|
|
* Create an execute data structure
|
|
*/
|
|
memset(&exData, 0, sizeof(exData));
|
|
exData.dwSize = sizeof(D3DI_EXECUTEDATA);
|
|
exData.dwHandle = lpBufferI->hBuf;
|
|
exData.dwVertexOffset = lpBufferI->exData.dwVertexOffset;
|
|
exData.dwVertexCount = lpBufferI->exData.dwVertexCount;
|
|
exData.dwInstructionOffset = lpBufferI->exData.dwInstructionOffset;
|
|
exData.dwInstructionLength = lpBufferI->exData.dwInstructionLength;
|
|
exData.dwHVertexOffset = lpBufferI->exData.dwHVertexOffset;
|
|
|
|
#if DBG
|
|
// Validation
|
|
if (exData.dwVertexOffset > exData.dwInstructionOffset ||
|
|
(exData.dwVertexCount * sizeof(D3DVERTEX) + exData.dwVertexOffset) >
|
|
exData.dwInstructionOffset)
|
|
{
|
|
D3D_WARN(1, "Execute: Instruction and vertex areas overlap");
|
|
}
|
|
|
|
#endif
|
|
|
|
this->dwFlags = D3DPV_INSIDEEXECUTE;
|
|
this->dwVIDOut = D3DFVF_TLVERTEX;
|
|
|
|
ret = this->ExecuteI(&exData, dwInpFlags);
|
|
if (ret != D3D_OK)
|
|
{
|
|
D3D_ERR("Error trying to Execute");
|
|
return ret;
|
|
}
|
|
|
|
this->dwFEFlags &= ~D3DFE_TLVERTEX; // This flag could be set inside
|
|
// Flush immediately since we cannot batch across EB calls (for DP2)
|
|
if ((ret=this->FlushStates()) != D3D_OK)
|
|
{
|
|
D3D_ERR("Error trying to flush batched commands");
|
|
return ret;
|
|
}
|
|
lpBufferI->exData.dsStatus = exData.dsStatus;
|
|
|
|
lpCurrentViewport = lpD3DOldViewI;
|
|
|
|
return (ret);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DDevice::GetCaps"
|
|
|
|
HRESULT D3DAPI CDirect3DDevice::GetCaps(LPD3DDEVICEDESC lpD3DHWDevDesc,
|
|
LPD3DDEVICEDESC lpD3DHELDevDesc)
|
|
{
|
|
HRESULT ret;
|
|
|
|
ret = GetCapsI(lpD3DHWDevDesc, lpD3DHELDevDesc);
|
|
if ((ret == D3D_OK) && IS_PRE_DX5_DEVICE(this))
|
|
{
|
|
lpD3DHELDevDesc->dpcLineCaps.dwTextureFilterCaps &= ~(D3DPTFILTERCAPS_MIPNEAREST |
|
|
D3DPTFILTERCAPS_MIPLINEAR |
|
|
D3DPTFILTERCAPS_LINEARMIPNEAREST);
|
|
lpD3DHELDevDesc->dpcTriCaps.dwTextureFilterCaps &= ~(D3DPTFILTERCAPS_MIPNEAREST |
|
|
D3DPTFILTERCAPS_MIPLINEAR |
|
|
D3DPTFILTERCAPS_LINEARMIPNEAREST);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
HRESULT D3DAPI D3DAPI DIRECT3DDEVICEI::GetCaps(LPD3DDEVICEDESC lpD3DHWDevDesc,
|
|
LPD3DDEVICEDESC lpD3DHELDevDesc)
|
|
{
|
|
return GetCapsI(lpD3DHWDevDesc, lpD3DHELDevDesc);
|
|
}
|
|
|
|
HRESULT DIRECT3DDEVICEI::GetCapsI(LPD3DDEVICEDESC lpD3DHWDevDesc,
|
|
LPD3DDEVICEDESC lpD3DHELDevDesc)
|
|
{
|
|
HRESULT ret;
|
|
|
|
ret = D3D_OK;
|
|
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
/*
|
|
* validate parms
|
|
*/
|
|
TRY
|
|
{
|
|
if (!VALID_DIRECT3DDEVICE3_PTR(this)) {
|
|
D3D_ERR( "Invalid Direct3DDevice pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
if (!VALID_D3DDEVICEDESC_PTR(lpD3DHWDevDesc)) {
|
|
D3D_ERR( "Invalid D3DDEVICEDESC pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (!VALID_D3DDEVICEDESC_PTR(lpD3DHELDevDesc)) {
|
|
D3D_ERR( "Invalid D3DDEVICEDESC pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
D3D_ERR( "Exception encountered validating parameters in GetCaps" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
memcpy(lpD3DHWDevDesc, &this->d3dHWDevDesc, lpD3DHWDevDesc->dwSize);
|
|
memcpy(lpD3DHELDevDesc, &this->d3dHELDevDesc, lpD3DHELDevDesc->dwSize);
|
|
return (ret);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DDevice::Pick"
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::Pick(LPDIRECT3DEXECUTEBUFFER lpD3DExBuf,
|
|
LPDIRECT3DVIEWPORT lpD3DView,
|
|
DWORD dwFlags,
|
|
LPD3DRECT lpRect)
|
|
{
|
|
HRESULT ret;
|
|
LPDIRECT3DVIEWPORTI lpD3DViewI;
|
|
LPDIRECT3DVIEWPORTI lpD3DOldViewI;
|
|
LPDIRECT3DEXECUTEBUFFERI lpBufferI;
|
|
D3DI_PICKDATA pdata;
|
|
D3DI_EXECUTEDATA exData;
|
|
|
|
ret = D3D_OK;
|
|
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
/*
|
|
* validate parms
|
|
*/
|
|
TRY
|
|
{
|
|
if (!VALID_DIRECT3DDEVICE3_PTR(this)) {
|
|
D3D_ERR( "Invalid Direct3DDevice pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
if (!VALID_DIRECT3DEXECUTEBUFFER_PTR(lpD3DExBuf)) {
|
|
D3D_ERR( "Invalid Direct3DExecuteBuffer pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
if (!VALID_DIRECT3DVIEWPORT_PTR(lpD3DView)) {
|
|
D3D_ERR( "Invalid Direct3DViewport pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
if (!VALID_D3DRECT_PTR(lpRect)) {
|
|
D3D_ERR( "Invalid D3DRECT pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
D3D_ERR( "Exception encountered validating parameters" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
lpD3DViewI = (LPDIRECT3DVIEWPORTI)lpD3DView;
|
|
|
|
/*
|
|
* The viewport must be associated with this device
|
|
*/
|
|
if (lpD3DViewI->lpDevI != this) {
|
|
D3D_ERR("viewport not associated with this device");
|
|
return (DDERR_INVALIDPARAMS);
|
|
}
|
|
|
|
lpBufferI = (LPDIRECT3DEXECUTEBUFFERI)lpD3DExBuf;
|
|
|
|
/* Make sure this buffer is associated with the correct device */
|
|
if (lpBufferI->lpDevI != this) {
|
|
D3D_ERR("Exe-buffer not associated with this device");
|
|
return (DDERR_INVALIDPARAMS);
|
|
}
|
|
|
|
if (lpBufferI->locked) {
|
|
D3D_ERR("Exe-buffer is locked");
|
|
return (D3DERR_EXECUTE_LOCKED);
|
|
}
|
|
|
|
lpD3DOldViewI = lpCurrentViewport;
|
|
lpCurrentViewport = lpD3DViewI;
|
|
|
|
ret = CheckDeviceSettings(this);
|
|
if (ret != D3D_OK)
|
|
{
|
|
D3D_ERR("Bad Device settings");
|
|
lpCurrentViewport = lpD3DOldViewI;
|
|
return (ret);
|
|
}
|
|
|
|
/*
|
|
* Create an execute data structure
|
|
*/
|
|
memset(&exData, 0, sizeof(exData));
|
|
exData.dwSize = sizeof(D3DI_EXECUTEDATA);
|
|
exData.dwHandle = lpBufferI->hBuf;
|
|
memcpy((LPBYTE)(&exData.dwVertexOffset),
|
|
(LPBYTE)(&lpBufferI->exData.dwVertexOffset),
|
|
sizeof(D3DEXECUTEDATA) - sizeof(DWORD));
|
|
pdata.exe = &exData;
|
|
pdata.pick.x1 = lpRect->x1;
|
|
pdata.pick.y1 = lpRect->y1;
|
|
pdata.pick.x2 = lpRect->x2;
|
|
pdata.pick.y2 = lpRect->y2;
|
|
|
|
this->dwFlags = D3DPV_INSIDEEXECUTE;
|
|
this->dwVIDOut = D3DFVF_TLVERTEX;
|
|
|
|
D3DHAL_ExecutePick(this, &pdata);
|
|
|
|
this->dwFEFlags &= ~D3DFE_TLVERTEX; // This flag could be set inside
|
|
lpCurrentViewport = lpD3DOldViewI;
|
|
|
|
return ret;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DDevice::GetPickRecords"
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::GetPickRecords(LPDWORD count,
|
|
LPD3DPICKRECORD records)
|
|
{
|
|
HRESULT ret;
|
|
D3DI_PICKDATA pdata;
|
|
D3DPICKRECORD* tmpBuff;
|
|
|
|
ret = D3D_OK;
|
|
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
/*
|
|
* validate parms
|
|
*/
|
|
TRY
|
|
{
|
|
if (!VALID_DIRECT3DDEVICE3_PTR(this)) {
|
|
D3D_ERR( "Invalid Direct3DDevice pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
if (!VALID_DWORD_PTR(count)) {
|
|
D3D_ERR( "Invalid DWORD pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
#if DBG
|
|
if (*count && records && IsBadWritePtr(records, *count * sizeof(D3DPICKRECORD))) {
|
|
D3D_ERR( "Invalid D3DPICKRECORD pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
#endif
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
D3D_ERR( "Exception encountered validating parameters" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
pdata.records = NULL;
|
|
GenGetPickRecords(this, &pdata);
|
|
|
|
if (count && records && *count >= (unsigned long)pdata.pick_count)
|
|
{
|
|
int picked_size = pdata.pick_count * sizeof(D3DPICKRECORD);
|
|
|
|
if (D3DMalloc((void**)&tmpBuff, picked_size) != DD_OK)
|
|
{
|
|
return (DDERR_OUTOFMEMORY);
|
|
}
|
|
pdata.records = tmpBuff;
|
|
GenGetPickRecords(this, &pdata);
|
|
memcpy((char*)records, (char*)tmpBuff, picked_size);
|
|
D3DFree(tmpBuff);
|
|
}
|
|
|
|
*count = pdata.pick_count;
|
|
|
|
return (D3D_OK);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DDevice::EnumTextureFormats"
|
|
|
|
|
|
#define DEFINEPF(flags, fourcc, bpp, rMask, gMask, bMask, aMask) \
|
|
{ sizeof(DDPIXELFORMAT), (flags), (fourcc), (bpp), (rMask), (gMask), (bMask), (aMask) }
|
|
|
|
static DDPIXELFORMAT g_DX5TexEnumIncListStatic[] = {
|
|
DEFINEPF(DDPF_RGB, 0UL, 16UL, 0x00007c00UL, 0x000003e0UL, 0x0000001fUL, 0x00000000), // 16bit 555
|
|
DEFINEPF(DDPF_RGB|DDPF_ALPHAPIXELS, 0UL, 16UL, 0x00007c00UL, 0x000003e0UL, 0x0000001fUL, 0x00008000), // 16bit 1555
|
|
DEFINEPF(DDPF_RGB, 0UL, 16UL, 0x0000f800UL, 0x000007e0UL, 0x0000001fUL, 0x00000000), // 16bit 565
|
|
DEFINEPF(DDPF_RGB|DDPF_ALPHAPIXELS, 0UL, 16UL, 0x00000f00UL, 0x000000f0UL, 0x0000000fUL, 0x0000f000), // 16bit 4444
|
|
DEFINEPF(DDPF_RGB|DDPF_ALPHAPIXELS, 0UL, 32UL, 0x00ff0000UL, 0x0000ff00UL, 0x000000ffUL, 0xff000000), // 32bit 8888
|
|
DEFINEPF(DDPF_RGB, 0UL, 32UL, 0x00ff0000UL, 0x0000ff00UL, 0x000000ffUL, 0x00000000), // 32bit 888
|
|
DEFINEPF(DDPF_RGB, 0UL, 8UL, 0x000000e0UL, 0x0000001cUL, 0x00000003UL, 0x00000000), // 8bit 332
|
|
DEFINEPF(DDPF_RGB|DDPF_PALETTEINDEXED4, 0UL, 4UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000), // 4bit pal
|
|
DEFINEPF(DDPF_RGB|DDPF_PALETTEINDEXED8, 0UL, 8UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000), // 8bit pal
|
|
};
|
|
DWORD g_cDX5TexEnumIncListStatic = sizeof(g_DX5TexEnumIncListStatic)/sizeof(DDPIXELFORMAT);
|
|
|
|
BOOL
|
|
MatchDDPIXELFORMAT( DDPIXELFORMAT* pddpfA, DDPIXELFORMAT* pddpfB )
|
|
{
|
|
if ( pddpfA->dwFlags != pddpfB->dwFlags ) return FALSE;
|
|
if ( pddpfA->dwRGBBitCount != pddpfB->dwRGBBitCount ) return FALSE;
|
|
if ( pddpfA->dwRBitMask != pddpfB->dwRBitMask ) return FALSE;
|
|
if ( pddpfA->dwGBitMask != pddpfB->dwGBitMask ) return FALSE;
|
|
if ( pddpfA->dwBBitMask != pddpfB->dwBBitMask ) return FALSE;
|
|
if ( pddpfA->dwRGBAlphaBitMask != pddpfB->dwRGBAlphaBitMask ) return FALSE;
|
|
if ( pddpfA->dwFourCC != pddpfB->dwFourCC ) return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
LoadTexEnumInclList( char* pResPath, DDPIXELFORMAT*& pddpfInclList, DWORD& cInclList)
|
|
{
|
|
HKEY hKey = (HKEY)NULL;
|
|
if (ERROR_SUCCESS == RegOpenKey( HKEY_LOCAL_MACHINE,
|
|
pResPath, &hKey))
|
|
{
|
|
DWORD cSubKeys = 0;
|
|
if ( ERROR_SUCCESS == RegQueryInfoKey ( hKey,
|
|
NULL,NULL,NULL, &cSubKeys, NULL,
|
|
NULL,NULL,NULL,NULL,NULL,NULL ) )
|
|
{
|
|
D3D_INFO(3,"LoadTexEnumInclList: cSubKeys = %d",cSubKeys);
|
|
|
|
if (cSubKeys == 0) return;
|
|
|
|
// allocate space for ddpf inclusion list
|
|
cInclList = cSubKeys;
|
|
if (D3DMalloc((void**)&pddpfInclList, cInclList*sizeof(DDPIXELFORMAT)) != D3D_OK) {
|
|
D3D_ERR("malloc failed on texture enum inclusion list");
|
|
pddpfInclList = NULL;
|
|
cInclList = 0;
|
|
}
|
|
memset( pddpfInclList, 0, cInclList*sizeof(DDPIXELFORMAT) );
|
|
|
|
for (DWORD i=0; i<cSubKeys; i++)
|
|
{
|
|
char pName[128] = "";
|
|
DWORD cbName = 128;
|
|
if (ERROR_SUCCESS == RegEnumKeyEx( hKey, i, pName, &cbName,
|
|
NULL,NULL,NULL,NULL ) )
|
|
{
|
|
HKEY hTexKey = (HKEY)NULL;
|
|
if (ERROR_SUCCESS == RegOpenKey( hKey, pName, &hTexKey))
|
|
{
|
|
DWORD dwType; DWORD dwSize;
|
|
|
|
// get string of full ddpf
|
|
char pDDPFStr[128] = ""; DWORD cbDDPFStr = 128;
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hTexKey, "ddpf",
|
|
NULL, &dwType, (LPBYTE)pDDPFStr, &cbDDPFStr) )
|
|
{
|
|
sscanf(pDDPFStr, "%x %x %d %x %x %x %x",
|
|
&pddpfInclList[i].dwFlags,&pddpfInclList[i].dwFourCC,&pddpfInclList[i].dwRGBBitCount,
|
|
&pddpfInclList[i].dwRBitMask,&pddpfInclList[i].dwGBitMask,&pddpfInclList[i].dwBBitMask,
|
|
&pddpfInclList[i].dwRGBAlphaBitMask);
|
|
}
|
|
|
|
D3D_INFO(3,"LoadTexEnumInclList: <%s> %08x %08x %2d %08x %08x %08x %08x",
|
|
pName,
|
|
pddpfInclList[i].dwFlags,
|
|
pddpfInclList[i].dwFourCC,
|
|
pddpfInclList[i].dwRGBBitCount,
|
|
pddpfInclList[i].dwRBitMask,
|
|
pddpfInclList[i].dwGBitMask,
|
|
pddpfInclList[i].dwBBitMask,
|
|
pddpfInclList[i].dwRGBAlphaBitMask);
|
|
}
|
|
else
|
|
{
|
|
D3D_INFO(3,"LoadTexEnumInclList: failed to open subkey %s",pName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
D3D_INFO(3,"LoadTexEnumInclList: failed to enumerate subkey %d",i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
DoEnumTextureFormats(
|
|
DIRECT3DDEVICEI* lpDevI,
|
|
LPD3DENUMTEXTUREFORMATSCALLBACK lpEnumCallbackDX5, // DX5 version
|
|
LPD3DENUMPIXELFORMATSCALLBACK lpEnumCallbackDX6, // DX6 version
|
|
LPVOID lpContext)
|
|
{
|
|
HRESULT ret, userRet;
|
|
LPDDSURFACEDESC lpDescs, lpRetDescs;
|
|
DWORD num_descs;
|
|
DWORD i;
|
|
|
|
ret = D3D_OK;
|
|
|
|
num_descs = lpDevI->lpD3DHALGlobalDriverData->dwNumTextureFormats;
|
|
lpDescs = lpDevI->lpD3DHALGlobalDriverData->lpTextureFormats;
|
|
if (!num_descs)
|
|
{
|
|
D3D_ERR("no texture formats supported");
|
|
return (D3DERR_TEXTURE_NO_SUPPORT);
|
|
}
|
|
|
|
if (D3DMalloc((void**)&lpRetDescs, sizeof(DDSURFACEDESC) * num_descs) != D3D_OK)
|
|
{
|
|
D3D_ERR("failed to alloc space for return descriptions");
|
|
return (DDERR_OUTOFMEMORY);
|
|
}
|
|
memcpy(lpRetDescs, lpDescs, sizeof(DDSURFACEDESC) * num_descs);
|
|
|
|
// get apphack flags
|
|
LPDDRAWI_DIRECTDRAW_LCL lpDDLcl = ((LPDDRAWI_DIRECTDRAW_INT)(lpDevI->lpDD))->lpLcl;
|
|
DWORD dwEnumInclAppHack =
|
|
((lpDDLcl->dwAppHackFlags & DDRAW_APPCOMPAT_TEXENUMINCL_0)?1:0) |
|
|
((lpDDLcl->dwAppHackFlags & DDRAW_APPCOMPAT_TEXENUMINCL_1)?2:0);
|
|
// two bit field:
|
|
// 0 - no apphack (default behavior)
|
|
// 1 - use no inclusion list
|
|
// 2 - use DX5 inclusion list
|
|
// 3 - use DX6 inclusion list
|
|
D3D_INFO(3, "APPCOMPAT_TEXENUMINCL: %d",dwEnumInclAppHack);
|
|
|
|
// enumeration limit defaults true for <DX6 interfaces, and can be disabled by apphack
|
|
BOOL bEnumLimit = (lpDevI->dwVersion < 3) ? TRUE : FALSE;
|
|
if (lpDDLcl->dwAppHackFlags & DDRAW_APPCOMPAT_TEXENUMLIMIT) { bEnumLimit = FALSE; }
|
|
D3D_INFO(3, "EnumTextureFormats: bEnumLimit %d",bEnumLimit);
|
|
|
|
#if DBG
|
|
// debug capability to eliminate enumeration of any subset of first 32 textures
|
|
DWORD dwEnumDisable = 0x0;
|
|
GetD3DRegValue(REG_DWORD, "TextureEnumDisable", &dwEnumDisable, sizeof(DWORD));
|
|
D3D_INFO(3, "TextureEnumDisable: %08x",dwEnumDisable);
|
|
#endif
|
|
|
|
DDPIXELFORMAT* pDX5TexEnumIncList = NULL;
|
|
DWORD cDX5TexEnumIncList = 0;
|
|
// load DX5 inclusion list from registry
|
|
LoadTexEnumInclList( RESPATH_D3D "\\DX5TextureEnumInclusionList",
|
|
pDX5TexEnumIncList, cDX5TexEnumIncList );
|
|
|
|
DDPIXELFORMAT* pDX6TexEnumIncList = NULL;
|
|
DWORD cDX6TexEnumIncList = 0;
|
|
// load DX6 list only for DX6 interface or apphack
|
|
if ((lpDevI->dwVersion == 3) || (dwEnumInclAppHack >= 3))
|
|
{
|
|
LoadTexEnumInclList( RESPATH_D3D "\\DX6TextureEnumInclusionList",
|
|
pDX6TexEnumIncList, cDX6TexEnumIncList );
|
|
}
|
|
|
|
userRet = D3DENUMRET_OK;
|
|
int cEnumLimit = 0;
|
|
for (i = 0; i < num_descs && userRet == D3DENUMRET_OK; i++)
|
|
{
|
|
|
|
D3D_INFO(3,"EnumTextureFormats: %2d %08x %08x %2d %08x %08x %08x %08x",i,
|
|
lpRetDescs[i].ddpfPixelFormat.dwFlags,
|
|
lpRetDescs[i].ddpfPixelFormat.dwFourCC,
|
|
lpRetDescs[i].ddpfPixelFormat.dwRGBBitCount,
|
|
lpRetDescs[i].ddpfPixelFormat.dwRBitMask,
|
|
lpRetDescs[i].ddpfPixelFormat.dwGBitMask,
|
|
lpRetDescs[i].ddpfPixelFormat.dwBBitMask,
|
|
lpRetDescs[i].ddpfPixelFormat.dwRGBAlphaBitMask);
|
|
|
|
#if DBG
|
|
if ( (i < 32) && (dwEnumDisable & (1<<i)) )
|
|
{
|
|
D3D_INFO(3, "EnumTextureFormats: filtering texture %d",i);
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
// Filtering out texture formats which are not on inclusion list -
|
|
if ( (dwEnumInclAppHack != 1) && // inclusion list not disabled by apphack
|
|
!(lpRetDescs[i].ddpfPixelFormat.dwFlags == DDPF_FOURCC) ) // not FourCC
|
|
{
|
|
BOOL bMatched = FALSE;
|
|
|
|
// match against DX5 base (static) inclusion list
|
|
for (DWORD j=0; j<g_cDX5TexEnumIncListStatic; j++)
|
|
{
|
|
if (MatchDDPIXELFORMAT( &(g_DX5TexEnumIncListStatic[j]), &(lpRetDescs[i].ddpfPixelFormat)))
|
|
{
|
|
bMatched = TRUE; break;
|
|
}
|
|
}
|
|
// match against DX5 extended (regkey) inclusion list
|
|
if (!bMatched && cDX5TexEnumIncList)
|
|
{
|
|
for (DWORD j=0; j<cDX5TexEnumIncList; j++)
|
|
{
|
|
if (MatchDDPIXELFORMAT( &(pDX5TexEnumIncList[j]), &(lpRetDescs[i].ddpfPixelFormat)))
|
|
{
|
|
bMatched = TRUE; break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// match against DX6 regkey list for:
|
|
// (DX6 interface AND apphack not forcing DX5 inclusion list only) OR
|
|
// (apphack forcing DX6 inclusion list)
|
|
if ( ((lpDevI->dwVersion == 3) && (dwEnumInclAppHack != 2)) ||
|
|
(dwEnumInclAppHack == 3) )
|
|
{
|
|
for (DWORD j=0; j<cDX6TexEnumIncList; j++)
|
|
{
|
|
if (MatchDDPIXELFORMAT( &(pDX6TexEnumIncList[j]), &(lpRetDescs[i].ddpfPixelFormat)))
|
|
{
|
|
bMatched = TRUE; break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bMatched) {
|
|
D3D_INFO(3, "EnumTextureFormats: filtering non-included texture %d",i);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// exclude DXT1..5 for <DX6 interfaces
|
|
if ( (lpDevI->dwVersion < 3) && (lpRetDescs[i].ddpfPixelFormat.dwFlags == DDPF_FOURCC) )
|
|
{
|
|
if ( (lpRetDescs[i].ddpfPixelFormat.dwFourCC == MAKEFOURCC('D', 'X', 'T', '1')) ||
|
|
(lpRetDescs[i].ddpfPixelFormat.dwFourCC == MAKEFOURCC('D', 'X', 'T', '2')) ||
|
|
(lpRetDescs[i].ddpfPixelFormat.dwFourCC == MAKEFOURCC('D', 'X', 'T', '3')) ||
|
|
(lpRetDescs[i].ddpfPixelFormat.dwFourCC == MAKEFOURCC('D', 'X', 'T', '4')) ||
|
|
(lpRetDescs[i].ddpfPixelFormat.dwFourCC == MAKEFOURCC('D', 'X', 'T', '5')) )
|
|
{
|
|
D3D_INFO(3, "EnumTextureFormats: filtering DXT1..5 format for DX3/5 interfaces");
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// exclude all FourCC code formats for <DX6 interfaces on DX7 drivers
|
|
if ( (lpDevI->dwVersion < 3) && IS_DX7HAL_DEVICE(lpDevI) &&
|
|
(lpRetDescs[i].ddpfPixelFormat.dwFlags == DDPF_FOURCC) )
|
|
{
|
|
D3D_INFO(3, "EnumTextureFormats: filtering all FOURCC formats for DX3/5 interfaces on DX7 HALs");
|
|
continue;
|
|
}
|
|
|
|
// do enumeration if not ('limit enabled' && 'limit exceeded')
|
|
if ( !(bEnumLimit && (++cEnumLimit > 10)) )
|
|
{
|
|
if (lpEnumCallbackDX5)
|
|
{
|
|
userRet = (*lpEnumCallbackDX5)(&lpRetDescs[i], lpContext);
|
|
}
|
|
if (lpEnumCallbackDX6)
|
|
{
|
|
userRet = (*lpEnumCallbackDX6)(&(lpRetDescs[i].ddpfPixelFormat), lpContext);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
D3D_INFO(3, "EnumTextureFormats: enumeration limit exceeded");
|
|
}
|
|
}
|
|
|
|
D3DFree(lpRetDescs);
|
|
if (pDX5TexEnumIncList) D3DFree(pDX5TexEnumIncList);
|
|
if (pDX6TexEnumIncList) D3DFree(pDX6TexEnumIncList);
|
|
|
|
return (D3D_OK);
|
|
}
|
|
|
|
|
|
// Device/Device2 version
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::EnumTextureFormats(
|
|
LPD3DENUMTEXTUREFORMATSCALLBACK lpEnumCallback,
|
|
LPVOID lpContext)
|
|
{
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
/*
|
|
* validate parms
|
|
*/
|
|
TRY
|
|
{
|
|
if (!VALID_DIRECT3DDEVICE3_PTR(this)) {
|
|
D3D_ERR( "Invalid Direct3DDevice pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
|
|
if (!VALIDEX_CODE_PTR(lpEnumCallback)) {
|
|
D3D_ERR( "Invalid callback pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
D3D_ERR( "Exception encountered validating parameters" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
return DoEnumTextureFormats(this, lpEnumCallback, NULL, lpContext);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DDevice::EnumTextureFormats"
|
|
|
|
// Device3 version
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::EnumTextureFormats(
|
|
LPD3DENUMPIXELFORMATSCALLBACK lpEnumCallback,
|
|
LPVOID lpContext)
|
|
{
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
/*
|
|
* validate parms
|
|
*/
|
|
TRY
|
|
{
|
|
if (!VALID_DIRECT3DDEVICE3_PTR(this)) {
|
|
D3D_ERR( "Invalid Direct3DDevice pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
|
|
if (!VALIDEX_CODE_PTR(lpEnumCallback)) {
|
|
D3D_ERR( "Invalid callback pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
D3D_ERR( "Exception encountered validating parameters" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
return DoEnumTextureFormats(this, NULL, lpEnumCallback, lpContext);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DDevice::SwapTextureHandles"
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::SwapTextureHandles(LPDIRECT3DTEXTURE lpTex1,
|
|
LPDIRECT3DTEXTURE lpTex2)
|
|
{
|
|
LPDIRECT3DTEXTUREI lpTex1I;
|
|
LPDIRECT3DTEXTUREI lpTex2I;
|
|
HRESULT ret;
|
|
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
/*
|
|
* validate parms
|
|
*/
|
|
TRY
|
|
{
|
|
if (!VALID_DIRECT3DDEVICE3_PTR(this)) {
|
|
D3D_ERR( "Invalid Direct3DDevice pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
if (!VALID_DIRECT3DTEXTURE_PTR(lpTex1)) {
|
|
D3D_ERR( "Invalid Direct3DTexture pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
if (!VALID_DIRECT3DTEXTURE_PTR(lpTex2)) {
|
|
D3D_ERR( "Invalid Direct3DTexture pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
lpTex1I = static_cast<LPDIRECT3DTEXTUREI>(lpTex1);
|
|
lpTex2I = static_cast<LPDIRECT3DTEXTUREI>(lpTex2);
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
D3D_ERR( "Exception encountered validating parameters" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
ret = SwapTextureHandles((LPDIRECT3DTEXTURE2)lpTex1I,
|
|
(LPDIRECT3DTEXTURE2)lpTex2I);
|
|
return ret;
|
|
}
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::SwapTextureHandles(LPDIRECT3DTEXTURE2 lpTex1,
|
|
LPDIRECT3DTEXTURE2 lpTex2)
|
|
{
|
|
LPDIRECT3DTEXTUREI lpTex1I;
|
|
LPDIRECT3DTEXTUREI lpTex2I;
|
|
HRESULT servRet;
|
|
D3DTEXTUREHANDLE hTex;
|
|
LPD3DI_TEXTUREBLOCK lptBlock1,lptBlock2;
|
|
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
/*
|
|
* validate parms
|
|
*/
|
|
TRY
|
|
{
|
|
if (!VALID_DIRECT3DDEVICE3_PTR(this)) {
|
|
D3D_ERR( "Invalid Direct3DDevice pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
if (!VALID_DIRECT3DTEXTURE2_PTR(lpTex1)) {
|
|
D3D_ERR( "Invalid Direct3DTexture pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
if (!VALID_DIRECT3DTEXTURE2_PTR(lpTex2)) {
|
|
D3D_ERR( "Invalid Direct3DTexture pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
lpTex1I = static_cast<LPDIRECT3DTEXTUREI>(lpTex1);
|
|
lpTex2I = static_cast<LPDIRECT3DTEXTUREI>(lpTex2);
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
D3D_ERR( "Exception encountered validating parameters" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (lpTex1I->lpDDSSys || lpTex2I->lpDDSSys)
|
|
{
|
|
D3D_ERR("Can't Swap Managed textures. Returning DDERR_INVALIDPARAMS");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (!(lptBlock1=D3DI_FindTextureBlock(lpTex1I,this)))
|
|
{
|
|
D3D_ERR("lpTex1 is an invalid texture handle.");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (!(lptBlock2=D3DI_FindTextureBlock(lpTex2I,this)))
|
|
{
|
|
D3D_ERR("lpTex2 is an invalid texture handle.");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if (D3D_OK != (servRet=FlushStates()))
|
|
{
|
|
D3D_ERR("Error trying to flush batched commands during TextureSwap");
|
|
return servRet;
|
|
}
|
|
|
|
if (IS_DX7HAL_DEVICE(this))
|
|
{
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf1 = ((LPDDRAWI_DDRAWSURFACE_INT)lpTex1I->lpDDS)->lpLcl;
|
|
LPDDRAWI_DDRAWSURFACE_LCL surf2 = ((LPDDRAWI_DDRAWSURFACE_INT)lpTex2I->lpDDS)->lpLcl;
|
|
LPDDRAWI_DIRECTDRAW_LCL pDDLcl = ((LPDDRAWI_DIRECTDRAW_INT)lpDirect3DI->lpDD)->lpLcl;
|
|
DDASSERT(pDDLcl != NULL);
|
|
|
|
// Update DDraw handle in driver GBL object.
|
|
pDDLcl->lpGbl->hDD = pDDLcl->hDD;
|
|
// Swap the handles stored in the surface locals
|
|
surf1->lpSurfMore->dwSurfaceHandle = lptBlock2->hTex;
|
|
surf2->lpSurfMore->dwSurfaceHandle = lptBlock1->hTex;
|
|
// Swap the surface pointers stored in the handle table stored in
|
|
// ddraw local
|
|
SURFACEHANDLELIST(pDDLcl).dwList[lptBlock1->hTex].lpSurface = surf2;
|
|
SURFACEHANDLELIST(pDDLcl).dwList[lptBlock2->hTex].lpSurface = surf1;
|
|
|
|
// call the driver to switch the textures mapped to the handles in
|
|
// the driver
|
|
DDASSERT(NULL != pDDLcl->lpGbl->lpDDCBtmp->HALDDMiscellaneous2.CreateSurfaceEx);
|
|
DDHAL_CREATESURFACEEXDATA csdex;
|
|
DWORD rc;
|
|
csdex.ddRVal = DDERR_GENERIC;
|
|
csdex.dwFlags = 0;
|
|
csdex.lpDDLcl = pDDLcl;
|
|
csdex.lpDDSLcl = surf1;
|
|
rc = pDDLcl->lpGbl->lpDDCBtmp->HALDDMiscellaneous2.CreateSurfaceEx(&csdex);
|
|
if( DDHAL_DRIVER_HANDLED == rc && DD_OK != csdex.ddRVal)
|
|
{
|
|
// Driver call failed
|
|
D3D_ERR("DdSwapTextureHandles failed!");
|
|
return D3DERR_TEXTURE_SWAP_FAILED;
|
|
}
|
|
csdex.lpDDSLcl = surf2;
|
|
rc = pDDLcl->lpGbl->lpDDCBtmp->HALDDMiscellaneous2.CreateSurfaceEx(&csdex);
|
|
if( DDHAL_DRIVER_HANDLED == rc && DD_OK != csdex.ddRVal)
|
|
{
|
|
// Driver call failed
|
|
D3D_ERR("DdSwapTextureHandles failed!");
|
|
return D3DERR_TEXTURE_SWAP_FAILED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
servRet=D3DHAL_TextureSwap(this,lptBlock1->hTex,lptBlock2->hTex);
|
|
if (D3D_OK != servRet)
|
|
{
|
|
D3D_ERR("SwapTextureHandles HAL call failed");
|
|
return D3DERR_TEXTURE_SWAP_FAILED;
|
|
}
|
|
}
|
|
hTex=lptBlock1->hTex;
|
|
lptBlock1->hTex=lptBlock2->hTex;
|
|
lptBlock2->hTex=hTex;
|
|
|
|
return (D3D_OK);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DDevice::CreateMatrix"
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::CreateMatrix(LPD3DMATRIXHANDLE lphMatrix)
|
|
{
|
|
HRESULT servRet;
|
|
D3DMATRIXHANDLE hMat;
|
|
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
/*
|
|
* validate parms
|
|
*/
|
|
TRY
|
|
{
|
|
if (!VALID_DIRECT3DDEVICE3_PTR(this)) {
|
|
D3D_ERR( "Invalid Direct3DDevice pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
if (!VALID_D3DMATRIXHANDLE_PTR(lphMatrix)) {
|
|
D3D_ERR( "Invalid D3DMATRIXHANDLE pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
D3D_ERR( "Exception encountered validating parameters" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
*lphMatrix = 0;
|
|
|
|
servRet = D3DHAL_MatrixCreate(this, &hMat);
|
|
if (servRet != D3D_OK)
|
|
{
|
|
D3D_ERR("Could not create matrix.");
|
|
return (DDERR_OUTOFMEMORY);
|
|
}
|
|
|
|
D3D_INFO(4, "CreateMatrix, Matrix created. handle = %d", hMat);
|
|
*lphMatrix = hMat;
|
|
|
|
return (D3D_OK);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DDevice::SetMatrix"
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::SetMatrix(D3DMATRIXHANDLE hMatrix,
|
|
const LPD3DMATRIX lpdmMatrix)
|
|
{
|
|
HRESULT servRet;
|
|
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
/*
|
|
* validate parms
|
|
*/
|
|
TRY
|
|
{
|
|
if (!VALID_DIRECT3DDEVICE3_PTR(this)) {
|
|
D3D_ERR( "Invalid Direct3DDevice pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
if (!VALID_D3DMATRIX_PTR(lpdmMatrix)) {
|
|
D3D_ERR( "Invalid D3DMATRIX pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
D3D_ERR( "Exception encountered validating parameters" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
if (!hMatrix) {
|
|
D3D_ERR("NULL hMatrix passed");
|
|
return (DDERR_INVALIDPARAMS);
|
|
}
|
|
|
|
servRet = D3DHAL_MatrixSetData(this, hMatrix, lpdmMatrix);
|
|
if (servRet != D3D_OK)
|
|
{
|
|
D3D_ERR("Could not set matrix");
|
|
return (DDERR_INVALIDPARAMS);
|
|
}
|
|
|
|
return (D3D_OK);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DDevice::GetMatrix"
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::GetMatrix(D3DMATRIXHANDLE hMatrix,
|
|
LPD3DMATRIX lpdmMatrix)
|
|
{
|
|
HRESULT servRet;
|
|
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
/*
|
|
* validate parms
|
|
*/
|
|
TRY
|
|
{
|
|
if (!VALID_DIRECT3DDEVICE3_PTR(this)) {
|
|
D3D_ERR( "Invalid Direct3DDevice pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
if (!VALID_D3DMATRIX_PTR(lpdmMatrix)) {
|
|
D3D_ERR( "Invalid D3DMATRIX pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
D3D_ERR( "Exception encountered validating parameters" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
if (!hMatrix)
|
|
{
|
|
D3D_ERR("NULL hMatrix passed.");
|
|
return (DDERR_INVALIDPARAMS);
|
|
}
|
|
|
|
memset(lpdmMatrix, 0, sizeof(D3DMATRIX));
|
|
|
|
servRet = D3DHAL_MatrixGetData(this, hMatrix, lpdmMatrix);
|
|
if (servRet != D3D_OK)
|
|
{
|
|
D3D_ERR("Could not get matrix");
|
|
return (DDERR_INVALIDPARAMS);
|
|
}
|
|
|
|
return (D3D_OK);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DDevice::DeleteMatrix"
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::DeleteMatrix(D3DMATRIXHANDLE hMatrix)
|
|
{
|
|
HRESULT servRet;
|
|
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
/*
|
|
* validate parms
|
|
*/
|
|
TRY
|
|
{
|
|
if (!VALID_DIRECT3DDEVICE3_PTR(this)) {
|
|
D3D_ERR( "Invalid Direct3DDevice pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
D3D_ERR( "Exception encountered validating parameters" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
if (!hMatrix) {
|
|
D3D_ERR("invalid D3DMATRIXHANDLE");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
servRet = D3DHAL_MatrixDestroy(this, hMatrix);
|
|
if (servRet != D3D_OK)
|
|
{
|
|
D3D_ERR("Could not delete matrix");
|
|
return (DDERR_INVALIDPARAMS);
|
|
}
|
|
|
|
return (D3D_OK);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DDevice::BeginScene"
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::BeginScene()
|
|
{
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
/*
|
|
* validate parms
|
|
*/
|
|
TRY
|
|
{
|
|
if (!VALID_DIRECT3DDEVICE_PTR(this)) {
|
|
D3D_ERR( "Invalid Direct3DDevice pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
D3D_ERR( "Exception encountered validating parameters" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
if (this->dwHintFlags & D3DDEVBOOL_HINTFLAGS_INSCENE)
|
|
{
|
|
D3D_ERR("BeginScene, already in scene.");
|
|
return (D3DERR_SCENE_IN_SCENE);
|
|
}
|
|
|
|
// Check if we lost surfaces or rtarget / zbuffer was locked
|
|
HRESULT servRet = this->CheckSurfaces();
|
|
if (servRet != D3D_OK)
|
|
{
|
|
// If we lost surfaces
|
|
if (servRet == DDERR_SURFACELOST)
|
|
{
|
|
// Even if the app restores the rendertargets and z buffer, it
|
|
// doesn't know anything about vidmem execute buffers or
|
|
// managed texture surfaces in vidmem. So, we need to do
|
|
// this on our own. We first check if it is safe to restore
|
|
// surfaces. If not, we fail in the usual way. Else, we
|
|
// do the restore. Note that we will fail *only* if the
|
|
// app calls BeginScene at the wrong time.
|
|
servRet = this->lpDirect3DI->lpDD4->TestCooperativeLevel();
|
|
if (servRet == DD_OK)
|
|
{
|
|
// Everything must be evicted otherwise Restore might not work
|
|
// as there might be new surface allocated, in fact, we should
|
|
// post a flag in Device so that Texture manage stop calling
|
|
// CreateSurface() if this flag is indicating TestCooperativeLevel()
|
|
// failed, however, even we added those, the EvictTextures below
|
|
// is still needed but not this critical--kanqiu
|
|
this->lpDirect3DI->lpTextureManager->EvictTextures();
|
|
servRet = this->lpDirect3DI->lpDD4->RestoreAllSurfaces();
|
|
if (servRet != DD_OK)
|
|
return D3DERR_SCENE_BEGIN_FAILED;
|
|
}
|
|
else
|
|
return DDERR_SURFACELOST;
|
|
}
|
|
else
|
|
{
|
|
// Render target and / or the z buffer was locked
|
|
return servRet;
|
|
}
|
|
}
|
|
servRet = D3DHAL_SceneCapture(this, TRUE);
|
|
|
|
if (servRet != D3D_OK && servRet != DDERR_NOTFOUND)
|
|
{
|
|
D3D_ERR("Could not BeginScene.");
|
|
return D3DERR_SCENE_BEGIN_FAILED;
|
|
}
|
|
|
|
this->dwHintFlags |= D3DDEVBOOL_HINTFLAGS_INSCENE;
|
|
if (lpD3DHALGlobalDriverData->hwCaps.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR)
|
|
{
|
|
lpDirect3DI->lpTextureManager->TimeStamp();
|
|
}
|
|
|
|
return (D3D_OK);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DDevice::EndScene"
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::EndScene()
|
|
{
|
|
HRESULT servRet;
|
|
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
/*
|
|
* validate parms
|
|
*/
|
|
TRY
|
|
{
|
|
if (!VALID_DIRECT3DDEVICE3_PTR(this)) {
|
|
D3D_ERR( "Invalid Direct3DDevice pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
D3D_ERR( "Exception encountered validating parameters" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
if (!(this->dwHintFlags & D3DDEVBOOL_HINTFLAGS_INSCENE)) {
|
|
D3D_ERR("EndScene, not in scene.");
|
|
return (D3DERR_SCENE_NOT_IN_SCENE);
|
|
}
|
|
|
|
this->dwHintFlags &= ~D3DDEVBOOL_HINTFLAGS_INSCENE;
|
|
if (IS_DX7HAL_DEVICE(this))
|
|
{
|
|
// must set the token before FlushStates()
|
|
SetRenderStateI((D3DRENDERSTATETYPE)D3DRENDERSTATE_SCENECAPTURE, FALSE);
|
|
}
|
|
|
|
servRet = FlushStates(); //time to flush DrawPrimitives
|
|
if (servRet != D3D_OK)
|
|
{
|
|
D3D_ERR("Could not Flush commands in EndScene!");
|
|
return (D3DERR_SCENE_END_FAILED);
|
|
}
|
|
if (!IS_DX7HAL_DEVICE(this))
|
|
{
|
|
servRet = D3DHAL_SceneCapture(this, FALSE);
|
|
|
|
if (servRet != D3D_OK && servRet != DDERR_NOTFOUND)
|
|
{
|
|
DPF(0, "(ERROR) Direct3DDevice::EndScene: Could not EndScene. Returning %d", servRet);
|
|
return (D3DERR_SCENE_END_FAILED);
|
|
}
|
|
}
|
|
|
|
// Did we lose any surfaces during this scene ?
|
|
if (this->dwFEFlags & D3DFE_LOSTSURFACES)
|
|
{
|
|
D3D_INFO(3, "reporting DDERR_SURFACELOST in EndScene");
|
|
this->dwFEFlags &= ~D3DFE_LOSTSURFACES;
|
|
return DDERR_SURFACELOST;
|
|
}
|
|
|
|
return (D3D_OK);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "Direct3DDevice::GetDirect3D"
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::GetDirect3D(LPDIRECT3D* lplpD3D)
|
|
{
|
|
LPDIRECT3D3 lpD3D3;
|
|
HRESULT ret;
|
|
|
|
ret = GetDirect3D(&lpD3D3);
|
|
if (ret == D3D_OK)
|
|
{
|
|
// *lplpD3D = dynamic_cast<LPDIRECT3D>(lpD3D3); // This is possible using RTTI
|
|
*lplpD3D = static_cast<LPDIRECT3D>(static_cast<LPDIRECT3DI>(lpD3D3)); // This is safe even using static_cast
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::GetDirect3D(LPDIRECT3D2* lplpD3D)
|
|
{
|
|
LPDIRECT3D3 lpD3D3;
|
|
HRESULT ret;
|
|
|
|
ret = GetDirect3D(&lpD3D3);
|
|
if (ret == D3D_OK)
|
|
{
|
|
// *lplpD3D = dynamic_cast<LPDIRECT3D>(lpD3D3); // This is possible using RTTI
|
|
*lplpD3D = static_cast<LPDIRECT3D2>(static_cast<LPDIRECT3DI>(lpD3D3)); // This is safe even using static_cast
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
HRESULT D3DAPI DIRECT3DDEVICEI::GetDirect3D(LPDIRECT3D3* lplpD3D)
|
|
{
|
|
|
|
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
|
|
|
|
/*
|
|
* validate parms
|
|
*/
|
|
TRY
|
|
{
|
|
if (!VALID_DIRECT3DDEVICE3_PTR(this)) {
|
|
D3D_ERR( "Invalid Direct3DDevice pointer" );
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
if (!VALID_OUTPTR(lplpD3D)) {
|
|
D3D_ERR( "Invalid Direct3D pointer pointer" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
D3D_ERR( "Exception encountered validating parameters" );
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
*lplpD3D = (LPDIRECT3D3) this->lpDirect3DI;
|
|
(*lplpD3D)->AddRef();
|
|
|
|
return (D3D_OK);
|
|
}
|
|
|
|
void
|
|
D3DDeviceDescConvert(LPD3DDEVICEDESC lpOut,
|
|
LPD3DDEVICEDESC_V1 lpV1,
|
|
LPD3DHAL_D3DEXTENDEDCAPS lpExt)
|
|
{
|
|
if(lpV1!=NULL)
|
|
memcpy(lpOut, lpV1, D3DDEVICEDESCSIZE_V1);
|
|
|
|
if (lpExt)
|
|
{
|
|
// DX5
|
|
lpOut->dwSize = D3DDEVICEDESCSIZE;
|
|
lpOut->dwMinTextureWidth = lpExt->dwMinTextureWidth;
|
|
lpOut->dwMaxTextureWidth = lpExt->dwMaxTextureWidth;
|
|
lpOut->dwMinTextureHeight = lpExt->dwMinTextureHeight;
|
|
lpOut->dwMaxTextureHeight = lpExt->dwMaxTextureHeight;
|
|
lpOut->dwMinStippleWidth = lpExt->dwMinStippleWidth;
|
|
lpOut->dwMaxStippleWidth = lpExt->dwMaxStippleWidth;
|
|
lpOut->dwMinStippleHeight = lpExt->dwMinStippleHeight;
|
|
lpOut->dwMaxStippleHeight = lpExt->dwMaxStippleHeight;
|
|
|
|
// DX6
|
|
lpOut->dwMaxTextureRepeat = lpExt->dwMaxTextureRepeat;
|
|
lpOut->dwMaxTextureAspectRatio = lpExt->dwMaxTextureAspectRatio;
|
|
lpOut->dwMaxAnisotropy = lpExt->dwMaxAnisotropy;
|
|
lpOut->dvGuardBandLeft = lpExt->dvGuardBandLeft;
|
|
lpOut->dvGuardBandTop = lpExt->dvGuardBandTop;
|
|
lpOut->dvGuardBandRight = lpExt->dvGuardBandRight;
|
|
lpOut->dvGuardBandBottom = lpExt->dvGuardBandBottom;
|
|
lpOut->dvExtentsAdjust = lpExt->dvExtentsAdjust;
|
|
lpOut->dwStencilCaps = lpExt->dwStencilCaps;
|
|
lpOut->dwFVFCaps = lpExt->dwFVFCaps;
|
|
lpOut->dwTextureOpCaps = lpExt->dwTextureOpCaps;
|
|
lpOut->wMaxTextureBlendStages = lpExt->wMaxTextureBlendStages;
|
|
lpOut->wMaxSimultaneousTextures = lpExt->wMaxSimultaneousTextures;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DIRECT3DDEVICEI::CheckSurfaces"
|
|
HRESULT DIRECT3DDEVICEI::CheckSurfaces()
|
|
{
|
|
if(this->lpDirect3DI->lpTextureManager->CheckIfLost())
|
|
{
|
|
D3D_ERR("Managed Textures lost");
|
|
return DDERR_SURFACELOST;
|
|
}
|
|
if ( ((LPDDRAWI_DDRAWSURFACE_INT) this->lpDDSTarget)->lpLcl->lpGbl->dwUsageCount ||
|
|
(this->lpDDSZBuffer && ((LPDDRAWI_DDRAWSURFACE_INT) this->lpDDSZBuffer)->lpLcl->lpGbl->dwUsageCount) )
|
|
{
|
|
D3D_ERR("Render target or Z buffer locked");
|
|
return DDERR_SURFACEBUSY;
|
|
}
|
|
if ( ((LPDDRAWI_DDRAWSURFACE_INT) this->lpDDSTarget)->lpLcl->dwFlags & DDRAWISURF_INVALID )\
|
|
{
|
|
D3D_ERR("Render target buffer lost");
|
|
return DDERR_SURFACELOST;
|
|
}
|
|
if ( this->lpDDSZBuffer && ( ((LPDDRAWI_DDRAWSURFACE_INT) this->lpDDSZBuffer)->lpLcl->dwFlags & DDRAWISURF_INVALID ) )
|
|
{
|
|
D3D_ERR("Z buffer lost");
|
|
return DDERR_SURFACELOST;
|
|
}
|
|
return D3D_OK;
|
|
}
|