这里不是比较
GLAD
和GLEW
优劣问题,而是简单地说一下其实现流程。
GLAD
因为
OpenGL
只是一个 标准/规范,具体的实现是由驱动开发商针对特定显卡实现的。由于OpenGL
驱动版本众多,大多数函数的位置(内存地址)都无法在 编译 时确定下来,需要在 运行时 查询。所以开发者在开发使用OpenGL
时,需要在 运行时 获取函数的内存地址并将其保存在一个函数指针中供以后使用。取得地址的方法因平台而异,(Windows)大致流程 如下:1
2
3
4
5
6
7// 定义函数原型
typedef void (*GL_GENBUFFERS) (GLsizei, GLuint*);
// 找到正确的函数并赋值给函数指针
GL_GENBUFFERS glGenBuffers = (GL_GENBUFFERS)wglGetProcAddress("glGenBuffers");
// 现在函数可以被正常调用了
GLuint buffer;
glGenBuffers(1, &buffer);然而写这些代码非常复杂,而且很繁琐,需要对每个可能使用的函数都要重复这个过程。不过
GLAD
的做过就是将上面的过程进行简化供开发者使用。根据
Load OpenGL Functions
WiKi,wglGetProcAddress
在失败时返回NULL
,但一些实现将返回其他值。1,2和3,以及-1过程如下:1
2
3
4
5
6
7
8
9
10
11
12
13void *GetAnyGLFuncAddress(const char *name)
{
void *p = (void *)wglGetProcAddress(name);
if(p == 0 ||
(p == (void*)0x1) || (p == (void*)0x2) || (p == (void*)0x3) ||
(p == (void*)-1) )
{
HMODULE module = LoadLibraryA("opengl32.dll");
p = (void *)GetProcAddress(module, name);
}
return p;
}在 MacOSX 平台,在 OSX 10.2 后
GL Fuction
是 weak 链接,也就意味着可以直接调用它们,未实现的扩展将解析为NULL
。Apple
建议需要getProcAddress
功能的程序使用NSSymbol
直接查找函数指针。如下:Listing C-1 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#import <mach-o/dyld.h>
#import <stdlib.h>
#import <string.h>
void * MyNSGLGetProcAddress (const char *name)
{
NSSymbol symbol;
char *symbolName;
symbolName = malloc (strlen (name) + 2);
strcpy(symbolName + 1, name);
symbolName[0] = '_';
symbol = NULL;
if (NSIsSymbolNameDefined (symbolName))
symbol = NSLookupAndBindSymbol (symbolName);
free (symbolName);
return symbol ? NSAddressOfSymbol (symbol) : NULL;
}Listing C-2:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31#import "MyNSGLGetProcAddress.h"
static void InitEntryPoints (void);
static void DeallocEntryPoints (void);
// Function pointer type definitions
typedef void (*glBlendColorProcPtr)(GLclampf red,GLclampf green,
GLclampf blue,GLclampf alpha);
typedef void (*glBlendEquationProcPtr)(GLenum mode);
typedef void (*glDrawRangeElementsProcPtr)(GLenum mode, GLuint start,
GLuint end,GLsizei count,GLenum type,const GLvoid *indices);
glBlendColorProcPtr pfglBlendColor = NULL;
glBlendEquationProcPtr pfglBlendEquation = NULL;
glDrawRangeElementsProcPtr pfglDrawRangeElements = NULL;
static void InitEntryPoints (void)
{
pfglBlendColor = (glBlendColorProcPtr) MyNSGLGetProcAddress
("glBlendColor");
pfglBlendEquation = (glBlendEquationProcPtr)MyNSGLGetProcAddress
("glBlendEquation");
pfglDrawRangeElements = (glDrawRangeElementsProcPtr)MyNSGLGetProcAddress
("glDrawRangeElements");
}
// -------------------------
static void DeallocEntryPoints (void)
{
pfglBlendColor = NULL;
pfglBlendEquation = NULL;
pfglDrawRangeElements = NULL;;
}关于以上代码的解释,可以到这里查看。
再回到
GLAD
,在 glad.h 文件可以看到
glGenBuffers
的定义:1
2
3
4
5
6
7
8
9#ifndef APIENTRYP
#define APIENTRYP APIENTRY *
#endif
define GLAPI extern
typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint *buffers);
GLAPI PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers;
#define glDeleteBuffers glad_glDeleteBuffers在 glad.c 文件中可以看到
gladGetProcAddressPtr
的定义:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35#ifndef __APPLE__
typedef void* (APIENTRYP PFNGLXGETPROCADDRESSPROC_PRIVATE)(const char*);
static PFNGLXGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr;
#endif
static
int open_gl(void) {
#ifdef __APPLE__
static const char *NAMES[] = {
"../Frameworks/OpenGL.framework/OpenGL",
"/Library/Frameworks/OpenGL.framework/OpenGL",
"/System/Library/Frameworks/OpenGL.framework/OpenGL",
"/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL"
};
#else
static const char *NAMES[] = {"libGL.so.1", "libGL.so"};
#endif
unsigned int index = 0;
for(index = 0; index < (sizeof(NAMES) / sizeof(NAMES[0])); index++) {
libGL = dlopen(NAMES[index], RTLD_NOW | RTLD_GLOBAL);
if(libGL != NULL) {
#ifdef __APPLE__
return 1;
#else
gladGetProcAddressPtr = (PFNGLXGETPROCADDRESSPROC_PRIVATE)dlsym(libGL,
"glXGetProcAddressARB");
return gladGetProcAddressPtr != NULL;
#endif
}
}
return 0;
}
GLEW
GLEW
的出现也是为了在开发时,能够针对不能显卡制造商的显卡的OpenGL
的不同版本,实现在 运行时 获取函数的内存地址并将其保存在一个函数指针中供以使用。在 glew.h 文件中可以看懂
glGenBuffers
的定义:1
2
3
4
5
6
7
8
9
10
11
12
13#ifndef GLEW_GET_FUN
#define GLEW_GET_FUN(x) x
#endif
#ifndef GLAPIENTRY
#define GLAPIENTRY
#endif
typedef void (GLAPIENTRY * PFNGLGENBUFFERSPROC) (GLsizei n, GLuint* buffers);
GLEW_FUN_EXPORT PFNGLGENBUFFERSPROC __glewGenBuffers;
#define glGenBuffers GLEW_GET_FUN(__glewGenBuffers)小结
GLAD
和GLEW
的作用都是帮助在开发OpenGL
时简化其在 运行时 获取函数的内存地址并将其保存在一个函数指针中供以使用的流程。