--- a/gfx/layers/basic/BasicImages.cpp
+++ b/gfx/layers/basic/BasicImages.cpp
@@ -139,57 +139,67 @@ BasicPlanarYCbCrImage::SetData(const Dat
// Do some sanity checks to prevent integer overflow
if (aData.mYSize.width > 16384 || aData.mYSize.height > 16384) {
NS_ERROR("Illegal width or height");
return;
}
gfxASurface::gfxImageFormat format = GetOffscreenFormat();
- // 'prescale' is true if the scaling is to be done as part of the
- // YCbCr to RGB conversion rather than on the RGB data when rendered.
- // We don't prescale if the image has an offset. See bug 639415.
- PRBool prescale = mScaleHint.width > 0 && mScaleHint.height > 0 &&
- aData.mPicX == 0 && aData.mPicY == 0;
- if (format == gfxASurface::ImageFormatRGB16_565) {
- if (have_ycbcr_to_rgb565()) {
- // yuv2rgb16 with scale function not yet available for NEON
- prescale = PR_FALSE;
- } else {
- // yuv2rgb16 function not yet available for non-NEON
- format = gfxASurface::ImageFormatRGB24;
- }
- }
- gfxIntSize size(prescale ? mScaleHint.width : aData.mPicSize.width,
- prescale ? mScaleHint.height : aData.mPicSize.height);
-
- mStride = gfxASurface::FormatStrideForWidth(format, size.width);
- mBuffer = new PRUint8[size.height * mStride];
- if (!mBuffer) {
- // out of memory
- return;
- }
-
gfx::YUVType type = gfx::YV12;
if (aData.mYSize.width == aData.mCbCrSize.width &&
aData.mYSize.height == aData.mCbCrSize.height) {
type = gfx::YV24;
}
else if (aData.mYSize.width / 2 == aData.mCbCrSize.width &&
aData.mYSize.height == aData.mCbCrSize.height) {
type = gfx::YV16;
}
else if (aData.mYSize.width / 2 == aData.mCbCrSize.width &&
aData.mYSize.height / 2 == aData.mCbCrSize.height ) {
type = gfx::YV12;
}
else {
NS_ERROR("YCbCr format not supported");
}
-
+
+ // 'prescale' is true if the scaling is to be done as part of the
+ // YCbCr to RGB conversion rather than on the RGB data when rendered.
+ // We don't prescale if the image has an offset. See bug 639415.
+ PRBool prescale = mScaleHint.width > 0 && mScaleHint.height > 0 &&
+ aData.mPicX == 0 && aData.mPicY == 0;
+ if (format == gfxASurface::ImageFormatRGB16_565) {
+#if defined(HAVE_YCBCR_TO_RGB565)
+ if (prescale && gfx::IsConvertYCbCrToRGB565Fast(aData.mPicX,
+ aData.mPicY,
+ aData.mPicSize.width,
+ aData.mPicSize.height,
+ type)) {
+ // yuv2rgb16 with scale function not yet available for NEON
+ prescale = PR_FALSE;
+ } else
+#endif
+ {
+ // yuv2rgb16 function not yet available for non-NEON, and currently
+ // using it requires a number of extra graphics operations, so it's
+ // probably better to fall back to 24-bit RGB.
+ // See https://bugzilla.mozilla.org/show_bug.cgi?id=641196
+ format = gfxASurface::ImageFormatRGB24;
+ }
+ }
+ gfxIntSize size(prescale ? mScaleHint.width : aData.mPicSize.width,
+ prescale ? mScaleHint.height : aData.mPicSize.height);
+
+ mStride = gfxASurface::FormatStrideForWidth(format, size.width);
+ mBuffer = new PRUint8[size.height * mStride];
+ if (!mBuffer) {
+ // out of memory
+ return;
+ }
+
// Convert from YCbCr to RGB now, scaling the image if needed.
if (size != aData.mPicSize) {
if (format == gfxASurface::ImageFormatRGB24) {
gfx::ScaleYCbCrToRGB32(aData.mYChannel,
aData.mCbChannel,
aData.mCrChannel,
mBuffer,
aData.mPicSize.width,
@@ -201,44 +211,44 @@ BasicPlanarYCbCrImage::SetData(const Dat
mStride,
type,
gfx::ROTATE_0,
gfx::FILTER_BILINEAR);
} else {
NS_ERROR("Fail, ScaleYCbCrToRGB format not supported\n");
}
} else { // no prescale
+#if defined(HAVE_YCBCR_TO_RGB565)
if (format == gfxASurface::ImageFormatRGB16_565) {
- NS_ASSERTION(have_ycbcr_to_rgb565(), "Cannot convert YCbCr to RGB565");
gfx::ConvertYCbCrToRGB565(aData.mYChannel,
aData.mCbChannel,
aData.mCrChannel,
mBuffer,
aData.mPicX,
aData.mPicY,
aData.mPicSize.width,
aData.mPicSize.height,
aData.mYStride,
aData.mCbCrStride,
mStride,
type);
- } else { // format != gfxASurface::ImageFormatRGB16_565
+ } else // format != gfxASurface::ImageFormatRGB16_565
+#endif
gfx::ConvertYCbCrToRGB32(aData.mYChannel,
aData.mCbChannel,
aData.mCrChannel,
mBuffer,
aData.mPicX,
aData.mPicY,
aData.mPicSize.width,
aData.mPicSize.height,
aData.mYStride,
aData.mCbCrStride,
mStride,
type);
- }
}
SetOffscreenFormat(format);
mSize = size;
}
static cairo_user_data_key_t imageSurfaceDataKey;
static void
--- a/gfx/ycbcr/README
+++ b/gfx/ycbcr/README
@@ -1,20 +1,23 @@
This color conversion code is from the Chromium open source project available here:
http://code.google.com/chromium/
The code comes from svn revision 63840 on 2010-10-26.
+If you just want to check out this individual directory, use:
+
+svn co -r 63840 http://src.chromium.org/svn/trunk/src/media/base
+
The code was copied from a Chromium svn checkout using the 'update.sh' script which then applies patches for our build and to add dynamic CPU detection.
convert.patch contains the following changes:
* Change Chromium code to build using Mozilla build system.
* Add runtime CPU detection for MMX
* Move default C implementation to work on all platforms.
* Change Chromium code to allow a picture region.
* The YUV conversion will convert within this picture region only.
* Add YCbCr 4:4:4 support
- * Bug 616469 - Add YCbCr to rgb16_565 conversion support.
* Bug 619178 - Update CPU detection in yuv_convert to new SSE.h interface.
* Bug 616778 - Split yuv_convert FilterRows vectorized code into separate files so it can
be properly guarded with cpuid() calls.
--- a/gfx/ycbcr/convert.patch
+++ b/gfx/ycbcr/convert.patch
@@ -1,12 +1,12 @@
diff --git a/gfx/ycbcr/yuv_convert.cpp b/gfx/ycbcr/yuv_convert.cpp
--- a/gfx/ycbcr/yuv_convert.cpp
+++ b/gfx/ycbcr/yuv_convert.cpp
-@@ -6,145 +6,133 @@
+@@ -6,145 +6,102 @@
// http://www.fourcc.org/yuv.php
// The actual conversion is best described here
// http://en.wikipedia.org/wiki/YUV
// An article on optimizing YUV conversion using tables instead of multiplies
// http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf
//
// YV12 is a full plane of Y and a half height, half width chroma planes
// YV16 is a full plane of Y and a full height, half width chroma planes
@@ -33,56 +33,25 @@ diff --git a/gfx/ycbcr/yuv_convert.cpp b
-#include <emmintrin.h>
-#endif
-
-namespace media {
-
+#include "yuv_row.h"
+#include "mozilla/SSE.h"
+
-+#ifdef HAVE_YCBCR_TO_RGB565
-+void __attribute((noinline)) yv12_to_rgb565_neon(uint16 *dst, const uint8 *y, const uint8 *u, const uint8 *v, int n, int oddflag);
-+#endif
-+
+namespace mozilla {
+
+namespace gfx {
+
// 16.16 fixed point arithmetic
const int kFractionBits = 16;
const int kFractionMax = 1 << kFractionBits;
const int kFractionMask = ((1 << kFractionBits) - 1);
-+
-+// Convert a frame of YUV to 16 bit RGB565.
-+NS_GFX_(void) ConvertYCbCrToRGB565(const uint8* y_buf,
-+ const uint8* u_buf,
-+ const uint8* v_buf,
-+ uint8* rgb_buf,
-+ int pic_x,
-+ int pic_y,
-+ int pic_width,
-+ int pic_height,
-+ int y_pitch,
-+ int uv_pitch,
-+ int rgb_pitch,
-+ YUVType yuv_type)
-+{
-+#ifdef HAVE_YCBCR_TO_RGB565
-+ for (int i = 0; i < pic_height; i++) {
-+ yv12_to_rgb565_neon((uint16*)(rgb_buf + rgb_pitch * i),
-+ y_buf + y_pitch * i,
-+ u_buf + uv_pitch * (i / 2),
-+ v_buf + uv_pitch * (i / 2),
-+ pic_width,
-+ 0);
-+ }
-+#endif
-+}
-+
// Convert a frame of YUV to 32 bit ARGB.
-void ConvertYUVToRGB32(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int width,
- int height,
- int y_pitch,
@@ -450,35 +419,31 @@ diff --git a/gfx/ycbcr/yuv_convert.cpp b
+ EMMS();
+}
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/ycbcr/yuv_convert.h b/gfx/ycbcr/yuv_convert.h
--- a/gfx/ycbcr/yuv_convert.h
+++ b/gfx/ycbcr/yuv_convert.h
-@@ -1,72 +1,98 @@
+@@ -1,72 +1,79 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_BASE_YUV_CONVERT_H_
#define MEDIA_BASE_YUV_CONVERT_H_
-#include "base/basictypes.h"
-
-namespace media {
-
+#include "chromium_types.h"
+#include "gfxCore.h"
+
-+#ifdef __arm__
-+#define HAVE_YCBCR_TO_RGB565 1
-+#endif
-+
+namespace mozilla {
+
+namespace gfx {
+
// Type of YUV surface.
// The value of these enums matter as they are used to shift vertical indices.
enum YUVType {
- YV16 = 0, // YV16 is half width and full height chroma channels.
@@ -506,31 +471,16 @@ diff --git a/gfx/ycbcr/yuv_convert.h b/g
enum ScaleFilter {
FILTER_NONE = 0, // No filter (point sampled).
FILTER_BILINEAR_H = 1, // Bilinear horizontal filter.
FILTER_BILINEAR_V = 2, // Bilinear vertical filter.
- FILTER_BILINEAR = 3, // Bilinear filter.
+ FILTER_BILINEAR = 3 // Bilinear filter.
};
-+// Convert a frame of YUV to 16 bit RGB565.
-+// Pass in YV12 formats
-+NS_GFX_(void) ConvertYCbCrToRGB565(const uint8* yplane,
-+ const uint8* uplane,
-+ const uint8* vplane,
-+ uint8* rgbframe,
-+ int pic_x,
-+ int pic_y,
-+ int pic_width,
-+ int pic_height,
-+ int ystride,
-+ int uvstride,
-+ int rgbstride,
-+ YUVType yuv_type);
-+
// Convert a frame of YUV to 32 bit ARGB.
// Pass in YV16/YV12 depending on source format
-void ConvertYUVToRGB32(const uint8* yplane,
- const uint8* uplane,
- const uint8* vplane,
- uint8* rgbframe,
- int width,
- int height,
--- a/gfx/ycbcr/ycbcr_to_rgb565.cpp
+++ b/gfx/ycbcr/ycbcr_to_rgb565.cpp
@@ -16,16 +16,18 @@
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Tom Brinkman <reportbase@gmail.com>
+ * Siarhei Siamashka <siarhei.siamashka@gmail.com>
+ * Timothy B. Terriberry <tterriberry@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
@@ -33,23 +35,125 @@
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "ycbcr_to_rgb565.h"
-#if !defined (MOZILLA_MAY_SUPPORT_NEON)
+#ifdef HAVE_YCBCR_TO_RGB565
+
+namespace mozilla {
+
+namespace gfx {
+
+# if defined(MOZILLA_MAY_SUPPORT_NEON)
+
+void __attribute((noinline)) yuv42x_to_rgb565_row_neon(uint16 *dst,
+ const uint8 *y,
+ const uint8 *u,
+ const uint8 *v,
+ int n,
+ int oddflag);
+
+#endif
-int have_ycbcr_to_rgb565 ()
+/*Convert a single pixel from Y'CbCr to RGB565.*/
+static PRUint16 yu2rgb565(int y, int u, int v) {
+ int r;
+ int g;
+ int b;
+ r = NS_CLAMP((74*y+102*v-14240+256)>>9, 0, 31);
+ g = NS_CLAMP((74*y-25*u-52*v+8704+128)>>8, 0, 63);
+ b = NS_CLAMP((74*y+129*u-17696+256)>>9, 0, 31);
+ return (PRUint16)(r<<11 | g<<5 | b);
+}
+
+
+
+void yuv_to_rgb565_row_c(uint16 *dst,
+ const uint8 *y,
+ const uint8 *u,
+ const uint8 *v,
+ int x_shift,
+ int pic_x,
+ int pic_width)
{
- return 0;
+ int x;
+ for (x = 0; x < pic_width; x++)
+ {
+ dst[x] = yu2rgb565(y[pic_x+x],
+ u[(pic_x+x)>>x_shift],
+ v[(pic_x+x)>>x_shift]);
+ }
}
-#else
-
-int have_ycbcr_to_rgb565 ()
+NS_GFX_(void) ConvertYCbCrToRGB565(const uint8* y_buf,
+ const uint8* u_buf,
+ const uint8* v_buf,
+ uint8* rgb_buf,
+ int pic_x,
+ int pic_y,
+ int pic_width,
+ int pic_height,
+ int y_pitch,
+ int uv_pitch,
+ int rgb_pitch,
+ YUVType yuv_type)
{
- return mozilla::supports_neon();
+ int x_shift;
+ int y_shift;
+ x_shift = yuv_type != YV24;
+ y_shift = yuv_type == YV12;
+# ifdef MOZILLA_MAY_SUPPORT_NEON
+ if (yuv_type != YV24 && supports_neon())
+ {
+ for (int i = 0; i < pic_height; i++) {
+ int yoffs;
+ int uvoffs;
+ yoffs = y_pitch * (pic_y+i) + pic_x;
+ uvoffs = uv_pitch * ((pic_y+i)>>y_shift) + (pic_x>>x_shift);
+ yuv42x_to_rgb565_row_neon((uint16*)(rgb_buf + rgb_pitch * i),
+ y_buf + yoffs,
+ u_buf + uvoffs,
+ v_buf + uvoffs,
+ pic_width,
+ pic_x&x_shift);
+ }
+ }
+ else
+# endif
+ {
+ for (int i = 0; i < pic_height; i++) {
+ int yoffs;
+ int uvoffs;
+ yoffs = y_pitch * (pic_y+i);
+ uvoffs = uv_pitch * ((pic_y+i)>>y_shift);
+ yuv_to_rgb565_row_c((uint16*)(rgb_buf + rgb_pitch * i),
+ y_buf + yoffs,
+ u_buf + uvoffs,
+ v_buf + uvoffs,
+ x_shift,
+ pic_x,
+ pic_width);
+ }
+ }
}
-#endif //MOZILLA_MAY_SUPPORT_NEON
+NS_GFX_(bool) IsConvertYCbCrToRGB565Fast(int pic_x,
+ int pic_y,
+ int pic_width,
+ int pic_height,
+ YUVType yuv_type)
+{
+# if defined(MOZILLA_MAY_SUPPORT_NEON)
+ return (yuv_type != YV24 && supports_neon());
+# else
+ return false;
+# endif
+}
+
+} // namespace gfx
+
+} // namespace mozilla
+
+#endif // HAVE_YCBCR_TO_RGB565
--- a/gfx/ycbcr/ycbcr_to_rgb565.h
+++ b/gfx/ycbcr/ycbcr_to_rgb565.h
@@ -1,10 +1,45 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_BASE_YCBCR_TO_RGB565_H_
#define MEDIA_BASE_YCBCR_TO_RGB565_H_
+#include "yuv_convert.h"
#include "mozilla/arm.h"
-int have_ycbcr_to_rgb565();
+// It's currently only worth including this if we have NEON support.
+#ifdef MOZILLA_MAY_SUPPORT_NEON
+#define HAVE_YCBCR_TO_RGB565 1
+#endif
+
+namespace mozilla {
+
+namespace gfx {
+
+#ifdef HAVE_YCBCR_TO_RGB565
+// Convert a frame of YUV to 16 bit RGB565.
+NS_GFX_(void) ConvertYCbCrToRGB565(const uint8* yplane,
+ const uint8* uplane,
+ const uint8* vplane,
+ uint8* rgbframe,
+ int pic_x,
+ int pic_y,
+ int pic_width,
+ int pic_height,
+ int ystride,
+ int uvstride,
+ int rgbstride,
+ YUVType yuv_type);
+
+// Used to test if we have an accelerated version.
+NS_GFX_(bool) IsConvertYCbCrToRGB565Fast(int pic_x,
+ int pic_y,
+ int pic_width,
+ int pic_height,
+ YUVType yuv_type);
+#endif // HAVE_YCBCR_TO_RGB565
+
+} // namespace gfx
+
+} // namespace mozilla
#endif // MEDIA_BASE_YCBCR_TO_RGB565_H_
--- a/gfx/ycbcr/yuv_convert.cpp
+++ b/gfx/ycbcr/yuv_convert.cpp
@@ -17,56 +17,25 @@
// The alpha is set to 255, allowing the application to use RGBA or RGB32.
#include "yuv_convert.h"
// Header for low level row functions.
#include "yuv_row.h"
#include "mozilla/SSE.h"
-#ifdef HAVE_YCBCR_TO_RGB565
-void __attribute((noinline)) yv12_to_rgb565_neon(uint16 *dst, const uint8 *y, const uint8 *u, const uint8 *v, int n, int oddflag);
-#endif
-
namespace mozilla {
namespace gfx {
// 16.16 fixed point arithmetic
const int kFractionBits = 16;
const int kFractionMax = 1 << kFractionBits;
const int kFractionMask = ((1 << kFractionBits) - 1);
-
-// Convert a frame of YUV to 16 bit RGB565.
-NS_GFX_(void) ConvertYCbCrToRGB565(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int pic_x,
- int pic_y,
- int pic_width,
- int pic_height,
- int y_pitch,
- int uv_pitch,
- int rgb_pitch,
- YUVType yuv_type)
-{
-#ifdef HAVE_YCBCR_TO_RGB565
- for (int i = 0; i < pic_height; i++) {
- yv12_to_rgb565_neon((uint16*)(rgb_buf + rgb_pitch * i),
- y_buf + y_pitch * i,
- u_buf + uv_pitch * (i / 2),
- v_buf + uv_pitch * (i / 2),
- pic_width,
- 0);
- }
-#endif
-}
-
// Convert a frame of YUV to 32 bit ARGB.
NS_GFX_(void) ConvertYCbCrToRGB32(const uint8* y_buf,
const uint8* u_buf,
const uint8* v_buf,
uint8* rgb_buf,
int pic_x,
int pic_y,
int pic_width,
--- a/gfx/ycbcr/yuv_convert.h
+++ b/gfx/ycbcr/yuv_convert.h
@@ -3,20 +3,16 @@
// found in the LICENSE file.
#ifndef MEDIA_BASE_YUV_CONVERT_H_
#define MEDIA_BASE_YUV_CONVERT_H_
#include "chromium_types.h"
#include "gfxCore.h"
-#ifdef HAVE_ARM_NEON
-#define HAVE_YCBCR_TO_RGB565 1
-#endif
-
namespace mozilla {
namespace gfx {
// Type of YUV surface.
// The value of these enums matter as they are used to shift vertical indices.
enum YUVType {
YV12 = 0, // YV12 is half width and half height chroma channels.
@@ -40,31 +36,16 @@ enum Rotate {
// Filter affects how scaling looks.
enum ScaleFilter {
FILTER_NONE = 0, // No filter (point sampled).
FILTER_BILINEAR_H = 1, // Bilinear horizontal filter.
FILTER_BILINEAR_V = 2, // Bilinear vertical filter.
FILTER_BILINEAR = 3 // Bilinear filter.
};
-// Convert a frame of YUV to 16 bit RGB565.
-// Pass in YV12 formats
-NS_GFX_(void) ConvertYCbCrToRGB565(const uint8* yplane,
- const uint8* uplane,
- const uint8* vplane,
- uint8* rgbframe,
- int pic_x,
- int pic_y,
- int pic_width,
- int pic_height,
- int ystride,
- int uvstride,
- int rgbstride,
- YUVType yuv_type);
-
// Convert a frame of YUV to 32 bit ARGB.
// Pass in YV16/YV12 depending on source format
NS_GFX_(void) ConvertYCbCrToRGB32(const uint8* yplane,
const uint8* uplane,
const uint8* vplane,
uint8* rgbframe,
int pic_x,
int pic_y,
--- a/gfx/ycbcr/yuv_convert_arm.cpp
+++ b/gfx/ycbcr/yuv_convert_arm.cpp
@@ -1,17 +1,32 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// contributor Siarhei Siamashka <siarhei.siamashka@gmail.com>
#include "yuv_convert.h"
+#include "ycbcr_to_rgb565.h"
-void __attribute((noinline)) yv12_to_rgb565_neon(uint16 *dst, const uint8 *y, const uint8 *u, const uint8 *v, int n, int oddflag)
+
+
+#ifdef HAVE_YCBCR_TO_RGB565
+
+namespace mozilla {
+
+namespace gfx {
+
+# if defined(MOZILLA_MAY_SUPPORT_NEON)
+void __attribute((noinline)) yuv42x_to_rgb565_row_neon(uint16 *dst,
+ const uint8 *y,
+ const uint8 *u,
+ const uint8 *v,
+ int n,
+ int oddflag)
{
static __attribute__((aligned(16))) uint16 acc_r[8] = {
22840, 22840, 22840, 22840, 22840, 22840, 22840, 22840,
};
static __attribute__((aligned(16))) uint16 acc_g[8] = {
17312, 17312, 17312, 17312, 17312, 17312, 17312, 17312,
};
static __attribute__((aligned(16))) uint16 acc_b[8] = {
@@ -194,8 +209,15 @@ void __attribute((noinline)) yv12_to_rgb
[oddflag] "r" (oddflag)
: "cc", "memory",
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
"d8", "d9", "d10", "d11", /* "d12", "d13", "d14", "d15", */
"d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
"d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31"
);
}
+# endif // MOZILLA_MAY_SUPPORT_NEON
+
+} // namespace gfx
+
+} // namespace mozilla
+
+#endif // HAVE_YCBCR_TO_RGB565