C++程序  |  182行  |  5.8 KB

#include "BenchGpuTimer_gl.h"
#include <string.h>

//GL
#define BENCH_GL_FUNCTION_TYPE
#if defined(SK_MESA)
    #include <GL/osmesa.h>
    #define SK_BENCH_CONTEXT_CHECK (NULL != OSMesaGetCurrentContext())
    
    #define SK_GL_GET_PROC(F) gBenchGL.f ## F = (BenchGL ## F ## Proc) \
            OSMesaGetProcAddress("gl" #F);
    #define SK_GL_GET_PROC_SUFFIX(F, S) gBenchGL.f ## F = (BenchGL##F##Proc)\
            OSMesaGetProcAddress("gl" #F #S);

#elif defined(SK_BUILD_FOR_WIN32)
    #define WIN32_LEAN_AND_MEAN 1
    #include <Windows.h>
    #include <GL/GL.h>
    #define SK_BENCH_CONTEXT_CHECK (NULL != wglGetCurrentContext())
    
    #undef BENCH_GL_FUNCTION_TYPE
    #define BENCH_GL_FUNCTION_TYPE __stdcall

    #define SK_GL_GET_PROC(F) gBenchGL.f ## F = (BenchGL ## F ## Proc) \
            wglGetProcAddress("gl" #F);
    #define SK_GL_GET_PROC_SUFFIX(F, S) gBenchGL.f ## F = (BenchGL##F##Proc)\
            wglGetProcAddress("gl" #F #S);
    
#elif defined(SK_BUILD_FOR_MAC)
    #include <OpenGL/gl.h>
    #include <OpenGL/CGLCurrent.h>
    #define SK_BENCH_CONTEXT_CHECK (NULL != CGLGetCurrentContext())
    
#elif defined(SK_BUILD_FOR_UNIX)
    #include <GL/gl.h>
    #include <GL/glx.h>
    #define SK_BENCH_CONTEXT_CHECK (NULL != glXGetCurrentContext())
    
    #define SK_GL_GET_PROC(F) gBenchGL.f ## F = (BenchGL ## F ## Proc) \
            glXGetProcAddressARB(reinterpret_cast<const GLubyte*>("gl" #F));
    #define SK_GL_GET_PROC_SUFFIX(F, S) gBenchGL.f ## F = (BenchGL##F##Proc)\
            glXGetProcAddressARB(reinterpret_cast<const GLubyte*>("gl" #F #S));
#else
    #error unsupported platform
#endif

#define BenchGL_TIME_ELAPSED 0x88BF
#define BenchGL_QUERY_RESULT 0x8866
#define BenchGL_QUERY_RESULT_AVAILABLE 0x8867

#if defined(SK_BUILD_FOR_WIN32)
typedef UINT64 BenchGLuint64;
#else
#include <stdint.h>
typedef uint64_t BenchGLuint64;
#endif

typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLGenQueriesProc) (GLsizei n, GLuint *ids);
typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLBeginQueryProc) (GLenum target, GLuint id);
typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLEndQueryProc) (GLenum target);
typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLDeleteQueriesProc) (GLsizei n, const GLuint *ids);
typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLGetQueryObjectivProc) (GLuint id, GLenum pname, GLint *params);
typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLGetQueryObjectui64vProc) (GLuint id, GLenum pname, BenchGLuint64 *params);

struct BenchGLInterface {
    bool fHasTimer;
    BenchGLGenQueriesProc fGenQueries;
    BenchGLBeginQueryProc fBeginQuery;
    BenchGLEndQueryProc fEndQuery;
    BenchGLDeleteQueriesProc fDeleteQueries;
    BenchGLGetQueryObjectivProc fGetQueryObjectiv;
    BenchGLGetQueryObjectui64vProc fGetQueryObjectui64v;
};

static bool BenchGLCheckExtension(const char* ext,
                                  const char* extensionString) {
    int extLength = strlen(ext);

    while (true) {
        int n = strcspn(extensionString, " ");
        if (n == extLength && 0 == strncmp(ext, extensionString, n)) {
            return true;
        }
        if (0 == extensionString[n]) {
            return false;
        }
        extensionString += n+1;
    }

    return false;
}

static BenchGLInterface gBenchGL;
static bool gBenchGLInterfaceInit = false;

static void BenchGLSetDefaultGLInterface() {
    gBenchGL.fHasTimer = false;
    if (gBenchGLInterfaceInit || !SK_BENCH_CONTEXT_CHECK) return;

    const char* glExts =
        reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
    const GLboolean ext =
        BenchGLCheckExtension("GL_EXT_timer_query", glExts);
    const GLboolean arb =
        BenchGLCheckExtension("GL_ARB_timer_query", glExts);
    if (ext || arb) {
#if defined(SK_BUILD_FOR_MAC)
        #if GL_EXT_timer_query || GL_ARB_timer_query
        gBenchGL.fHasTimer = true;
        gBenchGL.fGenQueries = glGenQueries;
        gBenchGL.fBeginQuery = glBeginQuery;
        gBenchGL.fEndQuery = glEndQuery;
        gBenchGL.fDeleteQueries = glDeleteQueries;
        gBenchGL.fGetQueryObjectiv = glGetQueryObjectiv;
        #endif
        #if GL_ARB_timer_query
        gBenchGL.fGetQueryObjectui64v = glGetQueryObjectui64v;
        #elif GL_EXT_timer_query
        gBenchGL.fGetQueryObjectui64v = glGetQueryObjectui64vEXT;
        #endif
#else
        gBenchGL.fHasTimer = true;
        SK_GL_GET_PROC(GenQueries)
        SK_GL_GET_PROC(BeginQuery)
        SK_GL_GET_PROC(EndQuery)
        SK_GL_GET_PROC(DeleteQueries)
        
        SK_GL_GET_PROC(GetQueryObjectiv)
        if (arb) {
            SK_GL_GET_PROC(GetQueryObjectui64v)
        } else {
            SK_GL_GET_PROC_SUFFIX(GetQueryObjectui64v, EXT)
        }
#endif
    }
    gBenchGLInterfaceInit = true;
}

BenchGpuTimer::BenchGpuTimer() {
    BenchGLSetDefaultGLInterface();
    if (gBenchGL.fHasTimer) {
        gBenchGL.fGenQueries(1, &this->fQuery);
    }
}

BenchGpuTimer::~BenchGpuTimer() {
    if (gBenchGL.fHasTimer) {
        gBenchGL.fDeleteQueries(1, &this->fQuery);
    }
}

void BenchGpuTimer::startGpu() {
    if (!gBenchGL.fHasTimer) return;
    
    this->fStarted = true;
    gBenchGL.fBeginQuery(BenchGL_TIME_ELAPSED, this->fQuery);
}

/**
 * It is important to stop the cpu clocks first,
 * as this will cpu wait for the gpu to finish.
 */
double BenchGpuTimer::endGpu() {
    if (!gBenchGL.fHasTimer) return 0;
    
    this->fStarted = false;
    gBenchGL.fEndQuery(BenchGL_TIME_ELAPSED);
    
    GLint available = 0;
    while (!available) {
        gBenchGL.fGetQueryObjectiv(this->fQuery
                                 , BenchGL_QUERY_RESULT_AVAILABLE
                                 , &available);
    }
    BenchGLuint64 totalGPUTimeElapsed = 0;
    gBenchGL.fGetQueryObjectui64v(this->fQuery
                                , BenchGL_QUERY_RESULT
                                , &totalGPUTimeElapsed);
    
    return totalGPUTimeElapsed / 1000000.0;
}