TextureDecoder_Common.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. // Copyright 2014 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <algorithm>
  4. #include <array>
  5. #include <cmath>
  6. #include <cstddef>
  7. #include <span>
  8. #include "Common/CommonTypes.h"
  9. #include "Common/MsgHandler.h"
  10. #include "Common/SpanUtils.h"
  11. #include "Common/Swap.h"
  12. #include "VideoCommon/LookUpTables.h"
  13. #include "VideoCommon/TextureDecoder.h"
  14. #include "VideoCommon/TextureDecoder_Util.h"
  15. #include "VideoCommon/sfont.inc"
  16. static bool TexFmt_Overlay_Enable = false;
  17. static bool TexFmt_Overlay_Center = false;
  18. // TRAM
  19. // STATE_TO_SAVE
  20. alignas(16) std::array<u8, TMEM_SIZE> s_tex_mem;
  21. int TexDecoder_GetTexelSizeInNibbles(TextureFormat format)
  22. {
  23. switch (format)
  24. {
  25. // 4-bit formats
  26. case TextureFormat::I4:
  27. case TextureFormat::C4:
  28. return 1;
  29. // 8-bit formats
  30. case TextureFormat::I8:
  31. case TextureFormat::IA4:
  32. case TextureFormat::C8:
  33. return 2;
  34. // 16-bit formats
  35. case TextureFormat::IA8:
  36. case TextureFormat::RGB565:
  37. case TextureFormat::RGB5A3:
  38. case TextureFormat::C14X2:
  39. return 4;
  40. // 32-bit formats
  41. case TextureFormat::RGBA8:
  42. return 8;
  43. // Compressed format
  44. case TextureFormat::CMPR:
  45. return 1;
  46. // Special formats
  47. case TextureFormat::XFB:
  48. return 4;
  49. default:
  50. PanicAlertFmt("Invalid Texture Format {}! (GetTexelSizeInNibbles)", format);
  51. return 1;
  52. }
  53. }
  54. int TexDecoder_GetTextureSizeInBytes(int width, int height, TextureFormat format)
  55. {
  56. return (width * height * TexDecoder_GetTexelSizeInNibbles(format)) / 2;
  57. }
  58. int TexDecoder_GetBlockWidthInTexels(TextureFormat format)
  59. {
  60. switch (format)
  61. {
  62. // 4-bit formats
  63. case TextureFormat::I4:
  64. case TextureFormat::C4:
  65. return 8;
  66. // 8-bit formats
  67. case TextureFormat::I8:
  68. case TextureFormat::IA4:
  69. case TextureFormat::C8:
  70. return 8;
  71. // 16-bit formats
  72. case TextureFormat::IA8:
  73. case TextureFormat::RGB565:
  74. case TextureFormat::RGB5A3:
  75. case TextureFormat::C14X2:
  76. return 4;
  77. // 32-bit formats
  78. case TextureFormat::RGBA8:
  79. return 4;
  80. // Compressed format
  81. case TextureFormat::CMPR:
  82. return 8;
  83. // Special formats
  84. case TextureFormat::XFB:
  85. return 16;
  86. default:
  87. PanicAlertFmt("Invalid Texture Format {}! (GetBlockWidthInTexels)", format);
  88. return 8;
  89. }
  90. }
  91. int TexDecoder_GetBlockHeightInTexels(TextureFormat format)
  92. {
  93. switch (format)
  94. {
  95. // 4-bit formats
  96. case TextureFormat::I4:
  97. case TextureFormat::C4:
  98. return 8;
  99. // 8-bit formats
  100. case TextureFormat::I8:
  101. case TextureFormat::IA4:
  102. case TextureFormat::C8:
  103. return 4;
  104. // 16-bit formats
  105. case TextureFormat::IA8:
  106. case TextureFormat::RGB565:
  107. case TextureFormat::RGB5A3:
  108. case TextureFormat::C14X2:
  109. return 4;
  110. // 32-bit formats
  111. case TextureFormat::RGBA8:
  112. return 4;
  113. // Compressed format
  114. case TextureFormat::CMPR:
  115. return 8;
  116. // Special formats
  117. case TextureFormat::XFB:
  118. return 1;
  119. default:
  120. PanicAlertFmt("Invalid Texture Format {}! (GetBlockHeightInTexels)", format);
  121. return 4;
  122. }
  123. }
  124. int TexDecoder_GetEFBCopyBlockWidthInTexels(EFBCopyFormat format)
  125. {
  126. switch (format)
  127. {
  128. // 4-bit formats
  129. case EFBCopyFormat::R4:
  130. return 8;
  131. // 8-bit formats
  132. case EFBCopyFormat::RA4:
  133. case EFBCopyFormat::A8:
  134. case EFBCopyFormat::R8_0x1:
  135. case EFBCopyFormat::R8:
  136. case EFBCopyFormat::G8:
  137. case EFBCopyFormat::B8:
  138. return 8;
  139. // 16-bit formats
  140. case EFBCopyFormat::RA8:
  141. case EFBCopyFormat::RGB565:
  142. case EFBCopyFormat::RGB5A3:
  143. case EFBCopyFormat::RG8:
  144. case EFBCopyFormat::GB8:
  145. return 4;
  146. // 32-bit formats
  147. case EFBCopyFormat::RGBA8:
  148. return 4;
  149. // Special formats
  150. case EFBCopyFormat::XFB:
  151. return 16;
  152. default:
  153. PanicAlertFmt("Invalid EFB Copy Format {}! (GetEFBCopyBlockWidthInTexels)", format);
  154. return 8;
  155. }
  156. }
  157. int TexDecoder_GetEFBCopyBlockHeightInTexels(EFBCopyFormat format)
  158. {
  159. switch (format)
  160. {
  161. // 4-bit formats
  162. case EFBCopyFormat::R4:
  163. return 8;
  164. // 8-bit formats
  165. case EFBCopyFormat::RA4:
  166. case EFBCopyFormat::A8:
  167. case EFBCopyFormat::R8_0x1:
  168. case EFBCopyFormat::R8:
  169. case EFBCopyFormat::G8:
  170. case EFBCopyFormat::B8:
  171. return 4;
  172. // 16-bit formats
  173. case EFBCopyFormat::RA8:
  174. case EFBCopyFormat::RGB565:
  175. case EFBCopyFormat::RGB5A3:
  176. case EFBCopyFormat::RG8:
  177. case EFBCopyFormat::GB8:
  178. return 4;
  179. // 32-bit formats
  180. case EFBCopyFormat::RGBA8:
  181. return 4;
  182. // Special formats
  183. case EFBCopyFormat::XFB:
  184. return 1;
  185. default:
  186. PanicAlertFmt("Invalid EFB Copy Format {}! (GetEFBCopyBlockHeightInTexels)", format);
  187. return 4;
  188. }
  189. }
  190. // returns bytes
  191. int TexDecoder_GetPaletteSize(TextureFormat format)
  192. {
  193. switch (format)
  194. {
  195. case TextureFormat::C4:
  196. return 16 * 2;
  197. case TextureFormat::C8:
  198. return 256 * 2;
  199. case TextureFormat::C14X2:
  200. return 16384 * 2;
  201. default:
  202. return 0;
  203. }
  204. }
  205. // Get the "in memory" texture format of an EFB copy's format.
  206. // With the exception of c4/c8/c14 paletted texture formats (which are handled elsewhere)
  207. // this is the format the game should be using when it is drawing an EFB copy back.
  208. TextureFormat TexDecoder_GetEFBCopyBaseFormat(EFBCopyFormat format)
  209. {
  210. switch (format)
  211. {
  212. case EFBCopyFormat::R4:
  213. return TextureFormat::I4;
  214. case EFBCopyFormat::A8:
  215. case EFBCopyFormat::R8_0x1:
  216. case EFBCopyFormat::R8:
  217. case EFBCopyFormat::G8:
  218. case EFBCopyFormat::B8:
  219. return TextureFormat::I8;
  220. case EFBCopyFormat::RA4:
  221. return TextureFormat::IA4;
  222. case EFBCopyFormat::RA8:
  223. case EFBCopyFormat::RG8:
  224. case EFBCopyFormat::GB8:
  225. return TextureFormat::IA8;
  226. case EFBCopyFormat::RGB565:
  227. return TextureFormat::RGB565;
  228. case EFBCopyFormat::RGB5A3:
  229. return TextureFormat::RGB5A3;
  230. case EFBCopyFormat::RGBA8:
  231. return TextureFormat::RGBA8;
  232. case EFBCopyFormat::XFB:
  233. return TextureFormat::XFB;
  234. default:
  235. PanicAlertFmt("Invalid EFB Copy Format {}! (GetEFBCopyBaseFormat)", format);
  236. return static_cast<TextureFormat>(format);
  237. }
  238. }
  239. void TexDecoder_SetTexFmtOverlayOptions(bool enable, bool center)
  240. {
  241. TexFmt_Overlay_Enable = enable;
  242. TexFmt_Overlay_Center = center;
  243. }
  244. static void TexDecoder_DrawOverlay(u8* dst, int width, int height, TextureFormat texformat)
  245. {
  246. int w = std::min(width, 40);
  247. int h = std::min(height, 10);
  248. int xoff = (width - w) >> 1;
  249. int yoff = (height - h) >> 1;
  250. if (!TexFmt_Overlay_Center)
  251. {
  252. xoff = 0;
  253. yoff = 0;
  254. }
  255. const auto fmt_str = fmt::to_string(texformat);
  256. for (char ch : fmt_str)
  257. {
  258. int xcnt = 0;
  259. int nchar = sfont_map[static_cast<u8>(ch)];
  260. const unsigned char* ptr = sfont_raw[nchar]; // each char is up to 9x10
  261. for (int x = 0; x < 9; x++)
  262. {
  263. if (ptr[x] == 0x78)
  264. break;
  265. xcnt++;
  266. }
  267. for (int y = 0; y < 10; y++)
  268. {
  269. for (int x = 0; x < xcnt; x++)
  270. {
  271. int* dtp = (int*)dst;
  272. dtp[(y + yoff) * width + x + xoff] = ptr[x] ? 0xFFFFFFFF : 0xFF000000;
  273. }
  274. ptr += 9;
  275. }
  276. xoff += xcnt;
  277. }
  278. }
  279. void TexDecoder_Decode(u8* dst, const u8* src, int width, int height, TextureFormat texformat,
  280. const u8* tlut, TLUTFormat tlutfmt)
  281. {
  282. _TexDecoder_DecodeImpl((u32*)dst, src, width, height, texformat, tlut, tlutfmt);
  283. if (TexFmt_Overlay_Enable)
  284. TexDecoder_DrawOverlay(dst, width, height, texformat);
  285. }
  286. static inline u32 DecodePixel_IA8(u16 val)
  287. {
  288. int a = val & 0xFF;
  289. int i = val >> 8;
  290. return i | (i << 8) | (i << 16) | (a << 24);
  291. }
  292. static inline u32 DecodePixel_RGB565(u16 val)
  293. {
  294. int r, g, b, a;
  295. r = Convert5To8((val >> 11) & 0x1f);
  296. g = Convert6To8((val >> 5) & 0x3f);
  297. b = Convert5To8((val)&0x1f);
  298. a = 0xFF;
  299. return r | (g << 8) | (b << 16) | (a << 24);
  300. }
  301. static inline u32 DecodePixel_RGB5A3(u16 val)
  302. {
  303. int r, g, b, a;
  304. if ((val & 0x8000))
  305. {
  306. r = Convert5To8((val >> 10) & 0x1f);
  307. g = Convert5To8((val >> 5) & 0x1f);
  308. b = Convert5To8((val)&0x1f);
  309. a = 0xFF;
  310. }
  311. else
  312. {
  313. a = Convert3To8((val >> 12) & 0x7);
  314. r = Convert4To8((val >> 8) & 0xf);
  315. g = Convert4To8((val >> 4) & 0xf);
  316. b = Convert4To8((val)&0xf);
  317. }
  318. return r | (g << 8) | (b << 16) | (a << 24);
  319. }
  320. static inline u32 DecodePixel_Paletted(u16 pixel, TLUTFormat tlutfmt)
  321. {
  322. switch (tlutfmt)
  323. {
  324. case TLUTFormat::IA8:
  325. return DecodePixel_IA8(pixel);
  326. case TLUTFormat::RGB565:
  327. return DecodePixel_RGB565(Common::swap16(pixel));
  328. case TLUTFormat::RGB5A3:
  329. return DecodePixel_RGB5A3(Common::swap16(pixel));
  330. default:
  331. return 0;
  332. }
  333. }
  334. void TexDecoder_DecodeTexel(u8* dst, std::span<const u8> src, int s, int t, int imageWidth,
  335. TextureFormat texformat, std::span<const u8> tlut_, TLUTFormat tlutfmt)
  336. {
  337. /* General formula for computing texture offset
  338. //
  339. u16 sBlk = s / blockWidth;
  340. u16 tBlk = t / blockHeight;
  341. u16 widthBlks = (width / blockWidth) + 1;
  342. u32 base = (tBlk * widthBlks + sBlk) * blockWidth * blockHeight;
  343. u16 blkS = s & (blockWidth - 1);
  344. u16 blkT = t & (blockHeight - 1);
  345. u32 blkOff = blkT * blockWidth + blkS;
  346. */
  347. switch (texformat)
  348. {
  349. case TextureFormat::C4:
  350. {
  351. u16 sBlk = s >> 3;
  352. u16 tBlk = t >> 3;
  353. u16 widthBlks = (imageWidth >> 3) + 1;
  354. u32 base = (tBlk * widthBlks + sBlk) << 5;
  355. u16 blkS = s & 7;
  356. u16 blkT = t & 7;
  357. u32 blkOff = (blkT << 3) + blkS;
  358. int rs = (blkOff & 1) ? 0 : 4;
  359. u32 offset = base + (blkOff >> 1);
  360. u8 val = (Common::SafeSpanRead<u8>(src, offset) >> rs) & 0xF;
  361. u16 pixel = Common::SafeSpanRead<u16>(tlut_, sizeof(u16) * val);
  362. *((u32*)dst) = DecodePixel_Paletted(pixel, tlutfmt);
  363. }
  364. break;
  365. case TextureFormat::I4:
  366. {
  367. u16 sBlk = s >> 3;
  368. u16 tBlk = t >> 3;
  369. u16 widthBlks = (imageWidth >> 3) + 1;
  370. u32 base = (tBlk * widthBlks + sBlk) << 5;
  371. u16 blkS = s & 7;
  372. u16 blkT = t & 7;
  373. u32 blkOff = (blkT << 3) + blkS;
  374. int rs = (blkOff & 1) ? 0 : 4;
  375. u32 offset = base + (blkOff >> 1);
  376. u8 val = (Common::SafeSpanRead<u8>(src, offset) >> rs) & 0xF;
  377. val = Convert4To8(val);
  378. dst[0] = val;
  379. dst[1] = val;
  380. dst[2] = val;
  381. dst[3] = val;
  382. }
  383. break;
  384. case TextureFormat::I8:
  385. {
  386. u16 sBlk = s >> 3;
  387. u16 tBlk = t >> 2;
  388. u16 widthBlks = (imageWidth >> 3) + 1;
  389. u32 base = (tBlk * widthBlks + sBlk) << 5;
  390. u16 blkS = s & 7;
  391. u16 blkT = t & 3;
  392. u32 blkOff = (blkT << 3) + blkS;
  393. u8 val = Common::SafeSpanRead<u8>(src, base + blkOff);
  394. dst[0] = val;
  395. dst[1] = val;
  396. dst[2] = val;
  397. dst[3] = val;
  398. }
  399. break;
  400. case TextureFormat::C8:
  401. {
  402. u16 sBlk = s >> 3;
  403. u16 tBlk = t >> 2;
  404. u16 widthBlks = (imageWidth >> 3) + 1;
  405. u32 base = (tBlk * widthBlks + sBlk) << 5;
  406. u16 blkS = s & 7;
  407. u16 blkT = t & 3;
  408. u32 blkOff = (blkT << 3) + blkS;
  409. u8 val = Common::SafeSpanRead<u8>(src, base + blkOff);
  410. u16 pixel = Common::SafeSpanRead<u16>(tlut_, sizeof(u16) * val);
  411. *((u32*)dst) = DecodePixel_Paletted(pixel, tlutfmt);
  412. }
  413. break;
  414. case TextureFormat::IA4:
  415. {
  416. u16 sBlk = s >> 3;
  417. u16 tBlk = t >> 2;
  418. u16 widthBlks = (imageWidth >> 3) + 1;
  419. u32 base = (tBlk * widthBlks + sBlk) << 5;
  420. u16 blkS = s & 7;
  421. u16 blkT = t & 3;
  422. u32 blkOff = (blkT << 3) + blkS;
  423. u8 val = Common::SafeSpanRead<u8>(src, base + blkOff);
  424. const u8 a = Convert4To8(val >> 4);
  425. const u8 l = Convert4To8(val & 0xF);
  426. dst[0] = l;
  427. dst[1] = l;
  428. dst[2] = l;
  429. dst[3] = a;
  430. }
  431. break;
  432. case TextureFormat::IA8:
  433. {
  434. u16 sBlk = s >> 2;
  435. u16 tBlk = t >> 2;
  436. u16 widthBlks = (imageWidth >> 2) + 1;
  437. u32 base = (tBlk * widthBlks + sBlk) << 4;
  438. u16 blkS = s & 3;
  439. u16 blkT = t & 3;
  440. u32 blkOff = (blkT << 2) + blkS;
  441. u32 offset = (base + blkOff) << 1;
  442. u16 val = Common::SafeSpanRead<u16>(src, offset);
  443. *((u32*)dst) = DecodePixel_IA8(val);
  444. }
  445. break;
  446. case TextureFormat::C14X2:
  447. {
  448. u16 sBlk = s >> 2;
  449. u16 tBlk = t >> 2;
  450. u16 widthBlks = (imageWidth >> 2) + 1;
  451. u32 base = (tBlk * widthBlks + sBlk) << 4;
  452. u16 blkS = s & 3;
  453. u16 blkT = t & 3;
  454. u32 blkOff = (blkT << 2) + blkS;
  455. u32 offset = (base + blkOff) << 1;
  456. u16 val = Common::swap16(Common::SafeSpanRead<u16>(src, offset)) & 0x3FFF;
  457. u16 pixel = Common::SafeSpanRead<u16>(tlut_, sizeof(u16) * val);
  458. *((u32*)dst) = DecodePixel_Paletted(pixel, tlutfmt);
  459. }
  460. break;
  461. case TextureFormat::RGB565:
  462. {
  463. u16 sBlk = s >> 2;
  464. u16 tBlk = t >> 2;
  465. u16 widthBlks = (imageWidth >> 2) + 1;
  466. u32 base = (tBlk * widthBlks + sBlk) << 4;
  467. u16 blkS = s & 3;
  468. u16 blkT = t & 3;
  469. u32 blkOff = (blkT << 2) + blkS;
  470. u32 offset = (base + blkOff) << 1;
  471. u16 val = Common::SafeSpanRead<u16>(src, offset);
  472. *((u32*)dst) = DecodePixel_RGB565(Common::swap16(val));
  473. }
  474. break;
  475. case TextureFormat::RGB5A3:
  476. {
  477. u16 sBlk = s >> 2;
  478. u16 tBlk = t >> 2;
  479. u16 widthBlks = (imageWidth >> 2) + 1;
  480. u32 base = (tBlk * widthBlks + sBlk) << 4;
  481. u16 blkS = s & 3;
  482. u16 blkT = t & 3;
  483. u32 blkOff = (blkT << 2) + blkS;
  484. u32 offset = (base + blkOff) << 1;
  485. u16 val = Common::SafeSpanRead<u16>(src, offset);
  486. *((u32*)dst) = DecodePixel_RGB5A3(Common::swap16(val));
  487. }
  488. break;
  489. case TextureFormat::RGBA8:
  490. {
  491. u16 sBlk = s >> 2;
  492. u16 tBlk = t >> 2;
  493. u16 widthBlks = (imageWidth >> 2) + 1;
  494. u32 base = (tBlk * widthBlks + sBlk) << 5; // shift by 5 is correct
  495. u16 blkS = s & 3;
  496. u16 blkT = t & 3;
  497. u32 blkOff = (blkT << 2) + blkS;
  498. u32 offset = (base + blkOff) << 1;
  499. dst[3] = Common::SafeSpanRead<u8>(src, offset);
  500. dst[0] = Common::SafeSpanRead<u8>(src, offset + 1);
  501. dst[1] = Common::SafeSpanRead<u8>(src, offset + 32);
  502. dst[2] = Common::SafeSpanRead<u8>(src, offset + 33);
  503. }
  504. break;
  505. case TextureFormat::CMPR:
  506. {
  507. u16 sDxt = s >> 2;
  508. u16 tDxt = t >> 2;
  509. u16 sBlk = sDxt >> 1;
  510. u16 tBlk = tDxt >> 1;
  511. u16 widthBlks = (imageWidth >> 3) + 1;
  512. u32 base = (tBlk * widthBlks + sBlk) << 2;
  513. u16 blkS = sDxt & 1;
  514. u16 blkT = tDxt & 1;
  515. u32 blkOff = (blkT << 1) + blkS;
  516. u32 offset = (base + blkOff) << 3;
  517. DXTBlock dxtBlock = Common::SafeSpanRead<DXTBlock>(src, offset);
  518. u16 c1 = Common::swap16(dxtBlock.color1);
  519. u16 c2 = Common::swap16(dxtBlock.color2);
  520. int blue1 = Convert5To8(c1 & 0x1F);
  521. int blue2 = Convert5To8(c2 & 0x1F);
  522. int green1 = Convert6To8((c1 >> 5) & 0x3F);
  523. int green2 = Convert6To8((c2 >> 5) & 0x3F);
  524. int red1 = Convert5To8((c1 >> 11) & 0x1F);
  525. int red2 = Convert5To8((c2 >> 11) & 0x1F);
  526. u16 ss = s & 3;
  527. u16 tt = t & 3;
  528. int colorSel = dxtBlock.lines[tt];
  529. int rs = 6 - (ss << 1);
  530. colorSel = (colorSel >> rs) & 3;
  531. colorSel |= c1 > c2 ? 0 : 4;
  532. u32 color = 0;
  533. switch (colorSel)
  534. {
  535. case 0:
  536. case 4:
  537. color = MakeRGBA(red1, green1, blue1, 255);
  538. break;
  539. case 1:
  540. case 5:
  541. color = MakeRGBA(red2, green2, blue2, 255);
  542. break;
  543. case 2:
  544. color = MakeRGBA(DXTBlend(red2, red1), DXTBlend(green2, green1), DXTBlend(blue2, blue1), 255);
  545. break;
  546. case 3:
  547. color = MakeRGBA(DXTBlend(red1, red2), DXTBlend(green1, green2), DXTBlend(blue1, blue2), 255);
  548. break;
  549. case 6:
  550. color = MakeRGBA((red1 + red2) / 2, (green1 + green2) / 2, (blue1 + blue2) / 2, 255);
  551. break;
  552. case 7:
  553. // color[3] is the same as color[2] (average of both colors), but transparent.
  554. // This differs from DXT1 where color[3] is transparent black.
  555. color = MakeRGBA((red1 + red2) / 2, (green1 + green2) / 2, (blue1 + blue2) / 2, 0);
  556. break;
  557. default:
  558. color = 0;
  559. break;
  560. }
  561. *((u32*)dst) = color;
  562. }
  563. break;
  564. case TextureFormat::XFB:
  565. {
  566. size_t offset = (t * imageWidth + (s & (~1))) * 2;
  567. // We do this one color sample (aka 2 RGB pixles) at a time
  568. int Y = int((s & 1) == 0 ? src[offset] : src[offset + 2]) - 16;
  569. int U = int(src[offset + 1]) - 128;
  570. int V = int(src[offset + 3]) - 128;
  571. // We do the inverse BT.601 conversion for YCbCr to RGB
  572. // http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion
  573. // TODO: Use more precise numbers for this conversion (although on real hardware, the XFB isn't
  574. // in a real texture format, so does this conversion actually ever happen?)
  575. u8 R = std::clamp(int(1.164f * Y + 1.596f * V), 0, 255);
  576. u8 G = std::clamp(int(1.164f * Y - 0.392f * U - 0.813f * V), 0, 255);
  577. u8 B = std::clamp(int(1.164f * Y + 2.017f * U), 0, 255);
  578. dst[t * imageWidth + s] = 0xff000000 | B << 16 | G << 8 | R;
  579. }
  580. break;
  581. }
  582. }
  583. void TexDecoder_DecodeTexelRGBA8FromTmem(u8* dst, std::span<const u8> src_ar,
  584. std::span<const u8> src_gb, int s, int t, int imageWidth)
  585. {
  586. u16 sBlk = s >> 2;
  587. u16 tBlk = t >> 2;
  588. u16 widthBlks =
  589. (imageWidth >> 2) + 1; // TODO: Looks wrong. Shouldn't this be ((imageWidth-1)>>2)+1 ?
  590. u32 base_ar = (tBlk * widthBlks + sBlk) << 4;
  591. u32 base_gb = (tBlk * widthBlks + sBlk) << 4;
  592. u16 blkS = s & 3;
  593. u16 blkT = t & 3;
  594. u32 blk_off = (blkT << 2) + blkS;
  595. u32 offset_ar = (base_ar + blk_off) << 1;
  596. u32 offset_gb = (base_gb + blk_off) << 1;
  597. dst[3] = Common::SafeSpanRead<u8>(src_ar, offset_ar); // A
  598. dst[0] = Common::SafeSpanRead<u8>(src_ar, offset_ar + 1); // R
  599. dst[1] = Common::SafeSpanRead<u8>(src_gb, offset_gb); // G
  600. dst[2] = Common::SafeSpanRead<u8>(src_gb, offset_gb + 1); // B
  601. }
  602. void TexDecoder_DecodeTexelRGBA8FromTmem(u8* dst, const u8* src_ar, const u8* src_gb, int s, int t,
  603. int imageWidth)
  604. {
  605. u16 sBlk = s >> 2;
  606. u16 tBlk = t >> 2;
  607. u16 widthBlks =
  608. (imageWidth >> 2) + 1; // TODO: Looks wrong. Shouldn't this be ((imageWidth-1)>>2)+1 ?
  609. u32 base_ar = (tBlk * widthBlks + sBlk) << 4;
  610. u32 base_gb = (tBlk * widthBlks + sBlk) << 4;
  611. u16 blkS = s & 3;
  612. u16 blkT = t & 3;
  613. u32 blk_off = (blkT << 2) + blkS;
  614. u32 offset_ar = (base_ar + blk_off) << 1;
  615. u32 offset_gb = (base_gb + blk_off) << 1;
  616. const u8* val_addr_ar = src_ar + offset_ar;
  617. const u8* val_addr_gb = src_gb + offset_gb;
  618. dst[3] = val_addr_ar[0]; // A
  619. dst[0] = val_addr_ar[1]; // R
  620. dst[1] = val_addr_gb[0]; // G
  621. dst[2] = val_addr_gb[1]; // B
  622. }
  623. void TexDecoder_DecodeRGBA8FromTmem(u8* dst, const u8* src_ar, const u8* src_gb, int width,
  624. int height)
  625. {
  626. // TODO for someone who cares: Make this less slow!
  627. for (int y = 0; y < height; ++y)
  628. {
  629. for (int x = 0; x < width; ++x)
  630. {
  631. TexDecoder_DecodeTexelRGBA8FromTmem(dst, src_ar, src_gb, x, y, width - 1);
  632. dst += 4;
  633. }
  634. }
  635. }
  636. void TexDecoder_DecodeXFB(u8* dst, const u8* src, u32 width, u32 height, u32 stride)
  637. {
  638. const u8* src_ptr = src;
  639. u8* dst_ptr = dst;
  640. for (u32 y = 0; y < height; y++)
  641. {
  642. const u8* row_ptr = src_ptr;
  643. for (u32 x = 0; x < width; x += 2)
  644. {
  645. // We do this one color sample (aka 2 RGB pixels) at a time
  646. int Y1 = int(*(row_ptr++)) - 16;
  647. int U = int(*(row_ptr++)) - 128;
  648. int Y2 = int(*(row_ptr++)) - 16;
  649. int V = int(*(row_ptr++)) - 128;
  650. // We do the inverse BT.601 conversion for YCbCr to RGB
  651. // http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion
  652. // TODO: Use more precise numbers for this conversion (although on real hardware, the XFB
  653. // isn't in a real texture format, so does this conversion actually ever happen?)
  654. u8 R1 = static_cast<u8>(std::clamp(int(1.164f * Y1 + 1.596f * V), 0, 255));
  655. u8 G1 = static_cast<u8>(std::clamp(int(1.164f * Y1 - 0.392f * U - 0.813f * V), 0, 255));
  656. u8 B1 = static_cast<u8>(std::clamp(int(1.164f * Y1 + 2.017f * U), 0, 255));
  657. u8 R2 = static_cast<u8>(std::clamp(int(1.164f * Y2 + 1.596f * V), 0, 255));
  658. u8 G2 = static_cast<u8>(std::clamp(int(1.164f * Y2 - 0.392f * U - 0.813f * V), 0, 255));
  659. u8 B2 = static_cast<u8>(std::clamp(int(1.164f * Y2 + 2.017f * U), 0, 255));
  660. u32 rgba = 0xff000000 | B1 << 16 | G1 << 8 | R1;
  661. std::memcpy(dst_ptr, &rgba, sizeof(rgba));
  662. dst_ptr += sizeof(rgba);
  663. rgba = 0xff000000 | B2 << 16 | G2 << 8 | R2;
  664. std::memcpy(dst_ptr, &rgba, sizeof(rgba));
  665. dst_ptr += sizeof(rgba);
  666. }
  667. src_ptr += stride;
  668. }
  669. }