Leaked source code of windows server 2003
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.
 
 
 
 
 
 

3333 lines
124 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 $
*
*@@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
#ifdef PROFILE4
#include <icecap.h>
#endif
#ifdef PROFILE
#include <icapexp.h>
#endif
// 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"
// DX3, DX5, DX6, DX7, TL
#define MAX_DRIVERMODELS_SUPPORTED 5
#define D3DDRVMODEL_DX3 0x00000001
#define D3DDRVMODEL_DX5 0x00000002
#define D3DDRVMODEL_DX6 0x00000003
#define D3DDRVMODEL_DX7 0x00000004
#define D3DDRVMODEL_TL 0x00000005
extern BOOL isMMXprocessor(void);
extern BOOL IsValidD3DDeviceGuid(REFCLSID riid);
extern void setIdentity(D3DMATRIXI * m);
extern DWORD dwCPUFeatures;
#ifdef _X86_
extern HRESULT D3DAPI katmai_FEContextCreate(DWORD dwFlags, LPD3DFE_PVFUNCS *lpLeafFuncs);
extern HRESULT D3DAPI wlmt_FEContextCreate(DWORD dwFlags, LPD3DFE_PVFUNCS *lpLeafFuncs);
extern LPD3DFE_CONTEXTCREATE px3DContextCreate;
#endif
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;
}
// This is a list of all rstates that UpdateInternalState does some
// work other than updating this->rstates[] array. This is used to
// do a quick bitwise check to see if this rstate is trivial or not.
const D3DRENDERSTATETYPE rsList[] = {
D3DRENDERSTATE_FOGENABLE,
D3DRENDERSTATE_SPECULARENABLE,
D3DRENDERSTATE_RANGEFOGENABLE,
D3DRENDERSTATE_FOGDENSITY,
D3DRENDERSTATE_FOGSTART,
D3DRENDERSTATE_FOGEND,
D3DRENDERSTATE_WRAP0,
D3DRENDERSTATE_WRAP1,
D3DRENDERSTATE_WRAP2,
D3DRENDERSTATE_WRAP3,
D3DRENDERSTATE_WRAP4,
D3DRENDERSTATE_WRAP5,
D3DRENDERSTATE_WRAP6,
D3DRENDERSTATE_WRAP7,
D3DRENDERSTATE_CLIPPING,
D3DRENDERSTATE_LIGHTING,
D3DRENDERSTATE_EXTENTS,
D3DRENDERSTATE_AMBIENT,
D3DRENDERSTATE_FOGVERTEXMODE,
D3DRENDERSTATE_COLORVERTEX,
D3DRENDERSTATE_LOCALVIEWER,
D3DRENDERSTATE_NORMALIZENORMALS,
D3DRENDERSTATE_COLORKEYBLENDENABLE,
D3DRENDERSTATE_DIFFUSEMATERIALSOURCE,
D3DRENDERSTATE_SPECULARMATERIALSOURCE,
D3DRENDERSTATE_AMBIENTMATERIALSOURCE,
D3DRENDERSTATE_EMISSIVEMATERIALSOURCE,
D3DRENDERSTATE_VERTEXBLEND,
D3DRENDERSTATE_CLIPPLANEENABLE,
D3DRENDERSTATE_SHADEMODE,
// Retired renderstates to be filtered with DPF error and INVALID return
// NOTE: everything listed here is also assumed to appear in rsListRetired
D3DRENDERSTATE_TEXTUREHANDLE,
D3DRENDERSTATE_TEXTUREADDRESS,
D3DRENDERSTATE_WRAPU,
D3DRENDERSTATE_WRAPV,
D3DRENDERSTATE_MONOENABLE,
D3DRENDERSTATE_ROP2,
D3DRENDERSTATE_PLANEMASK,
D3DRENDERSTATE_TEXTUREMAG,
D3DRENDERSTATE_TEXTUREMIN,
D3DRENDERSTATE_TEXTUREMAPBLEND,
D3DRENDERSTATE_SUBPIXEL,
D3DRENDERSTATE_SUBPIXELX,
D3DRENDERSTATE_STIPPLEENABLE,
D3DRENDERSTATE_BORDERCOLOR,
D3DRENDERSTATE_TEXTUREADDRESSU,
D3DRENDERSTATE_TEXTUREADDRESSV,
D3DRENDERSTATE_MIPMAPLODBIAS,
D3DRENDERSTATE_ANISOTROPY,
D3DRENDERSTATE_TRANSLUCENTSORTINDEPENDENT,
D3DRENDERSTATE_STIPPLEPATTERN00,
D3DRENDERSTATE_STIPPLEPATTERN01,
D3DRENDERSTATE_STIPPLEPATTERN02,
D3DRENDERSTATE_STIPPLEPATTERN03,
D3DRENDERSTATE_STIPPLEPATTERN04,
D3DRENDERSTATE_STIPPLEPATTERN05,
D3DRENDERSTATE_STIPPLEPATTERN06,
D3DRENDERSTATE_STIPPLEPATTERN07,
D3DRENDERSTATE_STIPPLEPATTERN08,
D3DRENDERSTATE_STIPPLEPATTERN09,
D3DRENDERSTATE_STIPPLEPATTERN10,
D3DRENDERSTATE_STIPPLEPATTERN11,
D3DRENDERSTATE_STIPPLEPATTERN12,
D3DRENDERSTATE_STIPPLEPATTERN13,
D3DRENDERSTATE_STIPPLEPATTERN14,
D3DRENDERSTATE_STIPPLEPATTERN15,
D3DRENDERSTATE_STIPPLEPATTERN16,
D3DRENDERSTATE_STIPPLEPATTERN17,
D3DRENDERSTATE_STIPPLEPATTERN18,
D3DRENDERSTATE_STIPPLEPATTERN19,
D3DRENDERSTATE_STIPPLEPATTERN20,
D3DRENDERSTATE_STIPPLEPATTERN21,
D3DRENDERSTATE_STIPPLEPATTERN22,
D3DRENDERSTATE_STIPPLEPATTERN23,
D3DRENDERSTATE_STIPPLEPATTERN24,
D3DRENDERSTATE_STIPPLEPATTERN25,
D3DRENDERSTATE_STIPPLEPATTERN26,
D3DRENDERSTATE_STIPPLEPATTERN27,
D3DRENDERSTATE_STIPPLEPATTERN28,
D3DRENDERSTATE_STIPPLEPATTERN29,
D3DRENDERSTATE_STIPPLEPATTERN30,
D3DRENDERSTATE_STIPPLEPATTERN31,
};
// list of retired renderstates - need to make sure these are
// filtered and never get from app directly to driver
const D3DRENDERSTATETYPE rsListRetired[] = {
D3DRENDERSTATE_TEXTUREHANDLE,
D3DRENDERSTATE_TEXTUREADDRESS,
D3DRENDERSTATE_WRAPU,
D3DRENDERSTATE_WRAPV,
D3DRENDERSTATE_MONOENABLE,
D3DRENDERSTATE_ROP2,
D3DRENDERSTATE_PLANEMASK,
D3DRENDERSTATE_TEXTUREMAG,
D3DRENDERSTATE_TEXTUREMIN,
D3DRENDERSTATE_TEXTUREMAPBLEND,
D3DRENDERSTATE_SUBPIXEL,
D3DRENDERSTATE_SUBPIXELX,
D3DRENDERSTATE_STIPPLEENABLE,
D3DRENDERSTATE_BORDERCOLOR,
D3DRENDERSTATE_TEXTUREADDRESSU,
D3DRENDERSTATE_TEXTUREADDRESSV,
D3DRENDERSTATE_MIPMAPLODBIAS,
D3DRENDERSTATE_ANISOTROPY,
D3DRENDERSTATE_TRANSLUCENTSORTINDEPENDENT,
D3DRENDERSTATE_STIPPLEPATTERN00,
D3DRENDERSTATE_STIPPLEPATTERN01,
D3DRENDERSTATE_STIPPLEPATTERN02,
D3DRENDERSTATE_STIPPLEPATTERN03,
D3DRENDERSTATE_STIPPLEPATTERN04,
D3DRENDERSTATE_STIPPLEPATTERN05,
D3DRENDERSTATE_STIPPLEPATTERN06,
D3DRENDERSTATE_STIPPLEPATTERN07,
D3DRENDERSTATE_STIPPLEPATTERN08,
D3DRENDERSTATE_STIPPLEPATTERN09,
D3DRENDERSTATE_STIPPLEPATTERN10,
D3DRENDERSTATE_STIPPLEPATTERN11,
D3DRENDERSTATE_STIPPLEPATTERN12,
D3DRENDERSTATE_STIPPLEPATTERN13,
D3DRENDERSTATE_STIPPLEPATTERN14,
D3DRENDERSTATE_STIPPLEPATTERN15,
D3DRENDERSTATE_STIPPLEPATTERN16,
D3DRENDERSTATE_STIPPLEPATTERN17,
D3DRENDERSTATE_STIPPLEPATTERN18,
D3DRENDERSTATE_STIPPLEPATTERN19,
D3DRENDERSTATE_STIPPLEPATTERN20,
D3DRENDERSTATE_STIPPLEPATTERN21,
D3DRENDERSTATE_STIPPLEPATTERN22,
D3DRENDERSTATE_STIPPLEPATTERN23,
D3DRENDERSTATE_STIPPLEPATTERN24,
D3DRENDERSTATE_STIPPLEPATTERN25,
D3DRENDERSTATE_STIPPLEPATTERN26,
D3DRENDERSTATE_STIPPLEPATTERN27,
D3DRENDERSTATE_STIPPLEPATTERN28,
D3DRENDERSTATE_STIPPLEPATTERN29,
D3DRENDERSTATE_STIPPLEPATTERN30,
D3DRENDERSTATE_STIPPLEPATTERN31,
};
//---------------------------------------------------------------------
DIRECT3DDEVICEI::DIRECT3DDEVICEI()
{
m_rsMax = D3DRENDERSTATE_CLIPPING;
m_tssMax = D3DTSS_TEXTURETRANSFORMFLAGS;
}
//---------------------------------------------------------------------
HRESULT DIRECT3DDEVICEI::stateInitialize(BOOL bZEnable)
{
D3DLINEPATTERN defLPat;
HRESULT ret;
float tmpval;
DWORD i;
// Initialize the bit array indicating the rstates needing non-trivial
// work.
for (i=0; i < sizeof(rsList) / sizeof(D3DRENDERSTATETYPE); ++i)
rsVec[rsList[i] >> D3D_RSVEC_SHIFT] |= 1 << (rsList[i] & D3D_RSVEC_MASK);
// Initialize the bit array indicating the retired rstates
for (i=0; i < sizeof(rsListRetired) / sizeof(D3DRENDERSTATETYPE); ++i)
rsVecRetired[rsListRetired[i] >> D3D_RSVEC_SHIFT] |= 1 << (rsListRetired[i] & D3D_RSVEC_MASK);
// Obviate SetRenderState filtering 'redundant' render state settings
// since this is the init step.
memset( this->rstates, 0xff, sizeof(DWORD)*D3D_MAXRENDERSTATES);
this->rstates[D3DRENDERSTATE_PLANEMASK] = 0;
this->rstates[D3DRENDERSTATE_STENCILMASK] = 0;
this->rstates[D3DRENDERSTATE_STENCILWRITEMASK] = 0;
this->rstates[D3DRENDERSTATE_TEXTUREFACTOR] = 0;
SetRenderStateInternal( D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE);
SetRenderStateInternal( D3DRENDERSTATE_SPECULARENABLE, FALSE);
SetRenderStateInternal( D3DRENDERSTATE_ZENABLE, bZEnable);
SetRenderStateInternal( D3DRENDERSTATE_FILLMODE, D3DFILL_SOLID);
SetRenderStateInternal( D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD);
defLPat.wRepeatFactor = 0;
defLPat.wLinePattern = 0;
SetRenderStateInternal( D3DRENDERSTATE_LINEPATTERN, *((LPDWORD)&defLPat)); /* 10 */
/*
((LPD3DSTATE)lpPointer)->drstRenderStateType =
(D3DRENDERSTATETYPE)D3DRENDERSTATE_LINEPATTERN;
memcpy(&(((LPD3DSTATE)lpPointer)->dwArg[0]), &defLPat, sizeof(DWORD));
lpPointer = (void *)(((LPD3DSTATE)lpPointer) + 1);*/
SetRenderStateInternal( D3DRENDERSTATE_ZWRITEENABLE, TRUE);
SetRenderStateInternal( D3DRENDERSTATE_ALPHATESTENABLE, FALSE);
SetRenderStateInternal( D3DRENDERSTATE_LASTPIXEL, TRUE);
SetRenderStateInternal( D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE);
SetRenderStateInternal( D3DRENDERSTATE_DESTBLEND, D3DBLEND_ZERO);
SetRenderStateInternal( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW); /* 21 */
SetRenderStateInternal( D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL);
SetRenderStateInternal( D3DRENDERSTATE_ALPHAREF, 0);
SetRenderStateInternal( D3DRENDERSTATE_ALPHAFUNC, D3DCMP_ALWAYS);
SetRenderStateInternal( D3DRENDERSTATE_DITHERENABLE, FALSE);
SetRenderStateInternal( D3DRENDERSTATE_FOGENABLE, FALSE);
SetRenderStateInternal( D3DRENDERSTATE_ZVISIBLE, FALSE);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEDALPHA, FALSE);
SetRenderStateInternal( D3DRENDERSTATE_FOGCOLOR, 0);
SetRenderStateInternal( D3DRENDERSTATE_FOGTABLEMODE, D3DFOG_NONE);
tmpval = 0.0f;
SetRenderStateInternal( D3DRENDERSTATE_FOGSTART, *((DWORD *)&tmpval));
tmpval = 1.0f;
SetRenderStateInternal( D3DRENDERSTATE_FOGEND, *((DWORD *)&tmpval));
tmpval = 1.0f;
SetRenderStateInternal( D3DRENDERSTATE_FOGDENSITY, *((DWORD *)&tmpval));
SetRenderStateInternal( D3DRENDERSTATE_COLORKEYENABLE, FALSE);
SetRenderStateInternal( D3DRENDERSTATE_ALPHABLENDENABLE, FALSE);
SetRenderStateInternal( D3DRENDERSTATE_ZBIAS, 0);
SetRenderStateInternal( D3DRENDERSTATE_RANGEFOGENABLE, FALSE);
if (deviceType < D3DDEVTYPE_DX7HAL)
{
// send retired renderstate init's to pre-DX7 HALs only
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEENABLE, FALSE);
SetRenderStateInternal( D3DRENDERSTATE_MONOENABLE, FALSE);
SetRenderStateInternal( D3DRENDERSTATE_ROP2, R2_COPYPEN);
SetRenderStateInternal( D3DRENDERSTATE_PLANEMASK, (DWORD)~0);
SetRenderStateInternal( D3DRENDERSTATE_WRAPU, FALSE);
SetRenderStateInternal( D3DRENDERSTATE_WRAPV, FALSE);
SetRenderStateInternal( D3DRENDERSTATE_ANTIALIAS, FALSE);
SetRenderStateInternal( D3DRENDERSTATE_SUBPIXEL, FALSE); /* 30 */
SetRenderStateInternal( D3DRENDERSTATE_SUBPIXELX, FALSE);
SetRenderStateInternal( D3DRENDERSTATE_EDGEANTIALIAS, FALSE);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN00, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN01, 0); /* 40 */
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN02, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN03, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN04, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN05, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN06, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN07, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN08, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN09, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN10, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN11, 0); /* 50 */
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN12, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN13, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN14, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN15, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN16, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN17, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN18, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN19, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN20, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN21, 0); /* 60 */
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN22, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN23, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN24, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN25, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN26, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN27, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN28, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN29, 0);
SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN30, 0);
SetRenderStateInternal( 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
SetRenderStateInternal( D3DRENDERSTATE_STENCILENABLE, FALSE);
SetRenderStateInternal( D3DRENDERSTATE_STENCILFAIL, D3DSTENCILOP_KEEP);
SetRenderStateInternal( D3DRENDERSTATE_STENCILZFAIL, D3DSTENCILOP_KEEP);
SetRenderStateInternal( D3DRENDERSTATE_STENCILPASS, D3DSTENCILOP_KEEP);
SetRenderStateInternal( D3DRENDERSTATE_STENCILFUNC, D3DCMP_ALWAYS);
SetRenderStateInternal( D3DRENDERSTATE_STENCILREF, 0);
SetRenderStateInternal( D3DRENDERSTATE_STENCILMASK, 0xFFFFFFFF);
SetRenderStateInternal( D3DRENDERSTATE_STENCILWRITEMASK,0xFFFFFFFF);
// don't forget about texturefactor (like we did in DX6.0...)
SetRenderStateInternal( D3DRENDERSTATE_TEXTUREFACTOR, 0xFFFFFFFF);
for (i = 0; i < 8; i++)
{
SetRenderStateInternal( (D3DRENDERSTATETYPE)
(D3DRENDERSTATE_WRAPBIAS + i), FALSE );
}
for (i = 0; i < D3DHAL_TSS_MAXSTAGES; i++)
{
lpD3DMappedTexI[i] = NULL;
lpD3DMappedBlock[i] = NULL;
}
m_dwStageDirty = 0;
// 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);
SetTextureStageState(i, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
}
#ifdef WIN95
// Force a mapping if old HAL
if(deviceType < D3DDEVTYPE_DP2HAL)
{
SetRenderStateInternal( D3DRENDERSTATE_TEXTUREHANDLE, (DWORD)NULL);
static_cast<CDirect3DDeviceIHW*>(this)->MapTSSToRS();
}
#endif
SetRenderStateInternal(D3DRENDERSTATE_AMBIENT, 0);
SetRenderStateInternal(D3DRENDERSTATE_COLORVERTEX, TRUE);
SetRenderStateInternal(D3DRENDERSTATE_FOGVERTEXMODE, D3DFOG_NONE);
SetRenderStateInternal(D3DRENDERSTATE_CLIPPING, TRUE);
SetRenderStateInternal(D3DRENDERSTATE_LIGHTING, TRUE);
SetRenderStateInternal(D3DRENDERSTATE_EXTENTS, FALSE);
SetRenderStateInternal(D3DRENDERSTATE_NORMALIZENORMALS, FALSE);
SetRenderStateInternal(D3DRENDERSTATE_LOCALVIEWER, TRUE);
SetRenderStateInternal(D3DRENDERSTATE_COLORKEYBLENDENABLE, FALSE);
SetRenderStateInternal(D3DRENDERSTATE_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL);
SetRenderStateInternal(D3DRENDERSTATE_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL);
SetRenderStateInternal(D3DRENDERSTATE_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
SetRenderStateInternal(D3DRENDERSTATE_SPECULARMATERIALSOURCE, D3DMCS_COLOR2);
SetRenderStateInternal(D3DRENDERSTATE_VERTEXBLEND, D3DVBLEND_DISABLE);
SetRenderStateInternal(D3DRENDERSTATE_CLIPPLANEENABLE, 0);
// If we have created any textures prior to creating this device, then
// let the driver know their priorities.
if(DDCAPS2_CANMANAGETEXTURE & ((LPDDRAWI_DIRECTDRAW_INT)lpDirect3DI->lpDD)->lpLcl->lpGbl->ddCaps.dwCaps2)
{
LPDIRECT3DTEXTUREI lpTexI = LIST_FIRST(&lpDirect3DI->textures);
while(lpTexI)
{
// If the texture is managed (by the driver)
if(DDSCAPS2_TEXTUREMANAGE & ((LPDDRAWI_DDRAWSURFACE_INT)(lpTexI->lpDDS))->lpLcl->lpSurfMore->ddsCapsEx.dwCaps2)
{
ret = lpTexI->SetPriority(lpTexI->m_dwPriority);
if(ret != D3D_OK)
{
D3D_ERR("SetPriority failed in device initialize.");
return ret;
}
ret = lpTexI->SetLOD(lpTexI->m_dwLOD);
if(ret != D3D_OK)
{
D3D_ERR("SetLOD failed in device initialize.");
return ret;
}
}
lpTexI = LIST_NEXT(lpTexI, m_List);
}
}
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)
{
D3DDEVICEDESC7 Desc;
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);
}
if (IS_HW_DEVICE(this)) {
/* 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 & this->d3dDevDesc.dwDeviceRenderBitDepth)) {
D3D_ERR("Render-target surface bitdepth is not supported by 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 (IS_HW_DEVICE(this)) {
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 (!(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;
D3DDEVICEDESC7 dummyDesc;
lpDDI = ((LPDDRAWI_DIRECTDRAW_INT)lpD3DI->lpDD)->lpLcl->lpGbl;
//
// Retrieve HAL information from provider.
//
if (IS_HW_DEVICE(lpDevI))
error = lpDevI->pHalProv->GetCaps(lpDDI,
&lpDevI->d3dDevDesc,
&dummyDesc,
4);
else
error = lpDevI->pHalProv->GetCaps(lpDDI,
&dummyDesc,
&lpDevI->d3dDevDesc,
4);
if (error != S_OK)
{
return (error);
}
// Insert the GUID
memcpy(&lpDevI->d3dDevDesc.deviceGUID, &lpDevI->guid, sizeof(GUID));
if( lpDevI->d3dDevDesc.wMaxVertexBlendMatrices == 1 )
lpDevI->d3dDevDesc.wMaxVertexBlendMatrices = 0;
//
// Fix up the caps for non-T&L devices
// That use out front-end
//
if( IsEqualIID(lpDevI->guid, IID_IDirect3DHALDevice) ||
IsEqualIID(lpDevI->guid, IID_IDirect3DRGBDevice) )
{
lpDevI->d3dDevDesc.dwMaxActiveLights = 0xffffffff;
lpDevI->d3dDevDesc.wMaxVertexBlendMatrices = 4;
lpDevI->d3dDevDesc.wMaxUserClipPlanes = __MAXUSERCLIPPLANES;
lpDevI->d3dDevDesc.dwVertexProcessingCaps = D3DVTXPCAPS_ALL;
}
D3DHALPROVIDER_INTERFACEDATA HalProviderIData;
memset(&HalProviderIData,0,sizeof(HalProviderIData));
HalProviderIData.dwSize = sizeof(HalProviderIData);
if ((error = lpDevI->pHalProv->GetInterface(lpDDI,
&HalProviderIData,
4)) != 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->pfnRastService = HalProviderIData.pfnRastService;
lpDevI->dwHintFlags = 0;
// This is available in all DX7+ drivers and is used by GetInfo API
// call.
lpDevI->pfnGetDriverState = HalProviderIData.pfnGetDriverState;
// Zero out 8 bpp render target caps for real hardware.
if (IS_HW_DEVICE(lpDevI))
{
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 ((
#ifdef WIN95
lpDevI->dwDebugFlags & D3DDEBUG_DISABLEDP ||
lpDevI->dwDebugFlags & D3DDEBUG_DISABLEDP2 ||
#endif // WIN95
(GetD3DRegValue(REG_DWORD, "DisableFVF", &value, 4) &&
value != 0)) &&
FVF_DRIVERSUPPORTED(lpDevI))
{
lpDevI->dwMaxTextureIndices = 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->transform.dwMaxUserClipPlanes =
lpDevI->d3dDevDesc.wMaxUserClipPlanes;
lpDevI->dwFEFlags |= D3DFE_FRONTEND_DIRTY;
#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 ){
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;
}
void DIRECT3DDEVICEI::CleanupTextures()
{
/*
* 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);
}
FlushStates();
}
/*
* Generic device part destroy
*/
DIRECT3DDEVICEI::~DIRECT3DDEVICEI()
{
LPDIRECTDRAWSURFACE lpDDS=NULL, lpDDSZ=NULL;
LPDIRECTDRAWSURFACE7 lpDDS_DDS7=NULL;
LPDIRECTDRAWPALETTE lpDDPal=NULL;
/* Clear flags that could prohibit cleanup */
this->dwHintFlags &= ~(D3DDEVBOOL_HINTFLAGS_INSCENE);
// Hold pointers into ddraw object for release after driver is destroyed
lpDDSZ = this->lpDDSZBuffer;
lpDDPal = this->lpDDPalTarget;
lpDDS_DDS7 = this->lpDDSTarget_DDS7;
// this indicates that the device need no longer be flushed when Locking, Blting
// or GetDC'ing from the previous rendertarget
if (this->lpDDSTarget)
((LPDDRAWI_DDRAWSURFACE_INT)this->lpDDSTarget)->lpLcl->lpSurfMore->qwBatch.QuadPart = 0;
// this indicates that the device need no longer be flushed when Locking, Blting
// or GetDC'ing from the previous zbuffer
if (this->lpDDSZBuffer)
((LPDDRAWI_DDRAWSURFACE_INT)this->lpDDSZBuffer)->lpLcl->lpSurfMore->qwBatch.QuadPart = 0;
if (pGeometryFuncs != &GeometryFuncsGuaranteed)
delete pGeometryFuncs;
D3DFE_Destroy(this);
if (this->lpDirect3DI)
UnhookFromD3D();
if (this->lpwDPBufferAlloced)
D3DFree(this->lpwDPBufferAlloced);
if (this->pHalProv != NULL)
{
this->pHalProv->Release();
}
if (this->hDllProv != NULL)
{
FreeLibrary(this->hDllProv);
}
// Free the rstates that was allocated
if(!(IS_HW_DEVICE(this) && IS_DP2HAL_DEVICE(this)))
{
delete rstates;
}
if (m_pStateSets)
delete m_pStateSets;
if (lpDDS)
lpDDS->Release();
if (lpDDSZ)
lpDDSZ->Release();
if (lpDDPal)
lpDDPal->Release();
if (lpDDS_DDS7)
lpDDS_DDS7->Release();
D3DFree(clrRects);
}
HRESULT DIRECT3DDEVICEI::HookToD3D(LPDIRECT3DI lpD3DI)
{
LIST_INSERT_ROOT(&lpD3DI->devices, this, list);
this->lpDirect3DI = lpD3DI;
this->lpDirect3DI->AddRef(); // Since we hold a pointer to Direct3D
lpD3DI->numDevs++;
return (D3D_OK);
}
HRESULT DIRECT3DDEVICEI::UnhookFromD3D()
{
LIST_DELETE(this, list);
this->lpDirect3DI->numDevs--;
this->lpDirect3DI->Release(); // Release our AddRef
this->lpDirect3DI = NULL;
return (D3D_OK);
}
/*
* 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)
{
LPDIRECT3DI lpD3DI;
LPDIRECT3DDEVICEI pd3ddev;
D3DCOLORMODEL cm = D3DCOLOR_MONO;
HRESULT ret = D3D_OK;
HKEY hKey = (HKEY) NULL;
bool bDisableST = false;
WORD wDriverStyle = MAX_DRIVERMODELS_SUPPORTED;
#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.
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;
}
*lplpD3DDevice = NULL;
// Might be safer to use dynamic_cast<> if RTTI is enabled
lpD3DI = reinterpret_cast<CDirect3DUnk*>(lpDirect3D)->pD3DI;
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;
if ( ERROR_SUCCESS == RegQueryValueEx( hKey, "DriverStyle", NULL, &dwType, (LPBYTE) &dwValue, &dwSize) &&
dwType == REG_DWORD &&
dwValue != 0)
{
// Win64 compiler will scream here!!
wDriverStyle = (WORD)dwValue;
if (wDriverStyle > MAX_DRIVERMODELS_SUPPORTED)
wDriverStyle = MAX_DRIVERMODELS_SUPPORTED;
}
D3D_INFO(2,"DriverStyle: %d",wDriverStyle);
if ( ERROR_SUCCESS == RegQueryValueEx( hKey, "DisableST", NULL, &dwType, (LPBYTE) &dwValue, &dwSize) &&
dwType == REG_DWORD &&
dwValue != 0)
{
bDisableST = true;
}
#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 );
}
// Now create the appropriate device based on the wDriverStyle settings
//---------------------------------------------------------------------
// HKEY_LOCAL_MACHINE\Software\Microsoft\Direct3D\DriverStyle
// In DX7 this registry key replaces the host of keys we had before like
// DisableDP, DisableDP2 etc. This stuff is for testing purpose only.
// It is more like a hint, in that, if the requested driver type is
// available, it is used otherwise the latest available driver is used
// The following is the meanings for this dword:
//
// Value: Driver-type:
// 0x0 Latest available
// 0x1 DeviceHW (DX3)
// 0x2 DeviceDP (DX5)
// 0x3 DeviceDP2 (DX6)
// 0x4 DeviceDX7 (DX7)
// 0x5 DeviceTL (DX7+T&L)
//
// The following are the various cases we need to consider:
// 1) NT Hardware: 3 and above are considered legal
// 2) W9x Hardware: All of the above are legal
// 3) Reference: 2 and above
// 4) Software: 3 till 4 (no TL)
//---------------------------------------------------------------------
if (IsEqualIID(riid, IID_IDirect3DTnLHalDevice))
{
// For T&L hal guid, we ignore the wDriverStyle hint
// set in the registry
if (DDGBL(lpD3DI)->lpD3DGlobalDriverData &&
(DDGBL(lpD3DI)->lpD3DGlobalDriverData->hwCaps.dwDevCaps &
D3DDEVCAPS_HWTRANSFORMANDLIGHT))
{
wDriverStyle = D3DDRVMODEL_TL;
}
else // fail device creation
{
wDriverStyle = 0;
}
D3D_INFO(1,"TnLHalDevice Driver Style %x",wDriverStyle);
}
else if (IsEqualIID(riid, IID_IDirect3DHALDevice))
{
WORD wDriverCaps = 0;
WORD wLatestDDI=0;
//
// 1) Determine what styles of DDIs the driver is capable of
//
// DX7 ?
if (DDGBL(lpD3DI)->lpDDCBtmp &&
DDGBL(lpD3DI)->lpDDCBtmp->HALDDMiscellaneous2.GetDriverState)
{
wDriverCaps |= (1 << D3DDRVMODEL_DX7);
if (wLatestDDI==0)
wLatestDDI = D3DDRVMODEL_DX7;
}
// DX6 ?
if (DDGBL(lpD3DI)->lpD3DHALCallbacks3 &&
DDGBL(lpD3DI)->lpD3DHALCallbacks3->DrawPrimitives2)
{
wDriverCaps |= (1 << D3DDRVMODEL_DX6);
if (wLatestDDI==0)
wLatestDDI = D3DDRVMODEL_DX6;
}
#ifdef WIN95
// DX5 ?
if (DDGBL(lpD3DI)->lpD3DHALCallbacks2 &&
DDGBL(lpD3DI)->lpD3DHALCallbacks2->DrawOnePrimitive)
{
wDriverCaps |= (1 << D3DDRVMODEL_DX5);
if (wLatestDDI==0)
wLatestDDI = D3DDRVMODEL_DX5;
}
// DX3 ?
if (DDGBL(lpD3DI)->lpD3DHALCallbacks &&
DDGBL(lpD3DI)->lpD3DHALCallbacks->RenderPrimitive)
{
wDriverCaps |= (1 << D3DDRVMODEL_DX3);
if (wLatestDDI==0)
wLatestDDI = D3DDRVMODEL_DX3;
}
#endif //WIN95
//
// 2) Verify if the requested driver is supported
//
if (wDriverCaps == 0)
{
wDriverStyle = 0; // nothing supported so fail
}
else if (!(wDriverCaps & (1 << wDriverStyle)))
{
// use the latest available if not specified or
// incorrectly specified or specified but not available
wDriverStyle = wLatestDDI;
}
D3D_INFO(1,"HalDevice Driver Style %x",wDriverStyle);
}
// Reference Device
else if (IsEqualIID(riid, IID_IDirect3DRefDevice))
{
// By default choose TL device for RefRast in DX7
if (wDriverStyle < D3DDRVMODEL_DX5 || wDriverStyle > D3DDRVMODEL_TL)
{
// Refrast is capable of DX7+T&L
wDriverStyle = D3DDRVMODEL_TL;
}
}
// Software Rasterizers
else
{
// Ignore driver style for everything except the reference rasterizer
wDriverStyle = D3DDRVMODEL_DX6;
}
// Note: If wDriverStyle == 0x0 here, driver creation will fail
// Something must have been chosen by now
switch (wDriverStyle)
{
#ifdef WIN95
case D3DDRVMODEL_DX3:
pd3ddev = static_cast<LPDIRECT3DDEVICEI>(new CDirect3DDeviceIHW());
break;
case D3DDRVMODEL_DX5:
pd3ddev = static_cast<LPDIRECT3DDEVICEI>(new CDirect3DDeviceIDP());
break;
#endif //WIN95
case D3DDRVMODEL_DX6:
pd3ddev = static_cast<LPDIRECT3DDEVICEI>(new CDirect3DDeviceIDP2());
break;
case D3DDRVMODEL_DX7:
pd3ddev = static_cast<LPDIRECT3DDEVICEI>(new CDirect3DDevice7());
break;
case D3DDRVMODEL_TL:
pd3ddev = static_cast<LPDIRECT3DDEVICEI>(new CDirect3DDeviceTL());
break;
default:
D3D_ERR("Runtime doesnt support requested/installed driver");
// Change this return value ?
return (DDERR_OUTOFMEMORY);
}
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();
}
ret = pd3ddev->Init(riid, lpD3DI, lpDDSTarget, pUnkOuter, lplpD3DDevice);
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_FPUPRESERVE) &&
IS_DP2HAL_DEVICE(pd3ddev))
{
pd3ddev->dwHintFlags |= D3DDEVBOOL_HINTFLAGS_FPUSETUP;
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)
{
DDSCAPS ddscaps;
DDSURFACEDESC ddsd;
HRESULT ret, ddrval;
LPDIRECTDRAWSURFACE lpDDSZ=NULL;
LPDIRECTDRAWPALETTE lpDDPal=NULL;
LPGUID pGuid;
DDSCAPS surfCaps;
m_qwBatch = 1;
this->dwVIDIn = 0;
this->refCnt = 1;
pD3DMappedTexI = (LPVOID*)(this->lpD3DMappedTexI);
/* Single threaded or Multi threaded app ? */
if (((LPDDRAWI_DIRECTDRAW_INT)lpD3DI->lpDD)->lpLcl->dwLocalFlags & DDRAWILCL_MULTITHREADED)
this->dwHintFlags |= D3DDEVBOOL_HINTFLAGS_MULTITHREADED;
/*
* Initialise textures
*/
LIST_INITIALIZE(&this->texBlocks);
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_IDirect3DTnLHalDevice))
{
D3D_INFO(0, "======================= TL-Hal device selected");
}
if (IsEqualIID(*pGuid, IID_IDirect3DRGBDevice))
{
D3D_INFO(0, "======================= RGB device selected");
}
if (IsEqualIID(*pGuid, IID_IDirect3DHALDevice))
{
D3D_INFO(0, "======================= HAL device selected");
}
if (IsEqualIID(*pGuid, IID_IDirect3DRefDevice))
{
D3D_INFO(0, "======================= Reference Rasterizer device selected");
}
if (IsEqualIID(*pGuid, IID_IDirect3DNullDevice))
{
D3D_INFO(0, "======================= Null device selected");
}
#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(0, " using MMX in RGB device");
}
}
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);
}
}
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)");
}
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) ||
IsEqualIID(riid, IID_IDirect3DTnLHalDevice)) {
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, lpD3DI->lpDD7, 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[D3D_MAXRENDERSTATES];
}
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_
if (value != 1)
{
if ( dwCPUFeatures & D3DCPU_X3D && value != 2)
pfnFEContextCreate = px3DContextCreate;
else if ( dwCPUFeatures & D3DCPU_WLMT )
pfnFEContextCreate = wlmt_FEContextCreate;
else if ( dwCPUFeatures & D3DCPU_SSE )
pfnFEContextCreate = katmai_FEContextCreate;
if (pfnFEContextCreate)
{
D3D_INFO(0, "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;
}
}
}
#endif // _X86_
/*
* put this device in the list of those owned by the Direct3D object
*/
ret = HookToD3D(lpD3DI);
if (ret != D3D_OK)
{
D3D_ERR("Failed to associate device with Direct3D");
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;
}
}
// this indicates that the device should always be flushed when Locking, Blting
// or GetDC'ing a rendertarget
((LPDDRAWI_DDRAWSURFACE_INT)lpDDS)->lpLcl->lpSurfMore->qwBatch.QuadPart = _UI64_MAX;
// this indicates that the device should always be flushed when Locking, Blting
// or GetDC'ing a zbuffer
if (lpDDSZ)
{
((LPDDRAWI_DDRAWSURFACE_INT)lpDDSZ)->lpLcl->lpSurfMore->qwBatch.QuadPart = _UI64_MAX;
}
/* 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;
}
// Setup the viewport
m_Viewport.dwX = 0;
m_Viewport.dwY = 0;
m_Viewport.dwWidth = ((LPDDRAWI_DDRAWSURFACE_INT) lpDDS)->lpLcl->lpGbl->wWidth;
m_Viewport.dwHeight = ((LPDDRAWI_DDRAWSURFACE_INT) lpDDS)->lpLcl->lpGbl->wHeight;
m_Viewport.dvMinZ = (D3DVALUE)0;
m_Viewport.dvMaxZ = (D3DVALUE)1;
if (FAILED(this->SetViewport(&m_Viewport)))
goto handle_err;
// Setup lights
m_dwNumLights = 8;
m_pLights = new DIRECT3DLIGHTI[8];
LIST_INITIALIZE(&m_ActiveLights);
// Setup material
memset(&this->lighting.material, 0, sizeof(this->lighting.material));
// Setup set states
m_pStateSets = new CStateSets;
if (m_pStateSets == NULL)
return DDERR_OUTOFMEMORY;
m_pStateSets->Init(this->dwFEFlags);
#ifdef PROFILE4
m_dwProfStart = m_dwProfStop = 0;
GetD3DRegValue(REG_DWORD, "ProfileStartFrame", &m_dwProfStart, 4);
GetD3DRegValue(REG_DWORD, "ProfileStopFrame", &m_dwProfStop, 4);
#endif
#ifdef PROFILE
m_dwProfStart = m_dwProfStop = 0;
GetD3DRegValue(REG_DWORD, "ProfileStartFrame", &m_dwProfStart, 4);
GetD3DRegValue(REG_DWORD, "ProfileStopFrame", &m_dwProfStop, 4);
#endif
#ifdef VTABLE_HACK
// Copy with vtable
lpVtbl = *((LPVOID**)this);
memcpy(newVtbl, lpVtbl, sizeof(PVOID)*D3D_NUM_VIRTUAL_FUNCTIONS);
// Point to the new one
*((LPVOID*)this) = (LPVOID)newVtbl;
// Set vtable hack for PreLoad() if single threaded and not software
if (!IS_MT_DEVICE(this) && (this->dwFEFlags & D3DFE_REALHAL))
{
VtblPreLoadFast();
}
#endif // VTABLE_HACK
/*
* 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);
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) {
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) {
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);
}
HRESULT D3DAPI DIRECT3DDEVICEI::GetCaps(LPD3DDEVICEDESC7 lpD3DDevDesc)
{
HRESULT ret;
ret = D3D_OK;
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
if (!VALID_DIRECT3DDEVICE_PTR(this))
{
D3D_ERR( "Invalid Direct3DDevice pointer" );
return DDERR_INVALIDOBJECT;
}
if (!VALID_D3DDEVICEDESC7_PTR(lpD3DDevDesc))
{
D3D_ERR( "Invalid D3DDEVICEDESC7 pointer" );
return DDERR_INVALIDPARAMS;
}
memcpy(lpD3DDevDesc, &this->d3dDevDesc, sizeof( D3DDEVICEDESC7 ));
return (ret);
}
#undef DPF_MODNAME
#define DPF_MODNAME "Direct3DDevice::EnumTextureFormats"
HRESULT D3DAPI DIRECT3DDEVICEI::EnumTextureFormats(
LPD3DENUMPIXELFORMATSCALLBACK lpEnumCallback,
LPVOID lpContext)
{
HRESULT ret, userRet;
LPDDSURFACEDESC lpDescs, lpRetDescs;
DWORD num_descs;
DWORD i;
try
{
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
ret = D3D_OK;
if (!VALID_DIRECT3DDEVICE_PTR(this))
{
D3D_ERR( "Invalid Direct3DDevice pointer" );
return DDERR_INVALIDOBJECT;
}
if (!VALIDEX_CODE_PTR(lpEnumCallback))
{
D3D_ERR( "Invalid callback pointer" );
return DDERR_INVALIDPARAMS;
}
LPDDRAWI_DIRECTDRAW_LCL lpDDLcl = ((LPDDRAWI_DIRECTDRAW_INT)(this->lpDD))->lpLcl;
BOOL bFourCCAppHack =
(lpDDLcl->dwAppHackFlags & DDRAW_APPCOMPAT_TEXENUMDX7FOURCC)?1:0;
D3D_INFO(3, "APPCOMPAT_TEXENUMDX7FOURCC: %d",bFourCCAppHack);
num_descs = this->lpD3DHALGlobalDriverData->dwNumTextureFormats;
lpDescs = this->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);
userRet = D3DENUMRET_OK;
for (i = 0; i < num_descs && userRet == D3DENUMRET_OK; i++) {
// Filter out any DX8 formats
if (lpRetDescs[i].ddpfPixelFormat.dwFlags & DDPF_D3DFORMAT)
{
continue;
}
// Filter out non-DXTn FourCCs if apphack set
if ( bFourCCAppHack && (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 non-DXT FourCC format <%08x>",
lpRetDescs[i].ddpfPixelFormat.dwFourCC);
continue;
}
}
userRet = (*lpEnumCallback)(&(lpRetDescs[i].ddpfPixelFormat), lpContext);
}
D3DFree(lpRetDescs);
return (D3D_OK);
}
catch (HRESULT ret)
{
return ret;
}
}
#if COLLECTSTATS
#undef DPF_MODNAME
#define DPF_MODNAME "Direct3DDevice::ResetStats"
void DIRECT3DDEVICEI::ResetTexStats()
{
this->lpDirect3DI->ResetTexStats();
memset(&m_texstats, 0, sizeof(D3DDEVINFO_TEXTURING));
}
#endif
#undef DPF_MODNAME
#define DPF_MODNAME "Direct3DDevice::BeginScene"
HRESULT D3DAPI DIRECT3DDEVICEI::BeginScene()
{
#ifdef PROFILE4
static DWORD dwFrameCount = 0;
#endif
#ifdef PROFILE
static DWORD dwFrameCount = 0;
#endif
try
{
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
if (!VALID_DIRECT3DDEVICE_PTR(this))
{
D3D_ERR( "Invalid Direct3DDevice pointer" );
return DDERR_INVALIDOBJECT;
}
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->lpDD7->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();
if(IS_DP2HAL_DEVICE(this))
{
// We just bother restoring our internal vertex and command buffers
// It is upto the app to restore all surfaces that IT allocated.
// (managed textures are taken care of by the preceding evict)
CDirect3DDeviceIDP2 *dp2dev = static_cast<CDirect3DDeviceIDP2*>(this);
servRet = dp2dev->TLVbuf_GetDDS()->Restore();
if (servRet != DD_OK)
return D3DERR_SCENE_BEGIN_FAILED;
servRet = dp2dev->lpDDSCB1->Restore();
if (servRet != DD_OK)
return D3DERR_SCENE_BEGIN_FAILED;
// If TLVbuf was really lost
if (dp2dev->TLVbuf_GetVBI()->position.lpvData == 0)
{
DPF(10, "Need to reallocate TLVbuf");
// Reallocate TLVbuf of the orig size in the same memory location as before
dp2dev->TLVbuf_base = 0;
DWORD origSize = dp2dev->TLVbuf_size;
dp2dev->TLVbuf_size = 0;
if (dp2dev->TLVbuf_Grow(origSize, (this->dwDeviceFlags & D3DDEV_TLVBUFWRITEONLY) != 0) != DD_OK)
{
D3D_ERR( "Out of memory in BeginScene (TLVbuf)" );
return DDERR_OUTOFMEMORY;
}
}
// Release current VB since it could be app created and app might want
// to get rid of it due to the mode change.
if (dp2dev->lpDP2CurrBatchVBI)
{
dp2dev->lpDP2CurrBatchVBI->lpDevIBatched = NULL;
dp2dev->lpDP2CurrBatchVBI->Release();
}
dp2dev->lpDP2CurrBatchVBI = dp2dev->TLVbuf_GetVBI();
dp2dev->lpDP2CurrBatchVBI->AddRef();
dp2dev->dp2data.lpDDVertex = DDSLCL(dp2dev->TLVbuf_GetDDS());
dp2dev->dp2data.dwVertexLength = 0;
#ifdef VTABLE_HACK
dp2dev->VtblDrawPrimitiveDefault();
dp2dev->VtblDrawPrimitiveVBDefault();
dp2dev->VtblDrawIndexedPrimitiveDefault();
dp2dev->VtblDrawIndexedPrimitiveVBDefault();
#endif
}
servRet = this->CheckSurfaces();
if(servRet != D3D_OK)
return servRet;
this->dwFEFlags &= ~D3DFE_LOSTSURFACES;
}
else
return DDERR_SURFACELOST;
}
else
{
// Render target and / or the z buffer was locked
return servRet;
}
}
else
{
// We need to check if TLVbuf was lost. The app could have restored
// all surfaces and thus we might not know by check TCL. However the
// BreakLock function would have been called on the VB and the position.lpvData
// would be set to NULL. We check this to detect that the TLVbuf was lost.
if (IS_DP2HAL_DEVICE(this))
{
CDirect3DDeviceIDP2 *dp2dev = static_cast<CDirect3DDeviceIDP2*>(this);
// If the lock was broken
if (dp2dev->TLVbuf_GetVBI()->position.lpvData == 0)
{
DPF(10, "Broken lock on TLVbuf. Need to reallocate");
// Reallocate TLVbuf of the orig size in the same memory location as before
dp2dev->TLVbuf_base = 0;
DWORD origSize = dp2dev->TLVbuf_size;
dp2dev->TLVbuf_size = 0;
if (dp2dev->TLVbuf_Grow(origSize, (this->dwDeviceFlags & D3DDEV_TLVBUFWRITEONLY) != 0) != DD_OK)
{
D3D_ERR( "Out of memory in BeginScene (TLVbuf)" );
return DDERR_OUTOFMEMORY;
}
}
}
}
if (IS_DX7HAL_DEVICE(this))
{
if (this->dwFEFlags & D3DFE_RECORDSTATEMODE)
{
D3D_ERR("Cannot be recording state macros when calling BeginScene");
return (D3DERR_SCENE_END_FAILED);
}
servRet = SetRenderStateI((D3DRENDERSTATETYPE)D3DRENDERSTATE_SCENECAPTURE, TRUE);
}
else
servRet = D3DHAL_SceneCapture(this, TRUE);
if (servRet != D3D_OK && servRet != DDERR_NOTFOUND)
{
D3D_ERR("Could not BeginScene.");
return D3DERR_SCENE_BEGIN_FAILED;
}
#ifdef PROFILE4
if (++dwFrameCount == m_dwProfStart)
{
OutputDebugString("Direct3D IM 7.0: Started Profiling...\n");
StartProfile(PROFILE_THREADLEVEL, PROFILE_CURRENTID);
}
else if (dwFrameCount == m_dwProfStop)
{
StopProfile(PROFILE_THREADLEVEL, PROFILE_CURRENTID);
OutputDebugString("Direct3D IM 7.0: Stopped Profiling.\n");
}
#endif
#ifdef PROFILE
if (++dwFrameCount == m_dwProfStart)
{
OutputDebugString("Direct3D IM 7.0: Started Profiling...\n");
StartCAP();
}
else if (dwFrameCount == m_dwProfStop)
{
StopCAP();
OutputDebugString("Direct3D IM 7.0: Stopped Profiling.\n");
}
#endif
// So that currently bound textures get scene stamped
m_dwStageDirty = (1ul << this->dwMaxTextureBlendStages) - 1ul;
this->dwFEFlags |= D3DFE_NEED_TEXTURE_UPDATE;
#if COLLECTSTATS
this->lpDirect3DI->lpTextureManager->ResetStatCounters();
this->ResetTexStats();
#endif
this->dwHintFlags |= D3DDEVBOOL_HINTFLAGS_INSCENE;
return (D3D_OK);
}
catch (HRESULT ret)
{
return ret;
}
}
#if COLLECTSTATS
#undef DPF_MODNAME
#define DPF_MODNAME "Direct3DDevice::DisplayStats"
void DIRECT3DDEVICEI::DisplayStats()
{
HDC hDC;
if(SUCCEEDED(this->lpDDSTarget_DDS7->GetDC(&hDC)))
{
HFONT hOldFont = (HFONT)SelectObject(hDC, this->lpDirect3DI->m_hFont);
SetTextColor(hDC, RGB(255,255,0));
SetBkMode(hDC, TRANSPARENT);
D3DDEVINFO_TEXTUREMANAGER stats;
GetInfo(D3DDEVINFOID_TEXTUREMANAGER, &stats, sizeof(D3DDEVINFO_TEXTUREMANAGER));
char str[256];
int x = STATS_FONT_SIZE, y = STATS_FONT_SIZE, len;
len = sprintf(str, "Texture Cache Management Statistics");
TextOut( hDC, x, y, str, len );
y += STATS_FONT_SIZE;
len = sprintf(str, "-----------------------------------");
TextOut( hDC, x, y, str, len );
y += STATS_FONT_SIZE;
len = sprintf(str, "Thrashing : %s", stats.bThrashing ? "Yes" : "No");
TextOut( hDC, x, y, str, len );
y += STATS_FONT_SIZE;
len = sprintf(str, "Downloaded : %d bytes", stats.dwApproxBytesDownloaded);
TextOut( hDC, x, y, str, len );
y += STATS_FONT_SIZE;
len = sprintf(str, "Evicts : %d", stats.dwNumEvicts);
TextOut( hDC, x, y, str, len );
y += STATS_FONT_SIZE;
len = sprintf(str, "Creates : %d", stats.dwNumVidCreates);
TextOut( hDC, x, y, str, len );
y += STATS_FONT_SIZE;
len = sprintf(str, "Textures used : %d", stats.dwNumTexturesUsed);
TextOut( hDC, x, y, str, len );
y += STATS_FONT_SIZE;
len = sprintf(str, "Hit rate : %d%%", stats.dwNumTexturesUsed != 0 ? ((stats.dwNumUsedTexInVid * 100) / stats.dwNumTexturesUsed) : 0);
TextOut( hDC, x, y, str, len );
y += STATS_FONT_SIZE;
len = sprintf(str, "Working set : %d (%d bytes)", stats.dwWorkingSet, stats.dwWorkingSetBytes);
TextOut( hDC, x, y, str, len );
y += STATS_FONT_SIZE;
len = sprintf(str, "Total managed : %d (%d bytes)", stats.dwTotalManaged, stats.dwTotalBytes);
TextOut( hDC, x, y, str, len );
D3DDEVINFO_TEXTURING texstats;
GetInfo(D3DDEVINFOID_TEXTURING, &texstats, sizeof(D3DDEVINFO_TEXTURING));
y += STATS_FONT_SIZE * 2;
len = sprintf(str, "Texturing Statistics");
TextOut( hDC, x, y, str, len );
y += STATS_FONT_SIZE;
len = sprintf(str, "--------------------");
TextOut( hDC, x, y, str, len );
y += STATS_FONT_SIZE;
len = sprintf(str, "Loads : %d (%d bytes)", texstats.dwNumLoads, texstats.dwApproxBytesLoaded);
TextOut( hDC, x, y, str, len );
y += STATS_FONT_SIZE;
len = sprintf(str, "PreLoads : %d", texstats.dwNumPreLoads);
TextOut( hDC, x, y, str, len );
y += STATS_FONT_SIZE;
len = sprintf(str, "SetTextures : %d", texstats.dwNumSet);
TextOut( hDC, x, y, str, len );
y += STATS_FONT_SIZE;
len = sprintf(str, "Creates : %d", texstats.dwNumCreates);
TextOut( hDC, x, y, str, len );
y += STATS_FONT_SIZE;
len = sprintf(str, "Destroys : %d", texstats.dwNumDestroys);
TextOut( hDC, x, y, str, len );
y += STATS_FONT_SIZE;
len = sprintf(str, "SetPriorities : %d", texstats.dwNumSetPriorities);
TextOut( hDC, x, y, str, len );
y += STATS_FONT_SIZE;
len = sprintf(str, "SetLODs : %d", texstats.dwNumSetLODs);
TextOut( hDC, x, y, str, len );
y += STATS_FONT_SIZE;
len = sprintf(str, "Locks : %d", texstats.dwNumLocks);
TextOut( hDC, x, y, str, len );
y += STATS_FONT_SIZE;
len = sprintf(str, "GetDCs : %d", texstats.dwNumGetDCs);
TextOut( hDC, x, y, str, len );
SelectObject(hDC, hOldFont);
this->lpDDSTarget_DDS7->ReleaseDC(hDC);
}
}
#endif
#undef DPF_MODNAME
#define DPF_MODNAME "Direct3DDevice::EndScene"
HRESULT D3DAPI DIRECT3DDEVICEI::EndScene()
{
HRESULT servRet;
try
{
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
if (!VALID_DIRECT3DDEVICE_PTR(this))
{
D3D_ERR( "Invalid Direct3DDevice pointer" );
return DDERR_INVALIDOBJECT;
}
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))
{
if (this->dwFEFlags & D3DFE_RECORDSTATEMODE)
{
D3D_ERR("Cannot be recording state macros when calling EndScene");
return (D3DERR_SCENE_END_FAILED);
}
servRet = SetRenderStateI((D3DRENDERSTATETYPE)D3DRENDERSTATE_SCENECAPTURE, FALSE);
if (servRet != D3D_OK)
{
D3D_ERR("Could not send EndScene to Driver!");
return (D3DERR_SCENE_END_FAILED);
}
servRet = FlushStates(); //time to flush DrawPrimitives
}
else
{
servRet = FlushStates(); //time to flush DrawPrimitives
if (servRet != D3D_OK)
{
D3D_ERR("Could not Flush commands in EndScene!");
return (D3DERR_SCENE_END_FAILED);
}
servRet = D3DHAL_SceneCapture(this, FALSE);
}
if (servRet != D3D_OK && servRet != DDERR_NOTFOUND)
{
DPF(0, "(ERROR) Direct3DDevice::EndScene: Could not EndScene. Returning %08lx", 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;
}
// Update the scene count in texman
lpDirect3DI->lpTextureManager->SceneStamp();
// Clear num TLVbuf changes per frame
if (IS_DP2HAL_DEVICE(this))
{
CDirect3DDeviceIDP2* dev = static_cast<CDirect3DDeviceIDP2*>(this);
dev->dwTLVbufChanges = 0;
}
#if COLLECTSTATS
// Display stats if they have been enabled via regkey
if(this->lpDirect3DI->m_hFont != 0)
{
DisplayStats();
}
#endif
return (D3D_OK);
}
catch (HRESULT ret)
{
return ret;
}
}
void
D3DDeviceDescConvert(LPD3DDEVICEDESC7 lpOut,
LPD3DDEVICEDESC_V1 lpV1,
LPD3DHAL_D3DEXTENDEDCAPS lpExt)
{
if( lpV1 )
{
lpOut->dwDevCaps = lpV1->dwDevCaps;
lpOut->dpcLineCaps = lpV1->dpcLineCaps;
lpOut->dpcTriCaps = lpV1->dpcTriCaps;
lpOut->dwDeviceRenderBitDepth = lpV1->dwDeviceRenderBitDepth;
lpOut->dwDeviceZBufferBitDepth = lpV1->dwDeviceZBufferBitDepth;
}
if (lpExt)
{
// DX5
lpOut->dwMinTextureWidth = lpExt->dwMinTextureWidth;
lpOut->dwMaxTextureWidth = lpExt->dwMaxTextureWidth;
lpOut->dwMinTextureHeight = lpExt->dwMinTextureHeight;
lpOut->dwMaxTextureHeight = lpExt->dwMaxTextureHeight;
// 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;
// DX7
lpOut->dwMaxActiveLights = lpExt->dwMaxActiveLights;
lpOut->dvMaxVertexW = lpExt->dvMaxVertexW;
lpOut->wMaxUserClipPlanes = lpExt->wMaxUserClipPlanes;
lpOut->wMaxVertexBlendMatrices = lpExt->wMaxVertexBlendMatrices;
lpOut->dwVertexProcessingCaps = lpExt->dwVertexProcessingCaps;
lpOut->dwReserved1 = lpExt->dwReserved1;
lpOut->dwReserved2 = lpExt->dwReserved2;
lpOut->dwReserved3 = lpExt->dwReserved3;
lpOut->dwReserved4 = lpExt->dwReserved4;
}
}
//---------------------------------------------------------------------
#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;
}
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DIRECT3DDEVICEI::GetDirect3D"
HRESULT D3DAPI DIRECT3DDEVICEI::GetDirect3D(LPDIRECT3D7 *lplpD3D)
{
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
if (!VALID_DIRECT3DDEVICE_PTR(this))
{
D3D_ERR( "Invalid Direct3DDevice pointer" );
return DDERR_INVALIDOBJECT;
}
if (!VALID_OUTPTR(lplpD3D))
{
D3D_ERR( "Invalid Direct3D pointer pointer" );
return DDERR_INVALIDPARAMS;
}
*lplpD3D = (LPDIRECT3D7) this->lpDirect3DI;
(*lplpD3D)->AddRef();
return (D3D_OK);
}
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DIRECT3DDEVICEI::HookTexture"
LPD3DI_TEXTUREBLOCK DIRECT3DDEVICEI::HookTexture(LPDIRECT3DTEXTUREI lpD3DText)
{
LPD3DI_TEXTUREBLOCK nBlock;
if (D3DMalloc((void**)&nBlock, sizeof(D3DI_TEXTUREBLOCK)) != D3D_OK)
{
D3D_ERR("failed to allocate space for texture block");
return NULL;
}
nBlock->lpDevI = this;
nBlock->lpD3DTextureI = lpD3DText;
nBlock->hTex = 0; // initialized to be zero
LIST_INSERT_ROOT(&lpD3DText->blocks, nBlock, list);
LIST_INSERT_ROOT(&texBlocks, nBlock, devList);
return nBlock;
}
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DIRECT3DDEVICEI::D3DI_FindTextureBlock"
LPD3DI_TEXTUREBLOCK DIRECT3DDEVICEI::D3DI_FindTextureBlock(LPDIRECT3DTEXTUREI lpTex)
{
LPD3DI_TEXTUREBLOCK tBlock;
tBlock = LIST_FIRST(&lpTex->blocks);
while (tBlock) {
// return match for Texture(2) only (not Texture3)
if (tBlock->lpDevI == this) {
return tBlock;
}
tBlock = LIST_NEXT(tBlock,list);
}
return NULL;
}
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DIRECT3DDEVICEI::GetTextureDDIHandle"
HRESULT DIRECT3DDEVICEI::GetTextureDDIHandle(LPDIRECT3DTEXTUREI lpTexI,
LPD3DI_TEXTUREBLOCK* lplpBlock)
{
HRESULT ret;
LPD3DI_TEXTUREBLOCK lpBlock=*lplpBlock; //in case has the pointer
DDASSERT(lpTexI);
/*
* Find out if we've used this device before.
*/
if (!lpBlock)
{
lpBlock = D3DI_FindTextureBlock(lpTexI);
if (!lpBlock)
{
/*
* Put this device in the list of those owned by the
* Direct3DDevice object
*/
lpBlock=HookTexture(lpTexI);
if (!lpBlock)
{
D3D_ERR("failed to associate texture with device");
return DDERR_OUTOFMEMORY;
}
}
*lplpBlock = lpBlock;
}
if (!lpBlock->hTex)
{
if (lpTexI->D3DManaged())
{
if(!lpTexI->InVidmem()) // This check covers the case when hTex is zero,
// but there ALREADY IS a vidmem copy don't
// create another one. This case arises when
// InvalidateHandles() is called by SetRenderTarget.
{
ret = lpDirect3DI->lpTextureManager->allocNode(lpTexI, this);
if (D3D_OK != ret)
{
D3D_ERR("Failed to create video memory surface");
return ret;
}
}
lpDirect3DI->lpTextureManager->TimeStamp(lpTexI);
}
CLockD3DST lockObject(this, DPF_MODNAME, REMIND(""));
if (D3D_OK != (ret=D3DHAL_TextureCreate(this, &lpBlock->hTex, (LPDIRECTDRAWSURFACE)&(lpTexI->DDS1Tex))))
return ret;
}
else
{
if(lpTexI->D3DManaged())
lpDirect3DI->lpTextureManager->TimeStamp(lpTexI);
}
DDASSERT(lpBlock->hTex);
return D3D_OK;
}
#if COLLECTSTATS
#undef DPF_MODNAME
#define DPF_MODNAME "BytesDownloaded"
DWORD BytesDownloaded(LPDDRAWI_DDRAWSURFACE_LCL lpLcl, LPRECT lpRect)
{
DWORD bytes;
if( (lpLcl->dwFlags & DDRAWISURF_HASPIXELFORMAT) &&
(lpLcl->lpGbl->ddpfSurface.dwFlags & DDPF_FOURCC) )
{
switch (lpLcl->lpGbl->ddpfSurface.dwFourCC)
{
case FOURCC_DXT1:
case FOURCC_DXT2:
case FOURCC_DXT3:
case FOURCC_DXT4:
case FOURCC_DXT5:
if(lpRect == NULL)
{
bytes = lpLcl->lpGbl->dwLinearSize;
}
else
{
bytes = (DWORD)(lpLcl->lpGbl->dwLinearSize * (double((lpRect->right - lpRect->left) * (lpRect->bottom - lpRect->top)) /
double(lpLcl->lpGbl->wWidth * lpLcl->lpGbl->wHeight)));
}
return lpLcl->lpSurfMore->dwMipMapCount == 0 ? bytes : (DWORD)(bytes * ((1. - pow(.25, lpLcl->lpSurfMore->dwMipMapCount)) / .75));
}
}
if(lpRect == NULL)
{
bytes = lpLcl->lpGbl->lPitch * lpLcl->lpGbl->wHeight;
}
else
{
bytes = (DWORD)(lpLcl->lpGbl->lPitch * lpLcl->lpGbl->wHeight *
(double((lpRect->right - lpRect->left) * (lpRect->bottom - lpRect->top)) /
double(lpLcl->lpGbl->wWidth * lpLcl->lpGbl->wHeight)));
}
return lpLcl->lpSurfMore->dwMipMapCount == 0 ? bytes : (DWORD)(bytes * ((1. - pow(.25, lpLcl->lpSurfMore->dwMipMapCount)) / .75));
}
#endif
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DIRECT3DDEVICEI::PreLoad"
HRESULT D3DAPI DIRECT3DDEVICEI::PreLoad(LPDIRECTDRAWSURFACE7 lpSrc)
{
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
// Release in the destructor
if(!(this->dwFEFlags & D3DFE_REALHAL))
{
D3D_WARN(2, "PreLoad called on a software device");
return D3D_OK;
}
return PreLoadFast(lpSrc);
}
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DIRECT3DDEVICEI::PreLoadFast"
HRESULT D3DAPI DIRECT3DDEVICEI::PreLoadFast(LPDIRECTDRAWSURFACE7 lpSrc)
{
#if DBG
if (!VALID_DIRECT3DDEVICE_PTR(this))
{
D3D_ERR( "Invalid DIRECT3DDEVICE7 pointer" );
return DDERR_INVALIDOBJECT;
}
if (!VALID_DDSURF_PTR(lpSrc))
{
D3D_ERR( "Invalid DIRECTDRAWSURFACE7 source pointer" );
return DDERR_INVALIDOBJECT;
}
if(!IsToplevel(((LPDDRAWI_DDRAWSURFACE_INT)lpSrc)->lpLcl))
{
D3D_ERR( "Cannot PreLoad a mipmap sublevel or a cubemap subface" );
return DDERR_INVALIDPARAMS;
}
#endif
LPDIRECT3DTEXTUREI this_src = reinterpret_cast<LPDIRECT3DTEXTUREI>(((LPDDRAWI_DDRAWSURFACE_INT)lpSrc)->lpLcl->lpSurfMore->lpTex);
#if DBG
if (this_src == NULL)
{
D3D_ERR( "Not a texture" );
return DDERR_INVALIDPARAMS;
}
#endif
#if COLLECTSTATS
this->IncNumPreLoads();
#endif
try
{
HRESULT ddrval = D3D_OK;
if (!this_src->D3DManaged())
{
#if DBG
// Make sure that texture is driver managed
if(!(DDSCAPS2_TEXTUREMANAGE & ((LPDDRAWI_DDRAWSURFACE_INT)(this_src->lpDDS))->lpLcl->lpSurfMore->ddsCapsEx.dwCaps2))
{
D3D_ERR( "Cannot PreLoad unmanaged textures" );
return DDERR_INVALIDPARAMS;
}
#endif
if(this->lpDirect3DI->numDevs > 1)
{
D3D_WARN(2, "Multiple devices used. Calling Flush");
ddrval = this->lpDirect3DI->FlushDevicesExcept(this); // to avoid sync problems
if(ddrval != D3D_OK)
{
D3D_ERR("Error flushing devices");
return ddrval;
}
}
POINT p = {0, 0};
RECTL r = {0, 0, 0, 0};
DDASSERT(IS_DX7HAL_DEVICE(this));
ddrval = static_cast<CDirect3DDevice7*>(this)->TexBltI(NULL, ((LPDDRAWI_DDRAWSURFACE_INT)(this_src->lpDDS))->lpLcl, &p, &r, 0);
if(ddrval != D3D_OK)
{
DPF_ERR("Error inserting TexBlt instruction in batch");
return ddrval;
}
if(this->lpDirect3DI->numDevs > 1)
{
ddrval = FlushStates(); // to avoid sync problems
if(ddrval != D3D_OK)
{
D3D_ERR("Error flushing device");
return ddrval;
}
}
else
{
BatchTexture(((LPDDRAWI_DDRAWSURFACE_INT)(this_src->lpDDS))->lpLcl);
}
}
else if (this_src->InVidmem())
{
if (this_src->bDirty)
{
// 0xFFFFFFFF is equivalent to ALL_FACES, but in addition indicates to CopySurface
// that this is a sysmem -> vidmem transfer.
ddrval = CopySurface(this_src->lpDDS,NULL,this_src->lpDDSSys,NULL,0xFFFFFFFF);
if (DD_OK == ddrval)
{
this_src->bDirty=FALSE;
D3D_INFO(4,"Load: Dirty texture updated");
}
}
#if COLLECTSTATS
this->lpDirect3DI->lpTextureManager->IncNumTexturesSet();
this->lpDirect3DI->lpTextureManager->IncNumSetTexInVid();
#endif
}
else
{
if(IS_DX7HAL_DEVICE(this))
{
D3DTEXTUREHANDLE hTex;
ddrval = static_cast<CDirect3DDevice7*>(this)->GetTextureDDIHandle(this_src, &hTex);
}
else
{
LPD3DI_TEXTUREBLOCK lpBlock = NULL;
ddrval = GetTextureDDIHandle(this_src, &lpBlock);
}
#if COLLECTSTATS
this->lpDirect3DI->lpTextureManager->IncNumTexturesSet();
#endif
}
return ddrval;
}
catch (HRESULT ret)
{
return ret;
}
}
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DIRECT3DDEVICEI::Load"
HRESULT D3DAPI DIRECT3DDEVICEI::Load(LPDIRECTDRAWSURFACE7 lpDest, LPPOINT lpDestPoint,
LPDIRECTDRAWSURFACE7 lpSrc, LPRECT lpSrcRect, DWORD dwFlags)
{
LPDIRECT3DTEXTUREI this_src, this_dst;
HRESULT ddrval = D3D_OK;
LPDIRECTDRAWSURFACE7 lpDDSSrc, lpDDSDst;
try
{
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock (can't take MT since code accesses DDraw surf global)
// Release in the destructor
#if DBG
// validate args
if(lpDestPoint != NULL && lpSrcRect == NULL)
{
D3D_ERR( "Cannot have NULL src rect and non-NULL dest" );
return DDERR_INVALIDPARAMS;
}
if(lpDestPoint != NULL)
{
if(!VALID_GDIPOINT_PTR(lpDestPoint))
{
D3D_ERR( "Invalid POINT pointer" );
return DDERR_INVALIDOBJECT;
}
}
if(lpSrcRect != NULL)
{
if(!VALID_GDIRECT_PTR(lpSrcRect))
{
D3D_ERR( "Invalid RECT pointer" );
return DDERR_INVALIDOBJECT;
}
}
if(dwFlags & (~DDSCAPS2_CUBEMAP_ALLFACES))
{
D3D_ERR( "Invalid flags" );
return DDERR_INVALIDPARAMS;
}
if (!VALID_DIRECT3DDEVICE_PTR(this))
{
D3D_ERR( "Invalid DIRECT3DDEVICE7 pointer" );
return DDERR_INVALIDOBJECT;
}
if (!VALID_DDSURF_PTR(lpDest))
{
D3D_ERR( "Invalid DIRECTDRAWSURFACE7 dest pointer" );
return DDERR_INVALIDOBJECT;
}
if(!IsToplevel(((LPDDRAWI_DDRAWSURFACE_INT)lpDest)->lpLcl))
{
D3D_ERR( "Cannot Load to a mipmap sublevel or a cubemap subface" );
return DDERR_INVALIDPARAMS;
}
#endif
this_dst = reinterpret_cast<LPDIRECT3DTEXTUREI>(((LPDDRAWI_DDRAWSURFACE_INT)lpDest)->lpLcl->lpSurfMore->lpTex);
#if DBG
if(this_dst == NULL)
{
D3D_ERR( "Destination surface not a texture" );
return DDERR_INVALIDPARAMS;
}
if (!VALID_DDSURF_PTR(lpSrc))
{
D3D_ERR( "Invalid DIRECTDRAWSURFACE7 source pointer" );
return DDERR_INVALIDOBJECT;
}
if(!IsToplevel(((LPDDRAWI_DDRAWSURFACE_INT)lpSrc)->lpLcl))
{
D3D_ERR( "Cannot Load from a mipmap sublevel or a cubemap subface" );
return DDERR_INVALIDPARAMS;
}
#endif
this_src = reinterpret_cast<LPDIRECT3DTEXTUREI>(((LPDDRAWI_DDRAWSURFACE_INT)lpSrc)->lpLcl->lpSurfMore->lpTex);
#if DBG
if(this_src == NULL)
{
D3D_ERR( "Source surface not a texture" );
return DDERR_INVALIDPARAMS;
}
#endif
#if COLLECTSTATS
this->IncNumLoads();
#endif
if(this_src->D3DManaged())
lpDDSSrc = this_src->lpDDSSys;
else
lpDDSSrc = this_src->lpDDS;
RECT destRect, *lpDestRect;
if(lpDestPoint)
{
if(IsRectEmpty(lpSrcRect))
{
D3D_ERR( "Source rectangle is empty" );
return DDERR_INVALIDPARAMS;
}
WORD &width = ((LPDDRAWI_DDRAWSURFACE_INT)lpDDSSrc)->lpLcl->lpGbl->wWidth;
WORD &height = ((LPDDRAWI_DDRAWSURFACE_INT)lpDDSSrc)->lpLcl->lpGbl->wHeight;
if(lpSrcRect->left < 0 ||
lpSrcRect->left >= width ||
lpSrcRect->top < 0 ||
lpSrcRect->top >= height ||
lpSrcRect->right <= 0 ||
lpSrcRect->right > width ||
lpSrcRect->bottom <= 0 ||
lpSrcRect->bottom > height)
{
D3D_ERR( "Rectangle outside source texture" );
return DDERR_INVALIDPARAMS;
}
destRect.left = lpDestPoint->x;
destRect.top = lpDestPoint->y;
destRect.right = lpDestPoint->x + (lpSrcRect->right - lpSrcRect->left);
destRect.bottom = lpDestPoint->y + (lpSrcRect->bottom - lpSrcRect->top);
lpDestRect = &destRect;
if(lpDestRect->left < 0 ||
lpDestRect->left >= width ||
lpDestRect->top < 0 ||
lpDestRect->top >= height ||
lpDestRect->right <= 0 ||
lpDestRect->right > width ||
lpDestRect->bottom <= 0 ||
lpDestRect->bottom > height)
{
D3D_ERR( "Rectangle outside destination texture" );
return DDERR_INVALIDPARAMS;
}
}
else
{
if(lpSrcRect)
{
if(IsRectEmpty(lpSrcRect))
{
D3D_ERR( "Source rectangle is empty" );
return DDERR_INVALIDPARAMS;
}
WORD &width = ((LPDDRAWI_DDRAWSURFACE_INT)lpDDSSrc)->lpLcl->lpGbl->wWidth;
WORD &height = ((LPDDRAWI_DDRAWSURFACE_INT)lpDDSSrc)->lpLcl->lpGbl->wHeight;
if(lpSrcRect->left < 0 ||
lpSrcRect->left >= width ||
lpSrcRect->top < 0 ||
lpSrcRect->top >= height ||
lpSrcRect->right <= 0 ||
lpSrcRect->right > width ||
lpSrcRect->bottom <= 0 ||
lpSrcRect->bottom > height)
{
D3D_ERR( "Source rectangle outside texture" );
return DDERR_INVALIDPARAMS;
}
destRect = *lpSrcRect;
lpDestRect = &destRect;
}
else
{
lpDestRect = NULL;
}
}
if(this_dst->D3DManaged())
lpDDSDst = this_dst->lpDDSSys;
else
lpDDSDst = this_dst->lpDDS;
ddrval = CopySurface(lpDDSDst, lpDestRect, lpDDSSrc, lpSrcRect, dwFlags);
return ddrval;
}
catch (HRESULT ret)
{
return ret;
}
}
#undef DPF_MODNAME
#define DPF_MODNAME "DIRECT3DDEVICEI::CanDoTexBlt"
bool DIRECT3DDEVICEI::CanDoTexBlt(LPDDRAWI_DDRAWSURFACE_LCL lpDDSSrcSubFace_lcl,
LPDDRAWI_DDRAWSURFACE_LCL lpDDSDstSubFace_lcl)
{
return false;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DIRECT3DDEVICEI::CopySurface"
HRESULT DIRECT3DDEVICEI::CopySurface(LPDIRECTDRAWSURFACE7 lpDDSDst,
LPRECT lpDestRect,
LPDIRECTDRAWSURFACE7 lpDDSSrc,
LPRECT lpSrcRect,
DWORD dwFlags)
{
DDRAWI_DDRAWSURFACE_INT DDSSrcSubFace, DDSDstSubFace;
DDSSrcSubFace.lpVtbl = DDSDstSubFace.lpVtbl = ((LPDDRAWI_DDRAWSURFACE_INT)lpDDSSrc)->lpVtbl;
DDSDstSubFace.lpLcl = ((LPDDRAWI_DDRAWSURFACE_INT)lpDDSDst)->lpLcl;
DDSSrcSubFace.lpLcl = ((LPDDRAWI_DDRAWSURFACE_INT)lpDDSSrc)->lpLcl;
LPDIRECTDRAWSURFACE7 lpDDSSrcSubFace = reinterpret_cast<LPDIRECTDRAWSURFACE7>(&DDSSrcSubFace);
LPDIRECTDRAWSURFACE7 lpDDSDstSubFace = reinterpret_cast<LPDIRECTDRAWSURFACE7>(&DDSDstSubFace);
CCubemapIter cmsrc(DDSSrcSubFace.lpLcl), cmdst(DDSDstSubFace.lpLcl);
while(true)
{
DDSSrcSubFace.lpLcl = cmsrc();
DDSDstSubFace.lpLcl = cmdst();
DWORD face = DDSSrcSubFace.lpLcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
if(face != (DDSDstSubFace.lpLcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES))
{
D3D_ERR("Destination texture has different cubemap faces than source");
return DDERR_INVALIDPARAMS;
}
if(face == 0 || (DDSSrcSubFace.lpLcl->lpSurfMore->ddsCapsEx.dwCaps2 & dwFlags))
{
HRESULT ddrval = D3D_OK;
DWORD psize = 0;
if (DDSDstSubFace.lpLcl->lpDDPalette)
{
if(DDSSrcSubFace.lpLcl->lpDDPalette)
{
const DWORD paltype = DDPF_PALETTEINDEXED8 | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED2 | DDPF_PALETTEINDEXED1;
if((PixelFormat(DDSDstSubFace.lpLcl).dwFlags & paltype) != (PixelFormat(DDSSrcSubFace.lpLcl).dwFlags & paltype))
{
D3D_ERR("Src texture is has a different type of palette than dest");
return DDERR_INVALIDPARAMS;
}
switch(PixelFormat(DDSDstSubFace.lpLcl).dwFlags & paltype)
{
case DDPF_PALETTEINDEXED1:
psize = 2;
break;
case DDPF_PALETTEINDEXED2:
psize = 4;
break;
case DDPF_PALETTEINDEXED4:
psize = 16;
break;
case DDPF_PALETTEINDEXED8:
psize = 256;
break;
default:
D3D_ERR("Paletted texture format not supported");
return E_NOTIMPL;
}
ddrval = (reinterpret_cast<LPDIRECTDRAWPALETTE>(DDSDstSubFace.lpLcl->lpDDPalette))->SetEntries(0, 0, psize, DDSSrcSubFace.lpLcl->lpDDPalette->lpLcl->lpGbl->lpColorTable);
if (ddrval != DD_OK)
{
D3D_ERR("Failed to set palette entries in dest texture");
return ddrval;
}
}
else
{
D3D_WARN(2, "Destination texture has palette, but source has none");
}
}
/* Copy color keys */
if(DDSSrcSubFace.lpLcl->dwFlags & DDRAWISURF_HASCKEYDESTBLT)
lpDDSDstSubFace->SetColorKey(DDCKEY_DESTBLT, &DDSSrcSubFace.lpLcl->ddckCKDestBlt);
else if(DDSDstSubFace.lpLcl->dwFlags & DDRAWISURF_HASCKEYDESTBLT)
lpDDSDstSubFace->SetColorKey(DDCKEY_DESTBLT, NULL);
if(DDSSrcSubFace.lpLcl->dwFlags & DDRAWISURF_HASCKEYSRCBLT)
lpDDSDstSubFace->SetColorKey(DDCKEY_SRCBLT, &DDSSrcSubFace.lpLcl->ddckCKSrcBlt);
else if(DDSDstSubFace.lpLcl->dwFlags & DDRAWISURF_HASCKEYSRCBLT)
lpDDSDstSubFace->SetColorKey(DDCKEY_SRCBLT, NULL);
DDRAWI_DDRAWSURFACE_INT DDSSrcSubMip, DDSDstSubMip;
DDSSrcSubMip.lpVtbl = DDSDstSubMip.lpVtbl = DDSSrcSubFace.lpVtbl;
DDSDstSubMip.lpLcl = DDSDstSubFace.lpLcl;
DDSSrcSubMip.lpLcl = DDSSrcSubFace.lpLcl;
LPDIRECTDRAWSURFACE7 lpDDSSrcSubMip = reinterpret_cast<LPDIRECTDRAWSURFACE7>(&DDSSrcSubMip);
LPDIRECTDRAWSURFACE7 lpDDSDstSubMip = reinterpret_cast<LPDIRECTDRAWSURFACE7>(&DDSDstSubMip);
RECT SrcRct, DstRct, *lpSrcRct, *lpDstRct;
if(lpSrcRect)
{
SrcRct = *lpSrcRect;
lpSrcRct = &SrcRct;
}
else
lpSrcRct = NULL;
if(lpDestRect)
{
DstRct = *lpDestRect;
lpDstRct = &DstRct;
}
else
lpDstRct = NULL;
CMipmapIter mmsrc(DDSSrcSubMip.lpLcl), mmdst(DDSDstSubMip.lpLcl);
unsigned srcmipoff = 0;
while(mmsrc()->lpGbl->wHeight != mmdst()->lpGbl->wHeight || mmsrc()->lpGbl->wWidth != mmdst()->lpGbl->wWidth)
{
//
// _COMPUTE_NEXT_LOD_RECT - Computes rectangle (in place) for next smaller LOD in mip
// chain. Top & left are divided by two, which effectively rounds down (via truncation).
// Bottom & right are incremented prior to truncated-division, which will round up.
// Result is guaranteed to be at least 1x1 in size.
//
#define _COMPUTE_NEXT_LOD_RECT( m_pRct ) \
{ \
(m_pRct)->left >>= 1; \
(m_pRct)->top >>= 1; \
DWORD right = ((m_pRct)->right +1) >> 1; \
DWORD bottom = ((m_pRct)->bottom+1) >> 1; \
(m_pRct)->right = ((right - (m_pRct)->left) < 1) ? ((m_pRct)->left+1) : (right); \
(m_pRct)->bottom = ((bottom - (m_pRct)->top ) < 1) ? ((m_pRct)->top +1) : (bottom); \
}
if(lpSrcRct)
{
_COMPUTE_NEXT_LOD_RECT(lpSrcRct)
}
if(lpDstRct)
{
_COMPUTE_NEXT_LOD_RECT(lpDstRct)
}
++srcmipoff;
++mmsrc;
if(mmsrc == 0)
{
D3D_ERR("Size mismatch between source and destination textures");
return DDERR_INVALIDPARAMS;
}
}
DWORD dstmipcnt = DDSDstSubMip.lpLcl->lpSurfMore->dwMipMapCount == 0 ? 1 : DDSDstSubMip.lpLcl->lpSurfMore->dwMipMapCount;
DWORD srcmipcnt = DDSSrcSubMip.lpLcl->lpSurfMore->dwMipMapCount == 0 ? 1 : DDSSrcSubMip.lpLcl->lpSurfMore->dwMipMapCount;
if(dstmipcnt != (srcmipcnt - srcmipoff))
{
if(dstmipcnt > (srcmipcnt - srcmipoff))
{
D3D_ERR("Destination texture has more mipmap levels than source");
return DDERR_INVALIDPARAMS;
}
else
D3D_INFO(3, "Destination texture has fewer mipmap levels than source");
}
#if COLLECTSTATS
if(dwFlags == 0xFFFFFFFF) // texman CopySurface
this->lpDirect3DI->lpTextureManager->IncBytesDownloaded(DDSDstSubMip.lpLcl, lpDstRct);
else
this->IncBytesDownloaded(DDSDstSubMip.lpLcl, lpDstRct);
#endif
if(this->lpDirect3DI->numDevs == 1 && CanDoTexBlt(DDSSrcSubFace.lpLcl, DDSDstSubFace.lpLcl))
{
bool doblt = true;
LPREGIONLIST lpRegionList = DDSSrcSubFace.lpLcl->lpSurfMore->lpRegionList;
if(dwFlags == 0xFFFFFFFF) // 0xFFFFFFFF indicates that we
// are loading from sysmem to vidmem
// and the regionlist should be used
{
if(lpRegionList->rdh.nCount == 0)
{
doblt = false;
}
else
{
if(lpRegionList->rdh.nCount != NUM_RECTS_IN_REGIONLIST)
{
if(DDSSrcSubFace.lpLcl->lpGbl->dwUsageCount > 0
|| DDSDstSubFace.lpLcl->lpGbl->dwUsageCount > 0)
{
D3D_ERR("Surfaces locked");
return DDERR_SURFACEBUSY;
}
for(unsigned i = 0; i < lpRegionList->rdh.nCount; ++i)
{
POINT p;
p.x = lpRegionList->rect[i].left;
p.y = lpRegionList->rect[i].top;
ddrval = static_cast<CDirect3DDevice7*>(this)->TexBltI(DDSDstSubFace.lpLcl,
DDSSrcSubFace.lpLcl,
&p, &lpRegionList->rect[i], 0);
if(ddrval != D3D_OK)
{
DPF_ERR("Error inserting TexBlt instruction in batch");
return ddrval;
}
}
BatchTexture(DDSDstSubFace.lpLcl);
BatchTexture(DDSSrcSubFace.lpLcl);
doblt = false;
}
lpRegionList->rdh.nCount = 0;
lpRegionList->rdh.nRgnSize = 0;
lpRegionList->rdh.rcBound.left = LONG_MAX;
lpRegionList->rdh.rcBound.right = 0;
lpRegionList->rdh.rcBound.top = LONG_MAX;
lpRegionList->rdh.rcBound.bottom = 0;
}
}
if(doblt)
{
if(DDSSrcSubFace.lpLcl->lpGbl->dwUsageCount > 0
|| DDSDstSubFace.lpLcl->lpGbl->dwUsageCount > 0)
{
D3D_ERR("Surfaces locked");
return DDERR_SURFACEBUSY;
}
POINT p;
if(lpDstRct)
{
p.x = lpDstRct->left;
p.y = lpDstRct->top;
}
else
{
p.x = 0;
p.y = 0;
}
RECTL r;
if(lpSrcRct)
{
r = *((LPRECTL)lpSrcRct);
}
else
{
r.bottom = DDSSrcSubFace.lpLcl->lpGbl->wHeight;
r.left = 0;
r.right = DDSSrcSubFace.lpLcl->lpGbl->wWidth;
r.top = 0;
}
ddrval = static_cast<CDirect3DDevice7*>(this)->TexBltI(DDSDstSubFace.lpLcl,
DDSSrcSubFace.lpLcl,
&p, &r, 0);
if(ddrval != D3D_OK)
{
DPF_ERR("Error inserting TexBlt instruction in batch");
return ddrval;
}
BatchTexture(DDSDstSubFace.lpLcl);
BatchTexture(DDSSrcSubFace.lpLcl);
if(IsD3DManaged(DDSDstSubFace.lpLcl))
{
MarkDirty(DDSDstSubFace.lpLcl);
LPREGIONLIST lpRegionList = DDSDstSubFace.lpLcl->lpSurfMore->lpRegionList;
if(lpDstRct)
{
if(lpRegionList->rdh.nCount != NUM_RECTS_IN_REGIONLIST)
{
lpRegionList->rect[(lpRegionList->rdh.nCount)++] = *((LPRECTL)lpDstRct);
lpRegionList->rdh.nRgnSize += sizeof(RECT);
if(lpDstRct->left < lpRegionList->rdh.rcBound.left)
lpRegionList->rdh.rcBound.left = lpDstRct->left;
if(lpDstRct->right > lpRegionList->rdh.rcBound.right)
lpRegionList->rdh.rcBound.right = lpDstRct->right;
if(lpDstRct->top < lpRegionList->rdh.rcBound.top)
lpRegionList->rdh.rcBound.top = lpDstRct->top;
if(lpDstRct->bottom > lpRegionList->rdh.rcBound.bottom)
lpRegionList->rdh.rcBound.bottom = lpDstRct->bottom;
}
}
else
{
/* Mark everything dirty */
lpRegionList->rdh.nCount = NUM_RECTS_IN_REGIONLIST;
}
}
}
}
else
{
do
{
DDSSrcSubMip.lpLcl = mmsrc();
DDSDstSubMip.lpLcl = mmdst();
bool doblt = true;
LPREGIONLIST lpRegionList = DDSSrcSubMip.lpLcl->lpSurfMore->lpRegionList;
if(dwFlags == 0xFFFFFFFF) // 0xFFFFFFFF indicates that we
// are loading from sysmem to vidmem
// and the regionlist should be used.
{
if(lpRegionList->rdh.nCount == 0)
{
doblt = false;
}
else if(lpRegionList->rdh.nCount != NUM_RECTS_IN_REGIONLIST)
{
if(lpClipper->SetClipList((LPRGNDATA)lpRegionList, 0) != DD_OK)
{
D3D_ERR("Failed to set clip list");
}
if(lpDDSDstSubMip->SetClipper(lpClipper) != DD_OK)
{
D3D_ERR("Failed to detach the clipper");
}
}
}
if(doblt)
{
ddrval = lpDDSDstSubMip->Blt(lpDstRct, lpDDSSrcSubMip, lpSrcRct, DDBLT_WAIT, NULL);
}
if(dwFlags == 0xFFFFFFFF)
{
if(lpRegionList->rdh.nCount)
{
if(lpRegionList->rdh.nCount != NUM_RECTS_IN_REGIONLIST)
{
if(lpDDSDstSubMip->SetClipper(NULL) != DD_OK)
{
D3D_ERR("Failed to detach the clipper");
}
}
lpRegionList->rdh.nCount = 0;
lpRegionList->rdh.nRgnSize = 0;
lpRegionList->rdh.rcBound.left = LONG_MAX;
lpRegionList->rdh.rcBound.right = 0;
lpRegionList->rdh.rcBound.top = LONG_MAX;
lpRegionList->rdh.rcBound.bottom = 0;
}
}
if (ddrval == E_NOTIMPL && (psize == 16 || psize == 4 || psize == 2))
{
DDSURFACEDESC2 ddsd_s, ddsd_d;
LPBYTE psrc, pdst;
DWORD i;
DWORD dwBytesPerLine;
memset(&ddsd_s, 0, sizeof ddsd_s);
memset(&ddsd_d, 0, sizeof ddsd_d);
ddsd_s.dwSize = ddsd_d.dwSize = sizeof(ddsd_s);
// ATTENTION: implement subrect locks and copy correctly.
if ((ddrval = lpDDSSrcSubMip->Lock(NULL, &ddsd_s, DDLOCK_WAIT, NULL)) != DD_OK)
{
if((ddrval == DDERR_SURFACELOST) && (this->dwHintFlags & D3DDEVBOOL_HINTFLAGS_INSCENE))
{
this->dwFEFlags |= D3DFE_LOSTSURFACES;
ddrval = DD_OK;
}
else
{
D3D_ERR("Failed to lock src texture");
}
return ddrval;
}
if ((ddrval = lpDDSDstSubMip->Lock(NULL, &ddsd_d, DDLOCK_WAIT, NULL)) != DD_OK)
{
lpDDSSrcSubMip->Unlock(NULL);
if((ddrval == DDERR_SURFACELOST) && (this->dwHintFlags & D3DDEVBOOL_HINTFLAGS_INSCENE))
{
this->dwFEFlags |= D3DFE_LOSTSURFACES;
ddrval = DD_OK;
}
else
{
D3D_ERR("Failed to lock dst texture");
}
return ddrval;
}
switch (psize)
{
case 16: dwBytesPerLine = (ddsd_s.dwWidth + 1) / 2; break;
case 4: dwBytesPerLine = (ddsd_s.dwWidth + 3) / 4; break;
case 2: dwBytesPerLine = (ddsd_s.dwWidth + 7) / 8; break;
}
psrc = (LPBYTE)ddsd_s.lpSurface;
pdst = (LPBYTE)ddsd_d.lpSurface;
for (i = 0; i < ddsd_s.dwHeight; i++) {
memcpy( pdst, psrc, dwBytesPerLine );
psrc += ddsd_s.lPitch;
pdst += ddsd_d.lPitch;
}
lpDDSSrcSubMip->Unlock(NULL);
lpDDSDstSubMip->Unlock(NULL);
}
else if (ddrval != DD_OK)
{
if((ddrval == DDERR_SURFACELOST) && (this->dwHintFlags & D3DDEVBOOL_HINTFLAGS_INSCENE))
{
this->dwFEFlags |= D3DFE_LOSTSURFACES;
ddrval = DD_OK;
}
else
{
D3D_ERR("Blt failure");
}
return ddrval;
}
if(lpSrcRct)
{
_COMPUTE_NEXT_LOD_RECT(lpSrcRct)
}
if(lpDstRct)
{
_COMPUTE_NEXT_LOD_RECT(lpDstRct)
}
++mmsrc;
++mmdst;
}
while(mmsrc != 0 && mmdst != 0);
}
}
++cmsrc;
if(cmsrc == 0)
{
break; // out of outer loop
}
++cmdst;
if(cmdst == 0)
{
D3D_ERR("Destination texture has different cubemap faces than source");
return DDERR_INVALIDPARAMS;
}
}
return D3D_OK;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DIRECT3DDEVICEI::VerifyTextureCaps"
HRESULT DIRECT3DDEVICEI::VerifyTextureCaps(LPDIRECT3DTEXTUREI lpTexI)
{
DWORD texcap;
WORD width, height;
LPDDRAWI_DDRAWSURFACE_INT lpDDS;
if(lpTexI->D3DManaged())
lpDDS = (LPDDRAWI_DDRAWSURFACE_INT)(lpTexI->lpDDSSys);
else
lpDDS = (LPDDRAWI_DDRAWSURFACE_INT)(lpTexI->lpDDS);
/*
* Are we palettized?
*/
LPDDPIXELFORMAT pPF = &PixelFormat(lpDDS->lpLcl);
if ( (pPF->dwFlags & DDPF_PALETTEINDEXED1) ||
(pPF->dwFlags & DDPF_PALETTEINDEXED2) ||
(pPF->dwFlags & DDPF_PALETTEINDEXED4) ||
(pPF->dwFlags & DDPF_PALETTEINDEXED8) )
{
if(lpDDS->lpLcl->lpDDPalette == NULL)
{
D3D_ERR("No palette attached to a palettized texture");
return DDERR_NOPALETTEATTACHED;
}
}
/* first verify the dimensions */
texcap = this->d3dDevDesc.dpcTriCaps.dwTextureCaps;
width = lpDDS->lpLcl->lpGbl->wWidth;
height = lpDDS->lpLcl->lpGbl->wHeight;
if (texcap & D3DPTEXTURECAPS_POW2)
{
if (width & (width - 1)) // Clear the right most set bit
{
if (texcap & D3DPTEXTURECAPS_NONPOW2CONDITIONAL)
{
D3D_INFO( 3, "Texture width not a power of two");
D3D_INFO( 3, " with D3DPTEXTURECAPS_NONPOW2CONDITIONAL");
}
else
{
D3D_ERR("Texture width not a power of two");
return D3DERR_TEXTURE_BADSIZE;
}
}
if (height & (height - 1)) // Clear the right most set bit
{
if (texcap & D3DPTEXTURECAPS_NONPOW2CONDITIONAL)
{
D3D_INFO( 3, "Texture height not a power of two");
D3D_INFO( 3, " with D3DPTEXTURECAPS_NONPOW2CONDITIONAL");
}
else
{
D3D_ERR("Texture height not a power of two");
return D3DERR_TEXTURE_BADSIZE;
}
}
}
if (texcap & D3DPTEXTURECAPS_SQUAREONLY)
{
if (width != height)
{
D3D_ERR("Texture not square");
return D3DERR_TEXTURE_BADSIZE;
}
}
return D3D_OK;
}
#if COLLECTSTATS
#undef DPF_MODNAME
#define DPF_MODNAME "Direct3DDevice::GetTexStats"
void DIRECT3DDEVICEI::GetTexStats(LPD3DDEVINFO_TEXTURING pStats)
{
lpDirect3DI->GetTexStats(&m_texstats);
*pStats = m_texstats;
}
#endif
#undef DPF_MODNAME
#define DPF_MODNAME "Direct3DDevice::GetInfoInternal"
BOOL DIRECT3DDEVICEI::GetInfoInternal(DWORD dwDevInfoID, LPVOID pDevInfoStruct, DWORD dwSize)
{
switch(dwDevInfoID)
{
#if COLLECTSTATS
case D3DDEVINFOID_D3DTEXTUREMANAGER:
if(dwSize < sizeof(D3DDEVINFO_TEXTUREMANAGER))
{
D3D_ERR( "Invalid size" );
throw DDERR_INVALIDPARAMS;
}
lpDirect3DI->lpTextureManager->GetStats((LPD3DDEVINFO_TEXTUREMANAGER)pDevInfoStruct);
break;
case D3DDEVINFOID_TEXTURING:
if(dwSize < sizeof(D3DDEVINFO_TEXTURING))
{
D3D_ERR( "Invalid size" );
throw DDERR_INVALIDPARAMS;
}
this->GetTexStats((LPD3DDEVINFO_TEXTURING)pDevInfoStruct);
break;
#else
case D3DDEVINFOID_D3DTEXTUREMANAGER:
case D3DDEVINFOID_TEXTURING:
D3D_WARN( 0, "Stats not collected in this build" );
memset(pDevInfoStruct, 0, dwSize);
throw S_FALSE;
#endif
default:
return FALSE;
}
return TRUE;
}
#undef DPF_MODNAME
#define DPF_MODNAME "Direct3DDevice::GetInfo"
HRESULT D3DAPI DIRECT3DDEVICEI::GetInfo(DWORD dwDevInfoID, LPVOID pDevInfoStruct, DWORD dwSize)
{
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
// Release in the destructor
if (!VALID_DIRECT3DDEVICE_PTR(this))
{
D3D_ERR( "Invalid DIRECT3DDEVICE7 pointer" );
return DDERR_INVALIDOBJECT;
}
if (dwSize == 0 || !VALID_D3DDEVINFOSTRUCT_PTR(pDevInfoStruct, dwSize))
{
D3D_ERR( "Invalid structure pointer or size" );
return DDERR_INVALIDOBJECT;
}
memset(pDevInfoStruct, 0, dwSize);
#if DBG
if (this->dwHintFlags & D3DDEVBOOL_HINTFLAGS_INSCENE)
{
D3D_WARN( 2, "GetInfo called within a scene" );
}
#endif
try
{
switch(dwDevInfoID)
{
#if COLLECTSTATS
case D3DDEVINFOID_TEXTUREMANAGER:
lpDirect3DI->lpTextureManager->GetStats((LPD3DDEVINFO_TEXTUREMANAGER)pDevInfoStruct);
return D3D_OK;
#else
case D3DDEVINFOID_TEXTUREMANAGER:
D3D_WARN( 0, "Stats not collected in this build" );
return S_FALSE;
#endif
default:
if(GetInfoInternal(dwDevInfoID, pDevInfoStruct, dwSize))
return D3D_OK;
}
D3D_WARN( 1, "Device information query unsupported" );
return E_FAIL;
}
catch(HRESULT hr)
{
memset(pDevInfoStruct, 0, dwSize);
return hr;
}
}