Commit 0d95d477 authored by fbarchard@google.com's avatar fbarchard@google.com

ARGBInterpolate for blending 2 images with a fractional amount of each.

BUG=none
TEST=none
Review URL: https://webrtc-codereview.appspot.com/670008

git-svn-id: http://libyuv.googlecode.com/svn/trunk@300 16f28f9a-4ce2-e073-06de-1de4eb20be90
parent 6398e1d4
Name: libyuv
URL: http://code.google.com/p/libyuv/
Version: 299
Version: 300
License: BSD
License File: LICENSE
......
......@@ -212,6 +212,16 @@ int ARGBShade(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb, int dst_stride_argb,
int width, int height, uint32 value);
// Interpolate between two ARGB images using specified amount of interpolation
// (0 to 255) and store to destination.
// 'interpolation' is specified as 8 bit fraction where 0 means 100% src_argb0
// and 255 means 1% src_argb0 and 99% src_argb1.
// Internally uses ARGBScale bilinear filtering.
int ARGBInterpolate(const uint8* src_argb0, int src_stride_argb0,
const uint8* src_argb1, int src_stride_argb1,
uint8* dst_argb, int dst_stride_argb,
int width, int height, int interpolation);
#ifdef __cplusplus
} // extern "C"
} // namespace libyuv
......
......@@ -11,6 +11,6 @@
#ifndef INCLUDE_LIBYUV_VERSION_H_ // NOLINT
#define INCLUDE_LIBYUV_VERSION_H_
#define LIBYUV_VERSION 299
#define LIBYUV_VERSION 300
#endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT
......@@ -1082,7 +1082,7 @@ int ARGBBlur(const uint8* src_argb, int src_stride_argb,
return 0;
}
// Multiply ARGB image by ARGB value.
// Multiply ARGB image by a specified ARGB value.
int ARGBShade(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb, int dst_stride_argb,
int width, int height, uint32 value) {
......@@ -1112,6 +1112,63 @@ int ARGBShade(const uint8* src_argb, int src_stride_argb,
return 0;
}
#if !defined(YUV_DISABLE_ASM) && (defined(_M_IX86) || \
(defined(__x86_64__) || defined(__i386__)))
#define HAS_SCALEARGBFILTERROWS_SSE2
#define HAS_SCALEARGBFILTERROWS_SSSE3
#endif
void ScaleARGBFilterRows_C(uint8* dst_ptr, const uint8* src_ptr, int src_stride,
int dst_width, int source_y_fraction);
void ScaleARGBFilterRows_SSE2(uint8* dst_ptr, const uint8* src_ptr,
int src_stride, int dst_width,
int source_y_fraction);
void ScaleARGBFilterRows_SSSE3(uint8* dst_ptr, const uint8* src_ptr,
int src_stride, int dst_width,
int source_y_fraction);
// Interpolate 2 ARGB images by specified amount (0 to 255).
int ARGBInterpolate(const uint8* src_argb0, int src_stride_argb0,
const uint8* src_argb1, int src_stride_argb1,
uint8* dst_argb, int dst_stride_argb,
int width, int height, int interpolation) {
if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
return -1;
}
// Negative height means invert the image.
if (height < 0) {
height = -height;
dst_argb = dst_argb + (height - 1) * dst_stride_argb;
dst_stride_argb = -dst_stride_argb;
}
void (*ScaleARGBFilterRows)(uint8* dst_ptr, const uint8* src_ptr,
int src_stride, int dst_width,
int source_y_fraction) = ScaleARGBFilterRows_C;
#if defined(HAS_SCALEARGBFILTERROWS_SSE2)
if (TestCpuFlag(kCpuHasSSE2) &&
IS_ALIGNED(src_argb0, 16) && IS_ALIGNED(src_stride_argb0, 16) &&
IS_ALIGNED(src_argb1, 16) && IS_ALIGNED(src_stride_argb1, 16) &&
IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
ScaleARGBFilterRows = ScaleARGBFilterRows_SSE2;
}
#endif
#if defined(HAS_SCALEARGBFILTERROWS_SSSE3)
if (TestCpuFlag(kCpuHasSSSE3) &&
IS_ALIGNED(src_argb0, 16) && IS_ALIGNED(src_stride_argb0, 16) &&
IS_ALIGNED(src_argb1, 16) && IS_ALIGNED(src_stride_argb1, 16) &&
IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
ScaleARGBFilterRows = ScaleARGBFilterRows_SSSE3;
}
#endif
for (int y = 0; y < height; ++y) {
ScaleARGBFilterRows(dst_argb, src_argb0, src_argb1 - src_argb0,
width, interpolation);
src_argb0 += src_stride_argb0;
src_argb1 += src_stride_argb1;
dst_argb += dst_stride_argb;
}
return 0;
}
#ifdef __cplusplus
} // extern "C"
} // namespace libyuv
......
......@@ -184,9 +184,9 @@ static void ScaleARGBRowDownEvenInt_SSE2(const uint8* src_ptr, int src_stride,
// Bilinear row filtering combines 4x2 -> 4x1. SSE2 version.
#define HAS_SCALEARGBFILTERROWS_SSE2
__declspec(naked) __declspec(align(16))
static void ScaleARGBFilterRows_SSE2(uint8* dst_ptr, const uint8* src_ptr,
int src_stride, int dst_width,
int source_y_fraction) {
void ScaleARGBFilterRows_SSE2(uint8* dst_ptr, const uint8* src_ptr,
int src_stride, int dst_width,
int source_y_fraction) {
__asm {
push esi
push edi
......@@ -271,9 +271,9 @@ static void ScaleARGBFilterRows_SSE2(uint8* dst_ptr, const uint8* src_ptr,
// Bilinear row filtering combines 4x2 -> 4x1. SSSE3 version.
#define HAS_SCALEARGBFILTERROWS_SSSE3
__declspec(naked) __declspec(align(16))
static void ScaleARGBFilterRows_SSSE3(uint8* dst_ptr, const uint8* src_ptr,
int src_stride, int dst_width,
int source_y_fraction) {
void ScaleARGBFilterRows_SSSE3(uint8* dst_ptr, const uint8* src_ptr,
int src_stride, int dst_width,
int source_y_fraction) {
__asm {
push esi
push edi
......@@ -499,9 +499,9 @@ static void ScaleARGBRowDownEvenInt_SSE2(const uint8* src_ptr, int src_stride,
// Bilinear row filtering combines 4x2 -> 4x1. SSE2 version
#define HAS_SCALEARGBFILTERROWS_SSE2
static void ScaleARGBFilterRows_SSE2(uint8* dst_ptr,
const uint8* src_ptr, int src_stride,
int dst_width, int source_y_fraction) {
void ScaleARGBFilterRows_SSE2(uint8* dst_ptr, const uint8* src_ptr,
int src_stride, int dst_width,
int source_y_fraction) {
asm volatile (
"sub %1,%0 \n"
"cmp $0x0,%3 \n"
......@@ -570,9 +570,9 @@ static void ScaleARGBFilterRows_SSE2(uint8* dst_ptr,
// Bilinear row filtering combines 4x2 -> 4x1. SSSE3 version
#define HAS_SCALEARGBFILTERROWS_SSSE3
static void ScaleARGBFilterRows_SSSE3(uint8* dst_ptr,
const uint8* src_ptr, int src_stride,
int dst_width, int source_y_fraction) {
void ScaleARGBFilterRows_SSSE3(uint8* dst_ptr, const uint8* src_ptr,
int src_stride, int dst_width,
int source_y_fraction) {
asm volatile (
"sub %1,%0 \n"
"shr %3 \n"
......@@ -743,9 +743,8 @@ static void ScaleARGBFilterCols_C(uint8* dst_ptr, const uint8* src_ptr,
static const int kMaxInputWidth = 2560;
// C version 2x2 -> 2x1
static void ScaleARGBFilterRows_C(uint8* dst_ptr,
const uint8* src_ptr, int src_stride,
int dst_width, int source_y_fraction) {
void ScaleARGBFilterRows_C(uint8* dst_ptr, const uint8* src_ptr, int src_stride,
int dst_width, int source_y_fraction) {
assert(dst_width > 0);
int y1_fraction = source_y_fraction;
int y0_fraction = 256 - y1_fraction;
......
......@@ -652,12 +652,10 @@ TEST_F(libyuvTest, TestShade) {
SIMD_ALIGNED(uint8 orig_pixels[256][4]);
SIMD_ALIGNED(uint8 shade_pixels[256][4]);
// Test unattenuation clamps
orig_pixels[0][0] = 10u;
orig_pixels[0][1] = 20u;
orig_pixels[0][2] = 40u;
orig_pixels[0][3] = 80u;
// Test unattenuation transparent and opaque are unaffected
orig_pixels[1][0] = 0u;
orig_pixels[1][1] = 0u;
orig_pixels[1][2] = 0u;
......@@ -700,4 +698,76 @@ TEST_F(libyuvTest, TestShade) {
}
}
TEST_F(libyuvTest, TestInterpolate) {
SIMD_ALIGNED(uint8 orig_pixels_0[256][4]);
SIMD_ALIGNED(uint8 orig_pixels_1[256][4]);
SIMD_ALIGNED(uint8 interpolate_pixels[256][4]);
orig_pixels_0[0][0] = 10u;
orig_pixels_0[0][1] = 20u;
orig_pixels_0[0][2] = 40u;
orig_pixels_0[0][3] = 80u;
orig_pixels_0[1][0] = 0u;
orig_pixels_0[1][1] = 0u;
orig_pixels_0[1][2] = 0u;
orig_pixels_0[1][3] = 255u;
orig_pixels_0[2][0] = 0u;
orig_pixels_0[2][1] = 0u;
orig_pixels_0[2][2] = 0u;
orig_pixels_0[2][3] = 0u;
orig_pixels_0[3][0] = 0u;
orig_pixels_0[3][1] = 0u;
orig_pixels_0[3][2] = 0u;
orig_pixels_0[3][3] = 0u;
orig_pixels_1[0][0] = 0u;
orig_pixels_1[0][1] = 0u;
orig_pixels_1[0][2] = 0u;
orig_pixels_1[0][3] = 0u;
orig_pixels_1[1][0] = 0u;
orig_pixels_1[1][1] = 0u;
orig_pixels_1[1][2] = 0u;
orig_pixels_1[1][3] = 0u;
orig_pixels_1[2][0] = 0u;
orig_pixels_1[2][1] = 0u;
orig_pixels_1[2][2] = 0u;
orig_pixels_1[2][3] = 0u;
orig_pixels_1[3][0] = 255u;
orig_pixels_1[3][1] = 255u;
orig_pixels_1[3][2] = 255u;
orig_pixels_1[3][3] = 255u;
ARGBInterpolate(&orig_pixels_0[0][0], 0, &orig_pixels_1[0][0], 0,
&interpolate_pixels[0][0], 0, 4, 1, 128);
EXPECT_EQ(5u, interpolate_pixels[0][0]);
EXPECT_EQ(10u, interpolate_pixels[0][1]);
EXPECT_EQ(20u, interpolate_pixels[0][2]);
EXPECT_EQ(40u, interpolate_pixels[0][3]);
EXPECT_EQ(0u, interpolate_pixels[1][0]);
EXPECT_EQ(0u, interpolate_pixels[1][1]);
EXPECT_EQ(0u, interpolate_pixels[1][2]);
EXPECT_NEAR(128u, interpolate_pixels[1][3], 1); // C = 127, SSE = 128.
EXPECT_EQ(0u, interpolate_pixels[2][0]);
EXPECT_EQ(0u, interpolate_pixels[2][1]);
EXPECT_EQ(0u, interpolate_pixels[2][2]);
EXPECT_EQ(0u, interpolate_pixels[2][3]);
EXPECT_NEAR(128u, interpolate_pixels[3][0], 1);
EXPECT_NEAR(128u, interpolate_pixels[3][1], 1);
EXPECT_NEAR(128u, interpolate_pixels[3][2], 1);
EXPECT_NEAR(128u, interpolate_pixels[3][3], 1);
ARGBInterpolate(&orig_pixels_0[0][0], 0, &orig_pixels_1[0][0], 0,
&interpolate_pixels[0][0], 0, 4, 1, 0);
EXPECT_EQ(10u, interpolate_pixels[0][0]);
EXPECT_EQ(20u, interpolate_pixels[0][1]);
EXPECT_EQ(40u, interpolate_pixels[0][2]);
EXPECT_EQ(80u, interpolate_pixels[0][3]);
for (int i = 0; i < 1000 * 1280 * 720 / 256; ++i) {
ARGBInterpolate(&orig_pixels_0[0][0], 0, &orig_pixels_1[0][0], 0,
&interpolate_pixels[0][0], 0, 256, 1, 128);
}
}
} // namespace libyuv
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment