gfx/ycbcr/ycbcr_to_rgb565.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include <stdlib.h>
     7 #include <limits.h>
     8 #include "nsDebug.h"
     9 #include "ycbcr_to_rgb565.h"
    10 #include "nsAlgorithm.h"
    14 #ifdef HAVE_YCBCR_TO_RGB565
    16 namespace mozilla {
    18 namespace gfx {
    20 /*This contains all of the parameters that are needed to convert a row.
    21   Passing them in a struct instead of as individual parameters saves the need
    22    to continually push onto the stack the ones that are fixed for every row.*/
    23 struct yuv2rgb565_row_scale_bilinear_ctx{
    24   uint16_t *rgb_row;
    25   const uint8_t *y_row;
    26   const uint8_t *u_row;
    27   const uint8_t *v_row;
    28   int y_yweight;
    29   int y_pitch;
    30   int width;
    31   int source_x0_q16;
    32   int source_dx_q16;
    33   /*Not used for 4:4:4, except with chroma-nearest.*/
    34   int source_uv_xoffs_q16;
    35   /*Not used for 4:4:4 or chroma-nearest.*/
    36   int uv_pitch;
    37   /*Not used for 4:2:2, 4:4:4, or chroma-nearest.*/
    38   int uv_yweight;
    39 };
    43 /*This contains all of the parameters that are needed to convert a row.
    44   Passing them in a struct instead of as individual parameters saves the need
    45    to continually push onto the stack the ones that are fixed for every row.*/
    46 struct yuv2rgb565_row_scale_nearest_ctx{
    47   uint16_t *rgb_row;
    48   const uint8_t *y_row;
    49   const uint8_t *u_row;
    50   const uint8_t *v_row;
    51   int width;
    52   int source_x0_q16;
    53   int source_dx_q16;
    54   /*Not used for 4:4:4.*/
    55   int source_uv_xoffs_q16;
    56 };
    60 typedef void (*yuv2rgb565_row_scale_bilinear_func)(
    61  const yuv2rgb565_row_scale_bilinear_ctx *ctx, int dither);
    63 typedef void (*yuv2rgb565_row_scale_nearest_func)(
    64  const yuv2rgb565_row_scale_nearest_ctx *ctx, int dither);
    68 # if defined(MOZILLA_MAY_SUPPORT_NEON)
    70 extern "C" void ScaleYCbCr42xToRGB565_BilinearY_Row_NEON(
    71  const yuv2rgb565_row_scale_bilinear_ctx *ctx, int dither);
    73 void __attribute((noinline)) yuv42x_to_rgb565_row_neon(uint16 *dst,
    74                                                        const uint8 *y,
    75                                                        const uint8 *u,
    76                                                        const uint8 *v,
    77                                                        int n,
    78                                                        int oddflag);
    80 #endif
    84 /*Bilinear interpolation of a single value.
    85   This uses the exact same formulas as the asm, even though it adds some extra
    86    shifts that do nothing but reduce accuracy.*/
    87 static int bislerp(const uint8_t *row,
    88                    int pitch,
    89                    int source_x,
    90                    int xweight,
    91                    int yweight) {
    92   int a;
    93   int b;
    94   int c;
    95   int d;
    96   a = row[source_x];
    97   b = row[source_x+1];
    98   c = row[source_x+pitch];
    99   d = row[source_x+pitch+1];
   100   a = ((a<<8)+(c-a)*yweight+128)>>8;
   101   b = ((b<<8)+(d-b)*yweight+128)>>8;
   102   return ((a<<8)+(b-a)*xweight+128)>>8;
   103 }
   105 /*Convert a single pixel from Y'CbCr to RGB565.
   106   This uses the exact same formulas as the asm, even though we could make the
   107    constants a lot more accurate with 32-bit wide registers.*/
   108 static uint16_t yu2rgb565(int y, int u, int v, int dither) {
   109   /*This combines the constant offset that needs to be added during the Y'CbCr
   110      conversion with a rounding offset that depends on the dither parameter.*/
   111   static const int DITHER_BIAS[4][3]={
   112     {-14240,    8704,    -17696},
   113     {-14240+128,8704+64, -17696+128},
   114     {-14240+256,8704+128,-17696+256},
   115     {-14240+384,8704+192,-17696+384}
   116   };
   117   int r;
   118   int g;
   119   int b;
   120   r = clamped((74*y+102*v+DITHER_BIAS[dither][0])>>9, 0, 31);
   121   g = clamped((74*y-25*u-52*v+DITHER_BIAS[dither][1])>>8, 0, 63);
   122   b = clamped((74*y+129*u+DITHER_BIAS[dither][2])>>9, 0, 31);
   123   return (uint16_t)(r<<11 | g<<5 | b);
   124 }
   126 static void ScaleYCbCr420ToRGB565_Bilinear_Row_C(
   127  const yuv2rgb565_row_scale_bilinear_ctx *ctx, int dither){
   128   int x;
   129   int source_x_q16;
   130   source_x_q16 = ctx->source_x0_q16;
   131   for (x = 0; x < ctx->width; x++) {
   132     int source_x;
   133     int xweight;
   134     int y;
   135     int u;
   136     int v;
   137     xweight = ((source_x_q16&0xFFFF)+128)>>8;
   138     source_x = source_x_q16>>16;
   139     y = bislerp(ctx->y_row, ctx->y_pitch, source_x, xweight, ctx->y_yweight);
   140     xweight = (((source_x_q16+ctx->source_uv_xoffs_q16)&0x1FFFF)+256)>>9;
   141     source_x = (source_x_q16+ctx->source_uv_xoffs_q16)>>17;
   142     source_x_q16 += ctx->source_dx_q16;
   143     u = bislerp(ctx->u_row, ctx->uv_pitch, source_x, xweight, ctx->uv_yweight);
   144     v = bislerp(ctx->v_row, ctx->uv_pitch, source_x, xweight, ctx->uv_yweight);
   145     ctx->rgb_row[x] = yu2rgb565(y, u, v, dither);
   146     dither ^= 3;
   147   }
   148 }
   150 static void ScaleYCbCr422ToRGB565_Bilinear_Row_C(
   151  const yuv2rgb565_row_scale_bilinear_ctx *ctx, int dither){
   152   int x;
   153   int source_x_q16;
   154   source_x_q16 = ctx->source_x0_q16;
   155   for (x = 0; x < ctx->width; x++) {
   156     int source_x;
   157     int xweight;
   158     int y;
   159     int u;
   160     int v;
   161     xweight = ((source_x_q16&0xFFFF)+128)>>8;
   162     source_x = source_x_q16>>16;
   163     y = bislerp(ctx->y_row, ctx->y_pitch, source_x, xweight, ctx->y_yweight);
   164     xweight = (((source_x_q16+ctx->source_uv_xoffs_q16)&0x1FFFF)+256)>>9;
   165     source_x = (source_x_q16+ctx->source_uv_xoffs_q16)>>17;
   166     source_x_q16 += ctx->source_dx_q16;
   167     u = bislerp(ctx->u_row, ctx->uv_pitch, source_x, xweight, ctx->y_yweight);
   168     v = bislerp(ctx->v_row, ctx->uv_pitch, source_x, xweight, ctx->y_yweight);
   169     ctx->rgb_row[x] = yu2rgb565(y, u, v, dither);
   170     dither ^= 3;
   171   }
   172 }
   174 static void ScaleYCbCr444ToRGB565_Bilinear_Row_C(
   175  const yuv2rgb565_row_scale_bilinear_ctx *ctx, int dither){
   176   int x;
   177   int source_x_q16;
   178   source_x_q16 = ctx->source_x0_q16;
   179   for (x = 0; x < ctx->width; x++) {
   180     int source_x;
   181     int xweight;
   182     int y;
   183     int u;
   184     int v;
   185     xweight = ((source_x_q16&0xFFFF)+128)>>8;
   186     source_x = source_x_q16>>16;
   187     source_x_q16 += ctx->source_dx_q16;
   188     y = bislerp(ctx->y_row, ctx->y_pitch, source_x, xweight, ctx->y_yweight);
   189     u = bislerp(ctx->u_row, ctx->y_pitch, source_x, xweight, ctx->y_yweight);
   190     v = bislerp(ctx->v_row, ctx->y_pitch, source_x, xweight, ctx->y_yweight);
   191     ctx->rgb_row[x] = yu2rgb565(y, u, v, dither);
   192     dither ^= 3;
   193   }
   194 }
   196 static void ScaleYCbCr42xToRGB565_BilinearY_Row_C(
   197  const yuv2rgb565_row_scale_bilinear_ctx *ctx, int dither){
   198   int x;
   199   int source_x_q16;
   200   source_x_q16 = ctx->source_x0_q16;
   201   for (x = 0; x < ctx->width; x++) {
   202     int source_x;
   203     int xweight;
   204     int y;
   205     int u;
   206     int v;
   207     xweight = ((source_x_q16&0xFFFF)+128)>>8;
   208     source_x = source_x_q16>>16;
   209     y = bislerp(ctx->y_row, ctx->y_pitch, source_x, xweight, ctx->y_yweight);
   210     source_x = (source_x_q16+ctx->source_uv_xoffs_q16)>>17;
   211     source_x_q16 += ctx->source_dx_q16;
   212     u = ctx->u_row[source_x];
   213     v = ctx->v_row[source_x];
   214     ctx->rgb_row[x] = yu2rgb565(y, u, v, dither);
   215     dither ^= 3;
   216   }
   217 }
   219 static void ScaleYCbCr444ToRGB565_BilinearY_Row_C(
   220  const yuv2rgb565_row_scale_bilinear_ctx *ctx, int dither){
   221   int x;
   222   int source_x_q16;
   223   source_x_q16 = ctx->source_x0_q16;
   224   for (x = 0; x < ctx->width; x++) {
   225     int source_x;
   226     int xweight;
   227     int y;
   228     int u;
   229     int v;
   230     xweight = ((source_x_q16&0xFFFF)+128)>>8;
   231     source_x = source_x_q16>>16;
   232     y = bislerp(ctx->y_row, ctx->y_pitch, source_x, xweight, ctx->y_yweight);
   233     source_x = (source_x_q16+ctx->source_uv_xoffs_q16)>>16;
   234     source_x_q16 += ctx->source_dx_q16;
   235     u = ctx->u_row[source_x];
   236     v = ctx->v_row[source_x];
   237     ctx->rgb_row[x] = yu2rgb565(y, u, v, dither);
   238     dither ^= 3;
   239   }
   240 }
   242 static void ScaleYCbCr42xToRGB565_Nearest_Row_C(
   243  const yuv2rgb565_row_scale_nearest_ctx *ctx, int dither){
   244   int y;
   245   int u;
   246   int v;
   247   int x;
   248   int source_x_q16;
   249   int source_x;
   250   source_x_q16 = ctx->source_x0_q16;
   251   for (x = 0; x < ctx->width; x++) {
   252     source_x = source_x_q16>>16;
   253     y = ctx->y_row[source_x];
   254     source_x = (source_x_q16+ctx->source_uv_xoffs_q16)>>17;
   255     source_x_q16 += ctx->source_dx_q16;
   256     u = ctx->u_row[source_x];
   257     v = ctx->v_row[source_x];
   258     ctx->rgb_row[x] = yu2rgb565(y, u, v, dither);
   259     dither ^= 3;
   260   }
   261 }
   263 static void ScaleYCbCr444ToRGB565_Nearest_Row_C(
   264  const yuv2rgb565_row_scale_nearest_ctx *ctx, int dither){
   265   int y;
   266   int u;
   267   int v;
   268   int x;
   269   int source_x_q16;
   270   int source_x;
   271   source_x_q16 = ctx->source_x0_q16;
   272   for (x = 0; x < ctx->width; x++) {
   273     source_x = source_x_q16>>16;
   274     source_x_q16 += ctx->source_dx_q16;
   275     y = ctx->y_row[source_x];
   276     u = ctx->u_row[source_x];
   277     v = ctx->v_row[source_x];
   278     ctx->rgb_row[x] = yu2rgb565(y, u, v, dither);
   279     dither ^= 3;
   280   }
   281 }
   283 NS_GFX_(void) ScaleYCbCrToRGB565(const uint8_t *y_buf,
   284                                  const uint8_t *u_buf,
   285                                  const uint8_t *v_buf,
   286                                  uint8_t *rgb_buf,
   287                                  int source_x0,
   288                                  int source_y0,
   289                                  int source_width,
   290                                  int source_height,
   291                                  int width,
   292                                  int height,
   293                                  int y_pitch,
   294                                  int uv_pitch,
   295                                  int rgb_pitch,
   296                                  YUVType yuv_type,
   297                                  ScaleFilter filter) {
   298   int source_x0_q16;
   299   int source_y0_q16;
   300   int source_dx_q16;
   301   int source_dy_q16;
   302   int source_uv_xoffs_q16;
   303   int source_uv_yoffs_q16;
   304   int x_shift;
   305   int y_shift;
   306   int ymin;
   307   int ymax;
   308   int uvmin;
   309   int uvmax;
   310   int dither;
   311   /*We don't support negative destination rectangles (just flip the source
   312      instead), and for empty ones there's nothing to do.*/
   313   if (width <= 0 || height <= 0)
   314     return;
   315   /*These bounds are required to avoid 16.16 fixed-point overflow.*/
   316   NS_ASSERTION(source_x0 > (INT_MIN>>16) && source_x0 < (INT_MAX>>16),
   317     "ScaleYCbCrToRGB565 source X offset out of bounds.");
   318   NS_ASSERTION(source_x0+source_width > (INT_MIN>>16)
   319             && source_x0+source_width < (INT_MAX>>16),
   320     "ScaleYCbCrToRGB565 source width out of bounds.");
   321   NS_ASSERTION(source_y0 > (INT_MIN>>16) && source_y0 < (INT_MAX>>16),
   322     "ScaleYCbCrToRGB565 source Y offset out of bounds.");
   323   NS_ASSERTION(source_y0+source_height > (INT_MIN>>16)
   324             && source_y0+source_height < (INT_MAX>>16),
   325     "ScaleYCbCrToRGB565 source height out of bounds.");
   326   /*We require the same stride for Y' and Cb and Cr for 4:4:4 content.*/
   327   NS_ASSERTION(yuv_type != YV24 || y_pitch == uv_pitch,
   328     "ScaleYCbCrToRGB565 luma stride differs from chroma for 4:4:4 content.");
   329   /*We assume we can read outside the bounds of the input, because it makes
   330      the code much simpler (and in practice is true: both Theora and VP8 return
   331      padded reference frames).
   332     In practice, we do not even _have_ the actual bounds of the source, as
   333      we are passed a crop rectangle from it, and not the dimensions of the full
   334      image.
   335     This assertion will not guarantee our out-of-bounds reads are safe, but it
   336      should at least catch the simple case of passing in an unpadded buffer.*/
   337   NS_ASSERTION(abs(y_pitch) >= abs(source_width)+16,
   338     "ScaleYCbCrToRGB565 source image unpadded?");
   339   /*The NEON code requires the pointers to be aligned to a 16-byte boundary at
   340      the start of each row.
   341     This should be true for all of our sources.
   342     We could try to fix this up if it's not true by adjusting source_x0, but
   343      that would require the mis-alignment to be the same for the U and V
   344      planes.*/
   345   NS_ASSERTION((y_pitch&15) == 0 && (uv_pitch&15) == 0 &&
   346    ((y_buf-(uint8_t *)nullptr)&15) == 0 &&
   347    ((u_buf-(uint8_t *)nullptr)&15) == 0 &&
   348    ((v_buf-(uint8_t *)nullptr)&15) == 0,
   349    "ScaleYCbCrToRGB565 source image unaligned");
   350   /*We take an area-based approach to pixel coverage to avoid shifting by small
   351      amounts (or not so small, when up-scaling or down-scaling by a large
   352      factor).
   354     An illustrative example: scaling 4:2:0 up by 2, using JPEG chroma cositing^.
   356     + = RGB destination locations
   357     * = Y' source locations
   358     - = Cb, Cr source locations
   360     +   +   +   +  +   +   +   +
   361       *       *      *       *
   362     +   +   +   +  +   +   +   +
   363           -              -
   364     +   +   +   +  +   +   +   +
   365       *       *      *       *
   366     +   +   +   +  +   +   +   +
   368     +   +   +   +  +   +   +   +
   369       *       *      *       *
   370     +   +   +   +  +   +   +   +
   371           -              -
   372     +   +   +   +  +   +   +   +
   373       *       *      *       *
   374     +   +   +   +  +   +   +   +
   376     So, the coordinates of the upper-left + (first destination site) should
   377      be (-0.25,-0.25) in the source Y' coordinate system.
   378     Similarly, the coordinates should be (-0.375,-0.375) in the source Cb, Cr
   379      coordinate system.
   380     Note that the origin and scale of these two coordinate systems is not the
   381      same!
   383     ^JPEG cositing is required for Theora; VP8 doesn't specify cositing rules,
   384      but nearly all software converters in existence (at least those that are
   385      open source, and many that are not) use JPEG cositing instead of MPEG.*/
   386   source_dx_q16 = (source_width<<16) / width;
   387   source_x0_q16 = (source_x0<<16)+(source_dx_q16>>1)-0x8000;
   388   source_dy_q16 = (source_height<<16) / height;
   389   source_y0_q16 = (source_y0<<16)+(source_dy_q16>>1)-0x8000;
   390   x_shift = (yuv_type != YV24);
   391   y_shift = (yuv_type == YV12);
   392   /*These two variables hold the difference between the origins of the Y' and
   393      the Cb, Cr coordinate systems, using the scale of the Y' coordinate
   394      system.*/
   395   source_uv_xoffs_q16 = -(x_shift<<15);
   396   source_uv_yoffs_q16 = -(y_shift<<15);
   397   /*Compute the range of source rows we'll actually use.
   398     This doesn't guarantee we won't read outside this range.*/
   399   ymin = source_height >= 0 ? source_y0 : source_y0+source_height-1;
   400   ymax = source_height >= 0 ? source_y0+source_height-1 : source_y0;
   401   uvmin = ymin>>y_shift;
   402   uvmax = ((ymax+1+y_shift)>>y_shift)-1;
   403   /*Pick a dithering pattern.
   404     The "&3" at the end is just in case RAND_MAX is lying.*/
   405   dither = (rand()/(RAND_MAX>>2))&3;
   406   /*Nearest-neighbor scaling.*/
   407   if (filter == FILTER_NONE) {
   408     yuv2rgb565_row_scale_nearest_ctx ctx;
   409     yuv2rgb565_row_scale_nearest_func scale_row;
   410     int y;
   411     /*Add rounding offsets once, in advance.*/
   412     source_x0_q16 += 0x8000;
   413     source_y0_q16 += 0x8000;
   414     source_uv_xoffs_q16 += (x_shift<<15);
   415     source_uv_yoffs_q16 += (y_shift<<15);
   416     if (yuv_type == YV12)
   417       scale_row = ScaleYCbCr42xToRGB565_Nearest_Row_C;
   418     else
   419       scale_row = ScaleYCbCr444ToRGB565_Nearest_Row_C;
   420     ctx.width = width;
   421     ctx.source_x0_q16 = source_x0_q16;
   422     ctx.source_dx_q16 = source_dx_q16;
   423     ctx.source_uv_xoffs_q16 = source_uv_xoffs_q16;
   424     for (y=0; y<height; y++) {
   425       int source_y;
   426       ctx.rgb_row = (uint16_t *)(rgb_buf + y*rgb_pitch);
   427       source_y = source_y0_q16>>16;
   428       source_y = clamped(source_y, ymin, ymax);
   429       ctx.y_row = y_buf + source_y*y_pitch;
   430       source_y = (source_y0_q16+source_uv_yoffs_q16)>>(16+y_shift);
   431       source_y = clamped(source_y, uvmin, uvmax);
   432       source_y0_q16 += source_dy_q16;
   433       ctx.u_row = u_buf + source_y*uv_pitch;
   434       ctx.v_row = v_buf + source_y*uv_pitch;
   435       (*scale_row)(&ctx, dither);
   436       dither ^= 2;
   437     }
   438   }
   439   /*Bilinear scaling.*/
   440   else {
   441     yuv2rgb565_row_scale_bilinear_ctx ctx;
   442     yuv2rgb565_row_scale_bilinear_func scale_row;
   443     int uvxscale_min;
   444     int uvxscale_max;
   445     int uvyscale_min;
   446     int uvyscale_max;
   447     int y;
   448     /*Check how close the chroma scaling is to unity.
   449       If it's close enough, we can get away with nearest-neighbor chroma
   450        sub-sampling, and only doing bilinear on luma.
   451       If a given axis is subsampled, we use bounds on the luma step of
   452        [0.67...2], which is equivalent to scaling chroma by [1...3].
   453       If it's not subsampled, we use bounds of [0.5...1.33], which is
   454        equivalent to scaling chroma by [0.75...2].
   455       The lower bound is chosen as a trade-off between speed and how terrible
   456        nearest neighbor looks when upscaling.*/
   457 # define CHROMA_NEAREST_SUBSAMP_STEP_MIN  0xAAAA
   458 # define CHROMA_NEAREST_NORMAL_STEP_MIN   0x8000
   459 # define CHROMA_NEAREST_SUBSAMP_STEP_MAX 0x20000
   460 # define CHROMA_NEAREST_NORMAL_STEP_MAX  0x15555
   461     uvxscale_min = yuv_type != YV24 ?
   462      CHROMA_NEAREST_SUBSAMP_STEP_MIN : CHROMA_NEAREST_NORMAL_STEP_MIN;
   463     uvxscale_max = yuv_type != YV24 ?
   464      CHROMA_NEAREST_SUBSAMP_STEP_MAX : CHROMA_NEAREST_NORMAL_STEP_MAX;
   465     uvyscale_min = yuv_type == YV12 ?
   466      CHROMA_NEAREST_SUBSAMP_STEP_MIN : CHROMA_NEAREST_NORMAL_STEP_MIN;
   467     uvyscale_max = yuv_type == YV12 ?
   468      CHROMA_NEAREST_SUBSAMP_STEP_MAX : CHROMA_NEAREST_NORMAL_STEP_MAX;
   469     if (uvxscale_min <= abs(source_dx_q16)
   470      && abs(source_dx_q16) <= uvxscale_max
   471      && uvyscale_min <= abs(source_dy_q16)
   472      && abs(source_dy_q16) <= uvyscale_max) {
   473       /*Add the rounding offsets now.*/
   474       source_uv_xoffs_q16 += 1<<(15+x_shift);
   475       source_uv_yoffs_q16 += 1<<(15+y_shift);
   476       if (yuv_type != YV24) {
   477         scale_row =
   478 #  if defined(MOZILLA_MAY_SUPPORT_NEON)
   479          supports_neon() ? ScaleYCbCr42xToRGB565_BilinearY_Row_NEON :
   480 #  endif
   481          ScaleYCbCr42xToRGB565_BilinearY_Row_C;
   482       }
   483       else
   484         scale_row = ScaleYCbCr444ToRGB565_BilinearY_Row_C;
   485     }
   486     else {
   487       if (yuv_type == YV12)
   488         scale_row = ScaleYCbCr420ToRGB565_Bilinear_Row_C;
   489       else if (yuv_type == YV16)
   490         scale_row = ScaleYCbCr422ToRGB565_Bilinear_Row_C;
   491       else
   492         scale_row = ScaleYCbCr444ToRGB565_Bilinear_Row_C;
   493     }
   494     ctx.width = width;
   495     ctx.y_pitch = y_pitch;
   496     ctx.source_x0_q16 = source_x0_q16;
   497     ctx.source_dx_q16 = source_dx_q16;
   498     ctx.source_uv_xoffs_q16 = source_uv_xoffs_q16;
   499     ctx.uv_pitch = uv_pitch;
   500     for (y=0; y<height; y++) {
   501       int source_y;
   502       int yweight;
   503       int uvweight;
   504       ctx.rgb_row = (uint16_t *)(rgb_buf + y*rgb_pitch);
   505       source_y = (source_y0_q16+128)>>16;
   506       yweight = ((source_y0_q16+128)>>8)&0xFF;
   507       if (source_y < ymin) {
   508         source_y = ymin;
   509         yweight = 0;
   510       }
   511       if (source_y > ymax) {
   512         source_y = ymax;
   513         yweight = 0;
   514       }
   515       ctx.y_row = y_buf + source_y*y_pitch;
   516       source_y = source_y0_q16+source_uv_yoffs_q16+(128<<y_shift);
   517       source_y0_q16 += source_dy_q16;
   518       uvweight = source_y>>(8+y_shift)&0xFF;
   519       source_y >>= 16+y_shift;
   520       if (source_y < uvmin) {
   521         source_y = uvmin;
   522         uvweight = 0;
   523       }
   524       if (source_y > uvmax) {
   525         source_y = uvmax;
   526         uvweight = 0;
   527       }
   528       ctx.u_row = u_buf + source_y*uv_pitch;
   529       ctx.v_row = v_buf + source_y*uv_pitch;
   530       ctx.y_yweight = yweight;
   531       ctx.uv_yweight = uvweight;
   532       (*scale_row)(&ctx, dither);
   533       dither ^= 2;
   534     }
   535   }
   536 }
   538 NS_GFX_(bool) IsScaleYCbCrToRGB565Fast(int source_x0,
   539                                        int source_y0,
   540                                        int source_width,
   541                                        int source_height,
   542                                        int width,
   543                                        int height,
   544                                        YUVType yuv_type,
   545                                        ScaleFilter filter)
   546 {
   547   // Very fast.
   548   if (width <= 0 || height <= 0)
   549     return true;
   550 #  if defined(MOZILLA_MAY_SUPPORT_NEON)
   551   if (filter != FILTER_NONE) {
   552     int source_dx_q16;
   553     int source_dy_q16;
   554     int uvxscale_min;
   555     int uvxscale_max;
   556     int uvyscale_min;
   557     int uvyscale_max;
   558     source_dx_q16 = (source_width<<16) / width;
   559     source_dy_q16 = (source_height<<16) / height;
   560     uvxscale_min = yuv_type != YV24 ?
   561      CHROMA_NEAREST_SUBSAMP_STEP_MIN : CHROMA_NEAREST_NORMAL_STEP_MIN;
   562     uvxscale_max = yuv_type != YV24 ?
   563      CHROMA_NEAREST_SUBSAMP_STEP_MAX : CHROMA_NEAREST_NORMAL_STEP_MAX;
   564     uvyscale_min = yuv_type == YV12 ?
   565      CHROMA_NEAREST_SUBSAMP_STEP_MIN : CHROMA_NEAREST_NORMAL_STEP_MIN;
   566     uvyscale_max = yuv_type == YV12 ?
   567      CHROMA_NEAREST_SUBSAMP_STEP_MAX : CHROMA_NEAREST_NORMAL_STEP_MAX;
   568     if (uvxscale_min <= abs(source_dx_q16)
   569      && abs(source_dx_q16) <= uvxscale_max
   570      && uvyscale_min <= abs(source_dy_q16)
   571      && abs(source_dy_q16) <= uvyscale_max) {
   572       if (yuv_type != YV24)
   573         return supports_neon();
   574     }
   575   }
   576 #  endif
   577   return false;
   578 }
   582 void yuv_to_rgb565_row_c(uint16 *dst,
   583                          const uint8 *y,
   584                          const uint8 *u,
   585                          const uint8 *v,
   586                          int x_shift,
   587                          int pic_x,
   588                          int pic_width)
   589 {
   590   int x;
   591   for (x = 0; x < pic_width; x++)
   592   {
   593     dst[x] = yu2rgb565(y[pic_x+x],
   594                        u[(pic_x+x)>>x_shift],
   595                        v[(pic_x+x)>>x_shift],
   596                        2); // Disable dithering for now.
   597   }
   598 }
   600 NS_GFX_(void) ConvertYCbCrToRGB565(const uint8* y_buf,
   601                                    const uint8* u_buf,
   602                                    const uint8* v_buf,
   603                                    uint8* rgb_buf,
   604                                    int pic_x,
   605                                    int pic_y,
   606                                    int pic_width,
   607                                    int pic_height,
   608                                    int y_pitch,
   609                                    int uv_pitch,
   610                                    int rgb_pitch,
   611                                    YUVType yuv_type)
   612 {
   613   int x_shift;
   614   int y_shift;
   615   x_shift = yuv_type != YV24;
   616   y_shift = yuv_type == YV12;
   617 #  ifdef MOZILLA_MAY_SUPPORT_NEON
   618   if (yuv_type != YV24 && supports_neon())
   619   {
   620     for (int i = 0; i < pic_height; i++) {
   621       int yoffs;
   622       int uvoffs;
   623       yoffs = y_pitch * (pic_y+i) + pic_x;
   624       uvoffs = uv_pitch * ((pic_y+i)>>y_shift) + (pic_x>>x_shift);
   625       yuv42x_to_rgb565_row_neon((uint16*)(rgb_buf + rgb_pitch * i),
   626                                 y_buf + yoffs,
   627                                 u_buf + uvoffs,
   628                                 v_buf + uvoffs,
   629                                 pic_width,
   630                                 pic_x&x_shift);
   631     }
   632   }
   633   else
   634 #  endif
   635   {
   636     for (int i = 0; i < pic_height; i++) {
   637       int yoffs;
   638       int uvoffs;
   639       yoffs = y_pitch * (pic_y+i);
   640       uvoffs = uv_pitch * ((pic_y+i)>>y_shift);
   641       yuv_to_rgb565_row_c((uint16*)(rgb_buf + rgb_pitch * i),
   642                           y_buf + yoffs,
   643                           u_buf + uvoffs,
   644                           v_buf + uvoffs,
   645                           x_shift,
   646                           pic_x,
   647                           pic_width);
   648     }
   649   }
   650 }
   652 NS_GFX_(bool) IsConvertYCbCrToRGB565Fast(int pic_x,
   653                                          int pic_y,
   654                                          int pic_width,
   655                                          int pic_height,
   656                                          YUVType yuv_type)
   657 {
   658 #  if defined(MOZILLA_MAY_SUPPORT_NEON)
   659   return (yuv_type != YV24 && supports_neon());
   660 #  else
   661   return false;
   662 #  endif
   663 }
   665 } // namespace gfx
   667 } // namespace mozilla
   669 #endif // HAVE_YCBCR_TO_RGB565

mercurial