astcenc_color_unquantize.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  1. // SPDX-License-Identifier: Apache-2.0
  2. // ----------------------------------------------------------------------------
  3. // Copyright 2011-2021 Arm Limited
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License"); you may not
  6. // use this file except in compliance with the License. You may obtain a copy
  7. // of the License at:
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  13. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  14. // License for the specific language governing permissions and limitations
  15. // under the License.
  16. // ----------------------------------------------------------------------------
  17. #include <utility>
  18. /**
  19. * @brief Functions for color unquantization.
  20. */
  21. #include "astcenc_internal.h"
  22. /**
  23. * @brief Un-blue-contract a color.
  24. *
  25. * This function reverses any applied blue contraction.
  26. *
  27. * @param input The input color that has been blue-contracted.
  28. *
  29. * @return The uncontracted color.
  30. */
  31. static ASTCENC_SIMD_INLINE vint4 uncontract_color(
  32. vint4 input
  33. ) {
  34. vmask4 mask(true, true, false, false);
  35. vint4 bc0 = asr<1>(input + input.lane<2>());
  36. return select(input, bc0, mask);
  37. }
  38. /**
  39. * @brief Unpack an LDR RGBA color that uses delta encoding.
  40. *
  41. * @param input0 The packed endpoint 0 color.
  42. * @param input1 The packed endpoint 1 color deltas.
  43. * @param[out] output0 The unpacked endpoint 0 color.
  44. * @param[out] output1 The unpacked endpoint 1 color.
  45. */
  46. static void rgba_delta_unpack(
  47. vint4 input0,
  48. vint4 input1,
  49. vint4& output0,
  50. vint4& output1
  51. ) {
  52. // Apply bit transfer
  53. bit_transfer_signed(input1, input0);
  54. // Apply blue-uncontraction if needed
  55. int rgb_sum = hadd_rgb_s(input1);
  56. input1 = input1 + input0;
  57. if (rgb_sum < 0)
  58. {
  59. input0 = uncontract_color(input0);
  60. input1 = uncontract_color(input1);
  61. std::swap(input0, input1);
  62. }
  63. output0 = clamp(0, 255, input0);
  64. output1 = clamp(0, 255, input1);
  65. }
  66. /**
  67. * @brief Unpack an LDR RGB color that uses delta encoding.
  68. *
  69. * Output alpha set to 255.
  70. *
  71. * @param input0 The packed endpoint 0 color.
  72. * @param input1 The packed endpoint 1 color deltas.
  73. * @param[out] output0 The unpacked endpoint 0 color.
  74. * @param[out] output1 The unpacked endpoint 1 color.
  75. */
  76. static void rgb_delta_unpack(
  77. vint4 input0,
  78. vint4 input1,
  79. vint4& output0,
  80. vint4& output1
  81. ) {
  82. rgba_delta_unpack(input0, input1, output0, output1);
  83. output0.set_lane<3>(255);
  84. output1.set_lane<3>(255);
  85. }
  86. /**
  87. * @brief Unpack an LDR RGBA color that uses direct encoding.
  88. *
  89. * @param input0 The packed endpoint 0 color.
  90. * @param input1 The packed endpoint 1 color.
  91. * @param[out] output0 The unpacked endpoint 0 color.
  92. * @param[out] output1 The unpacked endpoint 1 color.
  93. */
  94. static void rgba_unpack(
  95. vint4 input0,
  96. vint4 input1,
  97. vint4& output0,
  98. vint4& output1
  99. ) {
  100. // Apply blue-uncontraction if needed
  101. if (hadd_rgb_s(input0) > hadd_rgb_s(input1))
  102. {
  103. input0 = uncontract_color(input0);
  104. input1 = uncontract_color(input1);
  105. std::swap(input0, input1);
  106. }
  107. output0 = input0;
  108. output1 = input1;
  109. }
  110. /**
  111. * @brief Unpack an LDR RGB color that uses direct encoding.
  112. *
  113. * Output alpha set to 255.
  114. *
  115. * @param input0 The packed endpoint 0 color.
  116. * @param input1 The packed endpoint 1 color.
  117. * @param[out] output0 The unpacked endpoint 0 color.
  118. * @param[out] output1 The unpacked endpoint 1 color.
  119. */
  120. static void rgb_unpack(
  121. vint4 input0,
  122. vint4 input1,
  123. vint4& output0,
  124. vint4& output1
  125. ) {
  126. rgba_unpack(input0, input1, output0, output1);
  127. output0.set_lane<3>(255);
  128. output1.set_lane<3>(255);
  129. }
  130. /**
  131. * @brief Unpack an LDR RGBA color that uses scaled encoding.
  132. *
  133. * Note only the RGB channels use the scaled encoding, alpha uses direct.
  134. *
  135. * @param input0 The packed endpoint 0 color.
  136. * @param alpha1 The packed endpoint 1 alpha value.
  137. * @param scale The packed quantized scale.
  138. * @param[out] output0 The unpacked endpoint 0 color.
  139. * @param[out] output1 The unpacked endpoint 1 color.
  140. */
  141. static void rgb_scale_alpha_unpack(
  142. vint4 input0,
  143. uint8_t alpha1,
  144. uint8_t scale,
  145. vint4& output0,
  146. vint4& output1
  147. ) {
  148. output1 = input0;
  149. output1.set_lane<3>(alpha1);
  150. output0 = asr<8>(input0 * scale);
  151. output0.set_lane<3>(input0.lane<3>());
  152. }
  153. /**
  154. * @brief Unpack an LDR RGB color that uses scaled encoding.
  155. *
  156. * Output alpha is 255.
  157. *
  158. * @param input0 The packed endpoint 0 color.
  159. * @param scale The packed scale.
  160. * @param[out] output0 The unpacked endpoint 0 color.
  161. * @param[out] output1 The unpacked endpoint 1 color.
  162. */
  163. static void rgb_scale_unpack(
  164. vint4 input0,
  165. int scale,
  166. vint4& output0,
  167. vint4& output1
  168. ) {
  169. output1 = input0;
  170. output1.set_lane<3>(255);
  171. output0 = asr<8>(input0 * scale);
  172. output0.set_lane<3>(255);
  173. }
  174. /**
  175. * @brief Unpack an LDR L color that uses direct encoding.
  176. *
  177. * Output alpha is 255.
  178. *
  179. * @param input The packed endpoints.
  180. * @param[out] output0 The unpacked endpoint 0 color.
  181. * @param[out] output1 The unpacked endpoint 1 color.
  182. */
  183. static void luminance_unpack(
  184. const uint8_t input[2],
  185. vint4& output0,
  186. vint4& output1
  187. ) {
  188. int lum0 = input[0];
  189. int lum1 = input[1];
  190. output0 = vint4(lum0, lum0, lum0, 255);
  191. output1 = vint4(lum1, lum1, lum1, 255);
  192. }
  193. /**
  194. * @brief Unpack an LDR L color that uses delta encoding.
  195. *
  196. * Output alpha is 255.
  197. *
  198. * @param input The packed endpoints (L0, L1).
  199. * @param[out] output0 The unpacked endpoint 0 color.
  200. * @param[out] output1 The unpacked endpoint 1 color.
  201. */
  202. static void luminance_delta_unpack(
  203. const uint8_t input[2],
  204. vint4& output0,
  205. vint4& output1
  206. ) {
  207. int v0 = input[0];
  208. int v1 = input[1];
  209. int l0 = (v0 >> 2) | (v1 & 0xC0);
  210. int l1 = l0 + (v1 & 0x3F);
  211. l1 = astc::min(l1, 255);
  212. output0 = vint4(l0, l0, l0, 255);
  213. output1 = vint4(l1, l1, l1, 255);
  214. }
  215. /**
  216. * @brief Unpack an LDR LA color that uses direct encoding.
  217. *
  218. * @param input The packed endpoints (L0, L1, A0, A1).
  219. * @param[out] output0 The unpacked endpoint 0 color.
  220. * @param[out] output1 The unpacked endpoint 1 color.
  221. */
  222. static void luminance_alpha_unpack(
  223. const uint8_t input[4],
  224. vint4& output0,
  225. vint4& output1
  226. ) {
  227. int lum0 = input[0];
  228. int lum1 = input[1];
  229. int alpha0 = input[2];
  230. int alpha1 = input[3];
  231. output0 = vint4(lum0, lum0, lum0, alpha0);
  232. output1 = vint4(lum1, lum1, lum1, alpha1);
  233. }
  234. /**
  235. * @brief Unpack an LDR LA color that uses delta encoding.
  236. *
  237. * @param input The packed endpoints (L0, L1, A0, A1).
  238. * @param[out] output0 The unpacked endpoint 0 color.
  239. * @param[out] output1 The unpacked endpoint 1 color.
  240. */
  241. static void luminance_alpha_delta_unpack(
  242. const uint8_t input[4],
  243. vint4& output0,
  244. vint4& output1
  245. ) {
  246. int lum0 = input[0];
  247. int lum1 = input[1];
  248. int alpha0 = input[2];
  249. int alpha1 = input[3];
  250. lum0 |= (lum1 & 0x80) << 1;
  251. alpha0 |= (alpha1 & 0x80) << 1;
  252. lum1 &= 0x7F;
  253. alpha1 &= 0x7F;
  254. if (lum1 & 0x40)
  255. {
  256. lum1 -= 0x80;
  257. }
  258. if (alpha1 & 0x40)
  259. {
  260. alpha1 -= 0x80;
  261. }
  262. lum0 >>= 1;
  263. lum1 >>= 1;
  264. alpha0 >>= 1;
  265. alpha1 >>= 1;
  266. lum1 += lum0;
  267. alpha1 += alpha0;
  268. lum1 = astc::clamp(lum1, 0, 255);
  269. alpha1 = astc::clamp(alpha1, 0, 255);
  270. output0 = vint4(lum0, lum0, lum0, alpha0);
  271. output1 = vint4(lum1, lum1, lum1, alpha1);
  272. }
  273. /**
  274. * @brief Unpack an HDR RGB + offset encoding.
  275. *
  276. * @param input The packed endpoints (packed and modal).
  277. * @param[out] output0 The unpacked endpoint 0 color.
  278. * @param[out] output1 The unpacked endpoint 1 color.
  279. */
  280. static void hdr_rgbo_unpack(
  281. const uint8_t input[4],
  282. vint4& output0,
  283. vint4& output1
  284. ) {
  285. int v0 = input[0];
  286. int v1 = input[1];
  287. int v2 = input[2];
  288. int v3 = input[3];
  289. int modeval = ((v0 & 0xC0) >> 6) | (((v1 & 0x80) >> 7) << 2) | (((v2 & 0x80) >> 7) << 3);
  290. int majcomp;
  291. int mode;
  292. if ((modeval & 0xC) != 0xC)
  293. {
  294. majcomp = modeval >> 2;
  295. mode = modeval & 3;
  296. }
  297. else if (modeval != 0xF)
  298. {
  299. majcomp = modeval & 3;
  300. mode = 4;
  301. }
  302. else
  303. {
  304. majcomp = 0;
  305. mode = 5;
  306. }
  307. int red = v0 & 0x3F;
  308. int green = v1 & 0x1F;
  309. int blue = v2 & 0x1F;
  310. int scale = v3 & 0x1F;
  311. int bit0 = (v1 >> 6) & 1;
  312. int bit1 = (v1 >> 5) & 1;
  313. int bit2 = (v2 >> 6) & 1;
  314. int bit3 = (v2 >> 5) & 1;
  315. int bit4 = (v3 >> 7) & 1;
  316. int bit5 = (v3 >> 6) & 1;
  317. int bit6 = (v3 >> 5) & 1;
  318. int ohcomp = 1 << mode;
  319. if (ohcomp & 0x30)
  320. green |= bit0 << 6;
  321. if (ohcomp & 0x3A)
  322. green |= bit1 << 5;
  323. if (ohcomp & 0x30)
  324. blue |= bit2 << 6;
  325. if (ohcomp & 0x3A)
  326. blue |= bit3 << 5;
  327. if (ohcomp & 0x3D)
  328. scale |= bit6 << 5;
  329. if (ohcomp & 0x2D)
  330. scale |= bit5 << 6;
  331. if (ohcomp & 0x04)
  332. scale |= bit4 << 7;
  333. if (ohcomp & 0x3B)
  334. red |= bit4 << 6;
  335. if (ohcomp & 0x04)
  336. red |= bit3 << 6;
  337. if (ohcomp & 0x10)
  338. red |= bit5 << 7;
  339. if (ohcomp & 0x0F)
  340. red |= bit2 << 7;
  341. if (ohcomp & 0x05)
  342. red |= bit1 << 8;
  343. if (ohcomp & 0x0A)
  344. red |= bit0 << 8;
  345. if (ohcomp & 0x05)
  346. red |= bit0 << 9;
  347. if (ohcomp & 0x02)
  348. red |= bit6 << 9;
  349. if (ohcomp & 0x01)
  350. red |= bit3 << 10;
  351. if (ohcomp & 0x02)
  352. red |= bit5 << 10;
  353. // expand to 12 bits.
  354. static const int shamts[6] { 1, 1, 2, 3, 4, 5 };
  355. int shamt = shamts[mode];
  356. red <<= shamt;
  357. green <<= shamt;
  358. blue <<= shamt;
  359. scale <<= shamt;
  360. // on modes 0 to 4, the values stored for "green" and "blue" are differentials,
  361. // not absolute values.
  362. if (mode != 5)
  363. {
  364. green = red - green;
  365. blue = red - blue;
  366. }
  367. // switch around components.
  368. int temp;
  369. switch (majcomp)
  370. {
  371. case 1:
  372. temp = red;
  373. red = green;
  374. green = temp;
  375. break;
  376. case 2:
  377. temp = red;
  378. red = blue;
  379. blue = temp;
  380. break;
  381. default:
  382. break;
  383. }
  384. int red0 = red - scale;
  385. int green0 = green - scale;
  386. int blue0 = blue - scale;
  387. // clamp to [0,0xFFF].
  388. if (red < 0)
  389. red = 0;
  390. if (green < 0)
  391. green = 0;
  392. if (blue < 0)
  393. blue = 0;
  394. if (red0 < 0)
  395. red0 = 0;
  396. if (green0 < 0)
  397. green0 = 0;
  398. if (blue0 < 0)
  399. blue0 = 0;
  400. output0 = vint4(red0 << 4, green0 << 4, blue0 << 4, 0x7800);
  401. output1 = vint4(red << 4, green << 4, blue << 4, 0x7800);
  402. }
  403. /**
  404. * @brief Unpack an HDR RGB direct encoding.
  405. *
  406. * @param input The packed endpoints (packed and modal).
  407. * @param[out] output0 The unpacked endpoint 0 color.
  408. * @param[out] output1 The unpacked endpoint 1 color.
  409. */
  410. static void hdr_rgb_unpack(
  411. const uint8_t input[6],
  412. vint4& output0,
  413. vint4& output1
  414. ) {
  415. int v0 = input[0];
  416. int v1 = input[1];
  417. int v2 = input[2];
  418. int v3 = input[3];
  419. int v4 = input[4];
  420. int v5 = input[5];
  421. // extract all the fixed-placement bitfields
  422. int modeval = ((v1 & 0x80) >> 7) | (((v2 & 0x80) >> 7) << 1) | (((v3 & 0x80) >> 7) << 2);
  423. int majcomp = ((v4 & 0x80) >> 7) | (((v5 & 0x80) >> 7) << 1);
  424. if (majcomp == 3)
  425. {
  426. output0 = vint4(v0 << 8, v2 << 8, (v4 & 0x7F) << 9, 0x7800);
  427. output1 = vint4(v1 << 8, v3 << 8, (v5 & 0x7F) << 9, 0x7800);
  428. return;
  429. }
  430. int a = v0 | ((v1 & 0x40) << 2);
  431. int b0 = v2 & 0x3f;
  432. int b1 = v3 & 0x3f;
  433. int c = v1 & 0x3f;
  434. int d0 = v4 & 0x7f;
  435. int d1 = v5 & 0x7f;
  436. // get hold of the number of bits in 'd0' and 'd1'
  437. static const int dbits_tab[8] { 7, 6, 7, 6, 5, 6, 5, 6 };
  438. int dbits = dbits_tab[modeval];
  439. // extract six variable-placement bits
  440. int bit0 = (v2 >> 6) & 1;
  441. int bit1 = (v3 >> 6) & 1;
  442. int bit2 = (v4 >> 6) & 1;
  443. int bit3 = (v5 >> 6) & 1;
  444. int bit4 = (v4 >> 5) & 1;
  445. int bit5 = (v5 >> 5) & 1;
  446. // and prepend the variable-placement bits depending on mode.
  447. int ohmod = 1 << modeval; // one-hot-mode
  448. if (ohmod & 0xA4)
  449. a |= bit0 << 9;
  450. if (ohmod & 0x8)
  451. a |= bit2 << 9;
  452. if (ohmod & 0x50)
  453. a |= bit4 << 9;
  454. if (ohmod & 0x50)
  455. a |= bit5 << 10;
  456. if (ohmod & 0xA0)
  457. a |= bit1 << 10;
  458. if (ohmod & 0xC0)
  459. a |= bit2 << 11;
  460. if (ohmod & 0x4)
  461. c |= bit1 << 6;
  462. if (ohmod & 0xE8)
  463. c |= bit3 << 6;
  464. if (ohmod & 0x20)
  465. c |= bit2 << 7;
  466. if (ohmod & 0x5B)
  467. {
  468. b0 |= bit0 << 6;
  469. b1 |= bit1 << 6;
  470. }
  471. if (ohmod & 0x12)
  472. {
  473. b0 |= bit2 << 7;
  474. b1 |= bit3 << 7;
  475. }
  476. if (ohmod & 0xAF)
  477. {
  478. d0 |= bit4 << 5;
  479. d1 |= bit5 << 5;
  480. }
  481. if (ohmod & 0x5)
  482. {
  483. d0 |= bit2 << 6;
  484. d1 |= bit3 << 6;
  485. }
  486. // sign-extend 'd0' and 'd1'
  487. // note: this code assumes that signed right-shift actually sign-fills, not zero-fills.
  488. int32_t d0x = d0;
  489. int32_t d1x = d1;
  490. int sx_shamt = 32 - dbits;
  491. d0x <<= sx_shamt;
  492. d0x >>= sx_shamt;
  493. d1x <<= sx_shamt;
  494. d1x >>= sx_shamt;
  495. d0 = d0x;
  496. d1 = d1x;
  497. // expand all values to 12 bits, with left-shift as needed.
  498. int val_shamt = (modeval >> 1) ^ 3;
  499. a <<= val_shamt;
  500. b0 <<= val_shamt;
  501. b1 <<= val_shamt;
  502. c <<= val_shamt;
  503. d0 <<= val_shamt;
  504. d1 <<= val_shamt;
  505. // then compute the actual color values.
  506. int red1 = a;
  507. int green1 = a - b0;
  508. int blue1 = a - b1;
  509. int red0 = a - c;
  510. int green0 = a - b0 - c - d0;
  511. int blue0 = a - b1 - c - d1;
  512. // clamp the color components to [0,2^12 - 1]
  513. red0 = astc::clamp(red0, 0, 4095);
  514. green0 = astc::clamp(green0, 0, 4095);
  515. blue0 = astc::clamp(blue0, 0, 4095);
  516. red1 = astc::clamp(red1, 0, 4095);
  517. green1 = astc::clamp(green1, 0, 4095);
  518. blue1 = astc::clamp(blue1, 0, 4095);
  519. // switch around the color components
  520. int temp0, temp1;
  521. switch (majcomp)
  522. {
  523. case 1: // switch around red and green
  524. temp0 = red0;
  525. temp1 = red1;
  526. red0 = green0;
  527. red1 = green1;
  528. green0 = temp0;
  529. green1 = temp1;
  530. break;
  531. case 2: // switch around red and blue
  532. temp0 = red0;
  533. temp1 = red1;
  534. red0 = blue0;
  535. red1 = blue1;
  536. blue0 = temp0;
  537. blue1 = temp1;
  538. break;
  539. case 0: // no switch
  540. break;
  541. }
  542. output0 = vint4(red0 << 4, green0 << 4, blue0 << 4, 0x7800);
  543. output1 = vint4(red1 << 4, green1 << 4, blue1 << 4, 0x7800);
  544. }
  545. /**
  546. * @brief Unpack an HDR RGB + LDR A direct encoding.
  547. *
  548. * @param input The packed endpoints (packed and modal).
  549. * @param[out] output0 The unpacked endpoint 0 color.
  550. * @param[out] output1 The unpacked endpoint 1 color.
  551. */
  552. static void hdr_rgb_ldr_alpha_unpack(
  553. const uint8_t input[8],
  554. vint4& output0,
  555. vint4& output1
  556. ) {
  557. hdr_rgb_unpack(input, output0, output1);
  558. int v6 = input[6];
  559. int v7 = input[7];
  560. output0.set_lane<3>(v6);
  561. output1.set_lane<3>(v7);
  562. }
  563. /**
  564. * @brief Unpack an HDR L (small range) direct encoding.
  565. *
  566. * @param input The packed endpoints (packed and modal).
  567. * @param[out] output0 The unpacked endpoint 0 color.
  568. * @param[out] output1 The unpacked endpoint 1 color.
  569. */
  570. static void hdr_luminance_small_range_unpack(
  571. const uint8_t input[2],
  572. vint4& output0,
  573. vint4& output1
  574. ) {
  575. int v0 = input[0];
  576. int v1 = input[1];
  577. int y0, y1;
  578. if (v0 & 0x80)
  579. {
  580. y0 = ((v1 & 0xE0) << 4) | ((v0 & 0x7F) << 2);
  581. y1 = (v1 & 0x1F) << 2;
  582. }
  583. else
  584. {
  585. y0 = ((v1 & 0xF0) << 4) | ((v0 & 0x7F) << 1);
  586. y1 = (v1 & 0xF) << 1;
  587. }
  588. y1 += y0;
  589. if (y1 > 0xFFF)
  590. {
  591. y1 = 0xFFF;
  592. }
  593. output0 = vint4(y0 << 4, y0 << 4, y0 << 4, 0x7800);
  594. output1 = vint4(y1 << 4, y1 << 4, y1 << 4, 0x7800);
  595. }
  596. /**
  597. * @brief Unpack an HDR L (large range) direct encoding.
  598. *
  599. * @param input The packed endpoints (packed and modal).
  600. * @param[out] output0 The unpacked endpoint 0 color.
  601. * @param[out] output1 The unpacked endpoint 1 color.
  602. */
  603. static void hdr_luminance_large_range_unpack(
  604. const uint8_t input[2],
  605. vint4& output0,
  606. vint4& output1
  607. ) {
  608. int v0 = input[0];
  609. int v1 = input[1];
  610. int y0, y1;
  611. if (v1 >= v0)
  612. {
  613. y0 = v0 << 4;
  614. y1 = v1 << 4;
  615. }
  616. else
  617. {
  618. y0 = (v1 << 4) + 8;
  619. y1 = (v0 << 4) - 8;
  620. }
  621. output0 = vint4(y0 << 4, y0 << 4, y0 << 4, 0x7800);
  622. output1 = vint4(y1 << 4, y1 << 4, y1 << 4, 0x7800);
  623. }
  624. /**
  625. * @brief Unpack an HDR A direct encoding.
  626. *
  627. * @param input The packed endpoints (packed and modal).
  628. * @param[out] output0 The unpacked endpoint 0 color.
  629. * @param[out] output1 The unpacked endpoint 1 color.
  630. */
  631. static void hdr_alpha_unpack(
  632. const uint8_t input[2],
  633. int& output0,
  634. int& output1
  635. ) {
  636. int v6 = input[0];
  637. int v7 = input[1];
  638. int selector = ((v6 >> 7) & 1) | ((v7 >> 6) & 2);
  639. v6 &= 0x7F;
  640. v7 &= 0x7F;
  641. if (selector == 3)
  642. {
  643. output0 = v6 << 5;
  644. output1 = v7 << 5;
  645. }
  646. else
  647. {
  648. v6 |= (v7 << (selector + 1)) & 0x780;
  649. v7 &= (0x3f >> selector);
  650. v7 ^= 32 >> selector;
  651. v7 -= 32 >> selector;
  652. v6 <<= (4 - selector);
  653. v7 <<= (4 - selector);
  654. v7 += v6;
  655. if (v7 < 0)
  656. {
  657. v7 = 0;
  658. }
  659. else if (v7 > 0xFFF)
  660. {
  661. v7 = 0xFFF;
  662. }
  663. output0 = v6;
  664. output1 = v7;
  665. }
  666. output0 <<= 4;
  667. output1 <<= 4;
  668. }
  669. /**
  670. * @brief Unpack an HDR RGBA direct encoding.
  671. *
  672. * @param input The packed endpoints (packed and modal).
  673. * @param[out] output0 The unpacked endpoint 0 color.
  674. * @param[out] output1 The unpacked endpoint 1 color.
  675. */
  676. static void hdr_rgb_hdr_alpha_unpack(
  677. const uint8_t input[8],
  678. vint4& output0,
  679. vint4& output1
  680. ) {
  681. hdr_rgb_unpack(input, output0, output1);
  682. int alpha0, alpha1;
  683. hdr_alpha_unpack(input + 6, alpha0, alpha1);
  684. output0.set_lane<3>(alpha0);
  685. output1.set_lane<3>(alpha1);
  686. }
  687. /* See header for documentation. */
  688. void unpack_color_endpoints(
  689. astcenc_profile decode_mode,
  690. int format,
  691. const uint8_t* input,
  692. bool& rgb_hdr,
  693. bool& alpha_hdr,
  694. vint4& output0,
  695. vint4& output1
  696. ) {
  697. // Assume no NaNs and LDR endpoints unless set later
  698. rgb_hdr = false;
  699. alpha_hdr = false;
  700. bool alpha_hdr_default = false;
  701. switch (format)
  702. {
  703. case FMT_LUMINANCE:
  704. luminance_unpack(input, output0, output1);
  705. break;
  706. case FMT_LUMINANCE_DELTA:
  707. luminance_delta_unpack(input, output0, output1);
  708. break;
  709. case FMT_HDR_LUMINANCE_SMALL_RANGE:
  710. rgb_hdr = true;
  711. alpha_hdr_default = true;
  712. hdr_luminance_small_range_unpack(input, output0, output1);
  713. break;
  714. case FMT_HDR_LUMINANCE_LARGE_RANGE:
  715. rgb_hdr = true;
  716. alpha_hdr_default = true;
  717. hdr_luminance_large_range_unpack(input, output0, output1);
  718. break;
  719. case FMT_LUMINANCE_ALPHA:
  720. luminance_alpha_unpack(input, output0, output1);
  721. break;
  722. case FMT_LUMINANCE_ALPHA_DELTA:
  723. luminance_alpha_delta_unpack(input, output0, output1);
  724. break;
  725. case FMT_RGB_SCALE:
  726. {
  727. vint4 input0q(input[0], input[1], input[2], 0);
  728. uint8_t scale = input[3];
  729. rgb_scale_unpack(input0q, scale, output0, output1);
  730. }
  731. break;
  732. case FMT_RGB_SCALE_ALPHA:
  733. {
  734. vint4 input0q(input[0], input[1], input[2], input[4]);
  735. uint8_t alpha1q = input[5];
  736. uint8_t scaleq = input[3];
  737. rgb_scale_alpha_unpack(input0q, alpha1q, scaleq, output0, output1);
  738. }
  739. break;
  740. case FMT_HDR_RGB_SCALE:
  741. rgb_hdr = true;
  742. alpha_hdr_default = true;
  743. hdr_rgbo_unpack(input, output0, output1);
  744. break;
  745. case FMT_RGB:
  746. {
  747. vint4 input0q(input[0], input[2], input[4], 0);
  748. vint4 input1q(input[1], input[3], input[5], 0);
  749. rgb_unpack(input0q, input1q, output0, output1);
  750. }
  751. break;
  752. case FMT_RGB_DELTA:
  753. {
  754. vint4 input0q(input[0], input[2], input[4], 0);
  755. vint4 input1q(input[1], input[3], input[5], 0);
  756. rgb_delta_unpack(input0q, input1q, output0, output1);
  757. }
  758. break;
  759. case FMT_HDR_RGB:
  760. rgb_hdr = true;
  761. alpha_hdr_default = true;
  762. hdr_rgb_unpack(input, output0, output1);
  763. break;
  764. case FMT_RGBA:
  765. {
  766. vint4 input0q(input[0], input[2], input[4], input[6]);
  767. vint4 input1q(input[1], input[3], input[5], input[7]);
  768. rgba_unpack(input0q, input1q, output0, output1);
  769. }
  770. break;
  771. case FMT_RGBA_DELTA:
  772. {
  773. vint4 input0q(input[0], input[2], input[4], input[6]);
  774. vint4 input1q(input[1], input[3], input[5], input[7]);
  775. rgba_delta_unpack(input0q, input1q, output0, output1);
  776. }
  777. break;
  778. case FMT_HDR_RGB_LDR_ALPHA:
  779. rgb_hdr = true;
  780. hdr_rgb_ldr_alpha_unpack(input, output0, output1);
  781. break;
  782. case FMT_HDR_RGBA:
  783. rgb_hdr = true;
  784. alpha_hdr = true;
  785. hdr_rgb_hdr_alpha_unpack(input, output0, output1);
  786. break;
  787. }
  788. // Assign a correct default alpha
  789. if (alpha_hdr_default)
  790. {
  791. if (decode_mode == ASTCENC_PRF_HDR)
  792. {
  793. output0.set_lane<3>(0x7800);
  794. output1.set_lane<3>(0x7800);
  795. alpha_hdr = true;
  796. }
  797. else
  798. {
  799. output0.set_lane<3>(0x00FF);
  800. output1.set_lane<3>(0x00FF);
  801. alpha_hdr = false;
  802. }
  803. }
  804. vint4 ldr_scale(257);
  805. vint4 hdr_scale(1);
  806. vint4 output_scale = ldr_scale;
  807. // An LDR profile image
  808. if ((decode_mode == ASTCENC_PRF_LDR) ||
  809. (decode_mode == ASTCENC_PRF_LDR_SRGB))
  810. {
  811. // Also matches HDR alpha, as cannot have HDR alpha without HDR RGB
  812. if (rgb_hdr == true)
  813. {
  814. output0 = vint4(0xFF00, 0x0000, 0xFF00, 0xFF00);
  815. output1 = vint4(0xFF00, 0x0000, 0xFF00, 0xFF00);
  816. output_scale = hdr_scale;
  817. rgb_hdr = false;
  818. alpha_hdr = false;
  819. }
  820. }
  821. // An HDR profile image
  822. else
  823. {
  824. vmask4 hdr_lanes(rgb_hdr, rgb_hdr, rgb_hdr, alpha_hdr);
  825. output_scale = select(ldr_scale, hdr_scale, hdr_lanes);
  826. }
  827. output0 = output0 * output_scale;
  828. output1 = output1 * output_scale;
  829. }