windows-nt/Source/XPSP1/NT/multimedia/directx/dxg/d3d8/shval/pshdrval.cpp
2020-09-26 16:20:57 +08:00

334 lines
13 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Copyright (C) Microsoft Corporation, 2000.
//
// pshdrval.cpp
//
// Direct3D Reference Device - PixelShader validation
//
///////////////////////////////////////////////////////////////////////////////
#include "pch.cpp"
#pragma hdrstop
// Use these macros when looking at CPSInstruction derived members of the current instruction (CBaseInstruction)
#define _CURR_PS_INST ((CPSInstruction*)m_pCurrInst)
#define _PREV_PS_INST (m_pCurrInst?((CPSInstruction*)(m_pCurrInst->m_pPrevInst)):NULL)
//-----------------------------------------------------------------------------
// CPSInstruction::CalculateComponentReadMasks()
//
// Figure out which components of each source parameter is read by a pixelshader
// instruction. For certain pixelshader instructions, the some components
// are also read from the dest parameter.
//
// Note: When this function is changed, the changes need to be ported to
// refrast's CalculateSourceReadMasks() function in rast\pshader.cpp
// (Though that function does not care about channels read from the dest parameter
// like this one does).
//-----------------------------------------------------------------------------
void CPSInstruction::CalculateComponentReadMasks(DWORD dwVersion)
{
UINT i, j;
switch( m_Type ) // instructions that actually read from the *Destination* register...
{
case D3DSIO_TEXM3x2DEPTH:
case D3DSIO_TEXDEPTH:
m_DstParam.m_ComponentReadMask = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1;
break;
case D3DSIO_TEXKILL:
if( (D3DPS_VERSION(1,4) == dwVersion) && (D3DSPR_TEMP == m_DstParam.m_RegType) )
{
// for ps.1.4, texkill on an r# register only reads rgb
m_DstParam.m_ComponentReadMask = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1 | D3DSP_WRITEMASK_2;
}
else
{
m_DstParam.m_ComponentReadMask = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1 | D3DSP_WRITEMASK_2 | D3DSP_WRITEMASK_3;
}
break;
}
for( i = 0; i < m_SrcParamCount; i++ )
{
DWORD NeededComponents;
DWORD ReadComponents = 0;
switch( m_Type )
{
case D3DSIO_TEX: // only in ps.1.4 does texld have source parameter
if( D3DPS_VERSION(1,4) == dwVersion )
{
// for ps.1.4, texld has a source parameter
NeededComponents = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1 | D3DSP_WRITEMASK_2;
}
else // versions < ps.1.4 don't have a src param on tex, so we shouldn't get here. But maybe in ps.2.0...
{
NeededComponents = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1 | D3DSP_WRITEMASK_2 | D3DSP_WRITEMASK_3;
}
break;
case D3DSIO_TEXCOORD:
if( D3DPS_VERSION(1,4) == dwVersion )
{
// for ps.1.4, texcrd has a source parameter
NeededComponents = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1 | D3DSP_WRITEMASK_2;
}
else // versions < ps.1.4 don't have a src param on texcoord, so we shouldn't get here. But maybe in ps.2.0...
{
NeededComponents = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1 | D3DSP_WRITEMASK_2 | D3DSP_WRITEMASK_3;
}
break;
case D3DSIO_TEXBEM:
case D3DSIO_TEXBEML:
NeededComponents = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1;
break;
case D3DSIO_DP3:
NeededComponents = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1 | D3DSP_WRITEMASK_2;
break;
case D3DSIO_DP4:
NeededComponents = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1 | D3DSP_WRITEMASK_2 | D3DSP_WRITEMASK_3;
break;
case D3DSIO_BEM: // ps.1.4
NeededComponents = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1;
break;
default:
// standard component-wise instruction,
// OR an op we know reads .rgba and we also know it will be validated to .rgba writemask
NeededComponents = m_DstParam.m_WriteMask;
break;
}
// Figure out which components of this source parameter are read (taking into account swizzle)
for(j = 0; j < 4; j++)
{
if( NeededComponents & COMPONENT_MASKS[j] )
ReadComponents |= COMPONENT_MASKS[(m_SrcParam[i].m_SwizzleShift >> (D3DVS_SWIZZLE_SHIFT + 2*j)) & 0x3];
}
m_SrcParam[i].m_ComponentReadMask = ReadComponents;
}
}
//-----------------------------------------------------------------------------
// CBasePShaderValidator::CBasePShaderValidator
//-----------------------------------------------------------------------------
CBasePShaderValidator::CBasePShaderValidator( const DWORD* pCode,
const D3DCAPS8* pCaps,
DWORD Flags )
: CBaseShaderValidator( pCode, pCaps, Flags )
{
// Note that the base constructor initialized m_ReturnCode to E_FAIL.
// Only set m_ReturnCode to S_OK if validation has succeeded,
// before exiting this constructor.
m_CycleNum = 0;
m_TexOpCount = 0;
m_BlendOpCount = 0;
m_TotalOpCount = 0;
m_pTempRegFile = NULL;
m_pInputRegFile = NULL;
m_pConstRegFile = NULL;
m_pTextureRegFile = NULL;
if( !m_bBaseInitOk )
return;
}
//-----------------------------------------------------------------------------
// CBasePShaderValidator::~CBasePShaderValidator
//-----------------------------------------------------------------------------
CBasePShaderValidator::~CBasePShaderValidator()
{
delete m_pTempRegFile;
delete m_pInputRegFile;
delete m_pConstRegFile;
delete m_pTextureRegFile;
}
//-----------------------------------------------------------------------------
// CBasePShaderValidator::AllocateNewInstruction
//-----------------------------------------------------------------------------
CBaseInstruction* CBasePShaderValidator::AllocateNewInstruction(CBaseInstruction*pPrevInst)
{
return new CPSInstruction((CPSInstruction*)pPrevInst);
}
//-----------------------------------------------------------------------------
// CBasePShaderValidator::DecodeNextInstruction
//-----------------------------------------------------------------------------
BOOL CBasePShaderValidator::DecodeNextInstruction()
{
m_pCurrInst->m_Type = (D3DSHADER_INSTRUCTION_OPCODE_TYPE)(*m_pCurrToken & D3DSI_OPCODE_MASK);
if( D3DSIO_COMMENT == m_pCurrInst->m_Type )
{
ParseCommentForAssemblerMessages(m_pCurrToken); // does not advance m_pCurrToken
// Skip comments
DWORD NumDWORDs = ((*m_pCurrToken) & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
m_pCurrToken += (NumDWORDs+1);
return TRUE;
}
// Find out if the instruction is a TexOp and/or TexMOp. Needed by multiple validation rules,
// as well as further below in DecodeNextInstruction.
IsCurrInstTexOp();
// If the assembler has sent us file and/or line number messages,
// received by ParseCommentForAssemblerMesssages(),
// then bind this information to the current instruction.
// This info can be used in error spew to direct the shader developer
// to exactly where a problem is located.
m_pCurrInst->SetSpewFileNameAndLineNumber(m_pLatestSpewFileName,m_pLatestSpewLineNumber);
if( *m_pCurrToken & D3DSI_COISSUE )
{
_CURR_PS_INST->m_bCoIssue = TRUE;
}
else if( D3DSIO_NOP != m_pCurrInst->m_Type )
{
m_CycleNum++; // First cycle is 1. (co-issued instructions will have same cycle number)
}
_CURR_PS_INST->m_CycleNum = m_CycleNum;
m_SpewInstructionCount++; // only used for spew, not for any limits
m_pCurrInst->m_SpewInstructionCount = m_SpewInstructionCount;
DWORD dwReservedBits = PS_INST_TOKEN_RESERVED_MASK;
if( (*m_pCurrToken) & dwReservedBits )
{
Spew(SPEW_INSTRUCTION_ERROR,m_pCurrInst,"Reserved bit(s) set in instruction parameter token! Aborting validation.");
return FALSE;
}
m_pCurrToken++;
// Decode dst param
if (*m_pCurrToken & (1L<<31))
{
(m_pCurrInst->m_DstParamCount)++;
DecodeDstParam( &m_pCurrInst->m_DstParam, *m_pCurrToken );
if( (*m_pCurrToken) & PS_DSTPARAM_TOKEN_RESERVED_MASK )
{
Spew(SPEW_INSTRUCTION_ERROR,m_pCurrInst,"Reserved bit(s) set in destination parameter token! Aborting validation.");
return FALSE;
}
m_pCurrToken++;
if( D3DSIO_DEF == m_pCurrInst->m_Type )
{
// Skip source params (float vector) - nothing to check
// This is the only instruction with 4 source params,
// and further, this is the only instruction that has
// raw numbers as parameters. This justifies the
// special case treatment here - we pretend
// D3DSIO_DEF only has a dst param (which we will check).
m_pCurrToken += 4;
return TRUE;
}
}
// Decode src param(s)
while (*m_pCurrToken & (1L<<31))
{
(m_pCurrInst->m_SrcParamCount)++;
if( (m_pCurrInst->m_SrcParamCount + m_pCurrInst->m_DstParamCount) > SHADER_INSTRUCTION_MAX_PARAMS )
{
m_pCurrInst->m_SrcParamCount--;
m_pCurrToken++; // eat up extra parameters and skip to next
continue;
}
// Below: index is [SrcParamCount - 1] because m_SrcParam array needs 0 based index.
DecodeSrcParam( &(m_pCurrInst->m_SrcParam[m_pCurrInst->m_SrcParamCount - 1]),*m_pCurrToken );
if( (*m_pCurrToken) & PS_SRCPARAM_TOKEN_RESERVED_MASK )
{
Spew(SPEW_INSTRUCTION_ERROR,m_pCurrInst,"Reserved bit(s) set in source %d parameter token! Aborting validation.",
m_pCurrInst->m_SrcParamCount);
return FALSE;
}
m_pCurrToken++;
}
// Figure out which components of each source operand actually need to be read,
// taking into account destination write mask, the type of instruction, source swizzle, etc.
// (must be after IsCurrInstTexOp() )
m_pCurrInst->CalculateComponentReadMasks(m_Version);
return TRUE;
}
//-----------------------------------------------------------------------------
//
// CBasePShaderValidator Wrapper Functions
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// GetNewPSValidator
//
// Called by ValidatePixelShaderInternal and ValidatePixelShader below.
//-----------------------------------------------------------------------------
CBasePShaderValidator* GetNewPSValidator( const DWORD* pCode,
const D3DCAPS8* pCaps,
const DWORD Flags )
{
if( !pCode )
return NULL;
else if( D3DPS_VERSION(1,4) > *pCode )
return new CPShaderValidator10(pCode,pCaps,Flags);
else
return new CPShaderValidator14(pCode,pCaps,Flags);
}
//-----------------------------------------------------------------------------
// ValidatePixelShaderInternal
//-----------------------------------------------------------------------------
BOOL ValidatePixelShaderInternal( const DWORD* pCode, const D3DCAPS8* pCaps )
{
CBasePShaderValidator * pValidator = NULL;
BOOL bSuccess = FALSE;
pValidator = GetNewPSValidator( pCode, pCaps, 0 );
if( NULL == pValidator )
{
OutputDebugString("Out of memory.\n");
return bSuccess;
}
bSuccess = SUCCEEDED(pValidator->GetStatus()) ? TRUE : FALSE;
delete pValidator;
return bSuccess;
}
//-----------------------------------------------------------------------------
// ValidatePixelShader
//
// Don't forget to call "free" on the buffer returned in ppBuf.
//-----------------------------------------------------------------------------
HRESULT WINAPI ValidatePixelShader( const DWORD* pCode,
const D3DCAPS8* pCaps,
const DWORD Flags,
char** const ppBuf )
{
CBasePShaderValidator * pValidator = NULL;
HRESULT hr;
pValidator = GetNewPSValidator( pCode, pCaps, Flags );
if( NULL == pValidator )
{
OutputDebugString("Out of memory.\n");
return E_FAIL;
}
if( ppBuf )
{
*ppBuf = (char*)HeapAlloc(GetProcessHeap(), 0, pValidator->GetRequiredLogBufferSize());
if( NULL == *ppBuf )
OutputDebugString("Out of memory.\n");
else
pValidator->WriteLogToBuffer(*ppBuf);
}
hr = pValidator->GetStatus();
delete pValidator;
return hr;
}