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.

1106 lines
27 KiB

  1. use String::CRC32;
  2. BEGIN {use File::Basename; push @INC, dirname($0); }
  3. require "valve_perl_helpers.pl";
  4. sub WriteHelperVar
  5. {
  6. local( $name ) = shift;
  7. local( $min ) = shift;
  8. local( $max ) = shift;
  9. local( $varname ) = "m_n" . $name;
  10. local( $boolname ) = "m_b" . $name;
  11. push @outputHeader, "private:\n";
  12. push @outputHeader, "\tint $varname;\n";
  13. push @outputHeader, "#ifdef _DEBUG\n";
  14. push @outputHeader, "\tbool $boolname;\n";
  15. push @outputHeader, "#endif\n";
  16. push @outputHeader, "public:\n";
  17. # int version of set function
  18. push @outputHeader, "\tvoid Set" . $name . "( int i )\n";
  19. push @outputHeader, "\t{\n";
  20. if ( $min != $max )
  21. {
  22. push @outputHeader, "\t\tAssert( i >= $min && i <= $max );\n";
  23. push @outputHeader, "\t\t$varname = i;\n";
  24. push @outputHeader, "#ifdef _DEBUG\n";
  25. push @outputHeader, "\t\t$boolname = true;\n";
  26. push @outputHeader, "#endif\n";
  27. }
  28. push @outputHeader, "\t}\n";
  29. # bool version of set function
  30. push @outputHeader, "\tvoid Set" . $name . "( bool i )\n";
  31. push @outputHeader, "\t{\n";
  32. if ( $min != $max )
  33. {
  34. # push @outputHeader, "\t\tAssert( i >= $min && i <= $max );\n";
  35. push @outputHeader, "\t\t$varname = i ? 1 : 0;\n";
  36. push @outputHeader, "#ifdef _DEBUG\n";
  37. push @outputHeader, "\t\t$boolname = true;\n";
  38. push @outputHeader, "#endif\n";
  39. }
  40. push @outputHeader, "\t}\n";
  41. }
  42. sub WriteStaticBoolExpression
  43. {
  44. local( $prefix ) = shift;
  45. local( $operator ) = shift;
  46. for( $i = 0; $i < scalar( @staticDefineNames ); $i++ )
  47. {
  48. if( $i )
  49. {
  50. push @outputHeader, " $operator ";
  51. }
  52. local( $name ) = @staticDefineNames[$i];
  53. local( $boolname ) = "m_b" . $name;
  54. push @outputHeader, "$prefix$boolname";
  55. }
  56. push @outputHeader, ";\n";
  57. }
  58. sub WriteDynamicBoolExpression
  59. {
  60. local( $prefix ) = shift;
  61. local( $operator ) = shift;
  62. for( $i = 0; $i < scalar( @dynamicDefineNames ); $i++ )
  63. {
  64. if( $i )
  65. {
  66. push @outputHeader, " $operator ";
  67. }
  68. local( $name ) = @dynamicDefineNames[$i];
  69. local( $boolname ) = "m_b" . $name;
  70. push @outputHeader, "$prefix$boolname";
  71. }
  72. push @outputHeader, ";\n";
  73. }
  74. sub WriteDynamicHelperClasses
  75. {
  76. local( $basename ) = $fxc_filename;
  77. $basename =~ s/\.fxc//i;
  78. $basename =~ tr/A-Z/a-z/;
  79. local( $classname ) = $basename . "_Dynamic_Index";
  80. push @outputHeader, "class $classname\n";
  81. push @outputHeader, "{\n";
  82. for( $i = 0; $i < scalar( @dynamicDefineNames ); $i++ )
  83. {
  84. $name = $dynamicDefineNames[$i];
  85. $min = $dynamicDefineMin[$i];
  86. $max = $dynamicDefineMax[$i];
  87. &WriteHelperVar( $name, $min, $max );
  88. }
  89. push @outputHeader, "public:\n";
  90. push @outputHeader, "\t$classname()\n";
  91. push @outputHeader, "\t{\n";
  92. for( $i = 0; $i < scalar( @dynamicDefineNames ); $i++ )
  93. {
  94. $min = $dynamicDefineMin[$i];
  95. $max = $dynamicDefineMax[$i];
  96. local( $name ) = @dynamicDefineNames[$i];
  97. local( $boolname ) = "m_b" . $name;
  98. local( $varname ) = "m_n" . $name;
  99. push @outputHeader, "#ifdef _DEBUG\n";
  100. if ( $min != $max )
  101. {
  102. push @outputHeader, "\t\t$boolname = false;\n";
  103. }
  104. else
  105. {
  106. push @outputHeader, "\t\t$boolname = true;\n";
  107. }
  108. push @outputHeader, "#endif // _DEBUG\n";
  109. push @outputHeader, "\t\t$varname = 0;\n";
  110. }
  111. push @outputHeader, "\t}\n";
  112. push @outputHeader, "\tint GetIndex()\n";
  113. push @outputHeader, "\t{\n";
  114. push @outputHeader, "\t\t// Asserts to make sure that we aren't using any skipped combinations.\n";
  115. foreach $skip (@perlskipcodeindividual)
  116. {
  117. $skip =~ s/\$/m_n/g;
  118. # push @outputHeader, "\t\tAssert( !( $skip ) );\n";
  119. }
  120. push @outputHeader, "\t\t// Asserts to make sure that we are setting all of the combination vars.\n";
  121. push @outputHeader, "#ifdef _DEBUG\n";
  122. if( scalar( @dynamicDefineNames ) > 0 )
  123. {
  124. push @outputHeader, "\t\tbool bAllDynamicVarsDefined = ";
  125. WriteDynamicBoolExpression( "", "&&" );
  126. }
  127. if( scalar( @dynamicDefineNames ) > 0 )
  128. {
  129. push @outputHeader, "\t\tAssert( bAllDynamicVarsDefined );\n";
  130. }
  131. push @outputHeader, "#endif // _DEBUG\n";
  132. if( $spewCombos && scalar( @dynamicDefineNames ) )
  133. {
  134. push @outputHeader, &CreateCCodeToSpewDynamicCombo();
  135. }
  136. push @outputHeader, "\t\treturn ";
  137. local( $scale ) = 1;
  138. for( $i = 0; $i < scalar( @dynamicDefineNames ); $i++ )
  139. {
  140. local( $name ) = @dynamicDefineNames[$i];
  141. local( $varname ) = "m_n" . $name;
  142. push @outputHeader, "( $scale * $varname ) + ";
  143. $scale *= $dynamicDefineMax[$i] - $dynamicDefineMin[$i] + 1;
  144. }
  145. push @outputHeader, "0;\n";
  146. push @outputHeader, "\t}\n";
  147. push @outputHeader, "};\n";
  148. }
  149. sub WriteStaticHelperClasses
  150. {
  151. local( $basename ) = $fxc_filename;
  152. $basename =~ s/\.fxc//i;
  153. $basename =~ tr/A-Z/a-z/;
  154. local( $classname ) = $basename . "_Static_Index";
  155. push @outputHeader, "class $classname\n";
  156. push @outputHeader, "{\n";
  157. for( $i = 0; $i < scalar( @staticDefineNames ); $i++ )
  158. {
  159. $name = $staticDefineNames[$i];
  160. $min = $staticDefineMin[$i];
  161. $max = $staticDefineMax[$i];
  162. &WriteHelperVar( $name, $min, $max );
  163. }
  164. push @outputHeader, "public:\n";
  165. push @outputHeader, "\t$classname()\n";
  166. push @outputHeader, "\t{\n";
  167. for( $i = 0; $i < scalar( @staticDefineNames ); $i++ )
  168. {
  169. $min = $staticDefineMin[$i];
  170. $max = $staticDefineMax[$i];
  171. local( $name ) = @staticDefineNames[$i];
  172. local( $boolname ) = "m_b" . $name;
  173. local( $varname ) = "m_n" . $name;
  174. push @outputHeader, "#ifdef _DEBUG\n";
  175. if ( $min != $max )
  176. {
  177. push @outputHeader, "\t\t$boolname = false;\n";
  178. }
  179. else
  180. {
  181. push @outputHeader, "\t\t$boolname = true;\n";
  182. }
  183. push @outputHeader, "#endif // _DEBUG\n";
  184. push @outputHeader, "\t\t$varname = 0;\n";
  185. }
  186. push @outputHeader, "\t}\n";
  187. push @outputHeader, "\tint GetIndex()\n";
  188. push @outputHeader, "\t{\n";
  189. push @outputHeader, "\t\t// Asserts to make sure that we aren't using any skipped combinations.\n";
  190. foreach $skip (@perlskipcodeindividual)
  191. {
  192. $skip =~ s/\$/m_n/g;
  193. # push @outputHeader, "\t\tAssert( !( $skip ) );\n";
  194. }
  195. push @outputHeader, "\t\t// Asserts to make sure that we are setting all of the combination vars.\n";
  196. push @outputHeader, "#ifdef _DEBUG\n";
  197. if( scalar( @staticDefineNames ) > 0 )
  198. {
  199. push @outputHeader, "\t\tbool bAllStaticVarsDefined = ";
  200. WriteStaticBoolExpression( "", "&&" );
  201. }
  202. if( scalar( @staticDefineNames ) > 0 )
  203. {
  204. push @outputHeader, "\t\tAssert( bAllStaticVarsDefined );\n";
  205. }
  206. push @outputHeader, "#endif // _DEBUG\n";
  207. if( $spewCombos && scalar( @staticDefineNames ) )
  208. {
  209. push @outputHeader, &CreateCCodeToSpewStaticCombo();
  210. }
  211. push @outputHeader, "\t\treturn ";
  212. local( $scale ) = 1;
  213. for( $i = 0; $i < scalar( @dynamicDefineNames ); $i++ )
  214. {
  215. $scale *= $dynamicDefineMax[$i] - $dynamicDefineMin[$i] + 1;
  216. }
  217. for( $i = 0; $i < scalar( @staticDefineNames ); $i++ )
  218. {
  219. local( $name ) = @staticDefineNames[$i];
  220. local( $varname ) = "m_n" . $name;
  221. push @outputHeader, "( $scale * $varname ) + ";
  222. $scale *= $staticDefineMax[$i] - $staticDefineMin[$i] + 1;
  223. }
  224. push @outputHeader, "0;\n";
  225. push @outputHeader, "\t}\n";
  226. push @outputHeader, "};\n";
  227. }
  228. sub CreateFuncToSetPerlVars
  229. {
  230. local( $out ) = "";
  231. $out .= "sub SetPerlVarsFunc\n";
  232. $out .= "{\n";
  233. $out .= " local( \$combo ) = shift;\n";
  234. $out .= " local( \$i );\n";
  235. local( $i );
  236. for( $i = 0; $i < scalar( @dynamicDefineNames ); \$i++ )
  237. {
  238. $out .= " \$$dynamicDefineNames[$i] = \$combo % ";
  239. $out .= ( $dynamicDefineMax[$i] - $dynamicDefineMin[$i] + 1 ) + $dynamicDefineMin[$i];
  240. $out .= ";\n";
  241. $out .= " \$combo = \$combo / " . ( $dynamicDefineMax[$i] - $dynamicDefineMin[$i] + 1 ) . ";\n";
  242. }
  243. for( $i = 0; $i < scalar( @staticDefineNames ); \$i++ )
  244. {
  245. $out .= " \$$staticDefineNames[$i] = \$combo % ";
  246. $out .= ( $staticDefineMax[$i] - $staticDefineMin[$i] + 1 ) + $staticDefineMin[$i];
  247. $out .= ";\n";
  248. $out .= " \$combo = \$combo / " . ( $staticDefineMax[$i] - $staticDefineMin[$i] + 1 ) . ";\n";
  249. }
  250. $out .= "}\n";
  251. # print $out;
  252. eval $out;
  253. }
  254. # These sections can be interchanged to enable profiling.
  255. #$ShowTimers = 1;
  256. #use Time::HiRes;
  257. #sub SampleTime()
  258. #{
  259. # return Time::HiRes::time();
  260. #}
  261. $ShowTimers = 0;
  262. sub SampleTime() { return 0; }
  263. $total_start_time = SampleTime();
  264. # NOTE: These must match the same values in macros.vsh!
  265. $vPos = "v0";
  266. $vBoneWeights = "v1";
  267. $vBoneIndices = "v2";
  268. $vNormal = "v3";
  269. if( $g_x360 )
  270. {
  271. $vPosFlex = "v4";
  272. $vNormalFlex = "v13";
  273. }
  274. $vColor = "v5";
  275. $vSpecular = "v6";
  276. $vTexCoord0 = "v7";
  277. $vTexCoord1 = "v8";
  278. $vTexCoord2 = "v9";
  279. $vTexCoord3 = "v10";
  280. $vTangentS = "v11";
  281. $vTangentT = "v12";
  282. $vUserData = "v14";
  283. sub ReadInputFileWithLineInfo
  284. {
  285. local( $base_filename ) = shift;
  286. local( *INPUT );
  287. local( @output );
  288. # Look in the stdshaders directory, followed by the current directory.
  289. # (This is for the SDK, since some of its files are under stdshaders).
  290. local( $filename ) = $base_filename;
  291. if ( !-e $filename )
  292. {
  293. $filename = "$g_SourceDir\\materialsystem\\stdshaders\\$base_filename";
  294. if ( !-e $filename )
  295. {
  296. die "\nvsh_prep.pl ERROR: missing include file: $filename.\n\n";
  297. }
  298. }
  299. open INPUT, "<$filename" || die;
  300. local( $line );
  301. local( $linenum ) = 1;
  302. while( $line = <INPUT> )
  303. {
  304. $line =~ s/\n//g;
  305. local( $postfix ) = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
  306. $postfix .= "; LINEINFO($filename)($linenum)\n";
  307. if( $line =~ m/\#include\s+\"(.*)\"/i )
  308. {
  309. push @output, &ReadInputFileWithLineInfo( $1 );
  310. }
  311. else
  312. {
  313. push @output, $line . $postfix;
  314. }
  315. $linenum++;
  316. }
  317. close INPUT;
  318. return @output;
  319. }
  320. sub ReadInputFileWithoutLineInfo
  321. {
  322. local( $base_filename ) = shift;
  323. local( *INPUT );
  324. local( @output );
  325. # Look in the stdshaders directory, followed by the current directory.
  326. # (This is for the SDK, since some of its files are under stdshaders).
  327. local( $filename ) = $base_filename;
  328. if ( !-e $filename )
  329. {
  330. $filename = "$g_SourceDir\\materialsystem\\stdshaders\\$base_filename";
  331. if ( !-e $filename )
  332. {
  333. die "\nERROR: missing include file: $filename.\n\n";
  334. }
  335. }
  336. open INPUT, "<$filename" || die;
  337. local( $line );
  338. while( $line = <INPUT> )
  339. {
  340. if( $line =~ m/\#include\s+\"(.*)\"/i )
  341. {
  342. push @output, &ReadInputFileWithoutLineInfo( $1 );
  343. }
  344. else
  345. {
  346. push @output, $line;
  347. }
  348. }
  349. close INPUT;
  350. return @output;
  351. }
  352. sub IsPerl
  353. {
  354. local( $line ) = shift;
  355. if( $line =~ m/^\s*sub.*\,/ )
  356. {
  357. return 0;
  358. }
  359. if( $line =~ m/^\#include/ ||
  360. $line =~ m/^\#define/ ||
  361. $line =~ m/^\#undef/ ||
  362. $line =~ m/^\#ifdef/ ||
  363. $line =~ m/^\#ifndef/ ||
  364. $line =~ m/^\#else/ ||
  365. $line =~ m/^\#endif/ ||
  366. $line =~ m/^\#error/
  367. )
  368. {
  369. return 0;
  370. }
  371. if( $line =~ m/^\s*if\s*\(/ ||
  372. $line =~ m/^\s*else/ ||
  373. $line =~ m/^\s*elsif/ ||
  374. $line =~ m/^\s*for\s*\(/ ||
  375. $line =~ m/^\s*\{/ ||
  376. $line =~ m/^sub\s*/ ||
  377. $line =~ m/^\s*\}/ ||
  378. $line =~ m/^\s*\&/ ||
  379. $line =~ m/^\s*\#/ ||
  380. $line =~ m/^\s*\$/ ||
  381. $line =~ m/^\s*print/ ||
  382. $line =~ m/^\s*return/ ||
  383. $line =~ m/^\s*exit/ ||
  384. $line =~ m/^\s*die/ ||
  385. $line =~ m/^\s*eval/ ||
  386. $line =~ m/^\s*local/ ||
  387. $line =~ m/^\s*my\s+/ ||
  388. $line =~ m/^\s*@/ ||
  389. $line =~ m/^\s*alloc\s+/ ||
  390. $line =~ m/^\s*free\s+/
  391. )
  392. {
  393. return 1;
  394. }
  395. return 0;
  396. }
  397. # translate the output into something that takes us back to the source line
  398. # that we care about in msdev
  399. sub TranslateErrorMessages
  400. {
  401. local( $origline );
  402. while( $origline = shift )
  403. {
  404. if( $origline =~ m/(.*)\((\d+)\)\s*:\s*(.*)$/i )
  405. {
  406. local( $filename ) = $1;
  407. local( $linenum ) = $2;
  408. local( $error ) = $3;
  409. local( *FILE );
  410. open FILE, "<$filename" || die;
  411. local( $i );
  412. local( $line );
  413. for( $i = 1; $i < $linenum; $i++ )
  414. {
  415. $line = <FILE>;
  416. }
  417. if( $line =~ m/LINEINFO\((.*)\)\((.*)\)/ )
  418. {
  419. print "$1\($2\) : $error\n";
  420. my $num = $linenum - 1;
  421. print "$filename\($num\) : original error location\n";
  422. }
  423. close FILE;
  424. }
  425. else
  426. {
  427. $origline =~ s/successful compile\!.*//gi;
  428. if( !( $origline =~ m/^\s*$/ ) )
  429. {
  430. # print "WTF: $origline\n";
  431. }
  432. }
  433. }
  434. }
  435. sub CountInstructions
  436. {
  437. local( $line );
  438. local( $count ) = 0;
  439. while( $line = shift )
  440. {
  441. # get rid of comments
  442. $line =~ s/;.*//gi;
  443. $line =~ s/\/\/.*//gi;
  444. # skip the vs1.1 statement
  445. $line =~ s/^\s*vs.*//gi;
  446. # if there's any text left, it's an instruction
  447. if( $line =~ /\S/gi )
  448. {
  449. $count++;
  450. }
  451. }
  452. return $count;
  453. }
  454. %compiled = ();
  455. sub UsesRegister
  456. {
  457. my $registerName = shift;
  458. my $str = shift;
  459. # Cache a compiled RE for each register name. This makes UsesRegister about 2.5x faster.
  460. if ( !$compiled{$registerName} )
  461. {
  462. $compiled{$registerName} = qr/\b$registerName\b/;
  463. }
  464. $ret = 0;
  465. if( $str =~ /$compiled{$registerName}/gi )
  466. {
  467. $ret = 1;
  468. }
  469. return $ret;
  470. }
  471. sub PadString
  472. {
  473. local( $str ) = shift;
  474. local( $desiredLen ) = shift;
  475. local( $len ) = length $str;
  476. while( $len < $desiredLen )
  477. {
  478. $str .= " ";
  479. $len++;
  480. }
  481. return $str;
  482. }
  483. sub FixupAllocateFree
  484. {
  485. local( $line ) = shift;
  486. $line =~ s/\&AllocateRegister\s*\(\s*\\(\S+)\s*\)/&AllocateRegister( \\$1, \"\\$1\" )/g;
  487. $line =~ s/\&FreeRegister\s*\(\s*\\(\S+)\s*\)/&FreeRegister( \\$1, \"\\$1\" )/g;
  488. $line =~ s/alloc\s+(\S+)\s*/local( $1 ); &AllocateRegister( \\$1, \"\\$1\" );/g;
  489. $line =~ s/free\s+(\S+)\s*/&FreeRegister( \\$1, \"\\$1\" );/g;
  490. return $line;
  491. }
  492. sub TranslateDXKeywords
  493. {
  494. local( $line ) = shift;
  495. $line =~ s/\bENDIF\b/endif/g;
  496. $line =~ s/\bIF\b/if/g;
  497. $line =~ s/\bELSE\b/else/g;
  498. return $line;
  499. }
  500. # This is used to make the generated pl files all pretty.
  501. sub GetLeadingWhiteSpace
  502. {
  503. local( $str ) = shift;
  504. if( $str =~ m/^;\S/ || $str =~ m/^; \S/ )
  505. {
  506. return "";
  507. }
  508. $str =~ s/^;/ /g; # count a leading ";" as whitespace as far as this is concerned.
  509. $str =~ m/^(\s*)/;
  510. return $1;
  511. }
  512. $g_dx9 = 1;
  513. $g_SourceDir = "..\\..";
  514. while( 1 )
  515. {
  516. $filename = shift;
  517. if ( $filename =~ m/-source/i )
  518. {
  519. $g_SourceDir = shift;
  520. }
  521. elsif( $filename =~ m/-x360/i )
  522. {
  523. $g_x360 = 1;
  524. }
  525. else
  526. {
  527. last;
  528. }
  529. }
  530. $filename =~ s/-----.*$//;
  531. #
  532. # Get the shader binary version number from a header file.
  533. #
  534. open FILE, "<$g_SourceDir\\public\\materialsystem\\shader_vcs_version.h" || die;
  535. while( $line = <FILE> )
  536. {
  537. if( $line =~ m/^\#define\s+SHADER_VCS_VERSION_NUMBER\s+(\d+)\s*$/ )
  538. {
  539. $shaderVersion = $1;
  540. last;
  541. }
  542. }
  543. if( !defined $shaderVersion )
  544. {
  545. die "couldn't get shader version from shader_vcs_version.h";
  546. }
  547. close FILE;
  548. if( $g_x360 )
  549. {
  550. $vshtmp = "vshtmp9_360_tmp";
  551. }
  552. else
  553. {
  554. $vshtmp = "vshtmp9_tmp";
  555. }
  556. if( !stat $vshtmp )
  557. {
  558. mkdir $vshtmp, 0777 || die $!;
  559. }
  560. # suck in all files, including $include files.
  561. @input = &ReadInputFileWithLineInfo( $filename );
  562. sub CalcNumCombos
  563. {
  564. local( $i, $numCombos );
  565. $numCombos = 1;
  566. for( $i = 0; $i < scalar( @dynamicDefineNames ); $i++ )
  567. {
  568. $numCombos *= $dynamicDefineMax[$i] - $dynamicDefineMin[$i] + 1;
  569. }
  570. for( $i = 0; $i < scalar( @staticDefineNames ); $i++ )
  571. {
  572. $numCombos *= $staticDefineMax[$i] - $staticDefineMin[$i] + 1;
  573. }
  574. return $numCombos;
  575. }
  576. sub CalcNumDynamicCombos
  577. {
  578. local( $i, $numCombos );
  579. $numCombos = 1;
  580. for( $i = 0; $i < scalar( @dynamicDefineNames ); $i++ )
  581. {
  582. $numCombos *= $dynamicDefineMax[$i] - $dynamicDefineMin[$i] + 1;
  583. }
  584. return $numCombos;
  585. }
  586. # READ THE TOP OF THE FILE TO FIND SHADER COMBOS
  587. foreach $_ ( @input )
  588. {
  589. next if( m/^\s*$/ );
  590. # last if( !m,^//, );
  591. s,^//\s*,,;
  592. if( m/\s*STATIC\s*\:\s*\"(.*)\"\s+\"(\d+)\.\.(\d+)\"/ )
  593. {
  594. local( $name, $min, $max );
  595. $name = $1;
  596. $min = $2;
  597. $max = $3;
  598. # print "\"$name\" \"$min..$max\"\n";
  599. if (/\[(.*)\]/)
  600. {
  601. $platforms=$1;
  602. next if ( ($g_x360) && (!($platforms=~/XBOX/i)) );
  603. next if ( (!$g_x360) && (!($platforms=~/PC/i)) );
  604. }
  605. push @staticDefineNames, $name;
  606. push @staticDefineMin, $min;
  607. push @staticDefineMax, $max;
  608. }
  609. elsif( m/\s*DYNAMIC\s*\:\s*\"(.*)\"\s+\"(\d+)\.\.(\d+)\"/ )
  610. {
  611. local( $name, $min, $max );
  612. $name = $1;
  613. $min = $2;
  614. $max = $3;
  615. if (/\[(.*)\]/)
  616. {
  617. $platforms=$1;
  618. next if ( ($g_x360) && (!($platforms=~/XBOX/i)) );
  619. next if ( (!$g_x360) && (!($platforms=~/PC/i)) );
  620. }
  621. # print "\"$name\" \"$min..$max\"\n";
  622. push @dynamicDefineNames, $name;
  623. push @dynamicDefineMin, $min;
  624. push @dynamicDefineMax, $max;
  625. }
  626. }
  627. # READ THE WHOLE FILE AND FIND SKIP STATEMENTS
  628. foreach $_ ( @input )
  629. {
  630. if( m/^\s*\#\s*SKIP\s*\:\s*(.*\S+)\s*\; LINEINFO.*$/ )
  631. {
  632. $perlskipcode .= "(" . $1 . ")||";
  633. push @perlskipcodeindividual, $1;
  634. }
  635. }
  636. if( defined $perlskipcode )
  637. {
  638. $perlskipcode .= "0";
  639. $perlskipcode =~ s/\n//g;
  640. }
  641. else
  642. {
  643. $perlskipcode = "0";
  644. }
  645. #print $perlskipcode . "\n";
  646. # Translate the input into a perl program that'll unroll everything and
  647. # substitute variables.
  648. while( $inputLine = shift @input )
  649. {
  650. $inputLine =~ s/\n//g;
  651. # leave out lines that are only whitespace.
  652. if( $inputLine =~ m/^\s*; LINEINFO.*$/ )
  653. {
  654. next;
  655. }
  656. local( $inputLineNoLineNum ) = $inputLine;
  657. $inputLineNoLineNum =~ s/; LINEINFO.*//gi;
  658. if( &IsPerl( $inputLineNoLineNum ) )
  659. {
  660. $inputLineNoLineNum = &FixupAllocateFree( $inputLineNoLineNum );
  661. push @outputProgram, $inputLineNoLineNum . "\n";
  662. }
  663. else
  664. {
  665. # make asm lines that have quotes in them not barf.
  666. $inputLine =~ s/\"/\\\"/g;
  667. $inputLine = &TranslateDXKeywords( $inputLine );
  668. push @outputProgram, &GetLeadingWhiteSpace( $inputLine ) . "push \@output, \"" .
  669. $inputLine . "\\n\";\n";
  670. }
  671. }
  672. $outputProgram = join "", @outputProgram;
  673. $filename_base = $filename;
  674. $filename_base =~ s/\.vsh//i;
  675. open DEBUGOUT, ">$vshtmp" . "/$filename_base.pl" || die;
  676. print DEBUGOUT $outputProgram;
  677. close DEBUGOUT;
  678. # Make a function called OutputProgram()
  679. $bigProg = "sub OutputProgram { " . $outputProgram . "}";
  680. eval( $bigProg );
  681. #print $outputProgram;
  682. #push @finalheader, "// hack to force dependency checking\n";
  683. #push @finalheader, "\#ifdef NEVER\n";
  684. #push @finalheader, "\#include \"" . $filename_base . "\.vsh\"\n";
  685. #push @finalheader, "\#include \"..\\..\\devtools\\bin\\vsh_prep.pl\"\n";
  686. #push @finalheader, "\#endif\n";
  687. %g_TimingBlocks = ();
  688. $main_start_time = SampleTime();
  689. $numCombos = &CalcNumCombos();
  690. $numDynamicCombos = &CalcNumDynamicCombos();
  691. #print "$numCombos total combos\n";
  692. #print "$numDynamicCombos dynamic combos\n";
  693. #print $numCombos / $numDynamicCombos . " static combos\n";
  694. # Write out the C++ helper class for picking shader combos
  695. $fxc_filename = $filename_base;
  696. &WriteStaticHelperClasses();
  697. &WriteDynamicHelperClasses();
  698. # Create a subroutine out of $perlskipcode
  699. $perlskipfunc = "sub SkipCombo { return $perlskipcode; }\n";
  700. #print $perlskipfunc;
  701. eval $perlskipfunc;
  702. &CreateFuncToSetPerlVars();
  703. my $incfilename = "$vshtmp/$filename_base" . ".inc";
  704. # Write the inc file that has indexing helpers, etc.
  705. &WriteFile( $incfilename, join( "", @outputHeader ) );
  706. # Run the output program for all the combinations of bones and lights.
  707. print "$filename_base.vsh\n";
  708. for( $i = 0; $i < $numCombos; $i++ )
  709. {
  710. # print "combo $i\n";
  711. &SetPerlVarsFunc( $i );
  712. local( $compileFailed );
  713. $ret = &SkipCombo;
  714. if( !defined $ret )
  715. {
  716. die "$@\n";
  717. }
  718. if( $ret )
  719. {
  720. # skip this combo!
  721. $compileFailed = 1;
  722. $numSkipped++;
  723. next;
  724. }
  725. $start = SampleTime();
  726. $g_usesPos = 0;
  727. $g_usesPosFlex = 0;
  728. $g_usesBoneWeights = 0;
  729. $g_usesBoneIndices = 0;
  730. $g_usesNormal = 0;
  731. $g_usesNormalFlex = 0;
  732. $g_usesColor = 0;
  733. $g_usesSpecular = 0;
  734. $g_usesTexCoord0 = 0;
  735. $g_usesTexCoord1 = 0;
  736. $g_usesTexCoord2 = 0;
  737. $g_usesTexCoord3 = 0;
  738. $g_usesTangentS = 0;
  739. $g_usesTangentT = 0;
  740. $g_usesUserData = 0;
  741. undef @output;
  742. $g_TimingBlocks{"inner1"} += SampleTime() - $start;
  743. $eval_start_time = SampleTime();
  744. &OutputProgram();
  745. $eval_total_time += (SampleTime() - $eval_start_time);
  746. $start = SampleTime();
  747. # Strip out comments once so we don't have to do it in all the UsesRegister calls.
  748. @stripped = @output;
  749. map
  750. {
  751. $_ =~ s/;.*//gi;
  752. $_ =~ s/\/\/.*//gi;
  753. } @stripped;
  754. my $strippedStr = join( "", @stripped );
  755. $g_TimingBlocks{"inner2"} += SampleTime() - $start;
  756. $start = SampleTime();
  757. # Have to make another pass through after we know which v registers are used. . yuck.
  758. $g_usesPos = &UsesRegister( $vPos, $strippedStr );
  759. if( $g_x360 )
  760. {
  761. $g_usesPosFlex = &UsesRegister( $vPosFlex, $strippedStr );
  762. $g_usesNormalFlex = &UsesRegister( $vNormalFlex, $strippedStr );
  763. }
  764. $g_usesBoneWeights = &UsesRegister( $vBoneWeights, $strippedStr );
  765. $g_usesBoneIndices = &UsesRegister( $vBoneIndices, $strippedStr );
  766. $g_usesNormal = &UsesRegister( $vNormal, $strippedStr );
  767. $g_usesColor = &UsesRegister( $vColor, $strippedStr );
  768. $g_usesSpecular = &UsesRegister( $vSpecular, $strippedStr );
  769. $g_usesTexCoord0 = &UsesRegister( $vTexCoord0, $strippedStr );
  770. $g_usesTexCoord1 = &UsesRegister( $vTexCoord1, $strippedStr );
  771. $g_usesTexCoord2 = &UsesRegister( $vTexCoord2, $strippedStr );
  772. $g_usesTexCoord3 = &UsesRegister( $vTexCoord3, $strippedStr );
  773. $g_usesTangentS = &UsesRegister( $vTangentS, $strippedStr );
  774. $g_usesTangentT = &UsesRegister( $vTangentT, $strippedStr );
  775. $g_usesUserData = &UsesRegister( $vUserData, $strippedStr );
  776. undef @output;
  777. $g_TimingBlocks{"inner2"} += SampleTime() - $start;
  778. $eval_start_time = SampleTime();
  779. # Running OutputProgram generates $outfilename
  780. &OutputProgram();
  781. $eval_total_time += (SampleTime() - $eval_start_time);
  782. $start = SampleTime();
  783. &CheckUnfreedRegisters();
  784. for( $j = 0; $j < scalar( @output ); $j++ )
  785. {
  786. # remove whitespace from the beginning of each line.
  787. $output[$j] =~ s/^\s+//;
  788. # remove LINEINFO from empty lines.
  789. $output[$j] =~ s/^; LINEINFO.*//;
  790. }
  791. $g_TimingBlocks{"inner3"} += SampleTime() - $start;
  792. $start = SampleTime();
  793. $outfilename_base = $filename_base . "_" . $i;
  794. # $outfilename is the name of the file generated from executing the perl code
  795. # for this shader. This file is generated once per combo.
  796. # We will assemble this shader with vsa.exe.
  797. $outfilename = "$vshtmp\\" . $outfilename_base . ".tmp";
  798. # $outhdrfilename = "$vshtmp\\" . $outfilename_base . ".h";
  799. # unlink $outhdrfilename;
  800. open OUTPUT, ">$outfilename" || die;
  801. print OUTPUT @output;
  802. close OUTPUT;
  803. $g_TimingBlocks{"inner4"} += SampleTime() - $start;
  804. $start = SampleTime();
  805. local( $instructionCount ) = &CountInstructions( @output );
  806. $g_TimingBlocks{"inner5"} += SampleTime() - $start;
  807. local( $debug );
  808. $debug = 1;
  809. # for( $debug = 1; $debug >= 0; $debug-- )
  810. {
  811. # assemble the vertex shader
  812. unlink "shader$i.o";
  813. if( $g_x360 )
  814. {
  815. $vsa = "..\\..\\x360xdk\\bin\\win32\\vsa";
  816. }
  817. else
  818. {
  819. $vsa = "..\\..\\dx9sdk\\utilities\\vsa";
  820. }
  821. $vsadebug = "$vsa /nologo /Foshader$i.o $outfilename";
  822. $vsanodebug = "$vsa /nologo /Foshader$i.o $outfilename";
  823. $vsa_start_time = SampleTime();
  824. if( $debug )
  825. {
  826. # print $vsadebug . "\n";
  827. @vsaoutput = `$vsadebug 2>&1`;
  828. # print @vsaoutput;
  829. }
  830. else
  831. {
  832. @vsaoutput = `$vsanodebug 2>&1`;
  833. }
  834. $vsa_total_time += SampleTime() - $vsa_start_time;
  835. $start = SampleTime();
  836. &TranslateErrorMessages( @vsaoutput );
  837. $g_TimingBlocks{"inner6"} += SampleTime() - $start;
  838. push @finalheader, @hdr;
  839. }
  840. }
  841. $main_total_time = SampleTime() - $main_start_time;
  842. # stick info about the shaders at the end of the inc file.
  843. push @finalheader, "static PrecompiledShaderByteCode_t $filename_base" . "_vertex_shaders[] = {\n";
  844. for( $i = 0; $i < $numCombos; $i++ )
  845. {
  846. $outfilename_base = $filename_base . "_" . $i;
  847. push @finalheader, "{ $outfilename_base, sizeof( $outfilename_base ) },\n";
  848. }
  849. push @finalheader, "};\n";
  850. push @finalheader, "struct $filename_base" . "_VertexShader_t : public PrecompiledShader_t\n";
  851. push @finalheader, "{\n";
  852. push @finalheader, "\t$filename_base" . "_VertexShader_t()\n";
  853. push @finalheader, "\t{\n";
  854. push @finalheader, "\t\tm_nFlags = 0;\n";
  855. $flags = 0;
  856. #push @finalheader, "\t\tppVertexShaders = $filename_base" . "_vertex_shaders;\n";
  857. push @finalheader, "\t\tm_pByteCode = $filename_base" . "_vertex_shaders;\n";
  858. push @finalheader, "\t\tm_pName = \"$filename_base\";\n";
  859. push @finalheader, "\t\tm_nShaderCount = " . ( $maxNumBones + 1 ) * $totalFogCombos * $totalLightCombos . ";\n";
  860. push @finalheader, "\t\tm_nDynamicCombos = m_nShaderCount;\n";
  861. push @finalheader, "\t\tGetShaderDLL()->InsertPrecompiledShader( PRECOMPILED_VERTEX_SHADER, this );\n";
  862. push @finalheader, "\t}\n";
  863. push @finalheader, "\tvirtual const PrecompiledShaderByteCode_t &GetByteCode( int shaderID )\n";
  864. push @finalheader, "\t{\n";
  865. push @finalheader, "\t\treturn m_pByteCode[shaderID];\n";
  866. push @finalheader, "\t}\n";
  867. push @finalheader, "};\n";
  868. push @finalheader, "static $filename_base" . "_VertexShader_t $filename_base" . "_VertexShaderInstance;\n";
  869. # Write the final header file with the compiled vertex shader programs.
  870. $finalheadername = "$vshtmp\\" . $filename_base . ".inc";
  871. #print "writing $finalheadername\n";
  872. #open FINALHEADER, ">$finalheadername" || die;
  873. #print FINALHEADER @finalheader;
  874. #close FINALHEADER;
  875. &MakeDirHier( "shaders/vsh" );
  876. my $vcsName = "";
  877. if( $g_x360 )
  878. {
  879. $vcsName = $filename_base . ".360.vcs";
  880. }
  881. else
  882. {
  883. $vcsName = $filename_base . ".vcs";
  884. }
  885. open COMPILEDSHADER, ">shaders/vsh/$vcsName" || die;
  886. binmode( COMPILEDSHADER );
  887. #
  888. # Write out the part of the header that we know. . we'll write the rest after writing the object code.
  889. #
  890. # Pack arguments
  891. my $sInt = "i";
  892. my $uInt = "I";
  893. if ( $g_x360 )
  894. {
  895. # Change arguments to "big endian long"
  896. $sInt = "N";
  897. $uInt = "N";
  898. }
  899. my $undecoratedinput = join "", &ReadInputFileWithoutLineInfo( $filename );
  900. #print STDERR "undecoratedinput: $undecoratedinput\n";
  901. my $crc = crc32( $undecoratedinput );
  902. #print STDERR "crc for $filename: $crc\n";
  903. # version
  904. print COMPILEDSHADER pack $sInt, 4;
  905. # totalCombos
  906. print COMPILEDSHADER pack $sInt, $numCombos;
  907. # dynamic combos
  908. print COMPILEDSHADER pack $sInt, $numDynamicCombos;
  909. # flags
  910. print COMPILEDSHADER pack $uInt, $flags;
  911. # centroid mask
  912. print COMPILEDSHADER pack $uInt, 0;
  913. # reference size
  914. print COMPILEDSHADER pack $uInt, 0;
  915. # crc32 of the source code
  916. print COMPILEDSHADER pack $uInt, $crc;
  917. my $beginningOfDir = tell COMPILEDSHADER;
  918. # Write out a blank directionary. . we'll fill it in later.
  919. for( $i = 0; $i < $numCombos; $i++ )
  920. {
  921. # offset from beginning of file.
  922. print COMPILEDSHADER pack $sInt, 0;
  923. # size
  924. print COMPILEDSHADER pack $sInt, 0;
  925. }
  926. my $startByteCode = tell COMPILEDSHADER;
  927. my @byteCodeStart;
  928. my @byteCodeSize;
  929. # Write out the shader object code.
  930. for( $shaderCombo = 0; $shaderCombo < $numCombos; $shaderCombo++ )
  931. {
  932. my $filename = "shader$shaderCombo\.o";
  933. my $filesize = (stat $filename)[7];
  934. $byteCodeStart[$shaderCombo] = tell COMPILEDSHADER;
  935. $byteCodeSize[$shaderCombo] = $filesize;
  936. open SHADERBYTECODE, "<$filename" || die;
  937. binmode SHADERBYTECODE;
  938. my $bin;
  939. my $numread = read SHADERBYTECODE, $bin, $filesize;
  940. # print "filename: $filename numread: $numread filesize: $filesize\n";
  941. close SHADERBYTECODE;
  942. unlink $filename;
  943. print COMPILEDSHADER $bin;
  944. }
  945. # Seek back to the directory and write it out.
  946. seek COMPILEDSHADER, $beginningOfDir, 0;
  947. for( $i = 0; $i < $numCombos; $i++ )
  948. {
  949. # offset from beginning of file.
  950. print COMPILEDSHADER pack $sInt, $byteCodeStart[$i];
  951. # size
  952. print COMPILEDSHADER pack $sInt, $byteCodeSize[$i];
  953. }
  954. close COMPILEDSHADER;
  955. $total_time = SampleTime() - $total_start_time;
  956. if ( $ShowTimers )
  957. {
  958. print "\n\n";
  959. print sprintf( "Main loop time : %0.4f sec, (%0.2f%%)\n", $main_total_time, 100*$main_total_time / $total_time );
  960. print sprintf( "Inner1 time : %0.4f sec, (%0.2f%%)\n", $inner1_total_time, 100*$inner1_total_time / $total_time );
  961. print sprintf( "VSA time : %0.4f sec, (%0.2f%%)\n", $vsa_total_time, 100*$vsa_total_time / $total_time );
  962. print sprintf( "eval() time : %0.4f sec, (%0.2f%%)\n", $eval_total_time, 100*$eval_total_time / $total_time );
  963. print sprintf( "UsesRegister time: %0.4f sec, (%0.2f%%)\n", $usesr_total_time, 100*$usesr_total_time / $total_time );
  964. foreach $key ( keys %g_TimingBlocks )
  965. {
  966. print sprintf( "$key time: %0.4f sec, (%0.2f%%)\n", $g_TimingBlocks{$key}, 100*$g_TimingBlocks{$key} / $total_time );
  967. }
  968. print sprintf( "Total time : %0.4f sec\n", $total_time );
  969. }