Skip to content

Commit

Permalink
Use libjpeg-turbo for YUV->RGB conversion in jpeg encoder
Browse files Browse the repository at this point in the history
This remove the previous codepath, which performed a less
accurate conversion to YUV.

It actually faster to use the more accurate conversion, now
that we have updated to libjpeg-turbo.

z620 Performance Speed-Up:
mandrill.jpg (512x512): 1.13x
color_wheel.jpg (128x128): 1.12x

This should fix:
https://buganizer.corp.google.com/u/0/issues/28161384
https://buganizer.corp.google.com/u/0/issues/21891795

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1886183002

Review URL: https://codereview.chromium.org/1886183002
  • Loading branch information
mattsarett authored and Commit bot committed Apr 18, 2016
1 parent b4b83dc commit c7d01d3
Showing 1 changed file with 16 additions and 113 deletions.
129 changes: 16 additions & 113 deletions src/images/SkJPEGImageEncoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,170 +28,72 @@ extern "C" {
// These enable timing code that report milliseconds for an encoding
//#define TIME_ENCODE

// this enables our rgb->yuv code, which is faster than libjpeg on ARM
#define WE_CONVERT_TO_YUV

///////////////////////////////////////////////////////////////////////////////

#include "SkColorPriv.h"

// taken from jcolor.c in libjpeg
#if 0 // 16bit - precise but slow
#define CYR 19595 // 0.299
#define CYG 38470 // 0.587
#define CYB 7471 // 0.114

#define CUR -11059 // -0.16874
#define CUG -21709 // -0.33126
#define CUB 32768 // 0.5

#define CVR 32768 // 0.5
#define CVG -27439 // -0.41869
#define CVB -5329 // -0.08131

#define CSHIFT 16
#else // 8bit - fast, slightly less precise
#define CYR 77 // 0.299
#define CYG 150 // 0.587
#define CYB 29 // 0.114

#define CUR -43 // -0.16874
#define CUG -85 // -0.33126
#define CUB 128 // 0.5

#define CVR 128 // 0.5
#define CVG -107 // -0.41869
#define CVB -21 // -0.08131

#define CSHIFT 8
#endif

static void rgb2yuv_32(uint8_t dst[], SkPMColor c) {
int r = SkGetPackedR32(c);
int g = SkGetPackedG32(c);
int b = SkGetPackedB32(c);

int y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT;
int u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT;
int v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT;

dst[0] = SkToU8(y);
dst[1] = SkToU8(u + 128);
dst[2] = SkToU8(v + 128);
}

static void rgb2yuv_4444(uint8_t dst[], U16CPU c) {
int r = SkGetPackedR4444(c);
int g = SkGetPackedG4444(c);
int b = SkGetPackedB4444(c);

int y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4);
int u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4);
int v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4);

dst[0] = SkToU8(y);
dst[1] = SkToU8(u + 128);
dst[2] = SkToU8(v + 128);
}

static void rgb2yuv_16(uint8_t dst[], U16CPU c) {
int r = SkGetPackedR16(c);
int g = SkGetPackedG16(c);
int b = SkGetPackedB16(c);

int y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2);
int u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2);
int v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2);

dst[0] = SkToU8(y);
dst[1] = SkToU8(u + 128);
dst[2] = SkToU8(v + 128);
}

///////////////////////////////////////////////////////////////////////////////

typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst,
const void* SK_RESTRICT src, int width,
const SkPMColor* SK_RESTRICT ctable);

static void Write_32_YUV(uint8_t* SK_RESTRICT dst,
static void Write_32_RGB(uint8_t* SK_RESTRICT dst,
const void* SK_RESTRICT srcRow, int width,
const SkPMColor*) {
const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow;
while (--width >= 0) {
#ifdef WE_CONVERT_TO_YUV
rgb2yuv_32(dst, *src++);
#else
uint32_t c = *src++;
dst[0] = SkGetPackedR32(c);
dst[1] = SkGetPackedG32(c);
dst[2] = SkGetPackedB32(c);
#endif
dst += 3;
}
}

static void Write_4444_YUV(uint8_t* SK_RESTRICT dst,
static void Write_4444_RGB(uint8_t* SK_RESTRICT dst,
const void* SK_RESTRICT srcRow, int width,
const SkPMColor*) {
const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow;
while (--width >= 0) {
#ifdef WE_CONVERT_TO_YUV
rgb2yuv_4444(dst, *src++);
#else
SkPMColor16 c = *src++;
dst[0] = SkPacked4444ToR32(c);
dst[1] = SkPacked4444ToG32(c);
dst[2] = SkPacked4444ToB32(c);
#endif
dst += 3;
}
}

static void Write_16_YUV(uint8_t* SK_RESTRICT dst,
static void Write_16_RGB(uint8_t* SK_RESTRICT dst,
const void* SK_RESTRICT srcRow, int width,
const SkPMColor*) {
const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow;
while (--width >= 0) {
#ifdef WE_CONVERT_TO_YUV
rgb2yuv_16(dst, *src++);
#else
uint16_t c = *src++;
dst[0] = SkPacked16ToR32(c);
dst[1] = SkPacked16ToG32(c);
dst[2] = SkPacked16ToB32(c);
#endif
dst += 3;
}
}

static void Write_Index_YUV(uint8_t* SK_RESTRICT dst,
static void Write_Index_RGB(uint8_t* SK_RESTRICT dst,
const void* SK_RESTRICT srcRow, int width,
const SkPMColor* SK_RESTRICT ctable) {
const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow;
while (--width >= 0) {
#ifdef WE_CONVERT_TO_YUV
rgb2yuv_32(dst, ctable[*src++]);
#else
uint32_t c = ctable[*src++];
dst[0] = SkGetPackedR32(c);
dst[1] = SkGetPackedG32(c);
dst[2] = SkGetPackedB32(c);
#endif
dst += 3;
}
}

static WriteScanline ChooseWriter(const SkBitmap& bm) {
switch (bm.colorType()) {
case kN32_SkColorType:
return Write_32_YUV;
return Write_32_RGB;
case kRGB_565_SkColorType:
return Write_16_YUV;
return Write_16_RGB;
case kARGB_4444_SkColorType:
return Write_4444_YUV;
return Write_4444_RGB;
case kIndex_8_SkColorType:
return Write_Index_YUV;
return Write_Index_RGB;
default:
return nullptr;
}
Expand Down Expand Up @@ -233,19 +135,20 @@ class SkJPEGImageEncoder : public SkImageEncoder {
cinfo.image_width = bm.width();
cinfo.image_height = bm.height();
cinfo.input_components = 3;
#ifdef WE_CONVERT_TO_YUV
cinfo.in_color_space = JCS_YCbCr;
#else

// FIXME: Can we take advantage of other in_color_spaces in libjpeg-turbo?
cinfo.in_color_space = JCS_RGB;
#endif

// The gamma value is ignored by libjpeg-turbo.
cinfo.input_gamma = 1;

jpeg_set_defaults(&cinfo);

// Tells libjpeg-turbo to compute optimal Huffman coding tables
// for the image. This improves compression at the cost of
// slower encode performance.
cinfo.optimize_coding = TRUE;
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
#ifdef DCT_IFAST_SUPPORTED
cinfo.dct_method = JDCT_IFAST;
#endif

jpeg_start_compress(&cinfo, TRUE);

Expand Down

0 comments on commit c7d01d3

Please sign in to comment.