Commit f86ba32b authored by fbarchard@google.com's avatar fbarchard@google.com

Unattenuate using a reciprocal

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

git-svn-id: http://libyuv.googlecode.com/svn/trunk@241 16f28f9a-4ce2-e073-06de-1de4eb20be90
parent 829e7ea4
Name: libyuv Name: libyuv
URL: http://code.google.com/p/libyuv/ URL: http://code.google.com/p/libyuv/
Version: 240 Version: 241
License: BSD License: BSD
License File: LICENSE License File: LICENSE
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#ifndef INCLUDE_LIBYUV_VERSION_H_ #ifndef INCLUDE_LIBYUV_VERSION_H_
#define INCLUDE_LIBYUV_VERSION_H_ #define INCLUDE_LIBYUV_VERSION_H_
#define LIBYUV_VERSION 240 #define LIBYUV_VERSION 241
#endif // INCLUDE_LIBYUV_VERSION_H_ #endif // INCLUDE_LIBYUV_VERSION_H_
...@@ -86,7 +86,7 @@ static uint32 HashDjb2_SSE41(const uint8* src, int count, uint32 seed) { ...@@ -86,7 +86,7 @@ static uint32 HashDjb2_SSE41(const uint8* src, int count, uint32 seed) {
wloop: wloop:
movdqu xmm1, [eax] // src[0-15] movdqu xmm1, [eax] // src[0-15]
lea eax, [eax + 16] lea eax, [eax + 16]
pmulld(0xc6) // pmulld xmm0,xmm6 hash *= 33 ^ 8 pmulld(0xc6) // pmulld xmm0,xmm6 hash *= 33 ^ 16
movdqa xmm5, kHashMul0 movdqa xmm5, kHashMul0
movdqa xmm2, xmm1 movdqa xmm2, xmm1
punpcklbw xmm2, xmm7 // src[0-7] punpcklbw xmm2, xmm7 // src[0-7]
......
...@@ -864,6 +864,7 @@ int ARGBRect(uint8* dst_argb, int dst_stride_argb, ...@@ -864,6 +864,7 @@ int ARGBRect(uint8* dst_argb, int dst_stride_argb,
} }
// Multiply source RGB by alpha and store to destination. // Multiply source RGB by alpha and store to destination.
// b = (b * a + 127) / 255;
static void ARGBAttenuateRow_C(const uint8* src_argb, uint8* dst_argb, static void ARGBAttenuateRow_C(const uint8* src_argb, uint8* dst_argb,
int width) { int width) {
for (int i = 0; i < width; ++i) { for (int i = 0; i < width; ++i) {
...@@ -871,17 +872,16 @@ static void ARGBAttenuateRow_C(const uint8* src_argb, uint8* dst_argb, ...@@ -871,17 +872,16 @@ static void ARGBAttenuateRow_C(const uint8* src_argb, uint8* dst_argb,
const uint32 g = src_argb[1]; const uint32 g = src_argb[1];
const uint32 r = src_argb[2]; const uint32 r = src_argb[2];
const uint32 a = src_argb[3]; const uint32 a = src_argb[3];
dst_argb[0] = (b * a + 128) / 255; dst_argb[0] = (b * a + 127) / 255;
dst_argb[1] = (g * a + 128) / 255; dst_argb[1] = (g * a + 127) / 255;
dst_argb[2] = (r * a + 128) / 255; dst_argb[2] = (r * a + 127) / 255;
dst_argb[3] = a; dst_argb[3] = a;
src_argb += 4; src_argb += 4;
dst_argb += 4; dst_argb += 4;
} }
} }
// Convert unattentuated ARGB values to preattenuated ARGB by multiplying RGB by // Convert unattentuated ARGB values to preattenuated ARGB.
// by alpha.
// An unattenutated ARGB alpha blend uses the formula // An unattenutated ARGB alpha blend uses the formula
// p = a * f + (1 - a) * b // p = a * f + (1 - a) * b
// where // where
...@@ -912,6 +912,10 @@ int ARGBAttenuate(const uint8* src_argb, int src_stride_argb, ...@@ -912,6 +912,10 @@ int ARGBAttenuate(const uint8* src_argb, int src_stride_argb,
} }
// Divide source RGB by alpha and store to destination. // Divide source RGB by alpha and store to destination.
// b = (b * 255 + (a / 2)) / a;
// g = (g * 255 + (a / 2)) / a;
// r = (r * 255 + (a / 2)) / a;
// Reciprocal method is off by 1 on some values. ie 125
static void ARGBUnattenuateRow_C(const uint8* src_argb, uint8* dst_argb, static void ARGBUnattenuateRow_C(const uint8* src_argb, uint8* dst_argb,
int width) { int width) {
for (int i = 0; i < width; ++i) { for (int i = 0; i < width; ++i) {
...@@ -920,15 +924,17 @@ static void ARGBUnattenuateRow_C(const uint8* src_argb, uint8* dst_argb, ...@@ -920,15 +924,17 @@ static void ARGBUnattenuateRow_C(const uint8* src_argb, uint8* dst_argb,
uint32 r = src_argb[2]; uint32 r = src_argb[2];
const uint32 a = src_argb[3]; const uint32 a = src_argb[3];
if (a) { if (a) {
b = (b * 255 + 127) / a; const uint32 ia = (0x1000000 + (a >> 1)) / a; // 8.16 fixed point
b = (b * ia + 0x8000) >> 16;
g = (g * ia + 0x8000) >> 16;
r = (r * ia + 0x8000) >> 16;
// Clamping should not be necessary but is free in assembly.
if (b > 255) { if (b > 255) {
b = 255; b = 255;
} }
g = (g * 255 + 127) / a;
if (g > 255) { if (g > 255) {
g = 255; g = 255;
} }
r = (r * 255 + 127) / a;
if (r > 255) { if (r > 255) {
r = 255; r = 255;
} }
...@@ -942,8 +948,7 @@ static void ARGBUnattenuateRow_C(const uint8* src_argb, uint8* dst_argb, ...@@ -942,8 +948,7 @@ static void ARGBUnattenuateRow_C(const uint8* src_argb, uint8* dst_argb,
} }
} }
// Convert unattentuated ARGB values to preattenuated ARGB by multiplying RGB by // Convert unattentuated ARGB values to preattenuated ARGB.
// by alpha.
int ARGBUnattenuate(const uint8* src_argb, int src_stride_argb, int ARGBUnattenuate(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb, int dst_stride_argb, uint8* dst_argb, int dst_stride_argb,
int width, int height) { int width, int height) {
......
...@@ -115,4 +115,51 @@ TESTI420TO(ARGB) ...@@ -115,4 +115,51 @@ TESTI420TO(ARGB)
TESTI420TO(BGRA) TESTI420TO(BGRA)
TESTI420TO(ABGR) TESTI420TO(ABGR)
TEST_F (libyuvTest, TestAttenuate) {
uint8 orig_pixels[256][4];
uint8 atten_pixels[256][4];
uint8 unatten_pixels[256][4];
uint8 atten2_pixels[256][4];
for (int i = 0; i < 256; ++i) {
orig_pixels[i][0] = i;
orig_pixels[i][1] = i / 2;
orig_pixels[i][2] = i / 3;
orig_pixels[i][3] = i;
}
ARGBAttenuate(&orig_pixels[0][0], 0, &atten_pixels[0][0], 0, 256, 1);
ARGBUnattenuate(&atten_pixels[0][0], 0, &unatten_pixels[0][0], 0, 256, 1);
ARGBAttenuate(&unatten_pixels[0][0], 0, &atten2_pixels[0][0], 0, 256, 1);
for (int i = 0; i < 256; ++i) {
EXPECT_NEAR(atten_pixels[i][0], atten2_pixels[i][0], 1);
EXPECT_NEAR(atten_pixels[i][1], atten2_pixels[i][1], 1);
EXPECT_NEAR(atten_pixels[i][2], atten2_pixels[i][2], 1);
EXPECT_NEAR(atten_pixels[i][3], atten2_pixels[i][3], 1);
}
// Make sure transparent, 50% and opaque are fully accurate.
EXPECT_EQ(0, atten_pixels[0][0]);
EXPECT_EQ(0, atten_pixels[0][1]);
EXPECT_EQ(0, atten_pixels[0][2]);
EXPECT_EQ(0, atten_pixels[0][3]);
EXPECT_EQ(64, atten_pixels[128][0]);
EXPECT_EQ(32, atten_pixels[128][1]);
EXPECT_EQ(21, atten_pixels[128][2]);
EXPECT_EQ(128, atten_pixels[128][3]);
EXPECT_EQ(255, atten_pixels[255][0]);
EXPECT_EQ(127, atten_pixels[255][1]);
EXPECT_EQ(85, atten_pixels[255][2]);
EXPECT_EQ(255, atten_pixels[255][3]);
// Test unattenuation clamps
orig_pixels[0][0] = 200;
orig_pixels[0][1] = 129;
orig_pixels[0][2] = 127;
orig_pixels[0][3] = 128;
ARGBUnattenuate(&orig_pixels[0][0], 0, &unatten_pixels[0][0], 0, 1, 1);
EXPECT_EQ(255, unatten_pixels[0][0]);
EXPECT_EQ(255, unatten_pixels[0][1]);
EXPECT_EQ(254, unatten_pixels[0][2]);
EXPECT_EQ(128, unatten_pixels[0][3]);
}
} }
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