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.
1442 lines
46 KiB
1442 lines
46 KiB
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: vvm.cpp
|
|
* Content: Virtual Vertex Machine implementation
|
|
*
|
|
*
|
|
***************************************************************************/
|
|
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
|
|
float MINUS_MAX()
|
|
{
|
|
DWORD v = 0xFF7FFFFF;
|
|
return *(float*)&v;
|
|
}
|
|
|
|
float PLUS_MAX()
|
|
{
|
|
DWORD v = 0x7F7FFFFF;
|
|
return *(float*)&v;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Returns instruction size, based on the op-code
|
|
//
|
|
UINT GetInstructionLength(DWORD inst)
|
|
{
|
|
DWORD opcode = D3DSI_GETOPCODE( inst );
|
|
// returns number of source operands + length of opcode and the destination
|
|
switch (opcode)
|
|
{
|
|
case D3DSIO_MOV : return 1 + 2;
|
|
case D3DSIO_ADD : return 2 + 2;
|
|
case D3DSIO_MAD : return 3 + 2;
|
|
case D3DSIO_MUL : return 2 + 2;
|
|
case D3DSIO_RCP : return 1 + 2;
|
|
case D3DSIO_RSQ : return 1 + 2;
|
|
case D3DSIO_DP3 : return 2 + 2;
|
|
case D3DSIO_DP4 : return 2 + 2;
|
|
case D3DSIO_MIN : return 2 + 2;
|
|
case D3DSIO_MAX : return 2 + 2;
|
|
case D3DSIO_SLT : return 2 + 2;
|
|
case D3DSIO_SGE : return 2 + 2;
|
|
case D3DSIO_EXP : return 1 + 2;
|
|
case D3DSIO_LOG : return 1 + 2;
|
|
case D3DSIO_EXPP: return 1 + 2;
|
|
case D3DSIO_LOGP: return 1 + 2;
|
|
case D3DSIO_LIT : return 1 + 2;
|
|
case D3DSIO_DST : return 2 + 2;
|
|
case D3DSIO_FRC : return 1 + 2;
|
|
case D3DSIO_M4x4: return 2 + 2;
|
|
case D3DSIO_M4x3: return 2 + 2;
|
|
case D3DSIO_M3x4: return 2 + 2;
|
|
case D3DSIO_M3x3: return 2 + 2;
|
|
case D3DSIO_M3x2: return 2 + 2;
|
|
case D3DSIO_NOP : return 1;
|
|
default: return 1;
|
|
case D3DSIO_COMMENT: return 1 + ((inst & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CVertexVM::GetDataPointer(DWORD dwMemType, RDVECTOR4 ** pData)
|
|
{
|
|
try
|
|
{
|
|
*pData = this->GetDataAddr(dwMemType, 0);
|
|
}
|
|
catch (CD3DException e)
|
|
{
|
|
*pData = NULL;
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// RefVM implementation.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Vertex Virtual Machine Opcode implementations
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::WriteResult()
|
|
{
|
|
if( m_WriteMask == D3DSP_WRITEMASK_ALL)
|
|
{
|
|
*m_pDest = m_TmpReg;
|
|
}
|
|
else
|
|
{
|
|
if( m_WriteMask & D3DSP_WRITEMASK_0)
|
|
m_pDest->x = m_TmpReg.x;
|
|
if( m_WriteMask & D3DSP_WRITEMASK_1)
|
|
m_pDest->y = m_TmpReg.y;
|
|
if( m_WriteMask & D3DSP_WRITEMASK_2)
|
|
m_pDest->z = m_TmpReg.z;
|
|
if( m_WriteMask & D3DSP_WRITEMASK_3)
|
|
m_pDest->w = m_TmpReg.w;
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstMov()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
|
|
if( m_pDest == m_reg.m_a )
|
|
{
|
|
float p = (float)floor(m_Source[0].x);
|
|
*(int*)&m_pDest->x = FTOI(p);
|
|
}
|
|
else
|
|
{
|
|
m_TmpReg = m_Source[0];
|
|
WriteResult();
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstAdd()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
SetSrcReg(1);
|
|
|
|
m_TmpReg.x = m_Source[0].x + m_Source[1].x;
|
|
m_TmpReg.y = m_Source[0].y + m_Source[1].y;
|
|
m_TmpReg.z = m_Source[0].z + m_Source[1].z;
|
|
m_TmpReg.w = m_Source[0].w + m_Source[1].w;
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstMad()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
SetSrcReg(1);
|
|
SetSrcReg(2);
|
|
|
|
m_TmpReg.x = m_Source[0].x * m_Source[1].x + m_Source[2].x;
|
|
m_TmpReg.y = m_Source[0].y * m_Source[1].y + m_Source[2].y;
|
|
m_TmpReg.z = m_Source[0].z * m_Source[1].z + m_Source[2].z;
|
|
m_TmpReg.w = m_Source[0].w * m_Source[1].w + m_Source[2].w;
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstMul()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
SetSrcReg(1);
|
|
|
|
m_TmpReg.x = m_Source[0].x * m_Source[1].x;
|
|
m_TmpReg.y = m_Source[0].y * m_Source[1].y;
|
|
m_TmpReg.z = m_Source[0].z * m_Source[1].z;
|
|
m_TmpReg.w = m_Source[0].w * m_Source[1].w;
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstRcp()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
|
|
if( m_Source[0].w == 1.0f )
|
|
{
|
|
// Must be exactly 1.0
|
|
m_TmpReg.x = m_TmpReg.y = m_TmpReg.z = m_TmpReg.w = 1.0f;
|
|
}
|
|
else if( m_Source[0].w == 0 )
|
|
{
|
|
m_TmpReg.x = m_TmpReg.y = m_TmpReg.z = m_TmpReg.w = PLUS_MAX();
|
|
}
|
|
else
|
|
{
|
|
m_TmpReg.x = m_TmpReg.y = m_TmpReg.z = m_TmpReg.w = 1.0f/m_Source[0].w;
|
|
}
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstRsq()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
|
|
float v = ABSF(m_Source[0].w);
|
|
if( v == 1.0f )
|
|
{
|
|
m_TmpReg.x = m_TmpReg.y = m_TmpReg.z = m_TmpReg.w = 1.0f;
|
|
}
|
|
else if( v == 0 )
|
|
{
|
|
m_TmpReg.x = m_TmpReg.y = m_TmpReg.z = m_TmpReg.w = PLUS_MAX();
|
|
}
|
|
else
|
|
{
|
|
v = (float)(1.0f / sqrt(v));
|
|
m_TmpReg.x = m_TmpReg.y = m_TmpReg.z = m_TmpReg.w = v;
|
|
}
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstDP3()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
SetSrcReg(1);
|
|
|
|
m_TmpReg.x =
|
|
m_TmpReg.y =
|
|
m_TmpReg.z =
|
|
m_TmpReg.w = m_Source[0].x * m_Source[1].x +
|
|
m_Source[0].y * m_Source[1].y +
|
|
m_Source[0].z * m_Source[1].z;
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstDP4()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
SetSrcReg(1);
|
|
|
|
m_TmpReg.x =
|
|
m_TmpReg.y =
|
|
m_TmpReg.z =
|
|
m_TmpReg.w = m_Source[0].x * m_Source[1].x +
|
|
m_Source[0].y * m_Source[1].y +
|
|
m_Source[0].z * m_Source[1].z +
|
|
m_Source[0].w * m_Source[1].w;
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstSlt()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
SetSrcReg(1);
|
|
|
|
m_TmpReg.x = (m_Source[0].x < m_Source[1].x) ? 1.0f : 0.0f;
|
|
m_TmpReg.y = (m_Source[0].y < m_Source[1].y) ? 1.0f : 0.0f;
|
|
m_TmpReg.z = (m_Source[0].z < m_Source[1].z) ? 1.0f : 0.0f;
|
|
m_TmpReg.w = (m_Source[0].w < m_Source[1].w) ? 1.0f : 0.0f;
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstSge()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
SetSrcReg(1);
|
|
|
|
m_TmpReg.x = (m_Source[0].x >= m_Source[1].x) ? 1.0f : 0.0f;
|
|
m_TmpReg.y = (m_Source[0].y >= m_Source[1].y) ? 1.0f : 0.0f;
|
|
m_TmpReg.z = (m_Source[0].z >= m_Source[1].z) ? 1.0f : 0.0f;
|
|
m_TmpReg.w = (m_Source[0].w >= m_Source[1].w) ? 1.0f : 0.0f;
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstMin()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
SetSrcReg(1);
|
|
|
|
m_TmpReg.x=(m_Source[0].x < m_Source[1].x) ? m_Source[0].x : m_Source[1].x;
|
|
m_TmpReg.y=(m_Source[0].y < m_Source[1].y) ? m_Source[0].y : m_Source[1].y;
|
|
m_TmpReg.z=(m_Source[0].z < m_Source[1].z) ? m_Source[0].z : m_Source[1].z;
|
|
m_TmpReg.w=(m_Source[0].w < m_Source[1].w) ? m_Source[0].w : m_Source[1].w;
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstMax()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
SetSrcReg(1);
|
|
|
|
m_TmpReg.x=(m_Source[0].x >= m_Source[1].x) ? m_Source[0].x : m_Source[1].x;
|
|
m_TmpReg.y=(m_Source[0].y >= m_Source[1].y) ? m_Source[0].y : m_Source[1].y;
|
|
m_TmpReg.z=(m_Source[0].z >= m_Source[1].z) ? m_Source[0].z : m_Source[1].z;
|
|
m_TmpReg.w=(m_Source[0].w >= m_Source[1].w) ? m_Source[0].w : m_Source[1].w;
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstExp()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
|
|
float v = m_Source[0].w;
|
|
|
|
m_TmpReg.x = m_TmpReg.y = m_TmpReg.z = m_TmpReg.w = (float)pow(2, v);
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstExpP()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
|
|
float w = m_Source[0].w;
|
|
float v = (float)floor(m_Source[0].w);
|
|
|
|
m_TmpReg.x = (float)pow(2, v);
|
|
m_TmpReg.y = w - v;
|
|
// Reduced precision exponent
|
|
float tmp = (float)pow(2, w);
|
|
DWORD tmpd = *(DWORD*)&tmp & 0xffffff00;
|
|
m_TmpReg.z = *(float*)&tmpd;
|
|
m_TmpReg.w = 1;
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstLog()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
|
|
float v = ABSF(m_Source[0].w);
|
|
if (v != 0)
|
|
{
|
|
m_TmpReg.x = m_TmpReg.y = m_TmpReg.z = m_TmpReg.w =
|
|
(float)(log(v)/log(2));
|
|
}
|
|
else
|
|
{
|
|
m_TmpReg.x = m_TmpReg.y = m_TmpReg.z = m_TmpReg.w = MINUS_MAX();
|
|
}
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstLogP()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
|
|
float v = ABSF(m_Source[0].w);
|
|
if (v != 0)
|
|
{
|
|
int p = (int)(*(DWORD*)&v >> 23) - 127;
|
|
m_TmpReg.x = (float)p; // exponent
|
|
p = (*(DWORD*)&v & 0x7FFFFF) | 0x3f800000;
|
|
m_TmpReg.y = *(float*)&p;// mantissa;
|
|
float tmp = (float)(log(v)/log(2));
|
|
DWORD tmpd = *(DWORD*)&tmp & 0xffffff00;
|
|
m_TmpReg.z = *(float*)&tmpd;
|
|
m_TmpReg.w = 1;
|
|
}
|
|
else
|
|
{
|
|
m_TmpReg.x = MINUS_MAX();
|
|
m_TmpReg.y = 1.0f;
|
|
m_TmpReg.z = MINUS_MAX();
|
|
m_TmpReg.w = 1.0f;
|
|
}
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstLit()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
|
|
m_TmpReg.x = 1;
|
|
m_TmpReg.y = 0;
|
|
m_TmpReg.z = 0;
|
|
m_TmpReg.w = 1;
|
|
float power = m_Source[0].w;
|
|
const float MAXPOWER = 127.9961f;
|
|
if (power < -MAXPOWER)
|
|
power = -MAXPOWER; // Fits into 8.8 fixed point format
|
|
else
|
|
if (power > MAXPOWER)
|
|
power = MAXPOWER; // Fits into 8.8 fixed point format
|
|
|
|
if (m_Source[0].x > 0)
|
|
{
|
|
m_TmpReg.y = m_Source[0].x;
|
|
if (m_Source[0].y > 0)
|
|
{
|
|
// Allowed approximation is EXP(power * LOG(m_Source[0].y))
|
|
m_TmpReg.z = (float)(pow(m_Source[0].y, power));
|
|
}
|
|
}
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstFrc()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
|
|
m_TmpReg.x = m_Source[0].x - (float)floor(m_Source[0].x);
|
|
m_TmpReg.y = m_Source[0].y - (float)floor(m_Source[0].y);
|
|
m_TmpReg.z = m_Source[0].z - (float)floor(m_Source[0].z);
|
|
m_TmpReg.w = m_Source[0].w - (float)floor(m_Source[0].w);
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstDst()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
SetSrcReg(1);
|
|
|
|
m_TmpReg.x = 1;
|
|
m_TmpReg.y = m_Source[0].y * m_Source[1].y;
|
|
m_TmpReg.z = m_Source[0].z;
|
|
m_TmpReg.w = m_Source[1].w;
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstM4x4()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
SetSrcReg(1, 4);
|
|
m_TmpReg.x = m_Source[0].x * m_Source[1].x +
|
|
m_Source[0].y * m_Source[1].y +
|
|
m_Source[0].z * m_Source[1].z +
|
|
m_Source[0].w * m_Source[1].w;
|
|
m_TmpReg.y = m_Source[0].x * m_Source[2].x +
|
|
m_Source[0].y * m_Source[2].y +
|
|
m_Source[0].z * m_Source[2].z +
|
|
m_Source[0].w * m_Source[2].w;
|
|
m_TmpReg.z = m_Source[0].x * m_Source[3].x +
|
|
m_Source[0].y * m_Source[3].y +
|
|
m_Source[0].z * m_Source[3].z +
|
|
m_Source[0].w * m_Source[3].w;
|
|
m_TmpReg.w = m_Source[0].x * m_Source[4].x +
|
|
m_Source[0].y * m_Source[4].y +
|
|
m_Source[0].z * m_Source[4].z +
|
|
m_Source[0].w * m_Source[4].w;
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstM4x3()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
SetSrcReg(1, 3);
|
|
m_TmpReg.x = m_Source[0].x * m_Source[1].x +
|
|
m_Source[0].y * m_Source[1].y +
|
|
m_Source[0].z * m_Source[1].z +
|
|
m_Source[0].w * m_Source[1].w;
|
|
m_TmpReg.y = m_Source[0].x * m_Source[2].x +
|
|
m_Source[0].y * m_Source[2].y +
|
|
m_Source[0].z * m_Source[2].z +
|
|
m_Source[0].w * m_Source[2].w;
|
|
m_TmpReg.z = m_Source[0].x * m_Source[3].x +
|
|
m_Source[0].y * m_Source[3].y +
|
|
m_Source[0].z * m_Source[3].z +
|
|
m_Source[0].w * m_Source[3].w;
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefVM::InstM3x4()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
SetSrcReg(1, 4);
|
|
m_TmpReg.x = m_Source[0].x * m_Source[1].x +
|
|
m_Source[0].y * m_Source[1].y +
|
|
m_Source[0].z * m_Source[1].z;
|
|
m_TmpReg.y = m_Source[0].x * m_Source[2].x +
|
|
m_Source[0].y * m_Source[2].y +
|
|
m_Source[0].z * m_Source[2].z;
|
|
m_TmpReg.z = m_Source[0].x * m_Source[3].x +
|
|
m_Source[0].y * m_Source[3].y +
|
|
m_Source[0].z * m_Source[3].z;
|
|
m_TmpReg.w = m_Source[0].x * m_Source[4].x +
|
|
m_Source[0].y * m_Source[4].y +
|
|
m_Source[0].z * m_Source[4].z;
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void RefVM::InstM3x3()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
SetSrcReg(1, 3);
|
|
m_TmpReg.x = m_Source[0].x * m_Source[1].x +
|
|
m_Source[0].y * m_Source[1].y +
|
|
m_Source[0].z * m_Source[1].z;
|
|
m_TmpReg.y = m_Source[0].x * m_Source[2].x +
|
|
m_Source[0].y * m_Source[2].y +
|
|
m_Source[0].z * m_Source[2].z;
|
|
m_TmpReg.z = m_Source[0].x * m_Source[3].x +
|
|
m_Source[0].y * m_Source[3].y +
|
|
m_Source[0].z * m_Source[3].z;
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void RefVM::InstM3x2()
|
|
{
|
|
SetDestReg();
|
|
SetSrcReg(0);
|
|
SetSrcReg(1, 2);
|
|
m_TmpReg.x = m_Source[0].x * m_Source[1].x +
|
|
m_Source[0].y * m_Source[1].y +
|
|
m_Source[0].z * m_Source[1].z;
|
|
m_TmpReg.y = m_Source[0].x * m_Source[2].x +
|
|
m_Source[0].y * m_Source[2].y +
|
|
m_Source[0].z * m_Source[2].z;
|
|
|
|
WriteResult();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
// RefVM::SetData
|
|
// Save data into the specified registers.
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
RefVM::SetData( DWORD dwMemType, DWORD dwStart, DWORD dwCount,
|
|
LPVOID pBuffer )
|
|
{
|
|
memcpy( GetDataAddr( dwMemType, dwStart ), pBuffer,
|
|
dwCount * sizeof(RDVECTOR4) );
|
|
return D3D_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// RefVM::GetData
|
|
// Fetch data from the specified registers.
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
RefVM::GetData( DWORD dwMemType, DWORD dwStart, DWORD dwCount,
|
|
LPVOID pBuffer )
|
|
{
|
|
memcpy( pBuffer, GetDataAddr( dwMemType, dwStart ),
|
|
dwCount * sizeof(RDVECTOR4) );
|
|
return D3D_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// RefVM::SetDestReg
|
|
// - parses destination token
|
|
// - computes m_pDest, m_WrideMask, m_dwOffset for the destination
|
|
// - current token pointer is andvanced to the next token
|
|
//-----------------------------------------------------------------------------
|
|
#undef RET_ERR
|
|
#define RET_ERR( a ) \
|
|
{ \
|
|
DPFERR( a ); \
|
|
return E_FAIL; \
|
|
}
|
|
HRESULT
|
|
RefVM::SetDestReg()
|
|
{
|
|
DWORD dwCurToken = *m_pCurToken;
|
|
DWORD dwRegType = D3DSI_GETREGTYPE(dwCurToken);
|
|
m_dwRegOffset = D3DSI_GETREGNUM(dwCurToken);
|
|
m_WriteMask = D3DSI_GETWRITEMASK(dwCurToken);
|
|
switch( dwRegType )
|
|
{
|
|
case D3DSPR_TEMP:
|
|
m_pDest = m_reg.m_t;
|
|
break;
|
|
case D3DSPR_RASTOUT:
|
|
m_pDest = m_reg.m_out;
|
|
break;
|
|
case D3DSPR_ATTROUT:
|
|
m_pDest = m_reg.m_col;
|
|
break;
|
|
case D3DSPR_TEXCRDOUT:
|
|
m_pDest = m_reg.m_tex;
|
|
break;
|
|
case D3DSPR_ADDR:
|
|
m_pDest = m_reg.m_a;
|
|
break;
|
|
default:
|
|
RET_ERR( "Invalid register for destination" );
|
|
}
|
|
m_pCurToken++;
|
|
m_pDest += m_dwRegOffset;
|
|
return S_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// RefVM::SetSrcReg
|
|
// Computes m_Source[index] and advances m_pCurToken
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
RefVM::SetSrcReg( DWORD index )
|
|
{
|
|
const DWORD dwCurToken = *m_pCurToken;
|
|
const DWORD dwRegType = D3DSI_GETREGTYPE( dwCurToken );
|
|
const DWORD dwOffset = D3DSI_GETREGNUM( dwCurToken );
|
|
RDVECTOR4 *src = NULL;
|
|
if( dwRegType == D3DSPR_CONST )
|
|
{
|
|
D3DVS_ADDRESSMODE_TYPE am;
|
|
am = (D3DVS_ADDRESSMODE_TYPE)D3DVS_GETADDRESSMODE( dwCurToken );
|
|
int offset = (int)dwOffset;
|
|
if( am == D3DVS_ADDRMODE_RELATIVE )
|
|
{
|
|
int relOffset = *(int*)&m_reg.m_a[0].x;
|
|
offset += relOffset;
|
|
if( offset < 0 || offset >= RD_MAX_NUMCONSTREG )
|
|
RET_ERR( "Constant register index is out of bounds" );
|
|
}
|
|
src = &m_reg.m_c[offset];
|
|
}
|
|
else
|
|
src = this->GetDataAddr(dwRegType, dwOffset);
|
|
|
|
_ASSERT( src != NULL, "src is NULL" );
|
|
RDVECTOR4 *outsrc = &m_Source[index];
|
|
DWORD swizzle = D3DVS_GETSWIZZLE(dwCurToken);
|
|
if( swizzle == D3DVS_NOSWIZZLE )
|
|
*outsrc = *src;
|
|
else
|
|
{
|
|
// Where to take X
|
|
const DWORD dwSrcX = D3DVS_GETSWIZZLECOMP(dwCurToken, 0);
|
|
// Where to take Y
|
|
const DWORD dwSrcY = D3DVS_GETSWIZZLECOMP(dwCurToken, 1);
|
|
// Where to take Z
|
|
const DWORD dwSrcZ = D3DVS_GETSWIZZLECOMP(dwCurToken, 2);
|
|
// Where to take W
|
|
const DWORD dwSrcW = D3DVS_GETSWIZZLECOMP(dwCurToken, 3);
|
|
outsrc->x = ((float*)src)[dwSrcX];
|
|
outsrc->y = ((float*)src)[dwSrcY];
|
|
outsrc->z = ((float*)src)[dwSrcZ];
|
|
outsrc->w = ((float*)src)[dwSrcW];
|
|
}
|
|
if( D3DVS_GETSRCMODIFIER( dwCurToken ) == D3DSPSM_NEG)
|
|
{
|
|
outsrc->x = -outsrc->x;
|
|
outsrc->y = -outsrc->y;
|
|
outsrc->z = -outsrc->z;
|
|
outsrc->w = -outsrc->w;
|
|
}
|
|
m_pCurToken++;
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
// RefVM::SetSrcReg
|
|
// Computes m_Source[index] and advances m_pCurToken
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
RefVM::SetSrcReg( DWORD index, DWORD count )
|
|
{
|
|
const DWORD dwCurToken = *m_pCurToken;
|
|
const DWORD dwRegType = D3DSI_GETREGTYPE(dwCurToken);
|
|
const DWORD dwOffset = D3DSI_GETREGNUM(dwCurToken);
|
|
RDVECTOR4 *src;
|
|
if (dwRegType == D3DSPR_CONST)
|
|
{
|
|
D3DVS_ADDRESSMODE_TYPE am;
|
|
am = (D3DVS_ADDRESSMODE_TYPE)D3DVS_GETADDRESSMODE(dwCurToken);
|
|
int offset = (int)dwOffset;
|
|
if (am == D3DVS_ADDRMODE_RELATIVE)
|
|
{
|
|
int relOffset = *(int*)&m_reg.m_a[0].x;
|
|
offset += relOffset;
|
|
if (offset < 0 || offset >= RD_MAX_NUMCONSTREG)
|
|
RET_ERR( "Constant register index is out of bounds" );
|
|
}
|
|
src = &m_reg.m_c[offset];
|
|
}
|
|
else
|
|
{
|
|
if (dwOffset >= RD_MAX_NUMCONSTREG)
|
|
RET_ERR( "Constant register index is out of bounds" );
|
|
src = this->GetDataAddr(dwRegType, dwOffset);
|
|
}
|
|
RDVECTOR4 *outsrc = &m_Source[index];
|
|
DWORD swizzle = D3DVS_GETSWIZZLE(dwCurToken);
|
|
// Where to take X
|
|
const DWORD dwSrcX = D3DVS_GETSWIZZLECOMP(dwCurToken, 0);
|
|
// Where to take Y
|
|
const DWORD dwSrcY = D3DVS_GETSWIZZLECOMP(dwCurToken, 1);
|
|
// Where to take Z
|
|
const DWORD dwSrcZ = D3DVS_GETSWIZZLECOMP(dwCurToken, 2);
|
|
// Where to take W
|
|
const DWORD dwSrcW = D3DVS_GETSWIZZLECOMP(dwCurToken, 3);
|
|
for (UINT i=0; i < count; i++)
|
|
{
|
|
if (swizzle == D3DVS_NOSWIZZLE)
|
|
*outsrc = *src;
|
|
else
|
|
{
|
|
outsrc->x = ((float*)src)[dwSrcX];
|
|
outsrc->y = ((float*)src)[dwSrcY];
|
|
outsrc->z = ((float*)src)[dwSrcZ];
|
|
outsrc->w = ((float*)src)[dwSrcW];
|
|
}
|
|
if (D3DVS_GETSRCMODIFIER(dwCurToken) == D3DSPSM_NEG)
|
|
{
|
|
outsrc->x = -outsrc->x;
|
|
outsrc->y = -outsrc->y;
|
|
outsrc->z = -outsrc->z;
|
|
outsrc->w = -outsrc->w;
|
|
}
|
|
outsrc++;
|
|
src++;
|
|
}
|
|
m_pCurToken++;
|
|
return S_OK;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// RefVM::GetDataAddr
|
|
// Parses binary shader representation, compiles is and returns
|
|
// compiled object
|
|
//---------------------------------------------------------------------
|
|
RDVECTOR4*
|
|
RefVM::GetDataAddr(DWORD dwRegType, DWORD dwElementIndex)
|
|
{
|
|
RDVECTOR4* src;
|
|
switch( dwRegType )
|
|
{
|
|
case D3DSPR_TEMP : src = m_reg.m_t; break;
|
|
case D3DSPR_INPUT : src = m_reg.m_i; break;
|
|
case D3DSPR_CONST : src = m_reg.m_c; break;
|
|
case D3DSPR_ADDR : src = m_reg.m_a; break;
|
|
case D3DSPR_RASTOUT : src = m_reg.m_out; break;
|
|
case D3DSPR_ATTROUT : src = m_reg.m_col; break;
|
|
case D3DSPR_TEXCRDOUT : src = m_reg.m_tex; break;
|
|
default:
|
|
return NULL;
|
|
}
|
|
return &src[dwElementIndex];
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// RefVM::ExecuteShader()
|
|
// Executes the shader once per vertex.
|
|
//---------------------------------------------------------------------
|
|
HRESULT
|
|
RefVM::ExecuteShader(RefDev *pRD)
|
|
{
|
|
if( m_pCurrentShaderCode == NULL )
|
|
{
|
|
RET_ERR( "No current shader set in the Virtual Shader Machine" );
|
|
}
|
|
|
|
m_pCurToken = m_pCurrentShaderCode->m_pRawBits;
|
|
DWORD* pEnd = m_pCurToken + m_pCurrentShaderCode->m_dwSize;
|
|
m_pCurToken++;
|
|
m_CurInstIndex = 0;
|
|
while( m_pCurToken < pEnd )
|
|
{
|
|
if( *m_pCurToken == D3DVS_END() ) break;
|
|
DWORD dwInst = *m_pCurToken;
|
|
DWORD dwOpCode = D3DSI_GETOPCODE( dwInst );
|
|
m_pCurToken++;
|
|
switch( dwOpCode )
|
|
{
|
|
case D3DSIO_COMMENT: m_pCurToken += (GetInstructionLength( dwInst ) - 1);
|
|
case D3DSIO_NOP : ; break;
|
|
case D3DSIO_MOV : InstMov(); break;
|
|
case D3DSIO_ADD : InstAdd(); break;
|
|
case D3DSIO_MAD : InstMad(); break;
|
|
case D3DSIO_MUL : InstMul(); break;
|
|
case D3DSIO_RCP : InstRcp(); break;
|
|
case D3DSIO_RSQ : InstRsq(); break;
|
|
case D3DSIO_DP3 : InstDP3(); break;
|
|
case D3DSIO_DP4 : InstDP4(); break;
|
|
case D3DSIO_MIN : InstMin(); break;
|
|
case D3DSIO_MAX : InstMax(); break;
|
|
case D3DSIO_SLT : InstSlt(); break;
|
|
case D3DSIO_SGE : InstSge(); break;
|
|
case D3DSIO_EXPP : InstExpP(); break;
|
|
case D3DSIO_LOGP : InstLogP(); break;
|
|
case D3DSIO_EXP : InstExp(); break;
|
|
case D3DSIO_LOG : InstLog(); break;
|
|
case D3DSIO_LIT : InstLit(); break;
|
|
case D3DSIO_DST : InstDst(); break;
|
|
case D3DSIO_FRC : InstFrc(); break;
|
|
case D3DSIO_M4x4 : InstM4x4(); break;
|
|
case D3DSIO_M4x3 : InstM4x3(); break;
|
|
case D3DSIO_M3x4 : InstM3x4(); break;
|
|
case D3DSIO_M3x3 : InstM3x3(); break;
|
|
case D3DSIO_M3x2 : InstM3x2(); break;
|
|
default:
|
|
RET_ERR( "Invalid shader opcode" );
|
|
}
|
|
if( dwOpCode != D3DSIO_COMMENT ) m_CurInstIndex++;
|
|
}
|
|
m_CurInstIndex = 0;
|
|
|
|
return D3D_OK;
|
|
}
|
|
|
|
#if DBG
|
|
//-----------------------------------------------------------------------------
|
|
// VertexShaderInstDisAsm - Generates human-readable character string for a
|
|
// single vertex shader instruction. String interface is similar to _snprintf.
|
|
//-----------------------------------------------------------------------------
|
|
static int VertexShaderInstDisAsm(
|
|
char* pStrRet, int StrSizeRet, DWORD* pShader, DWORD Flags )
|
|
{
|
|
DWORD* pToken = pShader;
|
|
|
|
// stage in local string, then copy
|
|
char pStr[256] = "";
|
|
#define _ADDSTR( _Str ) { _snprintf( pStr, 256, "%s" _Str , pStr ); }
|
|
#define _ADDSTRP( _Str, _Param ) { _snprintf( pStr, 256, "%s" _Str , pStr, _Param ); }
|
|
|
|
DWORD Inst = *pToken++;
|
|
DWORD Opcode = (Inst & D3DSI_OPCODE_MASK);
|
|
switch (Opcode)
|
|
{
|
|
case D3DSIO_NOP: _ADDSTR("NOP"); break;
|
|
case D3DSIO_MOV: _ADDSTR("MOV"); break;
|
|
case D3DSIO_ADD: _ADDSTR("ADD"); break;
|
|
case D3DSIO_MAD: _ADDSTR("MAD"); break;
|
|
case D3DSIO_MUL: _ADDSTR("MUL"); break;
|
|
case D3DSIO_RCP: _ADDSTR("RCP"); break;
|
|
case D3DSIO_RSQ: _ADDSTR("RSQ"); break;
|
|
case D3DSIO_DP3: _ADDSTR("DP3"); break;
|
|
case D3DSIO_DP4: _ADDSTR("DP4"); break;
|
|
case D3DSIO_MIN: _ADDSTR("MIN"); break;
|
|
case D3DSIO_MAX: _ADDSTR("MAX"); break;
|
|
case D3DSIO_SLT: _ADDSTR("SLT"); break;
|
|
case D3DSIO_SGE: _ADDSTR("SGE"); break;
|
|
case D3DSIO_EXP: _ADDSTR("EXP"); break;
|
|
case D3DSIO_LOG: _ADDSTR("LOG"); break;
|
|
case D3DSIO_EXPP: _ADDSTR("EXPP"); break;
|
|
case D3DSIO_LOGP: _ADDSTR("LOGP"); break;
|
|
case D3DSIO_LIT: _ADDSTR("LIT"); break;
|
|
case D3DSIO_DST: _ADDSTR("DST"); break;
|
|
default : _ADDSTR("???"); break;
|
|
}
|
|
if (*pToken & (1L<<31))
|
|
{
|
|
DWORD DstParam = *pToken++;
|
|
switch (DstParam & D3DSP_REGTYPE_MASK)
|
|
{
|
|
case D3DSPR_TEMP : _ADDSTRP(" T%d", (DstParam & D3DSP_REGNUM_MASK) ); break;
|
|
case D3DSPR_ADDR : _ADDSTR(" Addr"); break;
|
|
case D3DSPR_RASTOUT : _ADDSTRP(" R%d", (DstParam & D3DSP_REGNUM_MASK) ); break;
|
|
case D3DSPR_ATTROUT : _ADDSTRP(" A%d", (DstParam & D3DSP_REGNUM_MASK) ); break;
|
|
case D3DSPR_TEXCRDOUT: _ADDSTRP(" T%d", (DstParam & D3DSP_REGNUM_MASK) ); break;
|
|
}
|
|
if (*pToken & (1L<<31)) _ADDSTR(" ");
|
|
while (*pToken & (1L<<31))
|
|
{
|
|
DWORD SrcParam = *pToken++;
|
|
switch (SrcParam & D3DSP_REGTYPE_MASK)
|
|
{
|
|
case D3DSPR_TEMP : _ADDSTRP(" T%d", (SrcParam & D3DSP_REGNUM_MASK) ); break;
|
|
case D3DSPR_INPUT : _ADDSTRP(" I%d", (SrcParam & D3DSP_REGNUM_MASK) ); break;
|
|
case D3DSPR_CONST : _ADDSTRP(" C%d", (SrcParam & D3DSP_REGNUM_MASK) ); break;
|
|
}
|
|
if (*pToken & (1L<<31)) _ADDSTR(",");
|
|
}
|
|
}
|
|
return _snprintf( pStrRet, StrSizeRet, "%s", pStr );
|
|
}
|
|
#endif // DBG
|
|
|
|
//---------------------------------------------------------------------
|
|
// RefVM::CompileCode
|
|
// Parses binary shader representation, compiles is and returns
|
|
// compiled object
|
|
//---------------------------------------------------------------------
|
|
#undef RET_ERR
|
|
#define RET_ERR( a ) \
|
|
{ \
|
|
DPFERR( a ); \
|
|
delete pShaderCode; \
|
|
return NULL; \
|
|
}
|
|
|
|
|
|
RDVShaderCode*
|
|
RefVM::CompileCode( DWORD dwSize, LPDWORD pBits )
|
|
{
|
|
RDVShaderCode* pShaderCode = new RDVShaderCode();
|
|
if( pShaderCode == NULL )
|
|
RET_ERR( "Out of memory allocating ShaderCode" );
|
|
|
|
pShaderCode->m_dwSize = dwSize >> 2; // #DWORDs
|
|
pShaderCode->m_pRawBits = new DWORD[pShaderCode->m_dwSize];
|
|
if( pShaderCode->m_pRawBits == NULL )
|
|
RET_ERR( "Out of memory allocating RawBits" );
|
|
|
|
memcpy( pShaderCode->m_pRawBits, (LPBYTE)pBits, dwSize );
|
|
|
|
|
|
// Based on the what output registers are modified, we compute the
|
|
// corresponding FVF id. The id will be used for memory allocation
|
|
// of the output buffer and will be passed to the rasterizer
|
|
UINT64 qwOutFVF = 0;
|
|
DWORD nTexCoord = 0; // Number of output texture coordinates
|
|
LPDWORD pEnd = NULL;
|
|
|
|
// For each texture register stores the combined write mask.
|
|
// Used to find how many floats are written to each texture coordinates
|
|
DWORD TextureWritten[8];
|
|
memset( TextureWritten, 0, sizeof(TextureWritten) );
|
|
|
|
m_pCurToken = pShaderCode->m_pRawBits;
|
|
pEnd = m_pCurToken + pShaderCode->m_dwSize;
|
|
m_pCurToken++; // Skip the version number
|
|
pShaderCode->m_InstCount = 0;
|
|
while( m_pCurToken < pEnd )
|
|
{
|
|
if( *m_pCurToken == D3DVS_END() ) break;
|
|
DWORD* pNextToken = m_pCurToken;
|
|
DWORD dwInst = *m_pCurToken;
|
|
DWORD dwOpCode = D3DSI_GETOPCODE(dwInst);
|
|
if( *m_pCurToken == D3DVS_END() ) break;
|
|
m_pCurToken++;
|
|
switch( dwOpCode )
|
|
{
|
|
case D3DSIO_COMMENT:
|
|
case D3DSIO_NOP : ; break;
|
|
case D3DSIO_MOV :
|
|
case D3DSIO_ADD :
|
|
case D3DSIO_MAD :
|
|
case D3DSIO_MUL :
|
|
case D3DSIO_RCP :
|
|
case D3DSIO_RSQ :
|
|
case D3DSIO_DP3 :
|
|
case D3DSIO_DP4 :
|
|
case D3DSIO_MIN :
|
|
case D3DSIO_MAX :
|
|
case D3DSIO_SLT :
|
|
case D3DSIO_SGE :
|
|
case D3DSIO_EXP :
|
|
case D3DSIO_LOG :
|
|
case D3DSIO_EXPP :
|
|
case D3DSIO_LOGP :
|
|
case D3DSIO_LIT :
|
|
case D3DSIO_DST :
|
|
case D3DSIO_FRC :
|
|
case D3DSIO_M4x4 :
|
|
case D3DSIO_M4x3 :
|
|
case D3DSIO_M3x4 :
|
|
case D3DSIO_M3x3 :
|
|
case D3DSIO_M3x2 :
|
|
{
|
|
// Find out if output register are modified by the command and
|
|
// update the output FVF
|
|
DWORD dwOffset;
|
|
if( FAILED( SetDestReg() ) )
|
|
RET_ERR( "Invalid shader opcode" );
|
|
|
|
RDVECTOR4* m_pOutRegister = NULL;
|
|
if( m_pDest - m_dwRegOffset != m_reg.m_t )
|
|
{
|
|
dwOffset = m_dwRegOffset;
|
|
m_pOutRegister = m_pDest - m_dwRegOffset;
|
|
}
|
|
else
|
|
break; // Output register is not modified
|
|
|
|
if( m_pOutRegister == m_reg.m_out )
|
|
{
|
|
if (dwOffset == D3DSRO_POSITION)
|
|
{
|
|
qwOutFVF |= D3DFVF_XYZRHW;
|
|
}
|
|
else if (dwOffset == D3DSRO_FOG)
|
|
{
|
|
qwOutFVF |= D3DFVFP_FOG;
|
|
}
|
|
else if (dwOffset == D3DSRO_POINT_SIZE)
|
|
{
|
|
qwOutFVF |= D3DFVF_PSIZE;
|
|
}
|
|
}
|
|
else if( m_pOutRegister == m_reg.m_col )
|
|
{
|
|
if( dwOffset == 0 )
|
|
{
|
|
qwOutFVF |= D3DFVF_DIFFUSE;
|
|
}
|
|
else
|
|
{
|
|
qwOutFVF |= D3DFVF_SPECULAR;
|
|
}
|
|
}
|
|
else if( m_pOutRegister == m_reg.m_tex )
|
|
{
|
|
if( TextureWritten[dwOffset] == 0 )
|
|
{
|
|
nTexCoord++;
|
|
}
|
|
TextureWritten[dwOffset] |= m_WriteMask;
|
|
}
|
|
else if( m_pOutRegister != m_reg.m_a )
|
|
RET_ERR( "Invalid output register offset" );
|
|
}
|
|
break;
|
|
default:
|
|
RET_ERR( "Invalid shader opcode" );
|
|
}
|
|
pShaderCode->m_InstCount++;
|
|
m_pCurToken = pNextToken + GetInstructionLength(dwInst);
|
|
}
|
|
|
|
// allocate and set instruction array
|
|
if (pShaderCode->m_InstCount)
|
|
{
|
|
pShaderCode->m_pInst = new RDVShaderInst[pShaderCode->m_InstCount];
|
|
if( pShaderCode->m_pInst == NULL )
|
|
RET_ERR( "Out of memory allocating Instructions" );
|
|
memset( pShaderCode->m_pInst, 0,
|
|
sizeof(RDVShaderInst)*pShaderCode->m_InstCount );
|
|
|
|
DWORD dwCurInst = 0;
|
|
m_pCurToken = pShaderCode->m_pRawBits;
|
|
pEnd = m_pCurToken + pShaderCode->m_dwSize;
|
|
m_pCurToken++;
|
|
while( m_pCurToken < pEnd )
|
|
{
|
|
DWORD dwInst = *m_pCurToken;
|
|
DWORD dwOpCode = D3DSI_GETOPCODE( dwInst );
|
|
if( *m_pCurToken == D3DVS_END() ) break;
|
|
UINT ilength = GetInstructionLength( dwInst );
|
|
if (dwOpCode == D3DSIO_COMMENT)
|
|
{
|
|
pShaderCode->m_pInst[dwCurInst].m_Tokens[0] = dwInst;
|
|
pShaderCode->m_pInst[dwCurInst].m_pComment = (m_pCurToken+1);
|
|
pShaderCode->m_pInst[dwCurInst].m_CommentSize = ilength - 1;
|
|
}
|
|
else
|
|
{
|
|
memcpy( pShaderCode->m_pInst[dwCurInst].m_Tokens, m_pCurToken,
|
|
4*ilength );
|
|
#if DBG
|
|
VertexShaderInstDisAsm( pShaderCode->m_pInst[dwCurInst].m_String,
|
|
RD_MAX_SHADERINSTSTRING, pShaderCode->m_pInst[dwCurInst].m_Tokens, 0x0 );
|
|
#else // !DBG
|
|
pShaderCode->m_pInst[dwCurInst].m_String[ 0 ] = '\0';
|
|
#endif // !DBG
|
|
}
|
|
m_pCurToken += ilength;
|
|
dwCurInst++;
|
|
}
|
|
}
|
|
|
|
qwOutFVF |= nTexCoord << D3DFVF_TEXCOUNT_SHIFT;
|
|
if( nTexCoord )
|
|
{
|
|
for( DWORD i = 0; i < nTexCoord; i++ )
|
|
{
|
|
if( TextureWritten[i] == 0 )
|
|
RET_ERR( "Texture coordinates are not continuous" );
|
|
switch( TextureWritten[i] )
|
|
{
|
|
case D3DSP_WRITEMASK_ALL:
|
|
qwOutFVF |= D3DFVF_TEXCOORDSIZE4(i);
|
|
break;
|
|
case D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1 | D3DSP_WRITEMASK_2:
|
|
qwOutFVF |= D3DFVF_TEXCOORDSIZE3(i);
|
|
break;
|
|
case D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1:
|
|
qwOutFVF |= D3DFVF_TEXCOORDSIZE2(i);
|
|
break;
|
|
case D3DSP_WRITEMASK_0:
|
|
qwOutFVF |= D3DFVF_TEXCOORDSIZE1(i);
|
|
break;
|
|
default:
|
|
RET_ERR( "Invalid write mask for texture register" );
|
|
}
|
|
}
|
|
}
|
|
pShaderCode->m_qwFVFOut = qwOutFVF;
|
|
return pShaderCode;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// RefDev implementation.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//---------------------------------------------------------------------
|
|
// RefDev::ProcessPrimitiveVVM()
|
|
// Processess and draw the current primitive using the VVM
|
|
//---------------------------------------------------------------------
|
|
HRESULT
|
|
RefDev::ProcessPrimitiveVVM( D3DPRIMITIVETYPE primType,
|
|
DWORD dwStartVertex,
|
|
DWORD cVertices,
|
|
DWORD dwStartIndex,
|
|
DWORD cIndices )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
RDCLIPCODE clipIntersection = ~0;
|
|
RDCLIPCODE clipUnion = 0;
|
|
|
|
// Save Prim Type for later use
|
|
m_primType = primType;
|
|
m_dwNumVertices = cVertices;
|
|
m_dwStartVertex = dwStartVertex;
|
|
m_dwNumIndices = cIndices;
|
|
m_dwStartIndex = dwStartIndex;
|
|
|
|
RDVDeclaration* pDecl = &(m_pCurrentVShader->m_Declaration);
|
|
RDVShaderCode* pCode = m_pCurrentVShader->m_pCode;
|
|
RDVVMREG* pRegisters = m_RefVM.GetRegisters();
|
|
|
|
// Output FVF that was computed at the compile time
|
|
m_qwFVFOut = pCode->m_qwFVFOut;
|
|
|
|
//
|
|
// Clipping information depends both on the output FVF computation
|
|
// and the other State, so do it here after both have been computed
|
|
//
|
|
HR_RET( UpdateClipper());
|
|
|
|
D3DVALUE scaleX = m_Clipper.scaleX;
|
|
D3DVALUE scaleY = m_Clipper.scaleY;
|
|
D3DVALUE scaleZ = m_Clipper.scaleZ;
|
|
|
|
D3DVALUE offsetX = m_Clipper.offsetX;
|
|
D3DVALUE offsetY = m_Clipper.offsetY;
|
|
D3DVALUE offsetZ = m_Clipper.offsetZ;
|
|
|
|
//
|
|
// Grow buffers to the requisite size
|
|
//
|
|
|
|
// Grow TLVArray if required
|
|
if( FAILED( this->m_TLVArray.Grow( m_dwNumVertices ) ) )
|
|
{
|
|
DPFERR( "Could not grow TL vertex buffer" );
|
|
hr = DDERR_OUTOFMEMORY;
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Process Vertices
|
|
//
|
|
for( DWORD i = 0; i < m_dwNumVertices; i++ )
|
|
{
|
|
RDVertex& Vout = m_TLVArray[i];
|
|
Vout.SetFVF( pCode->m_qwFVFOut | D3DFVFP_CLIP );
|
|
|
|
// Copy vertex elements to the input vertex registers
|
|
for( DWORD j = 0; j < pDecl->m_dwNumElements; j++ )
|
|
{
|
|
RDVElement& ve = pDecl->m_VertexElements[j];
|
|
RDVStream* pStream = &m_VStream[ve.m_dwStreamIndex];
|
|
LPBYTE pData = (LPBYTE)pStream->m_pData + ve.m_dwOffset +
|
|
pStream->m_dwStride * (m_dwStartVertex + i);
|
|
RDVECTOR4* pReg = m_RefVM.GetDataAddr( D3DSPR_INPUT,
|
|
ve.m_dwRegister );
|
|
|
|
ve.m_pfnCopy( pData, pReg );
|
|
}
|
|
|
|
// Execute the shader
|
|
m_RefVM.ExecuteShader(this);
|
|
|
|
// Get the result from the output VVM registers
|
|
float x, y, z, w, inv_w_clip = 0.0f;
|
|
|
|
w = pRegisters->m_out[D3DSRO_POSITION].w;
|
|
z = pRegisters->m_out[D3DSRO_POSITION].z;
|
|
|
|
// Make clipping rules 0 < x < w; 0 < y < w
|
|
|
|
x = (pRegisters->m_out[D3DSRO_POSITION].x + w) * 0.5f;
|
|
y = (pRegisters->m_out[D3DSRO_POSITION].y + w) * 0.5f;
|
|
|
|
// Save the clip coordinates
|
|
Vout.m_clip_x = x;
|
|
Vout.m_clip_y = y;
|
|
Vout.m_clip_z = z;
|
|
Vout.m_clip_w = w;
|
|
|
|
//
|
|
// Compute clip codes if needed
|
|
//
|
|
if( GetRS()[D3DRENDERSTATE_CLIPPING] )
|
|
{
|
|
RDCLIPCODE clip = m_Clipper.ComputeClipCodes(
|
|
&clipIntersection, &clipUnion, x, y, z, w);
|
|
if( clip == 0 )
|
|
{
|
|
Vout.m_clip = 0;
|
|
inv_w_clip = 1.0f/w;
|
|
}
|
|
else
|
|
{
|
|
if( m_Clipper.UseGuardBand() )
|
|
{
|
|
if( (clip & ~RDCLIP_INGUARDBAND) == 0 )
|
|
{
|
|
// If vertex is inside the guardband we have to compute
|
|
// screen coordinates
|
|
inv_w_clip = 1.0f/w;
|
|
Vout.m_clip = (RDCLIPCODE)clip;
|
|
goto l_DoScreenCoord;
|
|
}
|
|
}
|
|
Vout.m_clip = (RDCLIPCODE)clip;
|
|
// If vertex is outside the frustum we can not compute screen
|
|
// coordinates, hence store the clip coordinates
|
|
#if 0
|
|
Vout.m_pos.x = x;
|
|
Vout.m_pos.y = y;
|
|
Vout.m_pos.z = z;
|
|
Vout.m_rhw = w;
|
|
#endif
|
|
goto l_DoLighting;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We have to check this only for DONOTCLIP case, because otherwise
|
|
// the vertex with "we = 0" will be clipped and screen coordinates
|
|
// will not be computed
|
|
// "clip" is not zero, if "we" is zero.
|
|
if( !FLOAT_EQZ(w) )
|
|
inv_w_clip = D3DVAL(1)/w;
|
|
else
|
|
inv_w_clip = __HUGE_PWR2;
|
|
}
|
|
l_DoScreenCoord:
|
|
Vout.m_pos.x = x * inv_w_clip * scaleX + offsetX;
|
|
Vout.m_pos.y = y * inv_w_clip * scaleY + offsetY;
|
|
Vout.m_pos.z = z * inv_w_clip * scaleZ + offsetZ;
|
|
Vout.m_rhw = inv_w_clip;
|
|
|
|
l_DoLighting:
|
|
if( m_qwFVFOut & D3DFVF_DIFFUSE )
|
|
{
|
|
// Clamp the colors before copying.
|
|
if( FLOAT_LTZ(pRegisters->m_col[0].a) )
|
|
pRegisters->m_col[0].a = 0.0f;
|
|
else if( FLOAT_CMP_PONE(pRegisters->m_col[0].a, >) )
|
|
pRegisters->m_col[0].a = 1.0f;
|
|
|
|
if( FLOAT_LTZ(pRegisters->m_col[0].r) )
|
|
pRegisters->m_col[0].r = 0.0f;
|
|
else if( FLOAT_CMP_PONE(pRegisters->m_col[0].r, >) )
|
|
pRegisters->m_col[0].r = 1.0f;
|
|
|
|
if( FLOAT_LTZ(pRegisters->m_col[0].g) )
|
|
pRegisters->m_col[0].g = 0.0f;
|
|
else if( FLOAT_CMP_PONE(pRegisters->m_col[0].g, >) )
|
|
pRegisters->m_col[0].g = 1.0f;
|
|
|
|
if( FLOAT_LTZ(pRegisters->m_col[0].b) )
|
|
pRegisters->m_col[0].b = 0.0f;
|
|
else if( FLOAT_CMP_PONE(pRegisters->m_col[0].b, >) )
|
|
pRegisters->m_col[0].b = 1.0f;
|
|
|
|
memcpy( &Vout.m_diffuse,&(pRegisters->m_col[0]),
|
|
sizeof(RDVECTOR4) );
|
|
}
|
|
if( m_qwFVFOut & D3DFVF_SPECULAR )
|
|
{
|
|
if( FLOAT_LTZ(pRegisters->m_col[1].a) )
|
|
pRegisters->m_col[1].a = 0.0f;
|
|
else if( FLOAT_CMP_PONE(pRegisters->m_col[1].a, >) )
|
|
pRegisters->m_col[1].a = 1.0f;
|
|
|
|
if( FLOAT_LTZ(pRegisters->m_col[1].r) )
|
|
pRegisters->m_col[1].r = 0.0f;
|
|
else if( FLOAT_CMP_PONE(pRegisters->m_col[1].r, >) )
|
|
pRegisters->m_col[1].r = 1.0f;
|
|
|
|
if( FLOAT_LTZ(pRegisters->m_col[1].g) )
|
|
pRegisters->m_col[1].g = 0.0f;
|
|
else if( FLOAT_CMP_PONE(pRegisters->m_col[1].g, >) )
|
|
pRegisters->m_col[1].g = 1.0f;
|
|
|
|
if( FLOAT_LTZ(pRegisters->m_col[1].b) )
|
|
pRegisters->m_col[1].b = 0.0f;
|
|
else if( FLOAT_CMP_PONE(pRegisters->m_col[1].b, >) )
|
|
pRegisters->m_col[1].b = 1.0f;
|
|
|
|
memcpy( &Vout.m_specular,&(pRegisters->m_col[1]),
|
|
sizeof(RDVECTOR4) );
|
|
}
|
|
if( m_qwFVFOut & D3DFVFP_FOG )
|
|
{
|
|
if( FLOAT_LTZ(pRegisters->m_out[D3DSRO_FOG].x) )
|
|
pRegisters->m_out[D3DSRO_FOG].x = 0.0f;
|
|
|
|
if( FLOAT_CMP_PONE(pRegisters->m_out[D3DSRO_FOG].x, >) )
|
|
pRegisters->m_out[D3DSRO_FOG].x = 1.0f;
|
|
|
|
Vout.m_fog = pRegisters->m_out[D3DSRO_FOG].x;
|
|
}
|
|
|
|
// Copy the textures over
|
|
if( m_qwFVFOut & D3DFVF_PSIZE )
|
|
{
|
|
Vout.m_pointsize = pRegisters->m_out[D3DSRO_POINT_SIZE].x;
|
|
}
|
|
|
|
|
|
// Copy the textures over
|
|
|
|
{
|
|
DWORD i, j;
|
|
DWORD numTex = FVF_TEXCOORD_NUMBER(m_qwFVFOut);
|
|
for( i = 0; i < numTex; i++ )
|
|
{
|
|
DWORD n = GetTexCoordDim( m_qwFVFOut, i );
|
|
// DWORD n = (DWORD)(m_dwTexCoordSizeArray[i] >> 2);
|
|
float *pCoordDest = (float *)&Vout.m_tex[i];
|
|
float *pCoordSrc = (float *)&pRegisters->m_tex[i];
|
|
for( j = 0; j < n; j++ )
|
|
{
|
|
pCoordDest[j] = pCoordSrc[j];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( GetRS()[D3DRENDERSTATE_CLIPPING] )
|
|
{
|
|
m_Clipper.m_clipIntersection = clipIntersection;
|
|
m_Clipper.m_clipUnion = clipUnion;
|
|
}
|
|
else
|
|
{
|
|
m_Clipper.m_clipIntersection = 0;
|
|
m_Clipper.m_clipUnion = 0;
|
|
}
|
|
|
|
|
|
//
|
|
// Clip and Draw the primitives
|
|
//
|
|
|
|
if( m_dwNumIndices )
|
|
{
|
|
if( !NeedClipping((m_Clipper.UseGuardBand()), m_Clipper.m_clipUnion) )
|
|
{
|
|
if( m_IndexStream.m_dwStride == 4 )
|
|
hr = DrawOneIndexedPrimitive(
|
|
m_TLVArray,
|
|
0,
|
|
(LPDWORD)m_IndexStream.m_pData,
|
|
m_dwStartIndex,
|
|
m_dwNumIndices,
|
|
m_primType );
|
|
else
|
|
hr = DrawOneIndexedPrimitive(
|
|
m_TLVArray,
|
|
0,
|
|
(LPWORD)m_IndexStream.m_pData,
|
|
m_dwStartIndex,
|
|
m_dwNumIndices,
|
|
m_primType );
|
|
}
|
|
else
|
|
{
|
|
if( m_IndexStream.m_dwStride == 4 )
|
|
hr = m_Clipper.DrawOneIndexedPrimitive(
|
|
m_TLVArray,
|
|
0,
|
|
(LPDWORD)m_IndexStream.m_pData,
|
|
m_dwStartIndex,
|
|
m_dwNumIndices,
|
|
m_primType );
|
|
else
|
|
hr = m_Clipper.DrawOneIndexedPrimitive(
|
|
m_TLVArray,
|
|
0,
|
|
(LPWORD)m_IndexStream.m_pData,
|
|
m_dwStartIndex,
|
|
m_dwNumIndices,
|
|
m_primType );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( !NeedClipping((m_Clipper.UseGuardBand()), m_Clipper.m_clipUnion) )
|
|
{
|
|
hr = DrawOnePrimitive(
|
|
m_TLVArray,
|
|
0,
|
|
m_primType,
|
|
m_dwNumVertices );
|
|
}
|
|
else
|
|
{
|
|
hr = m_Clipper.DrawOnePrimitive(
|
|
m_TLVArray,
|
|
0,
|
|
m_primType,
|
|
m_dwNumVertices );
|
|
}
|
|
}
|
|
return hr;
|
|
}
|