crn_comp.cpp 72 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178
  1. // File: crn_comp.cpp
  2. // See Copyright Notice and license at the end of inc/crnlib.h
  3. #include "crn_core.h"
  4. #include "crn_console.h"
  5. #include "crn_comp.h"
  6. #include "crn_zeng.h"
  7. #include "crn_checksum.h"
  8. #define CRNLIB_CREATE_DEBUG_IMAGES 0
  9. #define CRNLIB_ENABLE_DEBUG_MESSAGES 0
  10. namespace crnlib
  11. {
  12. static const uint cEncodingMapNumChunksPerCode = 3;
  13. crn_comp::crn_comp() :
  14. m_pParams(NULL)
  15. {
  16. }
  17. crn_comp::~crn_comp()
  18. {
  19. }
  20. float crn_comp::color_endpoint_similarity_func(uint index_a, uint index_b, void* pContext)
  21. {
  22. dxt_hc& hvq = *static_cast<dxt_hc*>(pContext);
  23. uint endpoint_a = hvq.get_color_endpoint(index_a);
  24. uint endpoint_b = hvq.get_color_endpoint(index_b);
  25. color_quad_u8 a[2];
  26. a[0] = dxt1_block::unpack_color((uint16)(endpoint_a & 0xFFFF), true);
  27. a[1] = dxt1_block::unpack_color((uint16)((endpoint_a >> 16) & 0xFFFF), true);
  28. color_quad_u8 b[2];
  29. b[0] = dxt1_block::unpack_color((uint16)(endpoint_b & 0xFFFF), true);
  30. b[1] = dxt1_block::unpack_color((uint16)((endpoint_b >> 16) & 0xFFFF), true);
  31. uint total_error = color::elucidian_distance(a[0], b[0], false) + color::elucidian_distance(a[1], b[1], false);
  32. float weight = 1.0f - math::clamp(total_error * 1.0f/8000.0f, 0.0f, 1.0f);
  33. return weight;
  34. }
  35. float crn_comp::alpha_endpoint_similarity_func(uint index_a, uint index_b, void* pContext)
  36. {
  37. dxt_hc& hvq = *static_cast<dxt_hc*>(pContext);
  38. uint endpoint_a = hvq.get_alpha_endpoint(index_a);
  39. int endpoint_a_lo = dxt5_block::unpack_endpoint(endpoint_a, 0);
  40. int endpoint_a_hi = dxt5_block::unpack_endpoint(endpoint_a, 1);
  41. uint endpoint_b = hvq.get_alpha_endpoint(index_b);
  42. int endpoint_b_lo = dxt5_block::unpack_endpoint(endpoint_b, 0);
  43. int endpoint_b_hi = dxt5_block::unpack_endpoint(endpoint_b, 1);
  44. int total_error = math::square(endpoint_a_lo - endpoint_b_lo) + math::square(endpoint_a_hi - endpoint_b_hi);
  45. float weight = 1.0f - math::clamp(total_error * 1.0f/256.0f, 0.0f, 1.0f);
  46. return weight;
  47. }
  48. void crn_comp::sort_color_endpoint_codebook(crnlib::vector<uint>& remapping, const crnlib::vector<uint>& endpoints)
  49. {
  50. remapping.resize(endpoints.size());
  51. uint lowest_energy = UINT_MAX;
  52. uint lowest_energy_index = 0;
  53. for (uint i = 0; i < endpoints.size(); i++)
  54. {
  55. color_quad_u8 a(dxt1_block::unpack_color(static_cast<uint16>(endpoints[i] & 0xFFFF), true));
  56. color_quad_u8 b(dxt1_block::unpack_color(static_cast<uint16>((endpoints[i] >> 16) & 0xFFFF), true));
  57. uint total = a.r + a.g + a.b + b.r + b.g + b.b;
  58. if (total < lowest_energy)
  59. {
  60. lowest_energy = total;
  61. lowest_energy_index = i;
  62. }
  63. }
  64. uint cur_index = lowest_energy_index;
  65. crnlib::vector<bool> chosen_flags(endpoints.size());
  66. uint n = 0;
  67. for ( ; ; )
  68. {
  69. chosen_flags[cur_index] = true;
  70. remapping[cur_index] = n;
  71. n++;
  72. if (n == endpoints.size())
  73. break;
  74. uint lowest_error = UINT_MAX;
  75. uint lowest_error_index = 0;
  76. color_quad_u8 a(dxt1_block::unpack_endpoint(endpoints[cur_index], 0, true));
  77. color_quad_u8 b(dxt1_block::unpack_endpoint(endpoints[cur_index], 1, true));
  78. for (uint i = 0; i < endpoints.size(); i++)
  79. {
  80. if (chosen_flags[i])
  81. continue;
  82. color_quad_u8 c(dxt1_block::unpack_endpoint(endpoints[i], 0, true));
  83. color_quad_u8 d(dxt1_block::unpack_endpoint(endpoints[i], 1, true));
  84. uint total = color::elucidian_distance(a, c, false) + color::elucidian_distance(b, d, false);
  85. if (total < lowest_error)
  86. {
  87. lowest_error = total;
  88. lowest_error_index = i;
  89. }
  90. }
  91. cur_index = lowest_error_index;
  92. }
  93. }
  94. void crn_comp::sort_alpha_endpoint_codebook(crnlib::vector<uint>& remapping, const crnlib::vector<uint>& endpoints)
  95. {
  96. remapping.resize(endpoints.size());
  97. uint lowest_energy = UINT_MAX;
  98. uint lowest_energy_index = 0;
  99. for (uint i = 0; i < endpoints.size(); i++)
  100. {
  101. uint a = dxt5_block::unpack_endpoint(endpoints[i], 0);
  102. uint b = dxt5_block::unpack_endpoint(endpoints[i], 1);
  103. uint total = a + b;
  104. if (total < lowest_energy)
  105. {
  106. lowest_energy = total;
  107. lowest_energy_index = i;
  108. }
  109. }
  110. uint cur_index = lowest_energy_index;
  111. crnlib::vector<bool> chosen_flags(endpoints.size());
  112. uint n = 0;
  113. for ( ; ; )
  114. {
  115. chosen_flags[cur_index] = true;
  116. remapping[cur_index] = n;
  117. n++;
  118. if (n == endpoints.size())
  119. break;
  120. uint lowest_error = UINT_MAX;
  121. uint lowest_error_index = 0;
  122. const int a = dxt5_block::unpack_endpoint(endpoints[cur_index], 0);
  123. const int b = dxt5_block::unpack_endpoint(endpoints[cur_index], 1);
  124. for (uint i = 0; i < endpoints.size(); i++)
  125. {
  126. if (chosen_flags[i])
  127. continue;
  128. const int c = dxt5_block::unpack_endpoint(endpoints[i], 0);
  129. const int d = dxt5_block::unpack_endpoint(endpoints[i], 1);
  130. uint total = math::square(a - c) + math::square(b - d);
  131. if (total < lowest_error)
  132. {
  133. lowest_error = total;
  134. lowest_error_index = i;
  135. }
  136. }
  137. cur_index = lowest_error_index;
  138. }
  139. }
  140. // The indices are only used for statistical purposes.
  141. bool crn_comp::pack_color_endpoints(
  142. crnlib::vector<uint8>& data,
  143. const crnlib::vector<uint>& remapping,
  144. const crnlib::vector<uint>& endpoint_indices,
  145. uint trial_index)
  146. {
  147. trial_index;
  148. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  149. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  150. console::debug("pack_color_endpoints: %u", trial_index);
  151. #endif
  152. crnlib::vector<uint> remapped_endpoints(m_hvq.get_color_endpoint_codebook_size());
  153. for (uint i = 0; i < m_hvq.get_color_endpoint_codebook_size(); i++)
  154. remapped_endpoints[remapping[i]] = m_hvq.get_color_endpoint(i);
  155. const uint component_limits[6] = { 31, 63, 31, 31, 63, 31 };
  156. symbol_histogram hist[2];
  157. hist[0].resize(32);
  158. hist[1].resize(64);
  159. #if CRNLIB_CREATE_DEBUG_IMAGES
  160. image_u8 endpoint_image(2, m_hvq.get_color_endpoint_codebook_size());
  161. image_u8 endpoint_residual_image(2, m_hvq.get_color_endpoint_codebook_size());
  162. #endif
  163. crnlib::vector<uint> residual_syms;
  164. residual_syms.reserve(m_hvq.get_color_endpoint_codebook_size()*2*3);
  165. color_quad_u8 prev[2];
  166. prev[0].clear();
  167. prev[1].clear();
  168. int total_residuals = 0;
  169. for (uint endpoint_index = 0; endpoint_index < m_hvq.get_color_endpoint_codebook_size(); endpoint_index++)
  170. {
  171. const uint endpoint = remapped_endpoints[endpoint_index];
  172. color_quad_u8 cur[2];
  173. cur[0] = dxt1_block::unpack_color((uint16)(endpoint & 0xFFFF), false);
  174. cur[1] = dxt1_block::unpack_color((uint16)((endpoint >> 16) & 0xFFFF), false);
  175. #if CRNLIB_CREATE_DEBUG_IMAGES
  176. endpoint_image(0, endpoint_index) = dxt1_block::unpack_color((uint16)(endpoint & 0xFFFF), true);
  177. endpoint_image(1, endpoint_index) = dxt1_block::unpack_color((uint16)((endpoint >> 16) & 0xFFFF), true);
  178. #endif
  179. for (uint j = 0; j < 2; j++)
  180. {
  181. for (uint k = 0; k < 3; k++)
  182. {
  183. int delta = cur[j][k] - prev[j][k];
  184. total_residuals += delta*delta;
  185. int sym = delta & component_limits[j*3+k];
  186. int table = (k == 1) ? 1 : 0;
  187. hist[table].inc_freq(sym);
  188. residual_syms.push_back(sym);
  189. #if CRNLIB_CREATE_DEBUG_IMAGES
  190. endpoint_residual_image(j, endpoint_index)[k] = static_cast<uint8>(sym);
  191. #endif
  192. }
  193. }
  194. prev[0] = cur[0];
  195. prev[1] = cur[1];
  196. }
  197. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  198. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  199. console::debug("Total endpoint residuals: %i", total_residuals);
  200. #endif
  201. if (endpoint_indices.size() > 1)
  202. {
  203. uint prev_index = remapping[endpoint_indices[0]];
  204. int64 total_delta = 0;
  205. for (uint i = 1; i < endpoint_indices.size(); i++)
  206. {
  207. uint cur_index = remapping[endpoint_indices[i]];
  208. int delta = cur_index - prev_index;
  209. prev_index = cur_index;
  210. total_delta += delta * delta;
  211. }
  212. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  213. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  214. console::debug("Total endpoint index delta: " CRNLIB_INT64_FORMAT_SPECIFIER, total_delta);
  215. #endif
  216. }
  217. #if CRNLIB_CREATE_DEBUG_IMAGES
  218. image_utils::write_to_file(dynamic_string(cVarArg, "color_endpoint_residuals_%u.tga", trial_index).get_ptr(), endpoint_residual_image);
  219. image_utils::write_to_file(dynamic_string(cVarArg, "color_endpoints_%u.tga", trial_index).get_ptr(), endpoint_image);
  220. #endif
  221. static_huffman_data_model residual_dm[2];
  222. symbol_codec codec;
  223. codec.start_encoding(1024*1024);
  224. // Transmit residuals
  225. for (uint i = 0; i < 2; i++)
  226. {
  227. if (!residual_dm[i].init(true, hist[i], 15))
  228. return false;
  229. if (!codec.encode_transmit_static_huffman_data_model(residual_dm[i], false))
  230. return false;
  231. }
  232. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  233. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  234. console::debug("Wrote %u bits for color endpoint residual Huffman tables", codec.encode_get_total_bits_written());
  235. #endif
  236. uint start_bits = codec.encode_get_total_bits_written();
  237. start_bits;
  238. for (uint i = 0; i < residual_syms.size(); i++)
  239. {
  240. const uint sym = residual_syms[i];
  241. const uint table = ((i % 3) == 1) ? 1 : 0;
  242. codec.encode(sym, residual_dm[table]);
  243. }
  244. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  245. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  246. console::debug("Wrote %u bits for color endpoint residuals", codec.encode_get_total_bits_written() - start_bits);
  247. #endif
  248. codec.stop_encoding(false);
  249. data.swap(codec.get_encoding_buf());
  250. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  251. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  252. {
  253. console::debug("Wrote a total of %u bits for color endpoint codebook", codec.encode_get_total_bits_written());
  254. console::debug("Wrote %f bits per each color endpoint", data.size() * 8.0f / m_hvq.get_color_endpoint_codebook_size());
  255. }
  256. #endif
  257. return true;
  258. }
  259. // The indices are only used for statistical purposes.
  260. bool crn_comp::pack_alpha_endpoints(
  261. crnlib::vector<uint8>& data,
  262. const crnlib::vector<uint>& remapping,
  263. const crnlib::vector<uint>& endpoint_indices,
  264. uint trial_index)
  265. {
  266. trial_index;
  267. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  268. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  269. console::debug("pack_alpha_endpoints: %u", trial_index);
  270. #endif
  271. crnlib::vector<uint> remapped_endpoints(m_hvq.get_alpha_endpoint_codebook_size());
  272. for (uint i = 0; i < m_hvq.get_alpha_endpoint_codebook_size(); i++)
  273. remapped_endpoints[remapping[i]] = m_hvq.get_alpha_endpoint(i);
  274. symbol_histogram hist;
  275. hist.resize(256);
  276. #if CRNLIB_CREATE_DEBUG_IMAGES
  277. image_u8 endpoint_image(2, m_hvq.get_alpha_endpoint_codebook_size());
  278. image_u8 endpoint_residual_image(2, m_hvq.get_alpha_endpoint_codebook_size());
  279. #endif
  280. crnlib::vector<uint> residual_syms;
  281. residual_syms.reserve(m_hvq.get_alpha_endpoint_codebook_size()*2*3);
  282. uint prev[2];
  283. utils::zero_object(prev);
  284. int total_residuals = 0;
  285. for (uint endpoint_index = 0; endpoint_index < m_hvq.get_alpha_endpoint_codebook_size(); endpoint_index++)
  286. {
  287. const uint endpoint = remapped_endpoints[endpoint_index];
  288. uint cur[2];
  289. cur[0] = dxt5_block::unpack_endpoint(endpoint, 0);
  290. cur[1] = dxt5_block::unpack_endpoint(endpoint, 1);
  291. #if CRNLIB_CREATE_DEBUG_IMAGES
  292. endpoint_image(0, endpoint_index) = cur[0];
  293. endpoint_image(1, endpoint_index) = cur[1];
  294. #endif
  295. for (uint j = 0; j < 2; j++)
  296. {
  297. int delta = cur[j] - prev[j];
  298. total_residuals += delta*delta;
  299. int sym = delta & 255;
  300. hist.inc_freq(sym);
  301. residual_syms.push_back(sym);
  302. #if CRNLIB_CREATE_DEBUG_IMAGES
  303. endpoint_residual_image(j, endpoint_index) = static_cast<uint8>(sym);
  304. #endif
  305. }
  306. prev[0] = cur[0];
  307. prev[1] = cur[1];
  308. }
  309. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  310. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  311. console::debug("Total endpoint residuals: %i", total_residuals);
  312. #endif
  313. if (endpoint_indices.size() > 1)
  314. {
  315. uint prev_index = remapping[endpoint_indices[0]];
  316. int64 total_delta = 0;
  317. for (uint i = 1; i < endpoint_indices.size(); i++)
  318. {
  319. uint cur_index = remapping[endpoint_indices[i]];
  320. int delta = cur_index - prev_index;
  321. prev_index = cur_index;
  322. total_delta += delta * delta;
  323. }
  324. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  325. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  326. console::debug("Total endpoint index delta: " CRNLIB_INT64_FORMAT_SPECIFIER, total_delta);
  327. #endif
  328. }
  329. #if CRNLIB_CREATE_DEBUG_IMAGES
  330. image_utils::write_to_file(dynamic_string(cVarArg, "alpha_endpoint_residuals_%u.tga", trial_index).get_ptr(), endpoint_residual_image);
  331. image_utils::write_to_file(dynamic_string(cVarArg, "alpha_endpoints_%u.tga", trial_index).get_ptr(), endpoint_image);
  332. #endif
  333. static_huffman_data_model residual_dm;
  334. symbol_codec codec;
  335. codec.start_encoding(1024*1024);
  336. // Transmit residuals
  337. if (!residual_dm.init(true, hist, 15))
  338. return false;
  339. if (!codec.encode_transmit_static_huffman_data_model(residual_dm, false))
  340. return false;
  341. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  342. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  343. console::debug("Wrote %u bits for alpha endpoint residual Huffman tables", codec.encode_get_total_bits_written());
  344. #endif
  345. uint start_bits = codec.encode_get_total_bits_written();
  346. start_bits;
  347. for (uint i = 0; i < residual_syms.size(); i++)
  348. {
  349. const uint sym = residual_syms[i];
  350. codec.encode(sym, residual_dm);
  351. }
  352. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  353. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  354. console::debug("Wrote %u bits for alpha endpoint residuals", codec.encode_get_total_bits_written() - start_bits);
  355. #endif
  356. codec.stop_encoding(false);
  357. data.swap(codec.get_encoding_buf());
  358. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  359. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  360. {
  361. console::debug("Wrote a total of %u bits for alpha endpoint codebook", codec.encode_get_total_bits_written());
  362. console::debug("Wrote %f bits per each alpha endpoint", data.size() * 8.0f / m_hvq.get_alpha_endpoint_codebook_size());
  363. }
  364. #endif
  365. return true;
  366. }
  367. float crn_comp::color_selector_similarity_func(uint index_a, uint index_b, void* pContext)
  368. {
  369. const crnlib::vector<dxt_hc::selectors>& selectors = *static_cast< const crnlib::vector<dxt_hc::selectors>* >(pContext);
  370. const dxt_hc::selectors& selectors_a = selectors[index_a];
  371. const dxt_hc::selectors& selectors_b = selectors[index_b];
  372. int total = 0;
  373. for (uint i = 0; i < 16; i++)
  374. {
  375. int a = g_dxt1_to_linear[selectors_a.get_by_index(i)];
  376. int b = g_dxt1_to_linear[selectors_b.get_by_index(i)];
  377. int delta = a - b;
  378. total += delta*delta;
  379. }
  380. float weight = 1.0f - math::clamp(total * 1.0f/20.0f, 0.0f, 1.0f);
  381. return weight;
  382. }
  383. float crn_comp::alpha_selector_similarity_func(uint index_a, uint index_b, void* pContext)
  384. {
  385. const crnlib::vector<dxt_hc::selectors>& selectors = *static_cast< const crnlib::vector<dxt_hc::selectors>* >(pContext);
  386. const dxt_hc::selectors& selectors_a = selectors[index_a];
  387. const dxt_hc::selectors& selectors_b = selectors[index_b];
  388. int total = 0;
  389. for (uint i = 0; i < 16; i++)
  390. {
  391. int a = g_dxt5_to_linear[selectors_a.get_by_index(i)];
  392. int b = g_dxt5_to_linear[selectors_b.get_by_index(i)];
  393. int delta = a - b;
  394. total += delta*delta;
  395. }
  396. float weight = 1.0f - math::clamp(total * 1.0f/100.0f, 0.0f, 1.0f);
  397. return weight;
  398. }
  399. void crn_comp::sort_selector_codebook(crnlib::vector<uint>& remapping, const crnlib::vector<dxt_hc::selectors>& selectors, const uint8* pTo_linear)
  400. {
  401. remapping.resize(selectors.size());
  402. uint lowest_energy = UINT_MAX;
  403. uint lowest_energy_index = 0;
  404. for (uint i = 0; i < selectors.size(); i++)
  405. {
  406. uint total = 0;
  407. for (uint j = 0; j < 16; j++)
  408. {
  409. int a = pTo_linear[selectors[i].get_by_index(j)];
  410. total += a*a;
  411. }
  412. if (total < lowest_energy)
  413. {
  414. lowest_energy = total;
  415. lowest_energy_index = i;
  416. }
  417. }
  418. uint cur_index = lowest_energy_index;
  419. crnlib::vector<bool> chosen_flags(selectors.size());
  420. uint n = 0;
  421. for ( ; ; )
  422. {
  423. chosen_flags[cur_index] = true;
  424. remapping[cur_index] = n;
  425. n++;
  426. if (n == selectors.size())
  427. break;
  428. uint lowest_error = UINT_MAX;
  429. uint lowest_error_index = 0;
  430. for (uint i = 0; i < selectors.size(); i++)
  431. {
  432. if (chosen_flags[i])
  433. continue;
  434. uint total = 0;
  435. for (uint j = 0; j < 16; j++)
  436. {
  437. int a = pTo_linear[selectors[cur_index].get_by_index(j)];
  438. int b = pTo_linear[selectors[i].get_by_index(j)];
  439. int delta = a - b;
  440. total += delta*delta;
  441. }
  442. if (total < lowest_error)
  443. {
  444. lowest_error = total;
  445. lowest_error_index = i;
  446. }
  447. }
  448. cur_index = lowest_error_index;
  449. }
  450. }
  451. // The indices are only used for statistical purposes.
  452. bool crn_comp::pack_selectors(
  453. crnlib::vector<uint8>& packed_data,
  454. const crnlib::vector<uint>& selector_indices,
  455. const crnlib::vector<dxt_hc::selectors>& selectors,
  456. const crnlib::vector<uint>& remapping,
  457. uint max_selector_value,
  458. const uint8* pTo_linear,
  459. uint trial_index)
  460. {
  461. trial_index;
  462. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  463. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  464. console::debug("pack_selectors: %u", trial_index);
  465. #endif
  466. crnlib::vector<dxt_hc::selectors> remapped_selectors(selectors.size());
  467. for (uint i = 0; i < selectors.size(); i++)
  468. remapped_selectors[remapping[i]] = selectors[i];
  469. #if CRNLIB_CREATE_DEBUG_IMAGES
  470. image_u8 residual_image(16, selectors.size());;
  471. image_u8 selector_image(16, selectors.size());;
  472. #endif
  473. crnlib::vector<uint> residual_syms;
  474. residual_syms.reserve(selectors.size() * 8);
  475. const uint num_baised_selector_values = (max_selector_value * 2 + 1);
  476. symbol_histogram hist(num_baised_selector_values * num_baised_selector_values);
  477. dxt_hc::selectors prev_selectors;
  478. utils::zero_object(prev_selectors);
  479. int total_residuals = 0;
  480. for (uint selector_index = 0; selector_index < selectors.size(); selector_index++)
  481. {
  482. const dxt_hc::selectors& s = remapped_selectors[selector_index];
  483. uint prev_sym = 0;
  484. for (uint i = 0; i < 16; i++)
  485. {
  486. int p = pTo_linear[crnlib_assert_range_incl<uint>(prev_selectors.get_by_index(i), max_selector_value)];
  487. int r = pTo_linear[crnlib_assert_range_incl<uint>(s.get_by_index(i), max_selector_value)] - p;
  488. total_residuals += r*r;
  489. uint sym = r + max_selector_value;
  490. CRNLIB_ASSERT(sym < num_baised_selector_values);
  491. if (i & 1)
  492. {
  493. uint paired_sym = (sym * num_baised_selector_values) + prev_sym;
  494. residual_syms.push_back(paired_sym);
  495. hist.inc_freq(paired_sym);
  496. }
  497. else
  498. prev_sym = sym;
  499. #if CRNLIB_CREATE_DEBUG_IMAGES
  500. selector_image(i, selector_index) = (pTo_linear[crnlib_assert_range_incl<uint>(s.get_by_index(i), max_selector_value)] * 255) / max_selector_value;
  501. residual_image(i, selector_index) = sym;
  502. #endif
  503. }
  504. prev_selectors = s;
  505. }
  506. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  507. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  508. console::debug("Total selector endpoint residuals: %u", total_residuals);
  509. #endif
  510. if (selector_indices.size() > 1)
  511. {
  512. uint prev_index = remapping[selector_indices[1]];
  513. int64 total_delta = 0;
  514. for (uint i = 1; i < selector_indices.size(); i++)
  515. {
  516. uint cur_index = remapping[selector_indices[i]];
  517. int delta = cur_index - prev_index;
  518. prev_index = cur_index;
  519. total_delta += delta * delta;
  520. }
  521. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  522. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  523. console::debug("Total selector index delta: " CRNLIB_INT64_FORMAT_SPECIFIER, total_delta);
  524. #endif
  525. }
  526. #if CRNLIB_CREATE_DEBUG_IMAGES
  527. image_utils::write_to_file(dynamic_string(cVarArg, "selectors_%u_%u.tga", trial_index, max_selector_value).get_ptr(), selector_image);
  528. image_utils::write_to_file(dynamic_string(cVarArg, "selector_residuals_%u_%u.tga", trial_index, max_selector_value).get_ptr(), residual_image);
  529. #endif
  530. static_huffman_data_model residual_dm;
  531. symbol_codec codec;
  532. codec.start_encoding(1024*1024);
  533. // Transmit residuals
  534. if (!residual_dm.init(true, hist, 15))
  535. return false;
  536. if (!codec.encode_transmit_static_huffman_data_model(residual_dm, false))
  537. return false;
  538. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  539. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  540. console::debug("Wrote %u bits for selector residual Huffman tables", codec.encode_get_total_bits_written());
  541. #endif
  542. uint start_bits = codec.encode_get_total_bits_written();
  543. start_bits;
  544. for (uint i = 0; i < residual_syms.size(); i++)
  545. {
  546. const uint sym = residual_syms[i];
  547. codec.encode(sym, residual_dm);
  548. }
  549. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  550. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  551. console::debug("Wrote %u bits for selector residuals", codec.encode_get_total_bits_written() - start_bits);
  552. #endif
  553. codec.stop_encoding(false);
  554. packed_data.swap(codec.get_encoding_buf());
  555. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  556. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  557. {
  558. console::debug("Wrote a total of %u bits for selector codebook", codec.encode_get_total_bits_written());
  559. console::debug("Wrote %f bits per each selector codebook entry", packed_data.size() * 8.0f / selectors.size());
  560. }
  561. #endif
  562. return true;
  563. }
  564. bool crn_comp::pack_chunks(
  565. uint first_chunk, uint num_chunks,
  566. bool clear_histograms,
  567. symbol_codec* pCodec,
  568. const crnlib::vector<uint>* pColor_endpoint_remap,
  569. const crnlib::vector<uint>* pColor_selector_remap,
  570. const crnlib::vector<uint>* pAlpha_endpoint_remap,
  571. const crnlib::vector<uint>* pAlpha_selector_remap)
  572. {
  573. if (!pCodec)
  574. {
  575. m_chunk_encoding_hist.resize(1 << (3 * cEncodingMapNumChunksPerCode));
  576. if (clear_histograms)
  577. m_chunk_encoding_hist.set_all(0);
  578. if (pColor_endpoint_remap)
  579. {
  580. CRNLIB_ASSERT(pColor_endpoint_remap->size() == m_hvq.get_color_endpoint_codebook_size());
  581. m_endpoint_index_hist[0].resize(pColor_endpoint_remap->size());
  582. if (clear_histograms)
  583. m_endpoint_index_hist[0].set_all(0);
  584. }
  585. if (pColor_selector_remap)
  586. {
  587. CRNLIB_ASSERT(pColor_selector_remap->size() == m_hvq.get_color_selector_codebook_size());
  588. m_selector_index_hist[0].resize(pColor_selector_remap->size());
  589. if (clear_histograms)
  590. m_selector_index_hist[0].set_all(0);
  591. }
  592. if (pAlpha_endpoint_remap)
  593. {
  594. CRNLIB_ASSERT(pAlpha_endpoint_remap->size() == m_hvq.get_alpha_endpoint_codebook_size());
  595. m_endpoint_index_hist[1].resize(pAlpha_endpoint_remap->size());
  596. if (clear_histograms)
  597. m_endpoint_index_hist[1].set_all(0);
  598. }
  599. if (pAlpha_selector_remap)
  600. {
  601. CRNLIB_ASSERT(pAlpha_selector_remap->size() == m_hvq.get_alpha_selector_codebook_size());
  602. m_selector_index_hist[1].resize(pAlpha_selector_remap->size());
  603. if (clear_histograms)
  604. m_selector_index_hist[1].set_all(0);
  605. }
  606. }
  607. uint prev_endpoint_index[cNumComps];
  608. utils::zero_object(prev_endpoint_index);
  609. uint prev_selector_index[cNumComps];
  610. utils::zero_object(prev_selector_index);
  611. uint num_encodings_left = 0;
  612. for (uint chunk_index = first_chunk; chunk_index < (first_chunk + num_chunks); chunk_index++)
  613. {
  614. if (!num_encodings_left)
  615. {
  616. uint index = 0;
  617. for (uint i = 0; i < cEncodingMapNumChunksPerCode; i++)
  618. if ((chunk_index + i) < (first_chunk + num_chunks))
  619. index |= (m_hvq.get_chunk_encoding(chunk_index + i).m_encoding_index << (i * 3));
  620. if (pCodec)
  621. pCodec->encode(index, m_chunk_encoding_dm);
  622. else
  623. m_chunk_encoding_hist.inc_freq(index);
  624. num_encodings_left = cEncodingMapNumChunksPerCode;
  625. }
  626. num_encodings_left--;
  627. const dxt_hc::chunk_encoding& encoding = m_hvq.get_chunk_encoding(chunk_index);
  628. const chunk_detail& details = m_chunk_details[chunk_index];
  629. const uint comp_order[3] = { cAlpha0, cAlpha1, cColor };
  630. for (uint c = 0; c < 3; c++)
  631. {
  632. const uint comp_index = comp_order[c];
  633. if (!m_has_comp[comp_index])
  634. continue;
  635. // endpoints
  636. if (comp_index == cColor)
  637. {
  638. if (pColor_endpoint_remap)
  639. {
  640. for (uint i = 0; i < encoding.m_num_tiles; i++)
  641. {
  642. uint cur_endpoint_index = (*pColor_endpoint_remap)[ m_endpoint_indices[cColor][details.m_first_endpoint_index + i] ];
  643. int endpoint_delta = cur_endpoint_index - prev_endpoint_index[cColor];
  644. int sym = endpoint_delta;
  645. if (sym < 0)
  646. sym += pColor_endpoint_remap->size();
  647. CRNLIB_ASSERT(sym >= 0 && sym < (int)pColor_endpoint_remap->size());
  648. if (!pCodec)
  649. m_endpoint_index_hist[cColor].inc_freq(sym);
  650. else
  651. pCodec->encode(sym, m_endpoint_index_dm[0]);
  652. prev_endpoint_index[cColor] = cur_endpoint_index;
  653. }
  654. }
  655. }
  656. else
  657. {
  658. if (pAlpha_endpoint_remap)
  659. {
  660. for (uint i = 0; i < encoding.m_num_tiles; i++)
  661. {
  662. uint cur_endpoint_index = (*pAlpha_endpoint_remap)[m_endpoint_indices[comp_index][details.m_first_endpoint_index + i]];
  663. int endpoint_delta = cur_endpoint_index - prev_endpoint_index[comp_index];
  664. int sym = endpoint_delta;
  665. if (sym < 0)
  666. sym += pAlpha_endpoint_remap->size();
  667. CRNLIB_ASSERT(sym >= 0 && sym < (int)pAlpha_endpoint_remap->size());
  668. if (!pCodec)
  669. m_endpoint_index_hist[1].inc_freq(sym);
  670. else
  671. pCodec->encode(sym, m_endpoint_index_dm[1]);
  672. prev_endpoint_index[comp_index] = cur_endpoint_index;
  673. }
  674. }
  675. }
  676. } // c
  677. // selectors
  678. for (uint y = 0; y < 2; y++)
  679. {
  680. for (uint x = 0; x < 2; x++)
  681. {
  682. for (uint c = 0; c < 3; c++)
  683. {
  684. const uint comp_index = comp_order[c];
  685. if (!m_has_comp[comp_index])
  686. continue;
  687. if (comp_index == cColor)
  688. {
  689. if (pColor_selector_remap)
  690. {
  691. uint cur_selector_index = (*pColor_selector_remap)[ m_selector_indices[cColor][details.m_first_selector_index + x + y * 2] ];
  692. int selector_delta = cur_selector_index - prev_selector_index[cColor];
  693. int sym = selector_delta;
  694. if (sym < 0)
  695. sym += pColor_selector_remap->size();
  696. CRNLIB_ASSERT(sym >= 0 && sym < (int)pColor_selector_remap->size());
  697. if (!pCodec)
  698. m_selector_index_hist[cColor].inc_freq(sym);
  699. else
  700. pCodec->encode(sym, m_selector_index_dm[cColor]);
  701. prev_selector_index[cColor] = cur_selector_index;
  702. }
  703. }
  704. else if (pAlpha_selector_remap)
  705. {
  706. uint cur_selector_index = (*pAlpha_selector_remap)[ m_selector_indices[comp_index][details.m_first_selector_index + x + y * 2] ];
  707. int selector_delta = cur_selector_index - prev_selector_index[comp_index];
  708. int sym = selector_delta;
  709. if (sym < 0)
  710. sym += pAlpha_selector_remap->size();
  711. CRNLIB_ASSERT(sym >= 0 && sym < (int)pAlpha_selector_remap->size());
  712. if (!pCodec)
  713. m_selector_index_hist[1].inc_freq(sym);
  714. else
  715. pCodec->encode(sym, m_selector_index_dm[1]);
  716. prev_selector_index[comp_index] = cur_selector_index;
  717. }
  718. } // c
  719. } // x
  720. } // y
  721. } // chunk_index
  722. return true;
  723. }
  724. bool crn_comp::pack_chunks_simulation(
  725. uint first_chunk, uint num_chunks,
  726. uint& total_bits,
  727. const crnlib::vector<uint>* pColor_endpoint_remap,
  728. const crnlib::vector<uint>* pColor_selector_remap,
  729. const crnlib::vector<uint>* pAlpha_endpoint_remap,
  730. const crnlib::vector<uint>* pAlpha_selector_remap)
  731. {
  732. if (!pack_chunks(first_chunk, num_chunks, true, NULL, pColor_endpoint_remap, pColor_selector_remap, pAlpha_endpoint_remap, pAlpha_selector_remap))
  733. return false;
  734. symbol_codec codec;
  735. codec.start_encoding(2*1024*1024);
  736. codec.encode_enable_simulation(true);
  737. m_chunk_encoding_dm.init(true, m_chunk_encoding_hist, 16);
  738. for (uint i = 0; i < 2; i++)
  739. {
  740. if (m_endpoint_index_hist[i].size())
  741. {
  742. m_endpoint_index_dm[i].init(true, m_endpoint_index_hist[i], 16);
  743. codec.encode_transmit_static_huffman_data_model(m_endpoint_index_dm[i], false);
  744. }
  745. if (m_selector_index_hist[i].size())
  746. {
  747. m_selector_index_dm[i].init(true, m_selector_index_hist[i], 16);
  748. codec.encode_transmit_static_huffman_data_model(m_selector_index_dm[i], false);
  749. }
  750. }
  751. if (!pack_chunks(first_chunk, num_chunks, false, &codec, pColor_endpoint_remap, pColor_selector_remap, pAlpha_endpoint_remap, pAlpha_selector_remap))
  752. return false;
  753. codec.stop_encoding(false);
  754. total_bits = codec.encode_get_total_bits_written();
  755. return true;
  756. }
  757. void crn_comp::append_vec(crnlib::vector<uint8>& a, const void* p, uint size)
  758. {
  759. if (size)
  760. {
  761. uint ofs = a.size();
  762. a.resize(ofs + size);
  763. memcpy(&a[ofs], p, size);
  764. }
  765. }
  766. void crn_comp::append_vec(crnlib::vector<uint8>& a, const crnlib::vector<uint8>& b)
  767. {
  768. if (!b.empty())
  769. {
  770. uint ofs = a.size();
  771. a.resize(ofs + b.size());
  772. memcpy(&a[ofs], &b[0], b.size());
  773. }
  774. }
  775. #if 0
  776. bool crn_comp::init_chunk_encoding_dm()
  777. {
  778. symbol_histogram hist(1 << (3 * cEncodingMapNumChunksPerCode));
  779. for (uint chunk_index = 0; chunk_index < m_hvq.get_num_chunks(); chunk_index += cEncodingMapNumChunksPerCode)
  780. {
  781. uint index = 0;
  782. for (uint i = 0; i < cEncodingMapNumChunksPerCode; i++)
  783. {
  784. if ((chunk_index + i) >= m_hvq.get_num_chunks())
  785. break;
  786. const dxt_hc::chunk_encoding& encoding = m_hvq.get_chunk_encoding(chunk_index + i);
  787. index |= (encoding.m_encoding_index << (i * 3));
  788. }
  789. hist.inc_freq(index);
  790. }
  791. if (!m_chunk_encoding_dm.init(true, hist, 16))
  792. return false;
  793. return true;
  794. }
  795. #endif
  796. bool crn_comp::alias_images()
  797. {
  798. for (uint face_index = 0; face_index < m_pParams->m_faces; face_index++)
  799. {
  800. for (uint level_index = 0; level_index < m_pParams->m_levels; level_index++)
  801. {
  802. const uint width = math::maximum(1U, m_pParams->m_width >> level_index);
  803. const uint height = math::maximum(1U, m_pParams->m_height >> level_index);
  804. if (!m_pParams->m_pImages[face_index][level_index])
  805. return false;
  806. m_images[face_index][level_index].alias((color_quad_u8*)m_pParams->m_pImages[face_index][level_index], width, height);
  807. }
  808. }
  809. image_utils::conversion_type conv_type = image_utils::get_image_conversion_type_from_crn_format((crn_format)m_pParams->m_format);
  810. if (conv_type != image_utils::cConversion_Invalid)
  811. {
  812. for (uint face_index = 0; face_index < m_pParams->m_faces; face_index++)
  813. {
  814. for (uint level_index = 0; level_index < m_pParams->m_levels; level_index++)
  815. {
  816. image_u8 cooked_image(m_images[face_index][level_index]);
  817. image_utils::convert_image(cooked_image, conv_type);
  818. m_images[face_index][level_index].swap(cooked_image);
  819. }
  820. }
  821. }
  822. m_mip_groups.clear();
  823. m_mip_groups.resize(m_pParams->m_levels);
  824. utils::zero_object(m_levels);
  825. uint mip_group = 0;
  826. uint chunk_index = 0;
  827. uint mip_group_chunk_index = 0; (void)mip_group_chunk_index;
  828. for (uint level_index = 0; level_index < m_pParams->m_levels; level_index++)
  829. {
  830. const uint width = math::maximum(1U, m_pParams->m_width >> level_index);
  831. const uint height = math::maximum(1U, m_pParams->m_height >> level_index);
  832. const uint chunk_width = math::align_up_value(width, cChunkPixelWidth) / cChunkPixelWidth;
  833. const uint chunk_height = math::align_up_value(height, cChunkPixelHeight) / cChunkPixelHeight;
  834. const uint num_chunks = m_pParams->m_faces * chunk_width * chunk_height;
  835. m_mip_groups[mip_group].m_first_chunk = chunk_index;
  836. mip_group_chunk_index = 0;
  837. m_mip_groups[mip_group].m_num_chunks += num_chunks;
  838. m_levels[level_index].m_width = width;
  839. m_levels[level_index].m_height = height;
  840. m_levels[level_index].m_chunk_width = chunk_width;
  841. m_levels[level_index].m_chunk_height = chunk_height;
  842. m_levels[level_index].m_first_chunk = chunk_index;
  843. m_levels[level_index].m_num_chunks = num_chunks;
  844. m_levels[level_index].m_group_index = mip_group;
  845. m_levels[level_index].m_group_first_chunk = 0;
  846. chunk_index += num_chunks;
  847. mip_group++;
  848. }
  849. m_total_chunks = chunk_index;
  850. return true;
  851. }
  852. void crn_comp::append_chunks(const image_u8& img, uint num_chunks_x, uint num_chunks_y, dxt_hc::pixel_chunk_vec& chunks, float weight)
  853. {
  854. for (uint y = 0; y < num_chunks_y; y++)
  855. {
  856. int x_start = 0;
  857. int x_end = num_chunks_x;
  858. int x_dir = 1;
  859. if (y & 1)
  860. {
  861. x_start = num_chunks_x - 1;
  862. x_end = -1;
  863. x_dir = -1;
  864. }
  865. for (int x = x_start; x != x_end; x += x_dir)
  866. {
  867. chunks.resize(chunks.size() + 1);
  868. dxt_hc::pixel_chunk& chunk = chunks.back();
  869. chunk.m_weight = weight;
  870. for (uint cy = 0; cy < cChunkPixelHeight; cy++)
  871. {
  872. uint py = y * cChunkPixelHeight + cy;
  873. py = math::minimum(py, img.get_height() - 1);
  874. for (uint cx = 0; cx < cChunkPixelWidth; cx++)
  875. {
  876. uint px = x * cChunkPixelWidth + cx;
  877. px = math::minimum(px, img.get_width() - 1);
  878. chunk(cx, cy) = img(px, py);
  879. }
  880. }
  881. }
  882. }
  883. }
  884. void crn_comp::create_chunks()
  885. {
  886. m_chunks.reserve(m_total_chunks);
  887. m_chunks.resize(0);
  888. for (uint level = 0; level < m_pParams->m_levels; level++)
  889. {
  890. for (uint face = 0; face < m_pParams->m_faces; face++)
  891. {
  892. if (!face)
  893. {
  894. CRNLIB_ASSERT(m_levels[level].m_first_chunk == m_chunks.size());
  895. }
  896. float mip_weight = math::minimum(12.0f, powf( 1.3f, static_cast<float>(level) ) );
  897. //float mip_weight = 1.0f;
  898. append_chunks(m_images[face][level], m_levels[level].m_chunk_width, m_levels[level].m_chunk_height, m_chunks, mip_weight);
  899. }
  900. }
  901. CRNLIB_ASSERT(m_chunks.size() == m_total_chunks);
  902. }
  903. void crn_comp::clear()
  904. {
  905. m_pParams = NULL;
  906. for (uint f = 0; f < cCRNMaxFaces; f++)
  907. for (uint l = 0; l < cCRNMaxLevels; l++)
  908. m_images[f][l].clear();
  909. utils::zero_object(m_levels);
  910. m_mip_groups.clear();
  911. utils::zero_object(m_has_comp);
  912. m_chunk_details.clear();
  913. for (uint i = 0; i < cNumComps; i++)
  914. {
  915. m_endpoint_indices[i].clear();
  916. m_selector_indices[i].clear();
  917. }
  918. m_total_chunks = 0;
  919. m_chunks.clear();
  920. utils::zero_object(m_crn_header);
  921. m_comp_data.clear();
  922. m_hvq.clear();
  923. m_chunk_encoding_hist.clear();
  924. m_chunk_encoding_dm.clear();
  925. for (uint i = 0; i < 2; i++)
  926. {
  927. m_endpoint_index_hist[i].clear();
  928. m_endpoint_index_dm[i].clear();
  929. m_selector_index_hist[i].clear();
  930. m_selector_index_dm[i].clear();
  931. }
  932. for (uint i = 0; i < cCRNMaxLevels; i++)
  933. m_packed_chunks[i].clear();
  934. m_packed_data_models.clear();
  935. m_packed_color_endpoints.clear();
  936. m_packed_color_selectors.clear();
  937. m_packed_alpha_endpoints.clear();
  938. m_packed_alpha_selectors.clear();
  939. }
  940. bool crn_comp::quantize_chunks()
  941. {
  942. dxt_hc::params params;
  943. params.m_adaptive_tile_alpha_psnr_derating = m_pParams->m_crn_adaptive_tile_alpha_psnr_derating;
  944. params.m_adaptive_tile_color_psnr_derating = m_pParams->m_crn_adaptive_tile_color_psnr_derating;
  945. if (m_pParams->m_flags & cCRNCompFlagManualPaletteSizes)
  946. {
  947. params.m_color_endpoint_codebook_size = math::clamp<int>(m_pParams->m_crn_color_endpoint_palette_size, cCRNMinPaletteSize, cCRNMaxPaletteSize);
  948. params.m_color_selector_codebook_size = math::clamp<int>(m_pParams->m_crn_color_selector_palette_size, cCRNMinPaletteSize, cCRNMaxPaletteSize);
  949. params.m_alpha_endpoint_codebook_size = math::clamp<int>(m_pParams->m_crn_alpha_endpoint_palette_size, cCRNMinPaletteSize, cCRNMaxPaletteSize);
  950. params.m_alpha_selector_codebook_size = math::clamp<int>(m_pParams->m_crn_alpha_selector_palette_size, cCRNMinPaletteSize, cCRNMaxPaletteSize);
  951. }
  952. else
  953. {
  954. uint max_codebook_entries = ((m_pParams->m_width + 3) / 4) * ((m_pParams->m_height + 3) / 4);
  955. max_codebook_entries = math::clamp<uint>(max_codebook_entries, cCRNMinPaletteSize, cCRNMaxPaletteSize);
  956. float quality = math::clamp<float>((float)m_pParams->m_quality_level / cCRNMaxQualityLevel, 0.0f, 1.0f);
  957. float color_quality_power_mul = 1.0f;
  958. float alpha_quality_power_mul = 1.0f;
  959. if (m_pParams->m_format == cCRNFmtDXT5_CCxY)
  960. {
  961. color_quality_power_mul = 3.5f;
  962. alpha_quality_power_mul = .35f;
  963. params.m_adaptive_tile_color_psnr_derating = 5.0f;
  964. }
  965. else if (m_pParams->m_format == cCRNFmtDXT5)
  966. color_quality_power_mul = .75f;
  967. float color_endpoint_quality = powf(quality, 1.8f * color_quality_power_mul);
  968. float color_selector_quality = powf(quality, 1.65f * color_quality_power_mul);
  969. params.m_color_endpoint_codebook_size = math::clamp<uint>(math::float_to_uint(.5f + math::lerp<float>(math::maximum<float>(64, cCRNMinPaletteSize), (float)max_codebook_entries, color_endpoint_quality)), cCRNMinPaletteSize, cCRNMaxPaletteSize);
  970. params.m_color_selector_codebook_size = math::clamp<uint>(math::float_to_uint(.5f + math::lerp<float>(math::maximum<float>(96, cCRNMinPaletteSize), (float)max_codebook_entries, color_selector_quality)), cCRNMinPaletteSize, cCRNMaxPaletteSize);
  971. float alpha_endpoint_quality = powf(quality, 2.1f * alpha_quality_power_mul);
  972. float alpha_selector_quality = powf(quality, 1.65f * alpha_quality_power_mul);
  973. params.m_alpha_endpoint_codebook_size = math::clamp<uint>(math::float_to_uint(.5f + math::lerp<float>(math::maximum<float>(24, cCRNMinPaletteSize), (float)max_codebook_entries, alpha_endpoint_quality)), cCRNMinPaletteSize, cCRNMaxPaletteSize);;
  974. params.m_alpha_selector_codebook_size = math::clamp<uint>(math::float_to_uint(.5f + math::lerp<float>(math::maximum<float>(48, cCRNMinPaletteSize), (float)max_codebook_entries, alpha_selector_quality)), cCRNMinPaletteSize, cCRNMaxPaletteSize);;
  975. }
  976. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  977. {
  978. console::debug("Color endpoints: %u", params.m_color_endpoint_codebook_size);
  979. console::debug("Color selectors: %u", params.m_color_selector_codebook_size);
  980. console::debug("Alpha endpoints: %u", params.m_alpha_endpoint_codebook_size);
  981. console::debug("Alpha selectors: %u", params.m_alpha_selector_codebook_size);
  982. }
  983. params.m_hierarchical = (m_pParams->m_flags & cCRNCompFlagHierarchical) != 0;
  984. params.m_perceptual = (m_pParams->m_flags & cCRNCompFlagPerceptual) != 0;
  985. params.m_pProgress_func = m_pParams->m_pProgress_func;
  986. params.m_pProgress_func_data = m_pParams->m_pProgress_func_data;
  987. switch (m_pParams->m_format)
  988. {
  989. case cCRNFmtDXT1:
  990. {
  991. params.m_format = cDXT1;
  992. m_has_comp[cColor] = true;
  993. break;
  994. }
  995. case cCRNFmtDXT3:
  996. {
  997. m_has_comp[cAlpha0] = true;
  998. return false;
  999. }
  1000. case cCRNFmtDXT5:
  1001. {
  1002. params.m_format = cDXT5;
  1003. params.m_alpha_component_indices[0] = m_pParams->m_alpha_component;
  1004. m_has_comp[cColor] = true;
  1005. m_has_comp[cAlpha0] = true;
  1006. break;
  1007. }
  1008. case cCRNFmtDXT5_CCxY:
  1009. {
  1010. params.m_format = cDXT5;
  1011. params.m_alpha_component_indices[0] = 3;
  1012. m_has_comp[cColor] = true;
  1013. m_has_comp[cAlpha0] = true;
  1014. params.m_perceptual = false;
  1015. //params.m_adaptive_tile_color_alpha_weighting_ratio = 1.0f;
  1016. params.m_adaptive_tile_color_alpha_weighting_ratio = 1.5f;
  1017. break;
  1018. }
  1019. case cCRNFmtDXT5_xGBR:
  1020. case cCRNFmtDXT5_AGBR:
  1021. case cCRNFmtDXT5_xGxR:
  1022. {
  1023. params.m_format = cDXT5;
  1024. params.m_alpha_component_indices[0] = 3;
  1025. m_has_comp[cColor] = true;
  1026. m_has_comp[cAlpha0] = true;
  1027. params.m_perceptual = false;
  1028. break;
  1029. }
  1030. case cCRNFmtDXN_XY:
  1031. {
  1032. params.m_format = cDXN_XY;
  1033. params.m_alpha_component_indices[0] = 0;
  1034. params.m_alpha_component_indices[1] = 1;
  1035. m_has_comp[cAlpha0] = true;
  1036. m_has_comp[cAlpha1] = true;
  1037. params.m_perceptual = false;
  1038. break;
  1039. }
  1040. case cCRNFmtDXN_YX:
  1041. {
  1042. params.m_format = cDXN_YX;
  1043. params.m_alpha_component_indices[0] = 1;
  1044. params.m_alpha_component_indices[1] = 0;
  1045. m_has_comp[cAlpha0] = true;
  1046. m_has_comp[cAlpha1] = true;
  1047. params.m_perceptual = false;
  1048. break;
  1049. }
  1050. case cCRNFmtDXT5A:
  1051. {
  1052. params.m_format = cDXT5A;
  1053. params.m_alpha_component_indices[0] = m_pParams->m_alpha_component;
  1054. m_has_comp[cAlpha0] = true;
  1055. params.m_perceptual = false;
  1056. break;
  1057. }
  1058. case cCRNFmtETC1:
  1059. {
  1060. console::warning("crn_comp::quantize_chunks: This class does not support ETC1");
  1061. return false;
  1062. }
  1063. default:
  1064. {
  1065. return false;
  1066. }
  1067. }
  1068. params.m_debugging = (m_pParams->m_flags & cCRNCompFlagDebugging) != 0;
  1069. params.m_num_levels = m_pParams->m_levels;
  1070. for (uint i = 0; i < m_pParams->m_levels; i++)
  1071. {
  1072. params.m_levels[i].m_first_chunk = m_levels[i].m_first_chunk;
  1073. params.m_levels[i].m_num_chunks = m_levels[i].m_num_chunks;
  1074. }
  1075. if (!m_hvq.compress(params, m_total_chunks, &m_chunks[0], m_task_pool))
  1076. return false;
  1077. #if CRNLIB_CREATE_DEBUG_IMAGES
  1078. if (params.m_debugging)
  1079. {
  1080. const dxt_hc::pixel_chunk_vec& pixel_chunks = m_hvq.get_compressed_chunk_pixels_final();
  1081. image_u8 img;
  1082. dxt_hc::create_debug_image_from_chunks((m_pParams->m_width+7)>>3, (m_pParams->m_height+7)>>3, pixel_chunks, &m_hvq.get_chunk_encoding_vec(), img, true, -1);
  1083. image_utils::write_to_file("quantized_chunks.tga", img);
  1084. }
  1085. #endif
  1086. return true;
  1087. }
  1088. void crn_comp::create_chunk_indices()
  1089. {
  1090. m_chunk_details.resize(m_total_chunks);
  1091. for (uint i = 0; i < cNumComps; i++)
  1092. {
  1093. m_endpoint_indices[i].clear();
  1094. m_selector_indices[i].clear();
  1095. }
  1096. for (uint chunk_index = 0; chunk_index < m_total_chunks; chunk_index++)
  1097. {
  1098. const dxt_hc::chunk_encoding& chunk_encoding = m_hvq.get_chunk_encoding(chunk_index);
  1099. for (uint i = 0; i < cNumComps; i++)
  1100. {
  1101. if (m_has_comp[i])
  1102. {
  1103. m_chunk_details[chunk_index].m_first_endpoint_index = m_endpoint_indices[i].size();
  1104. m_chunk_details[chunk_index].m_first_selector_index = m_selector_indices[i].size();
  1105. break;
  1106. }
  1107. }
  1108. for (uint i = 0; i < cNumComps; i++)
  1109. {
  1110. if (!m_has_comp[i])
  1111. continue;
  1112. for (uint tile_index = 0; tile_index < chunk_encoding.m_num_tiles; tile_index++)
  1113. m_endpoint_indices[i].push_back(chunk_encoding.m_endpoint_indices[i][tile_index]);
  1114. for (uint y = 0; y < cChunkBlockHeight; y++)
  1115. for (uint x = 0; x < cChunkBlockWidth; x++)
  1116. m_selector_indices[i].push_back(chunk_encoding.m_selector_indices[i][y][x]);
  1117. }
  1118. }
  1119. }
  1120. struct optimize_color_endpoint_codebook_params
  1121. {
  1122. crnlib::vector<uint>* m_pTrial_color_endpoint_remap;
  1123. uint m_iter_index;
  1124. uint m_max_iter_index;
  1125. };
  1126. void crn_comp::optimize_color_endpoint_codebook_task(uint64 data, void* pData_ptr)
  1127. {
  1128. data;
  1129. optimize_color_endpoint_codebook_params* pParams = reinterpret_cast<optimize_color_endpoint_codebook_params*>(pData_ptr);
  1130. if (pParams->m_iter_index == pParams->m_max_iter_index)
  1131. {
  1132. sort_color_endpoint_codebook(*pParams->m_pTrial_color_endpoint_remap, m_hvq.get_color_endpoint_vec());
  1133. }
  1134. else
  1135. {
  1136. float f = pParams->m_iter_index / static_cast<float>(pParams->m_max_iter_index - 1);
  1137. create_zeng_reorder_table(
  1138. m_hvq.get_color_endpoint_codebook_size(),
  1139. m_endpoint_indices[cColor].size(),
  1140. &m_endpoint_indices[cColor][0],
  1141. *pParams->m_pTrial_color_endpoint_remap,
  1142. pParams->m_iter_index ? color_endpoint_similarity_func : NULL,
  1143. &m_hvq,
  1144. f);
  1145. }
  1146. crnlib_delete(pParams);
  1147. }
  1148. bool crn_comp::optimize_color_endpoint_codebook(crnlib::vector<uint>& remapping)
  1149. {
  1150. if (m_pParams->m_flags & cCRNCompFlagQuick)
  1151. {
  1152. remapping.resize(m_hvq.get_color_endpoint_vec().size());
  1153. for (uint i = 0; i < m_hvq.get_color_endpoint_vec().size(); i++)
  1154. remapping[i] = i;
  1155. if (!pack_color_endpoints(m_packed_color_endpoints, remapping, m_endpoint_indices[cColor], 0))
  1156. return false;
  1157. return true;
  1158. }
  1159. const uint cMaxEndpointRemapIters = 3;
  1160. uint best_bits = UINT_MAX;
  1161. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  1162. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  1163. console::debug("----- Begin optimization of color endpoint codebook");
  1164. #endif
  1165. crnlib::vector<uint> trial_color_endpoint_remaps[cMaxEndpointRemapIters + 1];
  1166. for (uint i = 0; i <= cMaxEndpointRemapIters; i++)
  1167. {
  1168. optimize_color_endpoint_codebook_params* pParams = crnlib_new<optimize_color_endpoint_codebook_params>();
  1169. pParams->m_iter_index = i;
  1170. pParams->m_max_iter_index = cMaxEndpointRemapIters;
  1171. pParams->m_pTrial_color_endpoint_remap = &trial_color_endpoint_remaps[i];
  1172. m_task_pool.queue_object_task(this, &crn_comp::optimize_color_endpoint_codebook_task, 0, pParams);
  1173. }
  1174. m_task_pool.join();
  1175. for (uint i = 0; i <= cMaxEndpointRemapIters; i++)
  1176. {
  1177. if (!update_progress(20, i, cMaxEndpointRemapIters+1))
  1178. return false;
  1179. crnlib::vector<uint>& trial_color_endpoint_remap = trial_color_endpoint_remaps[i];
  1180. crnlib::vector<uint8> packed_data;
  1181. if (!pack_color_endpoints(packed_data, trial_color_endpoint_remap, m_endpoint_indices[cColor], i))
  1182. return false;
  1183. uint total_packed_chunk_bits;
  1184. if (!pack_chunks_simulation(0, m_total_chunks, total_packed_chunk_bits, &trial_color_endpoint_remap, NULL, NULL, NULL))
  1185. return false;
  1186. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  1187. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  1188. console::debug("Pack chunks simulation: %u bits", total_packed_chunk_bits);
  1189. #endif
  1190. uint total_bits = packed_data.size() * 8 + total_packed_chunk_bits;
  1191. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  1192. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  1193. console::debug("Total bits: %u", total_bits);
  1194. #endif
  1195. if (total_bits < best_bits)
  1196. {
  1197. m_packed_color_endpoints.swap(packed_data);
  1198. remapping.swap(trial_color_endpoint_remap);
  1199. best_bits = total_bits;
  1200. }
  1201. }
  1202. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  1203. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  1204. console::debug("End optimization of color endpoint codebook");
  1205. #endif
  1206. return true;
  1207. }
  1208. struct optimize_color_selector_codebook_params
  1209. {
  1210. crnlib::vector<uint>* m_pTrial_color_selector_remap;
  1211. uint m_iter_index;
  1212. uint m_max_iter_index;
  1213. };
  1214. void crn_comp::optimize_color_selector_codebook_task(uint64 data, void* pData_ptr)
  1215. {
  1216. data;
  1217. optimize_color_selector_codebook_params* pParams = reinterpret_cast<optimize_color_selector_codebook_params*>(pData_ptr);
  1218. if (pParams->m_iter_index == pParams->m_max_iter_index)
  1219. {
  1220. sort_selector_codebook(*pParams->m_pTrial_color_selector_remap, m_hvq.get_color_selectors_vec(), g_dxt1_to_linear);
  1221. }
  1222. else
  1223. {
  1224. float f = pParams->m_iter_index / static_cast<float>(pParams->m_max_iter_index - 1);
  1225. create_zeng_reorder_table(
  1226. m_hvq.get_color_selector_codebook_size(),
  1227. m_selector_indices[cColor].size(),
  1228. &m_selector_indices[cColor][0],
  1229. *pParams->m_pTrial_color_selector_remap,
  1230. pParams->m_iter_index ? color_selector_similarity_func : NULL,
  1231. (void*)&m_hvq.get_color_selectors_vec(),
  1232. f);
  1233. }
  1234. crnlib_delete(pParams);
  1235. }
  1236. bool crn_comp::optimize_color_selector_codebook(crnlib::vector<uint>& remapping)
  1237. {
  1238. if (m_pParams->m_flags & cCRNCompFlagQuick)
  1239. {
  1240. remapping.resize(m_hvq.get_color_selectors_vec().size());
  1241. for (uint i = 0; i < m_hvq.get_color_selectors_vec().size(); i++)
  1242. remapping[i] = i;
  1243. if (!pack_selectors(
  1244. m_packed_color_selectors,
  1245. m_selector_indices[cColor],
  1246. m_hvq.get_color_selectors_vec(),
  1247. remapping,
  1248. 3,
  1249. g_dxt1_to_linear, 0))
  1250. {
  1251. return false;
  1252. }
  1253. return true;
  1254. }
  1255. const uint cMaxSelectorRemapIters = 3;
  1256. uint best_bits = UINT_MAX;
  1257. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  1258. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  1259. console::debug("----- Begin optimization of color selector codebook");
  1260. #endif
  1261. crnlib::vector<uint> trial_color_selector_remaps[cMaxSelectorRemapIters + 1];
  1262. for (uint i = 0; i <= cMaxSelectorRemapIters; i++)
  1263. {
  1264. optimize_color_selector_codebook_params* pParams = crnlib_new<optimize_color_selector_codebook_params>();
  1265. pParams->m_iter_index = i;
  1266. pParams->m_max_iter_index = cMaxSelectorRemapIters;
  1267. pParams->m_pTrial_color_selector_remap = &trial_color_selector_remaps[i];
  1268. m_task_pool.queue_object_task(this, &crn_comp::optimize_color_selector_codebook_task, 0, pParams);
  1269. }
  1270. m_task_pool.join();
  1271. for (uint i = 0; i <= cMaxSelectorRemapIters; i++)
  1272. {
  1273. if (!update_progress(21, i, cMaxSelectorRemapIters+1))
  1274. return false;
  1275. crnlib::vector<uint>& trial_color_selector_remap = trial_color_selector_remaps[i];
  1276. crnlib::vector<uint8> packed_data;
  1277. if (!pack_selectors(
  1278. packed_data,
  1279. m_selector_indices[cColor],
  1280. m_hvq.get_color_selectors_vec(),
  1281. trial_color_selector_remap,
  1282. 3,
  1283. g_dxt1_to_linear, i))
  1284. {
  1285. return false;
  1286. }
  1287. uint total_packed_chunk_bits;
  1288. if (!pack_chunks_simulation(0, m_total_chunks, total_packed_chunk_bits, NULL, &trial_color_selector_remap, NULL, NULL))
  1289. return false;
  1290. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  1291. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  1292. console::debug("Pack chunks simulation: %u bits", total_packed_chunk_bits);
  1293. #endif
  1294. uint total_bits = packed_data.size() * 8 + total_packed_chunk_bits;
  1295. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  1296. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  1297. console::debug("Total bits: %u", total_bits);
  1298. #endif
  1299. if (total_bits < best_bits)
  1300. {
  1301. m_packed_color_selectors.swap(packed_data);
  1302. remapping.swap(trial_color_selector_remap);
  1303. best_bits = total_bits;
  1304. }
  1305. }
  1306. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  1307. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  1308. console::debug("End optimization of color selector codebook");
  1309. #endif
  1310. return true;
  1311. }
  1312. struct optimize_alpha_endpoint_codebook_params
  1313. {
  1314. crnlib::vector<uint>* m_pAlpha_indices;
  1315. crnlib::vector<uint>* m_pTrial_alpha_endpoint_remap;
  1316. uint m_iter_index;
  1317. uint m_max_iter_index;
  1318. };
  1319. void crn_comp::optimize_alpha_endpoint_codebook_task(uint64 data, void* pData_ptr)
  1320. {
  1321. data;
  1322. optimize_alpha_endpoint_codebook_params* pParams = reinterpret_cast<optimize_alpha_endpoint_codebook_params*>(pData_ptr);
  1323. if (pParams->m_iter_index == pParams->m_max_iter_index)
  1324. {
  1325. sort_alpha_endpoint_codebook(*pParams->m_pTrial_alpha_endpoint_remap, m_hvq.get_alpha_endpoint_vec());
  1326. }
  1327. else
  1328. {
  1329. float f = pParams->m_iter_index / static_cast<float>(pParams->m_max_iter_index - 1);
  1330. create_zeng_reorder_table(
  1331. m_hvq.get_alpha_endpoint_codebook_size(),
  1332. pParams->m_pAlpha_indices->size(),
  1333. &(*pParams->m_pAlpha_indices)[0],
  1334. *pParams->m_pTrial_alpha_endpoint_remap,
  1335. pParams->m_iter_index ? alpha_endpoint_similarity_func : NULL,
  1336. &m_hvq,
  1337. f);
  1338. }
  1339. crnlib_delete(pParams);
  1340. }
  1341. bool crn_comp::optimize_alpha_endpoint_codebook(crnlib::vector<uint>& remapping)
  1342. {
  1343. crnlib::vector<uint> alpha_indices;
  1344. alpha_indices.reserve(m_endpoint_indices[cAlpha0].size() + m_endpoint_indices[cAlpha1].size());
  1345. for (uint i = 0; i < m_endpoint_indices[cAlpha0].size(); i++)
  1346. alpha_indices.push_back(m_endpoint_indices[cAlpha0][i]);
  1347. for (uint i = 0; i < m_endpoint_indices[cAlpha1].size(); i++)
  1348. alpha_indices.push_back(m_endpoint_indices[cAlpha1][i]);
  1349. if (m_pParams->m_flags & cCRNCompFlagQuick)
  1350. {
  1351. remapping.resize(m_hvq.get_alpha_endpoint_vec().size());
  1352. for (uint i = 0; i < m_hvq.get_alpha_endpoint_vec().size(); i++)
  1353. remapping[i] = i;
  1354. if (!pack_alpha_endpoints(m_packed_alpha_endpoints, remapping, alpha_indices, 0))
  1355. return false;
  1356. return true;
  1357. }
  1358. const uint cMaxEndpointRemapIters = 3;
  1359. uint best_bits = UINT_MAX;
  1360. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  1361. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  1362. console::debug("----- Begin optimization of alpha endpoint codebook");
  1363. #endif
  1364. crnlib::vector<uint> trial_alpha_endpoint_remaps[cMaxEndpointRemapIters + 1];
  1365. for (uint i = 0; i <= cMaxEndpointRemapIters; i++)
  1366. {
  1367. optimize_alpha_endpoint_codebook_params* pParams = crnlib_new<optimize_alpha_endpoint_codebook_params>();
  1368. pParams->m_pAlpha_indices = &alpha_indices;
  1369. pParams->m_iter_index = i;
  1370. pParams->m_max_iter_index = cMaxEndpointRemapIters;
  1371. pParams->m_pTrial_alpha_endpoint_remap = &trial_alpha_endpoint_remaps[i];
  1372. m_task_pool.queue_object_task(this, &crn_comp::optimize_alpha_endpoint_codebook_task, 0, pParams);
  1373. }
  1374. m_task_pool.join();
  1375. for (uint i = 0; i <= cMaxEndpointRemapIters; i++)
  1376. {
  1377. if (!update_progress(22, i, cMaxEndpointRemapIters+1))
  1378. return false;
  1379. crnlib::vector<uint>& trial_alpha_endpoint_remap = trial_alpha_endpoint_remaps[i];
  1380. crnlib::vector<uint8> packed_data;
  1381. if (!pack_alpha_endpoints(packed_data, trial_alpha_endpoint_remap, alpha_indices, i))
  1382. return false;
  1383. uint total_packed_chunk_bits;
  1384. if (!pack_chunks_simulation(0, m_total_chunks, total_packed_chunk_bits, NULL, NULL, &trial_alpha_endpoint_remap, NULL))
  1385. return false;
  1386. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  1387. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  1388. console::debug("Pack chunks simulation: %u bits", total_packed_chunk_bits);
  1389. #endif
  1390. uint total_bits = packed_data.size() * 8 + total_packed_chunk_bits;
  1391. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  1392. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  1393. console::debug("Total bits: %u", total_bits);
  1394. #endif
  1395. if (total_bits < best_bits)
  1396. {
  1397. m_packed_alpha_endpoints.swap(packed_data);
  1398. remapping.swap(trial_alpha_endpoint_remap);
  1399. best_bits = total_bits;
  1400. }
  1401. }
  1402. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  1403. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  1404. console::debug("End optimization of alpha endpoint codebook");
  1405. #endif
  1406. return true;
  1407. }
  1408. struct optimize_alpha_selector_codebook_params
  1409. {
  1410. crnlib::vector<uint>* m_pAlpha_indices;
  1411. crnlib::vector<uint>* m_pTrial_alpha_selector_remap;
  1412. uint m_iter_index;
  1413. uint m_max_iter_index;
  1414. };
  1415. void crn_comp::optimize_alpha_selector_codebook_task(uint64 data, void* pData_ptr)
  1416. {
  1417. data;
  1418. optimize_alpha_selector_codebook_params* pParams = reinterpret_cast<optimize_alpha_selector_codebook_params*>(pData_ptr);
  1419. if (pParams->m_iter_index == pParams->m_max_iter_index)
  1420. {
  1421. sort_selector_codebook(*pParams->m_pTrial_alpha_selector_remap, m_hvq.get_alpha_selectors_vec(), g_dxt5_to_linear);
  1422. }
  1423. else
  1424. {
  1425. float f = pParams->m_iter_index / static_cast<float>(pParams->m_max_iter_index - 1);
  1426. create_zeng_reorder_table(
  1427. m_hvq.get_alpha_selector_codebook_size(),
  1428. pParams->m_pAlpha_indices->size(),
  1429. &(*pParams->m_pAlpha_indices)[0],
  1430. *pParams->m_pTrial_alpha_selector_remap,
  1431. pParams->m_iter_index ? alpha_selector_similarity_func : NULL,
  1432. (void*)&m_hvq.get_alpha_selectors_vec(),
  1433. f);
  1434. }
  1435. }
  1436. bool crn_comp::optimize_alpha_selector_codebook(crnlib::vector<uint>& remapping)
  1437. {
  1438. crnlib::vector<uint> alpha_indices;
  1439. alpha_indices.reserve(m_selector_indices[cAlpha0].size() + m_selector_indices[cAlpha1].size());
  1440. for (uint i = 0; i < m_selector_indices[cAlpha0].size(); i++)
  1441. alpha_indices.push_back(m_selector_indices[cAlpha0][i]);
  1442. for (uint i = 0; i < m_selector_indices[cAlpha1].size(); i++)
  1443. alpha_indices.push_back(m_selector_indices[cAlpha1][i]);
  1444. if (m_pParams->m_flags & cCRNCompFlagQuick)
  1445. {
  1446. remapping.resize(m_hvq.get_alpha_selectors_vec().size());
  1447. for (uint i = 0; i < m_hvq.get_alpha_selectors_vec().size(); i++)
  1448. remapping[i] = i;
  1449. if (!pack_selectors(
  1450. m_packed_alpha_selectors,
  1451. alpha_indices,
  1452. m_hvq.get_alpha_selectors_vec(),
  1453. remapping,
  1454. 7,
  1455. g_dxt5_to_linear, 0))
  1456. {
  1457. return false;
  1458. }
  1459. return true;
  1460. }
  1461. const uint cMaxSelectorRemapIters = 3;
  1462. uint best_bits = UINT_MAX;
  1463. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  1464. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  1465. console::debug("----- Begin optimization of alpha selector codebook");
  1466. #endif
  1467. crnlib::vector<uint> trial_alpha_selector_remaps[cMaxSelectorRemapIters + 1];
  1468. for (uint i = 0; i <= cMaxSelectorRemapIters; i++)
  1469. {
  1470. optimize_alpha_selector_codebook_params* pParams = crnlib_new<optimize_alpha_selector_codebook_params>();
  1471. pParams->m_pAlpha_indices = &alpha_indices;
  1472. pParams->m_iter_index = i;
  1473. pParams->m_max_iter_index = cMaxSelectorRemapIters;
  1474. pParams->m_pTrial_alpha_selector_remap = &trial_alpha_selector_remaps[i];
  1475. m_task_pool.queue_object_task(this, &crn_comp::optimize_alpha_selector_codebook_task, 0, pParams);
  1476. }
  1477. m_task_pool.join();
  1478. for (uint i = 0; i <= cMaxSelectorRemapIters; i++)
  1479. {
  1480. if (!update_progress(23, i, cMaxSelectorRemapIters+1))
  1481. return false;
  1482. crnlib::vector<uint>& trial_alpha_selector_remap = trial_alpha_selector_remaps[i];
  1483. crnlib::vector<uint8> packed_data;
  1484. if (!pack_selectors(
  1485. packed_data,
  1486. alpha_indices,
  1487. m_hvq.get_alpha_selectors_vec(),
  1488. trial_alpha_selector_remap,
  1489. 7,
  1490. g_dxt5_to_linear, i))
  1491. {
  1492. return false;
  1493. }
  1494. uint total_packed_chunk_bits;
  1495. if (!pack_chunks_simulation(0, m_total_chunks, total_packed_chunk_bits, NULL, NULL, NULL, &trial_alpha_selector_remap))
  1496. return false;
  1497. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  1498. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  1499. console::debug("Pack chunks simulation: %u bits", total_packed_chunk_bits);
  1500. #endif
  1501. uint total_bits = packed_data.size() * 8 + total_packed_chunk_bits;
  1502. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  1503. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  1504. console::debug("Total bits: %u", total_bits);
  1505. #endif
  1506. if (total_bits < best_bits)
  1507. {
  1508. m_packed_alpha_selectors.swap(packed_data);
  1509. remapping.swap(trial_alpha_selector_remap);
  1510. best_bits = total_bits;
  1511. }
  1512. }
  1513. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  1514. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  1515. console::debug("End optimization of alpha selector codebook");
  1516. #endif
  1517. return true;
  1518. }
  1519. bool crn_comp::pack_data_models()
  1520. {
  1521. symbol_codec codec;
  1522. codec.start_encoding(1024*1024);
  1523. if (!codec.encode_transmit_static_huffman_data_model(m_chunk_encoding_dm, false))
  1524. return false;
  1525. for (uint i = 0; i < 2; i++)
  1526. {
  1527. if (m_endpoint_index_dm[i].get_total_syms())
  1528. {
  1529. if (!codec.encode_transmit_static_huffman_data_model(m_endpoint_index_dm[i], false))
  1530. return false;
  1531. }
  1532. if (m_selector_index_dm[i].get_total_syms())
  1533. {
  1534. if (!codec.encode_transmit_static_huffman_data_model(m_selector_index_dm[i], false))
  1535. return false;
  1536. }
  1537. }
  1538. codec.stop_encoding(false);
  1539. m_packed_data_models.swap(codec.get_encoding_buf());
  1540. return true;
  1541. }
  1542. bool crn_comp::create_comp_data()
  1543. {
  1544. utils::zero_object(m_crn_header);
  1545. m_crn_header.m_width = static_cast<uint16>(m_pParams->m_width);
  1546. m_crn_header.m_height = static_cast<uint16>(m_pParams->m_height);
  1547. m_crn_header.m_levels = static_cast<uint8>(m_pParams->m_levels);
  1548. m_crn_header.m_faces = static_cast<uint8>(m_pParams->m_faces);
  1549. m_crn_header.m_format = static_cast<uint8>(m_pParams->m_format);
  1550. m_crn_header.m_userdata0 = m_pParams->m_userdata0;
  1551. m_crn_header.m_userdata1 = m_pParams->m_userdata1;
  1552. m_comp_data.clear();
  1553. m_comp_data.reserve(2*1024*1024);
  1554. append_vec(m_comp_data, &m_crn_header, sizeof(m_crn_header));
  1555. // tack on the rest of the variable size m_level_ofs array
  1556. m_comp_data.resize( m_comp_data.size() + sizeof(m_crn_header.m_level_ofs[0]) * (m_pParams->m_levels - 1) );
  1557. if (m_packed_color_endpoints.size())
  1558. {
  1559. m_crn_header.m_color_endpoints.m_num = static_cast<uint16>(m_hvq.get_color_endpoint_codebook_size());
  1560. m_crn_header.m_color_endpoints.m_size = m_packed_color_endpoints.size();
  1561. m_crn_header.m_color_endpoints.m_ofs = m_comp_data.size();
  1562. append_vec(m_comp_data, m_packed_color_endpoints);
  1563. }
  1564. if (m_packed_color_selectors.size())
  1565. {
  1566. m_crn_header.m_color_selectors.m_num = static_cast<uint16>(m_hvq.get_color_selector_codebook_size());
  1567. m_crn_header.m_color_selectors.m_size = m_packed_color_selectors.size();
  1568. m_crn_header.m_color_selectors.m_ofs = m_comp_data.size();
  1569. append_vec(m_comp_data, m_packed_color_selectors);
  1570. }
  1571. if (m_packed_alpha_endpoints.size())
  1572. {
  1573. m_crn_header.m_alpha_endpoints.m_num = static_cast<uint16>(m_hvq.get_alpha_endpoint_codebook_size());
  1574. m_crn_header.m_alpha_endpoints.m_size = m_packed_alpha_endpoints.size();
  1575. m_crn_header.m_alpha_endpoints.m_ofs = m_comp_data.size();
  1576. append_vec(m_comp_data, m_packed_alpha_endpoints);
  1577. }
  1578. if (m_packed_alpha_selectors.size())
  1579. {
  1580. m_crn_header.m_alpha_selectors.m_num = static_cast<uint16>(m_hvq.get_alpha_selector_codebook_size());
  1581. m_crn_header.m_alpha_selectors.m_size = m_packed_alpha_selectors.size();
  1582. m_crn_header.m_alpha_selectors.m_ofs = m_comp_data.size();
  1583. append_vec(m_comp_data, m_packed_alpha_selectors);
  1584. }
  1585. m_crn_header.m_tables_ofs = m_comp_data.size();
  1586. m_crn_header.m_tables_size = m_packed_data_models.size();
  1587. append_vec(m_comp_data, m_packed_data_models);
  1588. uint level_ofs[cCRNMaxLevels];
  1589. for (uint i = 0; i < m_mip_groups.size(); i++)
  1590. {
  1591. level_ofs[i] = m_comp_data.size();
  1592. append_vec(m_comp_data, m_packed_chunks[i]);
  1593. }
  1594. crnd::crn_header& dst_header = *(crnd::crn_header*)&m_comp_data[0];
  1595. // don't change the m_comp_data vector - or dst_header will be invalidated!
  1596. memcpy(&dst_header, &m_crn_header, sizeof(dst_header));
  1597. for (uint i = 0; i < m_mip_groups.size(); i++)
  1598. dst_header.m_level_ofs[i] = level_ofs[i];
  1599. const uint actual_header_size = sizeof(crnd::crn_header) + sizeof(dst_header.m_level_ofs[0]) * (m_mip_groups.size() - 1);
  1600. dst_header.m_sig = crnd::crn_header::cCRNSigValue;
  1601. dst_header.m_data_size = m_comp_data.size();
  1602. dst_header.m_data_crc16 = crc16(&m_comp_data[actual_header_size], m_comp_data.size() - actual_header_size);
  1603. dst_header.m_header_size = actual_header_size;
  1604. dst_header.m_header_crc16 = crc16(&dst_header.m_data_size, actual_header_size - (uint)((uint8*)&dst_header.m_data_size - (uint8*)&dst_header));
  1605. return true;
  1606. }
  1607. bool crn_comp::update_progress(uint phase_index, uint subphase_index, uint subphase_total)
  1608. {
  1609. if (!m_pParams->m_pProgress_func)
  1610. return true;
  1611. #if CRNLIB_ENABLE_DEBUG_MESSAGES
  1612. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  1613. return true;
  1614. #endif
  1615. return (*m_pParams->m_pProgress_func)(phase_index, cTotalCompressionPhases, subphase_index, subphase_total, m_pParams->m_pProgress_func_data) != 0;
  1616. }
  1617. bool crn_comp::compress_internal()
  1618. {
  1619. if (!alias_images())
  1620. return false;
  1621. create_chunks();
  1622. if (!quantize_chunks())
  1623. return false;
  1624. create_chunk_indices();
  1625. crnlib::vector<uint> endpoint_remap[2];
  1626. crnlib::vector<uint> selector_remap[2];
  1627. if (m_has_comp[cColor])
  1628. {
  1629. if (!optimize_color_endpoint_codebook(endpoint_remap[0]))
  1630. return false;
  1631. if (!optimize_color_selector_codebook(selector_remap[0]))
  1632. return false;
  1633. }
  1634. if (m_has_comp[cAlpha0])
  1635. {
  1636. if (!optimize_alpha_endpoint_codebook(endpoint_remap[1]))
  1637. return false;
  1638. if (!optimize_alpha_selector_codebook(selector_remap[1]))
  1639. return false;
  1640. }
  1641. m_chunk_encoding_hist.clear();
  1642. for (uint i = 0; i < 2; i++)
  1643. {
  1644. m_endpoint_index_hist[i].clear();
  1645. m_endpoint_index_dm[i].clear();
  1646. m_selector_index_hist[i].clear();
  1647. m_selector_index_dm[i].clear();
  1648. }
  1649. for (uint pass = 0; pass < 2; pass++)
  1650. {
  1651. for (uint mip_group = 0; mip_group < m_mip_groups.size(); mip_group++)
  1652. {
  1653. symbol_codec codec;
  1654. codec.start_encoding(2*1024*1024);
  1655. if (!pack_chunks(
  1656. m_mip_groups[mip_group].m_first_chunk, m_mip_groups[mip_group].m_num_chunks,
  1657. !pass && !mip_group, pass ? &codec : NULL,
  1658. m_has_comp[cColor] ? &endpoint_remap[0] : NULL, m_has_comp[cColor] ? &selector_remap[0] : NULL,
  1659. m_has_comp[cAlpha0] ? &endpoint_remap[1] : NULL, m_has_comp[cAlpha0] ? &selector_remap[1] : NULL))
  1660. {
  1661. return false;
  1662. }
  1663. codec.stop_encoding(false);
  1664. if (pass)
  1665. m_packed_chunks[mip_group].swap(codec.get_encoding_buf());
  1666. }
  1667. if (!pass)
  1668. {
  1669. m_chunk_encoding_dm.init(true, m_chunk_encoding_hist, 16);
  1670. for (uint i = 0; i < 2; i++)
  1671. {
  1672. if (m_endpoint_index_hist[i].size())
  1673. m_endpoint_index_dm[i].init(true, m_endpoint_index_hist[i], 16);
  1674. if (m_selector_index_hist[i].size())
  1675. m_selector_index_dm[i].init(true, m_selector_index_hist[i], 16);
  1676. }
  1677. }
  1678. }
  1679. if (!pack_data_models())
  1680. return false;
  1681. if (!create_comp_data())
  1682. return false;
  1683. if (!update_progress(24, 1, 1))
  1684. return false;
  1685. if (m_pParams->m_flags & cCRNCompFlagDebugging)
  1686. {
  1687. crnlib_print_mem_stats();
  1688. }
  1689. return true;
  1690. }
  1691. bool crn_comp::compress_init(const crn_comp_params& params)
  1692. {
  1693. params;
  1694. return true;
  1695. }
  1696. bool crn_comp::compress_pass(const crn_comp_params& params, float *pEffective_bitrate)
  1697. {
  1698. clear();
  1699. if (pEffective_bitrate) *pEffective_bitrate = 0.0f;
  1700. m_pParams = &params;
  1701. if ((math::minimum(m_pParams->m_width, m_pParams->m_height) < 1) || (math::maximum(m_pParams->m_width, m_pParams->m_height) > cCRNMaxLevelResolution))
  1702. return false;
  1703. if (!m_task_pool.init(params.m_num_helper_threads))
  1704. return false;
  1705. bool status = compress_internal();
  1706. m_task_pool.deinit();
  1707. if ((status) && (pEffective_bitrate))
  1708. {
  1709. uint total_pixels = 0;
  1710. for (uint f = 0; f < m_pParams->m_faces; f++)
  1711. for (uint l = 0; l < m_pParams->m_levels; l++)
  1712. total_pixels += m_images[f][l].get_total_pixels();
  1713. *pEffective_bitrate = (m_comp_data.size() * 8.0f) / total_pixels;
  1714. }
  1715. return status;
  1716. }
  1717. void crn_comp::compress_deinit()
  1718. {
  1719. }
  1720. } // namespace crnlib