手动调用OpenGL函数

3

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

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

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

    return pr;
}

这返回一个OpenGL函数的地址。如果我不使用reinterpret_cast,就会出现奇怪的编译器错误,因此它们存在的原因就在这里。

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

typedef void _GLACTIVETEXTURE(GLenum texture);

在另一个头文件中定义了一个枚举类型的 GLenum。然后我在一个类中声明了函数指针:

_GLACTIVETEXTURE glActiveTexture;

然后在一个名为init的函数中,我执行以下操作:

void GLFunctions::init()
{
    glActiveTexture = (_GLACTIVETEXTURE)getProcAddress("glActiveTexture");
}
getProcAddress函数本身可以编译通过,但上述代码行无法编译。GCC会抛出以下编译器错误:
error: invalid cast to function type ‘_GLACTIVETEXTURE {aka void(GLenum)}’

我不知道如何处理这种编译器错误。这没有意义,因为这是一个函数指针,而不是函数本身,除非我使用()。我不确定问题出在哪里,是我的问题还是GCC的问题。这一点也不清楚。我尝试过调整指针和voids,但都无济于事,仍然出现相同的错误消息。有人知道这里发生了什么,以及我如何正确调用OpenGL函数吗?


你是否了解glew?http://glew.sourceforge.net/ - H. Guijt
@H.Guijt想要通过手动加载函数指针来实现。 - Akib Azmain Turja
@Akib Azmain 不要居高临下。指出替代方案并可能为某人节省大量工作并不是犯罪。 - H. Guijt
2个回答

5
@nshct已经解释了编译器为什么会抱怨你的代码。但这个答案没有解决的问题是,为什么你需要首先使用reinterpret_cast。原因在于,函数指针与常规指针不同,并且完全有可能sizeof(void*) != sizeof(void(*)(void)),也就是说函数指针可能具有完全不同的值范围和对齐规则。 dlsym的man页面详细介绍了这一点: 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 的定义已经考虑到了这一点,并且显式地编写为返回函数指针。但是因为函数指针与普通指针不同,您不能将函数指针强制转换为普通指针。相反,您必须将其转换为目标函数指针类型,或者像使用 dlsym 一样将函数指针变量 lvalue 在赋值时进行转换以匹配 glXGetProcAddress 的 rvalue。


有没有真正的系统,其中函数指针和常规指针实际上是不同的?我不怀疑理论,只是想知道它是否是现实生活中的问题。 - Reto Koradi
@RetoKoradi:几乎所有哈佛架构处理器都是如此。大多数DSP都是哈佛架构,许多微控制器也是如此。 - datenwolf
例如,看一下模拟器件ADSP-219x DSP:它们使用16位可寻址数据存储总线(即数据的16位地址空间),但程序存储总线具有24个可寻址位(24位地址空间)。因此,如果您将函数指针转换为常规数据指针,则会被截断。 - datenwolf
1
具有dlsym [posix / unix]或GetProcAddress [Windows]的系统必定具有统一的数据和代码指针。对于其他系统则无法这样说。 - Zsigmond Lőrinczy
1
我认为这种“左值转换技巧”可能会导致问题,如果数据指针和代码指针的大小不同(例如:如果数据指针长度为32位而代码指针长度为16位,则在“fptr”之后覆盖16位)。 - Lorinczy Zsigmond

3
您的typedef有误。您正在创建函数类型的别名,而不是函数指针的别名。以下是正确的做法:
typedef void (*_GLACTIVETEXTURE)(GLenum texture);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接