Skip to content

Instantly share code, notes, and snippets.

@kuniyoshi
Created December 9, 2015 07:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kuniyoshi/7b1fb6f121c66a25c76f to your computer and use it in GitHub Desktop.
Save kuniyoshi/7b1fb6f121c66a25c76f to your computer and use it in GitHub Desktop.
アルファブレンドの高速化
#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();
@kuniyoshi
Copy link
Author

alpha_blend range_vs_cpu_time
alpha_blend range_vs_iterations
alpha_blend

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment