手动调用 OpenGL 函数

Manually calling OpenGL functions

我一直致力于创建一个 OpenGL 函数加载库,它将帮助我在需要时调用 OpenGL 函数。

我有一个使用 glX 的 getProcAddress 函数。

void* getProcAddress(const char *name)
{
    auto pr = reinterpret_cast<void*>(glXGetProcAddress(
            reinterpret_cast<const unsigned char*>(name)));

    return pr;
}

此 returns OpenGL 函数的地址。如果我不使用 reinterpret_casts,我会得到奇怪的编译器错误,所以这就是它们存在的原因。

然后我在头文件中定义一个 gl* 函数原型:

typedef void _GLACTIVETEXTURE(GLenum texture);

其中GLenum在另一个头文件中定义为枚举。然后我在 class:

中声明函数指针
_GLACTIVETEXTURE glActiveTexture;

然后在一个名为 init 的函数中我做:

void GLFunctions::init()
{
    glActiveTexture = (_GLACTIVETEXTURE)getProcAddress("glActiveTexture");
}

getProcAddress 函数可以自行编译,但上面的代码行无法编译。 GCC 抛出此编译器错误:

error: invalid cast to function type ‘_GLACTIVETEXTURE {aka void(GLenum)}’

而且我不知道如何处理这种编译器错误。这没有意义,因为这是一个函数指针,而不是函数本身,除非我使用 ()。我不太确定这里的问题是什么;无论是我这边还是 GCC。目前还不清楚。我试过摆弄指针和空隙,但都是徒劳的,并且出现了相同的错误消息。有谁知道这里发生了什么以及我如何正确调用 OpenGL 函数?

你的typedef错了。您正在为函数 type 创建别名,而不是函数 pointer。这是正确的做法:

typedef void (*_GLACTIVETEXTURE)(GLenum texture);

@nshct 已经向您解释了为什么编译器会抱怨您的代码。该答案没有解决的是,为什么您的 reinterpret_cast 首先是必需的。这样做的原因是,函数指针与常规指针不同,并且完全有可能 sizeof(void*) != sizeof(void(*)(void)),即函数指针可能具有与常规指针完全不同的值范围和对齐规则。 dlsym 的手册页详细解决了这个问题:

http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html

Rationale

The ISO C standard does not require that pointers to functions can be cast back and forth to pointers to data. Indeed, the ISO C standard does not require that an object of type void * can hold a pointer to a function. Implementations supporting the XSI extension, however, do require that an object of type void * can hold a pointer to a function. The result of converting a pointer to a function into a pointer to another data type (except void *) is still undefined, however. Note that compilers conforming to the ISO C standard are required to generate a warning if a conversion from a void * pointer to a function pointer is attempted as in:

fptr = (int (*)(int))dlsym(handle, "my_function");

Due to the problem noted here, a future version may either add a new function to return function pointers, or the current interface may be deprecated in favor of two new functions: one that returns data pointers and the other that returns function pointers.

因此在使用 dlsym 时必须使用一种特殊的转换方式,即一些左值转换技巧。

void    *handle;
int     (*fptr)(int);

/* open the needed object */
handle = dlopen("/usr/home/me/libfoo.so", RTLD_LOCAL | RTLD_LAZY);

/* find the address of function and data objects */
*(void **)(&fptr) = dlsym(handle, "my_function");

glXGetProcAddress 的定义意识到了这一点,并明确地写成 returns 一个函数指针。但是因为函数指针不同于常规指针,所以您不能将函数指针转换为常规指针。相反,您必须转换为目标函数指针类型,或者在赋值中转换函数指针变量左值(与 dlsym 一样)以匹配 glXGetProcAddress 的右值。