Tev.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. // Copyright 2009 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "VideoBackends/Software/Tev.h"
  4. #include <algorithm>
  5. #include <cmath>
  6. #include <cstring>
  7. #include "Common/Assert.h"
  8. #include "Common/CommonTypes.h"
  9. #include "Core/System.h"
  10. #include "VideoBackends/Software/SWBoundingBox.h"
  11. #include "VideoBackends/Software/SWEfbInterface.h"
  12. #include "VideoBackends/Software/TextureSampler.h"
  13. #include "VideoCommon/PixelShaderManager.h"
  14. #include "VideoCommon/Statistics.h"
  15. #include "VideoCommon/VideoCommon.h"
  16. #include "VideoCommon/XFMemory.h"
  17. static inline s16 Clamp255(s16 in)
  18. {
  19. return std::clamp<s16>(in, 0, 255);
  20. }
  21. static inline s16 Clamp1024(s16 in)
  22. {
  23. return std::clamp<s16>(in, -1024, 1023);
  24. }
  25. void Tev::SetRasColor(RasColorChan colorChan, u32 swaptable)
  26. {
  27. switch (colorChan)
  28. {
  29. case RasColorChan::Color0:
  30. {
  31. const u8* color = Color[0];
  32. const auto& swap = bpmem.tevksel.GetSwapTable(swaptable);
  33. RasColor.r = color[u32(swap[ColorChannel::Red])];
  34. RasColor.g = color[u32(swap[ColorChannel::Green])];
  35. RasColor.b = color[u32(swap[ColorChannel::Blue])];
  36. RasColor.a = color[u32(swap[ColorChannel::Alpha])];
  37. }
  38. break;
  39. case RasColorChan::Color1:
  40. {
  41. const u8* color = Color[1];
  42. const auto& swap = bpmem.tevksel.GetSwapTable(swaptable);
  43. RasColor.r = color[u32(swap[ColorChannel::Red])];
  44. RasColor.g = color[u32(swap[ColorChannel::Green])];
  45. RasColor.b = color[u32(swap[ColorChannel::Blue])];
  46. RasColor.a = color[u32(swap[ColorChannel::Alpha])];
  47. }
  48. break;
  49. case RasColorChan::AlphaBump:
  50. {
  51. RasColor = TevColor::All(AlphaBump);
  52. }
  53. break;
  54. case RasColorChan::NormalizedAlphaBump:
  55. {
  56. const u8 normalized = AlphaBump | AlphaBump >> 5;
  57. RasColor = TevColor::All(normalized);
  58. }
  59. break;
  60. default:
  61. {
  62. if (colorChan != RasColorChan::Zero)
  63. PanicAlertFmt("Invalid ras color channel: {}", colorChan);
  64. RasColor = TevColor::All(0);
  65. }
  66. break;
  67. }
  68. }
  69. void Tev::DrawColorRegular(const TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4])
  70. {
  71. for (int i = BLU_C; i <= RED_C; i++)
  72. {
  73. const InputRegType& InputReg = inputs[i];
  74. const u16 c = InputReg.c + (InputReg.c >> 7);
  75. s32 temp = InputReg.a * (256 - c) + (InputReg.b * c);
  76. temp <<= s_ScaleLShiftLUT[cc.scale];
  77. temp += (cc.scale == TevScale::Divide2) ? 0 : (cc.op == TevOp::Sub) ? 127 : 128;
  78. temp >>= 8;
  79. temp = cc.op == TevOp::Sub ? -temp : temp;
  80. s32 result = ((InputReg.d + s_BiasLUT[cc.bias]) << s_ScaleLShiftLUT[cc.scale]) + temp;
  81. result = result >> s_ScaleRShiftLUT[cc.scale];
  82. Reg[cc.dest][i] = result;
  83. }
  84. }
  85. void Tev::DrawColorCompare(const TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4])
  86. {
  87. for (int i = BLU_C; i <= RED_C; i++)
  88. {
  89. u32 a, b;
  90. switch (cc.compare_mode)
  91. {
  92. case TevCompareMode::R8:
  93. a = inputs[RED_C].a;
  94. b = inputs[RED_C].b;
  95. break;
  96. case TevCompareMode::GR16:
  97. a = (inputs[GRN_C].a << 8) | inputs[RED_C].a;
  98. b = (inputs[GRN_C].b << 8) | inputs[RED_C].b;
  99. break;
  100. case TevCompareMode::BGR24:
  101. a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a;
  102. b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b;
  103. break;
  104. case TevCompareMode::RGB8:
  105. a = inputs[i].a;
  106. b = inputs[i].b;
  107. break;
  108. default:
  109. PanicAlertFmt("Invalid compare mode {}", cc.compare_mode);
  110. continue;
  111. }
  112. if (cc.comparison == TevComparison::GT)
  113. Reg[cc.dest][i] = inputs[i].d + ((a > b) ? inputs[i].c : 0);
  114. else
  115. Reg[cc.dest][i] = inputs[i].d + ((a == b) ? inputs[i].c : 0);
  116. }
  117. }
  118. void Tev::DrawAlphaRegular(const TevStageCombiner::AlphaCombiner& ac, const InputRegType inputs[4])
  119. {
  120. const InputRegType& InputReg = inputs[ALP_C];
  121. const u16 c = InputReg.c + (InputReg.c >> 7);
  122. s32 temp = InputReg.a * (256 - c) + (InputReg.b * c);
  123. temp <<= s_ScaleLShiftLUT[ac.scale];
  124. temp += (ac.scale == TevScale::Divide2) ? 0 : (ac.op == TevOp::Sub) ? 127 : 128;
  125. temp = ac.op == TevOp::Sub ? (-temp >> 8) : (temp >> 8);
  126. s32 result = ((InputReg.d + s_BiasLUT[ac.bias]) << s_ScaleLShiftLUT[ac.scale]) + temp;
  127. result = result >> s_ScaleRShiftLUT[ac.scale];
  128. Reg[ac.dest].a = result;
  129. }
  130. void Tev::DrawAlphaCompare(const TevStageCombiner::AlphaCombiner& ac, const InputRegType inputs[4])
  131. {
  132. u32 a, b;
  133. switch (ac.compare_mode)
  134. {
  135. case TevCompareMode::R8:
  136. a = inputs[RED_C].a;
  137. b = inputs[RED_C].b;
  138. break;
  139. case TevCompareMode::GR16:
  140. a = (inputs[GRN_C].a << 8) | inputs[RED_C].a;
  141. b = (inputs[GRN_C].b << 8) | inputs[RED_C].b;
  142. break;
  143. case TevCompareMode::BGR24:
  144. a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a;
  145. b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b;
  146. break;
  147. case TevCompareMode::A8:
  148. a = inputs[ALP_C].a;
  149. b = inputs[ALP_C].b;
  150. break;
  151. default:
  152. PanicAlertFmt("Invalid compare mode {}", ac.compare_mode);
  153. return;
  154. }
  155. if (ac.comparison == TevComparison::GT)
  156. Reg[ac.dest].a = inputs[ALP_C].d + ((a > b) ? inputs[ALP_C].c : 0);
  157. else
  158. Reg[ac.dest].a = inputs[ALP_C].d + ((a == b) ? inputs[ALP_C].c : 0);
  159. }
  160. static bool AlphaCompare(int alpha, int ref, CompareMode comp)
  161. {
  162. switch (comp)
  163. {
  164. case CompareMode::Always:
  165. return true;
  166. case CompareMode::Never:
  167. return false;
  168. case CompareMode::LEqual:
  169. return alpha <= ref;
  170. case CompareMode::Less:
  171. return alpha < ref;
  172. case CompareMode::GEqual:
  173. return alpha >= ref;
  174. case CompareMode::Greater:
  175. return alpha > ref;
  176. case CompareMode::Equal:
  177. return alpha == ref;
  178. case CompareMode::NEqual:
  179. return alpha != ref;
  180. default:
  181. PanicAlertFmt("Invalid compare mode {}", comp);
  182. return true;
  183. }
  184. }
  185. static bool TevAlphaTest(int alpha)
  186. {
  187. const bool comp0 = AlphaCompare(alpha, bpmem.alpha_test.ref0, bpmem.alpha_test.comp0);
  188. const bool comp1 = AlphaCompare(alpha, bpmem.alpha_test.ref1, bpmem.alpha_test.comp1);
  189. switch (bpmem.alpha_test.logic)
  190. {
  191. case AlphaTestOp::And:
  192. return comp0 && comp1;
  193. case AlphaTestOp::Or:
  194. return comp0 || comp1;
  195. case AlphaTestOp::Xor:
  196. return comp0 ^ comp1;
  197. case AlphaTestOp::Xnor:
  198. return !(comp0 ^ comp1);
  199. default:
  200. PanicAlertFmt("Invalid AlphaTestOp {}", bpmem.alpha_test.logic);
  201. return true;
  202. }
  203. }
  204. static inline s32 WrapIndirectCoord(s32 coord, IndTexWrap wrapMode)
  205. {
  206. switch (wrapMode)
  207. {
  208. case IndTexWrap::ITW_OFF:
  209. return coord;
  210. case IndTexWrap::ITW_256:
  211. return (coord & ((256 << 7) - 1));
  212. case IndTexWrap::ITW_128:
  213. return (coord & ((128 << 7) - 1));
  214. case IndTexWrap::ITW_64:
  215. return (coord & ((64 << 7) - 1));
  216. case IndTexWrap::ITW_32:
  217. return (coord & ((32 << 7) - 1));
  218. case IndTexWrap::ITW_16:
  219. return (coord & ((16 << 7) - 1));
  220. case IndTexWrap::ITW_0:
  221. return 0;
  222. default:
  223. PanicAlertFmt("Invalid indirect wrap mode {}", wrapMode);
  224. return 0;
  225. }
  226. }
  227. void Tev::Indirect(unsigned int stageNum, s32 s, s32 t)
  228. {
  229. const TevStageIndirect& indirect = bpmem.tevind[stageNum];
  230. const u8* indmap = IndirectTex[indirect.bt];
  231. s32 indcoord[3];
  232. // alpha bump select
  233. switch (indirect.bs)
  234. {
  235. case IndTexBumpAlpha::Off:
  236. AlphaBump = 0;
  237. break;
  238. case IndTexBumpAlpha::S:
  239. AlphaBump = indmap[TextureSampler::ALP_SMP];
  240. break;
  241. case IndTexBumpAlpha::T:
  242. AlphaBump = indmap[TextureSampler::BLU_SMP];
  243. break;
  244. case IndTexBumpAlpha::U:
  245. AlphaBump = indmap[TextureSampler::GRN_SMP];
  246. break;
  247. default:
  248. PanicAlertFmt("Invalid alpha bump {}", indirect.bs);
  249. return;
  250. }
  251. // bias select
  252. const s16 biasValue = indirect.fmt == IndTexFormat::ITF_8 ? -128 : 1;
  253. s16 bias[3];
  254. bias[0] = indirect.bias_s ? biasValue : 0;
  255. bias[1] = indirect.bias_t ? biasValue : 0;
  256. bias[2] = indirect.bias_u ? biasValue : 0;
  257. // format
  258. switch (indirect.fmt)
  259. {
  260. case IndTexFormat::ITF_8:
  261. indcoord[0] = indmap[TextureSampler::ALP_SMP] + bias[0];
  262. indcoord[1] = indmap[TextureSampler::BLU_SMP] + bias[1];
  263. indcoord[2] = indmap[TextureSampler::GRN_SMP] + bias[2];
  264. AlphaBump = AlphaBump & 0xf8;
  265. break;
  266. case IndTexFormat::ITF_5:
  267. indcoord[0] = (indmap[TextureSampler::ALP_SMP] >> 3) + bias[0];
  268. indcoord[1] = (indmap[TextureSampler::BLU_SMP] >> 3) + bias[1];
  269. indcoord[2] = (indmap[TextureSampler::GRN_SMP] >> 3) + bias[2];
  270. AlphaBump = AlphaBump << 5;
  271. break;
  272. case IndTexFormat::ITF_4:
  273. indcoord[0] = (indmap[TextureSampler::ALP_SMP] >> 4) + bias[0];
  274. indcoord[1] = (indmap[TextureSampler::BLU_SMP] >> 4) + bias[1];
  275. indcoord[2] = (indmap[TextureSampler::GRN_SMP] >> 4) + bias[2];
  276. AlphaBump = AlphaBump << 4;
  277. break;
  278. case IndTexFormat::ITF_3:
  279. indcoord[0] = (indmap[TextureSampler::ALP_SMP] >> 5) + bias[0];
  280. indcoord[1] = (indmap[TextureSampler::BLU_SMP] >> 5) + bias[1];
  281. indcoord[2] = (indmap[TextureSampler::GRN_SMP] >> 5) + bias[2];
  282. AlphaBump = AlphaBump << 3;
  283. break;
  284. default:
  285. PanicAlertFmt("Invalid indirect format {}", indirect.fmt);
  286. return;
  287. }
  288. s32 indtevtrans[2] = {0, 0};
  289. // matrix multiply - results might overflow, but we don't care since we only use the lower 24 bits
  290. // of the result.
  291. if (indirect.matrix_index != IndMtxIndex::Off)
  292. {
  293. const IND_MTX& indmtx = bpmem.indmtx[static_cast<u32>(indirect.matrix_index.Value()) - 1];
  294. const int shift = 17 - indmtx.GetScale();
  295. switch (indirect.matrix_id)
  296. {
  297. case IndMtxId::Indirect:
  298. // matrix values are S0.10, output format is S17.7, so divide by 8
  299. indtevtrans[0] = (indmtx.col0.ma * indcoord[0] + indmtx.col1.mc * indcoord[1] +
  300. indmtx.col2.me * indcoord[2]) >>
  301. 3;
  302. indtevtrans[1] = (indmtx.col0.mb * indcoord[0] + indmtx.col1.md * indcoord[1] +
  303. indmtx.col2.mf * indcoord[2]) >>
  304. 3;
  305. break;
  306. case IndMtxId::S:
  307. // s is S17.7, matrix elements are divided by 256, output is S17.7, so divide by 256. - TODO:
  308. // Maybe, since s is actually stored as S24, we should divide by 256*64?
  309. indtevtrans[0] = s * indcoord[0] / 256;
  310. indtevtrans[1] = t * indcoord[0] / 256;
  311. break;
  312. case IndMtxId::T:
  313. indtevtrans[0] = s * indcoord[1] / 256;
  314. indtevtrans[1] = t * indcoord[1] / 256;
  315. break;
  316. default:
  317. PanicAlertFmt("Invalid indirect matrix ID {}", indirect.matrix_id);
  318. return;
  319. }
  320. indtevtrans[0] = shift >= 0 ? indtevtrans[0] >> shift : indtevtrans[0] << -shift;
  321. indtevtrans[1] = shift >= 0 ? indtevtrans[1] >> shift : indtevtrans[1] << -shift;
  322. }
  323. else
  324. {
  325. // If matrix_index is Off (0), matrix_id should be Indirect (0)
  326. ASSERT(indirect.matrix_id == IndMtxId::Indirect);
  327. }
  328. if (indirect.fb_addprev)
  329. {
  330. TexCoord.s += (int)(WrapIndirectCoord(s, indirect.sw) + indtevtrans[0]);
  331. TexCoord.t += (int)(WrapIndirectCoord(t, indirect.tw) + indtevtrans[1]);
  332. }
  333. else
  334. {
  335. TexCoord.s = (int)(WrapIndirectCoord(s, indirect.sw) + indtevtrans[0]);
  336. TexCoord.t = (int)(WrapIndirectCoord(t, indirect.tw) + indtevtrans[1]);
  337. }
  338. }
  339. void Tev::Draw()
  340. {
  341. ASSERT(Position[0] >= 0 && Position[0] < s32(EFB_WIDTH));
  342. ASSERT(Position[1] >= 0 && Position[1] < s32(EFB_HEIGHT));
  343. INCSTAT(g_stats.this_frame.tev_pixels_in);
  344. auto& system = Core::System::GetInstance();
  345. auto& pixel_shader_manager = system.GetPixelShaderManager();
  346. // initial color values
  347. for (int i = 0; i < 4; i++)
  348. {
  349. Reg[static_cast<TevOutput>(i)].r = pixel_shader_manager.constants.colors[i][0];
  350. Reg[static_cast<TevOutput>(i)].g = pixel_shader_manager.constants.colors[i][1];
  351. Reg[static_cast<TevOutput>(i)].b = pixel_shader_manager.constants.colors[i][2];
  352. Reg[static_cast<TevOutput>(i)].a = pixel_shader_manager.constants.colors[i][3];
  353. }
  354. for (unsigned int stageNum = 0; stageNum < bpmem.genMode.numindstages; stageNum++)
  355. {
  356. const int stageNum2 = stageNum >> 1;
  357. const int stageOdd = stageNum & 1;
  358. u32 texcoordSel = bpmem.tevindref.getTexCoord(stageNum);
  359. const u32 texmap = bpmem.tevindref.getTexMap(stageNum);
  360. // Quirk: when the tex coord is not less than the number of tex gens (i.e. the tex coord does
  361. // not exist), then tex coord 0 is used (though sometimes glitchy effects happen on console).
  362. // This affects the Mario portrait in Luigi's Mansion, where the developers forgot to set
  363. // the number of tex gens to 2 (bug 11462).
  364. if (texcoordSel >= bpmem.genMode.numtexgens)
  365. texcoordSel = 0;
  366. const TEXSCALE& texscale = bpmem.texscale[stageNum2];
  367. const s32 scaleS = stageOdd ? texscale.ss1 : texscale.ss0;
  368. const s32 scaleT = stageOdd ? texscale.ts1 : texscale.ts0;
  369. TextureSampler::Sample(Uv[texcoordSel].s >> scaleS, Uv[texcoordSel].t >> scaleT,
  370. IndirectLod[stageNum], IndirectLinear[stageNum], texmap,
  371. IndirectTex[stageNum]);
  372. }
  373. for (unsigned int stageNum = 0; stageNum <= bpmem.genMode.numtevstages; stageNum++)
  374. {
  375. const int stageNum2 = stageNum >> 1;
  376. const int stageOdd = stageNum & 1;
  377. const TwoTevStageOrders& order = bpmem.tevorders[stageNum2];
  378. // stage combiners
  379. const TevStageCombiner::ColorCombiner& cc = bpmem.combiners[stageNum].colorC;
  380. const TevStageCombiner::AlphaCombiner& ac = bpmem.combiners[stageNum].alphaC;
  381. u32 texcoordSel = order.getTexCoord(stageOdd);
  382. const u32 texmap = order.getTexMap(stageOdd);
  383. // Quirk: when the tex coord is not less than the number of tex gens (i.e. the tex coord does
  384. // not exist), then tex coord 0 is used (though sometimes glitchy effects happen on console).
  385. if (texcoordSel >= bpmem.genMode.numtexgens)
  386. texcoordSel = 0;
  387. Indirect(stageNum, Uv[texcoordSel].s, Uv[texcoordSel].t);
  388. // sample texture
  389. if (order.getEnable(stageOdd))
  390. {
  391. // RGBA
  392. u8 texel[4];
  393. if (bpmem.genMode.numtexgens > 0)
  394. {
  395. TextureSampler::Sample(TexCoord.s, TexCoord.t, TextureLod[stageNum],
  396. TextureLinear[stageNum], texmap, texel);
  397. }
  398. else
  399. {
  400. // It seems like the result is always black when no tex coords are enabled, but further
  401. // hardware testing is needed.
  402. std::memset(texel, 0, 4);
  403. }
  404. RawTexColor.r = texel[u32(ColorChannel::Red)];
  405. RawTexColor.g = texel[u32(ColorChannel::Green)];
  406. RawTexColor.b = texel[u32(ColorChannel::Blue)];
  407. RawTexColor.a = texel[u32(ColorChannel::Alpha)];
  408. const auto& swap = bpmem.tevksel.GetSwapTable(ac.tswap);
  409. TexColor.r = texel[u32(swap[ColorChannel::Red])];
  410. TexColor.g = texel[u32(swap[ColorChannel::Green])];
  411. TexColor.b = texel[u32(swap[ColorChannel::Blue])];
  412. TexColor.a = texel[u32(swap[ColorChannel::Alpha])];
  413. }
  414. // set konst for this stage
  415. const auto kc = bpmem.tevksel.GetKonstColor(stageNum);
  416. const auto ka = bpmem.tevksel.GetKonstAlpha(stageNum);
  417. StageKonst.r = m_KonstLUT[kc].r;
  418. StageKonst.g = m_KonstLUT[kc].g;
  419. StageKonst.b = m_KonstLUT[kc].b;
  420. StageKonst.a = m_KonstLUT[ka].a;
  421. // set color
  422. SetRasColor(order.getColorChan(stageOdd), ac.rswap);
  423. // combine inputs
  424. InputRegType inputs[4];
  425. inputs[BLU_C].a = m_ColorInputLUT[cc.a].b;
  426. inputs[BLU_C].b = m_ColorInputLUT[cc.b].b;
  427. inputs[BLU_C].c = m_ColorInputLUT[cc.c].b;
  428. inputs[BLU_C].d = m_ColorInputLUT[cc.d].b;
  429. inputs[GRN_C].a = m_ColorInputLUT[cc.a].g;
  430. inputs[GRN_C].b = m_ColorInputLUT[cc.b].g;
  431. inputs[GRN_C].c = m_ColorInputLUT[cc.c].g;
  432. inputs[GRN_C].d = m_ColorInputLUT[cc.d].g;
  433. inputs[RED_C].a = m_ColorInputLUT[cc.a].r;
  434. inputs[RED_C].b = m_ColorInputLUT[cc.b].r;
  435. inputs[RED_C].c = m_ColorInputLUT[cc.c].r;
  436. inputs[RED_C].d = m_ColorInputLUT[cc.d].r;
  437. inputs[ALP_C].a = m_AlphaInputLUT[ac.a].a;
  438. inputs[ALP_C].b = m_AlphaInputLUT[ac.b].a;
  439. inputs[ALP_C].c = m_AlphaInputLUT[ac.c].a;
  440. inputs[ALP_C].d = m_AlphaInputLUT[ac.d].a;
  441. if (cc.bias != TevBias::Compare)
  442. DrawColorRegular(cc, inputs);
  443. else
  444. DrawColorCompare(cc, inputs);
  445. if (cc.clamp)
  446. {
  447. Reg[cc.dest].r = Clamp255(Reg[cc.dest].r);
  448. Reg[cc.dest].g = Clamp255(Reg[cc.dest].g);
  449. Reg[cc.dest].b = Clamp255(Reg[cc.dest].b);
  450. }
  451. else
  452. {
  453. Reg[cc.dest].r = Clamp1024(Reg[cc.dest].r);
  454. Reg[cc.dest].g = Clamp1024(Reg[cc.dest].g);
  455. Reg[cc.dest].b = Clamp1024(Reg[cc.dest].b);
  456. }
  457. if (ac.bias != TevBias::Compare)
  458. DrawAlphaRegular(ac, inputs);
  459. else
  460. DrawAlphaCompare(ac, inputs);
  461. if (ac.clamp)
  462. Reg[ac.dest].a = Clamp255(Reg[ac.dest].a);
  463. else
  464. Reg[ac.dest].a = Clamp1024(Reg[ac.dest].a);
  465. }
  466. // convert to 8 bits per component
  467. // the results of the last tev stage are put onto the screen,
  468. // regardless of the used destination register - TODO: Verify!
  469. const auto& color_index = bpmem.combiners[bpmem.genMode.numtevstages].colorC.dest;
  470. const auto& alpha_index = bpmem.combiners[bpmem.genMode.numtevstages].alphaC.dest;
  471. u8 output[4] = {(u8)Reg[alpha_index].a, (u8)Reg[color_index].b, (u8)Reg[color_index].g,
  472. (u8)Reg[color_index].r};
  473. if (!TevAlphaTest(output[ALP_C]))
  474. return;
  475. // z texture
  476. if (bpmem.ztex2.op != ZTexOp::Disabled)
  477. {
  478. u32 ztex = bpmem.ztex1.bias;
  479. switch (bpmem.ztex2.type)
  480. {
  481. case ZTexFormat::U8:
  482. ztex += RawTexColor[ALP_C];
  483. break;
  484. case ZTexFormat::U16:
  485. ztex += RawTexColor[ALP_C] << 8 | RawTexColor[RED_C];
  486. break;
  487. case ZTexFormat::U24:
  488. ztex += RawTexColor[RED_C] << 16 | RawTexColor[GRN_C] << 8 | RawTexColor[BLU_C];
  489. break;
  490. default:
  491. PanicAlertFmt("Invalid ztex format {}", bpmem.ztex2.type);
  492. }
  493. if (bpmem.ztex2.op == ZTexOp::Add)
  494. ztex += Position[2];
  495. Position[2] = ztex & 0x00ffffff;
  496. }
  497. // fog
  498. if (bpmem.fog.c_proj_fsel.fsel != FogType::Off)
  499. {
  500. float ze;
  501. if (bpmem.fog.c_proj_fsel.proj == FogProjection::Perspective)
  502. {
  503. // perspective
  504. // ze = A/(B - (Zs >> B_SHF))
  505. const s32 denom = bpmem.fog.b_magnitude - (Position[2] >> bpmem.fog.b_shift);
  506. // in addition downscale magnitude and zs to 0.24 bits
  507. ze = (bpmem.fog.GetA() * 16777215.0f) / static_cast<float>(denom);
  508. }
  509. else
  510. {
  511. // orthographic
  512. // ze = a*Zs
  513. // in addition downscale zs to 0.24 bits
  514. ze = bpmem.fog.GetA() * (static_cast<float>(Position[2]) / 16777215.0f);
  515. }
  516. if (bpmem.fogRange.Base.Enabled)
  517. {
  518. // TODO: This is untested and should definitely be checked against real hw.
  519. // - No idea if offset is really normalized against the viewport width or against the
  520. // projection matrix or yet something else
  521. // - scaling of the "k" coefficient isn't clear either.
  522. // First, calculate the offset from the viewport center (normalized to 0..1)
  523. const float offset =
  524. (Position[0] - (static_cast<s32>(bpmem.fogRange.Base.Center.Value()) - 342)) /
  525. static_cast<float>(xfmem.viewport.wd);
  526. // Based on that, choose the index such that points which are far away from the z-axis use the
  527. // 10th "k" value and such that central points use the first value.
  528. float floatindex = 9.f - std::abs(offset) * 9.f;
  529. floatindex = std::clamp(floatindex, 0.f, 9.f); // TODO: This shouldn't be necessary!
  530. // Get the two closest integer indices, look up the corresponding samples
  531. const int indexlower = (int)floatindex;
  532. const int indexupper = indexlower + 1;
  533. // Look up coefficient... Seems like multiplying by 4 makes Fortune Street work properly (fog
  534. // is too strong without the factor)
  535. const float klower = bpmem.fogRange.K[indexlower / 2].GetValue(indexlower % 2) * 4.f;
  536. const float kupper = bpmem.fogRange.K[indexupper / 2].GetValue(indexupper % 2) * 4.f;
  537. // linearly interpolate the samples and multiple ze by the resulting adjustment factor
  538. const float factor = indexupper - floatindex;
  539. const float k = klower * factor + kupper * (1.f - factor);
  540. const float x_adjust = sqrt(offset * offset + k * k) / k;
  541. ze *= x_adjust; // NOTE: This is basically dividing by a cosine (hidden behind
  542. // GXInitFogAdjTable): 1/cos = c/b = sqrt(a^2+b^2)/b
  543. }
  544. ze -= bpmem.fog.GetC();
  545. // clamp 0 to 1
  546. float fog = std::clamp(ze, 0.f, 1.f);
  547. switch (bpmem.fog.c_proj_fsel.fsel)
  548. {
  549. case FogType::Exp:
  550. fog = 1.0f - pow(2.0f, -8.0f * fog);
  551. break;
  552. case FogType::ExpSq:
  553. fog = 1.0f - pow(2.0f, -8.0f * fog * fog);
  554. break;
  555. case FogType::BackwardsExp:
  556. fog = 1.0f - fog;
  557. fog = pow(2.0f, -8.0f * fog);
  558. break;
  559. case FogType::BackwardsExpSq:
  560. fog = 1.0f - fog;
  561. fog = pow(2.0f, -8.0f * fog * fog);
  562. break;
  563. default:
  564. break;
  565. }
  566. // lerp from output to fog color
  567. const u32 fogInt = (u32)(fog * 256);
  568. const u32 invFog = 256 - fogInt;
  569. output[RED_C] = (output[RED_C] * invFog + fogInt * bpmem.fog.color.r) >> 8;
  570. output[GRN_C] = (output[GRN_C] * invFog + fogInt * bpmem.fog.color.g) >> 8;
  571. output[BLU_C] = (output[BLU_C] * invFog + fogInt * bpmem.fog.color.b) >> 8;
  572. }
  573. if (bpmem.GetEmulatedZ() == EmulatedZ::Late)
  574. {
  575. // TODO: Check against hw if these values get incremented even if depth testing is disabled
  576. EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_INPUT);
  577. if (!EfbInterface::ZCompare(Position[0], Position[1], Position[2]))
  578. return;
  579. EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_OUTPUT);
  580. }
  581. // The GC/Wii GPU rasterizes in 2x2 pixel groups, so bounding box values will be rounded to the
  582. // extents of these groups, rather than the exact pixel.
  583. BBoxManager::Update(static_cast<u16>(Position[0] & ~1), static_cast<u16>(Position[0] | 1),
  584. static_cast<u16>(Position[1] & ~1), static_cast<u16>(Position[1] | 1));
  585. INCSTAT(g_stats.this_frame.tev_pixels_out);
  586. EfbInterface::IncPerfCounterQuadCount(PQ_BLEND_INPUT);
  587. EfbInterface::BlendTev(Position[0], Position[1], output);
  588. }
  589. void Tev::SetKonstColors()
  590. {
  591. auto& system = Core::System::GetInstance();
  592. auto& pixel_shader_manager = system.GetPixelShaderManager();
  593. for (int i = 0; i < 4; i++)
  594. {
  595. KonstantColors[i].r = pixel_shader_manager.constants.kcolors[i][0];
  596. KonstantColors[i].g = pixel_shader_manager.constants.kcolors[i][1];
  597. KonstantColors[i].b = pixel_shader_manager.constants.kcolors[i][2];
  598. KonstantColors[i].a = pixel_shader_manager.constants.kcolors[i][3];
  599. }
  600. }