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

FixedDiv function in C and benchmark

BUG=none
TEST=FixedDiv*
R=johannkoenig@google.com

Review URL: https://webrtc-codereview.appspot.com/1668004

git-svn-id: http://libyuv.googlecode.com/svn/trunk@727 16f28f9a-4ce2-e073-06de-1de4eb20be90
parent ff0db0ea
......@@ -16,6 +16,7 @@ LOCAL_SRC_FILES := \
source/convert_to_argb.cc \
source/convert_to_i420.cc \
source/cpu_id.cc \
source/fixed_math.cc \
source/format_conversion.cc \
source/planar_functions.cc \
source/rotate.cc \
......
Name: libyuv
URL: http://code.google.com/p/libyuv/
Version: 726
Version: 727
License: BSD
License File: LICENSE
......
......@@ -11,6 +11,6 @@
#ifndef INCLUDE_LIBYUV_VERSION_H_ // NOLINT
#define INCLUDE_LIBYUV_VERSION_H_
#define LIBYUV_VERSION 726
#define LIBYUV_VERSION 727
#endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT
......@@ -76,6 +76,7 @@
'include/libyuv/scale_argb.h',
'include/libyuv/version.h',
'include/libyuv/video_common.h',
'source/fixed_math.h',
# sources.
'source/compare.cc',
......@@ -91,6 +92,7 @@
'source/convert_to_argb.cc',
'source/convert_to_i420.cc',
'source/cpu_id.cc',
'source/fixed_math.cc',
'source/format_conversion.cc',
'source/mjpeg_decoder.cc',
'source/mjpeg_validate.cc',
......
......@@ -35,6 +35,7 @@
'unit_test/compare_test.cc',
'unit_test/convert_test.cc',
'unit_test/cpu_test.cc',
'unit_test/math_test.cc',
'unit_test/planar_test.cc',
'unit_test/rotate_argb_test.cc',
'unit_test/rotate_test.cc',
......
This diff is collapsed.
/*
* Copyright 2013 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef INCLUDE_LIBYUV_FIXED_MATH_H_ // NOLINT
#define INCLUDE_LIBYUV_FIXED_MATH_H_
#include "libyuv/basic_types.h"
#ifdef __cplusplus
namespace libyuv {
extern "C" {
#endif
extern const float kRecipTable[4097];
// Divide num by div and return value as 16.16 fixed point.
static __inline int FixedDiv(int num, int div) {
if (static_cast<unsigned int>(div) <= 4096u) {
return static_cast<int>(num * kRecipTable[div]);
}
return static_cast<int>((static_cast<int64>(num) << 16) / div);
}
#ifdef __cplusplus
} // extern "C"
} // namespace libyuv
#endif
#endif // INCLUDE_LIBYUV_FIXED_MATH_H_ NOLINT
......@@ -13,6 +13,7 @@
#include <assert.h>
#include <string.h>
#include "./fixed_math.h" // For FixedDiv
#include "libyuv/cpu_id.h"
#include "libyuv/planar_functions.h" // For CopyPlane
#include "libyuv/row.h"
......@@ -2005,8 +2006,8 @@ static void ScalePlaneBox(int src_width, int src_height,
const uint8* src_ptr, uint8* dst_ptr) {
assert(dst_width > 0);
assert(dst_height > 0);
int dx = (Abs(src_width) << 16) / dst_width;
int dy = (src_height << 16) / dst_height;
int dx = FixedDiv(Abs(src_width), dst_width);
int dy = FixedDiv(src_height, dst_height);
int x = 0;
int y = 0;
// Negative src_width means horizontally mirror.
......@@ -2124,10 +2125,10 @@ void ScalePlaneBilinear(int src_width, int src_height,
int x = 0;
int y = 0;
if (dst_width <= Abs(src_width)) {
dx = (Abs(src_width) << 16) / dst_width;
dx = FixedDiv(Abs(src_width), dst_width);
x = (dx >> 1) - 32768;
} else if (dst_width > 1) {
dx = ((Abs(src_width) - 1) << 16) / (dst_width - 1);
dx = FixedDiv(Abs(src_width) - 1, dst_width - 1);
}
// Negative src_width means horizontally mirror.
if (src_width < 0) {
......@@ -2136,10 +2137,10 @@ void ScalePlaneBilinear(int src_width, int src_height,
src_width = -src_width;
}
if (dst_height <= src_height) {
dy = (src_height << 16) / dst_height;
dy = FixedDiv(src_height, dst_height);
y = (dy >> 1) - 32768;
} else if (dst_height > 1) {
dy = ((src_height - 1) << 16) / (dst_height - 1);
dy = FixedDiv(src_height - 1, dst_height - 1);
}
const int max_y = (src_height > 1) ? ((src_height - 1) << 16) - 1 : 0;
for (int j = 0; j < dst_height; ++j) {
......@@ -2165,8 +2166,8 @@ static void ScalePlaneSimple(int src_width, int src_height,
int dst_width, int dst_height,
int src_stride, int dst_stride,
const uint8* src_ptr, uint8* dst_ptr) {
int dx = (Abs(src_width) << 16) / dst_width;
int dy = (src_height << 16) / dst_height;
int dx = FixedDiv(Abs(src_width), dst_width);
int dy = FixedDiv(src_height, dst_height);
int x = dx >> 1;
int y = dy >> 1;
// Negative src_width means horizontally mirror.
......@@ -2299,8 +2300,7 @@ int I420Scale(const uint8* src_y, int src_stride_y,
int dst_width, int dst_height,
FilterMode filtering) {
if (!src_y || !src_u || !src_v || src_width == 0 || src_height == 0 ||
!dst_y || !dst_u || !dst_v || dst_width <= 0 || dst_height <= 0 ||
src_width > 32767 || src_height > 32767) {
!dst_y || !dst_u || !dst_v || dst_width <= 0 || dst_height <= 0) {
return -1;
}
// Negative height means invert the image.
......@@ -2363,8 +2363,7 @@ int Scale(const uint8* src_y, const uint8* src_u, const uint8* src_v,
int dst_width, int dst_height,
bool interpolate) {
if (!src_y || !src_u || !src_v || src_width <= 0 || src_height == 0 ||
!dst_y || !dst_u || !dst_v || dst_width <= 0 || dst_height <= 0 ||
src_width > 32767 || src_height > 32767) {
!dst_y || !dst_u || !dst_v || dst_width <= 0 || dst_height <= 0) {
return -1;
}
// Negative height means invert the image.
......@@ -2425,7 +2424,6 @@ int ScaleOffset(const uint8* src, int src_width, int src_height,
bool interpolate) {
if (!src || src_width <= 0 || src_height <= 0 ||
!dst || dst_width <= 0 || dst_height <= 0 || dst_yoffset < 0 ||
src_width > 32767 || src_height > 32767 ||
dst_yoffset >= dst_height) {
return -1;
}
......
......@@ -13,6 +13,7 @@
#include <assert.h>
#include <string.h>
#include "./fixed_math.h" // For FixedDiv
#include "libyuv/cpu_id.h"
#include "libyuv/planar_functions.h" // For CopyARGB
#include "libyuv/row.h"
......@@ -743,7 +744,7 @@ static void ScaleARGBDown2(int /* src_width */, int /* src_height */,
FilterMode filtering) {
assert(dx == 65536 * 2); // Test scale factor of 2.
assert((dy & 0x1ffff) == 0); // Test vertical scale is multiple of 2.
// Advance to odd row / even column.
// Advance to odd row, even column.
if (filtering) {
src_argb += (y >> 16) * src_stride + (x >> 16) * 4;
} else {
......@@ -1249,21 +1250,21 @@ static void ScaleARGB(const uint8* src, int src_stride,
if (filtering) {
// Scale step for bilinear sampling renders last pixel once for upsample.
if (dst_width <= Abs(src_width)) {
dx = (Abs(src_width) << 16) / dst_width;
dx = FixedDiv(Abs(src_width), dst_width);
x = (dx >> 1) - 32768;
} else if (dst_width > 1) {
dx = ((Abs(src_width) - 1) << 16) / (dst_width - 1);
dx = FixedDiv(Abs(src_width) - 1, dst_width - 1);
}
if (dst_height <= src_height) {
dy = (src_height << 16) / dst_height;
dy = FixedDiv(src_height, dst_height);
y = (dy >> 1) - 32768;
} else if (dst_height > 1) {
dy = ((src_height - 1) << 16) / (dst_height - 1);
dy = FixedDiv(src_height - 1, dst_height - 1);
}
} else {
// Scale step for point sampling duplicates all pixels equally.
dx = (Abs(src_width) << 16) / dst_width;
dy = (src_height << 16) / dst_height;
dx = FixedDiv(Abs(src_width), dst_width);
dy = FixedDiv(src_height, dst_height);
x = dx >> 1;
y = dy >> 1;
}
......@@ -1304,7 +1305,7 @@ static void ScaleARGB(const uint8* src, int src_stride,
// Optimized odd scale down. ie 3, 5, 7, 9x.
if ((dx & 0x10000) && (dy & 0x10000)) {
filtering = kFilterNone;
if (dst_width == src_width && dst_height == src_height) {
if (dx == 0x10000 && dy == 0x10000) {
// Straight copy.
ARGBCopy(src + (y >> 16) * src_stride + (x >> 16) * 4, src_stride,
dst, dst_stride, clip_width, clip_height);
......@@ -1330,7 +1331,6 @@ int ARGBScaleClip(const uint8* src_argb, int src_stride_argb,
if (!src_argb || src_width == 0 || src_height == 0 ||
!dst_argb || dst_width <= 0 || dst_height <= 0 ||
clip_x < 0 || clip_y < 0 ||
src_width > 32767 || src_height > 32767 ||
(clip_x + clip_width) > dst_width ||
(clip_y + clip_height) > dst_height) {
return -1;
......@@ -1349,8 +1349,7 @@ int ARGBScale(const uint8* src_argb, int src_stride_argb,
int dst_width, int dst_height,
FilterMode filtering) {
if (!src_argb || src_width == 0 || src_height == 0 ||
!dst_argb || dst_width <= 0 || dst_height <= 0 ||
src_width > 32767 || src_height > 32767) {
!dst_argb || dst_width <= 0 || dst_height <= 0) {
return -1;
}
ScaleARGB(src_argb, src_stride_argb, src_width, src_height,
......
/*
* Copyright 2013 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <stdlib.h>
#include <string.h>
#include "libyuv/basic_types.h"
#include "libyuv/cpu_id.h"
#include "libyuv/version.h"
#include "../source/fixed_math.h"
#include "../unit_test/unit_test.h"
namespace libyuv {
// Divide num by div and return value as 16.16 fixed point.
static int FixedDiv_C(int num, int div) {
return static_cast<int>((static_cast<int64>(num) << 16) / div);
}
TEST_F(libyuvTest, TestFixedDiv) {
int num[256];
int div[256];
int result_opt[256];
int result_c[256];
srandom(time(NULL));
MemRandomize(reinterpret_cast<uint8*>(&num[0]), sizeof(num));
MemRandomize(reinterpret_cast<uint8*>(&div[0]), sizeof(div));
for (int j = 0; j < 256; ++j) {
if (div[j] == 0) {
div[j] = 1280;
}
}
for (int i = 0; i < benchmark_pixels_div256_; ++i) {
for (int j = 0; j < 256; ++j) {
result_opt[j] = libyuv::FixedDiv(num[j], div[j]);
}
}
for (int j = 0; j < 256; ++j) {
result_c[j] = libyuv::FixedDiv_C(num[j], div[j]);
EXPECT_NEAR(result_c[j], result_opt[j], 3);
}
}
TEST_F(libyuvTest, TestFixedDiv_Opt) {
int num[256];
int div[256];
int result_opt[256];
int result_c[256];
EXPECT_EQ(0x20000, libyuv::FixedDiv(640 * 2, 640));
EXPECT_EQ(0x30000, libyuv::FixedDiv(640 * 3, 640));
EXPECT_EQ(0x40000, libyuv::FixedDiv(640 * 4, 640));
EXPECT_EQ(0x50000, libyuv::FixedDiv(640 * 5, 640));
EXPECT_EQ(0x60000, libyuv::FixedDiv(640 * 6, 640));
EXPECT_EQ(0x70000, libyuv::FixedDiv(640 * 7, 640));
EXPECT_EQ(0x80000, libyuv::FixedDiv(640 * 8, 640));
EXPECT_EQ(0xa0000, libyuv::FixedDiv(640 * 10, 640));
EXPECT_EQ(0x20000, libyuv::FixedDiv(960 * 2, 960));
EXPECT_EQ(0x08000, libyuv::FixedDiv(640 / 2, 640));
EXPECT_EQ(0x04000, libyuv::FixedDiv(640 / 4, 640));
EXPECT_EQ(0x20000, libyuv::FixedDiv(1080 * 2, 1080));
srandom(time(NULL));
MemRandomize(reinterpret_cast<uint8*>(&num[0]), sizeof(num));
MemRandomize(reinterpret_cast<uint8*>(&div[0]), sizeof(div));
for (int j = 0; j < 256; ++j) {
num[j] &= 4095; // Make numerator smaller.
div[j] &= 4095; // Make divisor smaller.
if (div[j] == 0) {
div[j] = 1280;
}
}
for (int i = 0; i < benchmark_pixels_div256_; ++i) {
for (int j = 0; j < 256; ++j) {
result_opt[j] = libyuv::FixedDiv(num[j], div[j]);
}
}
for (int j = 0; j < 256; ++j) {
result_c[j] = libyuv::FixedDiv_C(num[j], div[j]);
EXPECT_NEAR(result_c[j], result_opt[j], 3);
}
}
} // namespace libyuv
......@@ -17,10 +17,6 @@
namespace libyuv {
static __inline int Abs(int v) {
return v >= 0 ? v : -v;
}
// Test scaling with C vs Opt and return maximum pixel difference. 0 = exact.
static int ARGBTestFilter(int src_width, int src_height,
int dst_width, int dst_height,
......@@ -85,7 +81,7 @@ static int ARGBTestFilter(int src_width, int src_height,
int max_diff = 0;
for (i = b; i < (dst_height + b); ++i) {
for (j = b * 4; j < (dst_width + b) * 4; ++j) {
int abs_diff = abs(dst_argb_c[(i * dst_stride_argb) + j] -
int abs_diff = Abs(dst_argb_c[(i * dst_stride_argb) + j] -
dst_argb_opt[(i * dst_stride_argb) + j]);
if (abs_diff > max_diff) {
max_diff = abs_diff;
......@@ -99,8 +95,8 @@ static int ARGBTestFilter(int src_width, int src_height,
return max_diff;
}
static const int kTileX = 32;
static const int kTileY = 32;
static const int kTileX = 8;
static const int kTileY = 8;
static int TileARGBScale(const uint8* src_argb, int src_stride_argb,
int src_width, int src_height,
......@@ -184,7 +180,7 @@ static int ARGBClipTestFilter(int src_width, int src_height,
int max_diff = 0;
for (i = b; i < (dst_height + b); ++i) {
for (j = b * 4; j < (dst_width + b) * 4; ++j) {
int abs_diff = abs(dst_argb_c[(i * dst_stride_argb) + j] -
int abs_diff = Abs(dst_argb_c[(i * dst_stride_argb) + j] -
dst_argb_opt[(i * dst_stride_argb) + j]);
if (abs_diff > max_diff) {
max_diff = abs_diff;
......
......@@ -17,10 +17,6 @@
namespace libyuv {
static __inline int Abs(int v) {
return v >= 0 ? v : -v;
}
// Test scaling with C vs Opt and return maximum pixel difference. 0 = exact.
static int TestFilter(int src_width, int src_height,
int dst_width, int dst_height,
......@@ -99,7 +95,7 @@ static int TestFilter(int src_width, int src_height,
int max_diff = 0;
for (i = b; i < (dst_height + b); ++i) {
for (j = b; j < (dst_width + b); ++j) {
int abs_diff = abs(dst_y_c[(i * dst_stride_y) + j] -
int abs_diff = Abs(dst_y_c[(i * dst_stride_y) + j] -
dst_y_opt[(i * dst_stride_y) + j]);
if (abs_diff > max_diff) {
max_diff = abs_diff;
......@@ -109,12 +105,12 @@ static int TestFilter(int src_width, int src_height,
for (i = b; i < (dst_height_uv + b); ++i) {
for (j = b; j < (dst_width_uv + b); ++j) {
int abs_diff = abs(dst_u_c[(i * dst_stride_uv) + j] -
int abs_diff = Abs(dst_u_c[(i * dst_stride_uv) + j] -
dst_u_opt[(i * dst_stride_uv) + j]);
if (abs_diff > max_diff) {
max_diff = abs_diff;
}
abs_diff = abs(dst_v_c[(i * dst_stride_uv) + j] -
abs_diff = Abs(dst_v_c[(i * dst_stride_uv) + j] -
dst_v_opt[(i * dst_stride_uv) + j]);
if (abs_diff > max_diff) {
max_diff = abs_diff;
......
......@@ -39,9 +39,10 @@ libyuvTest::libyuvTest() : rotate_max_w_(128), rotate_max_h_(128),
if (height) {
benchmark_height_ = atoi(height); // NOLINT
}
benchmark_pixels_div256_ = static_cast<int>(
(static_cast<double>(benchmark_width_ *
benchmark_height_) * benchmark_iterations_ + 255.0) / 256.0);
benchmark_pixels_div256_ = static_cast<int>((
static_cast<double>(Abs(benchmark_width_)) *
static_cast<double>(Abs(benchmark_height_)) *
static_cast<double>(benchmark_iterations_) + 255.0) / 256.0);
}
int main(int argc, char** argv) {
......
......@@ -15,6 +15,10 @@
#include "libyuv/basic_types.h"
static __inline int Abs(int v) {
return v >= 0 ? v : -v;
}
#define align_buffer_64(var, size) \
uint8* var; \
uint8* var##_mem; \
......
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