rescaler.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // Copyright 2014 Google Inc. All Rights Reserved.
  2. //
  3. // Use of this source code is governed by a BSD-style license
  4. // that can be found in the COPYING file in the root of the source
  5. // tree. An additional intellectual property rights grant can be found
  6. // in the file PATENTS. All contributing project authors may
  7. // be found in the AUTHORS file in the root of the source tree.
  8. // -----------------------------------------------------------------------------
  9. //
  10. // Rescaling functions
  11. //
  12. // Author: Skal ([email protected])
  13. #include <assert.h>
  14. #include "./dsp.h"
  15. #include "../utils/rescaler.h"
  16. //------------------------------------------------------------------------------
  17. // Implementations of critical functions ImportRow / ExportRow
  18. #define ROUNDER (WEBP_RESCALER_ONE >> 1)
  19. #define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
  20. //------------------------------------------------------------------------------
  21. // Row import
  22. void WebPRescalerImportRowExpandC(WebPRescaler* const wrk, const uint8_t* src) {
  23. const int x_stride = wrk->num_channels;
  24. const int x_out_max = wrk->dst_width * wrk->num_channels;
  25. int channel;
  26. assert(!WebPRescalerInputDone(wrk));
  27. assert(wrk->x_expand);
  28. for (channel = 0; channel < x_stride; ++channel) {
  29. int x_in = channel;
  30. int x_out = channel;
  31. // simple bilinear interpolation
  32. int accum = wrk->x_add;
  33. int left = src[x_in];
  34. int right = (wrk->src_width > 1) ? src[x_in + x_stride] : left;
  35. x_in += x_stride;
  36. while (1) {
  37. wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum;
  38. x_out += x_stride;
  39. if (x_out >= x_out_max) break;
  40. accum -= wrk->x_sub;
  41. if (accum < 0) {
  42. left = right;
  43. x_in += x_stride;
  44. assert(x_in < wrk->src_width * x_stride);
  45. right = src[x_in];
  46. accum += wrk->x_add;
  47. }
  48. }
  49. assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0);
  50. }
  51. }
  52. void WebPRescalerImportRowShrinkC(WebPRescaler* const wrk, const uint8_t* src) {
  53. const int x_stride = wrk->num_channels;
  54. const int x_out_max = wrk->dst_width * wrk->num_channels;
  55. int channel;
  56. assert(!WebPRescalerInputDone(wrk));
  57. assert(!wrk->x_expand);
  58. for (channel = 0; channel < x_stride; ++channel) {
  59. int x_in = channel;
  60. int x_out = channel;
  61. uint32_t sum = 0;
  62. int accum = 0;
  63. while (x_out < x_out_max) {
  64. uint32_t base = 0;
  65. accum += wrk->x_add;
  66. while (accum > 0) {
  67. accum -= wrk->x_sub;
  68. assert(x_in < wrk->src_width * x_stride);
  69. base = src[x_in];
  70. sum += base;
  71. x_in += x_stride;
  72. }
  73. { // Emit next horizontal pixel.
  74. const rescaler_t frac = base * (-accum);
  75. wrk->frow[x_out] = sum * wrk->x_sub - frac;
  76. // fresh fractional start for next pixel
  77. sum = (int)MULT_FIX(frac, wrk->fx_scale);
  78. }
  79. x_out += x_stride;
  80. }
  81. assert(accum == 0);
  82. }
  83. }
  84. //------------------------------------------------------------------------------
  85. // Row export
  86. void WebPRescalerExportRowExpandC(WebPRescaler* const wrk) {
  87. int x_out;
  88. uint8_t* const dst = wrk->dst;
  89. rescaler_t* const irow = wrk->irow;
  90. const int x_out_max = wrk->dst_width * wrk->num_channels;
  91. const rescaler_t* const frow = wrk->frow;
  92. assert(!WebPRescalerOutputDone(wrk));
  93. assert(wrk->y_accum <= 0);
  94. assert(wrk->y_expand);
  95. assert(wrk->y_sub != 0);
  96. if (wrk->y_accum == 0) {
  97. for (x_out = 0; x_out < x_out_max; ++x_out) {
  98. const uint32_t J = frow[x_out];
  99. const int v = (int)MULT_FIX(J, wrk->fy_scale);
  100. assert(v >= 0 && v <= 255);
  101. dst[x_out] = v;
  102. }
  103. } else {
  104. const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
  105. const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B);
  106. for (x_out = 0; x_out < x_out_max; ++x_out) {
  107. const uint64_t I = (uint64_t)A * frow[x_out]
  108. + (uint64_t)B * irow[x_out];
  109. const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
  110. const int v = (int)MULT_FIX(J, wrk->fy_scale);
  111. assert(v >= 0 && v <= 255);
  112. dst[x_out] = v;
  113. }
  114. }
  115. }
  116. void WebPRescalerExportRowShrinkC(WebPRescaler* const wrk) {
  117. int x_out;
  118. uint8_t* const dst = wrk->dst;
  119. rescaler_t* const irow = wrk->irow;
  120. const int x_out_max = wrk->dst_width * wrk->num_channels;
  121. const rescaler_t* const frow = wrk->frow;
  122. const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum);
  123. assert(!WebPRescalerOutputDone(wrk));
  124. assert(wrk->y_accum <= 0);
  125. assert(!wrk->y_expand);
  126. if (yscale) {
  127. for (x_out = 0; x_out < x_out_max; ++x_out) {
  128. const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale);
  129. const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
  130. assert(v >= 0 && v <= 255);
  131. dst[x_out] = v;
  132. irow[x_out] = frac; // new fractional start
  133. }
  134. } else {
  135. for (x_out = 0; x_out < x_out_max; ++x_out) {
  136. const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale);
  137. assert(v >= 0 && v <= 255);
  138. dst[x_out] = v;
  139. irow[x_out] = 0;
  140. }
  141. }
  142. }
  143. #undef MULT_FIX
  144. #undef ROUNDER
  145. //------------------------------------------------------------------------------
  146. // Main entry calls
  147. void WebPRescalerImportRow(WebPRescaler* const wrk, const uint8_t* src) {
  148. assert(!WebPRescalerInputDone(wrk));
  149. if (!wrk->x_expand) {
  150. WebPRescalerImportRowShrink(wrk, src);
  151. } else {
  152. WebPRescalerImportRowExpand(wrk, src);
  153. }
  154. }
  155. void WebPRescalerExportRow(WebPRescaler* const wrk) {
  156. if (wrk->y_accum <= 0) {
  157. assert(!WebPRescalerOutputDone(wrk));
  158. if (wrk->y_expand) {
  159. WebPRescalerExportRowExpand(wrk);
  160. } else if (wrk->fxy_scale) {
  161. WebPRescalerExportRowShrink(wrk);
  162. } else { // very special case for src = dst = 1x1
  163. int i;
  164. assert(wrk->src_width == 1 && wrk->dst_width <= 2);
  165. assert(wrk->src_height == 1 && wrk->dst_height == 1);
  166. for (i = 0; i < wrk->num_channels * wrk->dst_width; ++i) {
  167. wrk->dst[i] = wrk->irow[i];
  168. wrk->irow[i] = 0;
  169. }
  170. }
  171. wrk->y_accum += wrk->y_add;
  172. wrk->dst += wrk->dst_stride;
  173. ++wrk->dst_y;
  174. }
  175. }
  176. //------------------------------------------------------------------------------
  177. WebPRescalerImportRowFunc WebPRescalerImportRowExpand;
  178. WebPRescalerImportRowFunc WebPRescalerImportRowShrink;
  179. WebPRescalerExportRowFunc WebPRescalerExportRowExpand;
  180. WebPRescalerExportRowFunc WebPRescalerExportRowShrink;
  181. extern void WebPRescalerDspInitSSE2(void);
  182. extern void WebPRescalerDspInitMIPS32(void);
  183. extern void WebPRescalerDspInitMIPSdspR2(void);
  184. extern void WebPRescalerDspInitNEON(void);
  185. static volatile VP8CPUInfo rescaler_last_cpuinfo_used =
  186. (VP8CPUInfo)&rescaler_last_cpuinfo_used;
  187. WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInit(void) {
  188. if (rescaler_last_cpuinfo_used == VP8GetCPUInfo) return;
  189. WebPRescalerImportRowExpand = WebPRescalerImportRowExpandC;
  190. WebPRescalerImportRowShrink = WebPRescalerImportRowShrinkC;
  191. WebPRescalerExportRowExpand = WebPRescalerExportRowExpandC;
  192. WebPRescalerExportRowShrink = WebPRescalerExportRowShrinkC;
  193. if (VP8GetCPUInfo != NULL) {
  194. #if defined(WEBP_USE_SSE2)
  195. if (VP8GetCPUInfo(kSSE2)) {
  196. WebPRescalerDspInitSSE2();
  197. }
  198. #endif
  199. #if defined(WEBP_USE_NEON)
  200. if (VP8GetCPUInfo(kNEON)) {
  201. WebPRescalerDspInitNEON();
  202. }
  203. #endif
  204. #if defined(WEBP_USE_MIPS32)
  205. if (VP8GetCPUInfo(kMIPS32)) {
  206. WebPRescalerDspInitMIPS32();
  207. }
  208. #endif
  209. #if defined(WEBP_USE_MIPS_DSP_R2)
  210. if (VP8GetCPUInfo(kMIPSdspR2)) {
  211. WebPRescalerDspInitMIPSdspR2();
  212. }
  213. #endif
  214. }
  215. rescaler_last_cpuinfo_used = VP8GetCPUInfo;
  216. }