Counter Strike : Global Offensive Source Code
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.

3527 lines
106 KiB

  1. //------------------------------------------------------------------------------
  2. // DX9AsmToGL2.cpp
  3. //------------------------------------------------------------------------------
  4. #include "dxabstract.h"
  5. #include "tier0/dbg.h"
  6. #include "tier1/strtools.h"
  7. #include "tier1/utlbuffer.h"
  8. #include "DX9AsmToGL2.h"
  9. #ifdef POSIX
  10. #include "glmgr/glmgrbasics.h"
  11. #endif
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include "tier0/memdbgon.h"
  14. #ifdef POSIX
  15. #define strcat_s( a, b, c) V_strcat( a, c, b )
  16. #endif
  17. #define DST_REGISTER 0
  18. #define SRC_REGISTER 1
  19. // Tracking and naming sampler dimensions
  20. #define SAMPLER_TYPE_2D 0
  21. #define SAMPLER_TYPE_CUBE 1
  22. #define SAMPLER_TYPE_3D 2
  23. #define SAMPLER_TYPE_UNUSED 3
  24. // Flags to PrintUsageAndIndexToString.
  25. #define SEMANTIC_OUTPUT 0x01
  26. #define SEMANTIC_INPUT 0x02
  27. #define UNDECLARED_OUTPUT 0xFFFFFFFF
  28. #ifndef POSIX
  29. #define Debugger() Assert(0)
  30. #endif
  31. //#define Assert(n) if( !(n) ){ DebuggerBreakIfDebugging(); }
  32. static char *g_szVecZeros[] = { NULL, "0.0", "vec2( 0.0, 0.0 )", "vec3( 0.0, 0.0, 0.0 )", "vec4( 0.0, 0.0, 0.0, 0.0 )" };
  33. static char *g_szVecOnes[] = { NULL, "1.0", "vec2( 1.0, 1.0 )", "vec3( 1.0, 1.0, 1.0 )", "vec4( 1.0, 1.0, 1.0, 1.0 )" };
  34. static char *g_szDefaultSwizzle = "xyzw";
  35. static char *g_szDefaultSwizzleStrings[] = { "x", "y", "z", "w" };
  36. static char *g_szSamplerStrings[] = { "2D", "CUBE", "3D" };
  37. static const char *g_pAtomicTempVarName = "atomic_temp_var";
  38. static const char *g_pTangentAttributeName = "g_tangent";
  39. int __cdecl SortInts( const int *a, const int *b )
  40. {
  41. if ( *a < *b )
  42. return -1;
  43. else if ( *a > *b )
  44. return 1;
  45. else
  46. return 0;
  47. }
  48. void StripExtraTrailingZeros( char *pStr )
  49. {
  50. int len = (int)V_strlen( pStr );
  51. while ( len >= 2 && pStr[len-1] == '0' && pStr[len-2] != '.' )
  52. {
  53. pStr[len-1] = 0;
  54. --len;
  55. }
  56. }
  57. void PrintToBuf( CUtlBuffer &buf, const char *pFormat, ... )
  58. {
  59. va_list marker;
  60. va_start( marker, pFormat );
  61. char szTemp[1024];
  62. V_vsnprintf( szTemp, sizeof( szTemp ), pFormat, marker );
  63. va_end( marker );
  64. strcat_s( (char*)buf.Base(), buf.Size(), szTemp );
  65. }
  66. void PrintToBuf( char *pOut, int nOutSize, const char *pFormat, ... )
  67. {
  68. int nStrlen = V_strlen( pOut );
  69. pOut += nStrlen;
  70. nOutSize -= nStrlen;
  71. va_list marker;
  72. va_start( marker, pFormat );
  73. V_vsnprintf( pOut, nOutSize, pFormat, marker );
  74. va_end( marker );
  75. }
  76. // Return the number of letters following the dot.
  77. // Returns 4 if there is no dot.
  78. // (So "r0.xy" returns 2 and "r0" returns 4).
  79. int GetNumWriteMaskEntries( const char *pParam )
  80. {
  81. const char *pDot = strchr( pParam, '.' );
  82. if ( pDot )
  83. return V_strlen( pDot + 1 );
  84. else
  85. return 4;
  86. }
  87. const char* GetSwizzleDot( const char *pParam )
  88. {
  89. const char *pDot = strrchr( pParam, '.' );
  90. // The test against ')' here is for stuff like vec4( gl_Normal, 0.0 ) - we want to treat that as a whole param name.
  91. if ( pDot && strrchr( pParam, ')' ) < pDot && strrchr( pParam, ']' ) < pDot )
  92. return pDot;
  93. else
  94. return NULL;
  95. }
  96. int GetNumSwizzleComponents( const char *pParam )
  97. {
  98. // Special scalar output which won't accept a swizzle
  99. if ( !V_stricmp( pParam, "gl_FogFragCoord" ) )
  100. return 1;
  101. // Special scalar output which won't accept a swizzle
  102. if ( !V_stricmp( pParam, "gl_FragDepth" ) )
  103. return 1;
  104. // Special scalar output which won't accept a swizzle
  105. if ( !V_stricmp( pParam, "a0" ) )
  106. return 1;
  107. const char *pDot = GetSwizzleDot( pParam );
  108. if ( pDot )
  109. return V_strlen( pDot + 1 );
  110. else
  111. return 0;
  112. }
  113. char GetSwizzleComponent( const char *pParam, int n )
  114. {
  115. Assert( n < 4 );
  116. const char *pDot = GetSwizzleDot( pParam );
  117. if ( pDot )
  118. {
  119. ++pDot;
  120. int nComponents = (int)V_strlen( pDot );
  121. Assert( nComponents > 0 );
  122. if ( n < nComponents )
  123. return pDot[n];
  124. else
  125. return pDot[nComponents-1];
  126. }
  127. return g_szDefaultSwizzle[n];
  128. }
  129. // Replace the parameter name and leave the swizzle intact.
  130. // So "somevar.xyz" becomes "othervar.xyz".
  131. void ReplaceParamName( const char *pSrc, const char *pNewParamName, char *pOut, int nOutLen )
  132. {
  133. // Start with the new parameter name.
  134. V_strncpy( pOut, pNewParamName, nOutLen );
  135. // Now add the swizzle if necessary.
  136. const char *pDot = GetSwizzleDot( pSrc );
  137. if ( pDot )
  138. {
  139. V_strncat( pOut, pDot, nOutLen );
  140. }
  141. }
  142. void GetParamNameWithoutSwizzle( const char *pParam, char *pOut, int nOutLen )
  143. {
  144. const char *pDot = GetSwizzleDot( pParam );
  145. // The test against ')' here is for stuff like vec4( gl_Normal, 0.0 ) - we want to treat that as a whole param name.
  146. if ( pDot )
  147. {
  148. int nToCopy = MIN( nOutLen-1, pDot - pParam );
  149. memcpy( pOut, pParam, nToCopy );
  150. pOut[nToCopy] = 0;
  151. }
  152. else
  153. {
  154. V_strncpy( pOut, pParam, nOutLen );
  155. }
  156. }
  157. bool DoParamNamesMatch( const char *pParam1, const char *pParam2 )
  158. {
  159. char szTemp[2][256];
  160. GetParamNameWithoutSwizzle( pParam1, szTemp[0], sizeof( szTemp[0] ) );
  161. GetParamNameWithoutSwizzle( pParam2, szTemp[1], sizeof( szTemp[1] ) );
  162. return ( V_stricmp( szTemp[0], szTemp[1] ) == 0 );
  163. }
  164. // Extract the n'th component of the swizzle mask.
  165. // If n would exceed the length of the swizzle mask, then it looks up into "xyzw".
  166. void WriteParamWithSingleMaskEntry( const char *pParam, int n, char *pOut, int nOutLen )
  167. {
  168. GetParamNameWithoutSwizzle( pParam, pOut, nOutLen );
  169. PrintToBuf( pOut, nOutLen, "." );
  170. PrintToBuf( pOut, nOutLen, "%c", GetSwizzleComponent( pParam, n ) );
  171. }
  172. float uint32ToFloat( uint32 dw )
  173. {
  174. return *((float*)&dw);
  175. }
  176. CUtlString EnsureNumSwizzleComponents( const char *pStr, int nComponents )
  177. {
  178. int nExisting = GetNumSwizzleComponents( pStr );
  179. if ( nExisting == nComponents )
  180. return pStr;
  181. char szReg[256];
  182. GetParamNameWithoutSwizzle( pStr, szReg, sizeof( szReg ) );
  183. if ( nComponents == 0 )
  184. return szReg;
  185. PrintToBuf( szReg, sizeof( szReg ), "." );
  186. if ( nExisting > nComponents )
  187. {
  188. // DX ASM will sometimes have statements like "NRM r0.xyz, r1.yzww", where it just doesn't use the last part of r1. So we won't either.
  189. for ( int i=0; i < nComponents; i++ )
  190. {
  191. PrintToBuf( szReg, sizeof( szReg ), "%c", GetSwizzleComponent( pStr, i ) );
  192. }
  193. }
  194. else
  195. {
  196. if ( nExisting == 0 )
  197. {
  198. // We've got something like r0 and need N more components, so add as much of "xyzw" is needed.
  199. for ( int i=0; i < nComponents; i++ )
  200. PrintToBuf( szReg, sizeof( szReg ), "%c", g_szDefaultSwizzle[i] );
  201. }
  202. else
  203. {
  204. // We've got something like r0.x and need N more components, so replicate the X so it looks like r0.xxx
  205. V_strncpy( szReg, pStr, sizeof( szReg ) );
  206. char cLast = pStr[ V_strlen( pStr ) - 1 ];
  207. for ( int i=nExisting; i < nComponents; i++ )
  208. {
  209. PrintToBuf( szReg, sizeof( szReg ), "%c", cLast );
  210. }
  211. }
  212. }
  213. return szReg;
  214. }
  215. D3DToGL::D3DToGL()
  216. {
  217. }
  218. uint32 D3DToGL::GetNextToken( void )
  219. {
  220. uint32 dwToken = *m_pdwNextToken;
  221. m_pdwNextToken++;
  222. return dwToken;
  223. }
  224. void D3DToGL::SkipTokens( uint32 numToSkip )
  225. {
  226. m_pdwNextToken += numToSkip;
  227. }
  228. uint32 D3DToGL::Opcode( uint32 dwToken )
  229. {
  230. return ( dwToken & D3DSI_OPCODE_MASK );
  231. }
  232. uint32 D3DToGL::OpcodeSpecificData (uint32 dwToken)
  233. {
  234. return ( ( dwToken & D3DSP_OPCODESPECIFICCONTROL_MASK ) >> D3DSP_OPCODESPECIFICCONTROL_SHIFT );
  235. }
  236. uint32 D3DToGL::TextureType ( uint32 dwToken )
  237. {
  238. return ( dwToken & D3DSP_TEXTURETYPE_MASK ); // Note this one doesn't shift due to weird D3DSAMPLER_TEXTURE_TYPE enum
  239. }
  240. // Print GLSL intrinsic corresponding to particular instruction
  241. bool D3DToGL::OpenIntrinsic( uint32 inst, char* buff, int nBufLen, uint32 destDimension, uint32 nArgumentDimension )
  242. {
  243. // Some GLSL intrinsics need type conversion, which we do in this routine
  244. // As a result, the caller must sometimes close both parentheses, not just one
  245. bool bDoubleClose = false;
  246. if ( nArgumentDimension == 0 )
  247. {
  248. nArgumentDimension = 4;
  249. }
  250. switch ( inst )
  251. {
  252. case D3DSIO_RSQ:
  253. V_snprintf( buff, nBufLen, "inversesqrt( " );
  254. break;
  255. case D3DSIO_DP3:
  256. case D3DSIO_DP4:
  257. if ( destDimension == 1 )
  258. {
  259. V_snprintf( buff, nBufLen, "dot( " );
  260. }
  261. else
  262. {
  263. V_snprintf( buff, nBufLen, "vec%d( dot( ", destDimension );
  264. bDoubleClose = true;
  265. }
  266. break;
  267. case D3DSIO_MIN:
  268. V_snprintf( buff, nBufLen, "min( " );
  269. break;
  270. case D3DSIO_MAX:
  271. V_snprintf( buff, nBufLen, "max( " );
  272. break;
  273. case D3DSIO_SLT:
  274. if ( nArgumentDimension == 1 )
  275. {
  276. V_snprintf( buff, nBufLen, "float( ", nArgumentDimension ); // lessThan doesn't have a scalar version
  277. }
  278. else
  279. {
  280. V_snprintf( buff, nBufLen, "vec%d( lessThan( ", nArgumentDimension );
  281. bDoubleClose = true;
  282. }
  283. break;
  284. case D3DSIO_SGE:
  285. if ( nArgumentDimension == 1 )
  286. {
  287. V_snprintf( buff, nBufLen, "float( ", nArgumentDimension ); // greaterThanEqual doesn't have a scalar version
  288. }
  289. else
  290. {
  291. V_snprintf( buff, nBufLen, "vec%d( greaterThanEqual( ", nArgumentDimension );
  292. bDoubleClose = true;
  293. }
  294. break;
  295. case D3DSIO_EXP:
  296. V_snprintf( buff, nBufLen, "exp( " ); // exp2 ?
  297. break;
  298. case D3DSIO_LOG:
  299. V_snprintf( buff, nBufLen, "log( " ); // log2 ?
  300. break;
  301. case D3DSIO_LIT:
  302. DebuggerBreakIfDebugging();
  303. V_snprintf( buff, nBufLen, "lit( " ); // gonna have to write this one
  304. break;
  305. case D3DSIO_DST:
  306. DebuggerBreakIfDebugging();
  307. V_snprintf( buff, nBufLen, "dst( " ); // gonna have to write this one
  308. break;
  309. case D3DSIO_LRP:
  310. Assert( !m_bVertexShader );
  311. V_snprintf( buff, nBufLen, "mix( " );
  312. break;
  313. case D3DSIO_FRC:
  314. V_snprintf( buff, nBufLen, "fract( " );
  315. break;
  316. case D3DSIO_M4x4:
  317. DebuggerBreakIfDebugging();
  318. V_snprintf( buff, nBufLen, "m4x4" );
  319. break;
  320. case D3DSIO_M4x3:
  321. case D3DSIO_M3x4:
  322. case D3DSIO_M3x3:
  323. case D3DSIO_M3x2:
  324. case D3DSIO_CALL:
  325. case D3DSIO_CALLNZ:
  326. case D3DSIO_LOOP:
  327. case D3DSIO_RET:
  328. case D3DSIO_ENDLOOP:
  329. case D3DSIO_LABEL:
  330. case D3DSIO_DCL:
  331. DebuggerBreakIfDebugging();
  332. break;
  333. case D3DSIO_POW:
  334. V_snprintf( buff, nBufLen, "pow( " );
  335. break;
  336. case D3DSIO_CRS:
  337. V_snprintf( buff, nBufLen, "cross( " );
  338. break;
  339. case D3DSIO_SGN:
  340. DebuggerBreakIfDebugging();
  341. V_snprintf( buff, nBufLen, "sign( " );
  342. break;
  343. case D3DSIO_ABS:
  344. V_snprintf( buff, nBufLen, "abs( " );
  345. break;
  346. case D3DSIO_NRM:
  347. DebuggerBreakIfDebugging();
  348. V_snprintf( buff, nBufLen, "normalize( " );
  349. break;
  350. case D3DSIO_SINCOS:
  351. DebuggerBreakIfDebugging();
  352. V_snprintf( buff, nBufLen, "sincos( " ); // gonna have to write this one
  353. break;
  354. case D3DSIO_REP:
  355. case D3DSIO_ENDREP:
  356. case D3DSIO_IF:
  357. case D3DSIO_IFC:
  358. case D3DSIO_ELSE:
  359. case D3DSIO_ENDIF:
  360. case D3DSIO_BREAK:
  361. case D3DSIO_BREAKC: // TODO: these are the reason we even need GLSL...gotta make these work
  362. DebuggerBreakIfDebugging();
  363. break;
  364. case D3DSIO_DEFB:
  365. case D3DSIO_DEFI:
  366. DebuggerBreakIfDebugging();
  367. break;
  368. case D3DSIO_TEXCOORD:
  369. V_snprintf( buff, nBufLen, "texcoord" );
  370. break;
  371. case D3DSIO_TEXKILL:
  372. V_snprintf( buff, nBufLen, "kill( " ); // wrap the discard instruction?
  373. break;
  374. case D3DSIO_TEX:
  375. DebuggerBreakIfDebugging();
  376. V_snprintf( buff, nBufLen, "TEX" ); // We shouldn't get here
  377. break;
  378. case D3DSIO_TEXBEM:
  379. case D3DSIO_TEXBEML:
  380. case D3DSIO_TEXREG2AR:
  381. case D3DSIO_TEXREG2GB:
  382. case D3DSIO_TEXM3x2PAD:
  383. case D3DSIO_TEXM3x2TEX:
  384. case D3DSIO_TEXM3x3PAD:
  385. case D3DSIO_TEXM3x3TEX:
  386. case D3DSIO_TEXM3x3SPEC:
  387. case D3DSIO_TEXM3x3VSPEC:
  388. DebuggerBreakIfDebugging();
  389. break;
  390. case D3DSIO_EXPP:
  391. V_snprintf( buff, nBufLen, "exp( " );
  392. break;
  393. case D3DSIO_LOGP:
  394. V_snprintf( buff, nBufLen, "log( " );
  395. break;
  396. case D3DSIO_CND:
  397. DebuggerBreakIfDebugging();
  398. break;
  399. case D3DSIO_DEF:
  400. DebuggerBreakIfDebugging();
  401. V_snprintf( buff, nBufLen, "DEF" );
  402. break;
  403. case D3DSIO_TEXREG2RGB:
  404. case D3DSIO_TEXDP3TEX:
  405. case D3DSIO_TEXM3x2DEPTH:
  406. case D3DSIO_TEXDP3:
  407. case D3DSIO_TEXM3x3:
  408. DebuggerBreakIfDebugging();
  409. break;
  410. case D3DSIO_TEXDEPTH:
  411. V_snprintf( buff, nBufLen, "texdepth" );
  412. break;
  413. case D3DSIO_CMP:
  414. DebuggerBreakIfDebugging();
  415. Assert( !m_bVertexShader );
  416. V_snprintf( buff, nBufLen, "CMP" );
  417. break;
  418. case D3DSIO_BEM:
  419. DebuggerBreakIfDebugging();
  420. break;
  421. case D3DSIO_DP2ADD:
  422. DebuggerBreakIfDebugging();
  423. break;
  424. case D3DSIO_DSX:
  425. case D3DSIO_DSY:
  426. DebuggerBreakIfDebugging();
  427. break;
  428. case D3DSIO_TEXLDD:
  429. V_snprintf( buff, nBufLen, "texldd" );
  430. break;
  431. case D3DSIO_SETP:
  432. DebuggerBreakIfDebugging();
  433. break;
  434. case D3DSIO_TEXLDL:
  435. V_snprintf( buff, nBufLen, "texldl" );
  436. break;
  437. case D3DSIO_BREAKP:
  438. case D3DSIO_PHASE:
  439. DebuggerBreakIfDebugging();
  440. break;
  441. }
  442. return bDoubleClose;
  443. }
  444. const char* D3DToGL::GetGLSLOperatorString( uint32 inst )
  445. {
  446. if ( inst == D3DSIO_ADD )
  447. return "+";
  448. else if ( inst == D3DSIO_SUB )
  449. return "-";
  450. else if ( inst == D3DSIO_MUL )
  451. return "*";
  452. Error( "GetGLSLOperatorString: unknown operator" );
  453. return "zzzz";
  454. }
  455. // Print ASM opcode
  456. void D3DToGL::PrintOpcode( uint32 inst, char* buff, int nBufLen )
  457. {
  458. switch ( inst )
  459. {
  460. case D3DSIO_NOP:
  461. V_snprintf( buff, nBufLen, "NOP" );
  462. DebuggerBreakIfDebugging();
  463. break;
  464. case D3DSIO_MOV:
  465. V_snprintf( buff, nBufLen, "MOV" );
  466. break;
  467. case D3DSIO_ADD:
  468. V_snprintf( buff, nBufLen, "ADD" );
  469. break;
  470. case D3DSIO_SUB:
  471. V_snprintf( buff, nBufLen, "SUB" );
  472. break;
  473. case D3DSIO_MAD:
  474. V_snprintf( buff, nBufLen, "MAD" );
  475. break;
  476. case D3DSIO_MUL:
  477. V_snprintf( buff, nBufLen, "MUL" );
  478. break;
  479. case D3DSIO_RCP:
  480. V_snprintf( buff, nBufLen, "RCP" );
  481. break;
  482. case D3DSIO_RSQ:
  483. V_snprintf( buff, nBufLen, "RSQ" );
  484. break;
  485. case D3DSIO_DP3:
  486. V_snprintf( buff, nBufLen, "DP3" );
  487. break;
  488. case D3DSIO_DP4:
  489. V_snprintf( buff, nBufLen, "DP4" );
  490. break;
  491. case D3DSIO_MIN:
  492. V_snprintf( buff, nBufLen, "MIN" );
  493. break;
  494. case D3DSIO_MAX:
  495. V_snprintf( buff, nBufLen, "MAX" );
  496. break;
  497. case D3DSIO_SLT:
  498. V_snprintf( buff, nBufLen, "SLT" );
  499. break;
  500. case D3DSIO_SGE:
  501. V_snprintf( buff, nBufLen, "SGE" );
  502. break;
  503. case D3DSIO_EXP:
  504. V_snprintf( buff, nBufLen, "EX2" );
  505. break;
  506. case D3DSIO_LOG:
  507. V_snprintf( buff, nBufLen, "LG2" );
  508. break;
  509. case D3DSIO_LIT:
  510. V_snprintf( buff, nBufLen, "LIT" );
  511. break;
  512. case D3DSIO_DST:
  513. V_snprintf( buff, nBufLen, "DST" );
  514. break;
  515. case D3DSIO_LRP:
  516. Assert( !m_bVertexShader );
  517. V_snprintf( buff, nBufLen, "LRP" );
  518. break;
  519. case D3DSIO_FRC:
  520. V_snprintf( buff, nBufLen, "FRC" );
  521. break;
  522. case D3DSIO_M4x4:
  523. V_snprintf( buff, nBufLen, "m4x4" );
  524. break;
  525. case D3DSIO_M4x3:
  526. case D3DSIO_M3x4:
  527. case D3DSIO_M3x3:
  528. case D3DSIO_M3x2:
  529. case D3DSIO_CALL:
  530. case D3DSIO_CALLNZ:
  531. case D3DSIO_LOOP:
  532. case D3DSIO_RET:
  533. case D3DSIO_ENDLOOP:
  534. case D3DSIO_LABEL:
  535. DebuggerBreakIfDebugging();
  536. break;
  537. case D3DSIO_DCL:
  538. V_snprintf( buff, nBufLen, "DCL" );
  539. break;
  540. case D3DSIO_POW:
  541. V_snprintf( buff, nBufLen, "POW" );
  542. break;
  543. case D3DSIO_CRS:
  544. V_snprintf( buff, nBufLen, "XPD" );
  545. break;
  546. case D3DSIO_SGN:
  547. DebuggerBreakIfDebugging();
  548. V_snprintf( buff, nBufLen, "SGN" );
  549. break;
  550. case D3DSIO_ABS:
  551. V_snprintf( buff, nBufLen, "ABS" );
  552. break;
  553. case D3DSIO_NRM:
  554. DebuggerBreakIfDebugging();
  555. V_snprintf( buff, nBufLen, "NRM" );
  556. break;
  557. case D3DSIO_SINCOS:
  558. Assert( !m_bVertexShader );
  559. V_snprintf( buff, nBufLen, "SCS" );
  560. break;
  561. case D3DSIO_REP:
  562. case D3DSIO_ENDREP:
  563. case D3DSIO_IF:
  564. case D3DSIO_IFC:
  565. case D3DSIO_ELSE:
  566. case D3DSIO_ENDIF:
  567. case D3DSIO_BREAK:
  568. case D3DSIO_BREAKC:
  569. DebuggerBreakIfDebugging();
  570. break;
  571. case D3DSIO_MOVA:
  572. Assert( m_bVertexShader );
  573. V_snprintf( buff, nBufLen, "MOV" ); // We're always moving into a temp instead, so this is MOV instead of ARL
  574. break;
  575. case D3DSIO_DEFB:
  576. case D3DSIO_DEFI:
  577. DebuggerBreakIfDebugging();
  578. break;
  579. case D3DSIO_TEXCOORD:
  580. V_snprintf( buff, nBufLen, "texcoord" );
  581. break;
  582. case D3DSIO_TEXKILL:
  583. V_snprintf( buff, nBufLen, "KIL" );
  584. break;
  585. case D3DSIO_TEX:
  586. V_snprintf( buff, nBufLen, "TEX" );
  587. break;
  588. case D3DSIO_TEXBEM:
  589. case D3DSIO_TEXBEML:
  590. case D3DSIO_TEXREG2AR:
  591. case D3DSIO_TEXREG2GB:
  592. case D3DSIO_TEXM3x2PAD:
  593. case D3DSIO_TEXM3x2TEX:
  594. case D3DSIO_TEXM3x3PAD:
  595. case D3DSIO_TEXM3x3TEX:
  596. case D3DSIO_TEXM3x3SPEC:
  597. case D3DSIO_TEXM3x3VSPEC:
  598. DebuggerBreakIfDebugging();
  599. break;
  600. case D3DSIO_EXPP:
  601. V_snprintf( buff, nBufLen, "EXP" );
  602. break;
  603. case D3DSIO_LOGP:
  604. V_snprintf( buff, nBufLen, "LOG" );
  605. break;
  606. case D3DSIO_CND:
  607. DebuggerBreakIfDebugging();
  608. break;
  609. case D3DSIO_DEF:
  610. V_snprintf( buff, nBufLen, "DEF" );
  611. break;
  612. case D3DSIO_TEXREG2RGB:
  613. case D3DSIO_TEXDP3TEX:
  614. case D3DSIO_TEXM3x2DEPTH:
  615. case D3DSIO_TEXDP3:
  616. case D3DSIO_TEXM3x3:
  617. DebuggerBreakIfDebugging();
  618. break;
  619. case D3DSIO_TEXDEPTH:
  620. V_snprintf( buff, nBufLen, "texdepth" );
  621. break;
  622. case D3DSIO_CMP:
  623. Assert( !m_bVertexShader );
  624. V_snprintf( buff, nBufLen, "CMP" );
  625. break;
  626. case D3DSIO_BEM:
  627. DebuggerBreakIfDebugging();
  628. break;
  629. case D3DSIO_DP2ADD:
  630. DebuggerBreakIfDebugging();
  631. break;
  632. case D3DSIO_DSX:
  633. case D3DSIO_DSY:
  634. DebuggerBreakIfDebugging();
  635. break;
  636. case D3DSIO_TEXLDD:
  637. V_snprintf( buff, nBufLen, "texldd" );
  638. break;
  639. case D3DSIO_SETP:
  640. DebuggerBreakIfDebugging();
  641. break;
  642. case D3DSIO_TEXLDL:
  643. V_snprintf( buff, nBufLen, "texldl" );
  644. break;
  645. case D3DSIO_BREAKP:
  646. case D3DSIO_PHASE:
  647. DebuggerBreakIfDebugging();
  648. break;
  649. }
  650. }
  651. CUtlString D3DToGL::GetUsageAndIndexString( uint32 dwToken, int fSemanticFlags )
  652. {
  653. char szTemp[1024];
  654. PrintUsageAndIndexToString( dwToken, szTemp, sizeof( szTemp ), fSemanticFlags );
  655. return szTemp;
  656. }
  657. //------------------------------------------------------------------------------
  658. // Helper function which prints ASCII representation of usage-usageindex pair to string
  659. //
  660. // Strictly used by vertex shaders
  661. // not used any more now that we have attribmap metadata
  662. //------------------------------------------------------------------------------
  663. void D3DToGL::PrintUsageAndIndexToString( uint32 dwToken, char* strUsageUsageIndexName, int nBufLen, int fSemanticFlags )
  664. {
  665. uint32 dwUsage = ( dwToken & D3DSP_DCL_USAGE_MASK );
  666. uint32 dwUsageIndex = ( dwToken & D3DSP_DCL_USAGEINDEX_MASK ) >> D3DSP_DCL_USAGEINDEX_SHIFT;
  667. switch ( dwUsage )
  668. {
  669. case D3DDECLUSAGE_POSITION:
  670. if ( m_bGLSL )
  671. {
  672. if ( m_bVertexShader )
  673. {
  674. if ( fSemanticFlags & SEMANTIC_OUTPUT )
  675. V_snprintf( strUsageUsageIndexName, nBufLen, "vTempPos" ); // effectively gl_Position
  676. else
  677. V_snprintf( strUsageUsageIndexName, nBufLen, "gl_Vertex" );
  678. }
  679. else
  680. {
  681. // .xy = position in viewport coordinates
  682. // .z = depth
  683. V_snprintf( strUsageUsageIndexName, nBufLen, "gl_FragCoord" );
  684. }
  685. }
  686. else
  687. {
  688. V_snprintf( strUsageUsageIndexName, nBufLen, "vertex.attrib[0]" ); //"vertex.position" ); // aka generic [0]
  689. }
  690. break;
  691. case D3DDECLUSAGE_BLENDWEIGHT:
  692. V_snprintf( strUsageUsageIndexName, nBufLen, "vertex.attrib[1]" ); // "vertex.attrib[12]" ); // or [1]
  693. break;
  694. case D3DDECLUSAGE_BLENDINDICES:
  695. V_snprintf( strUsageUsageIndexName, nBufLen, "vertex.attrib[13]" ); // "vertex.attrib[13]" ); // or [ 7 ]
  696. break;
  697. case D3DDECLUSAGE_NORMAL:
  698. V_snprintf( strUsageUsageIndexName, nBufLen, m_bGLSL ? "vec4( gl_Normal, 0.0 )" : "vertex.attrib[2]" );
  699. break;
  700. case D3DDECLUSAGE_PSIZE:
  701. DebuggerBreakIfDebugging();
  702. V_snprintf( strUsageUsageIndexName, nBufLen, "_psize" ); // no analog
  703. break;
  704. case D3DDECLUSAGE_TEXCOORD:
  705. if ( m_bGLSL )
  706. {
  707. // GLSL vs output and ps inputs reference gl_TexCoord[n], not gl_MultiTexCoord.
  708. if ( !m_bVertexShader || (fSemanticFlags & SEMANTIC_OUTPUT) )
  709. V_snprintf( strUsageUsageIndexName, nBufLen, "gl_TexCoord[%d]", dwUsageIndex );
  710. else
  711. V_snprintf( strUsageUsageIndexName, nBufLen, "gl_MultiTexCoord%d", dwUsageIndex );
  712. }
  713. else
  714. {
  715. V_snprintf( strUsageUsageIndexName, nBufLen, "vertex.attrib[%d]", 8+dwUsageIndex ); // "vertex.texcoord[%d]", dwUsageIndex ); // aka [8] - [15] ?
  716. }
  717. break;
  718. case D3DDECLUSAGE_TANGENT:
  719. if ( m_bGLSL )
  720. {
  721. NoteTangentInputUsed();
  722. V_strncpy( strUsageUsageIndexName, g_pTangentAttributeName, nBufLen );
  723. }
  724. else
  725. {
  726. V_snprintf( strUsageUsageIndexName, nBufLen, "vertex.attrib[15]" ); // aka texc[7]
  727. }
  728. break;
  729. case D3DDECLUSAGE_BINORMAL:
  730. V_snprintf( strUsageUsageIndexName, nBufLen, "vertex.attrib[14]" ); // aka texc[6]
  731. break;
  732. // case D3DDECLUSAGE_TESSFACTOR:
  733. // DebuggerBreakIfDebugging();
  734. // V_snprintf( strUsageUsageIndexName, nBufLen, "_position" ); // no analog
  735. // break;
  736. // case D3DDECLUSAGE_POSITIONT:
  737. // DebuggerBreakIfDebugging();
  738. // V_snprintf( strUsageUsageIndexName, nBufLen, "_positiont" ); // no analog
  739. // break;
  740. case D3DDECLUSAGE_COLOR:
  741. if ( m_bGLSL )
  742. {
  743. // if ( fSemanticFlags & SEMANTIC_OUTPUT )
  744. // V_snprintf( strUsageUsageIndexName, nBufLen, dwUsageIndex != 0 ? "gl_BackColor" : "gl_FrontColor" );
  745. // else
  746. V_snprintf( strUsageUsageIndexName, nBufLen, dwUsageIndex != 0 ? "gl_SecondaryColor" : "gl_Color" );
  747. }
  748. else
  749. {
  750. V_snprintf( strUsageUsageIndexName, nBufLen, "vertex.attrib[%d]", 3+dwUsageIndex ); //dwUsageIndex ); // != 0 ? "vertex.color.secondary" : "vertex.color" ); // aka [3] / [4] (second)
  751. }
  752. break;
  753. case D3DDECLUSAGE_FOG:
  754. Assert( !m_bGLSL );
  755. V_snprintf( strUsageUsageIndexName, nBufLen, "vertex.attrib[5]" ); //"vertex.position" /* "_fog" */ ); //FIXME, evil // aka [5] / vertex.fogcoord
  756. break;
  757. case D3DDECLUSAGE_DEPTH:
  758. DebuggerBreakIfDebugging();
  759. V_snprintf( strUsageUsageIndexName, nBufLen, "_depth" ); // no analog
  760. break;
  761. case D3DDECLUSAGE_SAMPLE:
  762. DebuggerBreakIfDebugging();
  763. V_snprintf( strUsageUsageIndexName, nBufLen, "_sample" ); // no analog
  764. break;
  765. default:
  766. Debugger();
  767. break;
  768. }
  769. }
  770. uint32 D3DToGL::GetRegType( uint32 dwRegToken )
  771. {
  772. return ( ( dwRegToken & D3DSP_REGTYPE_MASK2 ) >> D3DSP_REGTYPE_SHIFT2 ) | ( ( dwRegToken & D3DSP_REGTYPE_MASK ) >> D3DSP_REGTYPE_SHIFT );
  773. }
  774. void D3DToGL::PrintIndentation( char *pBuf, int nBufLen )
  775. {
  776. for( int i=0; i<m_NumIndentTabs; i++ )
  777. {
  778. strcat_s( pBuf, nBufLen, "\t" );
  779. }
  780. }
  781. CUtlString D3DToGL::GetParameterString( uint32 dwToken, uint32 dwSourceOrDest, bool bForceScalarSource, int *pARLDestReg )
  782. {
  783. char szTemp[1024];
  784. PrintParameterToString( dwToken, dwSourceOrDest, szTemp, sizeof( szTemp ), bForceScalarSource, pARLDestReg );
  785. return szTemp;
  786. }
  787. // If the register happens to end with ".xyzw", then this strips off the mask.
  788. void SimplifyFourParamRegister( char *pRegister )
  789. {
  790. int nLen = V_strlen( pRegister );
  791. if ( nLen > 5 && V_strcmp( &pRegister[nLen-5], ".xyzw" ) == 0 )
  792. pRegister[nLen-5] = 0;
  793. }
  794. // This returns 0 for x, 1 for y, 2 for z, and 3 for w.
  795. int GetSwizzleComponentVectorIndex( char chMask )
  796. {
  797. if ( chMask == 'x' )
  798. return 0;
  799. else if ( chMask == 'y' )
  800. return 1;
  801. else if ( chMask == 'z' )
  802. return 2;
  803. else if ( chMask == 'w' )
  804. return 3;
  805. Error( "GetSwizzleComponentVectorIndex( '%c' ) - invalid parameter.\n", chMask );
  806. return 0;
  807. }
  808. // GLSL needs the # of src masks to match the dest write mask.
  809. //
  810. // So this:
  811. // r0.xy = r1 + r2;
  812. // becomes:
  813. // r0.xy = r1.xy + r2.xy;
  814. //
  815. //
  816. // Also, and this is the trickier one: GLSL reads the source registers from their first component on
  817. // whereas D3D reads them as referenced in the dest register mask!
  818. //
  819. // So this code in D3D:
  820. // r0.yz = c0.x + c1.wxyz
  821. // Really means:
  822. // r0.y = c0.x + c1.x
  823. // r0.z = c0.x + c1.y
  824. // So we translate it to this in GLSL:
  825. // r0.yz = c0.xx + c1.wx
  826. // r0.yz = c0.xx + c1.xy
  827. //
  828. CUtlString D3DToGL::FixGLSLSwizzle( const char *pDestRegisterName, const char *pSrcRegisterName )
  829. {
  830. if ( !m_bGLSL )
  831. return pSrcRegisterName;
  832. int nSwizzlesInDest = GetNumSwizzleComponents( pDestRegisterName );
  833. if ( nSwizzlesInDest == 0 )
  834. nSwizzlesInDest = 4;
  835. char szFixedSrcRegister[128];
  836. GetParamNameWithoutSwizzle( pSrcRegisterName, szFixedSrcRegister, sizeof( szFixedSrcRegister ) );
  837. V_strncat( szFixedSrcRegister, ".", sizeof( szFixedSrcRegister ) );
  838. for ( int i=0; i < nSwizzlesInDest; i++ )
  839. {
  840. char chDestWriteMask = GetSwizzleComponent( pDestRegisterName, i );
  841. int nVectorIndex = GetSwizzleComponentVectorIndex( chDestWriteMask );
  842. char ch[2];
  843. ch[0] = GetSwizzleComponent( pSrcRegisterName, nVectorIndex );
  844. ch[1] = 0;
  845. V_strncat( szFixedSrcRegister, ch, sizeof( szFixedSrcRegister ) );
  846. }
  847. SimplifyFourParamRegister( szFixedSrcRegister );
  848. return szFixedSrcRegister;
  849. }
  850. // Weird encoding...bits are split apart in the dwToken
  851. inline uint32 GetRegTypeFromToken( uint32 dwToken )
  852. {
  853. return ( ( dwToken & D3DSP_REGTYPE_MASK2 ) >> D3DSP_REGTYPE_SHIFT2 ) | ( ( dwToken & D3DSP_REGTYPE_MASK ) >> D3DSP_REGTYPE_SHIFT );
  854. }
  855. void D3DToGL::FlagIndirectRegister( uint32 dwToken, int *pARLDestReg )
  856. {
  857. if ( !pARLDestReg )
  858. return;
  859. switch ( dwToken & D3DVS_SWIZZLE_MASK & D3DVS_X_W )
  860. {
  861. case D3DVS_X_X:
  862. *pARLDestReg = ARL_DEST_X;
  863. break;
  864. case D3DVS_X_Y:
  865. *pARLDestReg = ARL_DEST_Y;
  866. break;
  867. case D3DVS_X_Z:
  868. *pARLDestReg = ARL_DEST_Z;
  869. break;
  870. case D3DVS_X_W:
  871. *pARLDestReg = ARL_DEST_W;
  872. break;
  873. }
  874. }
  875. //------------------------------------------------------------------------------
  876. // PrintParameterToString()
  877. //
  878. // Helper function which prints ASCII representation of passed Parameter dwToken
  879. // to string. Token defines parameter details. The dwSourceOrDest parameter says
  880. // whether or not this is a source or destination register
  881. //------------------------------------------------------------------------------
  882. void D3DToGL::PrintParameterToString ( uint32 dwToken, uint32 dwSourceOrDest, char *pRegisterName, int nBufLen, bool bForceScalarSource, int *pARLDestReg )
  883. {
  884. char buff[32];
  885. bool bAllowWriteMask = true;
  886. bool bAllowSwizzle = true;
  887. uint32 dwRegNum = dwToken & D3DSP_REGNUM_MASK;
  888. uint32 dwRegType, dwSwizzle;
  889. uint32 dwSrcModifier = D3DSPSM_NONE;
  890. // Clear string to zero length
  891. V_snprintf( pRegisterName, nBufLen, "" );
  892. dwRegType = GetRegTypeFromToken( dwToken );
  893. // If this is a dest register
  894. if ( dwSourceOrDest == DST_REGISTER )
  895. {
  896. // Instruction modifiers
  897. if ( dwToken & D3DSPDM_PARTIALPRECISION )
  898. {
  899. // strcat_s( pRegisterName, nBufLen, "_pp" );
  900. }
  901. if ( dwToken & D3DSPDM_SATURATE && !m_bGLSL )
  902. {
  903. strcat_s( pRegisterName, nBufLen, "_SAT" );
  904. }
  905. if ( dwToken & D3DSPDM_MSAMPCENTROID)
  906. {
  907. // strcat_s( pRegisterName, nBufLen, "_centroid" );
  908. }
  909. if ( !m_bGLSL )
  910. {
  911. strcat_s( pRegisterName, nBufLen, " " );
  912. }
  913. }
  914. // If this is a source register
  915. if ( dwSourceOrDest == SRC_REGISTER )
  916. {
  917. dwSrcModifier = dwToken & D3DSP_SRCMOD_MASK;
  918. // If there are any source modifiers, check to see if they're at
  919. // least partially "prefix" and prepend appropriately
  920. if ( dwSrcModifier != D3DSPSM_NONE )
  921. {
  922. switch ( dwSrcModifier )
  923. {
  924. // These four start with just minus... (some may result in "postfix" notation as well later on)
  925. case D3DSPSM_NEG: // negate
  926. strcat_s( pRegisterName, nBufLen, "-" );
  927. break;
  928. case D3DSPSM_BIASNEG: // bias and negate
  929. case D3DSPSM_SIGNNEG: // sign and negate
  930. case D3DSPSM_X2NEG: // *2 and negate
  931. DebuggerBreakIfDebugging();
  932. strcat_s( pRegisterName, nBufLen, "-" );
  933. break;
  934. case D3DSPSM_COMP: // complement
  935. DebuggerBreakIfDebugging();
  936. strcat_s( pRegisterName, nBufLen, "1-" );
  937. break;
  938. case D3DSPSM_ABS: // abs()
  939. if ( m_bGLSL )
  940. {
  941. strcat_s( pRegisterName, nBufLen, "abs(" );
  942. }
  943. else if ( !m_bGeneratingDebugText )
  944. {
  945. DebuggerBreakIfDebugging();
  946. }
  947. break;
  948. case D3DSPSM_ABSNEG: // -abs()
  949. if ( m_bGLSL )
  950. {
  951. strcat_s( pRegisterName, nBufLen, "-abs(" );
  952. }
  953. else if ( !m_bGeneratingDebugText )
  954. {
  955. DebuggerBreakIfDebugging();
  956. }
  957. break;
  958. case D3DSPSM_NOT: // for predicate register: "!p0"
  959. DebuggerBreakIfDebugging();
  960. strcat_s( pRegisterName, nBufLen, "!" );
  961. break;
  962. }
  963. }
  964. }
  965. // Register name (from type and number)
  966. switch ( dwRegType )
  967. {
  968. case D3DSPR_TEMP:
  969. V_snprintf( buff, sizeof( buff ), "r%d", dwRegNum );
  970. strcat_s( pRegisterName, nBufLen, buff );
  971. m_dwTempUsageMask |= 0x00000001 << dwRegNum; // Keep track of the use of this temp
  972. break;
  973. case D3DSPR_INPUT:
  974. if ( !m_bVertexShader && ( dwSourceOrDest == SRC_REGISTER ) && m_bGLSL )
  975. {
  976. V_snprintf( buff, sizeof( buff ), dwRegNum == 0 ? "gl_Color" : "gl_SecondaryColor" );
  977. strcat_s( pRegisterName, nBufLen, buff );
  978. }
  979. else if ( m_bVertexShader || ( dwSourceOrDest == SRC_REGISTER ) || m_bGLSL )
  980. {
  981. V_snprintf( buff, sizeof( buff ), "v%d", dwRegNum );
  982. strcat_s( pRegisterName, nBufLen, buff );
  983. }
  984. else // asm pixel shader declaration syntax:
  985. {
  986. V_snprintf( buff, sizeof( buff ), dwRegNum == 0 ? "v0 = fragment.color" : "v1 = fragment.color.secondary" );
  987. strcat_s( pRegisterName, nBufLen, buff );
  988. bAllowWriteMask = false;
  989. }
  990. break;
  991. case D3DSPR_CONST:
  992. if ( m_bConstantRegisterDefined[dwRegNum] )
  993. {
  994. char szConstantRegName[3];
  995. if ( m_bVertexShader )
  996. {
  997. V_snprintf( szConstantRegName, 3, "vd" );
  998. }
  999. else
  1000. {
  1001. V_snprintf( szConstantRegName, 3, "pd" );
  1002. }
  1003. // Put defined constants into their own namespace "d"
  1004. V_snprintf( buff, sizeof( buff ), "%s%d", szConstantRegName, dwRegNum );
  1005. strcat_s( pRegisterName, nBufLen, buff );
  1006. }
  1007. else if ( dwToken & D3DSHADER_ADDRESSMODE_MASK ) // Indirect addressing (e.g. skinning in a vertex shader)
  1008. {
  1009. char szConstantRegName[3];
  1010. if ( m_bVertexShader )
  1011. {
  1012. V_snprintf( szConstantRegName, 3, "vc" );
  1013. }
  1014. else // No indirect addressing in PS, this shouldn't happen
  1015. {
  1016. DebuggerBreakIfDebugging();
  1017. V_snprintf( szConstantRegName, 3, "pc" );
  1018. }
  1019. // Index into single pc/vc[] register array with relative addressing
  1020. FlagIndirectRegister( GetNextToken(), pARLDestReg );
  1021. V_snprintf( buff, sizeof( buff ), m_bGLSL ? "%s[a0 + %d]" : "%s[a0.x + %d]", szConstantRegName, dwRegNum );
  1022. strcat_s( pRegisterName, nBufLen, buff );
  1023. bAllowSwizzle = false;
  1024. m_nHighestRegister = DXABSTRACT_VS_PARAM_SLOTS - 1;
  1025. }
  1026. else // Direct addressing of constant array
  1027. {
  1028. char szConstantRegName[3];
  1029. V_snprintf( szConstantRegName, 3, m_bVertexShader ? "vc" : "pc" );
  1030. // Index into single pc/vc[] register array with absolute addressing, same for GLSL and ASM
  1031. V_snprintf( buff, sizeof( buff ), "%s[%d]", szConstantRegName, dwRegNum );
  1032. strcat_s( pRegisterName, nBufLen, buff );
  1033. //// NOGO if (dwRegNum != 255) // have seen cases where dwRegNum is 0xFF... need to figure out where those opcodes are coming from
  1034. {
  1035. m_nHighestRegister = MAX( m_nHighestRegister, dwRegNum );
  1036. }
  1037. Assert( m_nHighestRegister < DXABSTRACT_VS_PARAM_SLOTS );
  1038. }
  1039. break;
  1040. case D3DSPR_ADDR: // aliases to D3DSPR_TEXTURE
  1041. if ( m_bVertexShader )
  1042. {
  1043. if ( m_bGLSL )
  1044. {
  1045. Assert( dwRegNum == 0 );
  1046. V_snprintf( buff, sizeof( buff ), "va_r", dwRegNum );
  1047. }
  1048. else
  1049. {
  1050. V_snprintf( buff, sizeof( buff ), "VA_REG" ); // Move into our temp, rather than a0
  1051. }
  1052. }
  1053. else // D3DSPR_TEXTURE in the pixel shader
  1054. {
  1055. // If dest reg, this is an iterator/varying declaration
  1056. if ( dwSourceOrDest == DST_REGISTER )
  1057. {
  1058. if ( m_bGLSL )
  1059. {
  1060. // Is this iterator centroid?
  1061. if ( m_nCentroidMask & ( 0x00000001 << dwRegNum ) )
  1062. {
  1063. V_snprintf( buff, sizeof( buff ), "centroid varying vec4 oT%d", dwRegNum ); // centroid varying
  1064. }
  1065. else
  1066. {
  1067. V_snprintf( buff, sizeof( buff ), "varying vec4 oT%d", dwRegNum );
  1068. }
  1069. }
  1070. else
  1071. {
  1072. V_snprintf( buff, sizeof( buff ), "t%d = fragment.texcoord[%d]", dwRegNum, dwRegNum );
  1073. }
  1074. bAllowWriteMask = false;
  1075. }
  1076. else // source register
  1077. {
  1078. if ( m_bGLSL )
  1079. {
  1080. V_snprintf( buff, sizeof( buff ), "oT%d", dwRegNum );
  1081. }
  1082. else
  1083. {
  1084. V_snprintf( buff, sizeof( buff ), "t%d", dwRegNum );
  1085. }
  1086. }
  1087. }
  1088. strcat_s( pRegisterName, nBufLen, buff );
  1089. break;
  1090. case D3DSPR_RASTOUT: // vertex shader oPos
  1091. Assert( m_bVertexShader );
  1092. switch( dwRegNum )
  1093. {
  1094. case D3DSRO_POSITION:
  1095. strcat_s( pRegisterName, nBufLen, m_bGLSL ? "vTempPos" : "oPos" ); // In GLSL, this ends up in gl_Position later on
  1096. m_bDeclareVSOPos = true;
  1097. break;
  1098. case D3DSRO_FOG:
  1099. strcat_s( pRegisterName, nBufLen, m_bGLSL ? "gl_FogFragCoord" : "oFog" );
  1100. m_bDeclareVSOFog = true;
  1101. break;
  1102. default:
  1103. printf( "\nD3DSPR_RASTOUT: dwRegNum is %08x and token is %08x", dwRegNum, dwToken );
  1104. DebuggerBreakIfDebugging();
  1105. break;
  1106. }
  1107. break;
  1108. case D3DSPR_ATTROUT:
  1109. Assert( m_bVertexShader );
  1110. if ( m_bGLSL )
  1111. {
  1112. if ( dwRegNum == 0 )
  1113. {
  1114. V_snprintf( buff, sizeof( buff ), "gl_FrontColor", dwRegNum );
  1115. }
  1116. else if ( dwRegNum == 1 )
  1117. {
  1118. V_snprintf( buff, sizeof( buff ), "gl_FrontSecondaryColor", dwRegNum );
  1119. }
  1120. else
  1121. {
  1122. Error( "Invalid D3DSPR_ATTROUT index" );
  1123. }
  1124. }
  1125. else
  1126. {
  1127. V_snprintf( buff, sizeof( buff ), "oD%d", dwRegNum );
  1128. }
  1129. strcat_s( pRegisterName, nBufLen, buff );
  1130. m_bOutputColorRegister[dwRegNum] = true;
  1131. break;
  1132. case D3DSPR_TEXCRDOUT: // aliases to D3DSPR_OUTPUT
  1133. if ( m_bVertexShader )
  1134. {
  1135. if ( m_bGLSL )
  1136. {
  1137. V_snprintf( buff, sizeof( buff ), "oT%d", dwRegNum );
  1138. }
  1139. else
  1140. {
  1141. V_snprintf( buff, sizeof( buff ), "oT%d", dwRegNum );
  1142. }
  1143. m_dwTexCoordOutMask |= ( 0x00000001 << dwRegNum );
  1144. }
  1145. else
  1146. {
  1147. V_snprintf( buff, sizeof( buff ), "oC%d", dwRegNum );
  1148. }
  1149. strcat_s( pRegisterName, nBufLen, buff );
  1150. break;
  1151. case D3DSPR_CONSTINT:
  1152. Assert( m_bGLSL && m_bAllowStaticControlFlow );
  1153. V_snprintf( buff, sizeof( buff ), "i%d", dwRegNum ); // Loops use these
  1154. strcat_s( pRegisterName, nBufLen, buff );
  1155. m_dwConstIntUsageMask |= 0x00000001 << dwRegNum; // Keep track of the use of this integer constant
  1156. break;
  1157. case D3DSPR_COLOROUT:
  1158. if ( m_bGLSL )
  1159. {
  1160. V_snprintf( buff, sizeof( buff ), "gl_FragData[%d]", dwRegNum );
  1161. }
  1162. else
  1163. {
  1164. V_snprintf( buff, sizeof( buff ), "oC%d", dwRegNum );
  1165. }
  1166. strcat_s( pRegisterName, nBufLen, buff );
  1167. m_bOutputColorRegister[dwRegNum] = true;
  1168. break;
  1169. case D3DSPR_DEPTHOUT:
  1170. V_snprintf( buff, sizeof( buff ), m_bGLSL ? "gl_FragDepth" : "oDepth" );
  1171. strcat_s( pRegisterName, nBufLen, buff );
  1172. m_bOutputDepthRegister = true;
  1173. break;
  1174. case D3DSPR_SAMPLER:
  1175. V_snprintf( buff, sizeof( buff ), m_bGLSL ? "sampler%d" : "texture[%d]", dwRegNum );
  1176. strcat_s( pRegisterName, nBufLen, buff );
  1177. break;
  1178. case D3DSPR_CONST2:
  1179. DebuggerBreakIfDebugging();
  1180. V_snprintf( buff, sizeof( buff ), "c%d", dwRegNum+2048);
  1181. strcat_s( pRegisterName, nBufLen, buff );
  1182. break;
  1183. case D3DSPR_CONST3:
  1184. DebuggerBreakIfDebugging();
  1185. V_snprintf( buff, sizeof( buff ), "c%d", dwRegNum+4096);
  1186. strcat_s( pRegisterName, nBufLen, buff );
  1187. break;
  1188. case D3DSPR_CONST4:
  1189. DebuggerBreakIfDebugging();
  1190. V_snprintf( buff, sizeof( buff ), "c%d", dwRegNum+6144);
  1191. strcat_s( pRegisterName, nBufLen, buff );
  1192. break;
  1193. case D3DSPR_CONSTBOOL:
  1194. Assert( m_bGLSL && m_bAllowStaticControlFlow );
  1195. V_snprintf( buff, sizeof( buff ), "b%d", dwRegNum );
  1196. strcat_s( pRegisterName, nBufLen, buff );
  1197. m_dwConstBoolUsageMask |= 0x00000001 << dwRegNum; // Keep track of the use of this bool constant
  1198. break;
  1199. case D3DSPR_LOOP:
  1200. DebuggerBreakIfDebugging();
  1201. V_snprintf( buff, sizeof( buff ), "aL%d", dwRegNum );
  1202. strcat_s( pRegisterName, nBufLen, buff );
  1203. break;
  1204. case D3DSPR_TEMPFLOAT16:
  1205. DebuggerBreakIfDebugging();
  1206. V_snprintf( buff, sizeof( buff ), "temp_float16_xxx%d", dwRegNum );
  1207. strcat_s( pRegisterName, nBufLen, buff );
  1208. break;
  1209. case D3DSPR_MISCTYPE:
  1210. if ( !m_bGLSL && !m_bGeneratingDebugText )
  1211. {
  1212. DebuggerBreakIfDebugging();
  1213. }
  1214. V_snprintf( buff, sizeof( buff ), "misc%d", dwRegNum );
  1215. strcat_s( pRegisterName, nBufLen, buff );
  1216. break;
  1217. case D3DSPR_LABEL:
  1218. DebuggerBreakIfDebugging();
  1219. V_snprintf( buff, sizeof( buff ), "label%d", dwRegNum );
  1220. strcat_s( pRegisterName, nBufLen, buff );
  1221. break;
  1222. case D3DSPR_PREDICATE:
  1223. DebuggerBreakIfDebugging();
  1224. V_snprintf( buff, sizeof( buff ), "p%d", dwRegNum );
  1225. strcat_s( pRegisterName, nBufLen, buff );
  1226. break;
  1227. }
  1228. // If this is a dest register
  1229. if ( dwSourceOrDest == DST_REGISTER )
  1230. {
  1231. //
  1232. // Write masks
  1233. //
  1234. // If some (not all, not none) of the write masks are set, we should include them
  1235. //
  1236. if ( bAllowWriteMask && ( !((dwToken & D3DSP_WRITEMASK_ALL) == D3DSP_WRITEMASK_ALL) || ((dwToken & D3DSP_WRITEMASK_ALL) == 0x00000000) ) )
  1237. {
  1238. // Put the dot on there
  1239. strcat_s( pRegisterName, nBufLen, "." );
  1240. // Optionally put on the x, y, z or w
  1241. int nMasksWritten = 0;
  1242. if ( dwToken & D3DSP_WRITEMASK_0 )
  1243. {
  1244. strcat_s( pRegisterName, nBufLen, "x" );
  1245. ++nMasksWritten;
  1246. }
  1247. if ( dwToken & D3DSP_WRITEMASK_1 )
  1248. {
  1249. strcat_s( pRegisterName, nBufLen, "y" );
  1250. ++nMasksWritten;
  1251. }
  1252. if ( dwToken & D3DSP_WRITEMASK_2 )
  1253. {
  1254. strcat_s( pRegisterName, nBufLen, "z" );
  1255. ++nMasksWritten;
  1256. }
  1257. if ( dwToken & D3DSP_WRITEMASK_3 )
  1258. {
  1259. strcat_s( pRegisterName, nBufLen, "w" );
  1260. ++nMasksWritten;
  1261. }
  1262. }
  1263. }
  1264. else // must be a source register
  1265. {
  1266. if ( bAllowSwizzle ) // relative addressing hard-codes the swizzle on a0.x
  1267. {
  1268. uint32 dwXSwizzle, dwYSwizzle, dwZSwizzle, dwWSwizzle;
  1269. // Mask out the swizzle modifier
  1270. dwSwizzle = dwToken & D3DVS_SWIZZLE_MASK;
  1271. // If there are any swizzles at all, tack on the appropriate notation
  1272. if ( dwSwizzle != D3DVS_NOSWIZZLE )
  1273. {
  1274. // Separate out the two-bit codes for each component swizzle
  1275. dwXSwizzle = dwSwizzle & D3DVS_X_W;
  1276. dwYSwizzle = dwSwizzle & D3DVS_Y_W;
  1277. dwZSwizzle = dwSwizzle & D3DVS_Z_W;
  1278. dwWSwizzle = dwSwizzle & D3DVS_W_W;
  1279. // Put on the dot
  1280. strcat_s( pRegisterName, nBufLen, "." );
  1281. // See where X comes from
  1282. switch ( dwXSwizzle )
  1283. {
  1284. case D3DVS_X_X:
  1285. strcat_s( pRegisterName, nBufLen, "x" );
  1286. break;
  1287. case D3DVS_X_Y:
  1288. strcat_s( pRegisterName, nBufLen, "y" );
  1289. break;
  1290. case D3DVS_X_Z:
  1291. strcat_s( pRegisterName, nBufLen, "z" );
  1292. break;
  1293. case D3DVS_X_W:
  1294. strcat_s( pRegisterName, nBufLen, "w" );
  1295. break;
  1296. }
  1297. if ( !bForceScalarSource )
  1298. {
  1299. // If the source of the remaining components are aren't
  1300. // identical to the source of x, continue with swizzle
  1301. if ( ((dwXSwizzle >> D3DVS_SWIZZLE_SHIFT) != (dwYSwizzle >> (D3DVS_SWIZZLE_SHIFT + 2))) || // X and Y sources match?
  1302. ((dwXSwizzle >> D3DVS_SWIZZLE_SHIFT) != (dwZSwizzle >> (D3DVS_SWIZZLE_SHIFT + 4))) || // X and Z sources match?
  1303. ((dwXSwizzle >> D3DVS_SWIZZLE_SHIFT) != (dwWSwizzle >> (D3DVS_SWIZZLE_SHIFT + 6)))) // X and W sources match?
  1304. {
  1305. // OpenGL seems to want us to have either 1 or 4 components in a swizzle, so just plow on through the rest
  1306. switch ( dwYSwizzle )
  1307. {
  1308. case D3DVS_Y_X:
  1309. strcat_s( pRegisterName, nBufLen, "x" );
  1310. break;
  1311. case D3DVS_Y_Y:
  1312. strcat_s( pRegisterName, nBufLen, "y" );
  1313. break;
  1314. case D3DVS_Y_Z:
  1315. strcat_s( pRegisterName, nBufLen, "z" );
  1316. break;
  1317. case D3DVS_Y_W:
  1318. strcat_s( pRegisterName, nBufLen, "w" );
  1319. break;
  1320. }
  1321. switch ( dwZSwizzle )
  1322. {
  1323. case D3DVS_Z_X:
  1324. strcat_s( pRegisterName, nBufLen, "x" );
  1325. break;
  1326. case D3DVS_Z_Y:
  1327. strcat_s( pRegisterName, nBufLen, "y" );
  1328. break;
  1329. case D3DVS_Z_Z:
  1330. strcat_s( pRegisterName, nBufLen, "z" );
  1331. break;
  1332. case D3DVS_Z_W:
  1333. strcat_s( pRegisterName, nBufLen, "w" );
  1334. break;
  1335. }
  1336. switch ( dwWSwizzle )
  1337. {
  1338. case D3DVS_W_X:
  1339. strcat_s( pRegisterName, nBufLen, "x" );
  1340. break;
  1341. case D3DVS_W_Y:
  1342. strcat_s( pRegisterName, nBufLen, "y" );
  1343. break;
  1344. case D3DVS_W_Z:
  1345. strcat_s( pRegisterName, nBufLen, "z" );
  1346. break;
  1347. case D3DVS_W_W:
  1348. strcat_s( pRegisterName, nBufLen, "w" );
  1349. break;
  1350. }
  1351. }
  1352. } // end !bForceScalarSource
  1353. }
  1354. else // dwSwizzle == D3DVS_NOSWIZZLE
  1355. {
  1356. // If this is a MOVA / ARL, GL on the Mac requires us to tack the .x onto the source register
  1357. if ( bForceScalarSource )
  1358. {
  1359. strcat_s( pRegisterName, nBufLen, ".x" );
  1360. }
  1361. }
  1362. } // bAllowSwizzle
  1363. // If there are any source modifiers, check to see if they're at
  1364. // least partially "postfix" and tack them on as appropriate
  1365. if ( dwSrcModifier != D3DSPSM_NONE )
  1366. {
  1367. switch ( dwSrcModifier )
  1368. {
  1369. case D3DSPSM_BIAS: // bias
  1370. case D3DSPSM_BIASNEG: // bias and negate
  1371. DebuggerBreakIfDebugging();
  1372. strcat_s( pRegisterName, nBufLen, "_bx2" );
  1373. break;
  1374. case D3DSPSM_SIGN: // sign
  1375. case D3DSPSM_SIGNNEG: // sign and negate
  1376. DebuggerBreakIfDebugging();
  1377. strcat_s( pRegisterName, nBufLen, "_sgn" );
  1378. break;
  1379. case D3DSPSM_X2: // *2
  1380. case D3DSPSM_X2NEG: // *2 and negate
  1381. DebuggerBreakIfDebugging();
  1382. strcat_s( pRegisterName, nBufLen, "_x2" );
  1383. break;
  1384. case D3DSPSM_ABS: // abs()
  1385. case D3DSPSM_ABSNEG: // -abs()
  1386. if ( m_bGLSL )
  1387. {
  1388. strcat_s( pRegisterName, nBufLen, ")" );
  1389. }
  1390. break;
  1391. case D3DSPSM_DZ: // divide through by z component
  1392. DebuggerBreakIfDebugging();
  1393. strcat_s( pRegisterName, nBufLen, "_dz" );
  1394. break;
  1395. case D3DSPSM_DW: // divide through by w component
  1396. DebuggerBreakIfDebugging();
  1397. strcat_s( pRegisterName, nBufLen, "_dw" );
  1398. break;
  1399. }
  1400. } // end postfix modifiers (really only ps.1.x)
  1401. }
  1402. }
  1403. void D3DToGL::RecordInputAndOutputPositions()
  1404. {
  1405. // Remember where we are in the token stream.
  1406. m_pRecordedInputTokenStart = m_pdwNextToken;
  1407. // Remember where our outputs are.
  1408. m_nRecordedParamCodeStrlen = V_strlen( (char*)m_pBufParamCode->Base() );
  1409. m_nRecordedALUCodeStrlen = V_strlen( (char*)m_pBufALUCode->Base() );
  1410. m_nRecordedAttribCodeStrlen = V_strlen( (char*)m_pBufAttribCode->Base() );
  1411. }
  1412. void D3DToGL::AddTokenHexCodeToBuffer( char *pBuffer, int nSize, int nLastStrlen )
  1413. {
  1414. int nCurStrlen = V_strlen( pBuffer );
  1415. if ( nCurStrlen == nLastStrlen )
  1416. return;
  1417. // Build a string with all the hex codes of the tokens since last time.
  1418. char szHex[512];
  1419. szHex[0] = '\n';
  1420. V_snprintf( &szHex[1], sizeof( szHex )-1, HEXCODE_HEADER );
  1421. int nTokens = MIN( 10, m_pdwNextToken - m_pRecordedInputTokenStart );
  1422. for ( int i=0; i < nTokens; i++ )
  1423. {
  1424. char szTemp[32];
  1425. V_snprintf( szTemp, sizeof( szTemp ), "0x%x ", m_pRecordedInputTokenStart[i] );
  1426. V_strncat( szHex, szTemp, sizeof( szHex ) );
  1427. }
  1428. V_strncat( szHex, "\n", sizeof( szHex ) );
  1429. // Insert the hex codes into the string.
  1430. int nBytesToInsert = V_strlen( szHex );
  1431. if ( nCurStrlen + nBytesToInsert + 1 >= nSize )
  1432. Error( "Buffer overflow writing token hex codes" );
  1433. if ( m_bPutHexCodesAfterLines )
  1434. {
  1435. // Put it at the end of the last line.
  1436. if ( pBuffer[nCurStrlen-1] == '\n' )
  1437. pBuffer[nCurStrlen-1] = 0;
  1438. V_strncat( pBuffer, &szHex[1], nSize );
  1439. }
  1440. else
  1441. {
  1442. memmove( pBuffer + nLastStrlen + nBytesToInsert, pBuffer + nLastStrlen, nCurStrlen - nLastStrlen + 1 );
  1443. memcpy( pBuffer + nLastStrlen, szHex, nBytesToInsert );
  1444. }
  1445. }
  1446. void D3DToGL::AddTokenHexCode()
  1447. {
  1448. if ( m_pdwNextToken > m_pRecordedInputTokenStart )
  1449. {
  1450. AddTokenHexCodeToBuffer( (char*)m_pBufParamCode->Base(), m_pBufParamCode->Size(), m_nRecordedParamCodeStrlen );
  1451. AddTokenHexCodeToBuffer( (char*)m_pBufALUCode->Base(), m_pBufALUCode->Size(), m_nRecordedALUCodeStrlen );
  1452. AddTokenHexCodeToBuffer( (char*)m_pBufAttribCode->Base(), m_pBufAttribCode->Size(), m_nRecordedAttribCodeStrlen );
  1453. }
  1454. }
  1455. uint32 D3DToGL::MaintainAttributeMap( uint32 dwToken, uint32 dwRegToken )
  1456. {
  1457. // Check that this reg index has not been used before - if it has, let Houston know
  1458. uint dwRegIndex = dwRegToken & D3DSP_REGNUM_MASK;
  1459. if ( m_dwAttribMap[ dwRegIndex ] == 0xFFFFFFFF )
  1460. {
  1461. // log it
  1462. // semantic/usage in the higher nibble
  1463. // usage index in the low nibble
  1464. uint usage = dwToken & D3DSP_DCL_USAGE_MASK;
  1465. uint usageindex = ( dwToken & D3DSP_DCL_USAGEINDEX_MASK ) >> D3DSP_DCL_USAGEINDEX_SHIFT;
  1466. m_dwAttribMap[ dwRegIndex ] = ( usage << 4 ) | usageindex;
  1467. // avoid writing 0xBB since runtime code uses that for an 'unused' marker
  1468. if ( m_dwAttribMap[ dwRegIndex ] == 0xBB )
  1469. {
  1470. Debugger();
  1471. }
  1472. }
  1473. else
  1474. {
  1475. //not OK
  1476. Debugger();
  1477. }
  1478. return dwRegIndex;
  1479. }
  1480. void D3DToGL::Handle_DCL()
  1481. {
  1482. uint32 dwToken = GetNextToken(); // What kind of dcl is this...
  1483. uint32 dwRegToken = GetNextToken(); // Look ahead to register token
  1484. if ( m_bVertexShader )
  1485. {
  1486. // If this is an output, remember the index (what the ASM code calls o0, o1, o2..) and the semantic.
  1487. // When GetParameterString( DST_REGISTER ) hits this one, we'll return "oN".
  1488. // At the end of the main() function, we'll insert a bunch of statements like "gl_Color = o2" based on what we remembered here.
  1489. if ( m_bGLSL )
  1490. {
  1491. if ( m_dwMajorVersion >= 3 && GetRegTypeFromToken( dwRegToken ) == D3DSPR_OUTPUT )
  1492. {
  1493. uint32 dwRegNum = dwRegToken & D3DSP_REGNUM_MASK;
  1494. if ( dwRegNum >= MAX_DECLARED_OUTPUTS )
  1495. Error( "Output register number (%d) too high (only %d supported).", dwRegNum, MAX_DECLARED_OUTPUTS );
  1496. if ( m_DeclaredOutputs[dwRegNum] != UNDECLARED_OUTPUT )
  1497. Error( "Output dcl_ hit for register #%d more than once!", dwRegNum );
  1498. Assert( dwToken != UNDECLARED_OUTPUT );
  1499. m_DeclaredOutputs[dwRegNum] = dwToken;
  1500. if ( m_bAddHexCodeComments )
  1501. {
  1502. CUtlString sParam2 = GetUsageAndIndexString( dwToken, SEMANTIC_OUTPUT );
  1503. PrintToBuf( *m_pBufHeaderCode, "// [GL remembering that o%d maps to %s]\n", dwRegNum, sParam2.String() );
  1504. }
  1505. PrintToBuf( *m_pBufHeaderCode, "varying vec4 o%d = vec4( 0.0, 0.0, 0.0, 0.0 );\n", dwRegNum );
  1506. }
  1507. else
  1508. {
  1509. CUtlString sParam1 = GetParameterString( dwRegToken, DST_REGISTER, false, NULL );
  1510. CUtlString sParam2 = GetUsageAndIndexString( dwToken, SEMANTIC_INPUT );
  1511. sParam2 = FixGLSLSwizzle( sParam1, sParam2 );
  1512. PrintToBuf( *m_pBufHeaderCode, "attribute vec4 %s; // ", sParam1.String() );
  1513. MaintainAttributeMap( dwToken, dwRegToken );
  1514. char temp[128];
  1515. // regnum goes straight into the vertex.attrib[n] index
  1516. sprintf( temp, "%08x %08x\n", dwToken, dwRegToken );
  1517. StrcatToHeaderCode( temp );
  1518. }
  1519. }
  1520. else // ARB_vertex_program ASM
  1521. {
  1522. StrcatToAttribCode( "ATTRIB" );
  1523. char buff[64];
  1524. PrintParameterToString( dwRegToken, DST_REGISTER, buff, sizeof( buff ), false, NULL );
  1525. StrcatToAttribCode( buff );
  1526. StrcatToAttribCode( " = " );
  1527. uint regIndex = MaintainAttributeMap( dwToken, dwRegToken );
  1528. char temp[128];
  1529. // regnum goes straight into the vertex.attrib[n] index
  1530. sprintf( temp, "vertex.attrib[%d]; # %08x %08x\n", regIndex, dwToken, dwRegToken );
  1531. StrcatToAttribCode( temp );
  1532. // ASM
  1533. // CUtlString sParam1 = GetParameterString( dwRegToken, DST_REGISTER );
  1534. // CUtlString sParam2 = GetUsageAndIndexString( dwToken, SEMANTIC_INPUT );
  1535. // PrintToBuf( m_pAttribCode, m_nAttribCodeBufSize, "ATTRIB%s = %s;\n", sParam1.String(), sParam2.String() );
  1536. }
  1537. }
  1538. else // Pixel shader
  1539. {
  1540. // If the register is a sampler, the dcl has a dimension decorator that we have to save for subsequent TEX instructions
  1541. uint32 nRegType = GetRegType( dwRegToken );
  1542. if ( nRegType == D3DSPR_SAMPLER )
  1543. {
  1544. int nRegNum = dwRegToken & D3DSP_REGNUM_MASK;
  1545. switch ( TextureType( dwToken ) )
  1546. {
  1547. default:
  1548. case D3DSTT_UNKNOWN:
  1549. case D3DSTT_2D:
  1550. m_dwSamplerTypes[nRegNum] = SAMPLER_TYPE_2D;
  1551. break;
  1552. case D3DSTT_CUBE:
  1553. m_dwSamplerTypes[nRegNum] = SAMPLER_TYPE_CUBE;
  1554. break;
  1555. case D3DSTT_VOLUME:
  1556. m_dwSamplerTypes[nRegNum] = SAMPLER_TYPE_3D;
  1557. break;
  1558. }
  1559. // Track sampler declarations
  1560. m_dwSamplerUsageMask |= 1 << nRegNum;
  1561. }
  1562. else // Not a sampler, we're going to generate vaying declaration code
  1563. {
  1564. if ( m_bGLSL )
  1565. {
  1566. // In pixel shaders we only declare texture coordinate varyings since they may be using centroid
  1567. if ( (!m_bVertexShader) && ( GetRegType( dwRegToken ) == D3DSPR_TEXTURE ) )
  1568. {
  1569. char buff[256];
  1570. PrintParameterToString( dwRegToken, DST_REGISTER, buff, sizeof( buff ), false, NULL );
  1571. PrintToBuf( *m_pBufHeaderCode, "%s;\n",buff );
  1572. }
  1573. }
  1574. else // asm
  1575. {
  1576. char buff[256];
  1577. PrintParameterToString( dwRegToken, DST_REGISTER, buff, sizeof( buff ), false, NULL );
  1578. PrintToBuf( *m_pBufAttribCode, "ATTRIB%s;\n", buff );
  1579. }
  1580. }
  1581. }
  1582. }
  1583. void D3DToGL::Handle_DEF()
  1584. {
  1585. //
  1586. // JasonM TODO: catch D3D's sincos-specific D3DSINCOSCONST1 and D3DSINCOSCONST2 constants and filter them out here
  1587. //
  1588. // Which register is being defined
  1589. uint32 dwToken = GetNextToken();
  1590. // Note that this constant was explicitly defined
  1591. m_bConstantRegisterDefined[dwToken & D3DSP_REGNUM_MASK] = true;
  1592. CUtlString sParamName = GetParameterString( dwToken, DST_REGISTER, false, NULL );
  1593. const char float_fmt[] = "%.12f";
  1594. const char float_fmt_commaspace[] = "%.12f, "; // %g causes GLSL compile problems around consts like "1e+2.0" - try %f
  1595. if ( m_bGLSL )
  1596. {
  1597. PrintToBuf( *m_pBufParamCode, "vec4 %s = vec4( ", sParamName.String() );
  1598. // Run through the 4 floats
  1599. for ( int i=0; i < 4; i++ )
  1600. {
  1601. float fConst = uint32ToFloat( GetNextToken() );
  1602. // It must have a decimal point.
  1603. char szTemp[256];
  1604. V_snprintf( szTemp, sizeof( szTemp ), float_fmt, fConst );
  1605. StripExtraTrailingZeros( szTemp ); // Turn 1.00000 into 1.0
  1606. if ( !strchr( szTemp, '.' ) )
  1607. {
  1608. V_strncat( szTemp, ".0", sizeof( szTemp ) );
  1609. }
  1610. PrintToBuf( *m_pBufParamCode, i != 3 ? "%s, " : "%s", szTemp ); // end with comma-space
  1611. }
  1612. PrintToBuf( *m_pBufParamCode, " );\n" );
  1613. }
  1614. else
  1615. {
  1616. PrintToBuf( *m_pBufParamCode, "PARAM%s = { ", sParamName.String() );
  1617. // Run through the 4 floats
  1618. for ( int i=0; i < 4; i++ )
  1619. {
  1620. float fConst = uint32ToFloat( GetNextToken() );
  1621. PrintToBuf( *m_pBufParamCode, i != 3 ? float_fmt_commaspace : float_fmt, fConst ); // end with comma-space
  1622. }
  1623. PrintToBuf( *m_pBufParamCode, " };\n" );
  1624. }
  1625. }
  1626. void D3DToGL::Handle_MAD( uint32 nInstruction )
  1627. {
  1628. uint32 nDestToken = GetNextToken();
  1629. CUtlString sParam1 = GetParameterString( nDestToken, DST_REGISTER, false, NULL );
  1630. int nARLComp0 = ARL_DEST_NONE;
  1631. CUtlString sParam2 = GetParameterString( GetNextToken(), SRC_REGISTER, false, &nARLComp0 );
  1632. int nARLComp1 = ARL_DEST_NONE;
  1633. CUtlString sParam3 = GetParameterString( GetNextToken(), SRC_REGISTER, false, &nARLComp1 );
  1634. int nARLComp2 = ARL_DEST_NONE;
  1635. CUtlString sParam4 = GetParameterString( GetNextToken(), SRC_REGISTER, false, &nARLComp2 );
  1636. // This optionally inserts a move from our dummy address register to the .x component of the real one
  1637. InsertMoveFromAddressRegister( m_pBufALUCode, nARLComp0, nARLComp1, nARLComp2 );
  1638. if ( m_bGLSL )
  1639. {
  1640. sParam2 = FixGLSLSwizzle( sParam1, sParam2 );
  1641. sParam3 = FixGLSLSwizzle( sParam1, sParam3 );
  1642. sParam4 = FixGLSLSwizzle( sParam1, sParam4 );
  1643. PrintToBuf( *m_pBufALUCode, "%s = %s * %s + %s;\n", sParam1.String(), sParam2.String(), sParam3.String(), sParam4.String() );
  1644. // If the _SAT instruction modifier is used, then do a saturate here.
  1645. if ( nDestToken & D3DSPDM_SATURATE )
  1646. {
  1647. int nComponents = GetNumSwizzleComponents( sParam1.String() );
  1648. if ( nComponents == 0 )
  1649. nComponents = 4;
  1650. PrintToBuf( *m_pBufALUCode, "%s = clamp( %s, %s, %s );\n", sParam1.String(), sParam1.String(), g_szVecZeros[nComponents], g_szVecOnes[nComponents] );
  1651. }
  1652. }
  1653. else
  1654. {
  1655. char buff[256];
  1656. PrintOpcode( nInstruction, buff, sizeof( buff ) );
  1657. PrintToBuf( *m_pBufALUCode, "%s%s, %s, %s, %s;\n", buff, sParam1.String(), sParam2.String(), sParam3.String(), sParam4.String() );
  1658. if ( nDestToken & D3DSPDM_SATURATE )
  1659. {
  1660. // Need to saturate asm!
  1661. DebuggerBreakIfDebugging();
  1662. }
  1663. }
  1664. }
  1665. void D3DToGL::Handle_DP2ADD()
  1666. {
  1667. char pDestReg[16], pSrc0Reg[16], pSrc1Reg[16], pSrc2Reg[16];
  1668. uint32 nDestToken = GetNextToken();
  1669. PrintParameterToString( nDestToken, DST_REGISTER, pDestReg, sizeof( pDestReg ), false, NULL );
  1670. PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc0Reg, sizeof( pSrc0Reg ), false, NULL );
  1671. PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc1Reg, sizeof( pSrc1Reg ), false, NULL );
  1672. PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc2Reg, sizeof( pSrc2Reg ), false, NULL );
  1673. if ( m_bGLSL )
  1674. {
  1675. // We should only be assigning to a single component of the dest.
  1676. Assert( GetNumSwizzleComponents( pDestReg ) == 1 );
  1677. Assert( GetNumSwizzleComponents( pSrc2Reg ) == 1 );
  1678. // This is a 2D dot product, so we only want two entries from the middle components.
  1679. CUtlString sArg0 = EnsureNumSwizzleComponents( pSrc0Reg, 2 );
  1680. CUtlString sArg1 = EnsureNumSwizzleComponents( pSrc1Reg, 2 );
  1681. PrintToBuf( *m_pBufALUCode, "%s = dot( %s, %s ) + %s;\n", pDestReg, sArg0.String(), sArg1.String(), pSrc2Reg );
  1682. // If the _SAT instruction modifier is used, then do a saturate here.
  1683. if ( nDestToken & D3DSPDM_SATURATE )
  1684. {
  1685. int nComponents = GetNumSwizzleComponents( pDestReg );
  1686. if ( nComponents == 0 )
  1687. nComponents = 4;
  1688. PrintToBuf( *m_pBufALUCode, "%s = clamp( %s, %s, %s );\n", pDestReg, pDestReg, g_szVecZeros[nComponents], g_szVecOnes[nComponents] );
  1689. }
  1690. }
  1691. else
  1692. {
  1693. m_bNeedsD2AddTemp = true;
  1694. PrintToBuf( *m_pBufALUCode, "MOV DP2A0, %s;\n", pSrc0Reg ); // MOV DP2A0, src0;
  1695. PrintToBuf( *m_pBufALUCode, "MOV DP2A0.z, 1;\n" ); // MOV DP2A0.z, 1;
  1696. PrintToBuf( *m_pBufALUCode, "MOV DP2A1, %s;\n", pSrc1Reg ); // MOV DP2A1, src1;
  1697. PrintToBuf( *m_pBufALUCode, "MOV DP2A1.z, %s;\n", pSrc2Reg ); // MOV DP2A1.z, src2;
  1698. PrintToBuf( *m_pBufALUCode, "DP3%s, DP2A0, DP2A1;\n", pDestReg ); // DP3 dest, DP2A0, DP2A1;
  1699. if ( nDestToken & D3DSPDM_SATURATE )
  1700. {
  1701. // Need to saturate asm!
  1702. DebuggerBreakIfDebugging();
  1703. }
  1704. }
  1705. }
  1706. void D3DToGL::Handle_SINCOS()
  1707. {
  1708. char pDestReg[16], pSrc0Reg[16];
  1709. PrintParameterToString( GetNextToken(), DST_REGISTER, pDestReg, sizeof( pDestReg ), false, NULL );
  1710. PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc0Reg, sizeof( pSrc0Reg ), true, NULL );
  1711. m_bNeedsSinCosDeclarations = true;
  1712. if ( m_bGLSL )
  1713. {
  1714. CUtlString sDest( pDestReg );
  1715. CUtlString sArg0 = EnsureNumSwizzleComponents( pSrc0Reg, 1 );// Ensure input is scalar
  1716. CUtlString sResult( "vSinCosTmp.xy" ); // Always going to populate this
  1717. sResult = FixGLSLSwizzle( sDest, sResult ); // Make sure we match the desired output reg
  1718. PrintToBuf( *m_pBufALUCode, "vSinCosTmp.z = %s * %s;\n", sArg0.String(), sArg0.String() );
  1719. PrintToBuf( *m_pBufALUCode, "vSinCosTmp.xy = vSinCosTmp.zz * scA.xy + scA.wz;\n" );
  1720. PrintToBuf( *m_pBufALUCode, "vSinCosTmp.xy = vSinCosTmp.xy * vSinCosTmp.zz + scB.xy;\n" );
  1721. PrintToBuf( *m_pBufALUCode, "vSinCosTmp.xy = vSinCosTmp.xy * vSinCosTmp.zz + scB.wz;\n" );
  1722. PrintToBuf( *m_pBufALUCode, "vSinCosTmp.x = vSinCosTmp.x * %s;\n", sArg0.String() );
  1723. PrintToBuf( *m_pBufALUCode, "vSinCosTmp.xy = vSinCosTmp.xy * vSinCosTmp.xx;\n" );
  1724. PrintToBuf( *m_pBufALUCode, "vSinCosTmp.xy = vSinCosTmp.xy + vSinCosTmp.xy;\n" );
  1725. PrintToBuf( *m_pBufALUCode, "vSinCosTmp.x = -vSinCosTmp.x + scB.z;\n" );
  1726. PrintToBuf( *m_pBufALUCode, "%s = %s;\n", sDest.String(), sResult.String() );
  1727. }
  1728. else
  1729. {
  1730. // This is the code sequence recommended to IHVs by Microsoft in the DirectX 9 DDK:
  1731. //
  1732. // http://msdn.microsoft.com/en-us/library/ms800337.aspx
  1733. //
  1734. // MUL SC_TEMP.z, src, src;
  1735. // MAD SC_TEMP.xy, SC_TEMP.z, scA, scA.wzyx;
  1736. // MAD SC_TEMP.xy, SC_TEMP, SC_TEMP.z, scB;
  1737. // MAD SC_TEMP.xy, SC_TEMP, SC_TEMP.z, scB.wzyx;
  1738. // MUL SC_TEMP.x, SC_TEMP.x, src;
  1739. // MUL SC_TEMP.xy, SC_TEMP, SC_TEMP.x;
  1740. // ADD SC_TEMP.xy, SC_TEMP, SC_TEMP;
  1741. // ADD SC_TEMP.x, -SC_TEMP.x, scB.z;
  1742. StrcatToALUCode( "MUL SC_TEMP.z, " ); // MUL SC_TEMP.z, src, src;
  1743. StrcatToALUCode( pSrc0Reg );
  1744. StrcatToALUCode( ", " );
  1745. StrcatToALUCode( pSrc0Reg );
  1746. StrcatToALUCode( ";\n" );
  1747. StrcatToALUCode( "MAD SC_TEMP.xy, SC_TEMP.z, scA, scA.wzyx;\n" );
  1748. StrcatToALUCode( "MAD SC_TEMP.xy, SC_TEMP, SC_TEMP.z, scB;\n" );
  1749. StrcatToALUCode( "MAD SC_TEMP.xy, SC_TEMP, SC_TEMP.z, scB.wzyx;\n" );
  1750. StrcatToALUCode( "MUL SC_TEMP.x, SC_TEMP.x, " );
  1751. StrcatToALUCode( pSrc0Reg );
  1752. StrcatToALUCode( ";\n" );
  1753. StrcatToALUCode( "MUL SC_TEMP.xy, SC_TEMP, SC_TEMP.x;\n" );
  1754. StrcatToALUCode( "ADD SC_TEMP.xy, SC_TEMP, SC_TEMP;\n" );
  1755. StrcatToALUCode( "ADD SC_TEMP.x, -SC_TEMP.x, scB.z;\n" );
  1756. StrcatToALUCode( "MOV" );
  1757. StrcatToALUCode( pDestReg );
  1758. StrcatToALUCode( ", SC_TEMP;\n" );
  1759. }
  1760. // Eat two more tokens since D3D defines Taylor series constants that we won't need
  1761. SkipTokens( 2 );
  1762. }
  1763. void D3DToGL::Handle_LRP( uint32 nInstruction )
  1764. {
  1765. if ( m_bGLSL )
  1766. {
  1767. uint32 nDestToken = GetNextToken();
  1768. CUtlString sDest = GetParameterString( nDestToken, DST_REGISTER, false, NULL );
  1769. int nARLComp0 = ARL_DEST_NONE;
  1770. CUtlString sParam0 = GetParameterString( GetNextToken(), SRC_REGISTER, false, &nARLComp0 );
  1771. int nARLComp1 = ARL_DEST_NONE;
  1772. CUtlString sParam1 = GetParameterString( GetNextToken(), SRC_REGISTER, false, &nARLComp1 );
  1773. int nARLComp2 = ARL_DEST_NONE;
  1774. CUtlString sParam2 = GetParameterString( GetNextToken(), SRC_REGISTER, false, &nARLComp2 );
  1775. // This optionally inserts a move from our dummy address register to the .x component of the real one
  1776. InsertMoveFromAddressRegister( m_pBufALUCode, nARLComp0, nARLComp1, nARLComp2 );
  1777. sParam0 = FixGLSLSwizzle( sDest, sParam0 );
  1778. sParam1 = FixGLSLSwizzle( sDest, sParam1 );
  1779. sParam2 = FixGLSLSwizzle( sDest, sParam2 );
  1780. // dest = src0 * (src1 - src2) + src2;
  1781. PrintToBuf( *m_pBufALUCode, "%s = %s * ( %s - %s ) + %s;\n", sDest.String(), sParam0.String(), sParam1.String(), sParam2.String(), sParam2.String() );
  1782. // If the _SAT instruction modifier is used, then do a saturate here.
  1783. if ( nDestToken & D3DSPDM_SATURATE )
  1784. {
  1785. int nComponents = GetNumSwizzleComponents( sDest.String() );
  1786. if ( nComponents == 0 )
  1787. nComponents = 4;
  1788. PrintToBuf( *m_pBufALUCode, "%s = clamp( %s, %s, %s );\n", sDest.String(), sDest.String(), g_szVecZeros[nComponents], g_szVecOnes[nComponents] );
  1789. }
  1790. }
  1791. else
  1792. {
  1793. if ( !m_bVertexShader )
  1794. {
  1795. char buff[256];
  1796. PrintOpcode( nInstruction, buff, sizeof( buff ) );
  1797. StrcatToALUCode( buff );
  1798. PrintParameterToString( GetNextToken(), DST_REGISTER, buff, sizeof( buff ), false, NULL );
  1799. StrcatToALUCode( buff );
  1800. StrcatToALUCode( ", " );
  1801. PrintParameterToString( GetNextToken(), SRC_REGISTER, buff, sizeof( buff ), false, NULL );
  1802. StrcatToALUCode( buff );
  1803. StrcatToALUCode( ", " );
  1804. PrintParameterToString( GetNextToken(), SRC_REGISTER, buff, sizeof( buff ), false, NULL );
  1805. StrcatToALUCode( buff );
  1806. StrcatToALUCode( ", " );
  1807. PrintParameterToString( GetNextToken(), SRC_REGISTER, buff, sizeof( buff ), false, NULL );
  1808. StrcatToALUCode( buff );
  1809. StrcatToALUCode( ";\n" );
  1810. }
  1811. else // VS doesn't actually have a LRP instruction. Emulate with a SUB and a MAD
  1812. {
  1813. char pDestReg[16], pSrc0Reg[16], pSrc1Reg[16], pSrc2Reg[16];
  1814. m_bNeedsLerpTemp = true;
  1815. // dest = src0 * (src1 - src2) + src2;
  1816. PrintParameterToString( GetNextToken(), DST_REGISTER, pDestReg, sizeof( pDestReg ), false, NULL );
  1817. PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc0Reg, sizeof( pSrc0Reg ), false, NULL );
  1818. PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc1Reg, sizeof( pSrc1Reg ), false, NULL );
  1819. PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc2Reg, sizeof( pSrc2Reg ), false, NULL );
  1820. StrcatToALUCode( "SUB LRP_TEMP, " ); // SUB LRP_TEMP, src1, src2;
  1821. StrcatToALUCode( pSrc1Reg );
  1822. StrcatToALUCode( ", " );
  1823. StrcatToALUCode( pSrc2Reg );
  1824. StrcatToALUCode( ";\n" );
  1825. StrcatToALUCode( "MAD" ); // MAD dst, src0, LRP_TEMP, src2;
  1826. StrcatToALUCode( pDestReg );
  1827. StrcatToALUCode( ", " );
  1828. StrcatToALUCode( pSrc0Reg );
  1829. StrcatToALUCode( ", LRP_TEMP, " );
  1830. StrcatToALUCode( pSrc2Reg );
  1831. StrcatToALUCode( ";\n" );
  1832. }
  1833. }
  1834. }
  1835. void D3DToGL::Handle_TEX( uint32 dwToken, bool bIsTexLDL )
  1836. {
  1837. char pDestReg[64], pSrc0Reg[64], pSrc1Reg[64];
  1838. PrintParameterToString( GetNextToken(), DST_REGISTER, pDestReg, sizeof( pDestReg ), false, NULL );
  1839. PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc0Reg, sizeof( pSrc0Reg ), false, NULL );
  1840. DWORD dwSrc1Token = GetNextToken();
  1841. PrintParameterToString( dwSrc1Token, SRC_REGISTER, pSrc1Reg, sizeof( pSrc1Reg ), false, NULL );
  1842. if ( m_bGLSL )
  1843. {
  1844. Assert( (dwSrc1Token & D3DSP_REGNUM_MASK) < ARRAYSIZE( m_dwSamplerTypes ) );
  1845. uint32 nSamplerType = m_dwSamplerTypes[dwSrc1Token & D3DSP_REGNUM_MASK];
  1846. if ( nSamplerType == SAMPLER_TYPE_2D )
  1847. {
  1848. CUtlString sCoordVar = EnsureNumSwizzleComponents( pSrc0Reg, 2 );
  1849. if ( bIsTexLDL )
  1850. {
  1851. // Strip out the W component of the pSrc0Reg and pass that as the LOD to texture2DLod.
  1852. char szLOD[128], szExtra[8];
  1853. GetParamNameWithoutSwizzle( pSrc0Reg, szLOD, sizeof( szLOD ) );
  1854. V_snprintf( szExtra, sizeof( szExtra ), ".%c", GetSwizzleComponent( pSrc0Reg, 3 ) );
  1855. V_strncat( szLOD, szExtra, sizeof( szLOD ) );
  1856. PrintToBuf( *m_pBufALUCode, "%s = texture2DLod( %s, %s, %s );\n", pDestReg, pSrc1Reg, sCoordVar.String(), szLOD );
  1857. }
  1858. else if ( ( (int) ( dwSrc1Token & D3DSP_REGNUM_MASK ) ) == m_nShadowDepthSampler ) // Syntax for shadow depth sampler
  1859. {
  1860. // .z is meant to contain the object depth, while .xy contains the 2D tex coords
  1861. CUtlString sCoordVar3D = EnsureNumSwizzleComponents( pSrc0Reg, 3 );
  1862. PrintToBuf( *m_pBufALUCode, "%s = shadow2D( %s, %s );\n", pDestReg, pSrc1Reg, sCoordVar3D.String() );
  1863. Assert( m_dwSamplerTypes[dwSrc1Token & D3DSP_REGNUM_MASK] == SAMPLER_TYPE_2D );
  1864. }
  1865. else if( ( OpcodeSpecificData( dwToken ) << D3DSP_OPCODESPECIFICCONTROL_SHIFT ) == D3DSI_TEXLD_PROJECT )
  1866. {
  1867. // This projective case is after the shadow case intentionally, due to the way that "projective"
  1868. // loads are overloaded in our D3D shaders for shadow lookups.
  1869. //
  1870. // We use the vec4 variant of texture2DProj() intentionally here, since it lines up well with Direct3D.
  1871. CUtlString s4DProjCoords = EnsureNumSwizzleComponents( pSrc0Reg, 4 ); // Ensure vec4 variant
  1872. PrintToBuf( *m_pBufALUCode, "%s = texture2DProj( %s, %s );\n", pDestReg, pSrc1Reg, s4DProjCoords.String() );
  1873. }
  1874. else
  1875. {
  1876. PrintToBuf( *m_pBufALUCode, "%s = texture2D( %s, %s );\n", pDestReg, pSrc1Reg, sCoordVar.String() );
  1877. }
  1878. }
  1879. else if ( nSamplerType == SAMPLER_TYPE_3D )
  1880. {
  1881. CUtlString sCoordVar = EnsureNumSwizzleComponents( pSrc0Reg, 3 );
  1882. PrintToBuf( *m_pBufALUCode, "%s = texture3D( %s, %s );\n", pDestReg, pSrc1Reg, sCoordVar.String() );
  1883. }
  1884. else if ( nSamplerType == SAMPLER_TYPE_CUBE )
  1885. {
  1886. CUtlString sCoordVar = EnsureNumSwizzleComponents( pSrc0Reg, 3 );
  1887. PrintToBuf( *m_pBufALUCode, "%s = textureCube( %s, %s );\n", pDestReg, pSrc1Reg, sCoordVar.String() );
  1888. }
  1889. else
  1890. {
  1891. Error( "TEX instruction: unsupported sampler type used" );
  1892. }
  1893. }
  1894. else
  1895. {
  1896. Assert( !( bIsTexLDL && !m_bGeneratingDebugText ) );
  1897. if( ( OpcodeSpecificData( dwToken ) << D3DSP_OPCODESPECIFICCONTROL_SHIFT ) == D3DSI_TEXLD_PROJECT )
  1898. {
  1899. StrcatToALUCode( "TXP" );
  1900. }
  1901. else if( ( OpcodeSpecificData( dwToken ) << D3DSP_OPCODESPECIFICCONTROL_SHIFT) == D3DSI_TEXLD_BIAS )
  1902. {
  1903. StrcatToALUCode( "TXB" );
  1904. }
  1905. else
  1906. {
  1907. StrcatToALUCode( "TEX" );
  1908. }
  1909. // Destination
  1910. StrcatToALUCode( pDestReg );
  1911. StrcatToALUCode( ", " );
  1912. // Source0
  1913. StrcatToALUCode( pSrc0Reg );
  1914. StrcatToALUCode( ", " );
  1915. // Source1
  1916. StrcatToALUCode( pSrc1Reg );
  1917. StrcatToALUCode( ", " );
  1918. // Syntax for shadow depth sampler
  1919. if ( ( (int) ( dwSrc1Token & D3DSP_REGNUM_MASK ) ) == m_nShadowDepthSampler )
  1920. {
  1921. m_bDeclareShadowOption = true;
  1922. StrcatToALUCode( "SHADOW" ); // Should result in SHADOW2D target
  1923. Assert( m_dwSamplerTypes[dwSrc1Token & D3DSP_REGNUM_MASK] == SAMPLER_TYPE_2D );
  1924. }
  1925. // Sampler dimension (2D, CUBE, 3D) determined by earlier declaration
  1926. StrcatToALUCode( g_szSamplerStrings[m_dwSamplerTypes[dwSrc1Token & D3DSP_REGNUM_MASK]] );
  1927. StrcatToALUCode( ";\n" );
  1928. }
  1929. }
  1930. void D3DToGL::StrcatToHeaderCode( const char *pBuf )
  1931. {
  1932. strcat_s( (char*)m_pBufHeaderCode->Base(), m_pBufHeaderCode->Size(), pBuf );
  1933. }
  1934. void D3DToGL::StrcatToALUCode( const char *pBuf )
  1935. {
  1936. strcat_s( (char*)m_pBufALUCode->Base(), m_pBufALUCode->Size(), pBuf );
  1937. }
  1938. void D3DToGL::StrcatToParamCode( const char *pBuf )
  1939. {
  1940. strcat_s( (char*)m_pBufParamCode->Base(), m_pBufParamCode->Size(), pBuf );
  1941. }
  1942. void D3DToGL::StrcatToAttribCode( const char *pBuf )
  1943. {
  1944. strcat_s( (char*)m_pBufAttribCode->Base(), m_pBufAttribCode->Size(), pBuf );
  1945. }
  1946. void D3DToGL::Handle_TexLDD( uint32 nInstruction )
  1947. {
  1948. Assert( !m_bGLSL ); // Not supported yet, but can be if we need it.
  1949. char buff[256];
  1950. PrintOpcode( nInstruction, buff, sizeof( buff ) );
  1951. StrcatToALUCode( buff );
  1952. PrintParameterToString( GetNextToken(), DST_REGISTER, buff, sizeof( buff ), false, NULL );
  1953. StrcatToALUCode( buff );
  1954. StrcatToALUCode( ", " );
  1955. PrintParameterToString( GetNextToken(), SRC_REGISTER, buff, sizeof( buff ), false, NULL );
  1956. StrcatToALUCode( buff );
  1957. StrcatToALUCode( ", " );
  1958. PrintParameterToString( GetNextToken(), SRC_REGISTER, buff, sizeof( buff ), false, NULL );
  1959. StrcatToALUCode( buff );
  1960. StrcatToALUCode( ", " );
  1961. PrintParameterToString( GetNextToken(), SRC_REGISTER, buff, sizeof( buff ), false, NULL );
  1962. StrcatToALUCode( buff );
  1963. StrcatToALUCode( ", " );
  1964. PrintParameterToString( GetNextToken(), SRC_REGISTER, buff, sizeof( buff ), false, NULL );
  1965. StrcatToALUCode( buff );
  1966. StrcatToALUCode( ";\n" );
  1967. }
  1968. void D3DToGL::Handle_TexCoord()
  1969. {
  1970. DebuggerBreakIfDebugging();
  1971. // If ps_1_4, this is texcrd
  1972. if ( (m_dwMajorVersion == 1) && (m_dwMinorVersion == 4) && (!m_bVertexShader) )
  1973. {
  1974. StrcatToALUCode( "texcrd" );
  1975. }
  1976. else // else it's texcoord
  1977. {
  1978. DebuggerBreakIfDebugging();
  1979. StrcatToALUCode( "texcoord" );
  1980. }
  1981. char buff[256];
  1982. PrintParameterToString( GetNextToken(), DST_REGISTER, buff, sizeof( buff ), false, NULL );
  1983. StrcatToALUCode( buff );
  1984. // If ps_1_4, texcrd also has a source parameter
  1985. if ((m_dwMajorVersion == 1) && (m_dwMinorVersion == 4) && (!m_bVertexShader))
  1986. {
  1987. StrcatToALUCode( ", " );
  1988. PrintParameterToString( GetNextToken(), SRC_REGISTER, buff, sizeof( buff ), false, NULL );
  1989. StrcatToALUCode( buff );
  1990. }
  1991. StrcatToALUCode( ";\n" );
  1992. }
  1993. void D3DToGL::HandleBinaryOp_GLSL( uint32 nInstruction )
  1994. {
  1995. uint32 nDestToken = GetNextToken();
  1996. CUtlString sParam1 = GetParameterString( nDestToken, DST_REGISTER, false, NULL );
  1997. int nARLComp0 = ARL_DEST_NONE;
  1998. CUtlString sParam2 = GetParameterString( GetNextToken(), SRC_REGISTER, false, &nARLComp0 );
  1999. int nARLComp1 = ARL_DEST_NONE;
  2000. CUtlString sParam3 = GetParameterString( GetNextToken(), SRC_REGISTER, false, &nARLComp1 );
  2001. // This optionally inserts a move from our dummy address register to the .x component of the real one
  2002. InsertMoveFromAddressRegister( m_pBufALUCode, nARLComp0, nARLComp1 );
  2003. // DST is a weird one. I haven't seen it used anywhere yet but can add support if necessary. This is what it does:
  2004. // dest.x = 1;
  2005. // dest.y = src0.y * src1.y;
  2006. // dest.z = src0.z;
  2007. // dest.w = src1.w;
  2008. Assert( nInstruction != D3DSIO_DST );
  2009. // Since DP3 and DP4 have a scalar as the dest and vectors as the src, don't screw with the swizzle specifications.
  2010. if ( nInstruction == D3DSIO_DP3 )
  2011. {
  2012. sParam2 = EnsureNumSwizzleComponents( sParam2, 3 );
  2013. sParam3 = EnsureNumSwizzleComponents( sParam3, 3 );
  2014. }
  2015. else if ( nInstruction == D3DSIO_DP4 )
  2016. {
  2017. sParam2 = EnsureNumSwizzleComponents( sParam2, 4 );
  2018. sParam3 = EnsureNumSwizzleComponents( sParam3, 4 );
  2019. }
  2020. else
  2021. {
  2022. sParam2 = FixGLSLSwizzle( sParam1, sParam2 );
  2023. sParam3 = FixGLSLSwizzle( sParam1, sParam3 );
  2024. }
  2025. char buff[256];
  2026. if ( nInstruction == D3DSIO_ADD || nInstruction == D3DSIO_SUB || nInstruction == D3DSIO_MUL )
  2027. {
  2028. // These all look like x = y op z
  2029. PrintToBuf( *m_pBufALUCode, "%s = %s %s %s;\n", sParam1.String(), sParam2.String(), GetGLSLOperatorString( nInstruction ), sParam3.String() );
  2030. }
  2031. else
  2032. {
  2033. if ( ( nInstruction == D3DSIO_SGE ) || ( nInstruction == D3DSIO_SLT ) )
  2034. {
  2035. sParam2 = FixGLSLSwizzle( sParam1, sParam2 );
  2036. sParam3 = FixGLSLSwizzle( sParam1, sParam3 );
  2037. }
  2038. int nDestComponents = GetNumSwizzleComponents( sParam1.String() );
  2039. int nSrcComponents = GetNumSwizzleComponents( sParam2.String() );
  2040. // All remaining instructions can use GLSL intrinsics like dot() and cross().
  2041. bool bDoubleClose = OpenIntrinsic( nInstruction, buff, sizeof( buff ), nDestComponents, nSrcComponents );
  2042. if ( ( nSrcComponents == 1 ) && ( nInstruction == D3DSIO_SGE ) )
  2043. {
  2044. PrintToBuf( *m_pBufALUCode, "%s = %s%s >= %s );\n", sParam1.String(), buff, sParam2.String(), sParam3.String() );
  2045. }
  2046. else if ( ( nSrcComponents == 1 ) && ( nInstruction == D3DSIO_SLT ) )
  2047. {
  2048. PrintToBuf( *m_pBufALUCode, "%s = %s%s < %s );\n", sParam1.String(), buff, sParam2.String(), sParam3.String() );
  2049. }
  2050. else
  2051. {
  2052. PrintToBuf( *m_pBufALUCode, "%s = %s%s, %s %s;\n", sParam1.String(), buff, sParam2.String(), sParam3.String(), bDoubleClose ? ") )" : ")" );
  2053. }
  2054. }
  2055. // If the _SAT instruction modifier is used, then do a saturate here.
  2056. if ( nDestToken & D3DSPDM_SATURATE )
  2057. {
  2058. int nComponents = GetNumSwizzleComponents( sParam1.String() );
  2059. if ( nComponents == 0 )
  2060. nComponents = 4;
  2061. PrintToBuf( *m_pBufALUCode, "%s = clamp( %s, %s, %s );\n", sParam1.String(), sParam1.String(), g_szVecZeros[nComponents], g_szVecOnes[nComponents] );
  2062. }
  2063. }
  2064. void D3DToGL::HandleBinaryOp_ASM( uint32 nInstruction )
  2065. {
  2066. CUtlString sParam1 = GetParameterString( GetNextToken(), DST_REGISTER, false, NULL );
  2067. int nARLComp0 = ARL_DEST_NONE;
  2068. CUtlString sParam2 = GetParameterString( GetNextToken(), SRC_REGISTER, false, &nARLComp0 );
  2069. int nARLComp1 = ARL_DEST_NONE;
  2070. CUtlString sParam3 = GetParameterString( GetNextToken(), SRC_REGISTER, false, &nARLComp1 );
  2071. // This optionally inserts a move from our dummy address register to the .x component of the real one
  2072. InsertMoveFromAddressRegister( m_pBufALUCode, nARLComp0, nARLComp1 );
  2073. char buff[256];
  2074. PrintOpcode( nInstruction, buff, sizeof( buff ) );
  2075. PrintToBuf( *m_pBufALUCode, "%s%s, %s, %s;\n", buff, sParam1.String(), sParam2.String(), sParam3.String() );
  2076. }
  2077. void D3DToGL::WriteGLSLCmp( const char *pDestReg, const char *pSrc0Reg, const char *pSrc1Reg, const char *pSrc2Reg )
  2078. {
  2079. int nWriteMaskEntries = GetNumWriteMaskEntries( pDestReg );
  2080. for ( int i=0; i < nWriteMaskEntries; i++ )
  2081. {
  2082. char params[4][256];
  2083. WriteParamWithSingleMaskEntry( pDestReg, i, params[0], sizeof( params[0] ) );
  2084. WriteParamWithSingleMaskEntry( pSrc0Reg, i, params[1], sizeof( params[1] ) );
  2085. WriteParamWithSingleMaskEntry( pSrc1Reg, i, params[2], sizeof( params[2] ) );
  2086. WriteParamWithSingleMaskEntry( pSrc2Reg, i, params[3], sizeof( params[3] ) );
  2087. PrintToBuf( *m_pBufALUCode, "%s = ( %s >= 0.0 ) ? %s : %s;\n", params[0], params[1], params[2], params[3] );
  2088. }
  2089. }
  2090. void D3DToGL::Handle_CMP()
  2091. {
  2092. // In Direct3D, result = (src0 >= 0.0) ? src1 : src2
  2093. // In OpenGL, result = (src0 < 0.0) ? src1 : src2
  2094. //
  2095. // As a result, arguments are effectively in a different order than Direct3D! !#$&*!%#$&
  2096. char pDestReg[64], pSrc0Reg[64], pSrc1Reg[64], pSrc2Reg[64];
  2097. uint32 nDestToken = GetNextToken();
  2098. PrintParameterToString( nDestToken, DST_REGISTER, pDestReg, sizeof( pDestReg ), false, NULL );
  2099. PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc0Reg, sizeof( pSrc0Reg ), false, NULL );
  2100. PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc1Reg, sizeof( pSrc1Reg ), false, NULL );
  2101. PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc2Reg, sizeof( pSrc2Reg ), false, NULL );
  2102. if ( m_bGLSL )
  2103. {
  2104. // These are a tricky case.. we have to expand it out into multiple statements.
  2105. char szDestBase[256];
  2106. GetParamNameWithoutSwizzle( pDestReg, szDestBase, sizeof( szDestBase ) );
  2107. V_strncpy( pSrc0Reg, FixGLSLSwizzle( pDestReg, pSrc0Reg ), sizeof( pSrc0Reg ) );
  2108. V_strncpy( pSrc1Reg, FixGLSLSwizzle( pDestReg, pSrc1Reg ), sizeof( pSrc1Reg ) );
  2109. V_strncpy( pSrc2Reg, FixGLSLSwizzle( pDestReg, pSrc2Reg ), sizeof( pSrc2Reg ) );
  2110. if ( DoParamNamesMatch( pDestReg, pSrc0Reg ) && GetNumSwizzleComponents( pDestReg ) > 1 )
  2111. {
  2112. // So the dest register is the same as the comperand. We're in danger of screwing up our results.
  2113. //
  2114. // For example, this code:
  2115. // CMP r0.xy, r0.xx, r1, r2
  2116. // would generate this:
  2117. // r0.x = (r0.x >= 0) ? r1.x : r2.x;
  2118. // r0.y = (r0.x >= 0) ? r1.x : r2.x;
  2119. //
  2120. // But the first lines changes r0.x and thus screws the atomicity of the CMP instruction for the second line.
  2121. // So we assign r0 to a temporary first and then write to the temporary.
  2122. PrintToBuf( *m_pBufALUCode, "%s = %s;\n", g_pAtomicTempVarName, szDestBase );
  2123. char szTempVar[256];
  2124. ReplaceParamName( pDestReg, g_pAtomicTempVarName, szTempVar, sizeof( szTempVar ) );
  2125. WriteGLSLCmp( szTempVar, pSrc0Reg, pSrc1Reg, pSrc2Reg );
  2126. PrintToBuf( *m_pBufALUCode, "%s = %s;\n", szDestBase, g_pAtomicTempVarName );
  2127. m_bUsedAtomicTempVar = true;
  2128. }
  2129. else
  2130. {
  2131. // Just write out the simple expanded version of the CMP. No need to use atomic_temp_var.
  2132. WriteGLSLCmp( pDestReg, pSrc0Reg, pSrc1Reg, pSrc2Reg );
  2133. }
  2134. // If the _SAT instruction modifier is used, then do a saturate here.
  2135. if ( nDestToken & D3DSPDM_SATURATE )
  2136. {
  2137. int nComponents = GetNumSwizzleComponents( pDestReg );
  2138. if ( nComponents == 0 )
  2139. nComponents = 4;
  2140. PrintToBuf( *m_pBufALUCode, "%s = clamp( %s, %s, %s );\n", pDestReg, pDestReg, g_szVecZeros[nComponents], g_szVecOnes[nComponents] );
  2141. }
  2142. }
  2143. else
  2144. {
  2145. StrcatToALUCode( "CMP" );
  2146. StrcatToALUCode( pDestReg );
  2147. StrcatToALUCode( ", " );
  2148. StrcatToALUCode( pSrc0Reg );
  2149. StrcatToALUCode( ", " );
  2150. StrcatToALUCode( pSrc2Reg ); // Src 2 |
  2151. StrcatToALUCode( ", " ); // |--- Swap these guys from Direct3D's convention
  2152. StrcatToALUCode( pSrc1Reg ); // Src 1 |
  2153. StrcatToALUCode( ";\n" );
  2154. }
  2155. }
  2156. void D3DToGL::Handle_NRM()
  2157. {
  2158. char pDestReg[64];
  2159. char pSrc0Reg[64];
  2160. PrintParameterToString( GetNextToken(), DST_REGISTER, pDestReg, sizeof( pDestReg ), false, NULL );
  2161. PrintParameterToString( GetNextToken(), SRC_REGISTER, pSrc0Reg, sizeof( pSrc0Reg ), false, NULL );
  2162. if ( m_bGLSL )
  2163. {
  2164. CUtlString sSrc = EnsureNumSwizzleComponents( pSrc0Reg, 3 );
  2165. PrintToBuf( *m_pBufALUCode, "%s = normalize( %s );\n", pDestReg, sSrc.String() );
  2166. }
  2167. else
  2168. {
  2169. m_bNeedsNRMTemp = true;
  2170. StrcatToALUCode( "DP3 NRM_TEMP.w, " );
  2171. StrcatToALUCode( pSrc0Reg );
  2172. StrcatToALUCode( ", " );
  2173. StrcatToALUCode( pSrc0Reg );
  2174. StrcatToALUCode( ";\nRSQ NRM_TEMP.w, NRM_TEMP.w;\nMUL" );
  2175. StrcatToALUCode( pDestReg );
  2176. StrcatToALUCode( ", NRM_TEMP.w, " );
  2177. StrcatToALUCode( pSrc0Reg );
  2178. StrcatToALUCode( ";\n" );
  2179. }
  2180. }
  2181. void D3DToGL::Handle_UnaryOp( uint32 nInstruction )
  2182. {
  2183. uint32 nDestToken = GetNextToken();
  2184. CUtlString sParam1 = GetParameterString( nDestToken, DST_REGISTER, false, NULL );
  2185. CUtlString sParam2 = GetParameterString( GetNextToken(), SRC_REGISTER, ( nInstruction == D3DSIO_MOVA) && !m_bGLSL, NULL );
  2186. sParam2 = FixGLSLSwizzle( sParam1, sParam2 );
  2187. if ( m_bGLSL )
  2188. {
  2189. if ( nInstruction == D3DSIO_MOV )
  2190. {
  2191. PrintToBuf( *m_pBufALUCode, "%s = %s;\n", sParam1.String(), sParam2.String() );
  2192. }
  2193. else if ( nInstruction == D3DSIO_RSQ )
  2194. {
  2195. PrintToBuf( *m_pBufALUCode, "%s = inversesqrt( %s );\n", sParam1.String(), sParam2.String() );
  2196. }
  2197. else if ( nInstruction == D3DSIO_RCP )
  2198. {
  2199. PrintToBuf( *m_pBufALUCode, "%s = 1.0 / %s;\n", sParam1.String(), sParam2.String() );
  2200. }
  2201. else if ( nInstruction == D3DSIO_EXP )
  2202. {
  2203. PrintToBuf( *m_pBufALUCode, "%s = exp2( %s );\n", sParam1.String(), sParam2.String() );
  2204. }
  2205. else if ( nInstruction == D3DSIO_FRC )
  2206. {
  2207. PrintToBuf( *m_pBufALUCode, "%s = fract( %s );\n", sParam1.String(), sParam2.String() );
  2208. }
  2209. else if ( nInstruction == D3DSIO_LOG ) // d3d 'log' is log base 2
  2210. {
  2211. PrintToBuf( *m_pBufALUCode, "%s = log2( %s );\n", sParam1.String(), sParam2.String() );
  2212. }
  2213. else if ( nInstruction == D3DSIO_ABS ) // rbarris did this one, Jason please check
  2214. {
  2215. PrintToBuf( *m_pBufALUCode, "%s = abs( %s );\n", sParam1.String(), sParam2.String() );
  2216. }
  2217. else if ( nInstruction == D3DSIO_MOVA )
  2218. {
  2219. m_bDeclareAddressReg = true;
  2220. PrintToBuf( *m_pBufALUCode, "%s = %s;\n", sParam1.String(), sParam2.String() );
  2221. m_nHighestRegister = DXABSTRACT_VS_PARAM_SLOTS - 1;
  2222. }
  2223. else
  2224. {
  2225. Error( "Unsupported instruction" );
  2226. }
  2227. // If the _SAT instruction modifier is used, then do a saturate here.
  2228. if ( nDestToken & D3DSPDM_SATURATE )
  2229. {
  2230. int nComponents = GetNumSwizzleComponents( sParam1.String() );
  2231. if ( nComponents == 0 )
  2232. {
  2233. nComponents = 4;
  2234. }
  2235. PrintToBuf( *m_pBufALUCode, "%s = clamp( %s, %s, %s );\n", sParam1.String(), sParam1.String(), g_szVecZeros[nComponents], g_szVecOnes[nComponents] );
  2236. }
  2237. }
  2238. else
  2239. {
  2240. if ( nInstruction == D3DSIO_MOVA )
  2241. {
  2242. m_bDeclareAddressReg = true;
  2243. m_nHighestRegister = DXABSTRACT_VS_PARAM_SLOTS - 1;
  2244. Assert( m_nHighestRegister < DXABSTRACT_VS_PARAM_SLOTS );
  2245. }
  2246. char buff[256];
  2247. PrintOpcode( nInstruction, buff, sizeof( buff ) );
  2248. PrintToBuf( *m_pBufALUCode, "%s%s, %s;\n", buff, sParam1.String(), sParam2.String() );
  2249. }
  2250. }
  2251. void D3DToGL::WriteGLSLSamplerDefinitions()
  2252. {
  2253. int nSamplersWritten = 0;
  2254. for ( int i=0; i < ARRAYSIZE( m_dwSamplerTypes ); i++ )
  2255. {
  2256. if ( m_dwSamplerTypes[i] == SAMPLER_TYPE_2D )
  2257. {
  2258. if ( i == m_nShadowDepthSampler )
  2259. {
  2260. PrintToBuf( *m_pBufHeaderCode, "uniform sampler2DShadow sampler%d;\n", i );
  2261. }
  2262. else
  2263. {
  2264. PrintToBuf( *m_pBufHeaderCode, "uniform sampler2D sampler%d;\n", i );
  2265. }
  2266. ++nSamplersWritten;
  2267. }
  2268. else if ( m_dwSamplerTypes[i] == SAMPLER_TYPE_3D )
  2269. {
  2270. PrintToBuf( *m_pBufHeaderCode, "uniform sampler3D sampler%d;\n", i );
  2271. ++nSamplersWritten;
  2272. }
  2273. else if ( m_dwSamplerTypes[i] == SAMPLER_TYPE_CUBE )
  2274. {
  2275. PrintToBuf( *m_pBufHeaderCode, "uniform samplerCube sampler%d;\n", i );
  2276. ++nSamplersWritten;
  2277. }
  2278. else if ( m_dwSamplerTypes[i] != SAMPLER_TYPE_UNUSED )
  2279. {
  2280. Error( "Unknown sampler type." );
  2281. }
  2282. }
  2283. if ( nSamplersWritten > 0 )
  2284. PrintToBuf( *m_pBufHeaderCode, "\n\n" );
  2285. }
  2286. void D3DToGL::WriteGLSLOutputVariableAssignments()
  2287. {
  2288. if ( m_bVertexShader )
  2289. {
  2290. // Map output "oN" registers back to GLSL output variables.
  2291. if ( m_bAddHexCodeComments )
  2292. {
  2293. PrintToBuf( *m_pBufAttribCode, "\n// Now we're storing the oN variables from the output dcl_ statements back into their GLSL equivalents.\n" );
  2294. }
  2295. for ( int i=0; i < ARRAYSIZE( m_DeclaredOutputs ); i++ )
  2296. {
  2297. if ( m_DeclaredOutputs[i] == UNDECLARED_OUTPUT )
  2298. continue;
  2299. CUtlString sOutputName = GetUsageAndIndexString( m_DeclaredOutputs[i], SEMANTIC_OUTPUT );
  2300. PrintToBuf( *m_pBufAttribCode, "%s = oT%d;\n", sOutputName.String(), i );
  2301. }
  2302. }
  2303. }
  2304. void D3DToGL::Handle_DeclarativeNonDclOp( uint32 nInstruction )
  2305. {
  2306. char buff[128];
  2307. uint32 dwToken = GetNextToken();
  2308. PrintParameterToString( dwToken, DST_REGISTER, buff, sizeof( buff ), false, NULL );
  2309. if ( m_bGLSL && nInstruction == D3DSIO_TEXKILL )
  2310. {
  2311. // TEXKILL is supposed to discard the pixel if any of the src register's X, Y, or Z components are less than zero.
  2312. // We have to translate it to something like:
  2313. // if ( r0.x < 0.0 || r0.y < 0.0 )
  2314. // discard;
  2315. char c[3];
  2316. c[0] = GetSwizzleComponent( buff, 0 );
  2317. c[1] = GetSwizzleComponent( buff, 1 );
  2318. c[2] = GetSwizzleComponent( buff, 2 );
  2319. // Get the unique components.
  2320. char cUnique[3];
  2321. cUnique[0] = c[0];
  2322. int nUnique = 1;
  2323. if ( c[1] != c[0] )
  2324. cUnique[nUnique++] = c[1];
  2325. if ( c[2] != c[1] && c[2] != c[0] )
  2326. cUnique[nUnique++] = c[2];
  2327. // Get the src register base name.
  2328. char szBase[256];
  2329. GetParamNameWithoutSwizzle( buff, szBase, sizeof( szBase ) );
  2330. PrintToBuf( *m_pBufALUCode, "if ( %s.%c < 0.0 ", szBase, cUnique[0] );
  2331. for ( int i=1; i < nUnique; i++ )
  2332. {
  2333. PrintToBuf( *m_pBufALUCode, "|| %s.%c < 0.0 ", szBase, cUnique[i] );
  2334. }
  2335. PrintToBuf( *m_pBufALUCode, ")\n{\n\tdiscard;\n}\n" );
  2336. }
  2337. else
  2338. {
  2339. char szOpcode[128];
  2340. PrintOpcode( nInstruction, szOpcode, sizeof( szOpcode ) );
  2341. StrcatToALUCode( szOpcode );
  2342. StrcatToALUCode( buff );
  2343. StrcatToALUCode( ";\n" );
  2344. }
  2345. }
  2346. void D3DToGL::NoteTangentInputUsed()
  2347. {
  2348. if ( !m_bTangentInputUsed )
  2349. {
  2350. m_bTangentInputUsed = true;
  2351. // PrintToBuf( *m_pBufParamCode, "attribute vec4 %s;\n", g_pTangentAttributeName );
  2352. }
  2353. }
  2354. // These are the only ARL instructions that should appear in the instruction stream
  2355. void D3DToGL::InsertMoveInstruction( CUtlBuffer *pCode, int nARLComponent )
  2356. {
  2357. switch ( nARLComponent )
  2358. {
  2359. case ARL_DEST_X:
  2360. strcat_s( ( char * )pCode->Base(), pCode->Size(), m_bGLSL ? "a0 = int( va_r.x );\n" : "ARL a0.x, VA_REG.x;\n" );
  2361. break;
  2362. case ARL_DEST_Y:
  2363. strcat_s( ( char * )pCode->Base(), pCode->Size(), m_bGLSL ? "a0 = int( va_r.y );\n" : "ARL a0.x, VA_REG.y;\n" );
  2364. break;
  2365. case ARL_DEST_Z:
  2366. strcat_s( ( char * )pCode->Base(), pCode->Size(), m_bGLSL ? "a0 = int( va_r.z );\n" : "ARL a0.x, VA_REG.z;\n" );
  2367. break;
  2368. case ARL_DEST_W:
  2369. strcat_s( ( char * )pCode->Base(), pCode->Size(), m_bGLSL ? "a0 = int( va_r.w );\n" : "ARL a0.x, VA_REG.w;\n" );
  2370. break;
  2371. }
  2372. }
  2373. // This optionally inserts a move from our dummy address register to the .x component of the real one
  2374. void D3DToGL::InsertMoveFromAddressRegister( CUtlBuffer *pCode, int nARLComp0, int nARLComp1, int nARLComp2 /* = ARL_DEST_NONE */ )
  2375. {
  2376. int nNumSwizzles = 0;
  2377. if ( nARLComp0 != ARL_DEST_NONE )
  2378. nNumSwizzles++;
  2379. if ( nARLComp1 != ARL_DEST_NONE )
  2380. nNumSwizzles++;
  2381. if ( nARLComp2 != ARL_DEST_NONE )
  2382. nNumSwizzles++;
  2383. // We shouldn't have any more than one indirect address usage in a single instruction
  2384. Assert( nNumSwizzles <= 1 );
  2385. if ( nARLComp0 != ARL_DEST_NONE )
  2386. {
  2387. InsertMoveInstruction( pCode, nARLComp0 );
  2388. }
  2389. else if ( nARLComp1 != ARL_DEST_NONE )
  2390. {
  2391. InsertMoveInstruction( pCode, nARLComp1 );
  2392. }
  2393. else if ( nARLComp2 != ARL_DEST_NONE )
  2394. {
  2395. InsertMoveInstruction( pCode, nARLComp2 );
  2396. }
  2397. }
  2398. //------------------------------------------------------------------------------
  2399. // TranslateShader()
  2400. //
  2401. // This is the main function that the outside world sees. A pointer to the
  2402. // uint32 stream returned from the D3DX compile routine is parsed and used
  2403. // to write human-readable asm code into the character array pointed to by
  2404. // pDisassembledCode. An error code is returned.
  2405. //------------------------------------------------------------------------------
  2406. static int g_translationCounter = 0;
  2407. int D3DToGL::TranslateShader( uint32* code, CUtlBuffer *pBufDisassembledCode, bool *bVertexShader, uint32 options, int32 nShadowDepthSampler, uint32 nCentroidMask, char *debugLabel )
  2408. {
  2409. CUtlString sLine, sParamName;
  2410. uint32 i, dwToken, nInstruction, nNumTokensToSkip;
  2411. char buff[256];
  2412. // obey options
  2413. m_bUseEnvParams = (options & D3DToGL_OptionUseEnvParams) != 0;
  2414. m_bDoFixupZ = (options & D3DToGL_OptionDoFixupZ) != 0;
  2415. m_bDoFixupY = (options & D3DToGL_OptionDoFixupY) != 0;
  2416. m_bDoUserClipPlanes = (options & D3DToGL_OptionDoUserClipPlanes) != 0;
  2417. m_bGLSL = (options & D3DToGL_OptionGLSL) != 0;
  2418. m_bAllowStaticControlFlow = m_bGLSL && (options & D3DToGL_OptionAllowStaticControlFlow) != 0;
  2419. m_bAddHexCodeComments = (options & D3DToGL_AddHexComments) != 0;
  2420. m_bPutHexCodesAfterLines = (options & D3DToGL_PutHexCommentsAfterLines) != 0;
  2421. m_bGeneratingDebugText = (options & D3DToGL_GeneratingDebugText) != 0;
  2422. m_bUseBindableUniforms = (options & D3DToGL_OptionUseBindableUniforms) != 0;
  2423. m_bGenerateSRGBWriteSuffix = (options & D3DToGL_OptionSRGBWriteSuffix) != 0;
  2424. m_nLoopDepth = 0;
  2425. // debugging
  2426. m_bSpew = (options & D3DToGL_OptionSpew) != 0;
  2427. // m_bSpew |= (g_translationCounter == 1012 ); // interested in this specific translation run
  2428. // These are not accessed below in a way that will cause them to glow, so
  2429. // we could overflow these and/or the buffer pointed to by pDisassembledCode
  2430. m_pBufAttribCode = new CUtlBuffer( 100, 10000, CUtlBuffer::TEXT_BUFFER );
  2431. m_pBufParamCode = new CUtlBuffer( 100, 10000, CUtlBuffer::TEXT_BUFFER );
  2432. m_pBufALUCode = new CUtlBuffer( 100, 60000, CUtlBuffer::TEXT_BUFFER );
  2433. // Pointers to text buffers for assembling sections of the program
  2434. m_pBufHeaderCode = pBufDisassembledCode;
  2435. char *pAttribMapStart = NULL;
  2436. ((char*)m_pBufHeaderCode->Base())[0] = 0;
  2437. ((char*)m_pBufAttribCode->Base())[0] = 0;
  2438. ((char*)m_pBufParamCode->Base())[0] = 0;
  2439. ((char*)m_pBufALUCode->Base())[0] = 0;
  2440. for ( i=0; i<MAX_SHADER_CONSTANTS; i++ )
  2441. {
  2442. m_bConstantRegisterDefined[i] = false;
  2443. }
  2444. // Track shadow sampler usage for proper declaration
  2445. m_nShadowDepthSampler = nShadowDepthSampler;
  2446. m_bDeclareShadowOption = false;
  2447. // Various flags set while parsing code to drive various declaration instructions
  2448. m_bNeedsD2AddTemp = false;
  2449. m_bNeedsLerpTemp = false;
  2450. m_bNeedsNRMTemp = false;
  2451. m_bNeedsSinCosDeclarations = false;
  2452. m_bDeclareAddressReg = false;
  2453. m_bDeclareVSOPos = false;
  2454. m_bDeclareVSOFog = false;
  2455. m_dwTexCoordOutMask = 0x00000000;
  2456. m_bOutputColorRegister[0] = false;
  2457. m_bOutputColorRegister[1] = false;
  2458. m_bOutputColorRegister[2] = false;
  2459. m_bOutputColorRegister[3] = false;
  2460. m_bOutputDepthRegister = false;
  2461. m_bTangentInputUsed = false;
  2462. m_dwTempUsageMask = 0x00000000;
  2463. m_dwSamplerUsageMask = 0x00000000;
  2464. m_dwConstIntUsageMask = 0x00000000;
  2465. m_dwConstBoolUsageMask = 0x00000000;
  2466. m_nCentroidMask = nCentroidMask;
  2467. m_nHighestRegister = 0;
  2468. m_bUsedAtomicTempVar = false;
  2469. for ( int i=0; i < ARRAYSIZE( m_dwSamplerTypes ); i++ )
  2470. {
  2471. m_dwSamplerTypes[i] = SAMPLER_TYPE_UNUSED;
  2472. }
  2473. for ( int i=0; i < ARRAYSIZE( m_DeclaredOutputs ); i++ )
  2474. {
  2475. m_DeclaredOutputs[i] = UNDECLARED_OUTPUT;
  2476. }
  2477. memset( m_dwAttribMap, 0xFF, sizeof(m_dwAttribMap) );
  2478. m_pdwBaseToken = m_pdwNextToken = code; // Initialize dwToken pointers
  2479. dwToken = GetNextToken();
  2480. m_dwMajorVersion = D3DSHADER_VERSION_MAJOR( dwToken );
  2481. m_dwMinorVersion = D3DSHADER_VERSION_MINOR( dwToken );
  2482. // We only do vs_2_0 and ps_2_x
  2483. if ( m_dwMajorVersion != 2 )
  2484. {
  2485. Debugger();
  2486. }
  2487. // If pixel shader
  2488. char *glslBindableUniformExtText = (char*)((m_bGLSL && m_bUseBindableUniforms) ? "#extension GL_EXT_bindable_uniform : enable\n" : "");
  2489. if ( ( dwToken & 0xFFFF0000 ) == 0xFFFF0000 )
  2490. {
  2491. // must explicitly enable extensions if emitting GLSL
  2492. V_snprintf( (char *)m_pBufHeaderCode->Base(), m_pBufHeaderCode->Size(), m_bGLSL ? "#version 120\n%s" : "!!ARBfp1.0\n", glslBindableUniformExtText );
  2493. m_bVertexShader = false;
  2494. }
  2495. else // vertex shader
  2496. {
  2497. m_bGenerateSRGBWriteSuffix = false;
  2498. if ( m_bGLSL )
  2499. {
  2500. V_snprintf( (char *)m_pBufHeaderCode->Base(), m_pBufHeaderCode->Size(), "#version 120\n%s//ATTRIBMAP-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx\n", glslBindableUniformExtText );
  2501. }
  2502. else // asm
  2503. {
  2504. if ( m_bDoUserClipPlanes )
  2505. {
  2506. // include "OPTION NV_vertex_program2;"
  2507. V_snprintf( (char *)m_pBufHeaderCode->Base(), m_pBufHeaderCode->Size(), "!!ARBvp1.0\n#//ATTRIBMAP-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx\nOPTION NV_vertex_program2;\n" );
  2508. }
  2509. else
  2510. {
  2511. // do not include "OPTION NV_vertex_program2;"
  2512. V_snprintf( (char *)m_pBufHeaderCode->Base(), m_pBufHeaderCode->Size(), "!!ARBvp1.0\n#//ATTRIBMAP-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx-xx\n" );
  2513. }
  2514. }
  2515. // find that first '-xx' which is where the attrib map will be written later.
  2516. pAttribMapStart = strstr( (char *)m_pBufHeaderCode->Base(), "-xx" ) + 1;
  2517. m_bVertexShader = true;
  2518. }
  2519. *bVertexShader = m_bVertexShader;
  2520. if ( m_bAddHexCodeComments )
  2521. {
  2522. RecordInputAndOutputPositions();
  2523. }
  2524. if ( m_bSpew )
  2525. {
  2526. printf("\n************* translating shader " );
  2527. }
  2528. int opcounter = 0;
  2529. // Loop until we hit the end dwToken...note that D3DPS_END() == D3DVS_END() so this works for either
  2530. while ( dwToken != D3DPS_END() )
  2531. {
  2532. if ( m_bAddHexCodeComments )
  2533. {
  2534. AddTokenHexCode();
  2535. RecordInputAndOutputPositions();
  2536. }
  2537. #ifdef POSIX
  2538. int tokenIndex = m_pdwNextToken - code;
  2539. #endif
  2540. int aluCodeLength0 = V_strlen( (char *) m_pBufALUCode->Base() );
  2541. dwToken = GetNextToken(); // Get next dwToken in the stream
  2542. nInstruction = Opcode( dwToken ); // Mask out the instruction opcode
  2543. if ( m_bSpew )
  2544. {
  2545. #ifdef POSIX
  2546. printf("\n** token# %04x inst# %04d opcode %s (%08x)", tokenIndex, opcounter, GLMDecode(eD3D_SIO, nInstruction), dwToken );
  2547. #endif
  2548. opcounter++;
  2549. }
  2550. switch ( nInstruction )
  2551. {
  2552. // -- No arguments at all -----------------------------------------------
  2553. case D3DSIO_NOP:
  2554. case D3DSIO_PHASE:
  2555. case D3DSIO_RET:
  2556. case D3DSIO_ENDLOOP:
  2557. case D3DSIO_BREAK:
  2558. DebuggerBreakIfDebugging();
  2559. PrintOpcode( nInstruction, buff, sizeof( buff ) );
  2560. StrcatToALUCode( buff );
  2561. StrcatToALUCode( ";\n" );
  2562. break;
  2563. // -- "Declarative" non dcl ops ----------------------------------------
  2564. case D3DSIO_TEXDEPTH:
  2565. case D3DSIO_TEXKILL:
  2566. Handle_DeclarativeNonDclOp( nInstruction );
  2567. break;
  2568. // -- Unary ops -------------------------------------------------
  2569. case D3DSIO_BEM:
  2570. case D3DSIO_TEXBEM:
  2571. case D3DSIO_TEXBEML:
  2572. case D3DSIO_TEXDP3:
  2573. case D3DSIO_TEXDP3TEX:
  2574. case D3DSIO_TEXM3x2DEPTH:
  2575. case D3DSIO_TEXM3x2TEX:
  2576. case D3DSIO_TEXM3x3:
  2577. case D3DSIO_TEXM3x3PAD:
  2578. case D3DSIO_TEXM3x3TEX:
  2579. case D3DSIO_TEXM3x3VSPEC:
  2580. case D3DSIO_TEXREG2AR:
  2581. case D3DSIO_TEXREG2GB:
  2582. case D3DSIO_TEXREG2RGB:
  2583. case D3DSIO_LABEL:
  2584. case D3DSIO_CALL:
  2585. case D3DSIO_LOOP:
  2586. case D3DSIO_BREAKP:
  2587. case D3DSIO_DSX:
  2588. case D3DSIO_DSY:
  2589. DebuggerBreakIfDebugging();
  2590. break;
  2591. case D3DSIO_IF:
  2592. Assert( m_bGLSL && m_bAllowStaticControlFlow );
  2593. if ( m_bGLSL && m_bAllowStaticControlFlow )
  2594. {
  2595. dwToken = GetNextToken();
  2596. PrintParameterToString( dwToken, SRC_REGISTER, buff, sizeof( buff ), false, NULL );
  2597. // In practice, this is the only form of for loop that will appear in DX asm
  2598. PrintToBuf( *m_pBufALUCode, "if ( %s ) {\n", buff );
  2599. }
  2600. break;
  2601. case D3DSIO_ELSE:
  2602. Assert( m_bGLSL && m_bAllowStaticControlFlow );
  2603. if ( m_bGLSL && m_bAllowStaticControlFlow )
  2604. {
  2605. StrcatToALUCode( "}\nelse\n{\n" );
  2606. }
  2607. break;
  2608. case D3DSIO_ENDIF:
  2609. Assert( m_bGLSL && m_bAllowStaticControlFlow );
  2610. if ( m_bGLSL && m_bAllowStaticControlFlow )
  2611. {
  2612. StrcatToALUCode( "}\n" );
  2613. }
  2614. break;
  2615. case D3DSIO_REP: // Start a for loop - GLSL only
  2616. Assert( m_bGLSL && m_bAllowStaticControlFlow );
  2617. if ( m_bGLSL && m_bAllowStaticControlFlow )
  2618. {
  2619. dwToken = GetNextToken();
  2620. PrintParameterToString( dwToken, SRC_REGISTER, buff, sizeof( buff ), false, NULL );
  2621. // In practice, this is the only form of for loop that will appear in DX asm
  2622. PrintToBuf( *m_pBufALUCode, "for( int i=0; i < %s; i++ ) {\n", buff );
  2623. m_nLoopDepth++;
  2624. // For now, we don't deal with loop nesting
  2625. // Easy enough to fix later with an array of loop names i, j, k etc
  2626. Assert( m_nLoopDepth <= 1 );
  2627. }
  2628. break;
  2629. case D3DSIO_ENDREP:
  2630. Assert( m_bGLSL && m_bAllowStaticControlFlow );
  2631. if ( m_bGLSL && m_bAllowStaticControlFlow )
  2632. {
  2633. m_nLoopDepth--;
  2634. StrcatToALUCode( "}\n" );
  2635. }
  2636. break;
  2637. case D3DSIO_NRM:
  2638. Handle_NRM();
  2639. break;
  2640. case D3DSIO_MOVA:
  2641. if ( m_bGLSL )
  2642. {
  2643. Handle_UnaryOp( nInstruction );
  2644. }
  2645. else // asm
  2646. {
  2647. m_bDeclareAddressReg = true;
  2648. m_nHighestRegister = DXABSTRACT_VS_PARAM_SLOTS - 1;
  2649. PrintOpcode( nInstruction, buff, sizeof( buff ) );
  2650. StrcatToALUCode( buff );
  2651. dwToken = GetNextToken();
  2652. PrintParameterToString( dwToken, DST_REGISTER, buff, sizeof( buff ), false, NULL );
  2653. StrcatToALUCode( buff );
  2654. StrcatToALUCode( ", " );
  2655. dwToken = GetNextToken();
  2656. PrintParameterToString( dwToken, SRC_REGISTER, buff, sizeof( buff ), false, NULL );
  2657. StrcatToALUCode( buff );
  2658. StrcatToALUCode( ";\n" );
  2659. }
  2660. break;
  2661. // Unary operations
  2662. case D3DSIO_MOV:
  2663. case D3DSIO_RCP:
  2664. case D3DSIO_RSQ:
  2665. case D3DSIO_EXP:
  2666. case D3DSIO_EXPP:
  2667. case D3DSIO_LOG:
  2668. case D3DSIO_LOGP:
  2669. case D3DSIO_FRC:
  2670. case D3DSIO_LIT:
  2671. case D3DSIO_ABS:
  2672. Handle_UnaryOp( nInstruction );
  2673. break;
  2674. // -- Binary ops -------------------------------------------------
  2675. case D3DSIO_TEXM3x3SPEC:
  2676. case D3DSIO_M4x4:
  2677. case D3DSIO_M4x3:
  2678. case D3DSIO_M3x4:
  2679. case D3DSIO_M3x3:
  2680. case D3DSIO_M3x2:
  2681. case D3DSIO_CALLNZ:
  2682. case D3DSIO_IFC:
  2683. case D3DSIO_BREAKC:
  2684. case D3DSIO_SETP:
  2685. DebuggerBreakIfDebugging();
  2686. break;
  2687. // Binary Operations
  2688. case D3DSIO_ADD:
  2689. case D3DSIO_SUB:
  2690. case D3DSIO_MUL:
  2691. case D3DSIO_DP3:
  2692. case D3DSIO_DP4:
  2693. case D3DSIO_MIN:
  2694. case D3DSIO_MAX:
  2695. case D3DSIO_DST:
  2696. case D3DSIO_SLT:
  2697. case D3DSIO_SGE:
  2698. case D3DSIO_CRS:
  2699. case D3DSIO_POW:
  2700. if ( m_bGLSL )
  2701. {
  2702. HandleBinaryOp_GLSL( nInstruction );
  2703. }
  2704. else
  2705. {
  2706. HandleBinaryOp_ASM( nInstruction );
  2707. }
  2708. break;
  2709. // -- Ternary ops -------------------------------------------------
  2710. case D3DSIO_DP2ADD:
  2711. Handle_DP2ADD();
  2712. break;
  2713. case D3DSIO_LRP:
  2714. Handle_LRP( nInstruction );
  2715. break;
  2716. case D3DSIO_SGN:
  2717. Assert( m_bVertexShader );
  2718. DebuggerBreakIfDebugging(); // TODO emulate with SLT etc
  2719. break;
  2720. case D3DSIO_CND:
  2721. DebuggerBreakIfDebugging();
  2722. break;
  2723. case D3DSIO_CMP:
  2724. Handle_CMP();
  2725. break;
  2726. case D3DSIO_SINCOS:
  2727. Handle_SINCOS();
  2728. break;
  2729. case D3DSIO_MAD:
  2730. Handle_MAD( nInstruction );
  2731. break;
  2732. // -- Quaternary op ------------------------------------------------
  2733. case D3DSIO_TEXLDD:
  2734. Handle_TexLDD( nInstruction );
  2735. break;
  2736. // -- Special cases: texcoord vs texcrd and tex vs texld -----------
  2737. case D3DSIO_TEXCOORD:
  2738. Handle_TexCoord();
  2739. break;
  2740. case D3DSIO_TEX:
  2741. Handle_TEX( dwToken, false );
  2742. break;
  2743. case D3DSIO_TEXLDL:
  2744. Handle_TEX( nInstruction, true );
  2745. break;
  2746. case D3DSIO_DCL:
  2747. Handle_DCL();
  2748. break;
  2749. case D3DSIO_DEFB:
  2750. case D3DSIO_DEFI:
  2751. // Shouldn't be using bool or integer constants
  2752. DebuggerBreakIfDebugging();
  2753. break;
  2754. case D3DSIO_DEF:
  2755. Handle_DEF();
  2756. break;
  2757. case D3DSIO_COMMENT:
  2758. // Using OpcodeSpecificData() can fail here since the comments can be longer than 0xff dwords
  2759. nNumTokensToSkip = ( dwToken & 0x0fff0000 ) >> 16;
  2760. SkipTokens( nNumTokensToSkip );
  2761. break;
  2762. case D3DSIO_END:
  2763. break;
  2764. }
  2765. if ( m_bSpew )
  2766. {
  2767. int aluCodeLength1 = V_strlen( (char *) m_pBufALUCode->Base() );
  2768. if ( aluCodeLength1 != aluCodeLength0 )
  2769. {
  2770. // code was emitted
  2771. printf( "\n > %s", ((char *)m_pBufALUCode->Base()) + aluCodeLength0 );
  2772. aluCodeLength0 = aluCodeLength1;
  2773. }
  2774. }
  2775. }
  2776. // Note that this constant packing expects .wzyx swizzles in case we ever use the SINCOS code in a ps_2_x shader
  2777. //
  2778. // The Microsoft documentation on this is all kinds of broken and, strangely, these numbers don't even
  2779. // match the D3DSINCOSCONST1 and D3DSINCOSCONST2 constants used by the D3D assembly sincos instruction...
  2780. if ( m_bNeedsSinCosDeclarations )
  2781. {
  2782. if ( m_bGLSL )
  2783. {
  2784. StrcatToParamCode( "vec4 scA = vec4( -1.55009923e-6, -2.17013894e-5, 0.00260416674, 0.00026041668 );\n" );
  2785. StrcatToParamCode( "vec4 scB = vec4( -0.020833334, -0.125, 1.0, 0.5 );\n" );
  2786. }
  2787. else
  2788. {
  2789. StrcatToParamCode( "PARAM scA = { -1.55009923e-6, -2.17013894e-5, 0.00260416674, 0.00026041668 };\n" );
  2790. StrcatToParamCode( "PARAM scB = { -0.020833334, -0.125, 1.0, 0.5 };\n" );
  2791. }
  2792. }
  2793. // Stick in the sampler mask in hex
  2794. PrintToBuf( *m_pBufHeaderCode, "%sSAMPLERMASK-%x\n", m_bGLSL ? "//" : "#", m_dwSamplerUsageMask );
  2795. // Uniforms
  2796. if ( m_bGLSL )
  2797. {
  2798. PrintToBuf( *m_pBufHeaderCode, "//HIGHWATER-%d\n", m_nHighestRegister );
  2799. PrintToBuf( *m_pBufHeaderCode, "\n%suniform vec4 %s[%d];\n", m_bUseBindableUniforms ? "bindable " : "", m_bVertexShader ? "vc" : "pc", m_nHighestRegister + 1 );
  2800. // On GLSL vertex shaders, we may have integer and boolean constants
  2801. if ( m_bAllowStaticControlFlow && m_bVertexShader )
  2802. {
  2803. for( int i=0; i<32; i++ )
  2804. {
  2805. if ( m_dwConstIntUsageMask & ( 0x00000001 << i ) )
  2806. {
  2807. PrintToBuf( *m_pBufHeaderCode, "uniform int i%d;\n", i );
  2808. }
  2809. }
  2810. for( int i=0; i<32; i++ )
  2811. {
  2812. if ( m_dwConstBoolUsageMask & ( 0x00000001 << i ) )
  2813. {
  2814. PrintToBuf( *m_pBufHeaderCode, "uniform bool b%d;\n", i );
  2815. }
  2816. }
  2817. }
  2818. // Control bit for sRGB Write suffix
  2819. if ( m_bGenerateSRGBWriteSuffix )
  2820. {
  2821. // R500 Hookup
  2822. // Set this guy to 1 when the sRGBWrite state is true, otherwise 0
  2823. StrcatToHeaderCode( "uniform float flSRGBWrite;\n" );
  2824. }
  2825. PrintToBuf( *m_pBufHeaderCode, "\n" );
  2826. // Write samplers
  2827. WriteGLSLSamplerDefinitions();
  2828. }
  2829. else
  2830. {
  2831. PrintToBuf( *m_pBufParamCode, "#HIGHWATER-%d\n", m_nHighestRegister );
  2832. PrintToBuf( *m_pBufParamCode, "PARAM %s[%d] = { program.%s[0..%d] };\n", m_bVertexShader ? "vc" : "pc", m_nHighestRegister + 1, m_bUseEnvParams ? "env" : "local", m_nHighestRegister );
  2833. }
  2834. if ( m_bDeclareAddressReg )
  2835. {
  2836. m_nHighestRegister = DXABSTRACT_VS_PARAM_SLOTS - 1;
  2837. if ( m_bGLSL )
  2838. {
  2839. StrcatToParamCode( "vec4 va_r;\nint a0;\n" );
  2840. }
  2841. else
  2842. {
  2843. StrcatToParamCode( "ADDRESS a0;\n" );
  2844. StrcatToParamCode( "TEMP VA_REG;\n" );
  2845. }
  2846. }
  2847. char *pTempVarStr = "TEMP";
  2848. if ( m_bGLSL )
  2849. {
  2850. pTempVarStr = "vec4";
  2851. }
  2852. // Declare temps in Param code buffer
  2853. for( int i=0; i<32; i++ )
  2854. {
  2855. if ( m_dwTempUsageMask & ( 0x00000001 << i ) )
  2856. {
  2857. PrintToBuf( *m_pBufParamCode, "%s r%d;\n", pTempVarStr, i );
  2858. }
  2859. }
  2860. if ( m_bGLSL && m_bVertexShader )
  2861. {
  2862. StrcatToParamCode( "vec4 vTempPos;\n" );
  2863. }
  2864. if ( m_bNeedsSinCosDeclarations )
  2865. {
  2866. if ( m_bGLSL )
  2867. {
  2868. StrcatToParamCode( "vec3 vSinCosTmp;\n" ); // declare temp used by GLSL sin and cos intrinsics
  2869. }
  2870. else
  2871. {
  2872. PrintToBuf( *m_pBufParamCode, "%s SC_TEMP;\n", pTempVarStr );
  2873. }
  2874. }
  2875. // Optional temps needed to emulate d2add instruction in DX pixel shaders
  2876. if ( m_bNeedsD2AddTemp )
  2877. {
  2878. PrintToBuf( *m_pBufParamCode, "%s DP2A0;\n%s DP2A1;\n", pTempVarStr, pTempVarStr );
  2879. }
  2880. // Optional temp needed to emulate lerp instruction in DX vertex shaders
  2881. if ( m_bNeedsLerpTemp )
  2882. {
  2883. PrintToBuf( *m_pBufParamCode, "%s LRP_TEMP;\n", pTempVarStr );
  2884. }
  2885. // Optional temp needed to emulate NRM instruction in DX shaders
  2886. if ( m_bNeedsNRMTemp )
  2887. {
  2888. PrintToBuf( *m_pBufParamCode, "%s NRM_TEMP;\n", pTempVarStr );
  2889. }
  2890. // Pixel shader color outputs (MRT support?...just declare MRT outputs as useless TEMPS)
  2891. if ( !m_bGLSL && !m_bVertexShader )
  2892. {
  2893. if ( m_bOutputColorRegister[1] )
  2894. {
  2895. StrcatToParamCode( "TEMP oC1;\n" );
  2896. }
  2897. if ( m_bOutputColorRegister[2] )
  2898. {
  2899. StrcatToParamCode( "TEMP oC2;\n" );
  2900. }
  2901. if ( m_bOutputColorRegister[3] )
  2902. {
  2903. StrcatToParamCode( "TEMP oC3;\n" );
  2904. }
  2905. if ( m_bOutputColorRegister[0] )
  2906. {
  2907. StrcatToParamCode( "OUTPUT oC0 = result.color;\n" );
  2908. }
  2909. }
  2910. if ( m_bDeclareVSOPos && m_bVertexShader )
  2911. {
  2912. if ( m_bGLSL )
  2913. {
  2914. if (m_bDoUserClipPlanes)
  2915. {
  2916. StrcatToALUCode( "gl_ClipVertex = vTempPos;\n" ); // if user clip is enabled, jam clip space position into gl_ClipVertex
  2917. }
  2918. }
  2919. if ( m_bDoFixupZ || m_bDoFixupY )
  2920. {
  2921. if ( !m_bGLSL )
  2922. {
  2923. // don't write to real reg - declare a temp and then declare a new output reg oPosGL
  2924. StrcatToParamCode( "TEMP oPos;\n" );
  2925. StrcatToParamCode( "OUTPUT oPosGL = result.position;\n" );
  2926. }
  2927. // TODO: insert clip distance computation something like this:
  2928. //
  2929. // StrcatToALUCode( "DP4 oCLP[0].x, oPos, vc[215]; \n" );
  2930. //
  2931. if ( m_bDoFixupZ )
  2932. {
  2933. if ( m_bGLSL )
  2934. {
  2935. StrcatToALUCode( "vTempPos.z = vTempPos.z * vc[0].z - vTempPos.w; // z' = (2*z)-w\n" );
  2936. }
  2937. else
  2938. {
  2939. // append instructions to perform Z fixup
  2940. // new Z = (old Z * 2.0) - W
  2941. // negate Z, double it, then add the 'w'.
  2942. // near: Z=0 -> Z' = +1.0. this seems wrong....
  2943. // far: Z=1 -> Z' = -1.0 uh, this ain't right...
  2944. // StrcatToALUCode( "MAD r0.z, -oPos.z, vc[0].z, oPos.w; # z' = (2*-z)+w\n" );
  2945. // double Z, subtract 'w'.
  2946. // near: Z=0 -> Z' = -1.0.
  2947. // far: Z=1 -> Z' = +1.0
  2948. //StrcatToALUCode( "MAD r0.z, oPos.z, vc[0].z, -oPos.w; # z' = (2*z)-w\n" );
  2949. StrcatToALUCode( "MAD oPos.z, oPos.z, vc[0].z, -oPos.w; # z' = (2*z)-w\n" );
  2950. }
  2951. }
  2952. if ( m_bDoFixupY )
  2953. {
  2954. // append instructions to flip Y over
  2955. // new Y = -(old Y)
  2956. if ( m_bGLSL )
  2957. {
  2958. StrcatToALUCode( "vTempPos.y = -vTempPos.y; // y' = -y \n" );
  2959. }
  2960. else
  2961. {
  2962. StrcatToALUCode( "MOV oPos.y, -oPos.y; # y' = -y \n" );
  2963. }
  2964. }
  2965. if ( m_bGLSL )
  2966. {
  2967. StrcatToALUCode( "gl_Position = vTempPos;\n" );
  2968. }
  2969. else
  2970. {
  2971. StrcatToALUCode( "MOV oPosGL, oPos;\n" );
  2972. }
  2973. }
  2974. else
  2975. {
  2976. StrcatToParamCode( "OUTPUT oPos = result.position;\n" );
  2977. // TODO: insert clip distance computation something like this:
  2978. //
  2979. // StrcatToALUCode( "DP4 oCLP[0].x, oPos, c[215]; \n" );
  2980. //
  2981. }
  2982. }
  2983. if ( m_bVertexShader && m_bDoUserClipPlanes && !m_bGLSL )
  2984. {
  2985. // insert oCLP generation instructions
  2986. char temp[256];
  2987. if(0)
  2988. {
  2989. V_snprintf( temp, sizeof( temp ), "DP4 result.clip[0].x, oPos, c[%d];\n", DXABSTRACT_VS_CLIP_PLANE_BASE ); // ask GLM where to stash the secret params
  2990. V_snprintf( temp, sizeof( temp ), "DP4 result.clip[1].x, oPos, c[%d];\n", DXABSTRACT_VS_CLIP_PLANE_BASE+1 );
  2991. }
  2992. if(0)
  2993. {
  2994. V_snprintf( temp, sizeof( temp ), "DP4 o[CLP0].x, oPos, c[%d];\n", DXABSTRACT_VS_CLIP_PLANE_BASE ); // ask GLM where to stash the secret params
  2995. V_snprintf( temp, sizeof( temp ), "DP4 o[CLP1].x, oPos, c[%d];\n", DXABSTRACT_VS_CLIP_PLANE_BASE+1 );
  2996. }
  2997. if(1)
  2998. {
  2999. V_snprintf( temp, sizeof( temp ), "DP4 oClip0.x, oPos, c[%d];\n", DXABSTRACT_VS_CLIP_PLANE_BASE ); // ask GLM where to stash the secret params
  3000. V_snprintf( temp, sizeof( temp ), "DP4 oClip1.x, oPos, c[%d];\n", DXABSTRACT_VS_CLIP_PLANE_BASE+1 );
  3001. }
  3002. StrcatToALUCode( temp );
  3003. }
  3004. if ( m_bGLSL )
  3005. {
  3006. if ( m_bVertexShader )
  3007. {
  3008. for ( int i=0; i<32; i++ )
  3009. {
  3010. char outTexCoordBuff[64];
  3011. if ( m_dwTexCoordOutMask & ( 0x00000001 << i ) )
  3012. {
  3013. if ( m_nCentroidMask & ( 0x00000001 << i ) )
  3014. {
  3015. V_snprintf( outTexCoordBuff, sizeof( outTexCoordBuff ), "centroid varying vec4 oT%d;\n", i ); // centroid varying
  3016. StrcatToHeaderCode( outTexCoordBuff );
  3017. }
  3018. else
  3019. {
  3020. V_snprintf( outTexCoordBuff, sizeof( outTexCoordBuff ), "varying vec4 oT%d;\n", i );
  3021. StrcatToHeaderCode( outTexCoordBuff );
  3022. }
  3023. }
  3024. }
  3025. }
  3026. }
  3027. else // asm
  3028. {
  3029. if ( m_bDeclareVSOFog && m_bVertexShader )
  3030. {
  3031. StrcatToParamCode( "OUTPUT oFog = result.fogcoord;\n" );
  3032. }
  3033. for ( int i=0; i<32; i++ )
  3034. {
  3035. char outTexCoordBuff[64];
  3036. if ( m_dwTexCoordOutMask & ( 0x00000001 << i ) )
  3037. {
  3038. V_snprintf( outTexCoordBuff, sizeof( outTexCoordBuff ), "OUTPUT oT%d = result.texcoord[%d];\n", i, i );
  3039. StrcatToParamCode( outTexCoordBuff );
  3040. }
  3041. }
  3042. if ( m_bOutputColorRegister[0] && m_bVertexShader )
  3043. {
  3044. StrcatToParamCode( "OUTPUT oD0 = result.color;\n" );
  3045. }
  3046. if ( m_bOutputColorRegister[1] && m_bVertexShader )
  3047. {
  3048. StrcatToParamCode( "OUTPUT oD1 = result.color.secondary;\n" );
  3049. }
  3050. }
  3051. if ( m_bOutputDepthRegister && !m_bVertexShader && !m_bGLSL )
  3052. {
  3053. StrcatToParamCode( "OUTPUT oDepth = result.depth;\n" );
  3054. }
  3055. if ( m_bDoUserClipPlanes && m_bVertexShader && !m_bGLSL )
  3056. {
  3057. StrcatToParamCode( "OUTPUT oClip0 = result.clip[0];\n" );
  3058. StrcatToParamCode( "OUTPUT oClip1 = result.clip[1];\n" );
  3059. }
  3060. // do some annotation at the end of the attrib block
  3061. {
  3062. char temp[1000];
  3063. if ( m_bVertexShader )
  3064. {
  3065. // write attrib map into the text starting at pAttribMapStart - two hex digits per attrib
  3066. for( int i=0; i<16; i++ )
  3067. {
  3068. if ( m_dwAttribMap[i] != 0xFFFFFFFF )
  3069. {
  3070. V_snprintf( temp, sizeof(temp), "%02X", m_dwAttribMap[i] );
  3071. memcpy( pAttribMapStart + (i*3), temp, 2 );
  3072. }
  3073. }
  3074. }
  3075. V_snprintf( temp, sizeof(temp), "%s trans#%d label:%s\n", m_bGLSL ? "//" : "#", g_translationCounter, debugLabel ? debugLabel : "none" );
  3076. StrcatToAttribCode( temp );
  3077. g_translationCounter++;
  3078. }
  3079. // If we actually sample from a shadow depth sampler, we need to declare the shadow option at the top
  3080. if ( m_bDeclareShadowOption )
  3081. {
  3082. StrcatToHeaderCode( "OPTION ARB_fragment_program_shadow;\n" );
  3083. }
  3084. if ( m_bGLSL )
  3085. {
  3086. StrcatToHeaderCode( "\nvoid main()\n{\n" );
  3087. if ( m_bUsedAtomicTempVar )
  3088. {
  3089. PrintToBuf( *m_pBufHeaderCode, "vec4 %s;\n\n", g_pAtomicTempVarName );
  3090. }
  3091. }
  3092. // sRGB Write suffix
  3093. if ( m_bGenerateSRGBWriteSuffix )
  3094. {
  3095. Assert( m_bGLSL );
  3096. if ( m_bGLSL )
  3097. {
  3098. StrcatToALUCode( "vec3 sRGBFragData;\n" );
  3099. StrcatToALUCode( "sRGBFragData.xyz = log( gl_FragData[0].xyz );\n" );
  3100. StrcatToALUCode( "sRGBFragData.xyz = sRGBFragData.xyz * vec3( 0.454545f, 0.454545f, 0.454545f );\n" );
  3101. StrcatToALUCode( "sRGBFragData.xyz = exp( sRGBFragData.xyz );\n" );
  3102. StrcatToALUCode( "gl_FragData[0].xyz = mix( gl_FragData[0].xyz, sRGBFragData, flSRGBWrite );\n" );
  3103. }
  3104. }
  3105. if ( m_bGLSL )
  3106. {
  3107. WriteGLSLOutputVariableAssignments();
  3108. StrcatToALUCode( "\n}\n" );
  3109. }
  3110. else
  3111. {
  3112. StrcatToALUCode( "END\n\0" );
  3113. }
  3114. // Put all of the strings together for final program ( pHeaderCode + pAttribCode + pParamCode + pALUCode )
  3115. StrcatToHeaderCode( (char*)m_pBufAttribCode->Base() );
  3116. StrcatToHeaderCode( (char*)m_pBufParamCode->Base() );
  3117. StrcatToHeaderCode( (char*)m_pBufALUCode->Base() );
  3118. // Cleanup - don't touch m_pBufHeaderCode, as it is managed by the caller
  3119. delete m_pBufAttribCode;
  3120. delete m_pBufParamCode;
  3121. delete m_pBufALUCode;
  3122. m_pBufAttribCode = m_pBufParamCode = m_pBufALUCode = NULL;
  3123. if ( m_bSpew )
  3124. {
  3125. printf("\n************* translation complete\n\n " );
  3126. }
  3127. return DISASM_OK;
  3128. }