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.

2708 lines
99 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. // PixelShader Validation Rule Coverage
  16. //
  17. // Below is the list of rules in "DX8 PixelShader Version Specification",
  18. // matched to the function(s) in this file which enforce them.
  19. // Note that the mapping from rules to funtions can be 1->n or n->1
  20. //
  21. // Generic Rules
  22. // -------------
  23. //
  24. // PS-G1: Rule_R0Written
  25. // PS-G2: Rule_SrcInitialized
  26. // PS-G3: Rule_ValidDstParam
  27. //
  28. // TEX Op Specific Rules
  29. // ---------------------
  30. //
  31. // PS-T1: Rule_TexOpAfterNonTexOp
  32. // PS-T2: Rule_ValidDstParam
  33. // PS-T3: Rule_ValidDstParam, Rule_ValidSrcParams
  34. // PS-T4: Rule_TexRegsDeclaredInOrder
  35. // PS-T5: Rule_SrcInitialized
  36. // PS-T6: Rule_ValidTEXM3xSequence, Rule_ValidTEXM3xRegisterNumbers, Rule_InstructionSupportedByVersion
  37. // PS-T7: Rule_ValidSrcParams
  38. //
  39. // Co-Issue Specific Rules
  40. // -----------------------
  41. //
  42. // PS-C1: Rule_ValidInstructionPairing
  43. // PS-C2: Rule_ValidInstructionPairing
  44. // PS-C3: Rule_ValidInstructionPairing
  45. // PS-C4: Rule_ValidInstructionPairing
  46. // PS-C5: Rule_ValidInstructionPairing
  47. //
  48. // Instruction Specific Rules
  49. // --------------------------
  50. //
  51. // PS-I1: Rule_ValidLRPInstruction
  52. // PS-I2: Rule_ValidCNDInstruction
  53. // PS-I3: Rule_ValidDstParam
  54. // PS-I4: Rule_ValidDP3Instruction
  55. // PS-I5: Rule_ValidInstructionCount
  56. //
  57. // Pixel Shader Version 1.0 Rules
  58. // ------------------------------
  59. //
  60. // PS.1.0-1: InitValidation,
  61. // Rule_SrcInitialized
  62. // PS.1.0-2: Rule_ValidInstructionPairing
  63. // PS.1.0-3: <empty rule>
  64. // PS.1.0-4: Rule_ValidInstructionCount
  65. // PS.1.0-5: <empty rule>
  66. //
  67. // Pixel Shader Version 1.1 Rules
  68. // ------------------------------
  69. //
  70. // PS.1.1-1: Rule_ValidDstParam
  71. // PS.1.1-2: Rule_ValidSrcParams
  72. // PS.1.1-3: Rule_SrcNoLongerAvailable
  73. // PS.1.1-4: Rule_SrcNoLongerAvailable
  74. // PS.1.1-5: Rule_SrcNoLongerAvailable
  75. // PS.1.1-6: Rule_ValidDstParam
  76. // PS.1.1-7: Rule_NegateAfterSat
  77. // PS.1.1-8: Rule_MultipleDependentTextureReads
  78. // PS.1.1-9: <not validated - implemented by refrast though>
  79. //
  80. //-----------------------------------------------------------------------------
  81. //-----------------------------------------------------------------------------
  82. // CPShaderValidator10::CPShaderValidator10
  83. //-----------------------------------------------------------------------------
  84. CPShaderValidator10::CPShaderValidator10( const DWORD* pCode,
  85. const D3DCAPS8* pCaps,
  86. DWORD Flags )
  87. : CBasePShaderValidator( pCode, pCaps, Flags )
  88. {
  89. // Note that the base constructor initialized m_ReturnCode to E_FAIL.
  90. // Only set m_ReturnCode to S_OK if validation has succeeded,
  91. // before exiting this constructor.
  92. m_TexMBaseDstReg = 0;
  93. if( !m_bBaseInitOk )
  94. return;
  95. ValidateShader(); // If successful, m_ReturnCode will be set to S_OK.
  96. // Call GetStatus() on this object to determine validation outcome.
  97. }
  98. //-----------------------------------------------------------------------------
  99. // CPShaderValidator10::IsCurrInstTexOp
  100. //-----------------------------------------------------------------------------
  101. void CPShaderValidator10::IsCurrInstTexOp()
  102. {
  103. DXGASSERT(m_pCurrInst);
  104. switch (m_pCurrInst->m_Type)
  105. {
  106. case D3DSIO_TEXM3x2PAD:
  107. case D3DSIO_TEXM3x2TEX:
  108. case D3DSIO_TEXM3x2DEPTH:
  109. case D3DSIO_TEXM3x3PAD:
  110. case D3DSIO_TEXM3x3TEX:
  111. case D3DSIO_TEXM3x3SPEC:
  112. case D3DSIO_TEXM3x3VSPEC:
  113. case D3DSIO_TEXM3x3:
  114. _CURR_PS_INST->m_bTexMOp = TRUE;
  115. // fall through
  116. case D3DSIO_TEXCOORD:
  117. case D3DSIO_TEXKILL:
  118. case D3DSIO_TEX:
  119. case D3DSIO_TEXBEM:
  120. case D3DSIO_TEXBEML:
  121. case D3DSIO_TEXREG2AR:
  122. case D3DSIO_TEXREG2GB:
  123. case D3DSIO_TEXDP3:
  124. case D3DSIO_TEXDP3TEX:
  125. case D3DSIO_TEXREG2RGB:
  126. _CURR_PS_INST->m_bTexOp = TRUE;
  127. break;
  128. }
  129. switch(m_pCurrInst->m_Type)
  130. {
  131. case D3DSIO_TEXM3x2PAD:
  132. case D3DSIO_TEXM3x3PAD:
  133. case D3DSIO_TEXM3x2DEPTH:
  134. case D3DSIO_TEXCOORD:
  135. case D3DSIO_TEXKILL:
  136. case D3DSIO_TEXDP3:
  137. case D3DSIO_TEXM3x3:
  138. _CURR_PS_INST->m_bTexOpThatReadsTexture = FALSE;
  139. break;
  140. case D3DSIO_TEX:
  141. case D3DSIO_TEXM3x2TEX:
  142. case D3DSIO_TEXM3x3TEX:
  143. case D3DSIO_TEXM3x3SPEC:
  144. case D3DSIO_TEXM3x3VSPEC:
  145. case D3DSIO_TEXBEM:
  146. case D3DSIO_TEXBEML:
  147. case D3DSIO_TEXREG2AR:
  148. case D3DSIO_TEXREG2GB:
  149. case D3DSIO_TEXREG2RGB:
  150. case D3DSIO_TEXDP3TEX:
  151. _CURR_PS_INST->m_bTexOpThatReadsTexture = TRUE;
  152. break;
  153. }
  154. }
  155. //-----------------------------------------------------------------------------
  156. // CPShaderValidator10::InitValidation
  157. //-----------------------------------------------------------------------------
  158. BOOL CPShaderValidator10::InitValidation()
  159. {
  160. switch( m_Version >> 16 )
  161. {
  162. case 0xfffe:
  163. Spew( SPEW_GLOBAL_ERROR, NULL, "Version Token: 0x%x indicates a vertex shader. Pixel shader version token must be of the form 0xffff****.",
  164. m_Version);
  165. return FALSE;
  166. case 0xffff:
  167. break; // pixelshader - ok.
  168. default:
  169. Spew( SPEW_GLOBAL_ERROR, NULL, "Version Token: 0x%x is invalid. Pixel shader version token must be of the form 0xffff****. Aborting pixel shader validation.",
  170. m_Version);
  171. return FALSE;
  172. }
  173. if( m_pCaps )
  174. {
  175. if( (m_pCaps->PixelShaderVersion & 0x0000FFFF) < (m_Version & 0x0000FFFF) )
  176. {
  177. Spew( SPEW_GLOBAL_ERROR, NULL, "Version Token: Pixel shader version %d.%d is too high for device. Maximum supported version is %d.%d. Aborting shader validation.",
  178. D3DSHADER_VERSION_MAJOR(m_Version),D3DSHADER_VERSION_MINOR(m_Version),
  179. D3DSHADER_VERSION_MAJOR(m_pCaps->PixelShaderVersion),D3DSHADER_VERSION_MINOR(m_pCaps->PixelShaderVersion));
  180. return FALSE;
  181. }
  182. }
  183. switch(m_Version)
  184. {
  185. case D3DPS_VERSION(1,0): // DX8.0
  186. m_pTempRegFile = new CRegisterFile(2,TRUE,2,FALSE); // #regs, bWritable, max# reads/instruction, pre-shader initialized
  187. m_pInputRegFile = new CRegisterFile(2,FALSE,1,TRUE);
  188. m_pConstRegFile = new CRegisterFile(8,FALSE,2,TRUE);
  189. m_pTextureRegFile = new CRegisterFile(4,FALSE,1,FALSE);
  190. break;
  191. case D3DPS_VERSION(1,1): // DX8.0
  192. m_pTempRegFile = new CRegisterFile(2,TRUE,2,FALSE); // #regs, bWritable, max# reads/instruction, pre-shader initialized
  193. m_pInputRegFile = new CRegisterFile(2,FALSE,2,TRUE);
  194. m_pConstRegFile = new CRegisterFile(8,FALSE,2,TRUE);
  195. m_pTextureRegFile = new CRegisterFile(4,TRUE,2,FALSE);
  196. break;
  197. case D3DPS_VERSION(1,2): // DX8.1
  198. case D3DPS_VERSION(1,3): // DX8.1
  199. m_pTempRegFile = new CRegisterFile(2,TRUE,2,FALSE); // #regs, bWritable, max# reads/instruction, pre-shader initialized
  200. m_pInputRegFile = new CRegisterFile(2,FALSE,2,TRUE);
  201. m_pConstRegFile = new CRegisterFile(8,FALSE,2,TRUE);
  202. m_pTextureRegFile = new CRegisterFile(4,TRUE,3,FALSE);
  203. break;
  204. default:
  205. Spew( SPEW_GLOBAL_ERROR, NULL, "Version Token: %d.%d is not a supported pixel shader version. Aborting pixel shader validation.",
  206. D3DSHADER_VERSION_MAJOR(m_Version),D3DSHADER_VERSION_MINOR(m_Version));
  207. return FALSE;
  208. }
  209. if( NULL == m_pTempRegFile ||
  210. NULL == m_pInputRegFile ||
  211. NULL == m_pConstRegFile ||
  212. NULL == m_pTextureRegFile )
  213. {
  214. Spew( SPEW_GLOBAL_ERROR, NULL, "Out of memory.");
  215. return FALSE;
  216. }
  217. return TRUE;
  218. }
  219. //-----------------------------------------------------------------------------
  220. // CPShaderValidator10::ApplyPerInstructionRules
  221. //
  222. // Returns FALSE if shader validation must terminate.
  223. // Returns TRUE if validation may proceed to next instruction.
  224. //-----------------------------------------------------------------------------
  225. BOOL CPShaderValidator10::ApplyPerInstructionRules()
  226. {
  227. if( ! Rule_InstructionRecognized() ) return FALSE; // Bail completely on unrecognized instr.
  228. if( ! Rule_InstructionSupportedByVersion() ) goto EXIT;
  229. if( ! Rule_ValidParamCount() ) goto EXIT;
  230. // Rules that examine source parameters
  231. if( ! Rule_ValidSrcParams() ) goto EXIT;
  232. if( ! Rule_NegateAfterSat() ) goto EXIT;
  233. if( ! Rule_SatBeforeBiasOrComplement() ) goto EXIT; // needs to be after _ValidSrcParams(), and before _ValidDstParam(), _SrcInitialized()
  234. if( ! Rule_MultipleDependentTextureReads() ) goto EXIT; // needs to be after _ValidSrcParams(), and before _ValidDstParam(), _SrcInitialized()
  235. if( ! Rule_SrcNoLongerAvailable() ) goto EXIT; // needs to be after _ValidSrcParams(), and before _ValidDstParam(), _SrcInitialized()
  236. if( ! Rule_SrcInitialized() ) goto EXIT; // needs to be before _ValidDstParam()
  237. if( ! Rule_ValidDstParam() ) goto EXIT;
  238. if( ! Rule_ValidRegisterPortUsage() ) goto EXIT;
  239. if( ! Rule_TexRegsDeclaredInOrder() ) goto EXIT;
  240. if( ! Rule_TexOpAfterNonTexOp() ) goto EXIT;
  241. if( ! Rule_ValidTEXM3xSequence() ) goto EXIT;
  242. if( ! Rule_ValidTEXM3xRegisterNumbers() ) goto EXIT;
  243. if( ! Rule_ValidCNDInstruction() ) goto EXIT;
  244. if( ! Rule_ValidCMPInstruction() ) goto EXIT;
  245. if( ! Rule_ValidLRPInstruction() ) goto EXIT;
  246. if( ! Rule_ValidDEFInstruction() ) goto EXIT;
  247. if( ! Rule_ValidDP3Instruction() ) goto EXIT;
  248. if( ! Rule_ValidDP4Instruction() ) goto EXIT;
  249. if( ! Rule_ValidInstructionPairing() ) goto EXIT;
  250. if( ! Rule_ValidInstructionCount() ) goto EXIT;
  251. EXIT:
  252. return TRUE;
  253. }
  254. //-----------------------------------------------------------------------------
  255. // CPShaderValidator10::ApplyPostInstructionsRules
  256. //-----------------------------------------------------------------------------
  257. void CPShaderValidator10::ApplyPostInstructionsRules()
  258. {
  259. Rule_ValidTEXM3xSequence(); // check once more to see if shader ended dangling in mid-sequence
  260. Rule_ValidInstructionCount(); // see if we went over the limits
  261. Rule_R0Written();
  262. }
  263. //-----------------------------------------------------------------------------
  264. //
  265. // Per Instruction Rules
  266. //
  267. //-----------------------------------------------------------------------------
  268. //-----------------------------------------------------------------------------
  269. // CPShaderValidator10::Rule_InstructionRecognized
  270. //
  271. // ** Rule:
  272. // Is the instruction opcode known? (regardless of shader version)
  273. //
  274. // ** When to call:
  275. // Per instruction.
  276. //
  277. // ** Returns:
  278. // FALSE when instruction not recognized.
  279. //
  280. //-----------------------------------------------------------------------------
  281. BOOL CPShaderValidator10::Rule_InstructionRecognized()
  282. {
  283. switch(m_pCurrInst->m_Type)
  284. {
  285. case D3DSIO_MOV:
  286. case D3DSIO_ADD:
  287. case D3DSIO_SUB:
  288. case D3DSIO_MUL:
  289. case D3DSIO_MAD:
  290. case D3DSIO_LRP:
  291. case D3DSIO_DP3:
  292. case D3DSIO_TEX:
  293. case D3DSIO_TEXBEM:
  294. case D3DSIO_TEXBEML:
  295. case D3DSIO_CND:
  296. case D3DSIO_TEXCOORD:
  297. case D3DSIO_TEXM3x2PAD:
  298. case D3DSIO_TEXM3x2TEX:
  299. case D3DSIO_TEXM3x3PAD:
  300. case D3DSIO_TEXM3x3TEX:
  301. case D3DSIO_TEXM3x3SPEC:
  302. case D3DSIO_TEXM3x3VSPEC:
  303. case D3DSIO_TEXREG2AR:
  304. case D3DSIO_TEXREG2GB:
  305. case D3DSIO_TEXKILL:
  306. case D3DSIO_END:
  307. case D3DSIO_NOP:
  308. case D3DSIO_DEF:
  309. case D3DSIO_TEXM3x2DEPTH:
  310. case D3DSIO_TEXDP3:
  311. case D3DSIO_TEXREG2RGB:
  312. case D3DSIO_DP4:
  313. case D3DSIO_CMP:
  314. case D3DSIO_TEXDP3TEX:
  315. case D3DSIO_TEXM3x3:
  316. case D3DSIO_TEXDEPTH:
  317. case D3DSIO_BEM:
  318. case D3DSIO_PHASE:
  319. return TRUE; // instruction recognized - ok.
  320. }
  321. // if we get here, the instruction is not recognized
  322. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Unrecognized instruction. Aborting pixel shader validation.");
  323. m_ErrorCount++;
  324. return FALSE;
  325. }
  326. //-----------------------------------------------------------------------------
  327. // CPShaderValidator10::Rule_InstructionSupportedByVersion
  328. //
  329. // ** Rule:
  330. // Is the instruction supported by the current pixel shader version?
  331. //
  332. // ** When to call:
  333. // Per instruction.
  334. //
  335. // ** Returns:
  336. // FALSE when instruction not supported by version.
  337. //
  338. //-----------------------------------------------------------------------------
  339. BOOL CPShaderValidator10::Rule_InstructionSupportedByVersion()
  340. {
  341. if( D3DPS_VERSION(1,0) <= m_Version ) // 1.0 and above
  342. {
  343. switch(m_pCurrInst->m_Type)
  344. {
  345. case D3DSIO_MOV:
  346. case D3DSIO_ADD:
  347. case D3DSIO_SUB:
  348. case D3DSIO_MUL:
  349. case D3DSIO_MAD:
  350. case D3DSIO_LRP:
  351. case D3DSIO_DP3:
  352. case D3DSIO_TEX:
  353. case D3DSIO_DEF:
  354. case D3DSIO_TEXBEM:
  355. case D3DSIO_TEXBEML:
  356. case D3DSIO_CND:
  357. case D3DSIO_TEXKILL:
  358. case D3DSIO_TEXCOORD:
  359. case D3DSIO_TEXM3x2PAD:
  360. case D3DSIO_TEXM3x2TEX:
  361. case D3DSIO_TEXM3x3PAD:
  362. case D3DSIO_TEXM3x3TEX:
  363. case D3DSIO_TEXM3x3SPEC:
  364. case D3DSIO_TEXM3x3VSPEC:
  365. case D3DSIO_TEXREG2AR:
  366. case D3DSIO_TEXREG2GB:
  367. return TRUE; // instruction supported - ok.
  368. }
  369. }
  370. if( D3DPS_VERSION(1,2) <= m_Version ) // 1.2 and above
  371. {
  372. switch(m_pCurrInst->m_Type)
  373. {
  374. case D3DSIO_CMP:
  375. case D3DSIO_DP4:
  376. case D3DSIO_TEXDP3:
  377. case D3DSIO_TEXDP3TEX:
  378. case D3DSIO_TEXM3x3:
  379. case D3DSIO_TEXREG2RGB:
  380. return TRUE; // instruction supported - ok.
  381. }
  382. }
  383. if( D3DPS_VERSION(1,3) <= m_Version ) // 1.3
  384. {
  385. switch(m_pCurrInst->m_Type)
  386. {
  387. case D3DSIO_TEXM3x2DEPTH:
  388. return TRUE; // instruction supported - ok.
  389. }
  390. }
  391. switch(m_pCurrInst->m_Type)
  392. {
  393. case D3DSIO_END:
  394. case D3DSIO_NOP:
  395. return TRUE; // instruction supported - ok.
  396. }
  397. // if we get here, the instruction is not supported.
  398. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Instruction not supported by version %d.%d pixel shader.",
  399. D3DSHADER_VERSION_MAJOR(m_Version),D3DSHADER_VERSION_MINOR(m_Version));
  400. m_ErrorCount++;
  401. return FALSE; // no more checks on this instruction
  402. }
  403. //-----------------------------------------------------------------------------
  404. // CPShaderValidator10::Rule_ValidParamCount
  405. //
  406. // ** Rule:
  407. // Is the parameter count correct for the instruction?
  408. //
  409. // DEF is a special case that is treated as having only 1 dest parameter,
  410. // even though there are also 4 source parameters. The 4 source params for DEF
  411. // are immediate float values, so there is nothing to check, and no way of
  412. // knowing whether or not those parameter tokens were actually present in the
  413. // token list - all the validator can do is skip over 4 DWORDS (which it does).
  414. //
  415. // ** When to call:
  416. // Per instruction.
  417. //
  418. // ** Returns:
  419. // FALSE when the parameter count is incorrect.
  420. //
  421. //-----------------------------------------------------------------------------
  422. BOOL CPShaderValidator10::Rule_ValidParamCount()
  423. {
  424. BOOL bBadParamCount = FALSE;
  425. if (m_pCurrInst->m_SrcParamCount + m_pCurrInst->m_DstParamCount > SHADER_INSTRUCTION_MAX_PARAMS) bBadParamCount = TRUE;
  426. switch (m_pCurrInst->m_Type)
  427. {
  428. case D3DSIO_NOP:
  429. bBadParamCount = (m_pCurrInst->m_DstParamCount != 0) || (m_pCurrInst->m_SrcParamCount != 0); break;
  430. case D3DSIO_MOV:
  431. bBadParamCount = (m_pCurrInst->m_DstParamCount != 1) || (m_pCurrInst->m_SrcParamCount != 1); break;
  432. case D3DSIO_ADD:
  433. case D3DSIO_SUB:
  434. case D3DSIO_MUL:
  435. case D3DSIO_DP3:
  436. case D3DSIO_DP4:
  437. bBadParamCount = (m_pCurrInst->m_DstParamCount != 1) || (m_pCurrInst->m_SrcParamCount != 2); break;
  438. case D3DSIO_MAD:
  439. case D3DSIO_LRP:
  440. case D3DSIO_CND:
  441. case D3DSIO_CMP:
  442. bBadParamCount = (m_pCurrInst->m_DstParamCount != 1) || (m_pCurrInst->m_SrcParamCount != 3); break;
  443. case D3DSIO_TEXCOORD:
  444. case D3DSIO_TEXKILL:
  445. case D3DSIO_TEX:
  446. case D3DSIO_DEF: // we skipped the last 4 parameters (float vector) - nothing to check
  447. bBadParamCount = (m_pCurrInst->m_DstParamCount != 1) || (m_pCurrInst->m_SrcParamCount != 0); break;
  448. case D3DSIO_TEXBEM:
  449. case D3DSIO_TEXBEML:
  450. case D3DSIO_TEXREG2AR:
  451. case D3DSIO_TEXREG2GB:
  452. case D3DSIO_TEXM3x2PAD:
  453. case D3DSIO_TEXM3x2TEX:
  454. case D3DSIO_TEXM3x3PAD:
  455. case D3DSIO_TEXM3x3TEX:
  456. case D3DSIO_TEXM3x3VSPEC:
  457. case D3DSIO_TEXM3x2DEPTH:
  458. case D3DSIO_TEXDP3:
  459. case D3DSIO_TEXREG2RGB:
  460. case D3DSIO_TEXM3x3:
  461. case D3DSIO_TEXDP3TEX:
  462. bBadParamCount = (m_pCurrInst->m_DstParamCount != 1) || (m_pCurrInst->m_SrcParamCount != 1); break;
  463. case D3DSIO_TEXM3x3SPEC:
  464. bBadParamCount = (m_pCurrInst->m_DstParamCount != 1) || (m_pCurrInst->m_SrcParamCount != 2); break;
  465. }
  466. if (bBadParamCount)
  467. {
  468. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Invalid parameter count.");
  469. m_ErrorCount++;
  470. return FALSE; // no more checks on this instruction
  471. }
  472. return TRUE;
  473. }
  474. //-----------------------------------------------------------------------------
  475. // CPShaderValidator10::Rule_ValidSrcParams
  476. //
  477. // ** Rule:
  478. // for each source parameter,
  479. // if current instruction is a texture instruction, then
  480. // source register type must be texture register
  481. // (with the exception of D3DSIO_SPEC, where Src1 must be c#), and
  482. // register # must be within range for texture registers, and
  483. // modifier must be D3DSPSM_NONE (or _BX2 for TexMatrixOps [version<=1.1],
  484. // _BX2 for any tex* op [version>=1.2])
  485. // swizzle must be D3DSP_NOSWIZZLE
  486. // else (non texture instruction)
  487. // source register type must be D3DSPR_TEMP/_INPUT/_CONST/_TEXTURE
  488. // register # must be within range for register type
  489. // modifier must be D3DSPSM_NONE/_NEG/_BIAS/_BIASNEG/_SIGN/_SIGNNEG/_COMP
  490. // swizzle must be D3DSP_NOSWIZZLE/_REPLICATEALPHA
  491. // and for ps.1.1+, D3DSP_REPLICATEBLUE (only on alpha op)
  492. //
  493. // Note that the parameter count for D3DSIO_DEF is treated as 1
  494. // (dest only), so this rule does nothing for it.
  495. //
  496. // ** When to call:
  497. // Per instruction.
  498. //
  499. // ** Returns:
  500. // Always TRUE.
  501. //
  502. // Errors in any of the source parameters causes m_bSrcParamError[i]
  503. // to be TRUE, so later rules that only apply when a particular source
  504. // parameter was valid know whether they need to execute or not.
  505. // e.g. Rule_SrcInitialized.
  506. //
  507. //-----------------------------------------------------------------------------
  508. BOOL CPShaderValidator10::Rule_ValidSrcParams() // could break this down for more granularity
  509. {
  510. for( UINT i = 0; i < m_pCurrInst->m_SrcParamCount; i++ )
  511. {
  512. BOOL bFoundSrcError = FALSE;
  513. SRCPARAM* pSrcParam = &(m_pCurrInst->m_SrcParam[i]);
  514. char* SourceName[3] = {"first", "second", "third"};
  515. if( _CURR_PS_INST->m_bTexOp )
  516. {
  517. if( D3DSPR_TEXTURE != pSrcParam->m_RegType )
  518. {
  519. if( D3DSIO_TEXM3x3SPEC == m_pCurrInst->m_Type && (1 == i) )
  520. {
  521. // for _SPEC, last source parameter must be c#
  522. if( D3DSPR_CONST != pSrcParam->m_RegType ||
  523. D3DSP_NOSWIZZLE != pSrcParam->m_SwizzleShift ||
  524. D3DSPSM_NONE != pSrcParam->m_SrcMod )
  525. {
  526. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Second source parameter for texm3x3spec must be c#.");
  527. m_ErrorCount++;
  528. bFoundSrcError = TRUE;
  529. goto LOOP_CONTINUE;
  530. }
  531. }
  532. else
  533. {
  534. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst,
  535. "Src reg for tex* instruction must be t# register (%s source param).",
  536. SourceName[i]);
  537. m_ErrorCount++;
  538. bFoundSrcError = TRUE;
  539. }
  540. }
  541. UINT ValidRegNum = 0;
  542. switch(pSrcParam->m_RegType)
  543. {
  544. case D3DSPR_CONST: ValidRegNum = m_pConstRegFile->GetNumRegs(); break;
  545. case D3DSPR_TEXTURE: ValidRegNum = m_pTextureRegFile->GetNumRegs(); break;
  546. default:
  547. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Invalid reg type (%s source param).",
  548. SourceName[i]);
  549. m_ErrorCount++;
  550. bFoundSrcError = TRUE;
  551. goto LOOP_CONTINUE;
  552. }
  553. if( pSrcParam->m_RegNum >= ValidRegNum )
  554. {
  555. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Invalid reg num %d (%s source param). Max allowed for this type is %d.",
  556. pSrcParam->m_RegNum, SourceName[i], ValidRegNum - 1);
  557. m_ErrorCount++;
  558. bFoundSrcError = TRUE;
  559. }
  560. switch(pSrcParam->m_SrcMod)
  561. {
  562. case D3DSPSM_NONE:
  563. break;
  564. case D3DSPSM_SIGN:
  565. if( D3DPS_VERSION(1,1) >= m_Version )
  566. {
  567. if( !(_CURR_PS_INST->m_bTexMOp) )
  568. {
  569. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "_bx2 is a valid src mod for texM* instructions only (%s source param).", SourceName[i]);
  570. m_ErrorCount++;
  571. }
  572. }
  573. break;
  574. default:
  575. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Invalid src mod for tex* instruction (%s source param).", SourceName[i]);
  576. m_ErrorCount++;
  577. bFoundSrcError = TRUE;
  578. }
  579. switch (pSrcParam->m_SwizzleShift)
  580. {
  581. case D3DSP_NOSWIZZLE:
  582. break;
  583. default:
  584. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Source swizzle not allowed for tex* instruction (%s source param).", SourceName[i]);
  585. m_ErrorCount++;
  586. bFoundSrcError = TRUE;
  587. }
  588. }
  589. else // not a tex op
  590. {
  591. UINT ValidRegNum = 0;
  592. switch(pSrcParam->m_RegType)
  593. {
  594. case D3DSPR_TEMP: ValidRegNum = m_pTempRegFile->GetNumRegs(); break;
  595. case D3DSPR_INPUT: ValidRegNum = m_pInputRegFile->GetNumRegs(); break;
  596. case D3DSPR_CONST: ValidRegNum = m_pConstRegFile->GetNumRegs(); break;
  597. case D3DSPR_TEXTURE: ValidRegNum = m_pTextureRegFile->GetNumRegs(); break;
  598. default:
  599. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Invalid reg type for %s source param.", SourceName[i]);
  600. m_ErrorCount++;
  601. bFoundSrcError = TRUE;
  602. }
  603. if( (!bFoundSrcError) && (pSrcParam->m_RegNum >= ValidRegNum) )
  604. {
  605. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Invalid reg num: %d for %s source param. Max allowed for this type is %d.",
  606. pSrcParam->m_RegNum, SourceName[i], ValidRegNum - 1);
  607. m_ErrorCount++;
  608. bFoundSrcError = TRUE;
  609. }
  610. switch( pSrcParam->m_SrcMod )
  611. {
  612. case D3DSPSM_NONE:
  613. case D3DSPSM_NEG:
  614. case D3DSPSM_BIAS:
  615. case D3DSPSM_BIASNEG:
  616. case D3DSPSM_SIGN:
  617. case D3DSPSM_SIGNNEG:
  618. case D3DSPSM_COMP:
  619. break;
  620. default:
  621. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Invalid src mod for %s source param.",
  622. SourceName[i]);
  623. m_ErrorCount++;
  624. bFoundSrcError = TRUE;
  625. }
  626. switch( pSrcParam->m_SwizzleShift )
  627. {
  628. case D3DSP_NOSWIZZLE:
  629. case D3DSP_REPLICATEALPHA:
  630. break;
  631. case D3DSP_REPLICATEBLUE:
  632. if( D3DPS_VERSION(1,1) <= m_Version )
  633. {
  634. DSTPARAM* pDstParam = &(m_pCurrInst->m_DstParam);
  635. BOOL bVectorOp = FALSE;
  636. switch( _CURR_PS_INST->m_Type )
  637. {
  638. case D3DSIO_DP3:
  639. case D3DSIO_DP4:
  640. bVectorOp = TRUE;
  641. break;
  642. }
  643. if((m_pCurrInst->m_DstParam.m_WriteMask & (D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1 | D3DSP_WRITEMASK_2))
  644. || bVectorOp )
  645. {
  646. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Src selector .b (%s source param) is only valid for instructions that occur in the alpha pipe.",
  647. SourceName[i]);
  648. m_ErrorCount++;
  649. bFoundSrcError = TRUE;
  650. }
  651. break;
  652. }
  653. // falling through
  654. default:
  655. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Invalid src swizzle for %s source param.",
  656. SourceName[i]);
  657. m_ErrorCount++;
  658. bFoundSrcError = TRUE;
  659. }
  660. }
  661. LOOP_CONTINUE:
  662. if( bFoundSrcError )
  663. {
  664. m_bSrcParamError[i] = TRUE; // needed in Rule_SrcInitialized
  665. }
  666. }
  667. return TRUE;
  668. }
  669. //-----------------------------------------------------------------------------
  670. // CPShaderValidator10::Rule_NegateAfterSat
  671. //
  672. // ** Rule:
  673. // for each source parameter,
  674. // if the last write to the register had _sat destination modifier,
  675. // then _NEG or _BIASNEG source modifiers are not allowed (version 1.1 and below)
  676. //
  677. // ** When to call:
  678. // Per instruction.
  679. //
  680. // ** Returns:
  681. // Always TRUE.
  682. //
  683. //-----------------------------------------------------------------------------
  684. BOOL CPShaderValidator10::Rule_NegateAfterSat()
  685. {
  686. if( D3DPS_VERSION(1,2) <= m_Version )
  687. return TRUE;
  688. for( UINT i = 0; i < m_pCurrInst->m_SrcParamCount; i++ )
  689. {
  690. SRCPARAM* pSrcParam = &(m_pCurrInst->m_SrcParam[i]);
  691. UINT RegNum = pSrcParam->m_RegNum;
  692. char* SourceName[3] = {"first", "second", "third"};
  693. DWORD AffectedComponents = 0;
  694. if( m_bSrcParamError[i] )
  695. continue;
  696. switch( pSrcParam->m_SrcMod )
  697. {
  698. case D3DSPSM_NEG:
  699. case D3DSPSM_BIASNEG:
  700. break;
  701. default:
  702. continue;
  703. }
  704. for( UINT Component = 0; Component < 4; Component++ )
  705. {
  706. if( !(COMPONENT_MASKS[Component] & pSrcParam->m_ComponentReadMask) )
  707. continue;
  708. CAccessHistoryNode* pMostRecentWriter = NULL;
  709. switch( pSrcParam->m_RegType )
  710. {
  711. case D3DSPR_TEXTURE:
  712. pMostRecentWriter = m_pTextureRegFile->m_pAccessHistory[Component][RegNum].m_pMostRecentWriter;
  713. break;
  714. case D3DSPR_INPUT:
  715. pMostRecentWriter = m_pInputRegFile->m_pAccessHistory[Component][RegNum].m_pMostRecentWriter;
  716. break;
  717. case D3DSPR_TEMP:
  718. pMostRecentWriter = m_pTempRegFile->m_pAccessHistory[Component][RegNum].m_pMostRecentWriter;
  719. break;
  720. case D3DSPR_CONST:
  721. pMostRecentWriter = m_pConstRegFile->m_pAccessHistory[Component][RegNum].m_pMostRecentWriter;
  722. break;
  723. }
  724. if( pMostRecentWriter &&
  725. pMostRecentWriter->m_pInst &&
  726. (((CPSInstruction*)pMostRecentWriter->m_pInst)->m_CycleNum != _CURR_PS_INST->m_CycleNum) &&
  727. (D3DSPDM_SATURATE == pMostRecentWriter->m_pInst->m_DstParam.m_DstMod )
  728. )
  729. {
  730. AffectedComponents |= COMPONENT_MASKS[Component];
  731. }
  732. }
  733. if( AffectedComponents )
  734. {
  735. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst,
  736. "Cannot apply a negation source modifier on data that was last written with the saturate destination modifier. "
  737. "Affected components(*) of %s source param: %s",
  738. SourceName[i],MakeAffectedComponentsText(AffectedComponents,TRUE,FALSE));
  739. m_ErrorCount++;
  740. m_bSrcParamError[i] = TRUE;
  741. }
  742. }
  743. return TRUE;
  744. }
  745. //-----------------------------------------------------------------------------
  746. // CPShaderValidator10::Rule_SatBeforeBiasOrComplement()
  747. //
  748. // ** Rule:
  749. // for each component of each source parameter,
  750. // if _BIAS or _COMP is applied to the source parameter, and
  751. // there was a previous writer that was a non-tex op
  752. // if the previous writer didn't do a _sat on its write, then
  753. // -> spew error.
  754. //
  755. // ** When to call:
  756. // Per instruction.
  757. //
  758. // ** Returns:
  759. // Always TRUE.
  760. //
  761. //-----------------------------------------------------------------------------
  762. BOOL CPShaderValidator10::Rule_SatBeforeBiasOrComplement()
  763. {
  764. #ifdef SHOW_VALIDATION_WARNINGS
  765. for( UINT i = 0; i < m_pCurrInst->m_SrcParamCount; i++ )
  766. {
  767. SRCPARAM* pSrcParam = &(m_pCurrInst->m_SrcParam[i]);
  768. UINT RegNum = pSrcParam->m_RegNum;
  769. char* SourceName[3] = {"first", "second", "third"};
  770. DWORD AffectedComponents = 0;
  771. if( m_bSrcParamError[i] )
  772. continue;
  773. switch( pSrcParam->m_SrcMod )
  774. {
  775. case D3DSPSM_BIAS:
  776. case D3DSPSM_COMP:
  777. break;
  778. default:
  779. continue;
  780. }
  781. for( UINT Component = 0; Component < 4; Component++ )
  782. {
  783. if( !(COMPONENT_MASKS[Component] & pSrcParam->m_ComponentReadMask) )
  784. continue;
  785. CAccessHistoryNode* pMostRecentWriter = NULL;
  786. switch( pSrcParam->m_RegType )
  787. {
  788. case D3DSPR_TEXTURE:
  789. pMostRecentWriter = m_pTextureRegFile->m_pAccessHistory[Component][RegNum].m_pMostRecentWriter;
  790. break;
  791. case D3DSPR_INPUT:
  792. pMostRecentWriter = m_pInputRegFile->m_pAccessHistory[Component][RegNum].m_pMostRecentWriter;
  793. break;
  794. case D3DSPR_TEMP:
  795. pMostRecentWriter = m_pTempRegFile->m_pAccessHistory[Component][RegNum].m_pMostRecentWriter;
  796. break;
  797. case D3DSPR_CONST:
  798. pMostRecentWriter = m_pConstRegFile->m_pAccessHistory[Component][RegNum].m_pMostRecentWriter;
  799. break;
  800. }
  801. if( pMostRecentWriter &&
  802. pMostRecentWriter->m_pInst &&
  803. (((CPSInstruction*)pMostRecentWriter->m_pInst)->m_CycleNum != _CURR_PS_INST->m_CycleNum) &&
  804. !((CPSInstruction*)pMostRecentWriter->m_pInst)->m_bTexOp &&
  805. (D3DSPDM_SATURATE != pMostRecentWriter->m_pInst->m_DstParam.m_DstMod )
  806. )
  807. {
  808. AffectedComponents |= COMPONENT_MASKS[Component];
  809. }
  810. }
  811. if( AffectedComponents )
  812. {
  813. // Warnings only
  814. if( D3DSPSM_BIAS == pSrcParam->m_SrcMod )
  815. Spew( SPEW_INSTRUCTION_WARNING, m_pCurrInst,
  816. "When using the bias source modifier on a register, "
  817. "the previous writer should apply the saturate modifier. "
  818. "This would ensure consistent behaviour across different hardware. "
  819. "Affected components(*) of %s source param: %s",
  820. SourceName[i],MakeAffectedComponentsText(AffectedComponents,TRUE,FALSE));
  821. else
  822. Spew( SPEW_INSTRUCTION_WARNING, m_pCurrInst,
  823. "When using the complement source modifier on a register, "
  824. "the previous writer should apply the saturate destination modifier. "
  825. "This would ensure consistent behaviour across different hardware. "
  826. "Affected components(*) of %s source param: %s",
  827. SourceName[i],MakeAffectedComponentsText(AffectedComponents,TRUE,FALSE));
  828. }
  829. }
  830. #endif
  831. return TRUE;
  832. }
  833. //-----------------------------------------------------------------------------
  834. // CPShaderValidator10::Rule_SrcNoLongerAvailable
  835. //
  836. // ** Rule:
  837. // for each source parameter,
  838. // if it refers to a texture register then
  839. // for each component of the source register that needs to be read,
  840. // the src register cannot have been written by TEXKILL or TEXM*PAD TEXM3x2DEPTH instructions, and
  841. // if the instruction is a tex op then
  842. // the src register cannot have been written by TEXBEM or TEXBEML
  843. // else
  844. // the src register cannot have been read by any tex op (1.0 only)
  845. //
  846. //
  847. // ** When to call:
  848. // Per instruction. This rule must be called before Rule_ValidDstParam(),
  849. // and before Rule_SrcInitialized(),
  850. // but after Rule_ValidSrcParams()
  851. //
  852. // ** Returns:
  853. // Always TRUE.
  854. //
  855. //-----------------------------------------------------------------------------
  856. BOOL CPShaderValidator10::Rule_SrcNoLongerAvailable()
  857. {
  858. for( UINT i = 0; i < m_pCurrInst->m_SrcParamCount; i++ )
  859. {
  860. SRCPARAM* pSrcParam = &(m_pCurrInst->m_SrcParam[i]);
  861. UINT RegNum = pSrcParam->m_RegNum;
  862. char* SourceName[3] = {"first", "second", "third"};
  863. DWORD AffectedComponents = 0;
  864. if( m_bSrcParamError[i] ) continue;
  865. for( UINT Component = 0; Component < 4; Component++ )
  866. {
  867. if( !(pSrcParam->m_ComponentReadMask & COMPONENT_MASKS[Component]) )
  868. continue;
  869. if( D3DSPR_TEXTURE == pSrcParam->m_RegType )
  870. {
  871. CAccessHistoryNode* pMostRecentWriter = m_pTextureRegFile->m_pAccessHistory[Component][RegNum].m_pMostRecentWriter;
  872. if( pMostRecentWriter && pMostRecentWriter->m_pInst )
  873. {
  874. switch( pMostRecentWriter->m_pInst->m_Type )
  875. {
  876. case D3DSIO_TEXKILL:
  877. case D3DSIO_TEXM3x2DEPTH:
  878. case D3DSIO_TEXM3x2PAD:
  879. case D3DSIO_TEXM3x3PAD:
  880. AffectedComponents |= COMPONENT_MASKS[Component];
  881. }
  882. }
  883. }
  884. }
  885. if( AffectedComponents )
  886. {
  887. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst,
  888. "Texture register result of texkill%s or texm*pad instructions must not be read. Affected components(*) of %s source param: %s",
  889. (D3DPS_VERSION(1,3) <= m_Version) ? ", texm3x2depth" : "",
  890. SourceName[i],MakeAffectedComponentsText(AffectedComponents,TRUE,FALSE));
  891. m_ErrorCount++;
  892. m_bSrcParamError[i] = TRUE;
  893. }
  894. if( _CURR_PS_INST->m_bTexOp )
  895. {
  896. AffectedComponents = 0;
  897. for( UINT Component = 0; Component < 4; Component++ )
  898. {
  899. if( !(pSrcParam->m_ComponentReadMask & COMPONENT_MASKS[Component]) )
  900. continue;
  901. if( D3DSPR_TEXTURE == pSrcParam->m_RegType )
  902. {
  903. CAccessHistoryNode* pMostRecentWriter = m_pTextureRegFile->m_pAccessHistory[Component][RegNum].m_pMostRecentWriter;
  904. if( pMostRecentWriter && pMostRecentWriter->m_pInst )
  905. {
  906. switch( pMostRecentWriter->m_pInst->m_Type )
  907. {
  908. case D3DSIO_TEXBEM:
  909. case D3DSIO_TEXBEML:
  910. AffectedComponents |= COMPONENT_MASKS[Component];
  911. break;
  912. }
  913. }
  914. }
  915. }
  916. if( AffectedComponents )
  917. {
  918. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst,
  919. "Texture register result of texbem or texbeml instruction must not be read by tex* instruction. Affected components(*) of %s source param: %s",
  920. SourceName[i],MakeAffectedComponentsText(AffectedComponents,TRUE,FALSE));
  921. m_ErrorCount++;
  922. m_bSrcParamError[i] = TRUE;
  923. }
  924. }
  925. else // non-tex op
  926. {
  927. if( D3DPS_VERSION(1,1) <= m_Version )
  928. continue;
  929. AffectedComponents = 0;
  930. for( UINT Component = 0; Component < 4; Component++ )
  931. {
  932. if( !(pSrcParam->m_ComponentReadMask & COMPONENT_MASKS[Component]) )
  933. continue;
  934. if( D3DSPR_TEXTURE == pSrcParam->m_RegType )
  935. {
  936. CAccessHistoryNode* pMostRecentAccess = m_pTextureRegFile->m_pAccessHistory[Component][RegNum].m_pMostRecentAccess;
  937. if( pMostRecentAccess &&
  938. pMostRecentAccess->m_pInst &&
  939. pMostRecentAccess->m_bRead &&
  940. ((CPSInstruction*)(pMostRecentAccess->m_pInst))->m_bTexOp )
  941. {
  942. AffectedComponents |= COMPONENT_MASKS[Component];
  943. }
  944. }
  945. }
  946. if( AffectedComponents )
  947. {
  948. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst,
  949. "Texture register that has been read by a tex* instruction cannot be read by a non-tex* instruction. Affected components(*) of %s source param: %s",
  950. SourceName[i],MakeAffectedComponentsText(AffectedComponents,TRUE,FALSE));
  951. m_ErrorCount++;
  952. m_bSrcParamError[i] = TRUE;
  953. }
  954. }
  955. }
  956. return TRUE;
  957. }
  958. //-----------------------------------------------------------------------------
  959. // CPShaderValidator10::Rule_MultipleDependentTextureReads
  960. //
  961. // ** Rule:
  962. //
  963. // Multiple dependent texture reads are disallowed. So texture read results
  964. // can be used as an address in a subsequent read, but the results from that
  965. // second read cannot be used as an address in yet another subsequent read.
  966. //
  967. // As pseudocode:
  968. //
  969. // if current instruction (x) is a tex-op that reads a texture
  970. // for each source param of x
  971. // if the register is a texture register
  972. // and there exists a previous writer (y),
  973. // and y is a tex op that reads a texture
  974. // if there exists a souce parameter of y that was previously
  975. // written by an instruction that reads a texture (z)
  976. // SPEW(Error)
  977. //
  978. // NOTE that it is assumed that tex ops must write to all components, so
  979. // only the read/write history for the R component is being checked.
  980. //
  981. // ** When to call:
  982. // Per instruction. This rule must be called before Rule_ValidDstParam(),
  983. // and Rule_SrcInitialized()
  984. // but after Rule_ValidSrcParams()
  985. //
  986. // ** Returns:
  987. // Always TRUE.
  988. //
  989. //-----------------------------------------------------------------------------
  990. BOOL CPShaderValidator10::Rule_MultipleDependentTextureReads()
  991. {
  992. if( !_CURR_PS_INST->m_bTexOpThatReadsTexture )
  993. return TRUE;
  994. for( UINT i = 0; i < m_pCurrInst->m_SrcParamCount; i++ )
  995. {
  996. SRCPARAM* pSrcParam = &(m_pCurrInst->m_SrcParam[i]);
  997. UINT RegNum = pSrcParam->m_RegNum;
  998. char* SourceName[3] = {"first", "second", "third"};
  999. if( m_bSrcParamError[i] ) continue;
  1000. // Just looking at component 0 in this function because we assume tex ops write to all components.
  1001. if( !(pSrcParam->m_ComponentReadMask & COMPONENT_MASKS[0]) )
  1002. continue;
  1003. if( D3DSPR_TEXTURE != pSrcParam->m_RegType )
  1004. continue;
  1005. CAccessHistoryNode* pMostRecentWriter = m_pTextureRegFile->m_pAccessHistory[0][RegNum].m_pMostRecentWriter;
  1006. if( (!pMostRecentWriter) || (!pMostRecentWriter->m_pInst) )
  1007. continue;
  1008. if(!((CPSInstruction*)(pMostRecentWriter->m_pInst))->m_bTexOp)
  1009. continue;
  1010. if(!((CPSInstruction*)(pMostRecentWriter->m_pInst))->m_bTexOpThatReadsTexture)
  1011. continue;
  1012. for( UINT j = 0; j < pMostRecentWriter->m_pInst->m_SrcParamCount; j++ )
  1013. {
  1014. if( D3DSPR_TEXTURE != pMostRecentWriter->m_pInst->m_SrcParam[j].m_RegType )
  1015. continue;
  1016. CAccessHistoryNode* pRootInstructionHistoryNode =
  1017. m_pTextureRegFile->m_pAccessHistory[0][pMostRecentWriter->m_pInst->m_SrcParam[j].m_RegNum].m_pMostRecentWriter;
  1018. CPSInstruction* pRootInstruction = pRootInstructionHistoryNode ? (CPSInstruction*)pRootInstructionHistoryNode->m_pInst : NULL;
  1019. if( (D3DSPR_TEXTURE == pMostRecentWriter->m_pInst->m_SrcParam[j].m_RegType)
  1020. && pRootInstruction->m_bTexOpThatReadsTexture )
  1021. {
  1022. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst,
  1023. "Multiple dependent texture reads are disallowed (%s source param). Texture read results can be used as an address for subsequent read, but the results from that read cannot be used as an address in yet another subsequent read.",
  1024. SourceName[i]);
  1025. m_ErrorCount++;
  1026. m_bSrcParamError[i] = TRUE;
  1027. break;
  1028. }
  1029. }
  1030. }
  1031. return TRUE;
  1032. }
  1033. //-----------------------------------------------------------------------------
  1034. // CPShaderValidator10::Rule_SrcInitialized
  1035. //
  1036. // ** Rule:
  1037. // for each source parameter,
  1038. // if source is a TEMP or TEXTURE register then
  1039. // if the source swizzle is D3DSP_NOSWIZZLE then
  1040. // if the current instruction is DP3 (a cross component op) then
  1041. // the r, g and b components of of the source reg
  1042. // must have been previously written
  1043. // else if there is a dest parameter, then
  1044. // the components in the dest parameter write mask must
  1045. // have been written to in the source reg. previously
  1046. // else
  1047. // all components of the source must have been written
  1048. // else if the source swizzle is _REPLICATEALPHA then
  1049. // alpha component of reg must have been previously
  1050. // written
  1051. //
  1052. // When checking if a component has been written previously,
  1053. // it must have been written in a previous cycle - so in the
  1054. // case of co-issued instructions, initialization of a component
  1055. // by one co-issued instruction is not available to the other for read.
  1056. //
  1057. // Note that the parameter count for D3DSIO_DEF is treated as 1
  1058. // (dest only), so this rule does nothing for it.
  1059. //
  1060. // ** When to call:
  1061. // Per instruction. This rule must be called before Rule_ValidDstParam().
  1062. //
  1063. // ** Returns:
  1064. // Always TRUE.
  1065. //
  1066. // NOTE: This rule also updates the access history to indicate reads of the
  1067. // affected components of each source register.
  1068. //-----------------------------------------------------------------------------
  1069. BOOL CPShaderValidator10::Rule_SrcInitialized()
  1070. {
  1071. DSTPARAM* pDstParam = &(m_pCurrInst->m_DstParam);
  1072. for( UINT i = 0; i < m_pCurrInst->m_SrcParamCount; i++ )
  1073. {
  1074. SRCPARAM* pSrcParam = &(m_pCurrInst->m_SrcParam[i]);
  1075. UINT RegNum = pSrcParam->m_RegNum;
  1076. CRegisterFile* pRegFile = NULL;
  1077. char* RegChar = NULL;
  1078. DWORD UninitializedComponentsMask = 0;
  1079. CAccessHistoryNode* pWriterInCurrCycle[4] = {0, 0, 0, 0};
  1080. UINT NumUninitializedComponents = 0;
  1081. if( m_bSrcParamError[i] ) continue;
  1082. switch( pSrcParam->m_RegType )
  1083. {
  1084. case D3DSPR_TEMP:
  1085. pRegFile = m_pTempRegFile;
  1086. RegChar = "r";
  1087. break;
  1088. case D3DSPR_TEXTURE:
  1089. pRegFile = m_pTextureRegFile;
  1090. RegChar = "t";
  1091. break;
  1092. case D3DSPR_INPUT:
  1093. pRegFile = m_pInputRegFile;
  1094. RegChar = "v";
  1095. break;
  1096. case D3DSPR_CONST:
  1097. pRegFile = m_pConstRegFile;
  1098. RegChar = "c";
  1099. break;
  1100. }
  1101. if( !pRegFile ) continue;
  1102. // check for read of uninitialized components
  1103. if( D3DSPR_TEMP == pSrcParam->m_RegType ||
  1104. D3DSPR_TEXTURE == pSrcParam->m_RegType )
  1105. {
  1106. for( UINT Component = 0; Component < 4; Component++ )
  1107. {
  1108. if( !(pSrcParam->m_ComponentReadMask & COMPONENT_MASKS[Component]) )
  1109. continue;
  1110. CAccessHistoryNode* pPreviousWriter = pRegFile->m_pAccessHistory[Component][RegNum].m_pMostRecentWriter;
  1111. CBaseInstruction* pCurrInst = m_pCurrInst;
  1112. // If co-issue, find the real previous writer.
  1113. while( pPreviousWriter
  1114. && ((CPSInstruction*)pPreviousWriter->m_pInst)->m_CycleNum == _CURR_PS_INST->m_CycleNum )
  1115. {
  1116. pWriterInCurrCycle[Component] = pPreviousWriter; // log read just before this write for co-issue
  1117. pPreviousWriter = pPreviousWriter->m_pPreviousWriter;
  1118. }
  1119. // Even if pPreviousWriter == NULL, the component could have been initialized pre-shader.
  1120. // So to check for initialization, we look at m_bInitialized below, rather than pPreviousWrite
  1121. if(pPreviousWriter == NULL && !pRegFile->m_pAccessHistory[Component][RegNum].m_bPreShaderInitialized)
  1122. {
  1123. NumUninitializedComponents++;
  1124. UninitializedComponentsMask |= COMPONENT_MASKS[Component];
  1125. }
  1126. }
  1127. if( NumUninitializedComponents )
  1128. {
  1129. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Read of uninitialized component%s(*) in %s%d: %s",
  1130. NumUninitializedComponents > 1 ? "s" : "",
  1131. RegChar, RegNum, MakeAffectedComponentsText(UninitializedComponentsMask,TRUE,FALSE));
  1132. m_ErrorCount++;
  1133. }
  1134. }
  1135. // Update register file to indicate READ.
  1136. // Multiple reads of the same register component by the current instruction
  1137. // will only be logged as one read in the access history.
  1138. for( UINT Component = 0; Component < 4; Component++ )
  1139. {
  1140. #define PREV_READER(_CHAN,_REG) \
  1141. ((NULL == pRegFile->m_pAccessHistory[_CHAN][_REG].m_pMostRecentReader) ? NULL :\
  1142. pRegFile->m_pAccessHistory[_CHAN][_REG].m_pMostRecentReader->m_pInst)
  1143. if( !(pSrcParam->m_ComponentReadMask & COMPONENT_MASKS[Component]) )
  1144. continue;
  1145. if( NULL != pWriterInCurrCycle[Component] )
  1146. {
  1147. if( !pWriterInCurrCycle[Component]->m_pPreviousReader ||
  1148. pWriterInCurrCycle[Component]->m_pPreviousReader->m_pInst != m_pCurrInst )
  1149. {
  1150. if( !pRegFile->m_pAccessHistory[Component][RegNum].InsertReadBeforeWrite(
  1151. pWriterInCurrCycle[Component], m_pCurrInst ) )
  1152. {
  1153. Spew( SPEW_GLOBAL_ERROR, NULL, "Out of memory");
  1154. m_ErrorCount++;
  1155. }
  1156. }
  1157. }
  1158. else if( PREV_READER(Component,RegNum) != m_pCurrInst )
  1159. {
  1160. if( !pRegFile->m_pAccessHistory[Component][RegNum].NewAccess(m_pCurrInst,FALSE) )
  1161. {
  1162. Spew( SPEW_GLOBAL_ERROR, NULL, "Out of memory");
  1163. m_ErrorCount++;
  1164. }
  1165. }
  1166. }
  1167. }
  1168. return TRUE;
  1169. }
  1170. //-----------------------------------------------------------------------------
  1171. // CPShaderValidator10::Rule_ValidDstParam
  1172. //
  1173. // ** Rule:
  1174. // if instruction is D3DSIO_DEF, then do nothing - this case has its own separate rule
  1175. // the dst register must be writable.
  1176. // if the instruction has a dest parameter (i.e. every instruction except NOP), then
  1177. // the dst register must be of type D3DSPR_TEMP or _TEXTURE, and
  1178. // register # must be within range for the register type, and
  1179. // the write mask must be: .rgba, .a or .rgb
  1180. // if instruction is a texture instruction, then
  1181. // the dst register must be of type D3DSPR_TEXTURE, and
  1182. // the writemask must be D3DSP_WRITEMASK_ALL, and
  1183. // the dst modifier must be D3DSPDM_NONE (or _SAT on version > 1.2), and
  1184. // the dst shift must be none
  1185. // else (non tex instruction)
  1186. // the dst modifier must be D3DSPDM_NONE or _SATURATE, and
  1187. // dst shift must be /2, none, *2, or *4
  1188. //
  1189. // ** When to call:
  1190. // Per instruction.
  1191. //
  1192. // ** Returns:
  1193. // Always TRUE.
  1194. //
  1195. // NOTE: After checking the dst parameter, if no error was found,
  1196. // the write to the appropriate component(s) of the destination register
  1197. // is recorded by this function, so subsequent rules may check for previous
  1198. // write to registers.
  1199. //-----------------------------------------------------------------------------
  1200. BOOL CPShaderValidator10::Rule_ValidDstParam() // could break this down for more granularity
  1201. {
  1202. BOOL bFoundDstError = FALSE;
  1203. DSTPARAM* pDstParam = &(m_pCurrInst->m_DstParam);
  1204. UINT RegNum = pDstParam->m_RegNum;
  1205. if( D3DSIO_DEF == m_pCurrInst->m_Type )
  1206. {
  1207. // _DEF is a special instruction whose dest is a const register.
  1208. // We do the checking for this in a separate function.
  1209. // Also, we don't need to keep track of the fact that
  1210. // this instruction wrote to a register (done below),
  1211. // since _DEF just declares a constant.
  1212. return TRUE;
  1213. }
  1214. if( pDstParam->m_bParamUsed )
  1215. {
  1216. UINT ValidRegNum = 0;
  1217. BOOL bWritable = FALSE;
  1218. switch( pDstParam->m_RegType )
  1219. {
  1220. case D3DSPR_TEMP:
  1221. bWritable = m_pTempRegFile->IsWritable();
  1222. ValidRegNum = m_pTempRegFile->GetNumRegs();
  1223. break;
  1224. case D3DSPR_TEXTURE:
  1225. if( _CURR_PS_INST->m_bTexOp )
  1226. bWritable = TRUE;
  1227. else
  1228. bWritable = m_pTextureRegFile->IsWritable();
  1229. ValidRegNum = m_pTextureRegFile->GetNumRegs();
  1230. break;
  1231. }
  1232. if( !bWritable || !ValidRegNum )
  1233. {
  1234. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Invalid reg type for dest param." );
  1235. m_ErrorCount++;
  1236. bFoundDstError = TRUE;
  1237. }
  1238. else if( RegNum >= ValidRegNum )
  1239. {
  1240. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Invalid dest reg num: %d. Max allowed for this reg type is %d.",
  1241. RegNum, ValidRegNum - 1);
  1242. m_ErrorCount++;
  1243. bFoundDstError = TRUE;
  1244. }
  1245. else
  1246. {
  1247. // Make sure we aren't writing to a register that is no longer available.
  1248. if( D3DSPR_TEXTURE == pDstParam->m_RegType )
  1249. {
  1250. for( UINT Component = 0; Component < 4; Component++ )
  1251. {
  1252. CAccessHistoryNode* pMostRecentWriter = m_pTextureRegFile->m_pAccessHistory[Component][RegNum].m_pMostRecentWriter;
  1253. if( pMostRecentWriter && pMostRecentWriter->m_pInst )
  1254. {
  1255. switch( pMostRecentWriter->m_pInst->m_Type )
  1256. {
  1257. case D3DSIO_TEXM3x2DEPTH:
  1258. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst,
  1259. "Destination of texm3x2depth instruction (t%d) is not available elsewhere in shader.",
  1260. RegNum);
  1261. m_ErrorCount++;
  1262. return TRUE;
  1263. }
  1264. }
  1265. }
  1266. }
  1267. }
  1268. if( _CURR_PS_INST->m_bTexOp )
  1269. {
  1270. if( D3DSPR_TEXTURE != pDstParam->m_RegType )
  1271. {
  1272. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Must use texture register a dest param for tex* instructions." );
  1273. m_ErrorCount++;
  1274. bFoundDstError = TRUE;
  1275. }
  1276. if( D3DSP_WRITEMASK_ALL != pDstParam->m_WriteMask )
  1277. {
  1278. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "tex* instructions must write all components." );
  1279. m_ErrorCount++;
  1280. bFoundDstError = TRUE;
  1281. }
  1282. switch( pDstParam->m_DstMod )
  1283. {
  1284. case D3DSPDM_NONE:
  1285. break;
  1286. case D3DSPDM_SATURATE:
  1287. // falling through
  1288. default:
  1289. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Instruction modifiers are not allowed for tex* instructions." );
  1290. m_ErrorCount++;
  1291. bFoundDstError = TRUE;
  1292. }
  1293. switch( pDstParam->m_DstShift )
  1294. {
  1295. case DSTSHIFT_NONE:
  1296. break;
  1297. default:
  1298. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Dest shift not allowed for tex* instructions." );
  1299. m_ErrorCount++;
  1300. bFoundDstError = TRUE;
  1301. }
  1302. }
  1303. else
  1304. {
  1305. switch( pDstParam->m_DstMod )
  1306. {
  1307. case D3DSPDM_NONE:
  1308. case D3DSPDM_SATURATE:
  1309. break;
  1310. default:
  1311. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Invalid dst modifier." );
  1312. m_ErrorCount++;
  1313. bFoundDstError = TRUE;
  1314. }
  1315. switch( pDstParam->m_DstShift )
  1316. {
  1317. case DSTSHIFT_NONE:
  1318. case DSTSHIFT_X2:
  1319. case DSTSHIFT_X4:
  1320. case DSTSHIFT_D2:
  1321. break;
  1322. default:
  1323. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Invalid dst shift." );
  1324. m_ErrorCount++;
  1325. bFoundDstError = TRUE;
  1326. }
  1327. }
  1328. if( (D3DSP_WRITEMASK_ALL != pDstParam->m_WriteMask)
  1329. && ((D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1 | D3DSP_WRITEMASK_2) != pDstParam->m_WriteMask )
  1330. && (D3DSP_WRITEMASK_3 != pDstParam->m_WriteMask ) )
  1331. {
  1332. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Dest write mask must be .rgb, .a, or .rgba (all)." );
  1333. m_ErrorCount++;
  1334. bFoundDstError = TRUE;
  1335. }
  1336. if( !bFoundDstError )
  1337. {
  1338. // Update register file to indicate write.
  1339. CRegisterFile* pRegFile = NULL;
  1340. switch( pDstParam->m_RegType )
  1341. {
  1342. case D3DSPR_TEMP: pRegFile = m_pTempRegFile; break;
  1343. case D3DSPR_TEXTURE: pRegFile = m_pTextureRegFile; break;
  1344. }
  1345. if( pRegFile )
  1346. {
  1347. if( pDstParam->m_WriteMask & D3DSP_WRITEMASK_0 )
  1348. pRegFile->m_pAccessHistory[0][RegNum].NewAccess(m_pCurrInst,TRUE);
  1349. if( pDstParam->m_WriteMask & D3DSP_WRITEMASK_1 )
  1350. pRegFile->m_pAccessHistory[1][RegNum].NewAccess(m_pCurrInst,TRUE);
  1351. if( pDstParam->m_WriteMask & D3DSP_WRITEMASK_2 )
  1352. pRegFile->m_pAccessHistory[2][RegNum].NewAccess(m_pCurrInst,TRUE);
  1353. if( pDstParam->m_WriteMask & D3DSP_WRITEMASK_3 )
  1354. pRegFile->m_pAccessHistory[3][RegNum].NewAccess(m_pCurrInst,TRUE);
  1355. }
  1356. }
  1357. }
  1358. return TRUE;
  1359. }
  1360. //-----------------------------------------------------------------------------
  1361. // CPShaderValidator10::Rule_ValidRegisterPortUsage
  1362. //
  1363. // ** Rule:
  1364. // Each register class (TEMP,TEXTURE,INPUT,CONST) may only appear as parameters
  1365. // in an individual instruction up to a maximum number of times.
  1366. //
  1367. // Multiple accesses to the same register number (in the same register class)
  1368. // only count as one access.
  1369. //
  1370. // ** When to call:
  1371. // Per instruction.
  1372. //
  1373. // ** Returns:
  1374. // Always TRUE.
  1375. //
  1376. //-----------------------------------------------------------------------------
  1377. BOOL CPShaderValidator10::Rule_ValidRegisterPortUsage()
  1378. {
  1379. UINT i, j;
  1380. UINT TempRegPortUsage[SHADER_INSTRUCTION_MAX_SRCPARAMS];
  1381. UINT InputRegPortUsage[SHADER_INSTRUCTION_MAX_SRCPARAMS];
  1382. UINT ConstRegPortUsage[SHADER_INSTRUCTION_MAX_SRCPARAMS];
  1383. UINT TextureRegPortUsage[SHADER_INSTRUCTION_MAX_SRCPARAMS];
  1384. UINT NumUniqueTempRegs = 0;
  1385. UINT NumUniqueInputRegs = 0;
  1386. UINT NumUniqueConstRegs = 0;
  1387. UINT NumUniqueTextureRegs = 0;
  1388. D3DSHADER_PARAM_REGISTER_TYPE RegType;
  1389. UINT RegNum;
  1390. static UINT s_TempRegPortUsageAcrossCoIssue[SHADER_INSTRUCTION_MAX_SRCPARAMS];
  1391. static UINT s_InputRegPortUsageAcrossCoIssue[SHADER_INSTRUCTION_MAX_SRCPARAMS];
  1392. static UINT s_ConstRegPortUsageAcrossCoIssue[SHADER_INSTRUCTION_MAX_SRCPARAMS];
  1393. static UINT s_TextureRegPortUsageAcrossCoIssue[SHADER_INSTRUCTION_MAX_SRCPARAMS];
  1394. static UINT s_NumUniqueTempRegsAcrossCoIssue;
  1395. static UINT s_NumUniqueInputRegsAcrossCoIssue;
  1396. static UINT s_NumUniqueConstRegsAcrossCoIssue;
  1397. static UINT s_NumUniqueTextureRegsAcrossCoIssue;
  1398. if( NULL == m_pCurrInst->m_pPrevInst ) // First instruction - initialize static vars
  1399. {
  1400. s_NumUniqueTempRegsAcrossCoIssue = 0;
  1401. s_NumUniqueInputRegsAcrossCoIssue = 0;
  1402. s_NumUniqueConstRegsAcrossCoIssue = 0;
  1403. s_NumUniqueTextureRegsAcrossCoIssue = 0;
  1404. }
  1405. for( i = 0; i < m_pCurrInst->m_SrcParamCount; i++ )
  1406. {
  1407. UINT* pRegPortUsage = NULL;
  1408. UINT* pNumUniqueRegs = NULL;
  1409. RegType = m_pCurrInst->m_SrcParam[i].m_RegType;
  1410. RegNum = m_pCurrInst->m_SrcParam[i].m_RegNum;
  1411. switch( RegType )
  1412. {
  1413. case D3DSPR_TEMP:
  1414. pRegPortUsage = TempRegPortUsage;
  1415. pNumUniqueRegs = &NumUniqueTempRegs;
  1416. break;
  1417. case D3DSPR_INPUT:
  1418. pRegPortUsage = InputRegPortUsage;
  1419. pNumUniqueRegs = &NumUniqueInputRegs;
  1420. break;
  1421. case D3DSPR_CONST:
  1422. pRegPortUsage = ConstRegPortUsage;
  1423. pNumUniqueRegs = &NumUniqueConstRegs;
  1424. break;
  1425. case D3DSPR_TEXTURE:
  1426. pRegPortUsage = TextureRegPortUsage;
  1427. pNumUniqueRegs = &NumUniqueTextureRegs;
  1428. break;
  1429. }
  1430. if( !pRegPortUsage ) continue;
  1431. BOOL bRegAlreadyAccessed = FALSE;
  1432. for( j = 0; j < *pNumUniqueRegs; j++ )
  1433. {
  1434. if( pRegPortUsage[j] == RegNum )
  1435. {
  1436. bRegAlreadyAccessed = TRUE;
  1437. break;
  1438. }
  1439. }
  1440. if( !bRegAlreadyAccessed )
  1441. {
  1442. pRegPortUsage[*pNumUniqueRegs] = RegNum;
  1443. (*pNumUniqueRegs)++;
  1444. }
  1445. }
  1446. if( NumUniqueTempRegs > m_pTempRegFile->GetNumReadPorts() )
  1447. {
  1448. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "%d different temp registers (r#) read by instruction. Max. different temp registers readable per instruction is %d.",
  1449. NumUniqueTempRegs, m_pTempRegFile->GetNumReadPorts());
  1450. m_ErrorCount++;
  1451. }
  1452. if( NumUniqueInputRegs > m_pInputRegFile->GetNumReadPorts() )
  1453. {
  1454. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "%d different input registers (v#) read by instruction. Max. different input registers readable per instruction is %d.",
  1455. NumUniqueInputRegs, m_pInputRegFile->GetNumReadPorts());
  1456. m_ErrorCount++;
  1457. }
  1458. if( NumUniqueConstRegs > m_pConstRegFile->GetNumReadPorts() )
  1459. {
  1460. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "%d different constant registers (c#) read by instruction. Max. different constant registers readable per instruction is %d.",
  1461. NumUniqueConstRegs, m_pConstRegFile->GetNumReadPorts());
  1462. m_ErrorCount++;
  1463. }
  1464. if( NumUniqueTextureRegs > m_pTextureRegFile->GetNumReadPorts() )
  1465. {
  1466. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "%d different texture registers (t#) read by instruction. Max. different texture registers readable per instruction is %d.",
  1467. NumUniqueTextureRegs, m_pTextureRegFile->GetNumReadPorts());
  1468. m_ErrorCount++;
  1469. }
  1470. // Read port limit for different register numbers of any one register type across co-issued instructions is MAX_READPORTS_ACROSS_COISSUE total.
  1471. if( _CURR_PS_INST->m_bCoIssue && _PREV_PS_INST && !(_PREV_PS_INST->m_bCoIssue)) // second clause is just a simple sanity check -> co-issue only involved 2 instructions.
  1472. {
  1473. for( i = 0; i < m_pCurrInst->m_SrcParamCount; i++ )
  1474. {
  1475. UINT* pRegPortUsageAcrossCoIssue = NULL;
  1476. UINT* pNumUniqueRegsAcrossCoIssue = NULL;
  1477. RegType = m_pCurrInst->m_SrcParam[i].m_RegType;
  1478. RegNum = m_pCurrInst->m_SrcParam[i].m_RegNum;
  1479. switch( RegType )
  1480. {
  1481. case D3DSPR_TEMP:
  1482. pRegPortUsageAcrossCoIssue = s_TempRegPortUsageAcrossCoIssue;
  1483. pNumUniqueRegsAcrossCoIssue = &s_NumUniqueTempRegsAcrossCoIssue;
  1484. break;
  1485. case D3DSPR_INPUT:
  1486. pRegPortUsageAcrossCoIssue = s_InputRegPortUsageAcrossCoIssue;
  1487. pNumUniqueRegsAcrossCoIssue = &s_NumUniqueInputRegsAcrossCoIssue;
  1488. break;
  1489. case D3DSPR_CONST:
  1490. pRegPortUsageAcrossCoIssue = s_ConstRegPortUsageAcrossCoIssue;
  1491. pNumUniqueRegsAcrossCoIssue = &s_NumUniqueConstRegsAcrossCoIssue;
  1492. break;
  1493. case D3DSPR_TEXTURE:
  1494. pRegPortUsageAcrossCoIssue = s_TextureRegPortUsageAcrossCoIssue;
  1495. pNumUniqueRegsAcrossCoIssue = &s_NumUniqueTextureRegsAcrossCoIssue;
  1496. break;
  1497. }
  1498. if( !pRegPortUsageAcrossCoIssue ) continue;
  1499. BOOL bRegAlreadyAccessed = FALSE;
  1500. for( j = 0; j < *pNumUniqueRegsAcrossCoIssue; j++ )
  1501. {
  1502. if( pRegPortUsageAcrossCoIssue[j] == RegNum )
  1503. {
  1504. bRegAlreadyAccessed = TRUE;
  1505. break;
  1506. }
  1507. }
  1508. if( !bRegAlreadyAccessed )
  1509. {
  1510. pRegPortUsageAcrossCoIssue[*pNumUniqueRegsAcrossCoIssue] = RegNum;
  1511. (*pNumUniqueRegsAcrossCoIssue)++;
  1512. }
  1513. }
  1514. #define MAX_READPORTS_ACROSS_COISSUE 3
  1515. if( s_NumUniqueTempRegsAcrossCoIssue > MAX_READPORTS_ACROSS_COISSUE )
  1516. {
  1517. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst,
  1518. "%d different temp registers (r#) read over 2 co-issued instructions. "\
  1519. "Max. different register numbers from any one register type readable across co-issued instructions is %d.",
  1520. s_NumUniqueTempRegsAcrossCoIssue, MAX_READPORTS_ACROSS_COISSUE);
  1521. m_ErrorCount++;
  1522. }
  1523. if( s_NumUniqueInputRegsAcrossCoIssue > MAX_READPORTS_ACROSS_COISSUE )
  1524. {
  1525. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst,
  1526. "%d different input registers (v#) read over 2 co-issued instructions. "\
  1527. "Max. different register numbers from any one register type readable across co-issued instructions is %d.",
  1528. s_NumUniqueInputRegsAcrossCoIssue, MAX_READPORTS_ACROSS_COISSUE);
  1529. m_ErrorCount++;
  1530. }
  1531. if( s_NumUniqueConstRegsAcrossCoIssue > MAX_READPORTS_ACROSS_COISSUE )
  1532. {
  1533. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst,
  1534. "%d different constant registers (c#) read over 2 co-issued instructions. "\
  1535. "Max. different register numbers from any one register type readable across co-issued instructions is %d.",
  1536. s_NumUniqueConstRegsAcrossCoIssue, MAX_READPORTS_ACROSS_COISSUE);
  1537. m_ErrorCount++;
  1538. }
  1539. if( s_NumUniqueTextureRegsAcrossCoIssue > MAX_READPORTS_ACROSS_COISSUE )
  1540. {
  1541. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst,
  1542. "%d different texture registers (t#) read over 2 co-issued instructions. "\
  1543. "Max. different register numbers from any one register type readable across co-issued instructions is %d.",
  1544. s_NumUniqueTextureRegsAcrossCoIssue, MAX_READPORTS_ACROSS_COISSUE);
  1545. m_ErrorCount++;
  1546. }
  1547. }
  1548. if( !_CURR_PS_INST->m_bCoIssue )
  1549. {
  1550. // Copy all state to static vars so that in case next instruction is co-issued with this one,
  1551. // cross-coissue read port limit of 3 can be enforced.
  1552. memcpy(&s_TempRegPortUsageAcrossCoIssue,&TempRegPortUsage,NumUniqueTempRegs*sizeof(UINT));
  1553. memcpy(&s_InputRegPortUsageAcrossCoIssue,&InputRegPortUsage,NumUniqueInputRegs*sizeof(UINT));
  1554. memcpy(&s_ConstRegPortUsageAcrossCoIssue,&ConstRegPortUsage,NumUniqueConstRegs*sizeof(UINT));
  1555. memcpy(&s_TextureRegPortUsageAcrossCoIssue,&TextureRegPortUsage,NumUniqueTextureRegs*sizeof(UINT));
  1556. s_NumUniqueTempRegsAcrossCoIssue = NumUniqueTempRegs;
  1557. s_NumUniqueInputRegsAcrossCoIssue = NumUniqueInputRegs;
  1558. s_NumUniqueConstRegsAcrossCoIssue = NumUniqueConstRegs;
  1559. s_NumUniqueTextureRegsAcrossCoIssue = NumUniqueTextureRegs;
  1560. }
  1561. else
  1562. {
  1563. // reset counts because the next instruction cannot be co-issued with this one.
  1564. s_NumUniqueTempRegsAcrossCoIssue = 0;
  1565. s_NumUniqueInputRegsAcrossCoIssue = 0;
  1566. s_NumUniqueConstRegsAcrossCoIssue = 0;
  1567. s_NumUniqueTextureRegsAcrossCoIssue = 0;
  1568. }
  1569. return TRUE;
  1570. }
  1571. //-----------------------------------------------------------------------------
  1572. // CPShaderValidator10::Rule_TexRegsDeclaredInOrder
  1573. //
  1574. // ** Rule:
  1575. // Tex registers must declared in increasing order.
  1576. // ex. invalid sequence: tex t0
  1577. // tex t3
  1578. // tex t1
  1579. //
  1580. // another invalid seq: tex t0
  1581. // tex t1
  1582. // texm3x2pad t1, t0 (t1 already declared)
  1583. // texm3x2pad t2, t0
  1584. //
  1585. // valid sequence: tex t0
  1586. // tex t1
  1587. // tex t3 (note missing t2.. OK)
  1588. //
  1589. // ** When to call:
  1590. // Per instruction.
  1591. //
  1592. // ** Returns:
  1593. // Always TRUE.
  1594. //
  1595. //-----------------------------------------------------------------------------
  1596. BOOL CPShaderValidator10::Rule_TexRegsDeclaredInOrder()
  1597. {
  1598. static DWORD s_TexOpRegDeclOrder; // bit flags
  1599. if( NULL == m_pCurrInst->m_pPrevInst ) // First instruction - initialize static vars
  1600. {
  1601. s_TexOpRegDeclOrder = 0;
  1602. }
  1603. if( !_CURR_PS_INST->m_bTexOp )
  1604. return TRUE;
  1605. DWORD RegNum = m_pCurrInst->m_DstParam.m_RegNum;
  1606. if( (D3DSPR_TEXTURE != m_pCurrInst->m_DstParam.m_RegType) ||
  1607. (RegNum > m_pTextureRegFile->GetNumRegs()) )
  1608. {
  1609. return TRUE;
  1610. }
  1611. DWORD RegMask = 1 << m_pCurrInst->m_DstParam.m_RegNum;
  1612. if( RegMask & s_TexOpRegDeclOrder)
  1613. {
  1614. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Tex register t%d already declared.",
  1615. RegNum);
  1616. m_ErrorCount++;
  1617. }
  1618. else if( s_TexOpRegDeclOrder > RegMask )
  1619. {
  1620. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "t# registers must appear in sequence (i.e. t0 before t2 OK, but t1 before t0 not valid)." );
  1621. m_ErrorCount++;
  1622. }
  1623. s_TexOpRegDeclOrder |= (1 << m_pCurrInst->m_DstParam.m_RegNum);
  1624. return TRUE;
  1625. }
  1626. //-----------------------------------------------------------------------------
  1627. // CPShaderValidator10::Rule_TexOpAfterNonTexOp
  1628. //
  1629. // ** Rule:
  1630. // Tex ops (see IsTexOp() for which instructions are considered tex ops)
  1631. // must appear before any other instruction, with the exception of DEF or NOP.
  1632. //
  1633. // ** When to call:
  1634. // Per instruction.
  1635. //
  1636. // ** Returns:
  1637. // Always TRUE.
  1638. //
  1639. //-----------------------------------------------------------------------------
  1640. BOOL CPShaderValidator10::Rule_TexOpAfterNonTexOp()
  1641. {
  1642. static BOOL s_bFoundNonTexOp;
  1643. static BOOL s_bRuleDisabled;
  1644. if( NULL == m_pCurrInst->m_pPrevInst ) // First instruction - initialize static vars
  1645. {
  1646. s_bFoundNonTexOp = FALSE;
  1647. s_bRuleDisabled = FALSE;
  1648. }
  1649. if( s_bRuleDisabled )
  1650. return TRUE;
  1651. // Execute the rule.
  1652. if( !(_CURR_PS_INST->m_bTexOp)
  1653. && m_pCurrInst->m_Type != D3DSIO_NOP
  1654. && m_pCurrInst->m_Type != D3DSIO_DEF)
  1655. {
  1656. s_bFoundNonTexOp = TRUE;
  1657. return TRUE;
  1658. }
  1659. if( _CURR_PS_INST->m_bTexOp && s_bFoundNonTexOp )
  1660. {
  1661. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Cannot use tex* instruction after non-tex* instruction." );
  1662. m_ErrorCount++;
  1663. s_bRuleDisabled = TRUE;
  1664. }
  1665. return TRUE;
  1666. }
  1667. //-----------------------------------------------------------------------------
  1668. // CPShaderValidator10::Rule_ValidTEXM3xSequence
  1669. //
  1670. // ** Rule:
  1671. // TEXM3x* instructions, if present in the pixel shader, must appear in
  1672. // any of the follwing sequences:
  1673. //
  1674. // 1) texm3x2pad
  1675. // 2) texm3x2tex / texdepth
  1676. //
  1677. // or 1) texm3x3pad
  1678. // 2) texm3x3pad
  1679. // 3) texm3x3tex
  1680. //
  1681. // or 1) texm3x3pad
  1682. // 2) texm3x3pad
  1683. // 3) texm3x3spec / texm3x3vspec
  1684. //
  1685. // ** When to call:
  1686. // Per instruction AND after all instructions have been seen.
  1687. //
  1688. // ** Returns:
  1689. // Always TRUE.
  1690. //
  1691. //-----------------------------------------------------------------------------
  1692. BOOL CPShaderValidator10::Rule_ValidTEXM3xSequence()
  1693. {
  1694. static UINT s_TexMSequence;
  1695. static UINT s_LastInst;
  1696. if( NULL == m_pCurrInst )
  1697. {
  1698. return TRUE;
  1699. }
  1700. if( NULL == m_pCurrInst->m_pPrevInst ) // First instruction - initialize static vars
  1701. {
  1702. s_TexMSequence = 0;
  1703. s_LastInst = D3DSIO_NOP;
  1704. }
  1705. if( m_bSeenAllInstructions )
  1706. {
  1707. if( s_TexMSequence )
  1708. {
  1709. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Incomplete texm* sequence." );
  1710. m_ErrorCount++;
  1711. }
  1712. return TRUE;
  1713. }
  1714. // Execute the rule.
  1715. if( _CURR_PS_INST->m_bTexMOp )
  1716. {
  1717. switch( m_pCurrInst->m_Type )
  1718. {
  1719. case D3DSIO_TEXM3x2PAD:
  1720. if( s_TexMSequence ) goto _TexMSeqInvalid;
  1721. m_TexMBaseDstReg = m_pCurrInst->m_DstParam.m_RegNum;
  1722. s_TexMSequence = 1;
  1723. break;
  1724. case D3DSIO_TEXM3x2TEX:
  1725. case D3DSIO_TEXM3x2DEPTH:
  1726. // must be one 3x2PAD previous
  1727. if ( (s_TexMSequence != 1) ||
  1728. (s_LastInst != D3DSIO_TEXM3x2PAD) ) goto _TexMSeqInvalid;
  1729. s_TexMSequence = 0;
  1730. break;
  1731. case D3DSIO_TEXM3x3PAD:
  1732. if (s_TexMSequence)
  1733. {
  1734. // if in sequence, then must be one 3x3PAD previous
  1735. if ( (s_TexMSequence != 1) ||
  1736. (s_LastInst != D3DSIO_TEXM3x3PAD) ) goto _TexMSeqInvalid;
  1737. s_TexMSequence = 2;
  1738. break;
  1739. }
  1740. m_TexMBaseDstReg = m_pCurrInst->m_DstParam.m_RegNum;
  1741. s_TexMSequence = 1;
  1742. break;
  1743. case D3DSIO_TEXM3x3:
  1744. case D3DSIO_TEXM3x3TEX:
  1745. case D3DSIO_TEXM3x3SPEC:
  1746. case D3DSIO_TEXM3x3VSPEC:
  1747. // must be two 3x3PAD previous
  1748. if ( (s_TexMSequence != 2) ||
  1749. (s_LastInst != D3DSIO_TEXM3x3PAD) ) goto _TexMSeqInvalid;
  1750. s_TexMSequence = 0;
  1751. break;
  1752. default:
  1753. break;
  1754. }
  1755. goto _TexMSeqOK;
  1756. _TexMSeqInvalid:
  1757. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Invalid texm* sequence." );
  1758. m_ErrorCount++;
  1759. }
  1760. _TexMSeqOK:
  1761. s_LastInst = m_pCurrInst->m_Type;
  1762. return TRUE;
  1763. }
  1764. //-----------------------------------------------------------------------------
  1765. // CPShaderValidator10::Rule_ValidTEXM3xRegisterNumbers
  1766. //
  1767. // ** Rule:
  1768. // If instruction is a TEXM3x*, register numbers must be as follows:
  1769. //
  1770. // 1) texm3x2pad / texm3x2depth t(x), t(y)
  1771. // 2) texm3x2tex t(x+1), t(y)
  1772. //
  1773. // 1) texm3x3pad t(x), t(y)
  1774. // 2) texm3x3pad t(x+1), t(y)
  1775. // 3) texm3x3tex/texm3x3 t(x+2), t(y)
  1776. //
  1777. // 1) texm3x3pad t(x), t(y)
  1778. // 2) texm3x3pad t(x+1), t(y)
  1779. // 3) texm3x3spec t(x+2), t(y), c#
  1780. //
  1781. // 1) texm3x3pad t(x), t(y)
  1782. // 2) texm3x3pad t(x+1), t(y)
  1783. // 3) texm3x3vspec t(x+2), t(y)
  1784. //
  1785. // ** When to call:
  1786. // Per instruction.
  1787. //
  1788. // ** Returns:
  1789. // Always TRUE.
  1790. //
  1791. //-----------------------------------------------------------------------------
  1792. BOOL CPShaderValidator10::Rule_ValidTEXM3xRegisterNumbers()
  1793. {
  1794. #define PREV_INST_TYPE(_INST) \
  1795. ((_INST && _INST->m_pPrevInst) ? _INST->m_pPrevInst->m_Type : D3DSIO_NOP)
  1796. #define PREV_INST_SRC0_REGNUM(_INST) \
  1797. ((_INST && _INST->m_pPrevInst) ? _INST->m_pPrevInst->m_SrcParam[0].m_RegNum : -1)
  1798. if( _CURR_PS_INST->m_bTexMOp )
  1799. {
  1800. DWORD DstParamR = m_pCurrInst->m_DstParam.m_RegNum;
  1801. DWORD SrcParam0R = m_pCurrInst->m_SrcParam[0].m_RegNum;
  1802. switch (m_pCurrInst->m_Type)
  1803. {
  1804. case D3DSIO_TEXM3x2PAD:
  1805. break;
  1806. case D3DSIO_TEXM3x2TEX:
  1807. case D3DSIO_TEXM3x2DEPTH:
  1808. if ( DstParamR != (m_TexMBaseDstReg + 1) )
  1809. goto _TexMRegInvalid;
  1810. if( SrcParam0R != PREV_INST_SRC0_REGNUM(m_pCurrInst) )
  1811. goto _TexMRegInvalid;
  1812. break;
  1813. case D3DSIO_TEXM3x3PAD:
  1814. {
  1815. if ( D3DSIO_TEXM3x3PAD == PREV_INST_TYPE(m_pCurrInst) &&
  1816. (DstParamR != (m_TexMBaseDstReg + 1) ) )
  1817. goto _TexMRegInvalid;
  1818. if ( D3DSIO_TEXM3x3PAD == PREV_INST_TYPE(m_pCurrInst) &&
  1819. (SrcParam0R != PREV_INST_SRC0_REGNUM(m_pCurrInst)) )
  1820. goto _TexMRegInvalid;
  1821. break;
  1822. }
  1823. case D3DSIO_TEXM3x3SPEC:
  1824. // SPEC requires second src param to be from const regs
  1825. if ( m_pCurrInst->m_SrcParam[1].m_RegType != D3DSPR_CONST )
  1826. goto _TexMRegInvalid;
  1827. // fall through
  1828. case D3DSIO_TEXM3x3:
  1829. case D3DSIO_TEXM3x3TEX:
  1830. case D3DSIO_TEXM3x3VSPEC:
  1831. if ( DstParamR != (m_TexMBaseDstReg + 2) )
  1832. goto _TexMRegInvalid;
  1833. if( SrcParam0R != PREV_INST_SRC0_REGNUM(m_pCurrInst) )
  1834. goto _TexMRegInvalid;
  1835. break;
  1836. default:
  1837. break;
  1838. }
  1839. goto _TexMRegOK;
  1840. _TexMRegInvalid:
  1841. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Invalid texm* register." );
  1842. m_ErrorCount++;
  1843. }
  1844. _TexMRegOK:
  1845. return TRUE;
  1846. }
  1847. //-----------------------------------------------------------------------------
  1848. // CPShaderValidator10::Rule_ValidCNDInstruction
  1849. //
  1850. // ** Rule:
  1851. // First source for cnd instruction must be 'r0.a' (exactly).
  1852. // i.e. cnd r1, r0.a, t0, t1
  1853. //
  1854. // ** When to call:
  1855. // Per instruction.
  1856. //
  1857. // ** Returns:
  1858. // Always TRUE.
  1859. //
  1860. //-----------------------------------------------------------------------------
  1861. BOOL CPShaderValidator10::Rule_ValidCNDInstruction()
  1862. {
  1863. if( D3DSIO_CND == m_pCurrInst->m_Type )
  1864. {
  1865. SRCPARAM Src0 = m_pCurrInst->m_SrcParam[0];
  1866. if( Src0.m_bParamUsed &&
  1867. D3DSPR_TEMP == Src0.m_RegType &&
  1868. 0 == Src0.m_RegNum &&
  1869. D3DSP_REPLICATEALPHA == Src0.m_SwizzleShift &&
  1870. D3DSPSM_NONE == Src0.m_SrcMod )
  1871. {
  1872. return TRUE; // Src 0 is r0.a
  1873. }
  1874. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "First source for cnd instruction must be 'r0.a'." );
  1875. m_ErrorCount++;
  1876. }
  1877. return TRUE;
  1878. }
  1879. //-----------------------------------------------------------------------------
  1880. // CPShaderValidator10::Rule_ValidCMPInstruction
  1881. //
  1882. // ** Rule:
  1883. // There may be at most 3 cmp instructions per shader.
  1884. // (only executed for ps.1.2)
  1885. //
  1886. // ** When to call:
  1887. // Per instruction.
  1888. //
  1889. // ** Returns:
  1890. // Always TRUE.
  1891. //
  1892. //-----------------------------------------------------------------------------
  1893. BOOL CPShaderValidator10::Rule_ValidCMPInstruction()
  1894. {
  1895. static UINT s_cCMPInstCount;
  1896. if( NULL == m_pCurrInst->m_pPrevInst ) // First instruction - initialize static vars
  1897. {
  1898. s_cCMPInstCount = 0;
  1899. }
  1900. if( D3DSIO_CMP == m_pCurrInst->m_Type && D3DPS_VERSION(1,3) >= m_Version)
  1901. {
  1902. s_cCMPInstCount++;
  1903. if( 3 < s_cCMPInstCount )
  1904. {
  1905. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Maximum of 3 cmp instructions allowed." );
  1906. m_ErrorCount++;
  1907. }
  1908. }
  1909. return TRUE;
  1910. }
  1911. //-----------------------------------------------------------------------------
  1912. // CPShaderValidator10::Rule_ValidLRPInstruction
  1913. //
  1914. // ** Rule:
  1915. // The only valid source modifier for the src0 operand for LRP is complement
  1916. // (1-reg)
  1917. // i.e. lrp r1, 1-r0, t0, t1
  1918. //
  1919. // If there was a previous writer to src0, then it must have applied
  1920. // the _sat destination modifier.
  1921. //
  1922. // ** When to call:
  1923. // Per instruction.
  1924. //
  1925. // ** Returns:
  1926. // Always TRUE.
  1927. //
  1928. //-----------------------------------------------------------------------------
  1929. BOOL CPShaderValidator10::Rule_ValidLRPInstruction()
  1930. {
  1931. if( D3DSIO_LRP == m_pCurrInst->m_Type )
  1932. {
  1933. SRCPARAM Src0 = m_pCurrInst->m_SrcParam[0];
  1934. if( !Src0.m_bParamUsed )
  1935. return TRUE;
  1936. switch( Src0.m_SrcMod )
  1937. {
  1938. case D3DSPSM_NONE:
  1939. case D3DSPSM_COMP:
  1940. break;
  1941. default:
  1942. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "The only valid modifiers for the first source parameter of lrp are: reg (no mod) or 1-reg (complement)." );
  1943. m_ErrorCount++;
  1944. }
  1945. #ifdef SHOW_VALIDATION_WARNINGS
  1946. UINT RegNum = Src0.m_RegNum;
  1947. DWORD AffectedComponents = 0;
  1948. if( m_bSrcParamError[0] )
  1949. return TRUE;
  1950. for( UINT Component = 0; Component < 4; Component++ )
  1951. {
  1952. if( !(COMPONENT_MASKS[Component] & Src0.m_ComponentReadMask) )
  1953. continue;
  1954. CAccessHistoryNode* pMostRecentWriter = NULL;
  1955. switch( Src0.m_RegType )
  1956. {
  1957. case D3DSPR_TEXTURE:
  1958. pMostRecentWriter = m_pTextureRegFile->m_pAccessHistory[Component][RegNum].m_pMostRecentWriter;
  1959. break;
  1960. case D3DSPR_INPUT:
  1961. pMostRecentWriter = m_pInputRegFile->m_pAccessHistory[Component][RegNum].m_pMostRecentWriter;
  1962. break;
  1963. case D3DSPR_TEMP:
  1964. pMostRecentWriter = m_pTempRegFile->m_pAccessHistory[Component][RegNum].m_pMostRecentWriter;
  1965. break;
  1966. case D3DSPR_CONST:
  1967. pMostRecentWriter = m_pConstRegFile->m_pAccessHistory[Component][RegNum].m_pMostRecentWriter;
  1968. break;
  1969. }
  1970. // The previous writer may be the current instruction.
  1971. // If so, go back one step (the previous writer before the current instruction).
  1972. if( pMostRecentWriter && pMostRecentWriter->m_pInst &&
  1973. pMostRecentWriter->m_pInst == m_pCurrInst )
  1974. {
  1975. pMostRecentWriter = pMostRecentWriter->m_pPreviousWriter;
  1976. }
  1977. if( pMostRecentWriter &&
  1978. pMostRecentWriter->m_pInst &&
  1979. !((CPSInstruction*)pMostRecentWriter->m_pInst)->m_bTexOp &&
  1980. (D3DSPDM_SATURATE != pMostRecentWriter->m_pInst->m_DstParam.m_DstMod )
  1981. )
  1982. {
  1983. AffectedComponents |= COMPONENT_MASKS[Component];
  1984. }
  1985. }
  1986. if( AffectedComponents )
  1987. {
  1988. // A warning.
  1989. Spew( SPEW_INSTRUCTION_WARNING, m_pCurrInst,
  1990. "Previous writer to the first source register of lrp instruction "
  1991. "should apply the saturate destination modifier. This ensures consistent "
  1992. "behaviour across different hardware. "
  1993. "Affected components(*) of first source register: %s",
  1994. MakeAffectedComponentsText(AffectedComponents,TRUE,FALSE));
  1995. }
  1996. #endif // SHOW_VALIDATION_WARNINGS
  1997. }
  1998. return TRUE;
  1999. }
  2000. //-----------------------------------------------------------------------------
  2001. // CPShaderValidator10::Rule_ValidDEFInstruction
  2002. //
  2003. // ** Rule:
  2004. // For the DEF instruction, make sure the dest parameter is a valid constant,
  2005. // and it has no modifiers.
  2006. //
  2007. // NOTE that we are pretending this instruction only has a dst parameter.
  2008. // We skipped over the 4 source parameters since they are immediate floats,
  2009. // for which there is nothing that can be checked.
  2010. //
  2011. // ** When to call:
  2012. // Per instruction.
  2013. //
  2014. // ** Returns:
  2015. // Always TRUE.
  2016. //
  2017. //-----------------------------------------------------------------------------
  2018. BOOL CPShaderValidator10::Rule_ValidDEFInstruction()
  2019. {
  2020. static BOOL s_bDEFInstructionAllowed;
  2021. if( NULL == m_pCurrInst->m_pPrevInst ) // First instruction - initialize static vars
  2022. {
  2023. s_bDEFInstructionAllowed = TRUE;
  2024. }
  2025. if( D3DSIO_COMMENT != m_pCurrInst->m_Type &&
  2026. D3DSIO_DEF != m_pCurrInst->m_Type )
  2027. {
  2028. s_bDEFInstructionAllowed = FALSE;
  2029. }
  2030. else if( D3DSIO_DEF == m_pCurrInst->m_Type )
  2031. {
  2032. if( !s_bDEFInstructionAllowed )
  2033. {
  2034. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Const declaration (def) must appear before other instructions." );
  2035. m_ErrorCount++;
  2036. }
  2037. DSTPARAM* pDstParam = &m_pCurrInst->m_DstParam;
  2038. if( D3DSP_WRITEMASK_ALL != pDstParam->m_WriteMask ||
  2039. D3DSPDM_NONE != pDstParam->m_DstMod ||
  2040. DSTSHIFT_NONE != pDstParam->m_DstShift ||
  2041. D3DSPR_CONST != pDstParam->m_RegType
  2042. )
  2043. {
  2044. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Destination for def instruction must be of the form c# (# = reg number, no modifiers)." );
  2045. m_ErrorCount++;
  2046. }
  2047. // Check that the register number is in bounds
  2048. if( D3DSPR_CONST == pDstParam->m_RegType &&
  2049. pDstParam->m_RegNum >= m_pConstRegFile->GetNumRegs() )
  2050. {
  2051. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Invalid const register num: %d. Max allowed is %d.",
  2052. pDstParam->m_RegNum,m_pConstRegFile->GetNumRegs() - 1);
  2053. m_ErrorCount++;
  2054. }
  2055. }
  2056. return TRUE;
  2057. }
  2058. //-----------------------------------------------------------------------------
  2059. // CPShaderValidator10::Rule_ValidDP3Instruction
  2060. //
  2061. // ** Rule:
  2062. // The .a result write mask is not valid for the DP3 instruction.
  2063. // (version <= 1.2)
  2064. //
  2065. // ** When to call:
  2066. // Per instruction.
  2067. //
  2068. // ** Returns:
  2069. // Always TRUE.
  2070. //
  2071. //-----------------------------------------------------------------------------
  2072. BOOL CPShaderValidator10::Rule_ValidDP3Instruction()
  2073. {
  2074. if( D3DSIO_DP3 == m_pCurrInst->m_Type &&
  2075. D3DPS_VERSION(1,3) >= m_Version )
  2076. {
  2077. if( (D3DSP_WRITEMASK_ALL != m_pCurrInst->m_DstParam.m_WriteMask)
  2078. && ((D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1 | D3DSP_WRITEMASK_2) != m_pCurrInst->m_DstParam.m_WriteMask ) )
  2079. {
  2080. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Dest write mask must be .rgb, or .rgba (all) for dp3." );
  2081. m_ErrorCount++;
  2082. }
  2083. }
  2084. return TRUE;
  2085. }
  2086. //-----------------------------------------------------------------------------
  2087. // CPShaderValidator10::Rule_ValidDP4Instruction
  2088. //
  2089. // ** Rule:
  2090. // There may be at most 4 DP4 instructions per shader.
  2091. // (only executed for ps.1.2)
  2092. //
  2093. // ** When to call:
  2094. // Per instruction.
  2095. //
  2096. // ** Returns:
  2097. // Always TRUE.
  2098. //
  2099. //-----------------------------------------------------------------------------
  2100. BOOL CPShaderValidator10::Rule_ValidDP4Instruction()
  2101. {
  2102. static UINT s_cDP4InstCount;
  2103. if( NULL == m_pCurrInst->m_pPrevInst ) // First instruction - initialize static vars
  2104. {
  2105. s_cDP4InstCount = 0;
  2106. }
  2107. if( D3DSIO_DP4 == m_pCurrInst->m_Type && D3DPS_VERSION(1,3) >= m_Version )
  2108. {
  2109. s_cDP4InstCount++;
  2110. if( 4 < s_cDP4InstCount )
  2111. {
  2112. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Maximum of 4 dp4 instructions allowed." );
  2113. m_ErrorCount++;
  2114. }
  2115. }
  2116. return TRUE;
  2117. }
  2118. //-----------------------------------------------------------------------------
  2119. // CPShaderValidator10::Rule_ValidInstructionPairing
  2120. //
  2121. // ** Rule:
  2122. // - If an instruction is co-issued with another instruction,
  2123. // make sure that both do not write to any of RGB at the same time,
  2124. // and that neither instruction individually writes to all of RGBA.
  2125. //
  2126. // - Co-issue can only involve 2 instructions,
  2127. // so consecutive instructions cannot have the "+" prefix (D3DSI_COISSUE).
  2128. //
  2129. // - Co-issue of instructions only applies to pixel blend instructions (non tex-ops).
  2130. //
  2131. // - The first color blend instruction cannot have "+" (D3DSI_COISSUE) set either.
  2132. //
  2133. // - NOP may not be used in a co-issue pair.
  2134. //
  2135. // - DP4 may not be used in a co-issue pair.
  2136. //
  2137. // - DP3 (dot product) always uses the color/vector pipeline (even if it is not writing
  2138. // to color components). Thus:
  2139. // - An instruction co-issued with a dot-product can only write to alpha.
  2140. // - A dot-product that writes to alpha cannot be co-issued.
  2141. // - Two dot-products cannot be co-issued.
  2142. //
  2143. // - For version <= 1.0, coissued instructions must write to the same register.
  2144. //
  2145. // ------------------
  2146. // examples:
  2147. //
  2148. // valid pair: mov r0.a, c0
  2149. // +add r1.rgb, v1, c1 (note dst reg #'s can be different)
  2150. //
  2151. // another valid pair: mov r0.a, c0
  2152. // +add r0.rgb, v1, c1
  2153. //
  2154. // another valid pair: dp3 r0.rgb, t1, v1
  2155. // +mul r0.a, t0, v0
  2156. //
  2157. // another valid pair: mov r0.a, c0
  2158. // +add r0.a, t0, t1
  2159. //
  2160. // invalid pair: mov r0.rgb, c0
  2161. // +add r0, t0, t1 (note the dst writes to rgba)
  2162. //
  2163. // another invalid pair: mov r1.rgb, c1
  2164. // +dp3 r0.a, t0, t1 (dp3 is using up color/vector pipe)
  2165. //
  2166. // ** When to call:
  2167. // Per instruction.
  2168. //
  2169. // ** Returns:
  2170. // Always TRUE.
  2171. //
  2172. //-----------------------------------------------------------------------------
  2173. BOOL CPShaderValidator10::Rule_ValidInstructionPairing()
  2174. {
  2175. static BOOL s_bSeenNonTexOp;
  2176. if( NULL == m_pCurrInst->m_pPrevInst ) // First instruction - initialize static vars
  2177. {
  2178. s_bSeenNonTexOp = FALSE;
  2179. }
  2180. if( !s_bSeenNonTexOp && !_CURR_PS_INST->m_bTexOp )
  2181. {
  2182. // first non-tex op. this cannot have co-issue set.
  2183. if( _CURR_PS_INST->m_bCoIssue )
  2184. {
  2185. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst,
  2186. "First arithmetic instruction cannot have co-issue ('+') set; there is no previous arithmetic instruction to pair with.");
  2187. m_ErrorCount++;
  2188. }
  2189. s_bSeenNonTexOp = TRUE;
  2190. }
  2191. if( _CURR_PS_INST->m_bTexOp && _CURR_PS_INST->m_bCoIssue )
  2192. {
  2193. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst,
  2194. "Cannot set co-issue ('+') on a texture instruction. Co-issue only applies to arithmetic instructions." );
  2195. m_ErrorCount++;
  2196. }
  2197. if( _CURR_PS_INST->m_bCoIssue && m_pCurrInst->m_pPrevInst &&
  2198. _PREV_PS_INST->m_bCoIssue )
  2199. {
  2200. // consecutive instructions cannot have co-issue set.
  2201. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Cannot set co-issue ('+') on consecutive instructions." );
  2202. m_ErrorCount++;
  2203. }
  2204. if( _CURR_PS_INST->m_bCoIssue && m_pCurrInst->m_pPrevInst &&
  2205. (D3DSIO_NOP == m_pCurrInst->m_pPrevInst->m_Type))
  2206. {
  2207. // NOP cannot be part of co-issue (previous instruction found to be NOP)
  2208. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst->m_pPrevInst, "nop instruction cannot be co-issued." );
  2209. m_ErrorCount++;
  2210. }
  2211. if( _CURR_PS_INST->m_bCoIssue && D3DSIO_NOP == m_pCurrInst->m_Type )
  2212. {
  2213. // NOP cannot be part of co-issue (current instruction found to be NOP)
  2214. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "nop instruction cannot be co-issued." );
  2215. m_ErrorCount++;
  2216. }
  2217. if( _CURR_PS_INST->m_bCoIssue && m_pCurrInst->m_pPrevInst &&
  2218. (D3DSIO_DP4 == m_pCurrInst->m_pPrevInst->m_Type))
  2219. {
  2220. // DP4 cannot be part of co-issue (previous instruction found to be DP4)
  2221. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst->m_pPrevInst, "dp4 instruction cannot be co-issued." );
  2222. m_ErrorCount++;
  2223. }
  2224. if( _CURR_PS_INST->m_bCoIssue && D3DSIO_DP4 == m_pCurrInst->m_Type )
  2225. {
  2226. // DP4 cannot be part of co-issue (current instruction found to be DP4)
  2227. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "dp4 instruction cannot be co-issued." );
  2228. m_ErrorCount++;
  2229. }
  2230. if( _CURR_PS_INST->m_bCoIssue && !_CURR_PS_INST->m_bTexOp &&
  2231. NULL != m_pCurrInst->m_pPrevInst && !_PREV_PS_INST->m_bTexOp &&
  2232. !_PREV_PS_INST->m_bCoIssue )
  2233. {
  2234. // instruction and previous instruction are candidate for co-issue.
  2235. // ...do further validation...
  2236. DWORD ColorWriteMask = D3DSP_WRITEMASK_0 | D3DSP_WRITEMASK_1 | D3DSP_WRITEMASK_2;
  2237. DWORD CurrInstWriteMask = 0;
  2238. DWORD PrevInstWriteMask = 0;
  2239. if( m_pCurrInst->m_DstParam.m_bParamUsed )
  2240. CurrInstWriteMask = m_pCurrInst->m_DstParam.m_WriteMask;
  2241. if( m_pCurrInst->m_pPrevInst->m_DstParam.m_bParamUsed )
  2242. PrevInstWriteMask = m_pCurrInst->m_pPrevInst->m_DstParam.m_WriteMask;
  2243. if( D3DSIO_DP3 == m_pCurrInst->m_Type &&
  2244. D3DSIO_DP3 == m_pCurrInst->m_pPrevInst->m_Type )
  2245. {
  2246. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst,
  2247. "Co-issued instructions cannot both be dot-product, since each require use of the color/vector pipeline to execute." );
  2248. m_ErrorCount++;
  2249. }
  2250. else if( D3DSIO_DP3 == m_pCurrInst->m_Type )
  2251. {
  2252. if( ColorWriteMask & PrevInstWriteMask )
  2253. {
  2254. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst->m_pPrevInst,
  2255. "Dot-product needs color/vector pipeline to execute, so instruction co-issued with it cannot write to color components." );
  2256. m_ErrorCount++;
  2257. }
  2258. if( D3DSP_WRITEMASK_3 & CurrInstWriteMask ) // alpha in addition to the implied rgb for dp3
  2259. {
  2260. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst,
  2261. "Dot-product which writes alpha cannot co-issue, because both alpha and color/vector pipelines used." );
  2262. m_ErrorCount++;
  2263. }
  2264. }
  2265. else if( D3DSIO_DP3 == m_pCurrInst->m_pPrevInst->m_Type )
  2266. {
  2267. if( ColorWriteMask & CurrInstWriteMask )
  2268. {
  2269. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst,
  2270. "Dot-product needs color/vector pipeline to execute, so instruction co-issued with it cannot write to color components." );
  2271. m_ErrorCount++;
  2272. }
  2273. if( D3DSP_WRITEMASK_3 & PrevInstWriteMask ) // alpha in addition to the implied rgb for dp3
  2274. {
  2275. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst->m_pPrevInst,
  2276. "Dot-product which writes alpha cannot co-issue, because both alpha and color/vector pipelines used by the dot product." );
  2277. m_ErrorCount++;
  2278. }
  2279. }
  2280. else
  2281. {
  2282. if( PrevInstWriteMask == D3DSP_WRITEMASK_ALL )
  2283. {
  2284. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst->m_pPrevInst,
  2285. "Co-issued instruction cannot write all components - must write either alpha or color." );
  2286. m_ErrorCount++;
  2287. }
  2288. if( CurrInstWriteMask == D3DSP_WRITEMASK_ALL )
  2289. {
  2290. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst,
  2291. "Co-issued instruction cannot write all components - must write either alpha or color." );
  2292. m_ErrorCount++;
  2293. }
  2294. if( (m_pCurrInst->m_DstParam.m_RegType == m_pCurrInst->m_pPrevInst->m_DstParam.m_RegType) &&
  2295. (m_pCurrInst->m_DstParam.m_RegNum == m_pCurrInst->m_pPrevInst->m_DstParam.m_RegNum) &&
  2296. ((CurrInstWriteMask & PrevInstWriteMask) != 0) )
  2297. {
  2298. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst,
  2299. "Co-issued instructions cannot both write to the same components of a register. Affected components: %s",
  2300. MakeAffectedComponentsText(CurrInstWriteMask & PrevInstWriteMask,TRUE,FALSE)
  2301. );
  2302. m_ErrorCount++;
  2303. }
  2304. if( (CurrInstWriteMask & ColorWriteMask) && (PrevInstWriteMask & ColorWriteMask) )
  2305. {
  2306. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Co-issued instructions cannot both write to color components." );
  2307. m_ErrorCount++;
  2308. }
  2309. if( (CurrInstWriteMask & D3DSP_WRITEMASK_3) && (PrevInstWriteMask & D3DSP_WRITEMASK_3) )
  2310. {
  2311. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Co-issued instructions cannot both write to alpha component." );
  2312. m_ErrorCount++;
  2313. }
  2314. }
  2315. if( D3DPS_VERSION(1,0) >= m_Version )
  2316. {
  2317. // both co-issued instructions must write to the same register number.
  2318. if( m_pCurrInst->m_DstParam.m_RegType != m_pCurrInst->m_pPrevInst->m_DstParam.m_RegType )
  2319. {
  2320. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Co-issued instructions must both write to the same register type for pixelshader version <= 1.0." );
  2321. m_ErrorCount++;
  2322. }
  2323. if( (m_pCurrInst->m_DstParam.m_RegNum != m_pCurrInst->m_pPrevInst->m_DstParam.m_RegNum) )
  2324. {
  2325. Spew( SPEW_INSTRUCTION_ERROR, m_pCurrInst, "Co-issued instructions must both write to the same register number for pixelshader version <= 1.0." );
  2326. m_ErrorCount++;
  2327. }
  2328. }
  2329. }
  2330. return TRUE;
  2331. }
  2332. //-----------------------------------------------------------------------------
  2333. // CPShaderValidator10::Rule_ValidInstructionCount
  2334. //
  2335. // ** Rule:
  2336. // Make sure instruction count for pixel shader version has not been exceeded.
  2337. // Separate counts are kept for texture address instructions, for
  2338. // pixel blending instructions, and for the total number of instructions.
  2339. // Note that the total may not be the sum of texture + pixel instructions.
  2340. //
  2341. // For version 1.0+, D3DSIO_TEX counts only toward the tex op limit,
  2342. // but not towards the total op count.
  2343. //
  2344. // TEXBEML takes 3 instructions.
  2345. //
  2346. // Co-issued pixel blending instructions only
  2347. // count as one instruction towards the limit.
  2348. //
  2349. // The def instruction, nop, and comments (already stripped), do not count
  2350. // toward any limits.
  2351. //
  2352. // ** When to call:
  2353. // Per instruction AND after all instructions seen.
  2354. //
  2355. // ** Returns:
  2356. // Always TRUE.
  2357. //
  2358. //-----------------------------------------------------------------------------
  2359. BOOL CPShaderValidator10::Rule_ValidInstructionCount()
  2360. {
  2361. static UINT s_MaxTexOpCount;
  2362. static UINT s_MaxBlendOpCount;
  2363. static UINT s_MaxTotalOpCount;
  2364. if( NULL == m_pCurrInst )
  2365. return TRUE;
  2366. if( NULL == m_pCurrInst->m_pPrevInst ) // First instruction - initialize static vars
  2367. {
  2368. m_TexOpCount = 0;
  2369. m_BlendOpCount = 0;
  2370. switch(m_Version)
  2371. {
  2372. case D3DPS_VERSION(1,0): // DX8.0
  2373. s_MaxTexOpCount = 4;
  2374. s_MaxBlendOpCount = 8;
  2375. s_MaxTotalOpCount = 8;
  2376. break;
  2377. default:
  2378. case D3DPS_VERSION(1,1): // DX8.0
  2379. case D3DPS_VERSION(1,2): // DX8.1
  2380. case D3DPS_VERSION(1,3): // DX8.1
  2381. s_MaxTexOpCount = 4;
  2382. s_MaxBlendOpCount = 8;
  2383. s_MaxTotalOpCount = 12;
  2384. break;
  2385. }
  2386. }
  2387. if( m_bSeenAllInstructions )
  2388. {
  2389. if( m_TexOpCount > s_MaxTexOpCount )
  2390. {
  2391. Spew( SPEW_GLOBAL_ERROR, NULL, "Too many texture addressing instruction slots used: %d. Max. allowed is %d. (Note that some texture addressing instructions may use up more than one instruction slot)",
  2392. m_TexOpCount, s_MaxTexOpCount);
  2393. m_ErrorCount++;
  2394. }
  2395. if( m_BlendOpCount > s_MaxBlendOpCount )
  2396. {
  2397. Spew( SPEW_GLOBAL_ERROR, NULL, "Too many arithmetic instruction slots used: %d. Max. allowed (counting any co-issued pairs as 1) is %d.",
  2398. m_BlendOpCount, s_MaxBlendOpCount);
  2399. m_ErrorCount++;
  2400. }
  2401. if( !(m_TexOpCount > s_MaxTexOpCount && m_BlendOpCount > s_MaxBlendOpCount) // not already spewed avove 2 errors
  2402. && (m_TotalOpCount > s_MaxTotalOpCount) )
  2403. {
  2404. Spew( SPEW_GLOBAL_ERROR, NULL, "Total number of instruction slots used too high: %d. Max. allowed (counting any co-issued pairs as 1) is %d.",
  2405. m_TotalOpCount, s_MaxTotalOpCount);
  2406. m_ErrorCount++;
  2407. }
  2408. return TRUE;
  2409. }
  2410. switch(m_pCurrInst->m_Type)
  2411. {
  2412. case D3DSIO_TEXBEML:
  2413. m_BlendOpCount += 1;
  2414. m_TotalOpCount += 1;
  2415. // falling through
  2416. case D3DSIO_TEXBEM:
  2417. if(D3DPS_VERSION(1,0) >= m_Version )
  2418. {
  2419. m_TexOpCount += 2;
  2420. m_TotalOpCount += 2;
  2421. }
  2422. else
  2423. {
  2424. m_TexOpCount += 1;
  2425. m_TotalOpCount += 1;
  2426. }
  2427. break;
  2428. case D3DSIO_TEX:
  2429. m_TexOpCount++;
  2430. if(D3DPS_VERSION(1,1) <= m_Version)
  2431. m_TotalOpCount += 1;
  2432. break;
  2433. case D3DSIO_TEXCOORD:
  2434. case D3DSIO_TEXM3x2PAD:
  2435. case D3DSIO_TEXM3x2TEX:
  2436. case D3DSIO_TEXM3x3PAD:
  2437. case D3DSIO_TEXM3x3TEX:
  2438. case D3DSIO_TEXM3x3SPEC:
  2439. case D3DSIO_TEXM3x3VSPEC:
  2440. case D3DSIO_TEXREG2AR:
  2441. case D3DSIO_TEXREG2GB:
  2442. case D3DSIO_TEXKILL:
  2443. case D3DSIO_TEXM3x2DEPTH:
  2444. case D3DSIO_TEXDP3:
  2445. case D3DSIO_TEXREG2RGB:
  2446. case D3DSIO_TEXDP3TEX:
  2447. case D3DSIO_TEXM3x3:
  2448. m_TexOpCount++;
  2449. m_TotalOpCount++;
  2450. break;
  2451. case D3DSIO_MOV:
  2452. case D3DSIO_ADD:
  2453. case D3DSIO_SUB:
  2454. case D3DSIO_MUL:
  2455. case D3DSIO_MAD:
  2456. case D3DSIO_LRP:
  2457. case D3DSIO_DP3:
  2458. case D3DSIO_CMP:
  2459. case D3DSIO_CND:
  2460. case D3DSIO_DP4:
  2461. if( !_CURR_PS_INST->m_bCoIssue )
  2462. {
  2463. m_BlendOpCount++;
  2464. m_TotalOpCount++;
  2465. }
  2466. break;
  2467. case D3DSIO_NOP:
  2468. case D3DSIO_END:
  2469. case D3DSIO_DEF:
  2470. break;
  2471. default:
  2472. DXGASSERT(FALSE);
  2473. }
  2474. return TRUE;
  2475. }
  2476. //-----------------------------------------------------------------------------
  2477. // CPShaderValidator10::Rule_R0Written
  2478. //
  2479. // ** Rule:
  2480. // All components (r,g,b,a) of register R0 must have been written by the
  2481. // pixel shader.
  2482. //
  2483. // ** When to call:
  2484. // After all instructions have been seen.
  2485. //
  2486. // ** Returns:
  2487. // Always TRUE.
  2488. //
  2489. //-----------------------------------------------------------------------------
  2490. BOOL CPShaderValidator10::Rule_R0Written()
  2491. {
  2492. UINT NumUninitializedComponents = 0;
  2493. DWORD UninitializedComponentsMask = 0;
  2494. for( UINT i = 0; i < NUM_COMPONENTS_IN_REGISTER; i++ )
  2495. {
  2496. if( NULL == m_pTempRegFile->m_pAccessHistory[i][0].m_pMostRecentWriter )
  2497. {
  2498. NumUninitializedComponents++;
  2499. UninitializedComponentsMask |= COMPONENT_MASKS[i];
  2500. }
  2501. }
  2502. if( NumUninitializedComponents )
  2503. {
  2504. Spew( SPEW_GLOBAL_ERROR, NULL, "r0 must be written by shader. Uninitialized component%s(*): %s",
  2505. NumUninitializedComponents > 1 ? "s" : "", MakeAffectedComponentsText(UninitializedComponentsMask,TRUE,FALSE));
  2506. m_ErrorCount++;
  2507. }
  2508. return TRUE;
  2509. }