rc1.0_general.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. #include "rc1.0_general.h"
  2. #include "nvparse_errors.h"
  3. #include "nvparse_externs.h"
  4. #include <stdio.h>
  5. void GeneralCombinersStruct::Validate(int numConsts, ConstColorStruct *pcc)
  6. {
  7. GLint maxGCs;
  8. glGetIntegerv(GL_MAX_GENERAL_COMBINERS_NV, &maxGCs);
  9. if (num > maxGCs) {
  10. char buffer[256];
  11. sprintf(buffer, "%d general combiners specified, only %d supported", num, (int)maxGCs);
  12. errors.set(buffer);
  13. num = maxGCs;
  14. }
  15. if (0 == num) {
  16. // Setup a "fake" general combiner 0
  17. general[0].ZeroOut();
  18. num = 1;
  19. }
  20. localConsts = 0;
  21. int i;
  22. for (i = 0; i < num; i++)
  23. localConsts += general[i].numConsts;
  24. if (localConsts > 0)
  25. if (NULL == glCombinerStageParameterfvNV)
  26. errors.set("local constant(s) specified, but not supported -- ignored");
  27. else
  28. for (i = 0; i < num; i++)
  29. general[i].SetUnusedLocalConsts(numConsts, pcc);
  30. for (i = 0; i < num; i++)
  31. general[i].Validate(i);
  32. for (; i < maxGCs; i++)
  33. general[i].ZeroOut();
  34. }
  35. void GeneralCombinersStruct::Invoke()
  36. {
  37. glCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, num);
  38. int i;
  39. for (i = 0; i < num; i++)
  40. general[i].Invoke(i);
  41. if (NULL != glCombinerStageParameterfvNV) {
  42. if (localConsts > 0)
  43. glEnable(GL_PER_STAGE_CONSTANTS_NV);
  44. else
  45. glDisable(GL_PER_STAGE_CONSTANTS_NV);
  46. }
  47. }
  48. void GeneralCombinerStruct::ZeroOut()
  49. {
  50. numPortions = 2;
  51. numConsts = 0;
  52. portion[0].ZeroOut();
  53. portion[0].designator = RCP_RGB;
  54. portion[1].ZeroOut();
  55. portion[1].designator = RCP_ALPHA;
  56. }
  57. void GeneralCombinerStruct::SetUnusedLocalConsts(int numGlobalConsts, ConstColorStruct *globalCCs)
  58. {
  59. int i;
  60. for (i = 0; i < numGlobalConsts; i++) {
  61. bool constUsed = false;
  62. int j;
  63. for (j = 0; j < numConsts; j++)
  64. constUsed |= (cc[j].reg.bits.name == globalCCs[i].reg.bits.name);
  65. if (!constUsed)
  66. cc[numConsts++] = globalCCs[i];
  67. }
  68. }
  69. void GeneralCombinerStruct::Validate(int stage)
  70. {
  71. if (2 == numConsts &&
  72. cc[0].reg.bits.name == cc[1].reg.bits.name)
  73. errors.set("local constant set twice");
  74. switch (numPortions)
  75. {
  76. case 0:
  77. portion[0].designator = RCP_RGB;
  78. // Fallthru
  79. case 1:
  80. portion[1].designator = ((RCP_RGB == portion[0].designator) ? RCP_ALPHA : RCP_RGB);
  81. // Fallthru
  82. case 2:
  83. if (portion[0].designator == portion[1].designator)
  84. errors.set("portion declared twice");
  85. break;
  86. }
  87. int i;
  88. for (i = 0; i < numPortions; i++)
  89. portion[i].Validate(stage);
  90. for (; i < 2; i++)
  91. portion[i].ZeroOut();
  92. }
  93. void GeneralCombinerStruct::Invoke(int stage)
  94. {
  95. int i;
  96. if (NULL != glCombinerStageParameterfvNV)
  97. for (i = 0; i < numConsts; i++)
  98. glCombinerStageParameterfvNV(GL_COMBINER0_NV + stage, cc[i].reg.bits.name, &(cc[i].v[0]));
  99. for (i = 0; i < 2; i++)
  100. portion[i].Invoke(stage);
  101. }
  102. void GeneralPortionStruct::Validate(int stage)
  103. {
  104. gf.Validate(stage, designator);
  105. }
  106. void GeneralPortionStruct::Invoke(int stage)
  107. {
  108. gf.Invoke(stage, designator, bs);
  109. }
  110. void GeneralPortionStruct::ZeroOut()
  111. {
  112. gf.ZeroOut();
  113. bs.word = RCP_SCALE_BY_ONE;
  114. }
  115. void GeneralFunctionStruct::ZeroOut()
  116. {
  117. // Create mapped registers for zero and discard
  118. MappedRegisterStruct unsignedZero;
  119. RegisterEnum zero;
  120. zero.word = RCP_ZERO;
  121. unsignedZero.Init(zero);
  122. MappedRegisterStruct unsignedDiscard;
  123. RegisterEnum discard;
  124. discard.word = RCP_DISCARD;
  125. unsignedDiscard.Init(discard);
  126. numOps = 3;
  127. op[0].op = RCP_MUL;
  128. op[0].reg[0] = unsignedDiscard;
  129. op[0].reg[1] = unsignedZero;
  130. op[0].reg[2] = unsignedZero;
  131. op[1].op = RCP_MUL;
  132. op[1].reg[0] = unsignedDiscard;
  133. op[1].reg[1] = unsignedZero;
  134. op[1].reg[2] = unsignedZero;
  135. op[2].op = RCP_SUM;
  136. op[2].reg[0] = unsignedDiscard;
  137. }
  138. void GeneralFunctionStruct::Validate(int stage, int portion)
  139. {
  140. int i;
  141. for (i = 0; i < numOps; i++)
  142. op[i].Validate(stage, portion);
  143. // Check if multiple ops are writing to same register (and it's not DISCARD)
  144. if (numOps > 1 &&
  145. op[0].reg[0].reg.bits.name == op[1].reg[0].reg.bits.name &&
  146. GL_DISCARD_NV != op[0].reg[0].reg.bits.name)
  147. errors.set("writing to same register twice");
  148. if (numOps > 2 &&
  149. (op[0].reg[0].reg.bits.name == op[2].reg[0].reg.bits.name ||
  150. op[1].reg[0].reg.bits.name == op[2].reg[0].reg.bits.name) &&
  151. GL_DISCARD_NV != op[2].reg[0].reg.bits.name)
  152. errors.set("writing to same register twice");
  153. // Set unused outputs to discard, unused inputs to zero/unsigned_identity
  154. if (numOps < 2) {
  155. // Set C input to zero
  156. op[1].reg[1].reg.bits.name = GL_ZERO;
  157. op[1].reg[1].map = GL_UNSIGNED_IDENTITY_NV;
  158. op[1].reg[1].reg.bits.channel = portion;
  159. // Set D input to zero
  160. op[1].reg[2].reg.bits.name = GL_ZERO;
  161. op[1].reg[2].map = GL_UNSIGNED_IDENTITY_NV;
  162. op[1].reg[2].reg.bits.channel = portion;
  163. // Discard CD output
  164. op[1].op = false;
  165. op[1].reg[0].reg.bits.name = GL_DISCARD_NV;
  166. }
  167. if (numOps < 3) {
  168. // Discard muxSum output
  169. op[2].reg[0].reg.bits.name = GL_DISCARD_NV;
  170. op[2].op = RCP_SUM;
  171. }
  172. }
  173. void GeneralFunctionStruct::Invoke(int stage, int portion, BiasScaleEnum bs)
  174. {
  175. GLenum portionEnum = (RCP_RGB == portion) ? GL_RGB : GL_ALPHA;
  176. glCombinerInputNV(GL_COMBINER0_NV + stage,
  177. portionEnum,
  178. GL_VARIABLE_A_NV,
  179. op[0].reg[1].reg.bits.name,
  180. op[0].reg[1].map,
  181. MAP_CHANNEL(op[0].reg[1].reg.bits.channel));
  182. glCombinerInputNV(GL_COMBINER0_NV + stage,
  183. portionEnum,
  184. GL_VARIABLE_B_NV,
  185. op[0].reg[2].reg.bits.name,
  186. op[0].reg[2].map,
  187. MAP_CHANNEL(op[0].reg[2].reg.bits.channel));
  188. glCombinerInputNV(GL_COMBINER0_NV + stage,
  189. portionEnum,
  190. GL_VARIABLE_C_NV,
  191. op[1].reg[1].reg.bits.name,
  192. op[1].reg[1].map,
  193. MAP_CHANNEL(op[1].reg[1].reg.bits.channel));
  194. glCombinerInputNV(GL_COMBINER0_NV + stage,
  195. portionEnum,
  196. GL_VARIABLE_D_NV,
  197. op[1].reg[2].reg.bits.name,
  198. op[1].reg[2].map,
  199. MAP_CHANNEL(op[1].reg[2].reg.bits.channel));
  200. glCombinerOutputNV(GL_COMBINER0_NV + stage,
  201. portionEnum,
  202. op[0].reg[0].reg.bits.name,
  203. op[1].reg[0].reg.bits.name,
  204. op[2].reg[0].reg.bits.name,
  205. bs.bits.scale,
  206. bs.bits.bias,
  207. op[0].op,
  208. op[1].op,
  209. (op[2].op == RCP_MUX) ? true : false);
  210. }
  211. // This helper function assigns a channel to an undesignated input register
  212. static void ConvertRegister(RegisterEnum& reg, int portion)
  213. {
  214. if (RCP_NONE == reg.bits.channel) {
  215. reg.bits.channel = portion;
  216. if (GL_FOG == reg.bits.name && RCP_ALPHA == portion)
  217. // Special case where fog alpha is final only, but RGB is not
  218. reg.bits.finalOnly = true;
  219. }
  220. }
  221. void OpStruct::Validate(int stage, int portion)
  222. {
  223. int args = 1;
  224. if (RCP_DOT == op || RCP_MUL == op)
  225. args = 3;
  226. else
  227. args = 1;
  228. if (reg[0].reg.bits.readOnly)
  229. errors.set("writing to a read-only register");
  230. if (RCP_ALPHA == portion &&
  231. RCP_DOT == op)
  232. errors.set("dot used in alpha portion");
  233. int i;
  234. for (i = 0; i < args; i++) {
  235. ConvertRegister(reg[i].reg, portion);
  236. if (reg[i].reg.bits.finalOnly)
  237. errors.set("final register used in general combiner");
  238. if (RCP_RGB == portion &&
  239. RCP_BLUE == reg[i].reg.bits.channel)
  240. errors.set("blue register used in rgb portion");
  241. if (RCP_ALPHA == portion &&
  242. RCP_RGB == reg[i].reg.bits.channel)
  243. errors.set("rgb register used in alpha portion");
  244. if (i > 0 &&
  245. GL_DISCARD_NV == reg[i].reg.bits.name)
  246. errors.set("reading from discard");
  247. }
  248. }