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.
5229 lines
165 KiB
5229 lines
165 KiB
/*==========================================================================;
|
|
*
|
|
* Copyright (C) 2000 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: d3dbase.cpp
|
|
* Content: Direct3D base device implementation
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
/*
|
|
* Create an api for the Direct3DDevice object
|
|
*/
|
|
extern "C" {
|
|
#define this _this
|
|
#include "ddrawpr.h"
|
|
#undef this
|
|
}
|
|
#include "drawprim.hpp"
|
|
#include "vvm.h"
|
|
#include "ddi.h"
|
|
|
|
#if defined(PROFILE4)
|
|
#include <icecap.h>
|
|
#elif defined(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"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// CD3DBase //
|
|
// //
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
CD3DBase::CD3DBase()
|
|
{
|
|
// Shaders are not re-created inside Init()
|
|
m_pVShaderArray = NULL;
|
|
m_pPShaderArray = NULL;
|
|
|
|
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
// DO NOT PUT INITIALIZATION IN THE CONSTRUCTOR.
|
|
// Put it in Init() instead. This is because the device can be
|
|
// "Destroy()ed" and "Init()ed" anytime via Reset. In this
|
|
// situation, the constructor is never called. (snene 01/00)
|
|
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
|
|
m_qwBatch = 1; // this is ok to put here because we DONT WANT
|
|
// it to be reinitialized upon Reset() (snene 02/00)
|
|
|
|
#ifdef FAST_PATH
|
|
m_pOrigVtbl = 0; // This is ok to put here since we DONT want it to
|
|
// be touched at Destroy()
|
|
#endif
|
|
}
|
|
//---------------------------------------------------------------------
|
|
HRESULT CD3DBase::ResetShaders()
|
|
{
|
|
try
|
|
{
|
|
// Re-create vertex shaders for after DX8.0 apps only
|
|
UINT size = m_pVShaderArray->GetSize();
|
|
for (UINT i=0; i < size; i++)
|
|
{
|
|
UINT Handle = m_pVShaderArray->HandleFromIndex(i);
|
|
CVShader* pShader = (CVShader*)m_pVShaderArray->GetObject(Handle);
|
|
if (pShader)
|
|
{
|
|
if (Enum()->GetAppSdkVersion() != D3D_SDK_VERSION_DX8)
|
|
{
|
|
CreateVertexShaderI(pShader->m_pOrgDeclaration,
|
|
pShader->m_OrgDeclSize,
|
|
pShader->m_pOrgFuncCode,
|
|
pShader->m_OrgFuncCodeSize,
|
|
Handle);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Re-create pixel shaders for after DX8.0 apps only
|
|
size = m_pPShaderArray->GetSize();
|
|
for (i=0; i < size; i++)
|
|
{
|
|
UINT Handle = m_pPShaderArray->HandleFromIndex(i);
|
|
CPShader* pShader = (CPShader*)m_pPShaderArray->GetObject(Handle);
|
|
if (pShader)
|
|
{
|
|
if (Enum()->GetAppSdkVersion() != D3D_SDK_VERSION_DX8)
|
|
{
|
|
m_pDDI->CreatePixelShader(pShader->m_pCode,
|
|
pShader->m_dwCodeSize, Handle);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
DPF_ERR("There was some error when resetting shaders");
|
|
return ret;
|
|
}
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
|
|
CD3DBase::~CD3DBase()
|
|
{
|
|
// Destroy() is called during Reset() and we do not want to delete
|
|
// shaders there
|
|
|
|
try
|
|
{
|
|
delete m_pPShaderArray;
|
|
m_pPShaderArray = NULL;
|
|
delete m_pVShaderArray;
|
|
m_pVShaderArray = NULL;
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
DPF_ERR("There was some error when destroying device");
|
|
}
|
|
|
|
Destroy();
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// This function can be called TWICE, so it is ESSENTIAL that all
|
|
// pointers be NULLED out and pointer dereferences be protected.
|
|
// This function is capable of cleaning up partial initialization.
|
|
void
|
|
CD3DBase::Destroy()
|
|
{
|
|
try // Since Destroy() can be called directly by fw
|
|
{
|
|
// The DDI layer is about to be be deleted; so
|
|
// we need to make sure that if Sync is called for
|
|
// any object, we don't try to use the DDI.
|
|
//
|
|
// So we increment our sync counter
|
|
// CONSIDER: should we NULL m_pDDI instead and check
|
|
// for that in various places?
|
|
DDASSERT(m_qwBatch > 0);
|
|
m_qwBatch++;
|
|
|
|
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
// MUST CLEANUP AND RELEASE CURRENTLY SET TEXTURES BEFORE
|
|
// DOING ANY OTHER WORK, else we will get into situations
|
|
// where we are calling FlushStates or batching DDI tokens.
|
|
CleanupTextures();
|
|
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
|
|
delete m_pCreatedLights;
|
|
m_pCreatedLights = NULL;
|
|
|
|
// Delete state sets
|
|
if (0 != m_pStateSets)
|
|
{
|
|
delete m_pStateSets;
|
|
m_pStateSets = 0;
|
|
}
|
|
|
|
#if DBG
|
|
delete m_pRTPatchValidationInfo;
|
|
m_pRTPatchValidationInfo = NULL;
|
|
#endif
|
|
|
|
delete m_pPaletteArray;
|
|
m_pPaletteArray = NULL;
|
|
|
|
delete [] m_pStream;
|
|
m_pStream = NULL; // Must NULL out
|
|
delete m_pIndexStream;
|
|
m_pIndexStream = NULL; // Must NULL out
|
|
|
|
// NOTE: we must free the DDI last; because releasing Driver
|
|
// allocated VBs causes an intrinsic call to Unlock through
|
|
// the DDI.
|
|
|
|
delete m_pDDI;
|
|
m_pDDI = NULL; // Must NULL out
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
DPF_ERR("There was some error when Reset()ing the device; as a result some resources may not be freed.");
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::CleanupTextures"
|
|
|
|
void __declspec(nothrow) CD3DBase::CleanupTextures()
|
|
{
|
|
if(GetDDIType() < D3DDDITYPE_DX8)
|
|
{
|
|
// We need to unset currently set textures on DX8 drives since we have
|
|
// seen these drivers do bad things when the TextureDestroy DDI is called.
|
|
BOOL bNeedFlush = FALSE;
|
|
for (DWORD dwStage = 0; dwStage < m_dwMaxTextureBlendStages; dwStage++)
|
|
{
|
|
if(m_dwDDITexHandle[dwStage] != 0)
|
|
{
|
|
try
|
|
{
|
|
m_pDDI->SetTSS(dwStage, (D3DTEXTURESTAGESTATETYPE)D3DTSS_TEXTUREMAP, 0);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
}
|
|
m_dwDDITexHandle[dwStage] = 0;
|
|
bNeedFlush = TRUE;
|
|
}
|
|
}
|
|
// Since flush-states (or any command stream thing) can throw
|
|
// we need to catch an error (so we can cleanup
|
|
// properly.) This flush here is a best-effort
|
|
// attempt for old-drivers; we don't want new drivers to rely on
|
|
// it since it can fail for lots of reasons.
|
|
try
|
|
{
|
|
if(bNeedFlush)
|
|
{
|
|
m_pDDI->FlushStates();
|
|
}
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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 (m_lpD3DMappedTexI[i])
|
|
{
|
|
m_lpD3DMappedTexI[i]->DecrementUseCount();
|
|
m_lpD3DMappedTexI[i] = NULL; // Must NULL out
|
|
}
|
|
}
|
|
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::Init"
|
|
|
|
HRESULT __declspec(nothrow)
|
|
CD3DBase::Init()
|
|
{
|
|
HRESULT ret = S_OK;
|
|
|
|
//
|
|
// FE's Init
|
|
//
|
|
ret = InitDevice();
|
|
if (ret!=D3D_OK)
|
|
{
|
|
D3D_ERR("Failed to initialize D3DDevice");
|
|
Destroy();
|
|
return ret;
|
|
}
|
|
|
|
//
|
|
// Initialize states
|
|
//
|
|
try
|
|
{
|
|
StateInitialize(ZBuffer() != 0);
|
|
}
|
|
catch (HRESULT ret)
|
|
{
|
|
D3D_ERR("Failed to initialize device state");
|
|
Destroy();
|
|
return ret;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::InitDevice"
|
|
|
|
HRESULT
|
|
CD3DBase::InitDevice()
|
|
{
|
|
HRESULT ret = D3D_OK;
|
|
HKEY hKey = (HKEY) NULL;
|
|
|
|
m_dwRuntimeFlags = 0;
|
|
m_dwHintFlags = 0;
|
|
m_pDDI = NULL;
|
|
m_dwMaxTextureBlendStages = 0;
|
|
m_dwStageDirty = 0;
|
|
m_dwStreamDirty = 0;
|
|
m_pStateSets = NULL;
|
|
|
|
m_dwCurrentShaderHandle = 0;
|
|
m_dwCurrentPixelShaderHandle = 0;
|
|
m_dwNumStreams = 0;
|
|
m_dwMaxUserClipPlanes = 0;
|
|
m_pStream = NULL;
|
|
m_pIndexStream = NULL;
|
|
m_dwPalette = __INVALIDPALETTE;
|
|
m_pPaletteArray = NULL;
|
|
#if DBG
|
|
m_pRTPatchValidationInfo = NULL;
|
|
m_SceneStamp = 0;
|
|
#endif
|
|
m_pCreatedLights = NULL;
|
|
|
|
m_pCreatedLights = new CPackedBitArray;
|
|
if( m_pCreatedLights == NULL )
|
|
{
|
|
D3D_ERR("Could not allocate internal light array m_pCreatedLights");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (FAILED(m_pCreatedLights->Init(64)))
|
|
{
|
|
D3D_ERR("Could not allocate internal bit vector for m_pCreatedLights");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
if (m_pVShaderArray == NULL)
|
|
m_pVShaderArray = new CVShaderHandleFactory;
|
|
if (m_pVShaderArray == NULL)
|
|
{
|
|
D3D_ERR("Could not allocate internal handle factory m_pVShaderArray");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
// Allocate the zero'th handle. We use the handle as a flag that no
|
|
// shader set.
|
|
if (__INVALIDHANDLE == m_pVShaderArray->CreateNewHandle(NULL))
|
|
{
|
|
D3D_ERR("Vertex shader Zero'th handle allocation failed");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (m_pPShaderArray == NULL)
|
|
m_pPShaderArray = new CHandleFactory;
|
|
if (m_pPShaderArray == NULL)
|
|
{
|
|
D3D_ERR("Could not allocate internal handle factory m_pPShaderArray");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
// Allocate the zero'th handle. We use the handle as a flag that no
|
|
// shader set.
|
|
if (__INVALIDHANDLE == m_pPShaderArray->CreateNewHandle(NULL))
|
|
{
|
|
D3D_ERR("Pixel shader Zero'th handle allocation failed");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
m_pPaletteArray = new CHandleArray;
|
|
if (m_pPaletteArray == NULL)
|
|
{
|
|
D3D_ERR("Could not allocate internal handle array m_pPaletteArray");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
#if DBG
|
|
m_pRTPatchValidationInfo = new CHandleArray;
|
|
if (m_pRTPatchValidationInfo == NULL)
|
|
{
|
|
D3D_ERR("Could not allocate internal handle array m_pRTPatchValidationInfo");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
#endif
|
|
|
|
m_MaxVertexShaderConst = GetD3DCaps()->MaxVertexShaderConst;
|
|
|
|
DWORD value;
|
|
if ((GetD3DRegValue(REG_DWORD, "DisableNVPS", &value, 4) &&
|
|
value != 0))
|
|
{
|
|
m_dwRuntimeFlags |= D3DRT_DISALLOWNVPSHADERS;
|
|
}
|
|
|
|
// Figure out the DDI type of the underlying driver
|
|
|
|
//---------------------------------------------------------------------
|
|
// 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
|
|
// 0x3 (DX6)
|
|
// 0x4 (DX7)
|
|
// 0x5 (DX7+TL)
|
|
// 0x6 (DX8)
|
|
// 0x7 (DX8+TL)
|
|
//
|
|
// The following are the various cases we need to consider:
|
|
// 1) NT Hardware: 4 and above are legal
|
|
// 2) W9x Hardware: 3 and above are legal
|
|
// 3) Reference: 4 and above
|
|
//---------------------------------------------------------------------
|
|
|
|
WORD wDriverCaps = 0;
|
|
D3DDDITYPE LatestDDI = D3DDDITYPE_NULL;
|
|
//
|
|
// 1) Determine what styles of DDIs the driver is capable of
|
|
//
|
|
|
|
// DX6 ?
|
|
if (GetHalCallbacks()->DrawPrimitives2 != 0)
|
|
{
|
|
wDriverCaps |= (1 << D3DDDITYPE_DX6);
|
|
LatestDDI = D3DDDITYPE_DX6;
|
|
}
|
|
|
|
// DX7 ?
|
|
if ((wDriverCaps & (1 << D3DDDITYPE_DX6)) &&
|
|
(GetHalCallbacks()->GetDriverState != 0))
|
|
{
|
|
wDriverCaps |= (1 << D3DDDITYPE_DX7);
|
|
LatestDDI = D3DDDITYPE_DX7;
|
|
}
|
|
|
|
// DX7&TL ?
|
|
if ((wDriverCaps & (1 << D3DDDITYPE_DX7)) &&
|
|
(GetD3DCaps()->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT))
|
|
{
|
|
wDriverCaps |= (1 << D3DDDITYPE_DX7TL);
|
|
LatestDDI = D3DDDITYPE_DX7TL;
|
|
}
|
|
|
|
// DX8 ?
|
|
if ((wDriverCaps & (1 << D3DDDITYPE_DX7)) &&
|
|
(GetD3DCaps()->MaxStreams != 0))
|
|
{
|
|
wDriverCaps |= (1 << D3DDDITYPE_DX8);
|
|
LatestDDI = D3DDDITYPE_DX8;
|
|
}
|
|
|
|
// DX8&TL ?
|
|
if ((wDriverCaps & (1 << D3DDDITYPE_DX8)) &&
|
|
(GetD3DCaps()->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT))
|
|
{
|
|
wDriverCaps |= (1 << D3DDDITYPE_DX8TL);
|
|
LatestDDI = D3DDDITYPE_DX8TL;
|
|
}
|
|
|
|
//
|
|
// 2) Verify if the requested driver is supported
|
|
//
|
|
if (wDriverCaps == 0)
|
|
{
|
|
m_ddiType = D3DDDITYPE_NULL; // nothing supported so fail
|
|
}
|
|
else
|
|
{
|
|
// use the latest available if not specified or
|
|
// incorrectly specified or specified but not available
|
|
m_ddiType = LatestDDI;
|
|
}
|
|
D3D_INFO(1,"HalDevice Driver Style %x", GetDDIType());
|
|
|
|
// Pure device is available only for DX8+ drivers only (check for cap)
|
|
if ( (BehaviorFlags() & D3DCREATE_PUREDEVICE) &&
|
|
!(GetD3DCaps()->DevCaps & D3DDEVCAPS_PUREDEVICE) )
|
|
{
|
|
DPF_ERR("No PUREDEVICE support available on this driver");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
#ifdef _IA64_
|
|
if (GetDDIType() < D3DDDITYPE_DX8)
|
|
{
|
|
D3D_ERR( "Pre-DX8 drivers are not supported in IA64" );
|
|
return E_FAIL;
|
|
}
|
|
#endif // _IA64_
|
|
|
|
// Now create the DDI object
|
|
// Note: If m_dwDriverStyle == 0x0 here, driver creation will fail
|
|
// Something must have been chosen by now
|
|
switch (GetDDIType())
|
|
{
|
|
case D3DDDITYPE_DX6:
|
|
m_pDDI = new CD3DDDIDX6();
|
|
break;
|
|
case D3DDDITYPE_DX7:
|
|
m_pDDI = new CD3DDDIDX7();
|
|
break;
|
|
case D3DDDITYPE_DX7TL:
|
|
m_pDDI = new CD3DDDITL();
|
|
break;
|
|
case D3DDDITYPE_DX8:
|
|
m_pDDI = new CD3DDDIDX8();
|
|
break;
|
|
case D3DDDITYPE_DX8TL:
|
|
m_pDDI = new CD3DDDIDX8TL();
|
|
break;
|
|
default:
|
|
D3D_ERR("The currently requested/installed driver is not supported.");
|
|
// Change this return value ?
|
|
return (E_OUTOFMEMORY);
|
|
}
|
|
|
|
if( m_pDDI == NULL )
|
|
{
|
|
D3D_ERR( "Could not allocate internal driver interface object" );
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Now try to initialize the ddi object
|
|
try
|
|
{
|
|
m_pDDI->Init(this);
|
|
m_pfnDrawPrim = m_pDDI->GetDrawPrimFunction();
|
|
m_pfnDrawIndexedPrim = m_pDDI->GetDrawIndexedPrimFunction();
|
|
m_pfnDrawPrimFromNPatch = m_pDDI->GetDrawPrimFunction();
|
|
m_pfnDrawIndexedPrimFromNPatch = m_pDDI->GetDrawIndexedPrimFunction();
|
|
}
|
|
catch(HRESULT hr)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
// Initialize some caps for the Software Vertex Processing
|
|
m_dwNumStreams = max(1, GetD3DCaps()->MaxStreams);
|
|
m_dwMaxUserClipPlanes = GetD3DCaps()->MaxUserClipPlanes;
|
|
|
|
#ifdef _X86_
|
|
if (!(BehaviorFlags() & D3DCREATE_FPU_PRESERVE))
|
|
{
|
|
m_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
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef FAST_PATH
|
|
if(m_pOrigVtbl == 0)
|
|
{
|
|
m_pOrigVtbl = *((VOID***)this);
|
|
memcpy(m_pVtbl, m_pOrigVtbl, sizeof(VOID*) * NUMVTBLENTRIES);
|
|
*((VOID***)this) = m_pVtbl;
|
|
}
|
|
|
|
FastPathSetRenderStateExecute();
|
|
FastPathSetTextureStageStateExecute();
|
|
FastPathApplyStateBlockExecute();
|
|
FastPathSetTextureExecute();
|
|
FastPathSetMaterialExecute();
|
|
FastPathSetVertexShaderFast();
|
|
FastPathSetStreamSourceFast();
|
|
FastPathSetIndicesFast();
|
|
FastPathSetTransformExecute();
|
|
FastPathMultiplyTransformExecute();
|
|
FastPathSetPixelShaderExecute();
|
|
FastPathSetPixelShaderConstantExecute();
|
|
FastPathSetVertexShaderConstantExecute();
|
|
#endif
|
|
|
|
// Setup the viewport
|
|
D3DSURFACE_DESC d3ddesc = RenderTarget()->InternalGetDesc();
|
|
D3DVIEWPORT8 Viewport;
|
|
Viewport.X = 0;
|
|
Viewport.Y = 0;
|
|
Viewport.Width = d3ddesc.Width;
|
|
Viewport.Height = d3ddesc.Height;
|
|
Viewport.MinZ = (D3DVALUE)0;
|
|
Viewport.MaxZ = (D3DVALUE)1;
|
|
if (FAILED(ret = this->SetViewport(&Viewport)))
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
m_pStream = new CVStream[__NUMSTREAMS];
|
|
if( m_pStream == NULL )
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
for (UINT i=0; i < __NUMSTREAMS; i++)
|
|
{
|
|
m_pStream[i].m_dwIndex = i;
|
|
}
|
|
m_pIndexStream = new CVIndexStream;
|
|
if( m_pIndexStream == NULL )
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Initialize the caps
|
|
//
|
|
const D3DCAPS8 *pCaps = GetD3DCaps();
|
|
DDASSERT( pCaps );
|
|
|
|
if (pCaps && pCaps->FVFCaps)
|
|
{
|
|
m_dwMaxTextureBlendStages = pCaps->MaxTextureBlendStages;
|
|
}
|
|
|
|
// Setup Statesets
|
|
m_pStateSets = new CStateSets;
|
|
if (m_pStateSets == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
m_pStateSets->Init(this);
|
|
|
|
#if defined(PROFILE4) || defined(PROFILE)
|
|
m_dwProfStart = m_dwProfStop = 0;
|
|
GetD3DRegValue(REG_DWORD, "ProfileStartFrame", &m_dwProfStart, 4);
|
|
GetD3DRegValue(REG_DWORD, "ProfileStopFrame", &m_dwProfStop, 4);
|
|
#endif
|
|
|
|
return D3D_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::TextureManagerDiscardBytes"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::ResourceManagerDiscardBytes(DWORD cbBytes)
|
|
{
|
|
API_ENTER(this);
|
|
|
|
// For driver-management we pass the number of
|
|
// bytes needed down through this renderstate. For DX7
|
|
// we passed the value "1" which mean EvictAll. Now
|
|
// if the app specifices 0 for cbBytes, that means EvictAll.
|
|
// So this should make it easy for drivers to support both
|
|
// dx7 and dx8+ uses of this renderstate.
|
|
if (CanDriverManageResource())
|
|
{
|
|
try
|
|
{
|
|
m_pDDI->SetRenderState((D3DRENDERSTATETYPE)D3DRENDERSTATE_EVICTMANAGEDTEXTURES,
|
|
cbBytes + 1);
|
|
m_pDDI->FlushStates();
|
|
}
|
|
catch (HRESULT ret)
|
|
{
|
|
DPF_ERR("ResourceManagerDiscardBytes failed.");
|
|
return ret;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ResourceManager()->DiscardBytes(cbBytes);
|
|
}
|
|
|
|
return D3D_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::ValidateDevice"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::ValidateDevice(LPDWORD lpdwNumPasses)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
#if DBG
|
|
// Validate Parameters
|
|
if (!VALID_WRITEPTR(lpdwNumPasses, sizeof(DWORD)))
|
|
{
|
|
D3D_ERR("Invalid NumPasses pointer passed. ValidateDevice failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
|
|
try
|
|
{
|
|
m_pDDI->ValidateDevice(lpdwNumPasses);
|
|
}
|
|
catch(HRESULT hr)
|
|
{
|
|
D3D_INFO(0, "ValidateDevice failed.");
|
|
return hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::BeginScene"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::BeginScene()
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if defined(PROFILE4) || defined(PROFILE)
|
|
static DWORD dwFrameCount = 0;
|
|
#endif
|
|
try
|
|
{
|
|
if (m_dwHintFlags & D3DDEVBOOL_HINTFLAGS_INSCENE)
|
|
{
|
|
D3D_ERR("BeginScene, already in scene. BeginScene failed.");
|
|
return (D3DERR_INVALIDCALL);
|
|
}
|
|
|
|
if (m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE)
|
|
{
|
|
D3D_ERR("Cannot be recording state macros when calling BeginScene. BeginScene failed.");
|
|
throw (D3DERR_INVALIDCALL);
|
|
}
|
|
|
|
m_pDDI->BeginScene();
|
|
|
|
#if defined(PROFILE4)
|
|
if (++dwFrameCount == m_dwProfStart)
|
|
{
|
|
OutputDebugString("Direct3D IM 8.0: Started Profiling...\n");
|
|
StartProfile(PROFILE_THREADLEVEL, PROFILE_CURRENTID);
|
|
}
|
|
else if (dwFrameCount == m_dwProfStop)
|
|
{
|
|
StopProfile(PROFILE_THREADLEVEL, PROFILE_CURRENTID);
|
|
OutputDebugString("Direct3D IM 8.0: Stopped Profiling.\n");
|
|
}
|
|
#elif defined(PROFILE)
|
|
if (++dwFrameCount == m_dwProfStart)
|
|
{
|
|
OutputDebugString("Direct3D IM 8.0: Started Profiling...\n");
|
|
StartCAP();
|
|
}
|
|
else if (dwFrameCount == m_dwProfStop)
|
|
{
|
|
StopCAP();
|
|
OutputDebugString("Direct3D IM 8.0: Stopped Profiling.\n");
|
|
}
|
|
#endif
|
|
|
|
// So that currently bound textures get scene stamped
|
|
m_dwStageDirty = (1ul << m_dwMaxTextureBlendStages) - 1ul;
|
|
m_dwStreamDirty = (((1ul << m_dwNumStreams) - 1ul) | (1 << __NUMSTREAMS));
|
|
m_dwRuntimeFlags |= (D3DRT_NEED_TEXTURE_UPDATE | D3DRT_NEED_VB_UPDATE);
|
|
m_dwHintFlags |= D3DDEVBOOL_HINTFLAGS_INSCENE;
|
|
return (D3D_OK);
|
|
}
|
|
catch (HRESULT ret)
|
|
{
|
|
DPF_ERR("BeginScene failed.");
|
|
return ret;
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::EndScene"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::EndScene()
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
try
|
|
{
|
|
if (!(m_dwHintFlags & D3DDEVBOOL_HINTFLAGS_INSCENE))
|
|
{
|
|
D3D_ERR("EndScene, not in scene. EndScene failed.");
|
|
return (D3DERR_INVALIDCALL);
|
|
}
|
|
|
|
if (m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE)
|
|
{
|
|
D3D_ERR("Cannot be recording state macros when calling EndScene. EndScene failed.");
|
|
throw (D3DERR_INVALIDCALL);
|
|
}
|
|
|
|
m_dwHintFlags &= ~D3DDEVBOOL_HINTFLAGS_INSCENE;
|
|
|
|
m_pDDI->EndScene();
|
|
|
|
// Update the scene count in texman
|
|
ResourceManager()->SceneStamp();
|
|
|
|
#if DBG
|
|
++m_SceneStamp;
|
|
#endif
|
|
|
|
return (D3D_OK);
|
|
}
|
|
catch (HRESULT ret)
|
|
{
|
|
DPF_ERR("EndScene failed.");
|
|
return ret;
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::MultiplyTransformI"
|
|
|
|
void
|
|
CD3DBase::MultiplyTransformI(D3DTRANSFORMSTATETYPE state, CONST D3DMATRIX* lpMat)
|
|
{
|
|
m_pDDI->MultiplyTransform(state, lpMat);
|
|
}
|
|
#ifdef FAST_PATH
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::MultiplyTransformFast"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::MultiplyTransformFast(D3DTRANSFORMSTATETYPE state, CONST D3DMATRIX* lpMat)
|
|
{
|
|
#if DBG
|
|
if (!VALID_PTR(lpMat, sizeof(D3DMATRIX)))
|
|
{
|
|
D3D_ERR("Invalid matrix pointer. MultiplyTransform failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if ((DWORD)state >= __WORLDMATRIXBASE &&
|
|
(DWORD)state < __WORLDMATRIXBASE + __MAXWORLDMATRICES)
|
|
{
|
|
}
|
|
else
|
|
switch (state)
|
|
{
|
|
case D3DTS_VIEW :
|
|
case D3DTS_PROJECTION :
|
|
case D3DTS_TEXTURE0:
|
|
case D3DTS_TEXTURE1:
|
|
case D3DTS_TEXTURE2:
|
|
case D3DTS_TEXTURE3:
|
|
case D3DTS_TEXTURE4:
|
|
case D3DTS_TEXTURE5:
|
|
case D3DTS_TEXTURE6:
|
|
case D3DTS_TEXTURE7:
|
|
break;
|
|
default :
|
|
D3D_ERR("Invalid state value passed to MultiplyTransform. MultiplyTransform failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
DXGASSERT((m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE) == 0 &&
|
|
(BehaviorFlags() & D3DCREATE_MULTITHREADED) == 0 &&
|
|
(BehaviorFlags() & D3DCREATE_PUREDEVICE) != 0);
|
|
try
|
|
{
|
|
m_pDDI->MultiplyTransform(state, lpMat);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
DPF_ERR("MultiplyTransform failed.");
|
|
return ret;
|
|
}
|
|
|
|
return D3D_OK;
|
|
}
|
|
#endif
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::MultiplyTransform"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::MultiplyTransform(D3DTRANSFORMSTATETYPE state, CONST D3DMATRIX* lpMat)
|
|
{
|
|
API_ENTER(this);
|
|
#if DBG
|
|
if (!VALID_PTR(lpMat, sizeof(D3DMATRIX)))
|
|
{
|
|
D3D_ERR("Invalid matrix pointer. MultiplyTransform failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if ((DWORD)state >= __WORLDMATRIXBASE &&
|
|
(DWORD)state < __WORLDMATRIXBASE + __MAXWORLDMATRICES)
|
|
{
|
|
}
|
|
else
|
|
switch (state)
|
|
{
|
|
case D3DTS_VIEW :
|
|
case D3DTS_PROJECTION :
|
|
case D3DTS_TEXTURE0:
|
|
case D3DTS_TEXTURE1:
|
|
case D3DTS_TEXTURE2:
|
|
case D3DTS_TEXTURE3:
|
|
case D3DTS_TEXTURE4:
|
|
case D3DTS_TEXTURE5:
|
|
case D3DTS_TEXTURE6:
|
|
case D3DTS_TEXTURE7:
|
|
break;
|
|
default :
|
|
D3D_ERR("Invalid state value passed to MultiplyTransform. MultiplyTransform failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
try
|
|
{
|
|
MultiplyTransformI(state, lpMat);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
DPF_ERR("MultiplyTransform failed.");
|
|
return ret;
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetTransformI"
|
|
|
|
void CD3DBase::SetTransformI(D3DTRANSFORMSTATETYPE state,
|
|
CONST D3DMATRIX* lpMat)
|
|
{
|
|
if( state == D3DTS_PROJECTION )
|
|
m_pDDI->UpdateWInfo( lpMat );
|
|
m_pDDI->SetTransform(state, lpMat);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetTransform"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetTransform(D3DTRANSFORMSTATETYPE state,
|
|
CONST D3DMATRIX* lpMat)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if DBG
|
|
if (!VALID_PTR(lpMat, sizeof(D3DMATRIX)))
|
|
{
|
|
D3D_ERR("Invalid matrix pointer. SetTransform failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if ((DWORD)state >= __WORLDMATRIXBASE &&
|
|
(DWORD)state < __WORLDMATRIXBASE + __MAXWORLDMATRICES)
|
|
{
|
|
}
|
|
else
|
|
switch (state)
|
|
{
|
|
case D3DTS_VIEW :
|
|
case D3DTS_PROJECTION :
|
|
case D3DTS_TEXTURE0:
|
|
case D3DTS_TEXTURE1:
|
|
case D3DTS_TEXTURE2:
|
|
case D3DTS_TEXTURE3:
|
|
case D3DTS_TEXTURE4:
|
|
case D3DTS_TEXTURE5:
|
|
case D3DTS_TEXTURE6:
|
|
case D3DTS_TEXTURE7:
|
|
break;
|
|
default :
|
|
D3D_ERR("Invalid state value passed to SetTransform. SetTransform failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
try
|
|
{
|
|
if (m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE)
|
|
m_pStateSets->InsertTransform(state, lpMat);
|
|
else
|
|
SetTransformI(state, lpMat);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
DPF_ERR("SetTransform failed.");
|
|
return ret;
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
#ifdef FAST_PATH
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetTransformFast"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetTransformFast(D3DTRANSFORMSTATETYPE state,
|
|
CONST D3DMATRIX* lpMat)
|
|
{
|
|
#if DBG
|
|
if (!VALID_PTR(lpMat, sizeof(D3DMATRIX)))
|
|
{
|
|
D3D_ERR("Invalid matrix pointer. SetTransform failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if ((DWORD)state >= __WORLDMATRIXBASE &&
|
|
(DWORD)state < __WORLDMATRIXBASE + __MAXWORLDMATRICES)
|
|
{
|
|
}
|
|
else
|
|
switch (state)
|
|
{
|
|
case D3DTS_VIEW :
|
|
case D3DTS_PROJECTION :
|
|
case D3DTS_TEXTURE0:
|
|
case D3DTS_TEXTURE1:
|
|
case D3DTS_TEXTURE2:
|
|
case D3DTS_TEXTURE3:
|
|
case D3DTS_TEXTURE4:
|
|
case D3DTS_TEXTURE5:
|
|
case D3DTS_TEXTURE6:
|
|
case D3DTS_TEXTURE7:
|
|
break;
|
|
default :
|
|
D3D_ERR("Invalid state value passed to SetTransform. SetTransform failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
DXGASSERT((m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE) == 0 &&
|
|
(BehaviorFlags() & D3DCREATE_MULTITHREADED) == 0 &&
|
|
(BehaviorFlags() & D3DCREATE_PUREDEVICE) != 0);
|
|
try
|
|
{
|
|
m_pDDI->SetTransform(state, lpMat);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
DPF_ERR("SetTransform failed.");
|
|
return ret;
|
|
}
|
|
return S_OK;
|
|
}
|
|
#endif // FAST_PATH
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetRenderTarget"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetRenderTarget(IDirect3DSurface8 *pRenderTarget,
|
|
IDirect3DSurface8 *pZStencil)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
try
|
|
{
|
|
CBaseSurface *pTarget;
|
|
CBaseSurface *pZ;
|
|
|
|
if (pRenderTarget != NULL)
|
|
{
|
|
if (!VALID_D3D_DIRECTDRAWSURFACE8_PTR(pRenderTarget))
|
|
{
|
|
D3D_ERR("Invalid IDirect3DSurface8 pointer passed for RenderTarget. SetRenderTarget failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
pTarget = static_cast<CBaseSurface*>(pRenderTarget);
|
|
if (pTarget->InternalGetDevice() != this)
|
|
{
|
|
D3D_ERR("Render Target wasn't created with this Device. SetRenderTarget fails");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
D3DSURFACE_DESC desc = pTarget->InternalGetDesc();
|
|
|
|
if ((desc.Usage & D3DUSAGE_RENDERTARGET) == 0)
|
|
{
|
|
D3D_ERR("**** The D3DUSAGE_RENDERTARGET is not set on this surface.");
|
|
D3D_ERR("**** You need to add D3DUSAGE_RENDERTARGET to the Usage parameter");
|
|
D3D_ERR("**** when creating the surface. SetRenderTarget failed.");
|
|
return (D3DERR_INVALIDCALL);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
pTarget = RenderTarget();
|
|
}
|
|
|
|
if (pZStencil != NULL)
|
|
{
|
|
if (!VALID_D3D_DIRECTDRAWSURFACE8_PTR(pZStencil))
|
|
{
|
|
D3D_ERR("Invalid IDirect3DSurface8 pointer passed for ZStencil. SetRenderTarget failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
pZ = static_cast<CBaseSurface*>(pZStencil);
|
|
if (pZ->InternalGetDevice() != this)
|
|
{
|
|
D3D_ERR("Zbuffer wasn't created with this Device. SetRenderTarget fails");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
// We call the external interface because
|
|
// we need to get the Z format that the user
|
|
// specified NOT our internal mapping.
|
|
D3DSURFACE_DESC descZ;
|
|
pZ->GetDesc(&descZ);
|
|
|
|
if ((descZ.Usage & D3DUSAGE_DEPTHSTENCIL) == 0)
|
|
{
|
|
D3D_ERR("**** The D3DUSAGE_DEPTHSTENCIL is not set on this surface.");
|
|
D3D_ERR("**** You need to add D3DUSAGE_DEPTHSTENCIL to the Usage parameter");
|
|
D3D_ERR("**** when creating the surface. SetRenderTarget failed.");
|
|
return (D3DERR_INVALIDCALL);
|
|
}
|
|
|
|
// Check that RT and Z have matching Multi-Sampleness
|
|
|
|
DXGASSERT(pTarget != NULL);
|
|
D3DSURFACE_DESC descTarget = pTarget->InternalGetDesc();
|
|
|
|
if (descZ.MultiSampleType != descTarget.MultiSampleType)
|
|
{
|
|
DPF_ERR("MultiSampleType between DepthStencil Buffer and RenderTarget must match. SetRenderTarget failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
// Ensure that the ZBuffer that is being set is atleast as big as the RenderTarget
|
|
if ((descZ.Width < descTarget.Width) ||
|
|
(descZ.Height < descTarget.Height))
|
|
{
|
|
DPF_ERR("DepthStencil Buffer must be atleast as big as the RenderTarget. SetRenderTarget failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
// Need to check whether formats are compatible if
|
|
// the format is the lockable D16 or has Stencil
|
|
if (descZ.Format == D3DFMT_D16_LOCKABLE ||
|
|
CPixel::HasStencilBits(descZ.Format))
|
|
{
|
|
HRESULT hr = CheckDepthStencilMatch(descTarget.Format, descZ.Format);
|
|
if (FAILED(hr))
|
|
{
|
|
DPF_ERR("SetRenderTarget failed; Z Buffer is incompatible with Render Target. See CheckDepthStencilMatch documentation.");
|
|
if (descZ.Format == D3DFMT_D16_LOCKABLE)
|
|
{
|
|
DPF_ERR("If you don't need to lock the z-buffer, then you should use D3DFMT_D16 instead of D3DFMT_D16_LOCKABLE");
|
|
}
|
|
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
pZ = NULL;
|
|
}
|
|
|
|
HRESULT hr = SetRenderTargetI(pTarget, pZ);
|
|
if( FAILED(hr) )
|
|
{
|
|
DPF_ERR("SetRenderTargetI failed because the driver failed a command a batch");
|
|
return hr;
|
|
}
|
|
|
|
// Set the viewport to default to the whole render-target
|
|
D3DVIEWPORT8 vp;
|
|
D3DSURFACE_DESC desc = pTarget->InternalGetDesc();
|
|
vp.X = 0;
|
|
vp.Y = 0;
|
|
vp.Width = desc.Width;
|
|
vp.Height = desc.Height;
|
|
vp.MinZ = 0.0f;
|
|
vp.MaxZ = 1.0f;
|
|
SetViewportI( &vp );
|
|
}
|
|
catch (HRESULT ret)
|
|
{
|
|
DPF_ERR("SetRenderTarget failed.");
|
|
return ret;
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetRenderTargetI"
|
|
|
|
HRESULT __declspec(nothrow)
|
|
CD3DBase::SetRenderTargetI( CBaseSurface* pTarget,
|
|
CBaseSurface* pZ )
|
|
{
|
|
try
|
|
{
|
|
m_pDDI->SetRenderTarget(pTarget, pZ);
|
|
UpdateRenderTarget(pTarget, pZ);
|
|
|
|
return D3D_OK;
|
|
}
|
|
catch (HRESULT ret)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetRenderTarget"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetRenderTarget(LPDIRECT3DSURFACE8* lplpDDS)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
if (!VALID_OUTPTR(lplpDDS))
|
|
{
|
|
D3D_ERR("Invalid ptr to IDirect3DSurface8*. GetRenderTarget failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
*lplpDDS = this->RenderTarget();
|
|
|
|
this->RenderTarget()->AddRef();
|
|
return D3D_OK;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetZStencilSurface"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetDepthStencilSurface(LPDIRECT3DSURFACE8* lplpDDS)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
if (!VALID_OUTPTR(lplpDDS))
|
|
{
|
|
D3D_ERR("Invalid ptr to IDirect3DSurface8*. GetDepthStencilSurface failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
*lplpDDS = this->ZBuffer();
|
|
|
|
if (*lplpDDS)
|
|
{
|
|
(*lplpDDS)->AddRef();
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
D3D_INFO(0, "Device doesn't have a Z Buffer.");
|
|
return D3DERR_NOTFOUND;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetViewport"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetViewport(CONST D3DVIEWPORT8* lpData)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
if (!VALID_PTR(lpData, sizeof(*lpData)))
|
|
{
|
|
D3D_ERR("Invalid viewport pointer. SetViewport failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
try
|
|
{
|
|
if (m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE)
|
|
m_pStateSets->InsertViewport(lpData);
|
|
else
|
|
SetViewportI(lpData);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
DPF_ERR("SetViewport failed.");
|
|
return ret;
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetViewportI"
|
|
|
|
void CD3DBase::SetViewportI(CONST D3DVIEWPORT8* lpData)
|
|
{
|
|
#if DBG
|
|
CheckViewport(lpData);
|
|
#endif
|
|
m_pDDI->SetViewport(lpData);
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetMaterial"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetMaterial(CONST D3DMATERIAL8* lpData)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if DBG
|
|
if (!VALID_PTR(lpData, sizeof(*lpData)))
|
|
{
|
|
D3D_ERR("Invalid D3DMATERIAL pointer. SetMaterial failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
|
|
try
|
|
{
|
|
if (m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE)
|
|
m_pStateSets->InsertMaterial(lpData);
|
|
else
|
|
this->SetMaterialFast(lpData);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
DPF_ERR("SetMaterial failed.");
|
|
return ret;
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetMaterialFast"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetMaterialFast(CONST D3DMATERIAL8* lpData)
|
|
{
|
|
#if DBG
|
|
if (!VALID_PTR(lpData, sizeof(*lpData)))
|
|
{
|
|
D3D_ERR("Invalid D3DMATERIAL pointer. SetMaterial failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
try
|
|
{
|
|
m_pDDI->SetMaterial(lpData);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
DPF_ERR("SetMaterial failed.");
|
|
return ret;
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetLight"
|
|
|
|
extern void CheckLightParams(CONST D3DLIGHT8* lpData);
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetLight(DWORD dwLightIndex,
|
|
CONST D3DLIGHT8* lpData)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
if (!VALID_PTR(lpData, sizeof(*lpData)))
|
|
{
|
|
D3D_ERR( "Invalid D3DLIGHT pointer. SetLight failed." );
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
try
|
|
{
|
|
#if DBG
|
|
CheckLightParams(lpData);
|
|
#endif // DBG
|
|
|
|
// If new index greater than allocated array - re-allocate the array
|
|
if (dwLightIndex >= m_pCreatedLights->GetSize())
|
|
m_pCreatedLights->Init(dwLightIndex + 32);
|
|
|
|
// If the light if not already created, send command to the DDI to
|
|
// create it.
|
|
if (!m_pCreatedLights->IsBitSet(dwLightIndex))
|
|
{
|
|
m_pDDI->CreateLight(dwLightIndex);
|
|
m_pCreatedLights->SetBit(dwLightIndex);
|
|
|
|
// If we are in the record mode, we need to create the light object.
|
|
// Otherwise, if we access the light during capture, we will have
|
|
// access violation.
|
|
if (m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE)
|
|
{
|
|
// Set default value to the light
|
|
D3DLIGHT8 light;
|
|
memset(&light, 0, sizeof(light));
|
|
light.Type = D3DLIGHT_DIRECTIONAL;
|
|
light.Direction.x = D3DVAL(0);
|
|
light.Direction.y = D3DVAL(0);
|
|
light.Direction.z = D3DVAL(1);
|
|
light.Diffuse.r = D3DVAL(1);
|
|
light.Diffuse.g = D3DVAL(1);
|
|
light.Diffuse.b = D3DVAL(1);
|
|
|
|
this->SetLightI(dwLightIndex, &light);
|
|
}
|
|
}
|
|
|
|
if (m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE)
|
|
m_pStateSets->InsertLight(dwLightIndex, lpData);
|
|
else
|
|
this->SetLightI(dwLightIndex, lpData);
|
|
return D3D_OK;
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
D3D_ERR("SetLight failed.");
|
|
return ret;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetLightI"
|
|
|
|
void
|
|
CD3DBase::SetLightI(DWORD dwLightIndex, CONST D3DLIGHT8* lpData)
|
|
{
|
|
m_pDDI->SetLight(dwLightIndex, lpData);
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::LightEnableI"
|
|
|
|
void
|
|
CD3DBase::LightEnableI(DWORD dwLightIndex, BOOL bEnable)
|
|
{
|
|
m_pDDI->LightEnable(dwLightIndex, bEnable);
|
|
}
|
|
//---------------------------------------------------------------------
|
|
BOOL ValidateRenderState(D3DRENDERSTATETYPE dwState, DWORD value)
|
|
{
|
|
if (dwState >= D3D_MAXRENDERSTATES || dwState == 0)
|
|
{
|
|
D3D_ERR("Invalid render state type. SetRenderState failed.");
|
|
return FALSE;
|
|
}
|
|
switch (dwState)
|
|
{
|
|
case D3DRS_POSITIONORDER:
|
|
if (!((value == D3DORDER_LINEAR) || (value == D3DORDER_CUBIC)))
|
|
{
|
|
D3D_ERR("D3DRS_POSITIONORDER should be D3DORDER_LINEAR or D3DORDER_CUBIC");
|
|
return FALSE;
|
|
}
|
|
break;
|
|
case D3DRS_NORMALORDER:
|
|
if (!((value == D3DORDER_LINEAR) || (value == D3DORDER_QUADRATIC)))
|
|
{
|
|
D3D_ERR("D3DRS_NORMALORDER should be D3DORDER_LINEAR or D3DORDER_QUADRATIC");
|
|
return FALSE;
|
|
}
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetRenderState"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetRenderState(D3DRENDERSTATETYPE dwState,
|
|
DWORD value)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if DBG
|
|
if (!ValidateRenderState(dwState, value))
|
|
return D3DERR_INVALIDCALL;
|
|
#endif
|
|
|
|
try
|
|
{
|
|
if (m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE)
|
|
m_pStateSets->InsertRenderState(dwState, value,
|
|
CanHandleRenderState(dwState));
|
|
else
|
|
m_pDDI->SetRenderState(dwState, value);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
DPF_ERR("SetRenderState failed.");
|
|
return ret;
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetRenderStateFast"
|
|
|
|
HRESULT D3DAPI CD3DBase::SetRenderStateFast(D3DRENDERSTATETYPE dwState,
|
|
DWORD value)
|
|
{
|
|
|
|
#if DBG
|
|
if (!ValidateRenderState(dwState, value))
|
|
return D3DERR_INVALIDCALL;
|
|
#endif
|
|
|
|
DXGASSERT((BehaviorFlags() & D3DCREATE_MULTITHREADED) == 0);
|
|
|
|
try
|
|
{
|
|
m_pDDI->SetRenderState(dwState, value);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
DPF_ERR("SetRenderState failed.");
|
|
return ret;
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetClipStatus"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetClipStatus(CONST D3DCLIPSTATUS8* lpStatus)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
D3D_ERR("SetClipStatus is not available for D3DCREATE_PUREDEVICE. SetClipStatus failed.");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetClipStatus"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetClipStatus(D3DCLIPSTATUS8* lpStatus)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
D3D_ERR("GetClipStatus is not available for D3DCREATE_PUREDEVICE. GetClipStatus failed.");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::ProcessVertices"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::ProcessVertices(UINT SrcStartIndex, UINT DestIndex, UINT VertexCount,
|
|
IDirect3DVertexBuffer8 *pDestBuffer,
|
|
DWORD Flags)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
if (pDestBuffer == NULL)
|
|
{
|
|
D3D_ERR("Invalid vertex buffer pointer. ProcessVertices failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
CVertexBuffer* pVB = static_cast<CVertexBuffer*>(pDestBuffer);
|
|
if (pVB->Device() != this)
|
|
{
|
|
D3D_ERR("VertexBuffer not created with this device. Process Vertices failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
D3D_ERR("ProcessVertices is not available for a PUREDEVICE. ProcessVertices failed.");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetTexture"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetTexture(DWORD dwStage,
|
|
IDirect3DBaseTexture8 *lpTex)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
try
|
|
{
|
|
|
|
#if DBG
|
|
HRESULT ret = VerifyTexture(dwStage, lpTex);
|
|
if (ret != D3D_OK)
|
|
return ret;
|
|
#endif
|
|
if (m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE)
|
|
{
|
|
m_pStateSets->InsertTexture(dwStage, lpTex);
|
|
return D3D_OK;
|
|
}
|
|
|
|
return SetTextureFast(dwStage, lpTex);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
DPF_ERR("SetTexture failed.");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::VerifyTexture"
|
|
HRESULT
|
|
CD3DBase::VerifyTexture(DWORD dwStage,
|
|
IDirect3DBaseTexture8 *lpTex)
|
|
{
|
|
if (dwStage >= D3DHAL_TSS_MAXSTAGES)
|
|
{
|
|
D3D_ERR("Invalid texture stage or state index. SetTexture failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
if (lpTex)
|
|
{
|
|
if (!VALID_DIRECT3DBASETEXTURE8_PTR(lpTex))
|
|
{
|
|
D3D_ERR("Invalid texture pointer. SetTexture failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
CBaseTexture *pTex = CBaseTexture::SafeCast(lpTex);
|
|
if (pTex->Device() != this)
|
|
{
|
|
D3D_ERR("Texture not created with this device. SetTexture failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
if (pTex->GetUserPool() == D3DPOOL_SYSTEMMEM)
|
|
{
|
|
if ((GetD3DCaps()->DevCaps & D3DDEVCAPS_TEXTURESYSTEMMEMORY) == 0)
|
|
{
|
|
D3D_ERR("Device cannot render using texture surface from system memory. SetTexture failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
}
|
|
if (pTex->GetUserPool() == D3DPOOL_SCRATCH)
|
|
{
|
|
D3D_ERR("D3DPOOL_SCRATCH resources cannot be passed to SetTexture. SetTexture fails.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
}
|
|
|
|
return D3D_OK;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetTextureFast"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetTextureFast(DWORD dwStage,
|
|
IDirect3DBaseTexture8 *lpTex)
|
|
{
|
|
// NOTE: This can become a public API through the
|
|
// v-table hack. This should only happen for
|
|
// single-threaded apps; so we don't need
|
|
// to take the critical section.
|
|
#if DBG
|
|
HRESULT ret = VerifyTexture(dwStage, lpTex);
|
|
if (ret != D3D_OK)
|
|
return ret;
|
|
#endif
|
|
|
|
CBaseTexture *lpTexI = CBaseTexture::SafeCast(lpTex);
|
|
|
|
if (m_lpD3DMappedTexI[dwStage] == lpTexI)
|
|
{
|
|
return D3D_OK;
|
|
}
|
|
|
|
if (m_lpD3DMappedTexI[dwStage])
|
|
{
|
|
m_lpD3DMappedTexI[dwStage]->DecrementUseCount();
|
|
}
|
|
|
|
m_lpD3DMappedTexI[dwStage] = lpTexI;
|
|
|
|
if (lpTexI)
|
|
{
|
|
lpTexI->IncrementUseCount();
|
|
}
|
|
|
|
m_dwStageDirty |= (1 << dwStage);
|
|
|
|
// Need to call UpdateTextures()
|
|
m_dwRuntimeFlags |= D3DRT_NEED_TEXTURE_UPDATE;
|
|
|
|
return D3D_OK;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetTexture"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetTexture(DWORD dwStage,
|
|
IDirect3DBaseTexture8 **lplpTex)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if DBG
|
|
if (dwStage >= D3DHAL_TSS_MAXSTAGES)
|
|
{
|
|
D3D_ERR("Invalid texture stage or state index. GetTexture failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
|
|
if (!VALID_WRITEPTR(lplpTex, sizeof(LPVOID)))
|
|
{
|
|
D3D_ERR("Invalid pointer to IDirect3DBaseTexture8*. GetTexture failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
if (m_lpD3DMappedTexI[dwStage])
|
|
{
|
|
switch(m_lpD3DMappedTexI[dwStage]->GetBufferDesc()->Type)
|
|
{
|
|
case D3DRTYPE_TEXTURE:
|
|
*lplpTex = static_cast<IDirect3DTexture8*>(static_cast<CMipMap*>(m_lpD3DMappedTexI[dwStage]));
|
|
break;
|
|
case D3DRTYPE_CUBETEXTURE:
|
|
*lplpTex = static_cast<IDirect3DCubeTexture8*>(static_cast<CCubeMap*>(m_lpD3DMappedTexI[dwStage]));
|
|
break;
|
|
case D3DRTYPE_VOLUMETEXTURE:
|
|
*lplpTex = static_cast<IDirect3DVolumeTexture8*>(static_cast<CMipVolume*>(m_lpD3DMappedTexI[dwStage]));
|
|
break;
|
|
}
|
|
(*lplpTex)->AddRef();
|
|
}
|
|
else
|
|
{
|
|
*lplpTex = NULL;
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetTextureStageState"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetTextureStageState(DWORD dwStage,
|
|
D3DTEXTURESTAGESTATETYPE dwState,
|
|
DWORD dwValue)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if DBG
|
|
if ( (dwStage >= D3DHAL_TSS_MAXSTAGES) ||
|
|
(dwState == 0) ||
|
|
(dwState >= D3DTSS_MAX) ||
|
|
(dwState == 12) ) // D3DTSS_ADDRESS no longer valid
|
|
{
|
|
D3D_ERR("Invalid texture stage or state index. SetTextureStageState failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif //DBG
|
|
try
|
|
{
|
|
if (m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE)
|
|
m_pStateSets->InsertTextureStageState(dwStage, dwState, dwValue);
|
|
else
|
|
m_pDDI->SetTSS(dwStage, dwState, dwValue);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
DPF_ERR("SetTextureStageState failed.");
|
|
return ret;
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetTextureStageStateFast"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetTextureStageStateFast(DWORD dwStage,
|
|
D3DTEXTURESTAGESTATETYPE dwState,
|
|
DWORD dwValue)
|
|
{
|
|
#if DBG
|
|
if ( (dwStage >= D3DHAL_TSS_MAXSTAGES) ||
|
|
(dwState == 0) ||
|
|
(dwState >= D3DTSS_MAX) ||
|
|
(dwState == 12) ) // D3DTSS_ADDRESS no longer valid
|
|
{
|
|
D3D_ERR("Invalid texture stage or state index. SetTextureStageState failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif //DBG
|
|
|
|
DXGASSERT((BehaviorFlags() & D3DCREATE_MULTITHREADED) == 0);
|
|
|
|
try
|
|
{
|
|
m_pDDI->SetTSS(dwStage, dwState, dwValue);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
DPF_ERR("SetTextureStageState failed.");
|
|
return ret;
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::LightEnable"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::LightEnable(DWORD dwLightIndex,
|
|
BOOL bEnable)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
try
|
|
{
|
|
// If light was never created, we create a default light
|
|
if (dwLightIndex >= m_pCreatedLights->GetSize() ||
|
|
!m_pCreatedLights->IsBitSet(dwLightIndex))
|
|
{
|
|
// Set default value to the light
|
|
D3DLIGHT8 light;
|
|
memset(&light, 0, sizeof(light));
|
|
light.Type = D3DLIGHT_DIRECTIONAL;
|
|
light.Direction.x = D3DVAL(0);
|
|
light.Direction.y = D3DVAL(0);
|
|
light.Direction.z = D3DVAL(1);
|
|
light.Diffuse.r = D3DVAL(1);
|
|
light.Diffuse.g = D3DVAL(1);
|
|
light.Diffuse.b = D3DVAL(1);
|
|
|
|
// When a new light is created we need to actually create it even
|
|
// in the record mode. So we clear record flag, create light and
|
|
// restore the flag.
|
|
DWORD OldBit = m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE;
|
|
m_dwRuntimeFlags &= ~D3DRT_RECORDSTATEMODE;
|
|
|
|
HRESULT ret = SetLight(dwLightIndex, &light);
|
|
|
|
m_dwRuntimeFlags |= OldBit;
|
|
|
|
if (ret != S_OK)
|
|
return ret;
|
|
}
|
|
|
|
if (m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE)
|
|
m_pStateSets->InsertLightEnable(dwLightIndex, bEnable);
|
|
else
|
|
LightEnableI(dwLightIndex, bEnable);
|
|
}
|
|
catch (HRESULT ret)
|
|
{
|
|
DPF_ERR("LightEnable failed.");
|
|
return ret;
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetInfo"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetInfo(DWORD dwDevInfoID,
|
|
LPVOID pDevInfoStruct,
|
|
DWORD dwSize)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
if (dwSize == 0 || !VALID_D3DDEVINFOSTRUCT_PTR(pDevInfoStruct, dwSize))
|
|
{
|
|
D3D_ERR("Invalid structure pointer or size. GetInfo failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
memset(pDevInfoStruct, 0, dwSize);
|
|
if (dwDevInfoID < D3DDEVINFOID_VCACHE)
|
|
{
|
|
D3D_ERR("DX7 DevInfo IDs not supported in DX8. GetInfo failed.");
|
|
return E_FAIL;
|
|
}
|
|
#if DBG
|
|
if (m_dwHintFlags & D3DDEVBOOL_HINTFLAGS_INSCENE)
|
|
{
|
|
DPF(2, "GetInfo called within a scene");
|
|
}
|
|
#endif
|
|
try
|
|
{
|
|
if( !IS_DX7HAL_DEVICE(this) ) // must be at least DX7
|
|
{
|
|
DPF( 1, "Device information query unsupported" );
|
|
return E_FAIL;
|
|
}
|
|
|
|
m_pDDI->FlushStates();
|
|
}
|
|
catch(HRESULT hr)
|
|
{
|
|
DPF_ERR("GetInfo failed.");
|
|
return hr;
|
|
}
|
|
|
|
D3D8_GETDRIVERSTATEDATA dsd;
|
|
dsd.dwFlags = dwDevInfoID;
|
|
dsd.dwhContext = m_pDDI->GetDeviceContext();
|
|
dsd.lpdwStates = (LPDWORD)pDevInfoStruct;
|
|
dsd.dwLength = dwSize;
|
|
|
|
HRESULT hr;
|
|
hr = GetHalCallbacks()->GetDriverState(&dsd);
|
|
if (hr != DDHAL_DRIVER_HANDLED)
|
|
{
|
|
DPF( 1, "Device information query unsupported" );
|
|
memset(pDevInfoStruct, 0, dwSize);
|
|
return S_FALSE;
|
|
}
|
|
else if (dsd.ddRVal != DD_OK)
|
|
{
|
|
D3D_ERR("Driver failed query. GetInfo failed.");
|
|
memset(pDevInfoStruct, 0, dwSize);
|
|
return E_FAIL;
|
|
}
|
|
|
|
return D3D_OK;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetCurrentTexturePalette"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetCurrentTexturePalette(UINT PaletteNumber)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
try
|
|
{
|
|
if (m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE)
|
|
{
|
|
m_pStateSets->InsertCurrentTexturePalette(PaletteNumber);
|
|
}
|
|
else
|
|
{
|
|
#if DBG
|
|
if (PaletteNumber >= m_pPaletteArray->GetSize())
|
|
{
|
|
D3D_ERR("Palette not defined. SetCurrentTexturePalette failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
if(PaletteNumber != m_dwPalette)
|
|
{
|
|
m_dwPalette = PaletteNumber;
|
|
|
|
// Need to call UpdateTextures()
|
|
m_dwRuntimeFlags |= D3DRT_NEED_TEXTURE_UPDATE;
|
|
}
|
|
}
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
DPF_ERR("SetCurrentTexturePalette failed.");
|
|
return ret;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetCurrentTexturePalette"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetCurrentTexturePalette(UINT *PaletteNumber)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if DBG
|
|
if (!VALID_PTR(PaletteNumber, sizeof(UINT)))
|
|
{
|
|
D3D_ERR("Invalid PaletteNumber pointer. GetCurrentTexturePalette failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
|
|
*PaletteNumber = m_dwPalette;
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetPaletteEntries"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetPaletteEntries(UINT PaletteNumber, CONST PALETTEENTRY *pEntries)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if DBG
|
|
if (!VALID_PTR(pEntries, sizeof(PALETTEENTRY) * 256))
|
|
{
|
|
D3D_ERR("Invalid Entries pointer. SetPaletteEntries failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (PaletteNumber > 0xffff)
|
|
{
|
|
D3D_ERR("Illegal PaletteNumber value. SetPaletteEntries failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
|
|
if (Enum()->GetAppSdkVersion() > D3D_SDK_VERSION_DX8)
|
|
{
|
|
bool bAlpha=false;
|
|
#if DBG
|
|
bool bAllTransparent = true;
|
|
#endif
|
|
for (int i=0;i<256;i++)
|
|
{
|
|
if (pEntries[i].peFlags != 0xff)
|
|
{
|
|
bAlpha = true;
|
|
}
|
|
#if DBG
|
|
if (pEntries[i].peFlags != 0)
|
|
{
|
|
bAllTransparent = false;
|
|
}
|
|
#endif
|
|
}
|
|
#if DBG
|
|
if (bAllTransparent)
|
|
{
|
|
D3D_WARN(0,"Every entry in palette has alpha (peFlags) == 0. Texture may not appear.");
|
|
}
|
|
#endif
|
|
if (bAlpha && (0 == (GetD3DCaps()->TextureCaps & D3DPTEXTURECAPS_ALPHAPALETTE)) )
|
|
{
|
|
D3D_ERR("Application cannot set a non-opaque palette alpha value (peFlags other than 0xFF) unless the device exposes D3DPTEXTURECAPS_ALPHAPALETTE. SetPaletteEntries failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT hr = m_pPaletteArray->Grow(PaletteNumber);
|
|
if(FAILED(hr))
|
|
{
|
|
D3D_ERR("Failed to set palette entries. SetPaletteEntries failed.");
|
|
return hr;
|
|
}
|
|
|
|
CPalette *pal = static_cast<CPalette*>((*m_pPaletteArray)[PaletteNumber].m_pObj);
|
|
if(pal == 0)
|
|
{
|
|
pal = new CPalette;
|
|
(*m_pPaletteArray)[PaletteNumber].m_pObj = pal;
|
|
if(pal == 0)
|
|
{
|
|
D3D_ERR("Could not allocate space to hold palette. SetPaletteEntries failed.");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
memcpy(pal->m_pEntries, pEntries, sizeof(PALETTEENTRY) * 256);
|
|
|
|
pal->m_dirty = TRUE;
|
|
|
|
if(m_dwPalette == PaletteNumber)
|
|
{
|
|
// Need to call UpdateTextures()
|
|
m_dwRuntimeFlags |= D3DRT_NEED_TEXTURE_UPDATE;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetPaletteEntries"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetPaletteEntries(UINT PaletteNumber, PALETTEENTRY *pEntries)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if DBG
|
|
if (!VALID_WRITEPTR(pEntries, sizeof(PALETTEENTRY) * 256))
|
|
{
|
|
D3D_ERR("Invalid ppEntries pointer. GetPaletteEntries failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (PaletteNumber >= m_pPaletteArray->GetSize())
|
|
{
|
|
D3D_ERR("Palette not defined. GetPaletteEntries failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
|
|
CPalette *pal = static_cast<CPalette*>((*m_pPaletteArray)[PaletteNumber].m_pObj);
|
|
|
|
#if DBG
|
|
if(pal == 0)
|
|
{
|
|
D3D_ERR("Palette not defined. GetPaletteEntries failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
|
|
memcpy(pEntries, pal->m_pEntries, sizeof(PALETTEENTRY) * 256);
|
|
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetClipPlaneI"
|
|
|
|
void CD3DBase::SetClipPlaneI(DWORD dwPlaneIndex,
|
|
CONST D3DVALUE* pPlaneEquation)
|
|
{
|
|
m_pDDI->SetClipPlane(dwPlaneIndex, pPlaneEquation);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetClipPlane"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetClipPlane(DWORD dwPlaneIndex,
|
|
CONST D3DVALUE* pPlaneEquation)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if DBG
|
|
if (dwPlaneIndex >= m_dwMaxUserClipPlanes)
|
|
{
|
|
D3D_ERR("Plane index is too big. SetClipPlane failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (!VALID_PTR(pPlaneEquation, sizeof(D3DVALUE)*4))
|
|
{
|
|
D3D_ERR("Invalid plane pointer. SetClipPlane failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
try
|
|
{
|
|
if (m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE)
|
|
m_pStateSets->InsertClipPlane(dwPlaneIndex, pPlaneEquation);
|
|
else
|
|
SetClipPlaneI(dwPlaneIndex, pPlaneEquation);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
DPF_ERR("SetClipPlane failed.");
|
|
return ret;
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetStreamSource"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetStreamSource(UINT StreamNumber,
|
|
IDirect3DVertexBuffer8 *pStreamData,
|
|
UINT Stride)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if DBG
|
|
// Validate Parameters
|
|
if (StreamNumber >= m_dwNumStreams)
|
|
{
|
|
D3D_ERR("Stream number should be less than %d. SetStreamSource failed.", m_dwNumStreams);
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (Stride > this->GetD3DCaps()->MaxStreamStride)
|
|
{
|
|
D3D_ERR("Stream stride is too big. Check device caps. SetStreamSource failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
// NULL is allowed to be passed
|
|
if (pStreamData)
|
|
{
|
|
CVertexBuffer* pVB = static_cast<CVertexBuffer*>(pStreamData);
|
|
if (pVB->Device() != this)
|
|
{
|
|
D3D_ERR("VertexBuffer not created with this Device. SetStreamSource fails.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE)
|
|
{
|
|
try
|
|
{
|
|
m_pStateSets->InsertStreamSource(StreamNumber, static_cast<CVertexBuffer *>(pStreamData), Stride);
|
|
}
|
|
catch(HRESULT hr)
|
|
{
|
|
DPF_ERR("SetStreamSource failed.");
|
|
return hr;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
CVStream* pStream = &m_pStream[StreamNumber];
|
|
|
|
if (pStream->m_pVB == static_cast<CVertexBuffer *>(pStreamData) &&
|
|
Stride == pStream->m_dwStride)
|
|
return D3D_OK;
|
|
|
|
// Release previously set vertex buffer
|
|
if (pStream->m_pVB)
|
|
{
|
|
m_pDDI->VBReleased(pStream->m_pVB);
|
|
pStream->m_pVB->DecrementUseCount();
|
|
pStream->m_pVB = NULL;
|
|
}
|
|
pStream->m_pData = NULL;
|
|
pStream->m_pVB = static_cast<CVertexBuffer *>(pStreamData);
|
|
if (pStreamData)
|
|
{
|
|
pStream->m_pVB->IncrementUseCount();
|
|
pStream->m_dwStride = Stride;
|
|
#if DBG
|
|
pStream->m_dwSize = pStream->m_pVB->GetBufferDesc()->Size;
|
|
#endif // DBG
|
|
m_dwStreamDirty |= (1 << StreamNumber);
|
|
m_dwRuntimeFlags |= D3DRT_NEED_VB_UPDATE; // Need to call UpdateDirtyStreams()
|
|
#if DBG
|
|
if (Stride == 0)
|
|
pStream->m_dwNumVertices = 1;
|
|
else
|
|
pStream->m_dwNumVertices = pStream->m_dwSize / Stride;
|
|
#endif
|
|
try
|
|
{
|
|
SetStreamSourceI(pStream);
|
|
}
|
|
catch(HRESULT hr)
|
|
{
|
|
DPF_ERR("SetStreamSource failed.");
|
|
return hr;
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetStreamSourceI"
|
|
|
|
void
|
|
CD3DBase::SetStreamSourceI(CVStream* pStream)
|
|
{
|
|
}
|
|
#ifdef FAST_PATH
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetStreamSourceFast"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetStreamSourceFast(UINT StreamNumber,
|
|
IDirect3DVertexBuffer8 *pStreamData,
|
|
UINT Stride)
|
|
{
|
|
#if DBG
|
|
// Validate Parameters
|
|
if (StreamNumber >= m_dwNumStreams)
|
|
{
|
|
D3D_ERR("Stream number should be less than %d. SetStreamSource failed.", m_dwNumStreams);
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (Stride > this->GetD3DCaps()->MaxStreamStride)
|
|
{
|
|
D3D_ERR("Stream stride is too big. Check device caps. SetStreamSource failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
// NULL is allowed to be passed
|
|
if (pStreamData)
|
|
{
|
|
CVertexBuffer* pVB = static_cast<CVertexBuffer*>(pStreamData);
|
|
if (pVB->Device() != this)
|
|
{
|
|
D3D_ERR("VertexBuffer not created with this Device. SetStreamSource fails.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
DXGASSERT((m_dwRuntimeFlags & (D3DRT_RECORDSTATEMODE | D3DRT_RSSOFTWAREPROCESSING)) == 0 &&
|
|
(BehaviorFlags() & D3DCREATE_MULTITHREADED) == 0);
|
|
|
|
CVStream* pStream = &m_pStream[StreamNumber];
|
|
|
|
if (pStream->m_pVB == static_cast<CVertexBuffer *>(pStreamData) &&
|
|
Stride == pStream->m_dwStride)
|
|
return D3D_OK;
|
|
|
|
// Release previously set vertex buffer
|
|
if (pStream->m_pVB)
|
|
{
|
|
// We don't call VBReleased() here because there is no need to update the DDI object since
|
|
// the fe/PSGP never does the redundant stream set check. This check is done in DrawPrim,
|
|
// DrawIndexPrim and DrawClippedPrim. It is important to call VBReleased whenever fe/PSGP
|
|
// is being used because it is possible that the user freed and recreated the same VB with
|
|
// the same address and then the redundant set check will not work.
|
|
pStream->m_pVB->DecrementUseCount();
|
|
pStream->m_pVB = NULL;
|
|
}
|
|
pStream->m_pData = NULL;
|
|
pStream->m_pVB = static_cast<CVertexBuffer *>(pStreamData);
|
|
if (pStreamData)
|
|
{
|
|
pStream->m_pVB->IncrementUseCount();
|
|
pStream->m_dwStride = Stride;
|
|
#if DBG
|
|
pStream->m_dwSize = pStream->m_pVB->GetBufferDesc()->Size;
|
|
#endif // DBG
|
|
m_dwStreamDirty |= (1 << StreamNumber);
|
|
m_dwRuntimeFlags |= D3DRT_NEED_VB_UPDATE; // Need to call UpdateDirtyStreams()
|
|
#if DBG
|
|
if (Stride == 0)
|
|
pStream->m_dwNumVertices = 1;
|
|
else
|
|
pStream->m_dwNumVertices = pStream->m_dwSize / Stride;
|
|
#endif
|
|
}
|
|
if (!IS_DX8HAL_DEVICE(this))
|
|
{
|
|
PickDrawPrimFn();
|
|
}
|
|
return S_OK;
|
|
}
|
|
#endif // FAST_PATH
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetStreamSource"
|
|
|
|
HRESULT
|
|
CD3DBase::GetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer8 **ppStreamData,
|
|
UINT* pStride)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if DBG
|
|
if (StreamNumber >= m_dwNumStreams)
|
|
{
|
|
D3D_ERR("Stream number should be less than %d. GetStreamSource failed.", m_dwNumStreams);
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (!VALID_WRITEPTR(ppStreamData, sizeof(IDirect3DVertexBuffer8*)))
|
|
{
|
|
D3D_ERR("Invalid stream data pointer. GetStreamSource failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (!VALID_WRITEPTR(pStride, sizeof(UINT*)))
|
|
{
|
|
D3D_ERR("Invalid stride pointer. GetStreamSource failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
CVStream* pStream = &m_pStream[StreamNumber];
|
|
*ppStreamData = (pStream) ? (pStream->m_pVB) : (NULL);
|
|
if (pStream->m_pVB)
|
|
pStream->m_pVB->AddRef();
|
|
*pStride = (pStream) ? (pStream->m_dwStride) : (0);
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetIndices"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetIndices(IDirect3DIndexBuffer8 *pIndexData, UINT BaseVertexIndex)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
try
|
|
{
|
|
CIndexBuffer * pVB = static_cast<CIndexBuffer*>(pIndexData);
|
|
#if DBG
|
|
if (pVB && pVB->Device() != this)
|
|
{
|
|
D3D_ERR("IndexBuffer not created with this Device. SetIndices fails.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
if (m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE)
|
|
{
|
|
m_pStateSets->InsertIndices(pVB, BaseVertexIndex);
|
|
return S_OK;
|
|
}
|
|
|
|
if (m_pIndexStream->m_pVBI == static_cast<CIndexBuffer *>(pIndexData))
|
|
{
|
|
m_pIndexStream->m_dwBaseIndex = BaseVertexIndex;
|
|
return D3D_OK;
|
|
}
|
|
|
|
// Release previously set vertex buffer
|
|
if (m_pIndexStream->m_pVBI)
|
|
{
|
|
m_pDDI->VBIReleased(m_pIndexStream->m_pVBI);
|
|
m_pIndexStream->m_pVBI->DecrementUseCount();
|
|
m_pIndexStream->m_pVBI = NULL;
|
|
}
|
|
m_pIndexStream->m_pVBI = static_cast<CIndexBuffer *>(pIndexData);
|
|
if (pVB)
|
|
{
|
|
switch (pVB->GetBufferDesc()->Format)
|
|
{
|
|
case D3DFMT_INDEX16:
|
|
m_pIndexStream->m_dwStride = 2;
|
|
break;
|
|
case D3DFMT_INDEX32:
|
|
#if DBG
|
|
if (GetD3DCaps()->MaxVertexIndex <= 0xFFFF)
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Device does not support 32-bit indices");
|
|
#endif
|
|
m_pIndexStream->m_dwStride = 4;
|
|
break;
|
|
default:
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Invalid index buffer format");
|
|
}
|
|
#if DBG
|
|
m_pIndexStream->m_dwSize = pVB->GetBufferDesc()->Size;
|
|
#endif
|
|
m_pIndexStream->m_dwBaseIndex = BaseVertexIndex;
|
|
m_pIndexStream->m_pData = NULL;
|
|
#if DBG
|
|
m_pIndexStream->m_dwNumVertices = m_pIndexStream->m_dwSize /
|
|
m_pIndexStream->m_dwStride;
|
|
#endif
|
|
m_pIndexStream->m_pVBI->IncrementUseCount();
|
|
m_dwStreamDirty |= (1 << __NUMSTREAMS);
|
|
m_dwRuntimeFlags |= D3DRT_NEED_VB_UPDATE; // Need to call UpdateDirtyStreams()
|
|
|
|
SetIndicesI(m_pIndexStream);
|
|
}
|
|
}
|
|
catch(HRESULT hr)
|
|
{
|
|
DPF_ERR("SetIndices failed.");
|
|
return hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetIndicesI"
|
|
|
|
void
|
|
CD3DBase::SetIndicesI(CVIndexStream* pStream)
|
|
{
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetIndices"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetIndices(IDirect3DIndexBuffer8 **ppIndexData, UINT* pBaseVertexIndex)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if DBG
|
|
if (!VALID_WRITEPTR(ppIndexData, sizeof(IDirect3DIndexBuffer8*)))
|
|
{
|
|
D3D_ERR("Invalid index data pointer. GetIndices failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (!VALID_WRITEPTR(pBaseVertexIndex, sizeof(UINT*)))
|
|
{
|
|
D3D_ERR("Invalid base index pointer. GetIndices failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif //DBG
|
|
*ppIndexData = m_pIndexStream->m_pVBI;
|
|
if (m_pIndexStream->m_pVBI)
|
|
m_pIndexStream->m_pVBI->AddRef();
|
|
*pBaseVertexIndex = m_pIndexStream->m_dwBaseIndex;
|
|
return S_OK;
|
|
}
|
|
#ifdef FAST_PATH
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetIndicesFast"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetIndicesFast(IDirect3DIndexBuffer8 *pIndexData, UINT BaseVertexIndex)
|
|
{
|
|
CIndexBuffer * pVB = static_cast<CIndexBuffer*>(pIndexData);
|
|
#if DBG
|
|
if (pVB && pVB->Device() != this)
|
|
{
|
|
D3D_ERR("IndexBuffer not created with this device. SetIndices fails.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
|
|
DXGASSERT((m_dwRuntimeFlags & (D3DRT_RECORDSTATEMODE | D3DRT_RSSOFTWAREPROCESSING)) == 0 &&
|
|
(BehaviorFlags() & D3DCREATE_MULTITHREADED) == 0);
|
|
|
|
if (m_pIndexStream->m_pVBI == pVB)
|
|
{
|
|
m_pIndexStream->m_dwBaseIndex = BaseVertexIndex;
|
|
return D3D_OK;
|
|
}
|
|
|
|
// Release previously set index buffer
|
|
if (m_pIndexStream->m_pVBI)
|
|
{
|
|
// We don't call VBReleased() here because there is no need to update the DDI object since
|
|
// the fe/PSGP never does the redundant stream set check. This check is done in DrawPrim,
|
|
// DrawIndexPrim and DrawClippedPrim. It is important to call VBReleased whenever fe/PSGP
|
|
// is being used because it is possible that the user freed and recreated the same VB with
|
|
// the same address and then the redundant set check will not work.
|
|
m_pIndexStream->m_pVBI->DecrementUseCount();
|
|
m_pIndexStream->m_pVBI = NULL;
|
|
}
|
|
m_pIndexStream->m_pVBI = static_cast<CIndexBuffer *>(pIndexData);
|
|
if (pVB)
|
|
{
|
|
switch (pVB->GetBufferDesc()->Format)
|
|
{
|
|
case D3DFMT_INDEX16:
|
|
m_pIndexStream->m_dwStride = 2;
|
|
break;
|
|
case D3DFMT_INDEX32:
|
|
#if DBG
|
|
if (GetD3DCaps()->MaxVertexIndex <= 0xFFFF)
|
|
{
|
|
DPF_ERR("Device does not support 32-bit indices. SetIndices failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
m_pIndexStream->m_dwStride = 4;
|
|
break;
|
|
default:
|
|
DPF_ERR("Invalid index buffer format. SetIndices failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#if DBG
|
|
m_pIndexStream->m_dwSize = pVB->GetBufferDesc()->Size;
|
|
#endif
|
|
m_pIndexStream->m_dwBaseIndex = BaseVertexIndex;
|
|
m_pIndexStream->m_pData = NULL;
|
|
#if DBG
|
|
m_pIndexStream->m_dwNumVertices = m_pIndexStream->m_dwSize /
|
|
m_pIndexStream->m_dwStride;
|
|
#endif
|
|
m_pIndexStream->m_pVBI->IncrementUseCount();
|
|
m_dwStreamDirty |= (1 << __NUMSTREAMS);
|
|
m_dwRuntimeFlags |= D3DRT_NEED_VB_UPDATE; // Need to call UpdateDirtyStreams()
|
|
}
|
|
return S_OK;
|
|
}
|
|
#endif // FAST_PATH
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::CreateVertexShader"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::CreateVertexShader(CONST DWORD* pdwDeclaration,
|
|
CONST DWORD* pdwFunction,
|
|
LPDWORD pdwHandle, DWORD Usage)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
#if DBG
|
|
// Validate Parameters
|
|
// WARNING!! sizeof(LPVOID) is not good enough
|
|
if (!VALID_PTR(pdwDeclaration, sizeof(LPVOID)))
|
|
{
|
|
D3D_ERR("Invalid shader declaration pointer. CreateVertexShader failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
// WARNING!! sizeof(LPVOID) is not good enough
|
|
if (pdwFunction && !VALID_PTR(pdwFunction, sizeof(LPVOID)))
|
|
{
|
|
D3D_ERR("Invalid shader function pointer. CreateVertexShader failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (pdwHandle && !VALID_WRITEPTR(pdwHandle, sizeof(DWORD)))
|
|
{
|
|
D3D_ERR("Invalid shader handle pointer. CreateVertexShader failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (Usage & ~D3DUSAGE_SOFTWAREPROCESSING)
|
|
{
|
|
D3D_ERR("Illegal usage value. CreateVertexShader failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (pdwHandle == NULL)
|
|
{
|
|
// Temporary vertex shaders are disabled
|
|
D3D_ERR("Output handle pointer cannot be NULL. CreateVertexShader failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if ((pdwFunction != NULL) &&
|
|
(GetD3DCaps()->VertexShaderVersion == D3DVS_VERSION(0,0)) &&
|
|
(BehaviorFlags() & (D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE)))
|
|
{
|
|
D3D_ERR("No programmable vertex shaders are supported by this device. CreateVertexShader failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
#endif // DBG
|
|
DWORD dwHandle = m_pVShaderArray->CreateNewHandle(NULL);
|
|
HRESULT ret = S_OK;
|
|
if (dwHandle == __INVALIDHANDLE)
|
|
{
|
|
D3D_ERR("Error in creating shader handle. CreateVertexShader failed.");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
CVShader *pShader = new CVShader(m_dwNumStreams);
|
|
if (pShader == NULL)
|
|
{
|
|
D3D_ERR("Cannot allocate memory for internal shader object. CreateVertexShader failed.");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
if (Usage & D3DUSAGE_SOFTWAREPROCESSING ||
|
|
BehaviorFlags() & D3DCREATE_SOFTWARE_VERTEXPROCESSING)
|
|
{
|
|
pShader->m_dwFlags |= CVShader::SOFTWARE;
|
|
Usage |= D3DUSAGE_SOFTWAREPROCESSING;
|
|
}
|
|
|
|
try
|
|
{
|
|
D3DCAPS8 Caps, *pCaps = NULL;
|
|
const D3DCAPS8 *pConstCaps = GetD3DCaps();
|
|
if( pConstCaps )
|
|
{
|
|
pCaps = &Caps;
|
|
memcpy(pCaps,pConstCaps,sizeof(D3DCAPS8));
|
|
pCaps->MaxStreams = m_dwNumStreams;
|
|
if( pShader->m_dwFlags & CVShader::SOFTWARE )
|
|
{
|
|
pCaps->VertexShaderVersion = D3DVS_VERSION(1, 1); // Version 1.1
|
|
pCaps->MaxVertexShaderConst = D3DVS_CONSTREG_MAX_V1_1;
|
|
}
|
|
}
|
|
if( !ValidateVertexShaderInternal(pdwFunction, pdwDeclaration, pCaps) )
|
|
{
|
|
ret = D3DERR_INVALIDCALL;
|
|
goto error;
|
|
}
|
|
|
|
// Even for the D3DCREATE_PUREDEVICE we create a shader object for
|
|
// validation
|
|
DWORD dwCodeOnlySize = 0;
|
|
DWORD dwCodeAndCommentSize = 0;
|
|
DWORD dwDeclSize = 0;
|
|
if (pdwFunction == NULL)
|
|
{
|
|
pShader->m_dwFlags |= CVShader::FIXEDFUNCTION;
|
|
pShader->m_Declaration.Parse(this, pdwDeclaration, TRUE, &dwDeclSize, Usage);
|
|
}
|
|
else
|
|
{
|
|
pShader->m_Declaration.Parse(this, pdwDeclaration, FALSE, &dwDeclSize, Usage);
|
|
HRESULT hr = ComputeShaderCodeSize(pdwFunction,
|
|
&dwCodeOnlySize,
|
|
&dwCodeAndCommentSize,
|
|
NULL);
|
|
if (hr != S_OK)
|
|
{
|
|
D3D_THROW(hr, "Unable to compute shader code size.");
|
|
}
|
|
pShader->m_pOrgFuncCode = new DWORD[dwCodeAndCommentSize];
|
|
pShader->m_pStrippedFuncCode = new DWORD[dwCodeOnlySize];
|
|
if (pShader->m_pOrgFuncCode == NULL ||
|
|
pShader->m_pStrippedFuncCode == NULL)
|
|
{
|
|
D3D_THROW(E_OUTOFMEMORY, "Could not allocate space for holding vertex shader");
|
|
}
|
|
|
|
pShader->m_OrgFuncCodeSize = dwCodeAndCommentSize;
|
|
memcpy(pShader->m_pOrgFuncCode, pdwFunction, dwCodeAndCommentSize);
|
|
|
|
pShader->m_StrippedFuncCodeSize = dwCodeOnlySize;
|
|
// copy and strip comments (instead of memcpy)
|
|
DWORD* pDst = pShader->m_pStrippedFuncCode;
|
|
CONST DWORD* pSrc = pdwFunction;
|
|
*pDst++ = *pSrc++; // copy version
|
|
while (*pSrc != 0x0000FFFF)
|
|
{
|
|
if(IsInstructionToken(*pSrc))
|
|
{
|
|
DWORD opCode = (*pSrc) & D3DSI_OPCODE_MASK;
|
|
if ( opCode == D3DSIO_COMMENT )
|
|
{
|
|
UINT DWordSize = ((*pSrc)&D3DSI_COMMENTSIZE_MASK)>>D3DSI_COMMENTSIZE_SHIFT;
|
|
pSrc += (DWordSize + 1); // comment + instruction token
|
|
}
|
|
else
|
|
{
|
|
*pDst++ = *pSrc++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pDst++ = *pSrc++;
|
|
}
|
|
}
|
|
*pDst++ = *pSrc++; // copy END
|
|
}
|
|
|
|
// ALways save the original declaration
|
|
pShader->m_pOrgDeclaration = new DWORD[dwDeclSize];
|
|
if (pShader->m_pOrgDeclaration == NULL)
|
|
{
|
|
D3D_THROW(E_OUTOFMEMORY, "Could not allocate space for holding vertex shader");
|
|
}
|
|
pShader->m_OrgDeclSize = dwDeclSize;
|
|
memcpy(pShader->m_pOrgDeclaration, pdwDeclaration, dwDeclSize);
|
|
|
|
m_pVShaderArray->SetObject(dwHandle, pShader);
|
|
|
|
CreateVertexShaderI(pdwDeclaration,
|
|
dwDeclSize,
|
|
pdwFunction,
|
|
dwCodeAndCommentSize, dwHandle);
|
|
}
|
|
catch(HRESULT hr)
|
|
{
|
|
ret = hr;
|
|
goto error;
|
|
}
|
|
|
|
*pdwHandle = dwHandle;
|
|
return S_OK;
|
|
|
|
error:
|
|
D3D_ERR("CreateVertexShader failed.");
|
|
delete pShader;
|
|
m_pVShaderArray->ReleaseHandle(dwHandle, FALSE);
|
|
return ret;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::CheckVertexShaderHandle"
|
|
|
|
void CD3DBase::CheckVertexShaderHandle(DWORD dwHandle)
|
|
{
|
|
if (dwHandle == 0)
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Invalid vertex shader handle");
|
|
}
|
|
if (D3DVSD_ISLEGACY(dwHandle))
|
|
{
|
|
if (((GetD3DCaps()->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0) &&
|
|
!FVF_TRANSFORMED(dwHandle) &&
|
|
(m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING) == 0)
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL,
|
|
"Untransformed data cannot be handles by this device");
|
|
}
|
|
|
|
if (FAILED(ValidateFVF(dwHandle)))
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Invalid FVF (or legacy vertex shader handle)");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CVShader* pShader = (CVShader*)m_pVShaderArray->GetObject(dwHandle);
|
|
if (pShader == NULL)
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Invalid vertex shader handle");
|
|
}
|
|
if (m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING)
|
|
{
|
|
if (!(pShader->m_dwFlags & CVShader::SOFTWARE))
|
|
{
|
|
D3D_THROW_FAIL("Vertex shader created in hardware mode cannot be used in software mode");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pShader->m_dwFlags & CVShader::SOFTWARE)
|
|
{
|
|
D3D_THROW_FAIL("Vertex shader created in software mode cannot be used in hardware mode");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::CheckPixelShaderHandle"
|
|
|
|
void CD3DBase::CheckPixelShaderHandle(DWORD dwHandle)
|
|
{
|
|
if (dwHandle != 0)
|
|
{
|
|
CPShader* pShader = (CPShader*)m_pPShaderArray->GetObject(dwHandle);
|
|
if (pShader == NULL)
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Invalid pixel shader handle");
|
|
}
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetVertexShader"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetVertexShader(DWORD dwHandle)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
try
|
|
{
|
|
#if DBG
|
|
CheckVertexShaderHandle(dwHandle);
|
|
#endif
|
|
if (m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE)
|
|
{
|
|
if (D3DVSD_ISLEGACY(dwHandle))
|
|
{
|
|
m_pStateSets->InsertVertexShader(dwHandle, TRUE);
|
|
}
|
|
else
|
|
{
|
|
CVShader* pShader = (CVShader*)m_pVShaderArray->GetObject(dwHandle);
|
|
if (pShader->m_dwFlags & CVShader::SOFTWARE)
|
|
m_pStateSets->InsertVertexShader(dwHandle, FALSE);
|
|
else
|
|
m_pStateSets->InsertVertexShader(dwHandle, TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetVertexShaderI(dwHandle);
|
|
}
|
|
}
|
|
catch(HRESULT hr)
|
|
{
|
|
DPF_ERR("SetVertexShader failed.");
|
|
ClearVertexShaderHandle();
|
|
return hr;
|
|
}
|
|
return S_OK;
|
|
}
|
|
#ifdef FAST_PATH
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetVertexShaderFast"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetVertexShaderFast(DWORD dwHandle)
|
|
{
|
|
try
|
|
{
|
|
#if DBG
|
|
CheckVertexShaderHandle(dwHandle);
|
|
if (!D3DVSD_ISLEGACY(dwHandle))
|
|
{
|
|
CVShader* pShader = (CVShader*)m_pVShaderArray->GetObject(dwHandle);
|
|
if (pShader->m_dwFlags & CVShader::SOFTWARE)
|
|
{
|
|
D3D_THROW_FAIL("Vertex shader created in software mode cannot be used in hardware mode");
|
|
}
|
|
}
|
|
#endif
|
|
DXGASSERT((m_dwRuntimeFlags & (D3DRT_RECORDSTATEMODE | D3DRT_RSSOFTWAREPROCESSING)) == 0 &&
|
|
(BehaviorFlags() & D3DCREATE_MULTITHREADED) == 0);
|
|
|
|
m_pDDI->SetVertexShaderHW(dwHandle);
|
|
}
|
|
catch(HRESULT hr)
|
|
{
|
|
DPF_ERR("SetVertexShader failed.");
|
|
ClearVertexShaderHandle();
|
|
return hr;
|
|
}
|
|
return S_OK;
|
|
}
|
|
#endif // FAST_PATH
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetVertexShader"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetVertexShader(LPDWORD pdwHandle)
|
|
{
|
|
API_ENTER(this);
|
|
D3D_ERR("GetVertexShader does not work in pure-device. GetVertexShader failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::DeleteVertexShader"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::DeleteVertexShader(DWORD dwHandle)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if DBG
|
|
// Validate Parameters
|
|
if (dwHandle == 0)
|
|
{
|
|
DPF_ERR( "Cannot delete a NULL vertex shader handle." );
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (D3DVSD_ISLEGACY(dwHandle))
|
|
{
|
|
DPF_ERR( "Cannot delete a legacy vertex shader handle (FVF ?)." );
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
if( m_pVShaderArray->GetObject(dwHandle) == NULL )
|
|
{
|
|
DPF_ERR( "Cannot delete a vertex shader handle that does not exist." );
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
try
|
|
{
|
|
DeleteVertexShaderI(dwHandle);
|
|
|
|
// Release handle and delete shader object
|
|
m_pVShaderArray->ReleaseHandle(dwHandle, TRUE);
|
|
}
|
|
catch(HRESULT hr)
|
|
{
|
|
DPF_ERR("DeleteVertexShader failed.");
|
|
return hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetVertexShaderConstant"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetVertexShaderConstant(DWORD Register,
|
|
CONST VOID* pData,
|
|
DWORD count)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if DBG
|
|
// Validate Parameters
|
|
if (!VALID_PTR(pData, 4* sizeof(DWORD) * count))
|
|
{
|
|
D3D_ERR("Invalid constant data pointer. SetVertexShaderConstant failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if ((GetD3DCaps()->VertexShaderVersion == D3DVS_VERSION(0,0)) &&
|
|
(BehaviorFlags() & (D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE)))
|
|
{
|
|
D3D_ERR("No programmable vertex shaders are supported by this device. SetVertexShaderConstant failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
UINT ValidationCount;
|
|
if (BehaviorFlags() & D3DCREATE_MIXED_VERTEXPROCESSING)
|
|
ValidationCount = max(m_MaxVertexShaderConst, D3DVS_CONSTREG_MAX_V1_1);
|
|
else
|
|
if (BehaviorFlags() & D3DCREATE_SOFTWARE_VERTEXPROCESSING)
|
|
ValidationCount = D3DVS_CONSTREG_MAX_V1_1;
|
|
else
|
|
ValidationCount = m_MaxVertexShaderConst;
|
|
if((Register + count) > ValidationCount)
|
|
{
|
|
D3D_ERR("Not that many constant registers in the vertex machine. SetVertexShaderConstant failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
try
|
|
{
|
|
if (m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE)
|
|
m_pStateSets->InsertVertexShaderConstant(Register,
|
|
pData,
|
|
count);
|
|
else
|
|
SetVertexShaderConstantI(Register, pData, count);
|
|
}
|
|
catch(HRESULT hr)
|
|
{
|
|
D3D_ERR("SetVertexShaderConstant failed.");
|
|
return hr;
|
|
}
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetVertexShaderConstantFast"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetVertexShaderConstantFast(DWORD Register,
|
|
CONST VOID* pData,
|
|
DWORD count)
|
|
{
|
|
|
|
#if DBG
|
|
// Validate Parameters
|
|
if (!VALID_PTR(pData, 4* sizeof(DWORD) * count))
|
|
{
|
|
D3D_ERR("Invalid constant data pointer. SetVertexShaderConstant failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if ((GetD3DCaps()->VertexShaderVersion == D3DVS_VERSION(0,0)) &&
|
|
(BehaviorFlags() & (D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE)))
|
|
{
|
|
D3D_ERR("No programmable vertex shaders are supported by this device. SetVertexShaderConstant failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
UINT ValidationCount;
|
|
if (BehaviorFlags() & D3DCREATE_MIXED_VERTEXPROCESSING)
|
|
ValidationCount = max(m_MaxVertexShaderConst, D3DVS_CONSTREG_MAX_V1_1);
|
|
else
|
|
if (BehaviorFlags() & D3DCREATE_SOFTWARE_VERTEXPROCESSING)
|
|
ValidationCount = D3DVS_CONSTREG_MAX_V1_1;
|
|
else
|
|
ValidationCount = m_MaxVertexShaderConst;
|
|
if((Register + count) > ValidationCount)
|
|
{
|
|
D3D_ERR("Not that many constant registers in the vertex machine. SetVertexShaderConstant failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
DXGASSERT((m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE) == 0 &&
|
|
(BehaviorFlags() & D3DCREATE_MULTITHREADED) == 0 &&
|
|
(BehaviorFlags() & D3DCREATE_PUREDEVICE) != 0);
|
|
try
|
|
{
|
|
m_pDDI->SetVertexShaderConstant(Register, pData, count);
|
|
}
|
|
catch(HRESULT hr)
|
|
{
|
|
D3D_ERR("SetVertexShaderConstant failed.");
|
|
return hr;
|
|
}
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetVertexShaderConstantI"
|
|
|
|
void
|
|
CD3DBase::SetVertexShaderConstantI(DWORD dwRegister, CONST VOID* pData, DWORD count)
|
|
{
|
|
m_pDDI->SetVertexShaderConstant(dwRegister, pData, count);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Pixel Shaders
|
|
//
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::CreatePixelShader"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::CreatePixelShader(CONST DWORD* pdwFunction, LPDWORD pdwHandle)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if DBG
|
|
// Validate Parameters
|
|
// WARNING!! sizeof(LPVOID) is not good enough
|
|
if (!VALID_PTR(pdwFunction, sizeof(LPVOID)))
|
|
{
|
|
D3D_ERR("Invalid shader function pointer. CreatePixelShader failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (!VALID_WRITEPTR(pdwHandle, sizeof(DWORD)))
|
|
{
|
|
D3D_ERR("Invalid handle pointer. CreatePixelShader failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
DWORD dwHandle = m_pPShaderArray->CreateNewHandle(NULL);
|
|
HRESULT ret = S_OK;
|
|
if (dwHandle == __INVALIDHANDLE)
|
|
{
|
|
D3D_ERR("Error in creating shader handle. CreatePixelShader failed.");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
CPShader *pShader = new CPShader();
|
|
if (pShader == NULL)
|
|
{
|
|
D3D_ERR("Cannot allocate memory for internal pixel shader object. CreatePixelShader failed.");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
try
|
|
{
|
|
if( !ValidatePixelShaderInternal(pdwFunction, GetD3DCaps()) )
|
|
{
|
|
ret = D3DERR_INVALIDCALL;
|
|
goto error;
|
|
}
|
|
DWORD dwVersion = *pdwFunction;
|
|
|
|
if ( (0xff == D3DSHADER_VERSION_MAJOR(dwVersion) )
|
|
&& (m_dwRuntimeFlags & D3DRT_DISALLOWNVPSHADERS) )
|
|
{
|
|
D3D_ERR("Disallowing non-versioned pixel shader.");
|
|
ret = D3DERR_INVALIDCALL;
|
|
goto error;
|
|
}
|
|
|
|
// Even for the D3DCREATE_PUREDEVICE we create a shader object for validation
|
|
pShader->Initialize(pdwFunction, GetDeviceType());
|
|
m_pPShaderArray->SetObject(dwHandle, pShader);
|
|
|
|
try
|
|
{
|
|
m_pDDI->CreatePixelShader(pShader->m_pCode,
|
|
pShader->m_dwCodeSize, dwHandle);
|
|
}
|
|
|
|
catch(HRESULT hr)
|
|
{
|
|
if( 0xff == D3DSHADER_VERSION_MAJOR(dwVersion) )
|
|
{
|
|
// This is a ff.ff shader. The driver is allowed to fail this.
|
|
D3D_INFO(0, "Driver failed the creation of this non-versioned pixel "
|
|
"shader");
|
|
throw D3DERR_DRIVERINVALIDCALL;
|
|
}
|
|
else
|
|
{
|
|
OutputDebugString( "Driver failed to create the requested "
|
|
"pixel shader. Please contact your "
|
|
"friendly video card manufacturer "
|
|
"to inquire why this problem was "
|
|
"encountered.\n" );
|
|
OutputDebugString( "\n" );
|
|
|
|
// NOTE! Prefix will catch this as a bug, but it is entirely
|
|
// intentional
|
|
*(DWORD *)0 = 0;
|
|
}
|
|
}
|
|
}
|
|
catch(HRESULT hr)
|
|
{
|
|
ret = hr;
|
|
goto error;
|
|
}
|
|
|
|
*pdwHandle = dwHandle;
|
|
return S_OK;
|
|
|
|
error:
|
|
|
|
D3D_ERR("CreatePixelShader failed.");
|
|
delete pShader;
|
|
m_pPShaderArray->ReleaseHandle(dwHandle, FALSE);
|
|
return ret;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetPixelShader"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetPixelShader(DWORD dwHandle)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
try
|
|
{
|
|
#if DBG
|
|
CheckPixelShaderHandle(dwHandle);
|
|
#endif
|
|
if (m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE)
|
|
m_pStateSets->InsertPixelShader(dwHandle);
|
|
else
|
|
SetPixelShaderFast(dwHandle);
|
|
}
|
|
catch(HRESULT hr)
|
|
{
|
|
D3D_ERR("SetPixelShader failed.");
|
|
m_dwCurrentPixelShaderHandle = 0;
|
|
return hr;
|
|
}
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetPixelShaderFast"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetPixelShaderFast(DWORD dwHandle)
|
|
{
|
|
try
|
|
{
|
|
#if DBG
|
|
CheckPixelShaderHandle(dwHandle);
|
|
#endif
|
|
// m_dwCurrentPixelShaderHandle is not defined for pure device
|
|
m_pDDI->SetPixelShader(dwHandle);
|
|
}
|
|
catch(HRESULT hr)
|
|
{
|
|
D3D_ERR("SetPixelShader failed.");
|
|
m_dwCurrentPixelShaderHandle = 0;
|
|
return hr;
|
|
}
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetPixelShader"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetPixelShader(LPDWORD pdwHandle)
|
|
{
|
|
API_ENTER(this);
|
|
D3D_ERR("GetPixelShader is not available for PUREDEVICE. GetPixelShader failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::DeletePixelShader"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::DeletePixelShader(DWORD dwHandle)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if DBG
|
|
// Validate Parameters
|
|
CPShader* pShader = (CPShader*)m_pPShaderArray->GetObject(dwHandle);
|
|
if (pShader == NULL)
|
|
{
|
|
D3D_ERR("Invalid pixel shader handle. DeletePixelShader failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
try
|
|
{
|
|
m_pDDI->DeletePixelShader(dwHandle);
|
|
|
|
// Release handle and delete shader object
|
|
m_pPShaderArray->ReleaseHandle(dwHandle, TRUE);
|
|
|
|
// If the pixel shader is current, set an invalid shader as current
|
|
// This is needed only for non-pure device.
|
|
if (dwHandle == m_dwCurrentPixelShaderHandle)
|
|
{
|
|
m_dwCurrentPixelShaderHandle = 0x0;
|
|
}
|
|
}
|
|
catch(HRESULT hr)
|
|
{
|
|
D3D_ERR("DeletePixelShader failed.");
|
|
return hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetPixelShaderConstant"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetPixelShaderConstant(DWORD Register, CONST VOID* pData,
|
|
DWORD count)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if DBG
|
|
// Validate Parameters
|
|
if (!VALID_PTR(pData, sizeof(DWORD) * count))
|
|
{
|
|
D3D_ERR("Invalid constant data pointer. SetPixelShaderConstant failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if(Register >= D3DPS_CONSTREG_MAX_DX8)
|
|
{
|
|
D3D_ERR("Invalid Constant Register number. SetPixelShaderConstant failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if( (Register + count) > D3DPS_CONSTREG_MAX_DX8 )
|
|
{
|
|
D3D_ERR("Not that many constant registers in the pixel machine. SetPixelShaderConstant failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
try
|
|
{
|
|
if (m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE)
|
|
m_pStateSets->InsertPixelShaderConstant(Register,
|
|
pData,
|
|
count);
|
|
else
|
|
SetPixelShaderConstantFast(Register, pData, count);
|
|
}
|
|
catch(HRESULT hr)
|
|
{
|
|
D3D_ERR("SetPixelShaderConstant failed.");
|
|
return hr;
|
|
}
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetPixelShaderConstantFast"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::SetPixelShaderConstantFast(DWORD Register, CONST VOID* pData,
|
|
DWORD count)
|
|
{
|
|
|
|
#if DBG
|
|
// Validate Parameters
|
|
if (!VALID_PTR(pData, sizeof(DWORD) * count))
|
|
{
|
|
D3D_ERR("Invalid constant data pointer. SetPixelShaderConstant failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if(Register >= D3DPS_CONSTREG_MAX_DX8)
|
|
{
|
|
D3D_ERR("Invalid Constant Register number. SetPixelShaderConstant failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if( (Register + count) > D3DPS_CONSTREG_MAX_DX8 )
|
|
{
|
|
D3D_ERR("Not that many constant registers in the pixel machine. SetPixelShaderConstant failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
try
|
|
{
|
|
m_pDDI->SetPixelShaderConstant(Register, pData, count);
|
|
}
|
|
catch(HRESULT hr)
|
|
{
|
|
D3D_ERR("SetPixelShaderConstant failed.");
|
|
return hr;
|
|
}
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetPixelShaderConstantI"
|
|
|
|
void
|
|
CD3DBase::GetPixelShaderConstantI(DWORD dwRegister, DWORD count, LPVOID pData)
|
|
{
|
|
// Should never be called.
|
|
DDASSERT( FALSE );
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::ValidateDraw"
|
|
|
|
void CD3DBase::ValidateDraw(D3DPRIMITIVETYPE primType,
|
|
UINT StartVertex,
|
|
UINT PrimitiveCount,
|
|
UINT NumVertices,
|
|
BOOL bIndexPrimitive,
|
|
BOOL bUserMemPrimitive)
|
|
{
|
|
#if DBG
|
|
if ((m_dwHintFlags & D3DDEVBOOL_HINTFLAGS_INSCENE) == 0)
|
|
{
|
|
D3D_THROW_FAIL("Need to call BeginScene before rendering.");
|
|
}
|
|
if (primType < D3DPT_POINTLIST || primType > D3DPT_TRIANGLEFAN)
|
|
{
|
|
D3D_THROW_FAIL("Invalid primitive type");
|
|
}
|
|
if (primType == D3DPT_POINTLIST && bIndexPrimitive)
|
|
{
|
|
D3D_THROW_FAIL("Indexed point lists are not supported");
|
|
}
|
|
if (PrimitiveCount == 0)
|
|
{
|
|
D3D_THROW_FAIL("Invalid primitive count");
|
|
}
|
|
// Number of vertices is always greater than or equal number of primitives
|
|
if (max(NumVertices, PrimitiveCount) > this->GetD3DCaps()->MaxPrimitiveCount)
|
|
{
|
|
D3D_THROW_FAIL("Primitive count or vertex count is too big. Check device caps.");
|
|
}
|
|
for (DWORD dwStage = 0; dwStage < m_dwMaxTextureBlendStages; dwStage++)
|
|
{
|
|
if (m_lpD3DMappedTexI[dwStage] != 0)
|
|
{
|
|
if (m_lpD3DMappedTexI[dwStage]->IsTextureLocked())
|
|
{
|
|
D3D_THROW_FAIL("Cannot render when currently set textures are locked.");
|
|
}
|
|
}
|
|
}
|
|
#endif //DBG
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
// Check if indices are within the range. We do it only for software
|
|
// processing because we do not want to read video memory
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::CheckIndices"
|
|
|
|
void CD3DBase::CheckIndices(CONST BYTE* pIndices, UINT NumIndices,
|
|
UINT StartIndex,
|
|
UINT MinIndex, UINT NumVertices, UINT IndexStride)
|
|
{
|
|
// Check if indices are within the range. We do it only for software
|
|
// processing because we do not want to read video memory
|
|
if (pIndices == NULL)
|
|
{
|
|
D3D_THROW_FAIL("Invalid index data pointer");
|
|
}
|
|
UINT MaxIndex = MinIndex + NumVertices - 1;
|
|
pIndices += IndexStride * StartIndex;
|
|
for (DWORD i = 0; i < NumIndices; i++)
|
|
{
|
|
DWORD dwIndex = IndexStride == 4?
|
|
*(DWORD*)pIndices : *(WORD*)pIndices;
|
|
pIndices += IndexStride;
|
|
if (dwIndex < MinIndex || dwIndex > MaxIndex)
|
|
{
|
|
D3D_ERR("Invalid index in the index stream: %d", dwIndex);
|
|
D3D_THROW_FAIL("");
|
|
}
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::DrawPrimitive"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType,
|
|
UINT StartVertex,
|
|
UINT PrimitiveCount)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
try
|
|
{
|
|
#if DBG
|
|
UINT nVer = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount);
|
|
try
|
|
{
|
|
ValidateDraw(PrimitiveType, StartVertex, PrimitiveCount, nVer,
|
|
FALSE, FALSE);
|
|
}
|
|
catch (HRESULT ret)
|
|
{
|
|
D3D_ERR("DrawPrimitive failed.");
|
|
return ret;
|
|
}
|
|
|
|
#endif // DBG
|
|
if (PrimitiveType != D3DPT_POINTLIST)
|
|
{
|
|
(*m_pfnDrawPrim)(this, PrimitiveType, StartVertex, PrimitiveCount);
|
|
}
|
|
else
|
|
DrawPointsI(PrimitiveType, StartVertex, PrimitiveCount);
|
|
}
|
|
catch (HRESULT ret)
|
|
{
|
|
D3D_ERR("DrawPrimitive failed.");
|
|
m_pDDI->ClearBatch(FALSE);
|
|
return ret;
|
|
}
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::DrawIndexedPrimitive"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::DrawIndexedPrimitive(D3DPRIMITIVETYPE PrimitiveType,
|
|
UINT MinIndex, UINT NumVertices, UINT StartIndex,
|
|
UINT PrimitiveCount)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if DBG
|
|
try
|
|
{
|
|
if (NumVertices == 0)
|
|
{
|
|
D3D_ERR("Invalid number of vertices. DrawIndexedPrimitive failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
DWORD dwNumIndices = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount);
|
|
if (dwNumIndices + StartIndex > m_pIndexStream->m_dwNumVertices)
|
|
{
|
|
D3D_ERR("Index stream does not have required number of indices. DrawIndexedPrimitive failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (m_pIndexStream == NULL)
|
|
{
|
|
D3D_ERR("No index stream object. Perhaps something went wrong at a mode-change. DrawIndexedPrimitive failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (m_pIndexStream->m_pVBI == NULL)
|
|
{
|
|
D3D_ERR("No valid index stream currently set. DrawIndexedPrimitive failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
ValidateDraw(PrimitiveType, MinIndex + m_pIndexStream->m_dwBaseIndex,
|
|
PrimitiveCount, NumVertices, TRUE, FALSE);
|
|
if (m_pIndexStream->m_pVBI->GetBufferDesc()->Pool == D3DPOOL_SYSTEMMEM &&
|
|
(m_pIndexStream->m_pVBI->GetBufferDesc()->Usage & D3DUSAGE_SOFTWAREPROCESSING) != 0)
|
|
{
|
|
CheckIndices((BYTE*)m_pIndexStream->m_pVBI->Data(),
|
|
dwNumIndices,
|
|
StartIndex, MinIndex, NumVertices,
|
|
m_pIndexStream->m_dwStride);
|
|
}
|
|
}
|
|
catch(HRESULT hr)
|
|
{
|
|
D3D_ERR("DrawIndexedPrimitive failed.");
|
|
return hr;
|
|
}
|
|
#endif //DBG
|
|
try
|
|
{
|
|
(*m_pfnDrawIndexedPrim)(this, PrimitiveType,
|
|
m_pIndexStream->m_dwBaseIndex,
|
|
MinIndex, NumVertices, StartIndex,
|
|
PrimitiveCount);
|
|
}
|
|
catch (HRESULT ret)
|
|
{
|
|
D3D_ERR("DrawIndexedPrimitive failed.");
|
|
m_pDDI->ClearBatch(FALSE);
|
|
return ret;
|
|
}
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::DrawRectPatch"
|
|
|
|
HRESULT D3DAPI CD3DBase::DrawRectPatch(UINT Handle, CONST FLOAT *pNumSegs,
|
|
CONST D3DRECTPATCH_INFO *pSurf)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if DBG
|
|
if ((m_dwHintFlags & D3DDEVBOOL_HINTFLAGS_INSCENE) == 0)
|
|
{
|
|
D3D_ERR("Need to call BeginScene before rendering.");
|
|
return (D3DERR_INVALIDCALL);
|
|
}
|
|
if ((m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING) != 0)
|
|
{
|
|
D3D_ERR("There is no emulation support for RT patches, hence only hardware device or hardware mode is legal. DrawRectPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if ((BehaviorFlags() & D3DCREATE_PUREDEVICE) == 0)
|
|
{
|
|
CD3DHal* pDevice = static_cast<CD3DHal*>(this);
|
|
if (!D3DVSD_ISLEGACY(pDevice->m_dwCurrentShaderHandle))
|
|
{
|
|
if (pDevice->m_pv->dwDeviceFlags & D3DDEV_VERTEXSHADERS)
|
|
{
|
|
for (DWORD i=0; i < D3DHAL_TSS_MAXSTAGES; i++)
|
|
{
|
|
if (pDevice->tsstates[i][D3DTSS_TEXCOORDINDEX] != i)
|
|
{
|
|
D3D_ERR("Stage %d - Texture coordinate index in the stage "
|
|
"must be equal to the stage index when programmable"
|
|
" vertex pipeline is used", i);
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
DWORD TexTransformFlags = pDevice->tsstates[i][D3DTSS_TEXTURETRANSFORMFLAGS];
|
|
if ((TexTransformFlags & ~D3DTTFF_PROJECTED) != D3DTTFF_DISABLE)
|
|
{
|
|
D3D_ERR("Stage %d - Count in D3DTSS_TEXTURETRANSFORMFLAGS "
|
|
"must be 0 when programmable pipeline is used", i);
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((GetD3DCaps()->DevCaps & D3DDEVCAPS_RTPATCHES) == 0)
|
|
{
|
|
D3D_ERR("RT patches unsupported on current device. DrawRectPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
if (Handle == 0 && pSurf == 0)
|
|
{
|
|
D3D_ERR("Handle and patch specification cannot be both zero. DrawRectPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
if (pSurf != 0)
|
|
{
|
|
if (!VALID_PTR(pSurf, sizeof(D3DRECTPATCH_INFO)))
|
|
{
|
|
D3D_ERR("Invalid patch information pointer. DrawRectPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (pSurf->Order != D3DORDER_LINEAR &&
|
|
pSurf->Order != D3DORDER_CUBIC &&
|
|
pSurf->Order != D3DORDER_QUINTIC)
|
|
{
|
|
D3D_ERR("Order not supported. DrawRectPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (pSurf->Order == D3DORDER_QUINTIC && (GetD3DCaps()->DevCaps & D3DDEVCAPS_QUINTICRTPATCHES) == 0)
|
|
{
|
|
D3D_ERR("Quintic patches not supported on this device. DrawRectPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (pSurf->Basis != D3DBASIS_BEZIER &&
|
|
pSurf->Basis != D3DBASIS_BSPLINE &&
|
|
pSurf->Basis != D3DBASIS_INTERPOLATE)
|
|
{
|
|
D3D_ERR("Basis not supported. DrawRectPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (pSurf->Basis == D3DBASIS_BEZIER)
|
|
{
|
|
if (pSurf->Width != (DWORD)pSurf->Order + 1 ||
|
|
pSurf->Height != (DWORD)pSurf->Order + 1)
|
|
{
|
|
D3D_ERR("Bezier patch must have correct dimensions to match order. DrawRectPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pSurf->Width <= (DWORD)pSurf->Order ||
|
|
pSurf->Height <= (DWORD)pSurf->Order)
|
|
{
|
|
D3D_ERR("Patch dimensions too small for the order. DrawRectPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (pSurf->Basis == D3DBASIS_INTERPOLATE && pSurf->Order != D3DORDER_CUBIC)
|
|
{
|
|
D3D_ERR("Only bicubic interpolating splines supported. DrawRectPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
}
|
|
|
|
if (pSurf->Stride == 0)
|
|
{
|
|
D3D_ERR("Stride cannot be zero. DrawRectPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
if ((BehaviorFlags() & D3DCREATE_PUREDEVICE) == 0)
|
|
{
|
|
try
|
|
{
|
|
static_cast<CD3DHal*>(this)->ValidateRTPatch();
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
D3D_ERR("DrawRectPatch failed.");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
if ((BehaviorFlags() & D3DCREATE_PUREDEVICE) == 0 && Handle != 0)
|
|
{
|
|
// Need to snapshot current Vshader in the Handle table
|
|
HRESULT hr = m_pRTPatchValidationInfo->Grow(Handle);
|
|
if (FAILED(hr))
|
|
{
|
|
D3D_ERR("Could not grow handle table. DrawRectPatch failed.");
|
|
return hr;
|
|
}
|
|
if ((*m_pRTPatchValidationInfo)[Handle].m_pObj == 0)
|
|
{
|
|
(*m_pRTPatchValidationInfo)[Handle].m_pObj = new CRTPatchValidationInfo;
|
|
if ((*m_pRTPatchValidationInfo)[Handle].m_pObj == 0)
|
|
{
|
|
D3D_ERR("Out of memory growing handle table. DrawRectPatch failed.");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
static_cast<CRTPatchValidationInfo*>((*m_pRTPatchValidationInfo)[Handle].m_pObj)->m_ShaderHandle = m_dwCurrentShaderHandle;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((BehaviorFlags() & D3DCREATE_PUREDEVICE) == 0 && Handle != 0)
|
|
{
|
|
if (Handle >= m_pRTPatchValidationInfo->GetSize())
|
|
{
|
|
D3D_ERR("Cannot draw a patch without any information. DrawRectPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if ((*m_pRTPatchValidationInfo)[Handle].m_pObj == 0)
|
|
{
|
|
D3D_ERR("Cannot draw a patch without any information. DrawRectPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (static_cast<CRTPatchValidationInfo*>((*m_pRTPatchValidationInfo)[Handle].m_pObj)->m_ShaderHandle != m_dwCurrentShaderHandle)
|
|
{
|
|
D3D_ERR("Cannot set a vertex shader different from the one set when the patch was first created. DrawRectPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
}
|
|
}
|
|
if (pNumSegs != 0)
|
|
{
|
|
if (!VALID_PTR(pNumSegs, sizeof(FLOAT) * 4))
|
|
{
|
|
D3D_ERR("Invalid pointer to array of 4 floats (NumSegs). DrawRectPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
try
|
|
{
|
|
m_pDDI->DrawRectPatch(Handle, pSurf, pNumSegs);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
D3D_ERR("DrawRectPatch failed.");
|
|
return ret;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::DrawTriPatch"
|
|
|
|
HRESULT D3DAPI CD3DBase::DrawTriPatch(UINT Handle, CONST FLOAT *pNumSegs,
|
|
CONST D3DTRIPATCH_INFO *pSurf)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if DBG
|
|
if ((m_dwHintFlags & D3DDEVBOOL_HINTFLAGS_INSCENE) == 0)
|
|
{
|
|
D3D_ERR("Need to call BeginScene before rendering.");
|
|
return (D3DERR_INVALIDCALL);
|
|
}
|
|
if ((m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING) != 0)
|
|
{
|
|
D3D_ERR("There is no emulation support for RT patches, hence only hardware device or hardware mode is legal. DrawTriPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if ((BehaviorFlags() & D3DCREATE_PUREDEVICE) == 0)
|
|
{
|
|
CD3DHal* pDevice = static_cast<CD3DHal*>(this);
|
|
if (!D3DVSD_ISLEGACY(pDevice->m_dwCurrentShaderHandle))
|
|
{
|
|
if (pDevice->m_pv->dwDeviceFlags & D3DDEV_VERTEXSHADERS)
|
|
{
|
|
for (DWORD i=0; i < D3DHAL_TSS_MAXSTAGES; i++)
|
|
{
|
|
if (pDevice->tsstates[i][D3DTSS_TEXCOORDINDEX] != i)
|
|
{
|
|
D3D_ERR("Stage %d - Texture coordinate index in the stage "
|
|
"must be equal to the stage index when programmable"
|
|
" vertex pipeline is used", i);
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
DWORD TexTransformFlags = pDevice->tsstates[i][D3DTSS_TEXTURETRANSFORMFLAGS];
|
|
if ((TexTransformFlags & ~D3DTTFF_PROJECTED) != D3DTTFF_DISABLE)
|
|
{
|
|
D3D_ERR("Stage %d - Count in D3DTSS_TEXTURETRANSFORMFLAGS "
|
|
"must be 0 when programmable pipeline is used", i);
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if ((GetD3DCaps()->DevCaps & D3DDEVCAPS_RTPATCHES) == 0)
|
|
{
|
|
D3D_ERR("RT patches unsupported on current device. DrawTriPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
if (Handle == 0 && pSurf == 0)
|
|
{
|
|
D3D_ERR("Handle and patch specification cannot be both zero. DrawTriPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
if (pSurf != 0)
|
|
{
|
|
if (!VALID_PTR(pSurf, sizeof(D3DTRIPATCH_INFO)))
|
|
{
|
|
D3D_ERR("Invalid patch information pointer. DrawTriPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (pSurf->Order != D3DORDER_LINEAR &&
|
|
pSurf->Order != D3DORDER_CUBIC &&
|
|
pSurf->Order != D3DORDER_QUINTIC)
|
|
{
|
|
D3D_ERR("Order not supported. DrawTriPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (pSurf->Order == D3DORDER_QUINTIC && (GetD3DCaps()->DevCaps & D3DDEVCAPS_QUINTICRTPATCHES) == 0)
|
|
{
|
|
D3D_ERR("Quintic patches not supported on this device. DrawTriPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (pSurf->Basis != D3DBASIS_BEZIER)
|
|
{
|
|
D3D_ERR("Only Bezier basis is supported. DrawTriPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (pSurf->Order == D3DORDER_LINEAR && pSurf->NumVertices != 3)
|
|
{
|
|
D3D_ERR("Only three vertices supported with linear order. DrawTriPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
else if (pSurf->Order == D3DORDER_CUBIC && pSurf->NumVertices != 10)
|
|
{
|
|
D3D_ERR("Only ten vertices supported with cubic order. DrawTriPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
else if (pSurf->Order == D3DORDER_QUINTIC && pSurf->NumVertices != 21)
|
|
{
|
|
D3D_ERR("Only 21 vertices supported with quintic order. DrawTriPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if ((BehaviorFlags() & D3DCREATE_PUREDEVICE) == 0)
|
|
{
|
|
try
|
|
{
|
|
static_cast<CD3DHal*>(this)->ValidateRTPatch();
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
D3D_ERR("DrawTriPatch failed.");
|
|
return ret;
|
|
}
|
|
}
|
|
if ((BehaviorFlags() & D3DCREATE_PUREDEVICE) == 0 && Handle != 0)
|
|
{
|
|
// Need to snapshot current Vshader in the Handle table
|
|
HRESULT hr = m_pRTPatchValidationInfo->Grow(Handle);
|
|
if (FAILED(hr))
|
|
{
|
|
D3D_ERR("Could not grow handle table. DrawTriPatch failed.");
|
|
return hr;
|
|
}
|
|
if ((*m_pRTPatchValidationInfo)[Handle].m_pObj == 0)
|
|
{
|
|
(*m_pRTPatchValidationInfo)[Handle].m_pObj = new CRTPatchValidationInfo;
|
|
if ((*m_pRTPatchValidationInfo)[Handle].m_pObj == 0)
|
|
{
|
|
D3D_ERR("Out of memory growing handle table. DrawTriPatch failed.");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
static_cast<CRTPatchValidationInfo*>((*m_pRTPatchValidationInfo)[Handle].m_pObj)->m_ShaderHandle = m_dwCurrentShaderHandle;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((BehaviorFlags() & D3DCREATE_PUREDEVICE) == 0 && Handle != 0)
|
|
{
|
|
if (Handle >= m_pRTPatchValidationInfo->GetSize())
|
|
{
|
|
D3D_ERR("Cannot draw a patch without any information. DrawTriPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if ((*m_pRTPatchValidationInfo)[Handle].m_pObj == 0)
|
|
{
|
|
D3D_ERR("Cannot draw a patch without any information. DrawTriPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (static_cast<CRTPatchValidationInfo*>((*m_pRTPatchValidationInfo)[Handle].m_pObj)->m_ShaderHandle != m_dwCurrentShaderHandle)
|
|
{
|
|
D3D_ERR("Cannot set a vertex shader different from the one set when the patch was first created. DrawTriPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
}
|
|
}
|
|
if (pNumSegs != 0)
|
|
{
|
|
if (!VALID_PTR(pNumSegs, sizeof(FLOAT) * 3))
|
|
{
|
|
D3D_ERR("Invalid pointer to array of 3 floats (NumSegs). DrawTriPatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
try
|
|
{
|
|
m_pDDI->DrawTriPatch(Handle, pSurf, pNumSegs);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
D3D_ERR("DrawTriPatch failed.");
|
|
return ret;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::DeletePatch"
|
|
|
|
HRESULT D3DAPI CD3DBase::DeletePatch(UINT Handle)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
if ((GetD3DCaps()->DevCaps & D3DDEVCAPS_RTPATCHES) == 0)
|
|
{
|
|
D3D_ERR("High order surfaces unsupported on current device. DeletePatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
if (Handle == 0)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
#if DBG
|
|
if ((BehaviorFlags() & D3DCREATE_PUREDEVICE) == 0)
|
|
{
|
|
if (Handle >= m_pRTPatchValidationInfo->GetSize())
|
|
{
|
|
D3D_ERR("Attempt to delete non-existent patch. DeletePatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if ((*m_pRTPatchValidationInfo)[Handle].m_pObj == 0)
|
|
{
|
|
D3D_ERR("Attempt to delete non-existent patch. DeletePatch failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
delete (*m_pRTPatchValidationInfo)[Handle].m_pObj;
|
|
(*m_pRTPatchValidationInfo)[Handle].m_pObj = 0;
|
|
}
|
|
#endif // DBG
|
|
|
|
try
|
|
{
|
|
m_pDDI->SetRenderState((D3DRENDERSTATETYPE)D3DRS_DELETERTPATCH, Handle);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
D3D_ERR("DeletePatch failed.");
|
|
return ret;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::DrawPrimitiveUP"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType,
|
|
UINT PrimitiveCount,
|
|
CONST VOID *pVertexStreamZeroData,
|
|
UINT VertexStreamZeroStride)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
m_dwRuntimeFlags |= D3DRT_USERMEMPRIMITIVE;
|
|
try
|
|
{
|
|
if (m_pStream[0].m_pVB)
|
|
{
|
|
m_pDDI->VBReleased(m_pStream[0].m_pVB);
|
|
m_pStream[0].m_pVB->DecrementUseCount();
|
|
m_pStream[0].m_pVB = NULL;
|
|
}
|
|
m_pStream[0].m_pData = (BYTE*)pVertexStreamZeroData;
|
|
m_pStream[0].m_dwStride = VertexStreamZeroStride;
|
|
#if DBG
|
|
UINT nVer = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount);
|
|
if (!VALID_PTR(pVertexStreamZeroData, nVer*VertexStreamZeroStride))
|
|
{
|
|
D3D_THROW_FAIL("Invalid input vertex stream pointer");
|
|
}
|
|
m_pStream[0].m_dwSize = nVer * VertexStreamZeroStride;
|
|
m_pStream[0].m_dwNumVertices = nVer;
|
|
try
|
|
{
|
|
ValidateDraw(PrimitiveType, 0, PrimitiveCount, nVer, FALSE, TRUE);
|
|
}
|
|
catch (HRESULT ret)
|
|
{
|
|
m_dwRuntimeFlags &= ~D3DRT_USERMEMPRIMITIVE;
|
|
return ret;
|
|
}
|
|
#endif // DBG
|
|
DrawPrimitiveUPI(PrimitiveType, PrimitiveCount);
|
|
// Invalidate stream zero
|
|
m_pStream[0].m_pData = NULL;
|
|
#if DBG
|
|
m_pStream[0].m_dwSize = 0;
|
|
#endif
|
|
m_pStream[0].m_dwStride = 0;
|
|
}
|
|
catch (HRESULT ret)
|
|
{
|
|
D3D_ERR("DrawPrimitiveUP failed.");
|
|
#if DBG
|
|
m_dwRuntimeFlags &= ~D3DRT_USERMEMPRIMITIVE;
|
|
#endif
|
|
m_pDDI->ClearBatch(FALSE);
|
|
return ret;
|
|
}
|
|
m_dwRuntimeFlags &= ~D3DRT_USERMEMPRIMITIVE;
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::DrawPrimitiveUPI"
|
|
|
|
void CD3DBase::DrawPrimitiveUPI(D3DPRIMITIVETYPE PrimType, UINT PrimCount)
|
|
{
|
|
m_pDDI->DrawPrimitiveUP(PrimType, PrimCount);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::DrawIndexedPrimitiveUPI"
|
|
|
|
void
|
|
CD3DBase::DrawIndexedPrimitiveUPI(D3DPRIMITIVETYPE PrimitiveType,
|
|
UINT MinVertexIndex,
|
|
UINT NumVertices,
|
|
UINT PrimitiveCount)
|
|
{
|
|
m_pDDI->DrawIndexedPrimitiveUP(PrimitiveType, MinVertexIndex, NumVertices,
|
|
PrimitiveCount);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::DrawIndexedPrimitiveUP"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType,
|
|
UINT MinIndex, UINT NumVertices,
|
|
UINT PrimitiveCount,
|
|
CONST VOID *pIndexData, D3DFORMAT IndexDataFormat,
|
|
CONST VOID *pVertexStreamZeroData,
|
|
UINT VertexStreamZeroStride)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
m_dwRuntimeFlags |= D3DRT_USERMEMPRIMITIVE;
|
|
|
|
try
|
|
{
|
|
if (m_pStream[0].m_pVB)
|
|
{
|
|
m_pDDI->VBReleased(m_pStream[0].m_pVB);
|
|
m_pStream[0].m_pVB->DecrementUseCount();
|
|
m_pStream[0].m_pVB = NULL;
|
|
}
|
|
if (m_pIndexStream->m_pVBI)
|
|
{
|
|
m_pDDI->VBIReleased(m_pIndexStream->m_pVBI);
|
|
m_pIndexStream->m_pVBI->DecrementUseCount();
|
|
m_pIndexStream->m_pVBI = NULL;
|
|
}
|
|
m_pStream[0].m_pData = (BYTE*)pVertexStreamZeroData;
|
|
m_pStream[0].m_dwStride = VertexStreamZeroStride;
|
|
|
|
m_pIndexStream->m_pData = (BYTE*)pIndexData;
|
|
m_pIndexStream->m_dwBaseIndex = 0;
|
|
if (IndexDataFormat == D3DFMT_INDEX16)
|
|
m_pIndexStream->m_dwStride = 2;
|
|
else
|
|
if (IndexDataFormat == D3DFMT_INDEX32)
|
|
{
|
|
#if DBG
|
|
if (GetD3DCaps()->MaxVertexIndex <= 0xFFFF)
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Device does not support 32-bit indices");
|
|
#endif
|
|
m_pIndexStream->m_dwStride = 4;
|
|
}
|
|
else
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Invalid index data format");
|
|
}
|
|
#if DBG
|
|
try
|
|
{
|
|
if (pVertexStreamZeroData == NULL)
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Invalid vertex stream pointer");
|
|
}
|
|
if (pIndexData == NULL)
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Invalid index data pointer");
|
|
}
|
|
if (NumVertices == 0)
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Invalid number of vertices");
|
|
}
|
|
m_pStream[0].m_dwSize = NumVertices * VertexStreamZeroStride;
|
|
m_pStream[0].m_dwNumVertices = NumVertices;
|
|
|
|
UINT NumIndices = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount);
|
|
m_pIndexStream[0].m_dwSize = NumIndices * m_pIndexStream[0].m_dwStride;
|
|
m_pIndexStream[0].m_dwNumVertices = NumIndices;
|
|
if (m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING)
|
|
{
|
|
CheckIndices((BYTE*)pIndexData, NumIndices, 0, MinIndex,
|
|
NumVertices, m_pIndexStream->m_dwStride);
|
|
}
|
|
ValidateDraw(PrimitiveType, MinIndex, PrimitiveCount, NumVertices,
|
|
TRUE, TRUE);
|
|
}
|
|
catch (HRESULT ret)
|
|
{
|
|
D3D_ERR("DrawIndexedPrimitiveUP failed.");
|
|
m_dwRuntimeFlags &= ~D3DRT_USERMEMPRIMITIVE;
|
|
return ret;
|
|
}
|
|
#endif // DBG
|
|
|
|
DrawIndexedPrimitiveUPI(PrimitiveType, MinIndex, NumVertices, PrimitiveCount);
|
|
|
|
// Invalidate stream zero
|
|
m_pStream[0].m_pData = NULL;
|
|
#if DBG
|
|
m_pStream[0].m_dwSize = 0;
|
|
#endif
|
|
m_pStream[0].m_dwStride = 0;
|
|
//Invalidate index stream
|
|
m_pIndexStream[0].m_pData = NULL;
|
|
#if DBG
|
|
m_pIndexStream[0].m_dwSize = 0;
|
|
#endif
|
|
m_pIndexStream[0].m_dwStride = 0;
|
|
}
|
|
catch (HRESULT ret)
|
|
{
|
|
D3D_ERR("DrawIndexedPrimitiveUP failed.");
|
|
m_dwRuntimeFlags &= ~D3DRT_USERMEMPRIMITIVE;
|
|
m_pDDI->ClearBatch(FALSE);
|
|
return ret;
|
|
}
|
|
m_dwRuntimeFlags &= ~D3DRT_USERMEMPRIMITIVE;
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::DrawPointsI"
|
|
|
|
void
|
|
CD3DBase::DrawPointsI(D3DPRIMITIVETYPE PrimitiveType,
|
|
UINT StartVertex,
|
|
UINT PrimitiveCount)
|
|
{
|
|
(*m_pfnDrawPrim)(this, PrimitiveType, StartVertex, PrimitiveCount);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::CreateVertexShaderI"
|
|
|
|
void
|
|
CD3DBase::CreateVertexShaderI(CONST DWORD* pdwDeclaration, DWORD dwDeclSize,
|
|
CONST DWORD* pdwFunction, DWORD dwCodeSize,
|
|
DWORD dwHandle)
|
|
{
|
|
CVShader* pShader = (CVShader*)m_pVShaderArray->GetObject(dwHandle);
|
|
#if DBG
|
|
if (pShader->m_dwFlags & CVShader::SOFTWARE)
|
|
{
|
|
D3D_THROW_FAIL("Software vertex shader cannot be created with a PUREDEVICE");
|
|
}
|
|
|
|
#endif // DBG
|
|
// always pass stripped version for pure hal
|
|
m_pDDI->CreateVertexShader(pdwDeclaration, dwDeclSize,
|
|
pShader->m_pStrippedFuncCode,
|
|
pShader->m_StrippedFuncCodeSize, dwHandle,
|
|
pShader->m_Declaration.m_bLegacyFVF);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetVertexShaderI"
|
|
|
|
void CD3DBase::SetVertexShaderI(DWORD dwHandle)
|
|
{
|
|
#if DBG
|
|
CheckVertexShaderHandle(dwHandle);
|
|
if (!D3DVSD_ISLEGACY(dwHandle))
|
|
{
|
|
CVShader* pShader = (CVShader*)m_pVShaderArray->GetObject(dwHandle);
|
|
if (pShader->m_dwFlags & CVShader::SOFTWARE)
|
|
{
|
|
D3D_THROW_FAIL("Vertex shader created in software mode cannot be used in hardware mode");
|
|
}
|
|
}
|
|
#endif // DBG
|
|
m_pDDI->SetVertexShaderHW(dwHandle);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::DeleteVertexShaderI"
|
|
|
|
void CD3DBase::DeleteVertexShaderI(DWORD dwHandle)
|
|
{
|
|
m_pDDI->DeleteVertexShader(dwHandle);
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::Clear"
|
|
|
|
#define bDoRGBClear ((dwFlags & D3DCLEAR_TARGET)!=0)
|
|
#define bDoZClear ((dwFlags & D3DCLEAR_ZBUFFER)!=0)
|
|
#define bDoStencilClear ((dwFlags & D3DCLEAR_STENCIL)!=0)
|
|
|
|
// Maximum number of clear rectangles considered legal.
|
|
// This limit is set by NT kernel for Clear2 callback
|
|
const DWORD MAX_CLEAR_RECTS = 0x1000;
|
|
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::ClearI"
|
|
|
|
void
|
|
CD3DBase::ClearI(DWORD dwCount,
|
|
CONST D3DRECT* rects,
|
|
DWORD dwFlags,
|
|
D3DCOLOR dwColor,
|
|
D3DVALUE dvZ,
|
|
DWORD dwStencil)
|
|
{
|
|
if (rects == NULL)
|
|
dwCount = 0;
|
|
|
|
// We do not cull rects against viewport, so let the driver do it
|
|
dwFlags |= D3DCLEAR_COMPUTERECTS;
|
|
m_pDDI->Clear(dwFlags, dwCount, (LPD3DRECT)rects, dwColor, dvZ, dwStencil);
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::Clear"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::Clear(DWORD dwCount,
|
|
CONST D3DRECT* rects,
|
|
DWORD dwFlags,
|
|
D3DCOLOR dwColor,
|
|
D3DVALUE dvZ,
|
|
DWORD dwStencil)
|
|
{
|
|
API_ENTER(this); // Takes D3D Lock if necessary
|
|
|
|
#if DBG
|
|
if (IsBadReadPtr(rects, dwCount * sizeof(D3DRECT)))
|
|
{
|
|
D3D_ERR("Invalid rects pointer. Clear failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
#endif
|
|
try
|
|
{
|
|
HRESULT err;
|
|
LPDDPIXELFORMAT pZPixFmt=NULL;
|
|
|
|
if (dwCount > MAX_CLEAR_RECTS)
|
|
{
|
|
D3D_ERR("Cannot support more than 64K rectangles. Clear failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (!(GetD3DCaps()->RasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR))
|
|
{
|
|
if (bDoStencilClear||bDoZClear)
|
|
{
|
|
if (this->ZBuffer()==NULL)
|
|
{
|
|
// unlike Clear(), specifying a Zbuffer-clearing flag without a zbuffer will
|
|
// be considered an error
|
|
#if DBG
|
|
if (bDoZClear)
|
|
{
|
|
D3D_ERR("Invalid flag D3DCLEAR_ZBUFFER: no zbuffer is associated with device. Clear failed.");
|
|
}
|
|
if (bDoStencilClear)
|
|
{
|
|
D3D_ERR("Invalid flag D3DCLEAR_STENCIL: no zbuffer is associated with device. Clear failed.");
|
|
}
|
|
#endif
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
if (bDoStencilClear)
|
|
{
|
|
D3DSURFACE_DESC desc = (this->ZBuffer())->InternalGetDesc();
|
|
if (!CPixel::IsIHVFormat(desc.Format) &&
|
|
!CPixel::HasStencilBits(desc.Format))
|
|
{
|
|
D3D_ERR("Invalid flag D3DCLEAR_STENCIL; current zbuffer's pixel format doesnt support stencil bits. Clear failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!(dwFlags & (D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL)))
|
|
{
|
|
D3D_ERR("Flags not valid. Clear failed.");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
// bad clear values just cause wacky results but no crashes, so OK to allow in retail bld
|
|
|
|
DDASSERT(!bDoZClear || ((dvZ>=0.0) && (dvZ<=1.0)));
|
|
DDASSERT(!bDoStencilClear || !pZPixFmt || (dwStencil <= (DWORD)((1<<pZPixFmt->dwStencilBitDepth)-1)));
|
|
|
|
ClearI(dwCount, rects, dwFlags, dwColor, dvZ, dwStencil);
|
|
return D3D_OK;
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
D3D_ERR("Clear failed.");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::FlushStatesNoThrow"
|
|
void __declspec(nothrow) CD3DBase::FlushStatesNoThrow()
|
|
{
|
|
try
|
|
{
|
|
DXGASSERT(m_pDDI);
|
|
m_pDDI->FlushStates();
|
|
}
|
|
catch(HRESULT hr)
|
|
{
|
|
DPF_ERR("Driver failed a command batch will synchronizing a synchronous call with the command stream. (No error will be returned to the app)");
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::TexBlt"
|
|
HRESULT __declspec(nothrow) CD3DBase::TexBlt(CBaseTexture *pDst,
|
|
CBaseTexture *pSrc,
|
|
POINT *pPoint,
|
|
RECTL *pRect)
|
|
{
|
|
// Get the draw prim handles
|
|
DWORD dwSrc = pSrc->BaseDrawPrimHandle();
|
|
|
|
DWORD dwDst = 0;
|
|
if (pDst)
|
|
{
|
|
dwDst = pDst->DriverAccessibleDrawPrimHandle();
|
|
}
|
|
|
|
// Insert the tokens now
|
|
try
|
|
{
|
|
m_pDDI->TexBlt(dwDst, dwSrc, pPoint, pRect);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
// If successful, batch the source and dest
|
|
// For the source, we want to call BatchBase since
|
|
// we want to batch the backing (or sysmem) texture
|
|
// rather than the promoted one.
|
|
pSrc->BatchBase();
|
|
if (pDst != NULL)
|
|
{
|
|
pDst->Batch();
|
|
}
|
|
|
|
return D3D_OK;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::CubeTexBlt"
|
|
|
|
// Very similar function to TexBlt except that
|
|
// this is done for cube-maps which are special since we
|
|
// need to send different handles for each face
|
|
HRESULT __declspec(nothrow) CD3DBase::CubeTexBlt(CBaseTexture *pDstParent,
|
|
CBaseTexture *pSrcParent,
|
|
DWORD dwDestFaceHandle,
|
|
DWORD dwSrcFaceHandle,
|
|
POINT *pPoint,
|
|
RECTL *pRect)
|
|
{
|
|
// CubeTexBlt is not overloaded for use with PreLoad semantics
|
|
// so we should always have a source and a dest
|
|
DXGASSERT(pDstParent);
|
|
DXGASSERT(pSrcParent);
|
|
|
|
// Insert the tokens now
|
|
try
|
|
{
|
|
m_pDDI->TexBlt(dwDestFaceHandle, dwSrcFaceHandle, pPoint, pRect);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
// If successful, batch the parents of the source and dest
|
|
// For the source, we want to call BatchBase since
|
|
// we want to batch the backing (or sysmem) texture
|
|
// rather than the promoted one.
|
|
pSrcParent->BatchBase();
|
|
pDstParent->Batch();
|
|
|
|
return D3D_OK;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::VolBlt"
|
|
HRESULT __declspec(nothrow)
|
|
CD3DBase::VolBlt(CBaseTexture *lpDst, CBaseTexture* lpSrc, DWORD dwDestX,
|
|
DWORD dwDestY, DWORD dwDestZ, D3DBOX *pBox)
|
|
{
|
|
try
|
|
{
|
|
m_pDDI->VolBlt(lpDst, lpSrc, dwDestX, dwDestY, dwDestZ, pBox);
|
|
return D3D_OK;
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::BufBlt"
|
|
HRESULT __declspec(nothrow)
|
|
CD3DBase::BufBlt(CBuffer *lpDst, CBuffer* lpSrc, DWORD dwOffset,
|
|
D3DRANGE* pRange)
|
|
{
|
|
try
|
|
{
|
|
m_pDDI->BufBlt(lpDst, lpSrc, dwOffset, pRange);
|
|
return D3D_OK;
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetPriority"
|
|
|
|
HRESULT __declspec(nothrow) CD3DBase::SetPriority(CResource *pRes, DWORD dwPriority)
|
|
{
|
|
try
|
|
{
|
|
m_pDDI->SetPriority(pRes, dwPriority);
|
|
return D3D_OK;
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetTexLOD"
|
|
|
|
HRESULT __declspec(nothrow) CD3DBase::SetTexLOD(CBaseTexture *pTex, DWORD dwLOD)
|
|
{
|
|
try
|
|
{
|
|
m_pDDI->SetTexLOD(pTex, dwLOD);
|
|
return D3D_OK;
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::AddDirtyRect"
|
|
|
|
HRESULT __declspec(nothrow) CD3DBase::AddDirtyRect(CBaseTexture *pTex, CONST RECTL *pRect)
|
|
{
|
|
DXGASSERT(pTex->IsD3DManaged() == 0);
|
|
DXGASSERT(pTex->GetBufferDesc()->Pool == D3DPOOL_MANAGED);
|
|
DXGASSERT((GetD3DCaps()->Caps2 & DDCAPS2_CANMANAGERESOURCE) != 0);
|
|
try
|
|
{
|
|
m_pDDI->AddDirtyRect(pTex->BaseDrawPrimHandle(), pRect);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
return ret;
|
|
}
|
|
pTex->BatchBase();
|
|
return D3D_OK;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::AddCubeDirtyRect"
|
|
|
|
HRESULT __declspec(nothrow) CD3DBase::AddCubeDirtyRect(CBaseTexture *pTex, DWORD dwFaceHandle, CONST RECTL *pRect)
|
|
{
|
|
DXGASSERT(pTex->IsD3DManaged() == 0);
|
|
DXGASSERT(pTex->GetBufferDesc()->Pool == D3DPOOL_MANAGED);
|
|
DXGASSERT((GetD3DCaps()->Caps2 & DDCAPS2_CANMANAGERESOURCE) != 0);
|
|
try
|
|
{
|
|
m_pDDI->AddDirtyRect(dwFaceHandle, pRect);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
return ret;
|
|
}
|
|
pTex->BatchBase();
|
|
return D3D_OK;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::AddDirtyBox"
|
|
|
|
HRESULT __declspec(nothrow) CD3DBase::AddDirtyBox(CBaseTexture *pTex, CONST D3DBOX *pBox)
|
|
{
|
|
DXGASSERT(pTex->IsD3DManaged() == 0);
|
|
DXGASSERT(pTex->GetBufferDesc()->Pool == D3DPOOL_MANAGED);
|
|
DXGASSERT((GetD3DCaps()->Caps2 & DDCAPS2_CANMANAGERESOURCE) != 0);
|
|
try
|
|
{
|
|
m_pDDI->AddDirtyBox(pTex->BaseDrawPrimHandle(), pBox);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
return ret;
|
|
}
|
|
pTex->BatchBase();
|
|
return D3D_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::OnTextureDestroy"
|
|
|
|
void __declspec(nothrow) CD3DBase::OnTextureDestroy(CBaseTexture *pTex)
|
|
{
|
|
// On a pre-DX8 driver, the code will ensure that if any
|
|
// texture got unset by an API call, the driver will be
|
|
// informed. This needs to be done before calling the
|
|
// driver to destroy a texture handle as we have seen
|
|
// instances of drivers crashing. (snene - 4/24/00)
|
|
if(GetDDIType() < D3DDDITYPE_DX8)
|
|
{
|
|
D3DTEXTUREHANDLE dwDDIHandle = pTex->DriverAccessibleDrawPrimHandle();
|
|
if(dwDDIHandle != 0)
|
|
{
|
|
try
|
|
{
|
|
BOOL bNeedFlush = FALSE;
|
|
for (DWORD dwStage = 0; dwStage < m_dwMaxTextureBlendStages; dwStage++)
|
|
{
|
|
if(dwDDIHandle == m_dwDDITexHandle[dwStage])
|
|
{
|
|
m_pDDI->SetTSS(dwStage, (D3DTEXTURESTAGESTATETYPE)D3DTSS_TEXTUREMAP, 0);
|
|
m_dwDDITexHandle[dwStage] = 0;
|
|
bNeedFlush = TRUE;
|
|
}
|
|
}
|
|
if(bNeedFlush)
|
|
{
|
|
m_pDDI->FlushStates();
|
|
}
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::SetRenderStateInternal"
|
|
|
|
void
|
|
CD3DBase::SetRenderStateInternal(D3DRENDERSTATETYPE dwState, DWORD dwValue)
|
|
{
|
|
if (CanHandleRenderState(dwState))
|
|
m_pDDI->SetRenderState(dwState, dwValue);
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::StateInitialize"
|
|
|
|
void
|
|
CD3DBase::StateInitialize(BOOL bZEnable)
|
|
{
|
|
m_rsMax = m_pDDI->GetMaxRenderState();
|
|
m_tssMax = m_pDDI->GetMaxTSS();
|
|
|
|
D3DLINEPATTERN defLPat;
|
|
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 */
|
|
|
|
float tmpval;
|
|
/*
|
|
((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_ALPHABLENDENABLE, FALSE);
|
|
SetRenderStateInternal(D3DRENDERSTATE_FOGENABLE, FALSE);
|
|
SetRenderStateInternal(D3DRENDERSTATE_SPECULARENABLE, FALSE);
|
|
SetRenderStateInternal(D3DRENDERSTATE_ZVISIBLE, 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_EDGEANTIALIAS, FALSE);
|
|
SetRenderStateInternal(D3DRENDERSTATE_ZBIAS, 0);
|
|
SetRenderStateInternal(D3DRENDERSTATE_RANGEFOGENABLE, FALSE);
|
|
|
|
// 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 (DWORD i = 0; i < 8; i++)
|
|
{
|
|
SetRenderStateInternal((D3DRENDERSTATETYPE)
|
|
(D3DRENDERSTATE_WRAPBIAS + i), FALSE);
|
|
}
|
|
for (i = 0; i < D3DHAL_TSS_MAXSTAGES; i++)
|
|
{
|
|
m_lpD3DMappedTexI[i] = NULL;
|
|
m_dwDDITexHandle[i] = 0;
|
|
}
|
|
m_dwStageDirty = 0;
|
|
|
|
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, i);
|
|
SetTextureStageState(i, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP);
|
|
SetTextureStageState(i, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP);
|
|
SetTextureStageState(i, D3DTSS_BORDERCOLOR, 0x00000000);
|
|
SetTextureStageState(i, D3DTSS_MAGFILTER, D3DTEXF_POINT);
|
|
SetTextureStageState(i, D3DTSS_MINFILTER, D3DTEXF_POINT);
|
|
SetTextureStageState(i, D3DTSS_MIPFILTER, D3DTEXF_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);
|
|
SetTextureStageState(i, D3DTSS_ADDRESSW, D3DTADDRESS_WRAP);
|
|
SetTextureStageState(i, D3DTSS_COLORARG0, D3DTA_CURRENT);
|
|
SetTextureStageState(i, D3DTSS_ALPHAARG0, D3DTA_CURRENT);
|
|
SetTextureStageState(i, D3DTSS_RESULTARG, D3DTA_CURRENT);
|
|
}
|
|
|
|
SetRenderStateInternal(D3DRENDERSTATE_CLIPPING, TRUE);
|
|
SetRenderStateInternal(D3DRENDERSTATE_LIGHTING, TRUE);
|
|
SetRenderStateInternal(D3DRENDERSTATE_AMBIENT, 0);
|
|
SetRenderStateInternal(D3DRENDERSTATE_FOGVERTEXMODE, D3DFOG_NONE);
|
|
SetRenderStateInternal(D3DRENDERSTATE_COLORVERTEX, TRUE);
|
|
SetRenderStateInternal(D3DRENDERSTATE_LOCALVIEWER, TRUE);
|
|
SetRenderStateInternal(D3DRENDERSTATE_NORMALIZENORMALS, FALSE);
|
|
SetRenderStateInternal(D3DRENDERSTATE_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
|
|
SetRenderStateInternal(D3DRENDERSTATE_SPECULARMATERIALSOURCE, D3DMCS_COLOR2);
|
|
SetRenderStateInternal(D3DRENDERSTATE_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL);
|
|
SetRenderStateInternal(D3DRENDERSTATE_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL);
|
|
SetRenderStateInternal(D3DRENDERSTATE_VERTEXBLEND, D3DVBF_DISABLE);
|
|
SetRenderStateInternal(D3DRENDERSTATE_CLIPPLANEENABLE, 0);
|
|
|
|
//
|
|
// new for DX8
|
|
//
|
|
SetRenderStateInternal(D3DRS_SOFTWAREVERTEXPROCESSING, 0);
|
|
|
|
tmpval = GetD3DCaps()->MaxPointSize;
|
|
if (tmpval == 0)
|
|
tmpval = __MAX_POINT_SIZE;
|
|
SetRenderStateInternal(D3DRS_POINTSIZE_MAX, *((DWORD *)&tmpval));
|
|
|
|
tmpval = 1.F;
|
|
SetRenderStateInternal(D3DRS_POINTSIZE, *((DWORD *)&tmpval));
|
|
SetRenderStateInternal(D3DRS_POINTSIZE_MIN, 0);
|
|
SetRenderStateInternal(D3DRS_POINTSPRITEENABLE, 0);
|
|
SetRenderStateInternal(D3DRS_POINTSCALEENABLE , 0);
|
|
SetRenderStateInternal(D3DRS_POINTSCALE_A, *((DWORD *)&tmpval));
|
|
SetRenderStateInternal(D3DRS_POINTSCALE_B, 0);
|
|
SetRenderStateInternal(D3DRS_POINTSCALE_C, 0);
|
|
|
|
SetRenderStateInternal(D3DRS_MULTISAMPLEMASK, 0xffffffff);
|
|
SetRenderStateInternal(D3DRS_MULTISAMPLEANTIALIAS, TRUE);
|
|
|
|
SetRenderStateInternal(D3DRS_PATCHEDGESTYLE, D3DPATCHEDGE_DISCRETE);
|
|
tmpval = 1.F;
|
|
SetRenderStateInternal(D3DRS_PATCHSEGMENTS, *((DWORD *)&tmpval));
|
|
SetRenderStateInternal(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
|
|
|
|
SetRenderStateInternal(D3DRS_COLORWRITEENABLE, 0xF);
|
|
|
|
tmpval = 0.F;
|
|
SetRenderStateInternal(D3DRS_TWEENFACTOR, *((DWORD *)&tmpval));
|
|
|
|
SetRenderStateInternal(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
|
|
|
// New for DX8.1
|
|
|
|
SetRenderStateInternal(D3DRS_POSITIONORDER, D3DORDER_CUBIC);
|
|
SetRenderStateInternal(D3DRS_NORMALORDER, D3DORDER_LINEAR);
|
|
|
|
// Initialize the transform state
|
|
D3DMATRIXI m;
|
|
setIdentity(&m);
|
|
this->SetTransform(D3DTS_VIEW, (D3DMATRIX*)&m);
|
|
this->SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)&m);
|
|
{
|
|
for (UINT i=0; i < __MAXWORLDMATRICES; i++)
|
|
this->SetTransform(D3DTS_WORLDMATRIX(i), (D3DMATRIX*)&m);
|
|
}
|
|
this->SetTransform(D3DTS_TEXTURE0, (D3DMATRIX*)&m);
|
|
this->SetTransform(D3DTS_TEXTURE1, (D3DMATRIX*)&m);
|
|
this->SetTransform(D3DTS_TEXTURE2, (D3DMATRIX*)&m);
|
|
this->SetTransform(D3DTS_TEXTURE3, (D3DMATRIX*)&m);
|
|
this->SetTransform(D3DTS_TEXTURE4, (D3DMATRIX*)&m);
|
|
this->SetTransform(D3DTS_TEXTURE5, (D3DMATRIX*)&m);
|
|
this->SetTransform(D3DTS_TEXTURE6, (D3DMATRIX*)&m);
|
|
this->SetTransform(D3DTS_TEXTURE7, (D3DMATRIX*)&m);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::UpdatePalette"
|
|
|
|
void CD3DBase::UpdatePalette(CBaseTexture *pTex, DWORD Palette, DWORD dwStage, BOOL bSavedWithinPrimitive)
|
|
{
|
|
try
|
|
{
|
|
if(Palette == __INVALIDPALETTE)
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Current palette not set");
|
|
}
|
|
if(pTex->GetPalette() != Palette)
|
|
{
|
|
DWORD dwFlags = DDRAWIPAL_256 | DDRAWIPAL_ALLOW256;
|
|
if (Enum()->GetAppSdkVersion() > D3D_SDK_VERSION_DX8)
|
|
{
|
|
if ((GetD3DCaps()->TextureCaps & D3DPTEXTURECAPS_ALPHAPALETTE) &&
|
|
(pTex->GetBufferDesc()->Format != D3DFMT_A8P8) )
|
|
{
|
|
dwFlags |= DDRAWIPAL_ALPHA;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//This odd selection of formats to receive the palette flag
|
|
//is inherited from DX8. It is wrong, but left in for app-compat reasons.
|
|
if (pTex->GetBufferDesc()->Format != D3DFMT_A8P8)
|
|
{
|
|
dwFlags |= DDRAWIPAL_ALPHA;
|
|
}
|
|
}
|
|
m_pDDI->SetPalette(Palette,
|
|
dwFlags,
|
|
pTex);
|
|
}
|
|
CPalette *pal = static_cast<CPalette*>((*m_pPaletteArray)[Palette].m_pObj);
|
|
if(pal->m_dirty)
|
|
{
|
|
m_pDDI->UpdatePalette(Palette, 0, 256, pal->m_pEntries);
|
|
pal->m_dirty = FALSE;
|
|
}
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
try
|
|
{
|
|
m_pDDI->SetTSS(dwStage,
|
|
(D3DTEXTURESTAGESTATETYPE)D3DTSS_TEXTUREMAP,
|
|
0);
|
|
}
|
|
catch(HRESULT ret)
|
|
{
|
|
m_pDDI->SetWithinPrimitive( bSavedWithinPrimitive );
|
|
D3D_THROW(ret, "");
|
|
}
|
|
m_dwDDITexHandle[dwStage] = 0;
|
|
m_pDDI->SetWithinPrimitive( bSavedWithinPrimitive );
|
|
D3D_THROW(ret, "");
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::UpdateTextures"
|
|
|
|
void CD3DBase::UpdateTextures()
|
|
{
|
|
BOOL bSavedWithinPrimitive = m_pDDI->GetWithinPrimitive();
|
|
m_pDDI->SetWithinPrimitive(TRUE);
|
|
for (DWORD dwStage = 0, StageMask = 1; dwStage < m_dwMaxTextureBlendStages; dwStage++, StageMask <<= 1)
|
|
{
|
|
D3DTEXTUREHANDLE dwDDIHandle;
|
|
BOOL bDirty = (m_dwStageDirty & StageMask) != 0;
|
|
m_dwStageDirty &= ~StageMask; // reset stage dirty
|
|
CBaseTexture *lpTexI = m_lpD3DMappedTexI[dwStage];
|
|
if(lpTexI)
|
|
{
|
|
#if DBG
|
|
if (lpTexI->IsTextureLocked())
|
|
{
|
|
DPF_ERR("Cannot update a locked texture. Texture will be disabled.");
|
|
dwDDIHandle = 0; //tell driver to disable this texture
|
|
}
|
|
else
|
|
{
|
|
#endif // DBG
|
|
if (lpTexI->IsD3DManaged())
|
|
{
|
|
HRESULT hr = ResourceManager()->UpdateVideo(lpTexI->RMHandle(), &bDirty);
|
|
if (FAILED(hr))
|
|
{
|
|
DPF_ERR("The resource manager failed to promote or update a dirty texture. The texture will be disabled.");
|
|
dwDDIHandle = 0; //tell driver to disable this texture
|
|
}
|
|
else
|
|
{
|
|
if (lpTexI->IsPaletted())
|
|
{
|
|
// UpdatePalette can THROW but it safely handles bSavedWithinPrimitive
|
|
UpdatePalette(lpTexI, m_dwPalette, dwStage, bSavedWithinPrimitive);
|
|
}
|
|
if (!bDirty)
|
|
{
|
|
continue; // Ok, then nothing needs to be done further
|
|
}
|
|
dwDDIHandle = static_cast<CMgmtInfo*>(lpTexI->RMHandle())->m_pRes->BaseDrawPrimHandle();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (lpTexI->IsPaletted())
|
|
{
|
|
// UpdatePalette can THROW but it safely handles bSavedWithinPrimitive
|
|
UpdatePalette(lpTexI, m_dwPalette, dwStage, bSavedWithinPrimitive);
|
|
}
|
|
if (!bDirty)
|
|
{
|
|
continue; // Ok, then nothing needs to be done further
|
|
}
|
|
dwDDIHandle = lpTexI->BaseDrawPrimHandle();
|
|
}
|
|
#if DBG
|
|
}
|
|
#endif // DBG
|
|
}
|
|
else if (bDirty)
|
|
{
|
|
dwDDIHandle = 0; //tell driver to disable this texture
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
|
|
try
|
|
{
|
|
m_pDDI->SetTSS(dwStage,
|
|
(D3DTEXTURESTAGESTATETYPE)D3DTSS_TEXTUREMAP,
|
|
dwDDIHandle);
|
|
}
|
|
catch (HRESULT ret)
|
|
{
|
|
m_pDDI->SetWithinPrimitive( bSavedWithinPrimitive );
|
|
D3D_THROW(ret, "");
|
|
}
|
|
|
|
m_dwDDITexHandle[dwStage] = dwDDIHandle;
|
|
if (lpTexI != 0)
|
|
{
|
|
lpTexI->Batch();
|
|
}
|
|
}
|
|
m_pDDI->SetWithinPrimitive( bSavedWithinPrimitive );
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::IncrementBatch"
|
|
|
|
void CD3DBase::IncrementBatchCount()
|
|
{
|
|
DXGASSERT(m_qwBatch > 0);
|
|
m_qwBatch++;
|
|
|
|
// Also we need to update the
|
|
// batch counts of our currently set
|
|
// render target and z
|
|
|
|
// Batch the current RT
|
|
// RT could be gone during Reset()
|
|
if (RenderTarget() != 0)
|
|
{
|
|
RenderTarget()->Batch();
|
|
}
|
|
|
|
if (ZBuffer() != 0)
|
|
{
|
|
// Update the batch count for the current Zbuffer
|
|
ZBuffer()->Batch();
|
|
}
|
|
|
|
// So that currently bound textures get rebatched
|
|
for (DWORD dwStage = 0; dwStage < m_dwMaxTextureBlendStages; dwStage++)
|
|
{
|
|
CBaseTexture *lpTexI = m_lpD3DMappedTexI[dwStage];
|
|
if (NULL != lpTexI)
|
|
{
|
|
lpTexI->Batch();
|
|
}
|
|
}
|
|
|
|
} // IncrementBatch
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetMaterial"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetMaterial(D3DMATERIAL8*)
|
|
{
|
|
API_ENTER(this);
|
|
D3D_ERR("GetMaterial does not work in pure-device");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetTransform"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetTransform(D3DTRANSFORMSTATETYPE, LPD3DMATRIX)
|
|
{
|
|
API_ENTER(this);
|
|
D3D_ERR("GetTransform does not work in pure-device");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetLight"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetLight(DWORD, D3DLIGHT8*)
|
|
{
|
|
API_ENTER(this);
|
|
D3D_ERR("GetLight does not work in pure-device");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetLightEnable"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetLightEnable(DWORD dwLightIndex, BOOL*)
|
|
{
|
|
API_ENTER(this);
|
|
D3D_ERR("GetLightEnable does not work in pure-device");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetClipPlane"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetClipPlane(DWORD dwPlaneIndex, D3DVALUE* pPlaneEquation)
|
|
{
|
|
API_ENTER(this);
|
|
D3D_ERR("GetClipPlane does not work in pure-device");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetTextureStageState"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetTextureStageState(DWORD, D3DTEXTURESTAGESTATETYPE, LPDWORD)
|
|
{
|
|
API_ENTER(this);
|
|
D3D_ERR("GetTextureStageState does not work in pure-device");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetViewport"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetViewport(D3DVIEWPORT8*)
|
|
{
|
|
API_ENTER(this);
|
|
D3D_ERR("GetViewport does not work in pure-device");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetRenderState"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetRenderState(D3DRENDERSTATETYPE, LPDWORD)
|
|
{
|
|
API_ENTER(this);
|
|
D3D_ERR("GetRenderState does not work in pure-device");
|
|
return D3DERR_INVALIDCALL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetPixelShaderConstant"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetPixelShaderConstant(DWORD dwRegisterAddress,
|
|
LPVOID lpvConstantData,
|
|
DWORD dwConstantCount)
|
|
{
|
|
API_ENTER(this);
|
|
D3D_ERR("GetPixelShaderConstant does not work in pure-device");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetVertexShaderConstant"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetVertexShaderConstant(DWORD dwRegisterAddress,
|
|
LPVOID lpvConstantData,
|
|
DWORD dwConstantCount)
|
|
{
|
|
API_ENTER(this);
|
|
D3D_ERR("GetVertexShaderConstant does not work in pure-device");
|
|
return E_NOTIMPL;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetVertexShaderDeclaration"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetVertexShaderDeclaration(DWORD dwHandle, void *pData,
|
|
DWORD *pSizeOfData)
|
|
{
|
|
API_ENTER(this);
|
|
try
|
|
{
|
|
#if DBG
|
|
if (!(VALID_WRITEPTR(pSizeOfData, sizeof(*pSizeOfData))))
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Invalid data size pointer");
|
|
}
|
|
if (pData && !(VALID_WRITEPTR(pData, *pSizeOfData)))
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Invalid data pointer");
|
|
}
|
|
#endif
|
|
if (D3DVSD_ISLEGACY(dwHandle))
|
|
{
|
|
*pSizeOfData = 0;
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Legacy vertex shaders do not have declaration");
|
|
}
|
|
else
|
|
{
|
|
CVShader* pShader = (CVShader*)m_pVShaderArray->GetObject(dwHandle);
|
|
if (pShader == NULL)
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Invalid vertex shader handle");
|
|
}
|
|
if (pData)
|
|
{
|
|
if (*pSizeOfData < pShader->m_OrgDeclSize)
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Invalid data pointer");
|
|
}
|
|
memcpy(pData, pShader->m_pOrgDeclaration, pShader->m_OrgDeclSize);
|
|
}
|
|
*pSizeOfData = pShader->m_OrgDeclSize;
|
|
}
|
|
}
|
|
catch (HRESULT ret)
|
|
{
|
|
DPF_ERR("GetVertexShaderDeclaration failed.");
|
|
return ret;
|
|
}
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetVertexShaderFunction"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetVertexShaderFunction(DWORD dwHandle, void *pData,
|
|
DWORD *pSizeOfData)
|
|
{
|
|
API_ENTER(this);
|
|
try
|
|
{
|
|
#if DBG
|
|
if (!(VALID_WRITEPTR(pSizeOfData, sizeof(*pSizeOfData))))
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Invalid data size pointer");
|
|
}
|
|
if (pData && !(VALID_WRITEPTR(pData, *pSizeOfData)))
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Invalid data pointer");
|
|
}
|
|
#endif
|
|
if (D3DVSD_ISLEGACY(dwHandle))
|
|
{
|
|
*pSizeOfData = 0;
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Legacy vertex shaders do not have function code");
|
|
}
|
|
else
|
|
{
|
|
CVShader* pShader = (CVShader*)m_pVShaderArray->GetObject(dwHandle);
|
|
if (pShader == NULL)
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Invalid vertex shader handle");
|
|
}
|
|
if (pData)
|
|
{
|
|
if (*pSizeOfData < pShader->m_OrgFuncCodeSize)
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Invalid data buffer size");
|
|
}
|
|
memcpy(pData, pShader->m_pOrgFuncCode, pShader->m_OrgFuncCodeSize);
|
|
}
|
|
*pSizeOfData = pShader->m_OrgFuncCodeSize;
|
|
}
|
|
}
|
|
catch (HRESULT ret)
|
|
{
|
|
DPF_ERR("GetVertexShaderFunction failed.");
|
|
return ret;
|
|
}
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CD3DBase::GetPixelShaderFunction"
|
|
|
|
HRESULT D3DAPI
|
|
CD3DBase::GetPixelShaderFunction(DWORD dwHandle, void *pData,
|
|
DWORD *pSizeOfData)
|
|
{
|
|
API_ENTER(this);
|
|
try
|
|
{
|
|
#if DBG
|
|
if (!(VALID_WRITEPTR(pSizeOfData, sizeof(*pSizeOfData))))
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Invalid data size pointer");
|
|
}
|
|
if (pData && !(VALID_WRITEPTR(pData, *pSizeOfData)))
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Invalid data pointer");
|
|
}
|
|
#endif
|
|
CPShader* pShader = (CPShader*)m_pPShaderArray->GetObject(dwHandle);
|
|
if (pShader == NULL)
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Invalid pixel shader handle");
|
|
}
|
|
if (pData)
|
|
{
|
|
if (*pSizeOfData < pShader->m_dwCodeSizeOrig)
|
|
{
|
|
D3D_THROW(D3DERR_INVALIDCALL, "Invalid data buffer size");
|
|
}
|
|
memcpy(pData, pShader->m_pCodeOrig, pShader->m_dwCodeSizeOrig);
|
|
}
|
|
*pSizeOfData = pShader->m_dwCodeSizeOrig;
|
|
}
|
|
catch (HRESULT ret)
|
|
{
|
|
DPF_ERR("GetPixelShaderFunction failed");
|
|
return ret;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|