3
0

CryTextureSquisher.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <ImageProcessing_Traits_Platform.h>
  9. #include "ColorBlockRGBA4x4c.h"
  10. #include "ColorBlockRGBA4x4s.h"
  11. #include "ColorBlockRGBA4x4f.h"
  12. #include "CryTextureSquisher.h"
  13. #include <AzCore/std/parallel/mutex.h>
  14. #if defined(__clang__)
  15. # pragma clang diagnostic push
  16. # pragma clang diagnostic ignored "-Wnull-dereference"
  17. # pragma clang diagnostic ignored "-Wsometimes-uninitialized"
  18. # pragma clang diagnostic ignored "-Wshift-negative-value"
  19. #endif
  20. #if AZ_TRAIT_IMAGEPROCESSING_SQUISH_DO_NOT_USE_FASTCALL
  21. #define __fastcall
  22. #define _fastcall
  23. #define __assume(x)
  24. #endif
  25. #include <squish-ccr/squish.h>
  26. #if defined(__clang__)
  27. # pragma clang diagnostic pop
  28. #endif
  29. // number of bytes per block per type
  30. #define BLOCKSIZE_BC1 8
  31. #define BLOCKSIZE_BC2 16
  32. #define BLOCKSIZE_BC3 16
  33. #define BLOCKSIZE_BC4 8
  34. #define BLOCKSIZE_BC5 16
  35. #define BLOCKSIZE_BC6 16
  36. #define BLOCKSIZE_BC7 16
  37. #define BLOCKSIZE_CTX1 8
  38. #define BLOCKSIZE_LIMIT 16
  39. #define PTROFFSET_R 0
  40. #define PTROFFSET_G 1
  41. #define PTROFFSET_B 2
  42. #define PTROFFSET_A 3
  43. namespace ImageProcessingAtom
  44. {
  45. AZStd::mutex s_squishLock;
  46. /* -------------------------------------------------------------------------------------------------------------
  47. * internal presets
  48. */
  49. static struct ParameterMatrix
  50. {
  51. int flagsBaseline;
  52. int flagsUniform;
  53. int flagsPerceptual;
  54. int flagsQuality[CryTextureSquisher::EQualityProfile::eQualityProfile_Num];
  55. size_t offset;
  56. bool alphaOnly;
  57. } P2P[] =
  58. {
  59. // eCompressorPreset_BC1U,
  60. {
  61. squish::kBtc1 + squish::kExcludeAlphaFromPalette,
  62. squish::kColourMetricUniform,
  63. squish::kColourMetricPerceptual,
  64. { squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit, squish::kColourIterativeClusterFit },
  65. 0, false
  66. },
  67. // eCompressorPreset_BC2U,
  68. {
  69. squish::kBtc2,
  70. squish::kColourMetricUniform,
  71. squish::kColourMetricPerceptual,
  72. { squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit, squish::kColourIterativeClusterFit },
  73. 0, false
  74. },
  75. // eCompressorPreset_BC3U,
  76. {
  77. squish::kBtc3,
  78. squish::kColourMetricUniform,
  79. squish::kColourMetricPerceptual,
  80. { squish::kColourRangeFit, squish::kColourClusterFit + squish::kAlphaIterativeFit, squish::kColourIterativeClusterFit + squish::kAlphaIterativeFit, squish::kColourIterativeClusterFit + squish::kAlphaIterativeFit },
  81. 0, false
  82. },
  83. // eCompressorPreset_BC4U,
  84. {
  85. squish::kBtc4,
  86. squish::kColourMetricUniform,
  87. squish::kColourMetricUniform,
  88. { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
  89. PTROFFSET_R, false
  90. },
  91. // eCompressorPreset_BC5U,
  92. {
  93. squish::kBtc5,
  94. squish::kColourMetricUniform,
  95. squish::kColourMetricPerceptual,
  96. { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
  97. PTROFFSET_R, false
  98. },
  99. // eCompressorPreset_BC6UH,
  100. {
  101. squish::kBtc6,
  102. squish::kColourMetricUniform,
  103. squish::kColourMetricPerceptual,
  104. { squish::kColourRangeFit, squish::kColourRangeFit, squish::kColourRangeFit, squish::kColourRangeFit },
  105. 0, false
  106. },
  107. // eCompressorPreset_BC7U,
  108. {
  109. squish::kBtc7,
  110. squish::kColourMetricUniform,
  111. squish::kColourMetricPerceptual,
  112. { squish::kColourRangeFit, squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit },
  113. 0, false
  114. },
  115. // eCompressorPreset_BC4S,
  116. {
  117. squish::kBtc4 + squish::kSignedInternal,
  118. squish::kColourMetricUniform,
  119. squish::kColourMetricUniform,
  120. { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
  121. PTROFFSET_R, false
  122. },
  123. // eCompressorPreset_BC5S,
  124. {
  125. squish::kBtc5 + squish::kSignedInternal,
  126. squish::kColourMetricUniform,
  127. squish::kColourMetricPerceptual,
  128. { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
  129. PTROFFSET_R, false
  130. },
  131. // eCompressorPreset_BC1Un,
  132. {
  133. squish::kBtc1 + squish::kExcludeAlphaFromPalette,
  134. squish::kColourMetricUnit,
  135. squish::kColourMetricUnit,
  136. { squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit },
  137. 0, false
  138. },
  139. // eCompressorPreset_BC2Un,
  140. {
  141. squish::kBtc2,
  142. squish::kColourMetricUnit,
  143. squish::kColourMetricUnit,
  144. { squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit },
  145. 0, false
  146. },
  147. // eCompressorPreset_BC3Un,
  148. {
  149. squish::kBtc3,
  150. squish::kColourMetricUnit,
  151. squish::kColourMetricUnit,
  152. { squish::kNormalRangeFit, squish::kNormalRangeFit + squish::kAlphaIterativeFit, squish::kNormalRangeFit + squish::kAlphaIterativeFit, squish::kNormalRangeFit + squish::kAlphaIterativeFit },
  153. 0, false
  154. },
  155. // eCompressorPreset_BC4Un,
  156. {
  157. squish::kBtc4,
  158. squish::kColourMetricUniform,
  159. squish::kColourMetricUniform,
  160. { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
  161. PTROFFSET_B, false
  162. },
  163. // eCompressorPreset_BC5Un,
  164. {
  165. squish::kBtc5,
  166. squish::kColourMetricUnit,
  167. squish::kColourMetricUnit,
  168. { 0, 0, squish::kNormalIterativeFit, squish::kNormalIterativeFit },
  169. PTROFFSET_R, false
  170. },
  171. // eCompressorPreset_BC6UHn,
  172. {
  173. squish::kBtc6,
  174. squish::kColourMetricUnit,
  175. squish::kColourMetricUnit,
  176. { squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit },
  177. 0, false
  178. },
  179. // eCompressorPreset_BC7Un,
  180. {
  181. squish::kBtc7,
  182. squish::kColourMetricUnit,
  183. squish::kColourMetricUnit,
  184. { squish::kColourRangeFit, squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit },
  185. 0, false
  186. },
  187. // eCompressorPreset_BC4Sn,
  188. {
  189. squish::kBtc4 + squish::kSignedInternal,
  190. squish::kColourMetricUniform,
  191. squish::kColourMetricUniform,
  192. { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
  193. PTROFFSET_B, false
  194. },
  195. // eCompressorPreset_BC5Sn,
  196. {
  197. squish::kBtc5 + squish::kSignedInternal,
  198. squish::kColourMetricUnit,
  199. squish::kColourMetricUnit,
  200. { 0, 0, squish::kNormalIterativeFit, squish::kNormalIterativeFit },
  201. PTROFFSET_R, false
  202. },
  203. // eCompressorPreset_BC1Ua,
  204. {
  205. squish::kBtc1 + squish::kWeightColourByAlpha,
  206. squish::kColourMetricUniform,
  207. squish::kColourMetricPerceptual,
  208. { squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit, squish::kColourIterativeClusterFit },
  209. 0, false
  210. },
  211. // eCompressorPreset_BC2Ut,
  212. {
  213. squish::kBtc2 + squish::kWeightColourByAlpha,
  214. squish::kColourMetricUniform,
  215. squish::kColourMetricPerceptual,
  216. { squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit, squish::kColourIterativeClusterFit },
  217. 0, false
  218. },
  219. // eCompressorPreset_BC3Ut,
  220. {
  221. squish::kBtc3 + squish::kWeightColourByAlpha,
  222. squish::kColourMetricUniform,
  223. squish::kColourMetricPerceptual,
  224. { squish::kColourRangeFit, squish::kColourClusterFit + squish::kAlphaIterativeFit, squish::kColourIterativeClusterFit + squish::kAlphaIterativeFit, squish::kColourIterativeClusterFit + squish::kAlphaIterativeFit },
  225. 0, false
  226. },
  227. // eCompressorPreset_BC4Ua,
  228. {
  229. squish::kBtc4,
  230. squish::kColourMetricUniform,
  231. squish::kColourMetricUniform,
  232. { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
  233. PTROFFSET_A, true
  234. },
  235. // eCompressorPreset_BC7Ut
  236. {
  237. squish::kBtc7 + squish::kWeightColourByAlpha,
  238. squish::kColourMetricUniform,
  239. squish::kColourMetricPerceptual,
  240. { squish::kColourRangeFit, squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit },
  241. 0, false
  242. },
  243. // eCompressorPreset_BC4Sa,
  244. {
  245. squish::kBtc4 + squish::kSignedInternal,
  246. squish::kColourMetricUniform,
  247. squish::kColourMetricUniform,
  248. { 0, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit, squish::kAlphaIterativeFit },
  249. PTROFFSET_A, true
  250. },
  251. // eCompressorPreset_BC7Ug
  252. {
  253. squish::kBtc7,
  254. squish::kColourMetricUniform,
  255. squish::kColourMetricUniform,
  256. { squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourClusterFit * 15, squish::kColourClusterFit * 15 },
  257. 0, false
  258. },
  259. // eCompressorPreset_CTX1U
  260. {
  261. squish::kCtx1,
  262. squish::kColourMetricUniform,
  263. squish::kColourMetricUniform,
  264. { squish::kColourRangeFit, squish::kColourClusterFit, squish::kColourIterativeClusterFit, squish::kColourIterativeClusterFit },
  265. 0, false
  266. },
  267. // eCompressorPreset_CTX1Un
  268. {
  269. squish::kCtx1,
  270. squish::kColourMetricUnit,
  271. squish::kColourMetricUnit,
  272. { squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit, squish::kNormalRangeFit },
  273. 0, false
  274. },
  275. };
  276. /* -------------------------------------------------------------------------------------------------------------
  277. * compression functions
  278. */
  279. void CryTextureSquisher::Compress(const CryTextureSquisher::CompressorParameters& compress)
  280. {
  281. const unsigned int w = compress.width;
  282. const unsigned int h = compress.height;
  283. const size_t offset = P2P[compress.preset].offset;
  284. int flags = P2P[compress.preset].flagsBaseline + P2P[compress.preset].flagsQuality[compress.quality] +
  285. (!compress.perceptual ? P2P[compress.preset].flagsUniform : P2P[compress.preset].flagsPerceptual);
  286. const bool bAlphaOnly = P2P[compress.preset].alphaOnly;
  287. squish::sqio::dtp datatype;
  288. switch (compress.srcType)
  289. {
  290. case eBufferType_sint8:
  291. flags += squish::kSignedExternal;
  292. case eBufferType_uint8:
  293. datatype = squish::sqio::dtp::DT_U8;
  294. break;
  295. case eBufferType_sint16:
  296. flags += squish::kSignedExternal;
  297. case eBufferType_uint16:
  298. datatype = squish::sqio::dtp::DT_U16;
  299. break;
  300. case eBufferType_sfloat:
  301. flags += squish::kSignedExternal;
  302. case eBufferType_ufloat:
  303. datatype = squish::sqio::dtp::DT_F23;
  304. break;
  305. default:
  306. __assume(0);
  307. break;
  308. }
  309. if (compress.perceptual && (flags & squish::kColourMetricPerceptual))
  310. {
  311. flags |= squish::kColourMetricCustom;
  312. }
  313. const struct squish::sqio sqio = squish::GetSquishIO(w, h, datatype, flags);
  314. if (compress.perceptual && (flags & squish::kColourMetricPerceptual))
  315. {
  316. s_squishLock.lock();
  317. }
  318. if (compress.perceptual && (flags & squish::kColourMetricPerceptual))
  319. {
  320. squish::SetWeights(sqio.flags, &compress.weights[0]);
  321. }
  322. AZ_Assert(!(h & 3), "%s: Unexpected compress parameter of height", __FUNCTION__);
  323. switch (compress.srcType)
  324. {
  325. // compress an unsigned 8bit texture --------------------------------------------------
  326. // compress a signed 8bit texture -----------------------------------------------------
  327. case eBufferType_uint8:
  328. case eBufferType_sint8:
  329. {
  330. for (unsigned int y = 0U; y < h; y += 4U)
  331. {
  332. ColorBlockRGBA4x4c srcBlock;
  333. uint8 dstBlock[BLOCKSIZE_LIMIT];
  334. uint8* const targetBlock = dstBlock;
  335. const uint8* const sourceRgba = (const uint8*)srcBlock.colors() + offset;
  336. for (unsigned int x = 0U; x < w; x += 4U)
  337. {
  338. if (!bAlphaOnly)
  339. {
  340. srcBlock.setRGBA8(compress.srcBuffer, w, h, compress.pitch, x, y);
  341. }
  342. else
  343. {
  344. srcBlock.setA8(compress.srcBuffer, w, h, compress.pitch, x, y);
  345. }
  346. sqio.encoder(sourceRgba, 0xFFFF, targetBlock, sqio.flags);
  347. if (compress.userOutputFunction)
  348. {
  349. compress.userOutputFunction(compress, targetBlock, sqio.blocksize, y >> 2, x >> 2);
  350. }
  351. }
  352. }
  353. }
  354. break;
  355. // compress an unsigned 16bit texture -------------------------------------------------
  356. // compress a signed 16bit texture ----------------------------------------------------
  357. case eBufferType_uint16:
  358. case eBufferType_sint16:
  359. {
  360. for (unsigned int y = 0U; y < h; y += 4U)
  361. {
  362. ColorBlockRGBA4x4s srcBlock;
  363. uint8 dstBlock[BLOCKSIZE_LIMIT];
  364. uint8* const targetBlock = dstBlock;
  365. const float* const sourceRgba = (const float*)srcBlock.colors() + offset;
  366. for (unsigned int x = 0U; x < w; x += 4U)
  367. {
  368. if (!bAlphaOnly)
  369. {
  370. srcBlock.setRGBA16(compress.srcBuffer, w, h, compress.pitch, x, y);
  371. }
  372. else
  373. {
  374. srcBlock.setA16(compress.srcBuffer, w, h, compress.pitch, x, y);
  375. }
  376. sqio.encoder(sourceRgba, 0xFFFF, targetBlock, sqio.flags);
  377. if (compress.userOutputFunction)
  378. {
  379. compress.userOutputFunction(compress, targetBlock, sqio.blocksize, y >> 2, x >> 2);
  380. }
  381. }
  382. }
  383. }
  384. break;
  385. // compress an unsigned floating point texture ----------------------------------------
  386. // compress a signed floating point texture -------------------------------------------
  387. case eBufferType_ufloat:
  388. case eBufferType_sfloat:
  389. {
  390. for (unsigned int y = 0U; y < h; y += 4U)
  391. {
  392. ColorBlockRGBA4x4f srcBlock;
  393. uint8 dstBlock[BLOCKSIZE_LIMIT];
  394. uint8* const targetBlock = dstBlock;
  395. const float* const sourceRgba = (const float*)srcBlock.colors() + offset;
  396. for (unsigned int x = 0U; x < w; x += 4U)
  397. {
  398. if (!bAlphaOnly)
  399. {
  400. srcBlock.setRGBAf(compress.srcBuffer, w, h, compress.pitch, x, y);
  401. }
  402. else
  403. {
  404. srcBlock.setAf(compress.srcBuffer, w, h, compress.pitch, x, y);
  405. }
  406. sqio.encoder(sourceRgba, 0xFFFF, targetBlock, sqio.flags);
  407. if (compress.userOutputFunction)
  408. {
  409. compress.userOutputFunction(compress, targetBlock, sqio.blocksize, y >> 2, x >> 2);
  410. }
  411. }
  412. }
  413. }
  414. break;
  415. default:
  416. AZ_Assert(false, "%s: Unexpected compress source type", __FUNCTION__);
  417. break;
  418. }
  419. if (compress.perceptual && (flags & squish::kColourMetricPerceptual))
  420. {
  421. s_squishLock.unlock();
  422. }
  423. }
  424. void CryTextureSquisher::Decompress(const DecompressorParameters& decompress)
  425. {
  426. const unsigned int w = decompress.width;
  427. const unsigned int h = decompress.height;
  428. const size_t offset = P2P[decompress.preset].offset;
  429. int flags = P2P[decompress.preset].flagsBaseline +
  430. P2P[decompress.preset].flagsUniform;
  431. const bool bAlphaOnly = P2P[decompress.preset].alphaOnly;
  432. squish::sqio::dtp datatype;
  433. switch (decompress.dstType)
  434. {
  435. case eBufferType_sint8:
  436. flags += squish::kSignedExternal;
  437. case eBufferType_uint8:
  438. datatype = squish::sqio::dtp::DT_U8;
  439. break;
  440. case eBufferType_sint16:
  441. flags += squish::kSignedExternal;
  442. case eBufferType_uint16:
  443. datatype = squish::sqio::dtp::DT_U16;
  444. break;
  445. case eBufferType_sfloat:
  446. flags += squish::kSignedExternal;
  447. case eBufferType_ufloat:
  448. datatype = squish::sqio::dtp::DT_F23;
  449. break;
  450. default:
  451. __assume(0);
  452. break;
  453. }
  454. const struct squish::sqio sqio = squish::GetSquishIO(w, h, datatype, flags);
  455. AZ_Assert(!(h & 3), "%s: Unexpected compress parameter of height", __FUNCTION__);
  456. switch (decompress.dstType)
  457. {
  458. // decompress an unsigned 8bit texture --------------------------------------------------
  459. // decompress a signed 8bit texture -----------------------------------------------------
  460. case eBufferType_uint8:
  461. case eBufferType_sint8:
  462. {
  463. for (unsigned int y = 0U; y < h; y += 4U)
  464. {
  465. uint8 srcBlock[BLOCKSIZE_LIMIT];
  466. ColorBlockRGBA4x4c dstBlock;
  467. uint8* const sourceBlock = srcBlock;
  468. uint8* const targetRgba = (uint8*)dstBlock.colors() + offset;
  469. for (unsigned int x = 0U; x < w; x += 4U)
  470. {
  471. if (decompress.userInputFunction)
  472. {
  473. decompress.userInputFunction(decompress, sourceBlock, sqio.blocksize, y >> 2, x >> 2);
  474. }
  475. if (!bAlphaOnly)
  476. {
  477. dstBlock.setRGBA8(decompress.dstBuffer, w, h, decompress.pitch, x, y);
  478. }
  479. sqio.decoder(targetRgba, sourceBlock, sqio.flags);
  480. if (!bAlphaOnly)
  481. {
  482. dstBlock.getRGBA8(decompress.dstBuffer, w, h, decompress.pitch, x, y);
  483. }
  484. else
  485. {
  486. dstBlock.getA8(decompress.dstBuffer, w, h, decompress.pitch, x, y);
  487. }
  488. }
  489. }
  490. }
  491. break;
  492. // decompress an unsigned 16bit texture -------------------------------------------------
  493. // decompress a signed 16bit texture ----------------------------------------------------
  494. case eBufferType_uint16:
  495. case eBufferType_sint16:
  496. {
  497. for (unsigned int y = 0U; y < h; y += 4U)
  498. {
  499. uint8 srcBlock[BLOCKSIZE_LIMIT];
  500. ColorBlockRGBA4x4s dstBlock;
  501. uint8* const sourceBlock = srcBlock;
  502. uint16* const targetRgba = (uint16*)dstBlock.colors() + offset;
  503. for (unsigned int x = 0U; x < w; x += 4U)
  504. {
  505. if (decompress.userInputFunction)
  506. {
  507. decompress.userInputFunction(decompress, sourceBlock, sqio.blocksize, y >> 2, x >> 2);
  508. }
  509. if (!bAlphaOnly)
  510. {
  511. dstBlock.setRGBA16(decompress.dstBuffer, w, h, decompress.pitch, x, y);
  512. }
  513. sqio.decoder(targetRgba, sourceBlock, sqio.flags);
  514. if (!bAlphaOnly)
  515. {
  516. dstBlock.setRGBA16(decompress.dstBuffer, w, h, decompress.pitch, x, y);
  517. }
  518. else
  519. {
  520. dstBlock.getA16(decompress.dstBuffer, w, h, decompress.pitch, x, y);
  521. }
  522. }
  523. }
  524. }
  525. break;
  526. // decompress an unsigned floating point texture ----------------------------------------
  527. // decompress a signed floating point texture -------------------------------------------
  528. case eBufferType_ufloat:
  529. case eBufferType_sfloat:
  530. {
  531. for (unsigned int y = 0U; y < h; y += 4U)
  532. {
  533. uint8 srcBlock[BLOCKSIZE_LIMIT];
  534. ColorBlockRGBA4x4f dstBlock;
  535. uint8* const sourceBlock = srcBlock;
  536. float* const targetRgba = (float*)dstBlock.colors() + offset;
  537. for (unsigned int x = 0U; x < w; x += 4U)
  538. {
  539. if (decompress.userInputFunction)
  540. {
  541. decompress.userInputFunction(decompress, sourceBlock, sqio.blocksize, y >> 2, x >> 2);
  542. }
  543. if (!bAlphaOnly)
  544. {
  545. dstBlock.setRGBAf(decompress.dstBuffer, w, h, decompress.pitch, x, y);
  546. }
  547. sqio.decoder(targetRgba, sourceBlock, sqio.flags);
  548. if (!bAlphaOnly)
  549. {
  550. dstBlock.getRGBAf(decompress.dstBuffer, w, h, decompress.pitch, x, y);
  551. }
  552. else
  553. {
  554. dstBlock.getAf(decompress.dstBuffer, w, h, decompress.pitch, x, y);
  555. }
  556. }
  557. }
  558. }
  559. break;
  560. default:
  561. AZ_Assert(false, "%s: Unexpected compress destination type", __FUNCTION__);
  562. break;
  563. }
  564. }
  565. } // namespace ImageProcessingAtom