EtcSortedBlockList.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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. EtcSortedBlockList.cpp
  18. SortedBlockList is a list of 4x4 blocks that can be used by the "effort" system to prioritize
  19. the encoding of the 4x4 blocks.
  20. The sorting is done with buckets, where each bucket is an indication of how much error each 4x4 block has
  21. */
  22. #include "EtcConfig.h"
  23. #include "EtcSortedBlockList.h"
  24. #include "EtcBlock4x4.h"
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <assert.h>
  28. namespace Etc
  29. {
  30. // ----------------------------------------------------------------------------------------------------
  31. // construct an empty list
  32. //
  33. // allocate enough memory to add all of the image's 4x4 blocks later
  34. // allocate enough buckets to sort the blocks
  35. //
  36. SortedBlockList::SortedBlockList(unsigned int a_uiImageBlocks, unsigned int a_uiBuckets)
  37. {
  38. m_uiImageBlocks = a_uiImageBlocks;
  39. m_iBuckets = (int)a_uiBuckets;
  40. m_uiAddedBlocks = 0;
  41. m_uiSortedBlocks = 0;
  42. m_palinkPool = new Link[m_uiImageBlocks];
  43. m_pabucket = new Bucket[m_iBuckets];
  44. m_fMaxError = 0.0f;
  45. InitBuckets();
  46. }
  47. // ----------------------------------------------------------------------------------------------------
  48. //
  49. SortedBlockList::~SortedBlockList(void)
  50. {
  51. delete[] m_palinkPool;
  52. delete[] m_pabucket;
  53. }
  54. // ----------------------------------------------------------------------------------------------------
  55. // add a 4x4 block to the list
  56. // the 4x4 block will be sorted later
  57. //
  58. void SortedBlockList::AddBlock(Block4x4 *a_pblock)
  59. {
  60. assert(m_uiAddedBlocks < m_uiImageBlocks);
  61. Link *plink = &m_palinkPool[m_uiAddedBlocks++];
  62. plink->Init(a_pblock);
  63. }
  64. // ----------------------------------------------------------------------------------------------------
  65. // sort all of the 4x4 blocks that have been added to the list
  66. //
  67. // first, determine the maximum error, then assign an error range to each bucket
  68. // next, determine which bucket each 4x4 block belongs to based on the 4x4 block's error
  69. // add the 4x4 block to the appropriate bucket
  70. // lastly, walk thru the buckets and add each bucket to a sorted linked list
  71. //
  72. // the resultant sorting is an approximate sorting from most to least error
  73. //
  74. void SortedBlockList::Sort(void)
  75. {
  76. assert(m_uiAddedBlocks == m_uiImageBlocks);
  77. InitBuckets();
  78. // find max block error
  79. m_fMaxError = -1.0f;
  80. for (unsigned int uiLink = 0; uiLink < m_uiAddedBlocks; uiLink++)
  81. {
  82. Link *plinkBlock = &m_palinkPool[uiLink];
  83. float fBlockError = plinkBlock->GetBlock()->GetError();
  84. if (fBlockError > m_fMaxError)
  85. {
  86. m_fMaxError = fBlockError;
  87. }
  88. }
  89. // prevent divide by zero or divide by negative
  90. if (m_fMaxError <= 0.0f)
  91. {
  92. m_fMaxError = 1.0f;
  93. }
  94. //used for debugging
  95. //int numDone = 0;
  96. // put all of the blocks with unfinished encodings into the appropriate bucket
  97. m_uiSortedBlocks = 0;
  98. for (unsigned int uiLink = 0; uiLink < m_uiAddedBlocks; uiLink++)
  99. {
  100. Link *plinkBlock = &m_palinkPool[uiLink];
  101. // if the encoding is done, don't add it to the list
  102. if (plinkBlock->GetBlock()->GetEncoding()->IsDone())
  103. {
  104. //numDone++;
  105. continue;
  106. }
  107. // calculate the appropriate sort bucket
  108. float fBlockError = plinkBlock->GetBlock()->GetError();
  109. int iBucket = (int) floorf(m_iBuckets * fBlockError / m_fMaxError);
  110. // clamp to bucket index
  111. iBucket = iBucket < 0 ? 0 : iBucket >= m_iBuckets ? m_iBuckets - 1 : iBucket;
  112. // add block to bucket
  113. {
  114. Bucket *pbucket = &m_pabucket[iBucket];
  115. if (pbucket->plinkLast)
  116. {
  117. pbucket->plinkLast->SetNext(plinkBlock);
  118. pbucket->plinkLast = plinkBlock;
  119. }
  120. else
  121. {
  122. pbucket->plinkFirst = pbucket->plinkLast = plinkBlock;
  123. }
  124. plinkBlock->SetNext(nullptr);
  125. }
  126. m_uiSortedBlocks++;
  127. if (0)
  128. {
  129. printf("%u: e=%.3f\n", uiLink, fBlockError);
  130. Print();
  131. printf("\n\n\n");
  132. }
  133. }
  134. //printf("num blocks already done: %d\n",numDone);
  135. //link the blocks together across buckets
  136. m_plinkFirst = nullptr;
  137. m_plinkLast = nullptr;
  138. for (int iBucket = m_iBuckets - 1; iBucket >= 0; iBucket--)
  139. {
  140. Bucket *pbucket = &m_pabucket[iBucket];
  141. if (pbucket->plinkFirst)
  142. {
  143. if (m_plinkFirst == nullptr)
  144. {
  145. m_plinkFirst = pbucket->plinkFirst;
  146. }
  147. else
  148. {
  149. assert(pbucket->plinkLast->GetNext() == nullptr);
  150. m_plinkLast->SetNext(pbucket->plinkFirst);
  151. }
  152. m_plinkLast = pbucket->plinkLast;
  153. }
  154. }
  155. }
  156. // ----------------------------------------------------------------------------------------------------
  157. // clear all of the buckets. normally done in preparation for a sort
  158. //
  159. void SortedBlockList::InitBuckets(void)
  160. {
  161. for (int iBucket = 0; iBucket < m_iBuckets; iBucket++)
  162. {
  163. Bucket *pbucket = &m_pabucket[iBucket];
  164. pbucket->plinkFirst = 0;
  165. pbucket->plinkLast = 0;
  166. }
  167. }
  168. // ----------------------------------------------------------------------------------------------------
  169. // print out the list of sorted 4x4 blocks
  170. // normally used for debugging
  171. //
  172. void SortedBlockList::Print(void)
  173. {
  174. for (int iBucket = m_iBuckets-1; iBucket >= 0; iBucket--)
  175. {
  176. Bucket *pbucket = &m_pabucket[iBucket];
  177. unsigned int uiBlocks = 0;
  178. for (Link *plink = pbucket->plinkFirst; plink != nullptr; plink = plink->GetNext() )
  179. {
  180. uiBlocks++;
  181. if (plink == pbucket->plinkLast)
  182. {
  183. break;
  184. }
  185. }
  186. float fBucketError = m_fMaxError * iBucket / m_iBuckets;
  187. float fBucketRMS = sqrtf(fBucketError / (4.0f*16.0f) );
  188. printf("%3d: e=%.3f rms=%.6f %u\n", iBucket, fBucketError, fBucketRMS, uiBlocks);
  189. }
  190. }
  191. // ----------------------------------------------------------------------------------------------------
  192. //
  193. } // namespace Etc