Created
December 9, 2015 07:26
-
-
Save kuniyoshi/7b1fb6f121c66a25c76f to your computer and use it in GitHub Desktop.
アルファブレンドの高速化
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <random> | |
#include "benchmark/benchmark.h" | |
#define WARN(x) warn(#x, x, __FILE__, __LINE__) | |
using namespace std; | |
template< class T > | |
void warn(const char* exp, T value, const char* filename, const int line) | |
{ | |
cerr << exp << ":\t" << value << "\tat " << filename << " line " << line << endl; | |
} | |
template< class T > | |
T abs(T a) { return a > 0 ? a : -a; } | |
unsigned diff(unsigned a, unsigned b) { return a - b; } | |
class Random | |
{ | |
private: | |
uniform_int_distribution< int > distribution; | |
mt19937 mt; | |
public: | |
Random(unsigned range_min, unsigned range_max) | |
{ | |
random_device rd; | |
mt = mt19937(rd()); | |
distribution = uniform_int_distribution< int >(range_min, range_max); | |
} | |
unsigned operator()() { return static_cast< unsigned >(distribution(mt)); } | |
}; | |
// data[0]: <<alpha:8, red:8, green:8, blue:8>> | |
class Image | |
{ | |
private: | |
unsigned* data; | |
unsigned size_; | |
public: | |
Image(unsigned size, Random* random) : size_(size) | |
{ | |
data = new unsigned[size_]; | |
for (unsigned i = 0; i < size_; ++i) | |
{ | |
data[i] = (*random)(); | |
} | |
} | |
Image(Image& image) : size_(image.size()) | |
{ | |
data = new unsigned[size_]; | |
for (unsigned i = 0; i < size_; ++i) | |
{ | |
data[i] = image[i]; | |
} | |
} | |
~Image() { delete[] data; data = 0; } | |
unsigned size() const { return size_; } | |
unsigned& operator[](unsigned i) { return data[i]; } | |
unsigned& operator[](unsigned i) const { return data[i]; } | |
bool operator==(const Image& image) const | |
{ | |
if (size_ != image.size()) | |
{ | |
return false; | |
} | |
for (unsigned i = 0; i < size_; ++i) | |
{ | |
if (!eq_within_eps(data[i], image[i], 1)) | |
{ | |
return false; | |
} | |
} | |
return true; | |
} | |
void print(ostream* os) | |
{ | |
for (unsigned i = 0; i < size(); ++i) | |
{ | |
*os << hex << data[i] << " "; | |
// *os << data[i] << " "; | |
} | |
} | |
private: | |
static bool eq_within_eps(const unsigned a, const unsigned b, const unsigned eps) | |
{ | |
if ((a & 0xff000000) != (b & 0xff000000)) | |
{ | |
return false; | |
} | |
unsigned ra = (a & 0xff0000) >> 16; | |
unsigned ga = (a & 0x00ff00) >> 8; | |
unsigned ba = (a & 0x0000ff) >> 0; | |
unsigned rb = (a & 0xff0000) >> 16; | |
unsigned gb = (a & 0x00ff00) >> 8; | |
unsigned bb = (a & 0x0000ff) >> 0; | |
if (abs(diff(ra, rb)) > eps) | |
{ | |
return false; | |
} | |
if (abs(diff(ga, gb)) > eps) | |
{ | |
return false; | |
} | |
if (abs(diff(ba, bb)) > eps) | |
{ | |
return false; | |
} | |
return true; | |
} | |
}; | |
ostream& operator<<(ostream &os, Image& image) | |
{ | |
image.print(&os); | |
return os; | |
} | |
void alpha_blend1(Image* base, const Image& upper) | |
{ | |
for (unsigned i = 0; i < base->size(); ++i) | |
{ | |
double alpha = static_cast< double >((upper[i] & 0xff000000) >> 24) / 255.0; | |
double upper_r = static_cast< double >((upper[i] & 0xff0000) >> 16); | |
double upper_g = static_cast< double >((upper[i] & 0x00ff00) >> 8); | |
double upper_b = static_cast< double >((upper[i] & 0x0000ff)); | |
double base_r = static_cast< double >(((*base)[i] & 0xff0000) >> 16); | |
double base_g = static_cast< double >(((*base)[i] & 0x00ff00) >> 8); | |
double base_b = static_cast< double >(((*base)[i] & 0x0000ff)); | |
double r = alpha * upper_r + (1.f - alpha) * base_r; | |
double g = alpha * upper_g + (1.f - alpha) * base_g; | |
double b = alpha * upper_b + (1.f - alpha) * base_b; | |
(*base)[i] = static_cast< unsigned >(r) << 16; | |
(*base)[i] += static_cast< unsigned >(g) << 8; | |
(*base)[i] += static_cast< unsigned >(b); | |
} | |
} | |
void alpha_blend2(Image* base, const Image& upper) | |
{ | |
for (unsigned i = 0; i < base->size(); ++i) | |
{ | |
unsigned alpha = (upper[i] & 0xff000000) >> 24; | |
unsigned upper_r = (upper[i] & 0xff0000) >> 16; | |
unsigned upper_g = (upper[i] & 0x00ff00) >> 8; | |
unsigned upper_b = (upper[i] & 0x0000ff); | |
unsigned base_r = ((*base)[i] & 0xff0000) >> 16; | |
unsigned base_g = ((*base)[i] & 0x00ff00) >> 8; | |
unsigned base_b = ((*base)[i] & 0x0000ff); | |
unsigned r = (upper_r - base_r) * alpha / 255 + base_r; | |
unsigned g = (upper_g - base_g) * alpha / 255 + base_g; | |
unsigned b = (upper_b - base_b) * alpha / 255 + base_b; | |
(*base)[i] = ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff); | |
} | |
} | |
void alpha_blend3(Image* base, const Image& upper) | |
{ | |
for (unsigned i = 0; i < base->size(); ++i) | |
{ | |
unsigned alpha = (upper[i] & 0xff000000) >> 24; | |
unsigned upper_r = upper[i] & 0xff0000; | |
unsigned upper_g = upper[i] & 0x00ff00; | |
unsigned upper_b = upper[i] & 0x0000ff; | |
unsigned base_r = (*base)[i] & 0xff0000; | |
unsigned base_g = (*base)[i] & 0x00ff00; | |
unsigned base_b = (*base)[i] & 0x0000ff; | |
unsigned r = (upper_r - base_r) * alpha / 255 + base_r; | |
unsigned g = (upper_g - base_g) * alpha / 255 + base_g; | |
unsigned b = (upper_b - base_b) * alpha / 255 + base_b; | |
(*base)[i] = (r & 0xff0000) | (g & 0x00ff00) | (b & 0x0000ff); | |
} | |
} | |
// int main() | |
// { | |
// Random r(0, 0x7fffffff); | |
// Image base(10, &r); | |
// cerr << base << endl; | |
// Image image(10, &r); | |
// cerr << base << endl; | |
// Image base1 = base; | |
// alpha_blend1(&base1, image); | |
// cerr << base1 << endl; | |
// Image base2 = base; | |
// alpha_blend2(&base2, image); | |
// cerr << base2 << endl; | |
// cerr << (base2 == base1) << endl; | |
// Image base3 = base; | |
// alpha_blend3(&base3, image); | |
// cerr << base3 << endl; | |
// cerr << (base3 == base1) << endl; | |
// return 0; | |
// } | |
static void bm_alpha_blend1(benchmark::State& state) | |
{ | |
Random r(0, 0x7fffffff); | |
while (state.KeepRunning()) | |
{ | |
Image base(state.range_x(), &r); | |
Image image(state.range_x(), &r); | |
alpha_blend1(&base, image); | |
} | |
} | |
BENCHMARK(bm_alpha_blend1)->Range(0, 1024 * 1024); | |
static void bm_alpha_blend2(benchmark::State& state) | |
{ | |
Random r(0, 0x7fffffff); | |
while (state.KeepRunning()) | |
{ | |
Image base(state.range_x(), &r); | |
Image image(state.range_x(), &r); | |
alpha_blend2(&base, image); | |
} | |
} | |
BENCHMARK(bm_alpha_blend2)->Range(0, 1024 * 1024); | |
static void bm_alpha_blend3(benchmark::State& state) | |
{ | |
Random r(0, 0x7fffffff); | |
while (state.KeepRunning()) | |
{ | |
Image base(state.range_x(), &r); | |
Image image(state.range_x(), &r); | |
alpha_blend3(&base, image); | |
} | |
} | |
BENCHMARK(bm_alpha_blend3)->Range(0, 1024 * 1024); | |
BENCHMARK_MAIN(); |
Author
kuniyoshi
commented
Dec 9, 2015
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment