basis_transcode.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. /* -*- tab-width: 4; -*- */
  2. /* vi: set sw=2 ts=4 expandtab: */
  3. /*
  4. * Copyright 2019-2020 The Khronos Group Inc.
  5. * SPDX-License-Identifier: Apache-2.0
  6. */
  7. /**
  8. * @internal
  9. * @file basis_transcode.cpp
  10. * @~English
  11. *
  12. * @brief Functions for transcoding Basis Universal BasisLZ/ETC1S and UASTC textures.
  13. *
  14. * Two worlds collide here too. More uglyness!
  15. *
  16. * @author Mark Callow, www.edgewise-consulting.com
  17. */
  18. #include <inttypes.h>
  19. #include <stdio.h>
  20. #include <KHR/khr_df.h>
  21. #include "dfdutils/dfd.h"
  22. #include "ktx.h"
  23. #include "ktxint.h"
  24. #include "texture2.h"
  25. #include "vkformat_enum.h"
  26. #include "vk_format.h"
  27. #include "basis_sgd.h"
  28. #include "transcoder/basisu_file_headers.h"
  29. #include "transcoder/basisu_transcoder.h"
  30. #include "transcoder/basisu_transcoder_internal.h"
  31. #undef DECLARE_PRIVATE
  32. #undef DECLARE_PROTECTED
  33. #define DECLARE_PRIVATE(n,t2) ktxTexture2_private& n = *(t2->_private)
  34. #define DECLARE_PROTECTED(n,t2) ktxTexture_protected& n = *(t2->_protected)
  35. using namespace basisu;
  36. using namespace basist;
  37. inline bool isPow2(uint32_t x) { return x && ((x & (x - 1U)) == 0U); }
  38. inline bool isPow2(uint64_t x) { return x && ((x & (x - 1U)) == 0U); }
  39. KTX_error_code
  40. ktxTexture2_transcodeLzEtc1s(ktxTexture2* This,
  41. alpha_content_e alphaContent,
  42. ktxTexture2* prototype,
  43. ktx_transcode_fmt_e outputFormat,
  44. ktx_transcode_flags transcodeFlags);
  45. KTX_error_code
  46. ktxTexture2_transcodeUastc(ktxTexture2* This,
  47. alpha_content_e alphaContent,
  48. ktxTexture2* prototype,
  49. ktx_transcode_fmt_e outputFormat,
  50. ktx_transcode_flags transcodeFlags);
  51. /**
  52. * @memberof ktxTexture2
  53. * @ingroup reader
  54. * @~English
  55. * @brief Transcode a KTX2 texture with BasisLZ/ETC1S or UASTC images.
  56. *
  57. * If the texture contains BasisLZ supercompressed images, Inflates them from
  58. * back to ETC1S then transcodes them to the specified block-compressed
  59. * format. If the texture contains UASTC images, inflates them, if they have been
  60. * supercompressed with zstd, then transcodes then to the specified format, The
  61. * transcoded images replace the original images and the texture's fields including
  62. * the DFD are modified to reflect the new format.
  63. *
  64. * These types of textures must be transcoded to a desired target
  65. * block-compressed format before they can be uploaded to a GPU via a
  66. * graphics API.
  67. *
  68. * The following block compressed transcode targets are available: @c KTX_TTF_ETC1_RGB,
  69. * @c KTX_TTF_ETC2_RGBA, @c KTX_TTF_BC1_RGB, @c KTX_TTF_BC3_RGBA,
  70. * @c KTX_TTF_BC4_R, @c KTX_TTF_BC5_RG, @c KTX_TTF_BC7_RGBA,
  71. * @c @c KTX_TTF_PVRTC1_4_RGB, @c KTX_TTF_PVRTC1_4_RGBA,
  72. * @c KTX_TTF_PVRTC2_4_RGB, @c KTX_TTF_PVRTC2_4_RGBA, @c KTX_TTF_ASTC_4x4_RGBA,
  73. * @c KTX_TTF_ETC2_EAC_R11, @c KTX_TTF_ETC2_EAC_RG11, @c KTX_TTF_ETC and
  74. * @c KTX_TTF_BC1_OR_3.
  75. *
  76. * @c KTX_TTF_ETC automatically selects between @c KTX_TTF_ETC1_RGB and
  77. * @c KTX_TTF_ETC2_RGBA according to whether an alpha channel is available. @c KTX_TTF_BC1_OR_3
  78. * does likewise between @c KTX_TTF_BC1_RGB and @c KTX_TTF_BC3_RGBA. Note that if
  79. * @c KTX_TTF_PVRTC1_4_RGBA or @c KTX_TTF_PVRTC2_4_RGBA is specified and there is no alpha
  80. * channel @c KTX_TTF_PVRTC1_4_RGB or @c KTX_TTF_PVRTC2_4_RGB respectively will be selected.
  81. *
  82. * Transcoding to ATC & FXT1 formats is not supported by libktx as there
  83. * are no equivalent Vulkan formats.
  84. *
  85. * The following uncompressed transcode targets are also available: @c KTX_TTF_RGBA32,
  86. * @c KTX_TTF_RGB565, KTX_TTF_BGR565 and KTX_TTF_RGBA4444.
  87. *
  88. * The following @p transcodeFlags are available.
  89. *
  90. * @sa ktxtexture2_CompressBasis().
  91. *
  92. * @param[in] This pointer to the ktxTexture2 object of interest.
  93. * @param[in] outputFormat a value from the ktx_texture_transcode_fmt_e enum
  94. * specifying the target format.
  95. * @param[in] transcodeFlags bitfield of flags modifying the transcode
  96. * operation. @sa ktx_texture_decode_flags_e.
  97. *
  98. * @return KTX_SUCCESS on success, other KTX_* enum values on error.
  99. *
  100. * @exception KTX_FILE_DATA_ERROR
  101. * Supercompression global data is corrupted.
  102. * @exception KTX_INVALID_OPERATION
  103. * The texture's format is not transcodable (not
  104. * ETC1S/BasisLZ or UASTC).
  105. * @exception KTX_INVALID_OPERATION
  106. * Supercompression global data is missing, i.e.,
  107. * the texture object is invalid.
  108. * @exception KTX_INVALID_OPERATION
  109. * Image data is missing, i.e., the texture object
  110. * is invalid.
  111. * @exception KTX_INVALID_OPERATION
  112. * @p outputFormat is PVRTC1 but the texture does
  113. * does not have power-of-two dimensions.
  114. * @exception KTX_INVALID_VALUE @p outputFormat is invalid.
  115. * @exception KTX_TRANSCODE_FAILED
  116. * Something went wrong during transcoding.
  117. * @exception KTX_UNSUPPORTED_FEATURE
  118. * KTX_TF_PVRTC_DECODE_TO_NEXT_POW2 was requested
  119. * or the specified transcode target has not been
  120. * included in the library being used.
  121. * @exception KTX_OUT_OF_MEMORY Not enough memory to carry out transcoding.
  122. */
  123. KTX_error_code
  124. ktxTexture2_TranscodeBasis(ktxTexture2* This,
  125. ktx_transcode_fmt_e outputFormat,
  126. ktx_transcode_flags transcodeFlags)
  127. {
  128. uint32_t* BDB = This->pDfd + 1;
  129. khr_df_model_e colorModel = (khr_df_model_e)KHR_DFDVAL(BDB, MODEL);
  130. if (colorModel != KHR_DF_MODEL_UASTC
  131. // Constructor has checked color model matches BASIS_LZ.
  132. && This->supercompressionScheme != KTX_SS_BASIS_LZ)
  133. {
  134. return KTX_INVALID_OPERATION; // Not in a transcodable format.
  135. }
  136. DECLARE_PRIVATE(priv, This);
  137. if (This->supercompressionScheme == KTX_SS_BASIS_LZ) {
  138. if (!priv._supercompressionGlobalData || priv._sgdByteLength == 0)
  139. return KTX_INVALID_OPERATION;
  140. }
  141. if (transcodeFlags & KTX_TF_PVRTC_DECODE_TO_NEXT_POW2) {
  142. debug_printf("ktxTexture_TranscodeBasis: KTX_TF_PVRTC_DECODE_TO_NEXT_POW2 currently unsupported\n");
  143. return KTX_UNSUPPORTED_FEATURE;
  144. }
  145. if (outputFormat == KTX_TTF_PVRTC1_4_RGB
  146. || outputFormat == KTX_TTF_PVRTC1_4_RGBA) {
  147. if ((!isPow2(This->baseWidth)) || (!isPow2(This->baseHeight))) {
  148. debug_printf("ktxTexture_TranscodeBasis: PVRTC1 only supports power of 2 dimensions\n");
  149. return KTX_INVALID_OPERATION;
  150. }
  151. }
  152. const bool srgb = (KHR_DFDVAL(BDB, TRANSFER) == KHR_DF_TRANSFER_SRGB);
  153. alpha_content_e alphaContent = eNone;
  154. if (colorModel == KHR_DF_MODEL_ETC1S) {
  155. if (KHR_DFDSAMPLECOUNT(BDB) == 2) {
  156. uint32_t channelId = KHR_DFDSVAL(BDB, 1, CHANNELID);
  157. if (channelId == KHR_DF_CHANNEL_ETC1S_AAA) {
  158. alphaContent = eAlpha;
  159. } else if (channelId == KHR_DF_CHANNEL_ETC1S_GGG){
  160. alphaContent = eGreen;
  161. } else {
  162. return KTX_FILE_DATA_ERROR;
  163. }
  164. }
  165. } else {
  166. uint32_t channelId = KHR_DFDSVAL(BDB, 0, CHANNELID);
  167. if (channelId == KHR_DF_CHANNEL_UASTC_RGBA)
  168. alphaContent = eAlpha;
  169. else if (channelId == KHR_DF_CHANNEL_UASTC_RRRG)
  170. alphaContent = eGreen;
  171. }
  172. VkFormat vkFormat;
  173. // Do some format mapping.
  174. switch (outputFormat) {
  175. case KTX_TTF_BC1_OR_3:
  176. outputFormat = alphaContent != eNone ? KTX_TTF_BC3_RGBA
  177. : KTX_TTF_BC1_RGB;
  178. break;
  179. case KTX_TTF_ETC:
  180. outputFormat = alphaContent != eNone ? KTX_TTF_ETC2_RGBA
  181. : KTX_TTF_ETC1_RGB;
  182. break;
  183. case KTX_TTF_PVRTC1_4_RGBA:
  184. // This transcoder does not write opaque alpha blocks.
  185. outputFormat = alphaContent != eNone ? KTX_TTF_PVRTC1_4_RGBA
  186. : KTX_TTF_PVRTC1_4_RGB;
  187. break;
  188. case KTX_TTF_PVRTC2_4_RGBA:
  189. // This transcoder does not write opaque alpha blocks.
  190. outputFormat = alphaContent != eNone ? KTX_TTF_PVRTC2_4_RGBA
  191. : KTX_TTF_PVRTC2_4_RGB;
  192. break;
  193. default:
  194. /*NOP*/;
  195. }
  196. switch (outputFormat) {
  197. case KTX_TTF_ETC1_RGB:
  198. vkFormat = srgb ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK
  199. : VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
  200. break;
  201. case KTX_TTF_ETC2_RGBA:
  202. vkFormat = srgb ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK
  203. : VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
  204. break;
  205. case KTX_TTF_ETC2_EAC_R11:
  206. vkFormat = VK_FORMAT_EAC_R11_UNORM_BLOCK;
  207. break;
  208. case KTX_TTF_ETC2_EAC_RG11:
  209. vkFormat = VK_FORMAT_EAC_R11G11_UNORM_BLOCK;
  210. break;
  211. case KTX_TTF_BC1_RGB:
  212. // Transcoding doesn't support BC1 alpha.
  213. vkFormat = srgb ? VK_FORMAT_BC1_RGB_SRGB_BLOCK
  214. : VK_FORMAT_BC1_RGB_UNORM_BLOCK;
  215. break;
  216. case KTX_TTF_BC3_RGBA:
  217. vkFormat = srgb ? VK_FORMAT_BC3_SRGB_BLOCK
  218. : VK_FORMAT_BC3_UNORM_BLOCK;
  219. break;
  220. case KTX_TTF_BC4_R:
  221. vkFormat = VK_FORMAT_BC4_UNORM_BLOCK;
  222. break;
  223. case KTX_TTF_BC5_RG:
  224. vkFormat = VK_FORMAT_BC5_UNORM_BLOCK;
  225. break;
  226. case KTX_TTF_PVRTC1_4_RGB:
  227. case KTX_TTF_PVRTC1_4_RGBA:
  228. vkFormat = srgb ? VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG
  229. : VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG;
  230. break;
  231. case KTX_TTF_PVRTC2_4_RGB:
  232. case KTX_TTF_PVRTC2_4_RGBA:
  233. vkFormat = srgb ? VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG
  234. : VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG;
  235. break;
  236. case KTX_TTF_BC7_RGBA:
  237. vkFormat = srgb ? VK_FORMAT_BC7_SRGB_BLOCK
  238. : VK_FORMAT_BC7_UNORM_BLOCK;
  239. break;
  240. case KTX_TTF_ASTC_4x4_RGBA:
  241. vkFormat = srgb ? VK_FORMAT_ASTC_4x4_SRGB_BLOCK
  242. : VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
  243. break;
  244. case KTX_TTF_RGB565:
  245. vkFormat = VK_FORMAT_R5G6B5_UNORM_PACK16;
  246. break;
  247. case KTX_TTF_BGR565:
  248. vkFormat = VK_FORMAT_B5G6R5_UNORM_PACK16;
  249. break;
  250. case KTX_TTF_RGBA4444:
  251. vkFormat = VK_FORMAT_R4G4B4A4_UNORM_PACK16;
  252. break;
  253. case KTX_TTF_RGBA32:
  254. vkFormat = srgb ? VK_FORMAT_R8G8B8A8_SRGB
  255. : VK_FORMAT_R8G8B8A8_UNORM;
  256. break;
  257. default:
  258. return KTX_INVALID_VALUE;
  259. }
  260. basis_tex_format textureFormat;
  261. if (colorModel == KHR_DF_MODEL_UASTC)
  262. textureFormat = basis_tex_format::cUASTC4x4;
  263. else
  264. textureFormat = basis_tex_format::cETC1S;
  265. if (!basis_is_format_supported((transcoder_texture_format)outputFormat,
  266. textureFormat)) {
  267. return KTX_UNSUPPORTED_FEATURE;
  268. }
  269. // Create a prototype texture to use for calculating sizes in the target
  270. // format and, as useful side effects, provide us with a properly sized
  271. // data allocation and the DFD for the target format.
  272. ktxTextureCreateInfo createInfo;
  273. createInfo.glInternalformat = 0;
  274. createInfo.vkFormat = vkFormat;
  275. createInfo.baseWidth = This->baseWidth;
  276. createInfo.baseHeight = This->baseHeight;
  277. createInfo.baseDepth = This->baseDepth;
  278. createInfo.generateMipmaps = This->generateMipmaps;
  279. createInfo.isArray = This->isArray;
  280. createInfo.numDimensions = This->numDimensions;
  281. createInfo.numFaces = This->numFaces;
  282. createInfo.numLayers = This->numLayers;
  283. createInfo.numLevels = This->numLevels;
  284. createInfo.pDfd = nullptr;
  285. KTX_error_code result;
  286. ktxTexture2* prototype;
  287. result = ktxTexture2_Create(&createInfo, KTX_TEXTURE_CREATE_ALLOC_STORAGE,
  288. &prototype);
  289. if (result != KTX_SUCCESS) {
  290. assert(result == KTX_OUT_OF_MEMORY); // The only run time error
  291. return result;
  292. }
  293. if (!This->pData) {
  294. if (ktxTexture_isActiveStream((ktxTexture*)This)) {
  295. // Load pending. Complete it.
  296. result = ktxTexture2_LoadImageData(This, NULL, 0);
  297. if (result != KTX_SUCCESS)
  298. {
  299. ktxTexture2_Destroy(prototype);
  300. return result;
  301. }
  302. } else {
  303. // No data to transcode.
  304. ktxTexture2_Destroy(prototype);
  305. return KTX_INVALID_OPERATION;
  306. }
  307. }
  308. // Transcoder global initialization. Requires ~9 milliseconds when compiled
  309. // and executed natively on a Core i7 2.2 GHz. If this is too slow, the
  310. // tables it computes can easily be moved to be compiled in.
  311. static bool transcoderInitialized;
  312. if (!transcoderInitialized) {
  313. basisu_transcoder_init();
  314. transcoderInitialized = true;
  315. }
  316. if (textureFormat == basis_tex_format::cETC1S) {
  317. result = ktxTexture2_transcodeLzEtc1s(This, alphaContent,
  318. prototype, outputFormat,
  319. transcodeFlags);
  320. } else {
  321. result = ktxTexture2_transcodeUastc(This, alphaContent,
  322. prototype, outputFormat,
  323. transcodeFlags);
  324. }
  325. if (result == KTX_SUCCESS) {
  326. // Fix up the current texture
  327. DECLARE_PROTECTED(thisPrtctd, This);
  328. DECLARE_PRIVATE(protoPriv, prototype);
  329. DECLARE_PROTECTED(protoPrtctd, prototype);
  330. memcpy(&thisPrtctd._formatSize, &protoPrtctd._formatSize,
  331. sizeof(ktxFormatSize));
  332. This->vkFormat = vkFormat;
  333. This->isCompressed = prototype->isCompressed;
  334. This->supercompressionScheme = KTX_SS_NONE;
  335. priv._requiredLevelAlignment = protoPriv._requiredLevelAlignment;
  336. // Copy the levelIndex from the prototype to This.
  337. memcpy(priv._levelIndex, protoPriv._levelIndex,
  338. This->numLevels * sizeof(ktxLevelIndexEntry));
  339. // Move the DFD and data from the prototype to This.
  340. free(This->pDfd);
  341. This->pDfd = prototype->pDfd;
  342. prototype->pDfd = 0;
  343. free(This->pData);
  344. This->pData = prototype->pData;
  345. This->dataSize = prototype->dataSize;
  346. prototype->pData = 0;
  347. prototype->dataSize = 0;
  348. // Free SGD data
  349. This->_private->_sgdByteLength = 0;
  350. if (This->_private->_supercompressionGlobalData) {
  351. free(This->_private->_supercompressionGlobalData);
  352. This->_private->_supercompressionGlobalData = NULL;
  353. }
  354. }
  355. ktxTexture2_Destroy(prototype);
  356. return result;
  357. }
  358. /**
  359. * @memberof ktxTexture2 @private
  360. * @ingroup reader
  361. * @~English
  362. * @brief Transcode a KTX2 texture with BasisLZ supercompressed ETC1S images.
  363. *
  364. * Inflates the images from BasisLZ supercompression back to ETC1S
  365. * then transcodes them to the specified block-compressed format. The
  366. * transcoded images replace the original images and the texture's fields
  367. * including the DFD are modified to reflect the new format.
  368. *
  369. * BasisLZ supercompressed textures must be transcoded to a desired target
  370. * block-compressed format before they can be uploaded to a GPU via a graphics
  371. * API.
  372. *
  373. * The following block compressed transcode targets are available: @c KTX_TTF_ETC1_RGB,
  374. * @c KTX_TTF_ETC2_RGBA, @c KTX_TTF_BC1_RGB, @c KTX_TTF_BC3_RGBA,
  375. * @c KTX_TTF_BC4_R, @c KTX_TTF_BC5_RG, @c KTX_TTF_BC7_RGBA,
  376. * @c @c KTX_TTF_PVRTC1_4_RGB, @c KTX_TTF_PVRTC1_4_RGBA,
  377. * @c KTX_TTF_PVRTC2_4_RGB, @c KTX_TTF_PVRTC2_4_RGBA, @c KTX_TTF_ASTC_4x4_RGBA,
  378. * @c KTX_TTF_ETC2_EAC_R11, @c KTX_TTF_ETC2_EAC_RG11, @c KTX_TTF_ETC and
  379. * @c KTX_TTF_BC1_OR_3.
  380. *
  381. * @c KTX_TTF_ETC automatically selects between @c KTX_TTF_ETC1_RGB and
  382. * @c KTX_TTF_ETC2_RGBA according to whether an alpha channel is available. @c KTX_TTF_BC1_OR_3
  383. * does likewise between @c KTX_TTF_BC1_RGB and @c KTX_TTF_BC3_RGBA. Note that if
  384. * @c KTX_TTF_PVRTC1_4_RGBA or @c KTX_TTF_PVRTC2_4_RGBA is specified and there is no alpha
  385. * channel @c KTX_TTF_PVRTC1_4_RGB or @c KTX_TTF_PVRTC2_4_RGB respectively will be selected.
  386. *
  387. * ATC & FXT1 formats are not supported by KTX2 & libktx as there are no equivalent Vulkan formats.
  388. *
  389. * The following uncompressed transcode targets are also available: @c KTX_TTF_RGBA32,
  390. * @c KTX_TTF_RGB565, KTX_TTF_BGR565 and KTX_TTF_RGBA4444.
  391. *
  392. * The following @p transcodeFlags are available.
  393. *
  394. * @sa ktxtexture2_CompressBasis().
  395. *
  396. * @param[in] This pointer to the ktxTexture2 object of interest.
  397. * @param[in] outputFormat a value from the ktx_texture_transcode_fmt_e enum
  398. * specifying the target format.
  399. * @param[in] transcodeFlags bitfield of flags modifying the transcode
  400. * operation. @sa ktx_texture_decode_flags_e.
  401. *
  402. * @return KTX_SUCCESS on success, other KTX_* enum values on error.
  403. *
  404. * @exception KTX_FILE_DATA_ERROR
  405. * Supercompression global data is corrupted.
  406. * @exception KTX_INVALID_OPERATION
  407. * The texture's format is not transcodable (not
  408. * ETC1S/BasisLZ or UASTC).
  409. * @exception KTX_INVALID_OPERATION
  410. * Supercompression global data is missing, i.e.,
  411. * the texture object is invalid.
  412. * @exception KTX_INVALID_OPERATION
  413. * Image data is missing, i.e., the texture object
  414. * is invalid.
  415. * @exception KTX_INVALID_OPERATION
  416. * @p outputFormat is PVRTC1 but the texture does
  417. * does not have power-of-two dimensions.
  418. * @exception KTX_INVALID_VALUE @p outputFormat is invalid.
  419. * @exception KTX_TRANSCODE_FAILED
  420. * Something went wrong during transcoding. The
  421. * texture object will be corrupted.
  422. * @exception KTX_UNSUPPORTED_FEATURE
  423. * KTX_TF_PVRTC_DECODE_TO_NEXT_POW2 was requested
  424. * or the specified transcode target has not been
  425. * included in the library being used.
  426. * @exception KTX_OUT_OF_MEMORY Not enough memory to carry out transcoding.
  427. */
  428. KTX_error_code
  429. ktxTexture2_transcodeLzEtc1s(ktxTexture2* This,
  430. alpha_content_e alphaContent,
  431. ktxTexture2* prototype,
  432. ktx_transcode_fmt_e outputFormat,
  433. ktx_transcode_flags transcodeFlags)
  434. {
  435. DECLARE_PRIVATE(priv, This);
  436. DECLARE_PRIVATE(protoPriv, prototype);
  437. KTX_error_code result = KTX_SUCCESS;
  438. assert(This->supercompressionScheme == KTX_SS_BASIS_LZ);
  439. uint8_t* bgd = priv._supercompressionGlobalData;
  440. ktxBasisLzGlobalHeader& bgdh = *reinterpret_cast<ktxBasisLzGlobalHeader*>(bgd);
  441. if (!(bgdh.endpointsByteLength && bgdh.selectorsByteLength && bgdh.tablesByteLength)) {
  442. debug_printf("ktxTexture_TranscodeBasis: missing endpoints, selectors or tables");
  443. return KTX_FILE_DATA_ERROR;
  444. }
  445. // Compute some helpful numbers.
  446. //
  447. // firstImages contains the indices of the first images for each level to
  448. // ease finding the correct slice description when iterating from smallest
  449. // level to largest or when randomly accessing them (t.b.c). The last array
  450. // entry contains the total number of images, for calculating the offsets
  451. // of the endpoints, etc.
  452. uint32_t* firstImages = new uint32_t[This->numLevels+1];
  453. // Temporary invariant value
  454. uint32_t layersFaces = This->numLayers * This->numFaces;
  455. firstImages[0] = 0;
  456. for (uint32_t level = 1; level <= This->numLevels; level++) {
  457. // NOTA BENE: numFaces * depth is only reasonable because they can't
  458. // both be > 1. I.e there are no 3d cubemaps.
  459. firstImages[level] = firstImages[level - 1]
  460. + layersFaces * MAX(This->baseDepth >> (level - 1), 1);
  461. }
  462. uint32_t& imageCount = firstImages[This->numLevels];
  463. if (BGD_TABLES_ADDR(0, bgdh, imageCount) + bgdh.tablesByteLength > priv._sgdByteLength) {
  464. return KTX_FILE_DATA_ERROR;
  465. }
  466. // FIXME: Do more validation.
  467. // Prepare low-level transcoder for transcoding slices.
  468. basist::basisu_lowlevel_etc1s_transcoder bit;
  469. // basisu_transcoder_state is used to find the previous frame when
  470. // decoding a video P-Frame. It tracks the previous frame for each mip
  471. // level. For cube map array textures we need to find the previous frame
  472. // for each face so we a state per face. Although providing this is only
  473. // needed for video, it is easier to always pass our own.
  474. std::vector<basisu_transcoder_state> xcoderStates;
  475. xcoderStates.resize(This->isVideo ? This->numFaces : 1);
  476. bit.decode_palettes(bgdh.endpointCount, BGD_ENDPOINTS_ADDR(bgd, imageCount),
  477. bgdh.endpointsByteLength,
  478. bgdh.selectorCount, BGD_SELECTORS_ADDR(bgd, bgdh, imageCount),
  479. bgdh.selectorsByteLength);
  480. bit.decode_tables(BGD_TABLES_ADDR(bgd, bgdh, imageCount),
  481. bgdh.tablesByteLength);
  482. // Find matching VkFormat and calculate output sizes.
  483. const bool isVideo = This->isVideo;
  484. ktx_uint8_t* pXcodedData = prototype->pData;
  485. // Inconveniently, the output buffer size parameter of transcode_image
  486. // has to be in pixels for uncompressed output and in blocks for
  487. // compressed output. The only reason for humouring the API is so
  488. // its buffer size tests provide a real check. An alternative is to
  489. // always provide the size in bytes which will always pass.
  490. ktx_uint32_t outputBlockByteLength
  491. = prototype->_protected->_formatSize.blockSizeInBits / 8;
  492. ktx_size_t xcodedDataLength
  493. = prototype->dataSize / outputBlockByteLength;
  494. ktxLevelIndexEntry* protoLevelIndex;
  495. uint64_t levelOffsetWrite;
  496. const ktxBasisLzEtc1sImageDesc* imageDescs = BGD_ETC1S_IMAGE_DESCS(bgd);
  497. // Finally we're ready to transcode the slices.
  498. // FIXME: Iframe flag needs to be queryable by the application. In Basis
  499. // the app can query file_info and image_info from the transcoder which
  500. // returns a structure with lots of info about the image.
  501. protoLevelIndex = protoPriv._levelIndex;
  502. levelOffsetWrite = 0;
  503. for (int32_t level = This->numLevels - 1; level >= 0; level--) {
  504. uint64_t levelOffset = ktxTexture2_levelDataOffset(This, level);
  505. uint64_t writeOffset = levelOffsetWrite;
  506. uint64_t writeOffsetBlocks = levelOffsetWrite / outputBlockByteLength;
  507. uint32_t levelWidth = MAX(1, This->baseWidth >> level);
  508. uint32_t levelHeight = MAX(1, This->baseHeight >> level);
  509. // ETC1S texel block dimensions
  510. const uint32_t bw = 4, bh = 4;
  511. uint32_t levelBlocksX = (levelWidth + (bw - 1)) / bw;
  512. uint32_t levelBlocksY = (levelHeight + (bh - 1)) / bh;
  513. uint32_t depth = MAX(1, This->baseDepth >> level);
  514. //uint32_t faceSlices = This->numFaces == 1 ? depth : This->numFaces;
  515. uint32_t faceSlices = This->numFaces * depth;
  516. uint32_t numImages = This->numLayers * faceSlices;
  517. uint32_t image = firstImages[level];
  518. uint32_t endImage = image + numImages;
  519. ktx_size_t levelImageSizeOut, levelSizeOut;
  520. uint32_t stateIndex = 0;
  521. levelSizeOut = 0;
  522. // FIXME: Figure out a way to get the size out of the transcoder.
  523. levelImageSizeOut = ktxTexture2_GetImageSize(prototype, level);
  524. for (; image < endImage; image++) {
  525. const ktxBasisLzEtc1sImageDesc& imageDesc = imageDescs[image];
  526. basisu_transcoder_state& xcoderState = xcoderStates[stateIndex];
  527. // We have face0 [face1 ...] within each layer. Use `stateIndex`
  528. // rather than a double loop of layers and faceSlices as this
  529. // works for 3d texture and non-array cube maps as well as
  530. // cube map arrays without special casing.
  531. if (++stateIndex == xcoderStates.size())
  532. stateIndex = 0;
  533. if (alphaContent != eNone)
  534. {
  535. // The slice descriptions should have alpha information.
  536. if (imageDesc.alphaSliceByteOffset == 0
  537. || imageDesc.alphaSliceByteLength == 0)
  538. return KTX_FILE_DATA_ERROR;
  539. }
  540. bool status;
  541. status = bit.transcode_image(
  542. (transcoder_texture_format)outputFormat,
  543. pXcodedData + writeOffset,
  544. (uint32_t)(xcodedDataLength - writeOffsetBlocks),
  545. This->pData,
  546. (uint32_t)This->dataSize,
  547. levelBlocksX,
  548. levelBlocksY,
  549. levelWidth,
  550. levelHeight,
  551. level,
  552. (uint32_t)(levelOffset + imageDesc.rgbSliceByteOffset),
  553. imageDesc.rgbSliceByteLength,
  554. (uint32_t)(levelOffset + imageDesc.alphaSliceByteOffset),
  555. imageDesc.alphaSliceByteLength,
  556. transcodeFlags,
  557. alphaContent != eNone,
  558. isVideo,
  559. // Our P-Frame flag is in the same bit as
  560. // cSliceDescFlagsFrameIsIFrame. We have to
  561. // invert it to make it an I-Frame flag.
  562. //
  563. // API currently doesn't have any way to pass
  564. // the I-Frame flag.
  565. //imageDesc.imageFlags ^ cSliceDescFlagsFrameIsIFrame,
  566. 0, // output_row_pitch_in_blocks_or_pixels
  567. &xcoderState,
  568. 0 // output_rows_in_pixels
  569. );
  570. if (!status) {
  571. result = KTX_TRANSCODE_FAILED;
  572. goto cleanup;
  573. }
  574. writeOffset += levelImageSizeOut;
  575. levelSizeOut += levelImageSizeOut;
  576. } // end images loop
  577. protoLevelIndex[level].byteOffset = levelOffsetWrite;
  578. protoLevelIndex[level].byteLength = levelSizeOut;
  579. protoLevelIndex[level].uncompressedByteLength = levelSizeOut;
  580. levelOffsetWrite += levelSizeOut;
  581. assert(levelOffsetWrite == writeOffset);
  582. // In case of transcoding to uncompressed.
  583. levelOffsetWrite = _KTX_PADN(protoPriv._requiredLevelAlignment,
  584. levelOffsetWrite);
  585. } // level loop
  586. result = KTX_SUCCESS;
  587. cleanup:
  588. delete[] firstImages;
  589. return result;
  590. }
  591. KTX_error_code
  592. ktxTexture2_transcodeUastc(ktxTexture2* This,
  593. alpha_content_e alphaContent,
  594. ktxTexture2* prototype,
  595. ktx_transcode_fmt_e outputFormat,
  596. ktx_transcode_flags transcodeFlags)
  597. {
  598. assert(This->supercompressionScheme != KTX_SS_BASIS_LZ);
  599. ktx_uint8_t* pXcodedData = prototype->pData;
  600. ktx_uint32_t outputBlockByteLength
  601. = prototype->_protected->_formatSize.blockSizeInBits / 8;
  602. ktx_size_t xcodedDataLength
  603. = prototype->dataSize / outputBlockByteLength;
  604. DECLARE_PRIVATE(protoPriv, prototype);
  605. ktxLevelIndexEntry* protoLevelIndex = protoPriv._levelIndex;
  606. ktx_size_t levelOffsetWrite = 0;
  607. basisu_lowlevel_uastc_transcoder uit;
  608. // See comment on same declaration in transcodeEtc1s.
  609. std::vector<basisu_transcoder_state> xcoderStates;
  610. xcoderStates.resize(This->isVideo ? This->numFaces : 1);
  611. for (ktx_int32_t level = This->numLevels - 1; level >= 0; level--)
  612. {
  613. ktx_uint32_t depth;
  614. uint64_t writeOffset = levelOffsetWrite;
  615. uint64_t writeOffsetBlocks = levelOffsetWrite / outputBlockByteLength;
  616. ktx_size_t levelImageSizeIn, levelImageOffsetIn;
  617. ktx_size_t levelImageSizeOut, levelSizeOut;
  618. ktx_uint32_t levelImageCount;
  619. uint32_t levelWidth = MAX(1, This->baseWidth >> level);
  620. uint32_t levelHeight = MAX(1, This->baseHeight >> level);
  621. // UASTC texel block dimensions
  622. const uint32_t bw = 4, bh = 4;
  623. uint32_t levelBlocksX = (levelWidth + (bw - 1)) / bw;
  624. uint32_t levelBlocksY = (levelHeight + (bh - 1)) / bh;
  625. uint32_t stateIndex = 0;
  626. depth = MAX(1, This->baseDepth >> level);
  627. levelImageCount = This->numLayers * This->numFaces * depth;
  628. levelImageSizeIn = ktxTexture_calcImageSize(ktxTexture(This), level,
  629. KTX_FORMAT_VERSION_TWO);
  630. levelImageSizeOut = ktxTexture_calcImageSize(ktxTexture(prototype),
  631. level,
  632. KTX_FORMAT_VERSION_TWO);
  633. levelImageOffsetIn = ktxTexture2_levelDataOffset(This, level);
  634. levelSizeOut = 0;
  635. bool status;
  636. for (uint32_t image = 0; image < levelImageCount; image++) {
  637. basisu_transcoder_state& xcoderState = xcoderStates[stateIndex];
  638. // See comment before same lines in transcodeEtc1s.
  639. if (++stateIndex == xcoderStates.size())
  640. stateIndex = 0;
  641. status = uit.transcode_image(
  642. (transcoder_texture_format)outputFormat,
  643. pXcodedData + writeOffset,
  644. (uint32_t)(xcodedDataLength - writeOffsetBlocks),
  645. This->pData,
  646. (uint32_t)This->dataSize,
  647. levelBlocksX,
  648. levelBlocksY,
  649. levelWidth,
  650. levelHeight,
  651. level,
  652. (uint32_t)levelImageOffsetIn,
  653. (uint32_t)levelImageSizeIn,
  654. transcodeFlags,
  655. alphaContent != eNone,
  656. This->isVideo, // is_video
  657. //imageDesc.imageFlags ^ cSliceDescFlagsFrameIsIFrame,
  658. 0, // output_row_pitch_in_blocks_or_pixels
  659. &xcoderState, // pState
  660. 0, // output_rows_in_pixels,
  661. -1, // channel0
  662. -1 // channel1
  663. );
  664. if (!status)
  665. return KTX_TRANSCODE_FAILED;
  666. writeOffset += levelImageSizeOut;
  667. levelSizeOut += levelImageSizeOut;
  668. levelImageOffsetIn += levelImageSizeIn;
  669. }
  670. protoLevelIndex[level].byteOffset = levelOffsetWrite;
  671. // writeOffset will be equal to total size of the images in the level.
  672. protoLevelIndex[level].byteLength = levelSizeOut;
  673. protoLevelIndex[level].uncompressedByteLength = levelSizeOut;
  674. levelOffsetWrite += levelSizeOut;
  675. }
  676. // In case of transcoding to uncompressed.
  677. levelOffsetWrite = _KTX_PADN(protoPriv._requiredLevelAlignment,
  678. levelOffsetWrite);
  679. return KTX_SUCCESS;
  680. }