rescaler.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  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 (pascal.massimino@gmail.com)
  13. #include <assert.h>
  14. #include "./dsp.h"
  15. #include "../utils/rescaler_utils.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. #define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
  21. //------------------------------------------------------------------------------
  22. // Row import
  23. void WebPRescalerImportRowExpand_C(WebPRescaler* const wrk,
  24. const uint8_t* src) {
  25. const int x_stride = wrk->num_channels;
  26. const int x_out_max = wrk->dst_width * wrk->num_channels;
  27. int channel;
  28. assert(!WebPRescalerInputDone(wrk));
  29. assert(wrk->x_expand);
  30. for (channel = 0; channel < x_stride; ++channel) {
  31. int x_in = channel;
  32. int x_out = channel;
  33. // simple bilinear interpolation
  34. int accum = wrk->x_add;
  35. rescaler_t left = (rescaler_t)src[x_in];
  36. rescaler_t right =
  37. (wrk->src_width > 1) ? (rescaler_t)src[x_in + x_stride] : left;
  38. x_in += x_stride;
  39. while (1) {
  40. wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum;
  41. x_out += x_stride;
  42. if (x_out >= x_out_max) break;
  43. accum -= wrk->x_sub;
  44. if (accum < 0) {
  45. left = right;
  46. x_in += x_stride;
  47. assert(x_in < wrk->src_width * x_stride);
  48. right = (rescaler_t)src[x_in];
  49. accum += wrk->x_add;
  50. }
  51. }
  52. assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0);
  53. }
  54. }
  55. void WebPRescalerImportRowShrink_C(WebPRescaler* const wrk,
  56. const uint8_t* src) {
  57. const int x_stride = wrk->num_channels;
  58. const int x_out_max = wrk->dst_width * wrk->num_channels;
  59. int channel;
  60. assert(!WebPRescalerInputDone(wrk));
  61. assert(!wrk->x_expand);
  62. for (channel = 0; channel < x_stride; ++channel) {
  63. int x_in = channel;
  64. int x_out = channel;
  65. uint32_t sum = 0;
  66. int accum = 0;
  67. while (x_out < x_out_max) {
  68. uint32_t base = 0;
  69. accum += wrk->x_add;
  70. while (accum > 0) {
  71. accum -= wrk->x_sub;
  72. assert(x_in < wrk->src_width * x_stride);
  73. base = src[x_in];
  74. sum += base;
  75. x_in += x_stride;
  76. }
  77. { // Emit next horizontal pixel.
  78. const rescaler_t frac = base * (-accum);
  79. wrk->frow[x_out] = sum * wrk->x_sub - frac;
  80. // fresh fractional start for next pixel
  81. sum = (int)MULT_FIX(frac, wrk->fx_scale);
  82. }
  83. x_out += x_stride;
  84. }
  85. assert(accum == 0);
  86. }
  87. }
  88. //------------------------------------------------------------------------------
  89. // Row export
  90. void WebPRescalerExportRowExpand_C(WebPRescaler* const wrk) {
  91. int x_out;
  92. uint8_t* const dst = wrk->dst;
  93. rescaler_t* const irow = wrk->irow;
  94. const int x_out_max = wrk->dst_width * wrk->num_channels;
  95. const rescaler_t* const frow = wrk->frow;
  96. assert(!WebPRescalerOutputDone(wrk));
  97. assert(wrk->y_accum <= 0);
  98. assert(wrk->y_expand);
  99. assert(wrk->y_sub != 0);
  100. if (wrk->y_accum == 0) {
  101. for (x_out = 0; x_out < x_out_max; ++x_out) {
  102. const uint32_t J = frow[x_out];
  103. const int v = (int)MULT_FIX(J, wrk->fy_scale);
  104. dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
  105. }
  106. } else {
  107. const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
  108. const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B);
  109. for (x_out = 0; x_out < x_out_max; ++x_out) {
  110. const uint64_t I = (uint64_t)A * frow[x_out]
  111. + (uint64_t)B * irow[x_out];
  112. const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
  113. const int v = (int)MULT_FIX(J, wrk->fy_scale);
  114. dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
  115. }
  116. }
  117. }
  118. void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) {
  119. int x_out;
  120. uint8_t* const dst = wrk->dst;
  121. rescaler_t* const irow = wrk->irow;
  122. const int x_out_max = wrk->dst_width * wrk->num_channels;
  123. const rescaler_t* const frow = wrk->frow;
  124. const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum);
  125. assert(!WebPRescalerOutputDone(wrk));
  126. assert(wrk->y_accum <= 0);
  127. assert(!wrk->y_expand);
  128. if (yscale) {
  129. for (x_out = 0; x_out < x_out_max; ++x_out) {
  130. const uint32_t frac = (uint32_t)MULT_FIX_FLOOR(frow[x_out], yscale);
  131. const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
  132. dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
  133. irow[x_out] = frac; // new fractional start
  134. }
  135. } else {
  136. for (x_out = 0; x_out < x_out_max; ++x_out) {
  137. const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale);
  138. dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
  139. irow[x_out] = 0;
  140. }
  141. }
  142. }
  143. #undef MULT_FIX_FLOOR
  144. #undef MULT_FIX
  145. #undef ROUNDER
  146. //------------------------------------------------------------------------------
  147. // Main entry calls
  148. void WebPRescalerImportRow(WebPRescaler* const wrk, const uint8_t* src) {
  149. assert(!WebPRescalerInputDone(wrk));
  150. if (!wrk->x_expand) {
  151. WebPRescalerImportRowShrink(wrk, src);
  152. } else {
  153. WebPRescalerImportRowExpand(wrk, src);
  154. }
  155. }
  156. void WebPRescalerExportRow(WebPRescaler* const wrk) {
  157. if (wrk->y_accum <= 0) {
  158. assert(!WebPRescalerOutputDone(wrk));
  159. if (wrk->y_expand) {
  160. WebPRescalerExportRowExpand(wrk);
  161. } else if (wrk->fxy_scale) {
  162. WebPRescalerExportRowShrink(wrk);
  163. } else { // special case
  164. int i;
  165. assert(wrk->src_height == wrk->dst_height && wrk->x_add == 1);
  166. assert(wrk->src_width == 1 && wrk->dst_width <= 2);
  167. for (i = 0; i < wrk->num_channels * wrk->dst_width; ++i) {
  168. wrk->dst[i] = wrk->irow[i];
  169. wrk->irow[i] = 0;
  170. }
  171. }
  172. wrk->y_accum += wrk->y_add;
  173. wrk->dst += wrk->dst_stride;
  174. ++wrk->dst_y;
  175. }
  176. }
  177. //------------------------------------------------------------------------------
  178. WebPRescalerImportRowFunc WebPRescalerImportRowExpand;
  179. WebPRescalerImportRowFunc WebPRescalerImportRowShrink;
  180. WebPRescalerExportRowFunc WebPRescalerExportRowExpand;
  181. WebPRescalerExportRowFunc WebPRescalerExportRowShrink;
  182. extern void WebPRescalerDspInitSSE2(void);
  183. extern void WebPRescalerDspInitMIPS32(void);
  184. extern void WebPRescalerDspInitMIPSdspR2(void);
  185. extern void WebPRescalerDspInitMSA(void);
  186. extern void WebPRescalerDspInitNEON(void);
  187. WEBP_DSP_INIT_FUNC(WebPRescalerDspInit) {
  188. #if !defined(WEBP_REDUCE_SIZE)
  189. #if !WEBP_NEON_OMIT_C_CODE
  190. WebPRescalerExportRowExpand = WebPRescalerExportRowExpand_C;
  191. WebPRescalerExportRowShrink = WebPRescalerExportRowShrink_C;
  192. #endif
  193. WebPRescalerImportRowExpand = WebPRescalerImportRowExpand_C;
  194. WebPRescalerImportRowShrink = WebPRescalerImportRowShrink_C;
  195. if (VP8GetCPUInfo != NULL) {
  196. #if defined(WEBP_HAVE_SSE2)
  197. if (VP8GetCPUInfo(kSSE2)) {
  198. WebPRescalerDspInitSSE2();
  199. }
  200. #endif
  201. #if defined(WEBP_USE_MIPS32)
  202. if (VP8GetCPUInfo(kMIPS32)) {
  203. WebPRescalerDspInitMIPS32();
  204. }
  205. #endif
  206. #if defined(WEBP_USE_MIPS_DSP_R2)
  207. if (VP8GetCPUInfo(kMIPSdspR2)) {
  208. WebPRescalerDspInitMIPSdspR2();
  209. }
  210. #endif
  211. #if defined(WEBP_USE_MSA)
  212. if (VP8GetCPUInfo(kMSA)) {
  213. WebPRescalerDspInitMSA();
  214. }
  215. #endif
  216. }
  217. #if defined(WEBP_HAVE_NEON)
  218. if (WEBP_NEON_OMIT_C_CODE ||
  219. (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
  220. WebPRescalerDspInitNEON();
  221. }
  222. #endif
  223. assert(WebPRescalerExportRowExpand != NULL);
  224. assert(WebPRescalerExportRowShrink != NULL);
  225. assert(WebPRescalerImportRowExpand != NULL);
  226. assert(WebPRescalerImportRowShrink != NULL);
  227. #endif // WEBP_REDUCE_SIZE
  228. }