Jakub Narębski
Jakub Narębski

Reputation: 323464

Benchmarking GLSL shaders to compare speed of alternative implementations

I want to plot two-dimensional function z = f(x,y) using OpenGL and GLSL shaders. I'd like to map the value of function to color using a colormap, but some colormaps are expressed using HSL or HSV colorspace (for example hue maps).

You can find (here and in other places) different alternative implementtions of hsv2rgb() in GLSL.

How can I benchmark those shaders (those functions) to find out which one is fastest?

Upvotes: 1

Views: 942

Answers (3)

Spektre
Spektre

Reputation: 51845

You need to be able to measure time of GL rendering first. I do it in C++ like this:

//------------------------------------------------------------------------------
class OpenGLtime
    {
public:
    unsigned int id[2];
    OpenGLtime();
    OpenGLtime(OpenGLtime& a);
    ~OpenGLtime();
    OpenGLtime* operator = (const OpenGLtime *a);
    //OpenGLtime* operator = (const OpenGLtime &a);
    void _init();
    void tbeg();            // mark start time for measure
    void tend();            // mark end time for measure
    double time();          // wait for measure and return time [s]
    };
//------------------------------------------------------------------------------
OpenGLtime::OpenGLtime()
    {
    id[0]=0;
    id[1]=0;
    }
//------------------------------------------------------------------------------
OpenGLtime::OpenGLtime(OpenGLtime& a)
    {
    id[0]=0;
    id[1]=0;
    }
//------------------------------------------------------------------------------
OpenGLtime::~OpenGLtime()
    {
    }
//------------------------------------------------------------------------------
OpenGLtime* OpenGLtime::operator = (const OpenGLtime *a)
    {
    *this=*a;
    return this;
    }
//------------------------------------------------------------------------------
void OpenGLtime::_init()
    {
    // generate two queries
    glGenQueries(2,id);
    }
//------------------------------------------------------------------------------
void OpenGLtime::tbeg()
    {
    if (!id[0]) _init();
    // issue the query
    glQueryCounter(id[0],GL_TIMESTAMP);
    }
//------------------------------------------------------------------------------
void OpenGLtime::tend()
    {
    if (!id[0]) _init();
    // issue the query
    glQueryCounter(id[1],GL_TIMESTAMP);
    }
//------------------------------------------------------------------------------
double OpenGLtime::time()
    {
    if (!id[0]) { _init(); return 0.0; }
    double dt;
    GLuint64 t0,t1;
    int _stop;

    // wait until the results are available
    for (_stop=0;!_stop;Sleep(1)) glGetQueryObjectiv(id[0],GL_QUERY_RESULT_AVAILABLE,&_stop);
    for (_stop=0;!_stop;Sleep(1)) glGetQueryObjectiv(id[1],GL_QUERY_RESULT_AVAILABLE,&_stop);
    // get query results
    glGetQueryObjectui64v(id[0],GL_QUERY_RESULT,&t0);
    glGetQueryObjectui64v(id[1],GL_QUERY_RESULT,&t1);
    dt=double(t1)-double(t0); dt*=0.000000001;

    return dt;
    }
//------------------------------------------------------------------------------

Now you just use it like this:

// few variables
OpenGLtime    tim;
double draw_time;

// measurement
tim.tbeg();
// here render your stuff using binded shader
tim.tend();
draw_time=tim.time(); // time the render took in [s] just output it somewhere so you can see it

Now you should create your rendering stuff. And can compare the runtimes directly.

As yo can see you will measure time of the whole rendering pass/call and not of a part of GLSL code. So you have to take that into account. I do not know any way to measure part of GLSL code directly. Instead you can measure time without the part in the question and with it ... and substract the times but the compiler optimizations could mess it up.

Upvotes: 0

246tNt
246tNt

Reputation: 2170

For having implemented color maps, I'd just recommend to use a texture.

Something like a 256x1 texture (1D texture are not supported in ES, if that matters to you) and then from the float result of f(x,y), just use that as the texture coordinate.

If you have a lot of points to plot, that's going to be faster than evaluating it in glsl each time and GPU are good at texturing :)

Upvotes: 0

Sorin
Sorin

Reputation: 11968

Implement all alternatives you want to try and apply the usual benchmark suggestions:

  • Repeat the individual benchmark enough times to have a time is seconds (less is going to be subject to too much noise)
  • Repeat the benchmarks in the environments you want to run it in.
  • Try to have a setup as close to reality as possible (same background processes, etc).
  • Repeat the benchmark runs several times and disregard outliers.
  • Randomize the order of algorithms/tests between runs.
  • Make sure you disable caching for the section that you are testing (if it's applicable).

Since you include OpenGL solutions you should consider if you want to count data transfers as well. Make sure you flush the pipelines (opengl deffers some calls, but flush will wait until they are actually finished).

If the run-times are too close you can either say they are about the same or increase data size/repetitions to make the difference more prominent.

Upvotes: 1

Related Questions