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