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
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;
|
|
}
|
|
}
|