Source code of Windows XP (NT5)
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.

333 lines
13 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) Microsoft Corporation, 2000.
  3. //
  4. // pshdrval.cpp
  5. //
  6. // Direct3D Reference Device - PixelShader validation
  7. //
  8. ///////////////////////////////////////////////////////////////////////////////
  9. #include "pch.cpp"
  10. #pragma hdrstop
  11. // Use these macros when looking at CPSInstruction derived members of the current instruction (CBaseInstruction)
  12. #define _CURR_PS_INST ((CPSInstruction*)m_pCurrInst)
  13. #define _PREV_PS_INST (m_pCurrInst?((CPSInstruction*)(m_pCurrInst->m_pPrevInst)):NULL)
  14. //-----------------------------------------------------------------------------
  15. // CPSInstruction::CalculateComponentReadMasks()
  16. //
  17. // Figure out which components of each source parameter is read by a pixelshader
  18. // instruction. For certain pixelshader instructions, the some components
  19. // are also read from the dest parameter.
  20. //
  21. // Note: When this function is changed, the changes need to be ported to
  22. // refrast's CalculateSourceReadMasks() function in rast\pshader.cpp
  23. // (Though that function does not care about channels read from the dest parameter
  24. // like this one does).
  25. //-----------------------------------------------------------------------------
  26. void CPSInstruction::CalculateComponentReadMasks(DWORD dwVersion)
  27. {
  28. UINT i, j;
  29. switch( m_Type ) // instructions that actually read from the *Destination* register...
  30. {
  31. case D3DSIO_TEXM3x2DEPTH:
  32. case D3DSIO_TEXDEPTH:
  33. m_DstParam.m_ComponentReadMask = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1;
  34. break;
  35. case D3DSIO_TEXKILL:
  36. if( (D3DPS_VERSION(1,4) == dwVersion) && (D3DSPR_TEMP == m_DstParam.m_RegType) )
  37. {
  38. // for ps.1.4, texkill on an r# register only reads rgb
  39. m_DstParam.m_ComponentReadMask = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1 | D3DSP_WRITEMASK_2;
  40. }
  41. else
  42. {
  43. m_DstParam.m_ComponentReadMask = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1 | D3DSP_WRITEMASK_2 | D3DSP_WRITEMASK_3;
  44. }
  45. break;
  46. }
  47. for( i = 0; i < m_SrcParamCount; i++ )
  48. {
  49. DWORD NeededComponents;
  50. DWORD ReadComponents = 0;
  51. switch( m_Type )
  52. {
  53. case D3DSIO_TEX: // only in ps.1.4 does texld have source parameter
  54. if( D3DPS_VERSION(1,4) == dwVersion )
  55. {
  56. // for ps.1.4, texld has a source parameter
  57. NeededComponents = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1 | D3DSP_WRITEMASK_2;
  58. }
  59. 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...
  60. {
  61. NeededComponents = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1 | D3DSP_WRITEMASK_2 | D3DSP_WRITEMASK_3;
  62. }
  63. break;
  64. case D3DSIO_TEXCOORD:
  65. if( D3DPS_VERSION(1,4) == dwVersion )
  66. {
  67. // for ps.1.4, texcrd has a source parameter
  68. NeededComponents = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1 | D3DSP_WRITEMASK_2;
  69. }
  70. 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...
  71. {
  72. NeededComponents = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1 | D3DSP_WRITEMASK_2 | D3DSP_WRITEMASK_3;
  73. }
  74. break;
  75. case D3DSIO_TEXBEM:
  76. case D3DSIO_TEXBEML:
  77. NeededComponents = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1;
  78. break;
  79. case D3DSIO_DP3:
  80. NeededComponents = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1 | D3DSP_WRITEMASK_2;
  81. break;
  82. case D3DSIO_DP4:
  83. NeededComponents = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1 | D3DSP_WRITEMASK_2 | D3DSP_WRITEMASK_3;
  84. break;
  85. case D3DSIO_BEM: // ps.1.4
  86. NeededComponents = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1;
  87. break;
  88. default:
  89. // standard component-wise instruction,
  90. // OR an op we know reads .rgba and we also know it will be validated to .rgba writemask
  91. NeededComponents = m_DstParam.m_WriteMask;
  92. break;
  93. }
  94. // Figure out which components of this source parameter are read (taking into account swizzle)
  95. for(j = 0; j < 4; j++)
  96. {
  97. if( NeededComponents & COMPONENT_MASKS[j] )
  98. ReadComponents |= COMPONENT_MASKS[(m_SrcParam[i].m_SwizzleShift >> (D3DVS_SWIZZLE_SHIFT + 2*j)) & 0x3];
  99. }
  100. m_SrcParam[i].m_ComponentReadMask = ReadComponents;
  101. }
  102. }
  103. //-----------------------------------------------------------------------------
  104. // CBasePShaderValidator::CBasePShaderValidator
  105. //-----------------------------------------------------------------------------
  106. CBasePShaderValidator::CBasePShaderValidator( const DWORD* pCode,
  107. const D3DCAPS8* pCaps,
  108. DWORD Flags )
  109. : CBaseShaderValidator( pCode, pCaps, Flags )
  110. {
  111. // Note that the base constructor initialized m_ReturnCode to E_FAIL.
  112. // Only set m_ReturnCode to S_OK if validation has succeeded,
  113. // before exiting this constructor.
  114. m_CycleNum = 0;
  115. m_TexOpCount = 0;
  116. m_BlendOpCount = 0;
  117. m_TotalOpCount = 0;
  118. m_pTempRegFile = NULL;
  119. m_pInputRegFile = NULL;
  120. m_pConstRegFile = NULL;
  121. m_pTextureRegFile = NULL;
  122. if( !m_bBaseInitOk )
  123. return;
  124. }
  125. //-----------------------------------------------------------------------------
  126. // CBasePShaderValidator::~CBasePShaderValidator
  127. //-----------------------------------------------------------------------------
  128. CBasePShaderValidator::~CBasePShaderValidator()
  129. {
  130. delete m_pTempRegFile;
  131. delete m_pInputRegFile;
  132. delete m_pConstRegFile;
  133. delete m_pTextureRegFile;
  134. }
  135. //-----------------------------------------------------------------------------
  136. // CBasePShaderValidator::AllocateNewInstruction
  137. //-----------------------------------------------------------------------------
  138. CBaseInstruction* CBasePShaderValidator::AllocateNewInstruction(CBaseInstruction*pPrevInst)
  139. {
  140. return new CPSInstruction((CPSInstruction*)pPrevInst);
  141. }
  142. //-----------------------------------------------------------------------------
  143. // CBasePShaderValidator::DecodeNextInstruction
  144. //-----------------------------------------------------------------------------
  145. BOOL CBasePShaderValidator::DecodeNextInstruction()
  146. {
  147. m_pCurrInst->m_Type = (D3DSHADER_INSTRUCTION_OPCODE_TYPE)(*m_pCurrToken & D3DSI_OPCODE_MASK);
  148. if( D3DSIO_COMMENT == m_pCurrInst->m_Type )
  149. {
  150. ParseCommentForAssemblerMessages(m_pCurrToken); // does not advance m_pCurrToken
  151. // Skip comments
  152. DWORD NumDWORDs = ((*m_pCurrToken) & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
  153. m_pCurrToken += (NumDWORDs+1);
  154. return TRUE;
  155. }
  156. // Find out if the instruction is a TexOp and/or TexMOp. Needed by multiple validation rules,
  157. // as well as further below in DecodeNextInstruction.
  158. IsCurrInstTexOp();
  159. // If the assembler has sent us file and/or line number messages,
  160. // received by ParseCommentForAssemblerMesssages(),
  161. // then bind this information to the current instruction.
  162. // This info can be used in error spew to direct the shader developer
  163. // to exactly where a problem is located.
  164. m_pCurrInst->SetSpewFileNameAndLineNumber(m_pLatestSpewFileName,m_pLatestSpewLineNumber);
  165. if( *m_pCurrToken & D3DSI_COISSUE )
  166. {
  167. _CURR_PS_INST->m_bCoIssue = TRUE;
  168. }
  169. else if( D3DSIO_NOP != m_pCurrInst->m_Type )
  170. {
  171. m_CycleNum++; // First cycle is 1. (co-issued instructions will have same cycle number)
  172. }
  173. _CURR_PS_INST->m_CycleNum = m_CycleNum;
  174. m_SpewInstructionCount++; // only used for spew, not for any limits
  175. m_pCurrInst->m_SpewInstructionCount = m_SpewInstructionCount;
  176. DWORD dwReservedBits = PS_INST_TOKEN_RESERVED_MASK;
  177. if( (*m_pCurrToken) & dwReservedBits )
  178. {
  179. Spew(SPEW_INSTRUCTION_ERROR,m_pCurrInst,"Reserved bit(s) set in instruction parameter token! Aborting validation.");
  180. return FALSE;
  181. }
  182. m_pCurrToken++;
  183. // Decode dst param
  184. if (*m_pCurrToken & (1L<<31))
  185. {
  186. (m_pCurrInst->m_DstParamCount)++;
  187. DecodeDstParam( &m_pCurrInst->m_DstParam, *m_pCurrToken );
  188. if( (*m_pCurrToken) & PS_DSTPARAM_TOKEN_RESERVED_MASK )
  189. {
  190. Spew(SPEW_INSTRUCTION_ERROR,m_pCurrInst,"Reserved bit(s) set in destination parameter token! Aborting validation.");
  191. return FALSE;
  192. }
  193. m_pCurrToken++;
  194. if( D3DSIO_DEF == m_pCurrInst->m_Type )
  195. {
  196. // Skip source params (float vector) - nothing to check
  197. // This is the only instruction with 4 source params,
  198. // and further, this is the only instruction that has
  199. // raw numbers as parameters. This justifies the
  200. // special case treatment here - we pretend
  201. // D3DSIO_DEF only has a dst param (which we will check).
  202. m_pCurrToken += 4;
  203. return TRUE;
  204. }
  205. }
  206. // Decode src param(s)
  207. while (*m_pCurrToken & (1L<<31))
  208. {
  209. (m_pCurrInst->m_SrcParamCount)++;
  210. if( (m_pCurrInst->m_SrcParamCount + m_pCurrInst->m_DstParamCount) > SHADER_INSTRUCTION_MAX_PARAMS )
  211. {
  212. m_pCurrInst->m_SrcParamCount--;
  213. m_pCurrToken++; // eat up extra parameters and skip to next
  214. continue;
  215. }
  216. // Below: index is [SrcParamCount - 1] because m_SrcParam array needs 0 based index.
  217. DecodeSrcParam( &(m_pCurrInst->m_SrcParam[m_pCurrInst->m_SrcParamCount - 1]),*m_pCurrToken );
  218. if( (*m_pCurrToken) & PS_SRCPARAM_TOKEN_RESERVED_MASK )
  219. {
  220. Spew(SPEW_INSTRUCTION_ERROR,m_pCurrInst,"Reserved bit(s) set in source %d parameter token! Aborting validation.",
  221. m_pCurrInst->m_SrcParamCount);
  222. return FALSE;
  223. }
  224. m_pCurrToken++;
  225. }
  226. // Figure out which components of each source operand actually need to be read,
  227. // taking into account destination write mask, the type of instruction, source swizzle, etc.
  228. // (must be after IsCurrInstTexOp() )
  229. m_pCurrInst->CalculateComponentReadMasks(m_Version);
  230. return TRUE;
  231. }
  232. //-----------------------------------------------------------------------------
  233. //
  234. // CBasePShaderValidator Wrapper Functions
  235. //
  236. //-----------------------------------------------------------------------------
  237. //-----------------------------------------------------------------------------
  238. // GetNewPSValidator
  239. //
  240. // Called by ValidatePixelShaderInternal and ValidatePixelShader below.
  241. //-----------------------------------------------------------------------------
  242. CBasePShaderValidator* GetNewPSValidator( const DWORD* pCode,
  243. const D3DCAPS8* pCaps,
  244. const DWORD Flags )
  245. {
  246. if( !pCode )
  247. return NULL;
  248. else if( D3DPS_VERSION(1,4) > *pCode )
  249. return new CPShaderValidator10(pCode,pCaps,Flags);
  250. else
  251. return new CPShaderValidator14(pCode,pCaps,Flags);
  252. }
  253. //-----------------------------------------------------------------------------
  254. // ValidatePixelShaderInternal
  255. //-----------------------------------------------------------------------------
  256. BOOL ValidatePixelShaderInternal( const DWORD* pCode, const D3DCAPS8* pCaps )
  257. {
  258. CBasePShaderValidator * pValidator = NULL;
  259. BOOL bSuccess = FALSE;
  260. pValidator = GetNewPSValidator( pCode, pCaps, 0 );
  261. if( NULL == pValidator )
  262. {
  263. OutputDebugString("Out of memory.\n");
  264. return bSuccess;
  265. }
  266. bSuccess = SUCCEEDED(pValidator->GetStatus()) ? TRUE : FALSE;
  267. delete pValidator;
  268. return bSuccess;
  269. }
  270. //-----------------------------------------------------------------------------
  271. // ValidatePixelShader
  272. //
  273. // Don't forget to call "free" on the buffer returned in ppBuf.
  274. //-----------------------------------------------------------------------------
  275. HRESULT WINAPI ValidatePixelShader( const DWORD* pCode,
  276. const D3DCAPS8* pCaps,
  277. const DWORD Flags,
  278. char** const ppBuf )
  279. {
  280. CBasePShaderValidator * pValidator = NULL;
  281. HRESULT hr;
  282. pValidator = GetNewPSValidator( pCode, pCaps, Flags );
  283. if( NULL == pValidator )
  284. {
  285. OutputDebugString("Out of memory.\n");
  286. return E_FAIL;
  287. }
  288. if( ppBuf )
  289. {
  290. *ppBuf = (char*)HeapAlloc(GetProcessHeap(), 0, pValidator->GetRequiredLogBufferSize());
  291. if( NULL == *ppBuf )
  292. OutputDebugString("Out of memory.\n");
  293. else
  294. pValidator->WriteLogToBuffer(*ppBuf);
  295. }
  296. hr = pValidator->GetStatus();
  297. delete pValidator;
  298. return hr;
  299. }