EtcImage.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. /*
  2. * Copyright 2015 The Etc2Comp Authors.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. EtcImage.cpp
  18. Image is an array of 4x4 blocks that represent the encoding of the source image
  19. */
  20. #include "EtcConfig.h"
  21. #include <stdlib.h>
  22. #include "EtcImage.h"
  23. #include "Etc.h"
  24. #include "EtcBlock4x4.h"
  25. #include "EtcBlock4x4EncodingBits.h"
  26. #include "EtcSortedBlockList.h"
  27. #if ETC_WINDOWS
  28. #include <windows.h>
  29. #endif
  30. #include <ctime>
  31. #include <chrono>
  32. #include <future>
  33. #include <stdio.h>
  34. #include <string.h>
  35. #include <assert.h>
  36. // fix conflict with Block4x4::AlphaMix
  37. #ifdef OPAQUE
  38. #undef OPAQUE
  39. #endif
  40. #ifdef TRANSPARENT
  41. #undef TRANSPARENT
  42. #endif
  43. namespace Etc
  44. {
  45. // ----------------------------------------------------------------------------------------------------
  46. //
  47. Image::Image(void)
  48. {
  49. m_encodingStatus = EncodingStatus::SUCCESS;
  50. m_warningsToCapture = EncodingStatus::SUCCESS;
  51. m_pafrgbaSource = nullptr;
  52. m_pablock = nullptr;
  53. m_encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN;
  54. m_uiEncodingBitsBytes = 0;
  55. m_paucEncodingBits = nullptr;
  56. m_format = Format::UNKNOWN;
  57. m_iNumOpaquePixels = 0;
  58. m_iNumTranslucentPixels = 0;
  59. m_iNumTransparentPixels = 0;
  60. }
  61. // ----------------------------------------------------------------------------------------------------
  62. // constructor using source image
  63. // used to set state before Encode() is called
  64. //
  65. Image::Image(float *a_pafSourceRGBA, unsigned int a_uiSourceWidth,
  66. unsigned int a_uiSourceHeight,
  67. ErrorMetric a_errormetric)
  68. {
  69. m_encodingStatus = EncodingStatus::SUCCESS;
  70. m_warningsToCapture = EncodingStatus::SUCCESS;
  71. m_pafrgbaSource = (ColorFloatRGBA *) a_pafSourceRGBA;
  72. m_uiSourceWidth = a_uiSourceWidth;
  73. m_uiSourceHeight = a_uiSourceHeight;
  74. m_uiExtendedWidth = CalcExtendedDimension((unsigned short)m_uiSourceWidth);
  75. m_uiExtendedHeight = CalcExtendedDimension((unsigned short)m_uiSourceHeight);
  76. m_uiBlockColumns = m_uiExtendedWidth >> 2;
  77. m_uiBlockRows = m_uiExtendedHeight >> 2;
  78. m_pablock = new Block4x4[GetNumberOfBlocks()];
  79. assert(m_pablock);
  80. m_format = Format::UNKNOWN;
  81. m_encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN;
  82. m_uiEncodingBitsBytes = 0;
  83. m_paucEncodingBits = nullptr;
  84. m_errormetric = a_errormetric;
  85. m_fEffort = 0.0f;
  86. m_iEncodeTime_ms = -1;
  87. m_iNumOpaquePixels = 0;
  88. m_iNumTranslucentPixels = 0;
  89. m_iNumTransparentPixels = 0;
  90. m_bVerboseOutput = false;
  91. }
  92. // ----------------------------------------------------------------------------------------------------
  93. // constructor using encoding bits
  94. // recreates encoding state using a previously encoded image
  95. //
  96. Image::Image(Format a_format,
  97. unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight,
  98. unsigned char *a_paucEncidingBits, unsigned int a_uiEncodingBitsBytes,
  99. Image *a_pimageSource, ErrorMetric a_errormetric)
  100. {
  101. m_encodingStatus = EncodingStatus::SUCCESS;
  102. m_pafrgbaSource = nullptr;
  103. m_uiSourceWidth = a_uiSourceWidth;
  104. m_uiSourceHeight = a_uiSourceHeight;
  105. m_uiExtendedWidth = CalcExtendedDimension((unsigned short)m_uiSourceWidth);
  106. m_uiExtendedHeight = CalcExtendedDimension((unsigned short)m_uiSourceHeight);
  107. m_uiBlockColumns = m_uiExtendedWidth >> 2;
  108. m_uiBlockRows = m_uiExtendedHeight >> 2;
  109. unsigned int uiBlocks = GetNumberOfBlocks();
  110. m_pablock = new Block4x4[uiBlocks];
  111. assert(m_pablock);
  112. m_format = a_format;
  113. m_iNumOpaquePixels = 0;
  114. m_iNumTranslucentPixels = 0;
  115. m_iNumTransparentPixels = 0;
  116. m_encodingbitsformat = DetermineEncodingBitsFormat(m_format);
  117. if (m_encodingbitsformat == Block4x4EncodingBits::Format::UNKNOWN)
  118. {
  119. AddToEncodingStatus(ERROR_UNKNOWN_FORMAT);
  120. return;
  121. }
  122. m_uiEncodingBitsBytes = a_uiEncodingBitsBytes;
  123. m_paucEncodingBits = a_paucEncidingBits;
  124. m_errormetric = a_errormetric;
  125. m_fEffort = 0.0f;
  126. m_bVerboseOutput = false;
  127. m_iEncodeTime_ms = -1;
  128. unsigned char *paucEncodingBits = m_paucEncodingBits;
  129. unsigned int uiEncodingBitsBytesPerBlock = Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat);
  130. unsigned int uiH = 0;
  131. unsigned int uiV = 0;
  132. for (unsigned int uiBlock = 0; uiBlock < uiBlocks; uiBlock++)
  133. {
  134. m_pablock[uiBlock].InitFromEtcEncodingBits(a_format, uiH, uiV, paucEncodingBits,
  135. a_pimageSource, a_errormetric);
  136. paucEncodingBits += uiEncodingBitsBytesPerBlock;
  137. uiH += 4;
  138. if (uiH >= m_uiSourceWidth)
  139. {
  140. uiH = 0;
  141. uiV += 4;
  142. }
  143. }
  144. }
  145. // ----------------------------------------------------------------------------------------------------
  146. //
  147. Image::~Image(void)
  148. {
  149. if (m_pablock != nullptr)
  150. {
  151. delete[] m_pablock;
  152. m_pablock = nullptr;
  153. }
  154. /*if (m_paucEncodingBits != nullptr)
  155. {
  156. delete[] m_paucEncodingBits;
  157. m_paucEncodingBits = nullptr;
  158. }*/
  159. }
  160. // ----------------------------------------------------------------------------------------------------
  161. // encode an image
  162. // create a set of encoding bits that conforms to a_format
  163. // find best fit using a_errormetric
  164. // explore a range of possible encodings based on a_fEffort (range = [0:100])
  165. // speed up process using a_uiJobs as the number of process threads (a_uiJobs must not excede a_uiMaxJobs)
  166. //
  167. Image::EncodingStatus Image::Encode(Format a_format, ErrorMetric a_errormetric, float a_fEffort, unsigned int a_uiJobs, unsigned int a_uiMaxJobs)
  168. {
  169. auto start = std::chrono::steady_clock::now();
  170. m_encodingStatus = EncodingStatus::SUCCESS;
  171. m_format = a_format;
  172. m_errormetric = a_errormetric;
  173. m_fEffort = a_fEffort;
  174. if (m_errormetric < 0 || m_errormetric > ERROR_METRICS)
  175. {
  176. AddToEncodingStatus(ERROR_UNKNOWN_ERROR_METRIC);
  177. return m_encodingStatus;
  178. }
  179. if (m_fEffort < ETCCOMP_MIN_EFFORT_LEVEL)
  180. {
  181. AddToEncodingStatus(WARNING_EFFORT_OUT_OF_RANGE);
  182. m_fEffort = ETCCOMP_MIN_EFFORT_LEVEL;
  183. }
  184. else if (m_fEffort > ETCCOMP_MAX_EFFORT_LEVEL)
  185. {
  186. AddToEncodingStatus(WARNING_EFFORT_OUT_OF_RANGE);
  187. m_fEffort = ETCCOMP_MAX_EFFORT_LEVEL;
  188. }
  189. if (a_uiJobs < 1)
  190. {
  191. a_uiJobs = 1;
  192. AddToEncodingStatus(WARNING_JOBS_OUT_OF_RANGE);
  193. }
  194. else if (a_uiJobs > a_uiMaxJobs)
  195. {
  196. a_uiJobs = a_uiMaxJobs;
  197. AddToEncodingStatus(WARNING_JOBS_OUT_OF_RANGE);
  198. }
  199. m_encodingbitsformat = DetermineEncodingBitsFormat(m_format);
  200. if (m_encodingbitsformat == Block4x4EncodingBits::Format::UNKNOWN)
  201. {
  202. AddToEncodingStatus(ERROR_UNKNOWN_FORMAT);
  203. return m_encodingStatus;
  204. }
  205. assert(m_paucEncodingBits == nullptr);
  206. m_uiEncodingBitsBytes = GetNumberOfBlocks() * Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat);
  207. m_paucEncodingBits = new unsigned char[m_uiEncodingBitsBytes];
  208. InitBlocksAndBlockSorter();
  209. std::future<void> *handle = new std::future<void>[a_uiMaxJobs];
  210. unsigned int uiNumThreadsNeeded = 0;
  211. unsigned int uiUnfinishedBlocks = GetNumberOfBlocks();
  212. uiNumThreadsNeeded = (uiUnfinishedBlocks < a_uiJobs) ? uiUnfinishedBlocks : a_uiJobs;
  213. for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++)
  214. {
  215. handle[i] = async(std::launch::async, &Image::RunFirstPass, this, i, uiNumThreadsNeeded);
  216. }
  217. RunFirstPass(uiNumThreadsNeeded - 1, uiNumThreadsNeeded);
  218. for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++)
  219. {
  220. handle[i].get();
  221. }
  222. // perform effort-based encoding
  223. if (m_fEffort > ETCCOMP_MIN_EFFORT_LEVEL)
  224. {
  225. unsigned int uiFinishedBlocks = 0;
  226. unsigned int uiTotalEffortBlocks = static_cast<unsigned int>(roundf(0.01f * m_fEffort * GetNumberOfBlocks()));
  227. if (m_bVerboseOutput)
  228. {
  229. printf("effortblocks = %d\n", uiTotalEffortBlocks);
  230. }
  231. unsigned int uiPass = 0;
  232. while (1)
  233. {
  234. if (m_bVerboseOutput)
  235. {
  236. uiPass++;
  237. printf("pass %u\n", uiPass);
  238. }
  239. m_psortedblocklist->Sort();
  240. uiUnfinishedBlocks = m_psortedblocklist->GetNumberOfSortedBlocks();
  241. uiFinishedBlocks = GetNumberOfBlocks() - uiUnfinishedBlocks;
  242. if (m_bVerboseOutput)
  243. {
  244. printf(" %u unfinished blocks\n", uiUnfinishedBlocks);
  245. // m_psortedblocklist->Print();
  246. }
  247. //stop enocding when we did enough to satify the effort percentage
  248. if (uiFinishedBlocks >= uiTotalEffortBlocks)
  249. {
  250. if (m_bVerboseOutput)
  251. {
  252. printf("Finished %d Blocks out of %d\n", uiFinishedBlocks, uiTotalEffortBlocks);
  253. }
  254. break;
  255. }
  256. unsigned int uiIteratedBlocks = 0;
  257. unsigned int blocksToIterateThisPass = (uiTotalEffortBlocks - uiFinishedBlocks);
  258. uiNumThreadsNeeded = (uiUnfinishedBlocks < a_uiJobs) ? uiUnfinishedBlocks : a_uiJobs;
  259. if (uiNumThreadsNeeded <= 1)
  260. {
  261. //since we already how many blocks each thread will process
  262. //cap the thread limit to do the proper amount of work, and not more
  263. uiIteratedBlocks = IterateThroughWorstBlocks(blocksToIterateThisPass, 0, 1);
  264. }
  265. else
  266. {
  267. //we have a lot of work to do, so lets multi thread it
  268. std::future<unsigned int> *handleToBlockEncoders = new std::future<unsigned int>[uiNumThreadsNeeded-1];
  269. for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++)
  270. {
  271. handleToBlockEncoders[i] = async(std::launch::async, &Image::IterateThroughWorstBlocks, this, blocksToIterateThisPass, i, uiNumThreadsNeeded);
  272. }
  273. uiIteratedBlocks = IterateThroughWorstBlocks(blocksToIterateThisPass, uiNumThreadsNeeded - 1, uiNumThreadsNeeded);
  274. for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++)
  275. {
  276. uiIteratedBlocks += handleToBlockEncoders[i].get();
  277. }
  278. delete[] handleToBlockEncoders;
  279. }
  280. if (m_bVerboseOutput)
  281. {
  282. printf(" %u iterated blocks\n", uiIteratedBlocks);
  283. }
  284. }
  285. }
  286. // generate Etc2-compatible bit-format 4x4 blocks
  287. for (int i = 0; i < (int)a_uiJobs - 1; i++)
  288. {
  289. handle[i] = async(std::launch::async, &Image::SetEncodingBits, this, i, a_uiJobs);
  290. }
  291. SetEncodingBits(a_uiJobs - 1, a_uiJobs);
  292. for (int i = 0; i < (int)a_uiJobs - 1; i++)
  293. {
  294. handle[i].get();
  295. }
  296. auto end = std::chrono::steady_clock::now();
  297. std::chrono::milliseconds elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
  298. m_iEncodeTime_ms = (int)elapsed.count();
  299. delete[] handle;
  300. delete m_psortedblocklist;
  301. return m_encodingStatus;
  302. }
  303. // ----------------------------------------------------------------------------------------------------
  304. // iterate the encoding thru the blocks with the worst error
  305. // stop when a_uiMaxBlocks blocks have been iterated
  306. // split the blocks between the process threads using a_uiMultithreadingOffset and a_uiMultithreadingStride
  307. //
  308. unsigned int Image::IterateThroughWorstBlocks(unsigned int a_uiMaxBlocks,
  309. unsigned int a_uiMultithreadingOffset,
  310. unsigned int a_uiMultithreadingStride)
  311. {
  312. assert(a_uiMultithreadingStride > 0);
  313. unsigned int uiIteratedBlocks = a_uiMultithreadingOffset;
  314. SortedBlockList::Link *plink = m_psortedblocklist->GetLinkToFirstBlock();
  315. for (plink = plink->Advance(a_uiMultithreadingOffset);
  316. plink != nullptr;
  317. plink = plink->Advance(a_uiMultithreadingStride) )
  318. {
  319. if (uiIteratedBlocks >= a_uiMaxBlocks)
  320. {
  321. break;
  322. }
  323. plink->GetBlock()->PerformEncodingIteration(m_fEffort);
  324. uiIteratedBlocks += a_uiMultithreadingStride;
  325. }
  326. return uiIteratedBlocks;
  327. }
  328. // ----------------------------------------------------------------------------------------------------
  329. // determine which warnings to check for during Encode() based on encoding format
  330. //
  331. void Image::FindEncodingWarningTypesForCurFormat()
  332. {
  333. TrackEncodingWarning(WARNING_ALL_TRANSPARENT_PIXELS);
  334. TrackEncodingWarning(WARNING_SOME_RGBA_NOT_0_TO_1);
  335. switch (m_format)
  336. {
  337. case Image::Format::ETC1:
  338. case Image::Format::RGB8:
  339. case Image::Format::SRGB8:
  340. TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS);
  341. TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS);
  342. break;
  343. case Image::Format::RGB8A1:
  344. case Image::Format::SRGB8A1:
  345. TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS);
  346. TrackEncodingWarning(WARNING_ALL_OPAQUE_PIXELS);
  347. break;
  348. case Image::Format::RGBA8:
  349. case Image::Format::SRGBA8:
  350. TrackEncodingWarning(WARNING_ALL_OPAQUE_PIXELS);
  351. break;
  352. case Image::Format::R11:
  353. case Image::Format::SIGNED_R11:
  354. TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS);
  355. TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS);
  356. TrackEncodingWarning(WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO);
  357. TrackEncodingWarning(WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO);
  358. break;
  359. case Image::Format::RG11:
  360. case Image::Format::SIGNED_RG11:
  361. TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS);
  362. TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS);
  363. TrackEncodingWarning(WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO);
  364. break;
  365. case Image::Format::FORMATS:
  366. case Image::Format::UNKNOWN:
  367. default:
  368. assert(0);
  369. break;
  370. }
  371. }
  372. // ----------------------------------------------------------------------------------------------------
  373. // examine source pixels to check for warnings
  374. //
  375. void Image::FindAndSetEncodingWarnings()
  376. {
  377. int numPixels = (m_uiBlockRows * 4) * (m_uiBlockColumns * 4);
  378. if (m_iNumOpaquePixels == numPixels)
  379. {
  380. AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_ALL_OPAQUE_PIXELS);
  381. }
  382. if (m_iNumOpaquePixels < numPixels)
  383. {
  384. AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_NON_OPAQUE_PIXELS);
  385. }
  386. if (m_iNumTranslucentPixels > 0)
  387. {
  388. AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_TRANSLUCENT_PIXELS);
  389. }
  390. if (m_iNumTransparentPixels == numPixels)
  391. {
  392. AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_ALL_TRANSPARENT_PIXELS);
  393. }
  394. if (m_numColorValues.fB > 0.0f)
  395. {
  396. AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO);
  397. }
  398. if (m_numColorValues.fG > 0.0f)
  399. {
  400. AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO);
  401. }
  402. if (m_numOutOfRangeValues.fR > 0.0f || m_numOutOfRangeValues.fG > 0.0f)
  403. {
  404. AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_RGBA_NOT_0_TO_1);
  405. }
  406. if (m_numOutOfRangeValues.fB > 0.0f || m_numOutOfRangeValues.fA > 0.0f)
  407. {
  408. AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_RGBA_NOT_0_TO_1);
  409. }
  410. }
  411. // ----------------------------------------------------------------------------------------------------
  412. // return a string name for a given image format
  413. //
  414. const char * Image::EncodingFormatToString(Image::Format a_format)
  415. {
  416. switch (a_format)
  417. {
  418. case Image::Format::ETC1:
  419. return "ETC1";
  420. case Image::Format::RGB8:
  421. return "RGB8";
  422. case Image::Format::SRGB8:
  423. return "SRGB8";
  424. case Image::Format::RGB8A1:
  425. return "RGB8A1";
  426. case Image::Format::SRGB8A1:
  427. return "SRGB8A1";
  428. case Image::Format::RGBA8:
  429. return "RGBA8";
  430. case Image::Format::SRGBA8:
  431. return "SRGBA8";
  432. case Image::Format::R11:
  433. return "R11";
  434. case Image::Format::SIGNED_R11:
  435. return "SIGNED_R11";
  436. case Image::Format::RG11:
  437. return "RG11";
  438. case Image::Format::SIGNED_RG11:
  439. return "SIGNED_RG11";
  440. case Image::Format::FORMATS:
  441. case Image::Format::UNKNOWN:
  442. default:
  443. return "UNKNOWN";
  444. }
  445. }
  446. // ----------------------------------------------------------------------------------------------------
  447. // return a string name for the image's format
  448. //
  449. const char * Image::EncodingFormatToString(void)
  450. {
  451. return EncodingFormatToString(m_format);
  452. }
  453. // ----------------------------------------------------------------------------------------------------
  454. // init image blocks prior to encoding
  455. // init block sorter for subsequent sortings
  456. // check for encoding warnings
  457. //
  458. void Image::InitBlocksAndBlockSorter(void)
  459. {
  460. FindEncodingWarningTypesForCurFormat();
  461. // init each block
  462. Block4x4 *pblock = m_pablock;
  463. unsigned char *paucEncodingBits = m_paucEncodingBits;
  464. for (unsigned int uiBlockRow = 0; uiBlockRow < m_uiBlockRows; uiBlockRow++)
  465. {
  466. unsigned int uiBlockV = uiBlockRow * 4;
  467. for (unsigned int uiBlockColumn = 0; uiBlockColumn < m_uiBlockColumns; uiBlockColumn++)
  468. {
  469. unsigned int uiBlockH = uiBlockColumn * 4;
  470. pblock->InitFromSource(this, uiBlockH, uiBlockV, paucEncodingBits, m_errormetric);
  471. paucEncodingBits += Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat);
  472. pblock++;
  473. }
  474. }
  475. FindAndSetEncodingWarnings();
  476. // init block sorter
  477. {
  478. m_psortedblocklist = new SortedBlockList(GetNumberOfBlocks(), 100);
  479. for (unsigned int uiBlock = 0; uiBlock < GetNumberOfBlocks(); uiBlock++)
  480. {
  481. pblock = &m_pablock[uiBlock];
  482. m_psortedblocklist->AddBlock(pblock);
  483. }
  484. }
  485. }
  486. // ----------------------------------------------------------------------------------------------------
  487. // run the first pass of the encoder
  488. // the encoder generally finds a reasonable, fast encoding
  489. // this is run on all blocks regardless of effort to ensure that all blocks have a valid encoding
  490. //
  491. void Image::RunFirstPass(unsigned int a_uiMultithreadingOffset, unsigned int a_uiMultithreadingStride)
  492. {
  493. assert(a_uiMultithreadingStride > 0);
  494. for (unsigned int uiBlock = a_uiMultithreadingOffset;
  495. uiBlock < GetNumberOfBlocks();
  496. uiBlock += a_uiMultithreadingStride)
  497. {
  498. Block4x4 *pblock = &m_pablock[uiBlock];
  499. pblock->PerformEncodingIteration(m_fEffort);
  500. }
  501. }
  502. // ----------------------------------------------------------------------------------------------------
  503. // set the encoding bits (for the output file) based on the best encoding for each block
  504. //
  505. void Image::SetEncodingBits(unsigned int a_uiMultithreadingOffset,
  506. unsigned int a_uiMultithreadingStride)
  507. {
  508. assert(a_uiMultithreadingStride > 0);
  509. for (unsigned int uiBlock = a_uiMultithreadingOffset;
  510. uiBlock < GetNumberOfBlocks();
  511. uiBlock += a_uiMultithreadingStride)
  512. {
  513. Block4x4 *pblock = &m_pablock[uiBlock];
  514. pblock->SetEncodingBitsFromEncoding();
  515. }
  516. }
  517. // ----------------------------------------------------------------------------------------------------
  518. // return the image error
  519. // image error is the sum of all block errors
  520. //
  521. float Image::GetError(void)
  522. {
  523. float fError = 0.0f;
  524. for (unsigned int uiBlock = 0; uiBlock < GetNumberOfBlocks(); uiBlock++)
  525. {
  526. Block4x4 *pblock = &m_pablock[uiBlock];
  527. fError += pblock->GetError();
  528. }
  529. return fError;
  530. }
  531. // ----------------------------------------------------------------------------------------------------
  532. // determine the encoding bits format based on the encoding format
  533. // the encoding bits format is a family of bit encodings that are shared across various encoding formats
  534. //
  535. Block4x4EncodingBits::Format Image::DetermineEncodingBitsFormat(Format a_format)
  536. {
  537. Block4x4EncodingBits::Format encodingbitsformat;
  538. // determine encoding bits format from image format
  539. switch (a_format)
  540. {
  541. case Format::ETC1:
  542. case Format::RGB8:
  543. case Format::SRGB8:
  544. encodingbitsformat = Block4x4EncodingBits::Format::RGB8;
  545. break;
  546. case Format::RGBA8:
  547. case Format::SRGBA8:
  548. encodingbitsformat = Block4x4EncodingBits::Format::RGBA8;
  549. break;
  550. case Format::R11:
  551. case Format::SIGNED_R11:
  552. encodingbitsformat = Block4x4EncodingBits::Format::R11;
  553. break;
  554. case Format::RG11:
  555. case Format::SIGNED_RG11:
  556. encodingbitsformat = Block4x4EncodingBits::Format::RG11;
  557. break;
  558. case Format::RGB8A1:
  559. case Format::SRGB8A1:
  560. encodingbitsformat = Block4x4EncodingBits::Format::RGB8A1;
  561. break;
  562. default:
  563. encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN;
  564. break;
  565. }
  566. return encodingbitsformat;
  567. }
  568. // ----------------------------------------------------------------------------------------------------
  569. //
  570. } // namespace Etc