OpenGL Loading

什麼是 OpenGL loading?linux

OpenGL是一份API規範,並非一個庫。記住這點很是重要!它意味着每個API背後的具體實現都依賴於你的GPU硬件、操做系統以及顯卡驅動。git

OpenGL規範定義了不少不一樣的函數,而且規範會按期進行更新,你的顯卡驅動可能不會支持所有的函數。你的顯卡和顯卡驅動的能力決定了你能使用的API規範的子集。這也是不把全部的OpenGL函數靜態定義在一個頭文件中供你使用的緣由。並且,將全部函數靜態連接成一個庫也是不可能的,由於你的應用運行的目標機器上會有各類各樣不一樣的OpenGL實現。github

Windows機器上,OpenGL是以dll的方式實現的。在64位Windows操做系統上,64位的dll庫位於 C:\Windows\system32\opengl32.dll,這個dll是顯卡驅動的一部分,是隨着顯卡驅動一塊兒發佈的。windows

再次強調,大部分的OpenGL函數是不能被定義在某個標準的頭文件中,而後靜態連接進你的應用程序的。這也是爲何OpenGL函數不能直接被調用,而須要顯式的聲明和加載。api

 

什麼是 GLEW?ide

GLEW(OpenGL Extension Wrangler)是一個跨平臺的用於OpenGL函數聲明和加載的庫,它一樣具有在運行時檢查目標機器是否支持某個OpenGL profile(一個profile就是一份指定配置支持的特定的OpenGL函數集)的能力。函數

GLEW很是的簡單,尤爲是針對剛開始接觸OpenGL的新手。它把全部的髒活累活都替你作了,你能夠在你的系統上自由的調用全部支持的有效OpenGL函數。ui

StackOverflow上,全部關於OpenGL loading的問題下,都有人建議你使用OpenGL Loading Library,中止本身定製OpenGL loading去使用GLEW。甚至OpenGL官方的wiki都強烈建議你使用OpenGL loading library。this

可是像GLEW這樣的OpenGL loading library有它們本身的缺點,下面就以GLEW爲例,來詳細講下這些缺點spa

 

爲何你最好不使用GLEW?

你能夠用如下兩種方式使用GLEW庫:

  1. Dynamically linking動態連接:一個OpenGL應用或者引擎發佈後,咱們但願用戶能夠很方便地在他們的機器上進行構建,GLEW使用動態連接的話,咱們要麼爲它要單獨創建一個編譯工程,要麼咱們本身要針對不一樣的目標機器,提早編譯好各類不一樣機器上的dll或so庫,這樣能夠說很麻煩
  2. Shipping the source連同代碼一塊兒發佈:將GLEW庫同OpenGL應用靜態編譯在一塊兒,這種方式能夠完美避開以上方式的缺點,惟一的缺點是GLEW庫的代碼量很大,它的存在增長了代碼的複雜度,同時增長了代碼的編譯時間。GLEW如此龐大的緣由是它維護了全部的OpenGL函數,而咱們的應用可能只須要其中很小的一個子集,好比咱們只須要modern opengl,也就是其core profile。

 

如何定製本身的OpenGL Loader?

github上有不少自定義的OpenGL loader,其中不乏短小精幹,很是好用的庫,好比https://gist.github.com/rygorous/16796a0c876cf8a5f542caddb55bce8a,在這個的基礎上,能夠增長一些跨平臺的宏定義。

    #if defined(__linux__)
    #include <dlfcn.h>
    #define GLDECL                // Empty define
    #define PAPAYA_GL_LIST_WIN32  // Empty define
    #endif // __linux__

    #if defined(_WIN32)
    #include <windows.h>
    #define GLDECL WINAPI

    #define GL_ARRAY_BUFFER         0x8892
    #define GL_ARRAY_BUFFER_BINDING 0x8894
    ...

    typedef char GLchar;
    typedef ptrdiff_t GLintptr;
    typedef ptrdiff_t GLsizeiptr;

    #define PAPAYA_GL_LIST_WIN32 \
        /* ret, name, params */ \
        GLE(void, BlendEquation, GLenum mode) \
        GLE(void, ActiveTexture, GLenum texture) \
        /* end */

    #endif // _WIN32

上面代碼咱們首先包含不一樣平臺的動態庫調用的頭文件。而後定義了windows平臺下的函數調用規範的宏GLDECL。咱們還須要包含GL/gl.h的頭文件,可是這個文件在Linux和Windows上是不一樣的。Windows SDK包含的gl.h版本是很是老的(OpenGL 1.1),因此它並無包含全部的OpenGL typedef,常量以及函數聲明,可是Linux平臺上通常是最新的。因此在Windows系統上須要手動添加這些定義。你能夠直接包含這個文件https://www.khronos.org/registry/OpenGL/api/GL/glext.h,它包含這些常量和函數的定義。

最後就是定義你須要的函數了,代碼以下:

#define BINKGL_LIST \
    /*  ret, name, params */ \
    GLE(void,      LinkProgram,         GLuint program) \
    GLE(void,      GetProgramiv,        GLuint program, GLenum pname, GLint *params) \
    GLE(GLuint,    CreateShader,        GLenum type) \
    GLE(void,      ShaderSource,        GLuint shader, GLsizei count, const GLchar* const *string, const GLint *length) \
    GLE(void,      CompileShader,       GLuint shader) \
    GLE(void,      GetShaderiv,         GLuint shader, GLenum pname, GLint *params) \
    GLE(void,      GetShaderInfoLog,    GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) \
    GLE(void,      DeleteShader,        GLuint shader) \
    GLE(GLuint,    CreateProgram,       void) \
    GLE(void,      AttachShader,        GLuint program, GLuint shader) \
    GLE(void,      DetachShader,        GLuint program, GLuint shader) \
    GLE(void,      UseProgram,          GLuint program) \
    GLE(void,      DeleteProgram,       GLuint program) \
    GLE(void,      GenVertexArrays,     GLsizei n, GLuint *arrays) \
    GLE(void,      BindVertexArray,     GLuint array) \
    GLE(void,      BufferData,          GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) \
    GLE(void,      GenBuffers,              GLsizei n, GLuint *buffers) \
    GLE(void,      BindBuffer,              GLenum target, GLuint buffer) \
    GLE(void,      DeleteBuffers,           GLsizei n, const GLuint *buffers) \
    GLE(void,      TexParameteri,           GLenum target, GLenum pname, GLint param) \
    GLE(void,      ActiveTexture,           GLenum texture) \
    GLE(void,      BindAttribLocation,      GLuint program, GLuint index, const GLchar *name) \
    GLE(GLint,     GetUniformLocation,      GLuint program, const GLchar *name) \
    GLE(void,      Uniform4f,               GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) \
    GLE(void,      Uniform4fv,    GLint location, GLsizei count, const GLfloat *value) \
    GLE(void,      DeleteVertexArrays,      GLsizei n, const GLuint *arrays) \
    GLE(void,      EnableVertexAttribArray, GLuint index) \
    GLE(void,      VertexAttribPointer,     GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) \
    GLE(void,      Uniform1i,               GLint location, GLint v0) \
    /* end */

#define GLE(ret, name, ...) typedef ret GLDECL name##proc(__VA_ARGS__); static name##proc * gl##name;
BINKGL_LIST
#undef GLE

static void *GLhandle;

bool gl_lite_init()
{
#if defined(__linux__)

    void* libGL = dlopen("libGL.so", RTLD_LAZY);
    if (!libGL) {
        printf("ERROR: libGL.so couldn't be loaded\n");
        return false;
    }

    #define GLE(ret, name, ...)                                                    \
            gl##name = (name##proc *) dlsym(libGL, "gl" #name);                    \
            if (!gl##name) {                                                       \
                printf("Function gl" #name " couldn't be loaded from libGL.so\n"); \
                return false;                                                      \
            }
        BINKGL_LIST
    #undef GLE

#elif defined(_WIN32)

    HINSTANCE dll = LoadLibraryA("opengl32.dll");
    typedef PROC WINAPI wglGetProcAddressproc(LPCSTR lpszProc);
    if (!dll) {
        OutputDebugStringA("opengl32.dll not found.\n");
        return false;
    }
    wglGetProcAddressproc* wglGetProcAddress =
        (wglGetProcAddressproc*)GetProcAddress(dll, "wglGetProcAddress");

    #define GLE(ret, name, ...)                                                                    \
            gl##name = (name##proc *)wglGetProcAddress("gl" #name);                                \
            if (!gl##name) {                                                                       \
                OutputDebugStringA("Function gl" #name " couldn't be loaded from opengl32.dll\n"); \
                return false;                                                                      \
            }
        BINKGL_LIST
    #undef GLE

#else
    #error "GL loading for this platform is not implemented yet."
#endif

    return true;
}
相關文章
相關標籤/搜索