在 OpenGL glTexImage2D() 中,如果“数据”指针为 NULL,最后两个枚举是不是执行任何操作?

Posted

技术标签:

【中文标题】在 OpenGL glTexImage2D() 中,如果“数据”指针为 NULL,最后两个枚举是不是执行任何操作?【英文标题】:In OpenGL glTexImage2D() do the last two enums do anything if the 'data' pointer is NULL?在 OpenGL glTexImage2D() 中,如果“数据”指针为 NULL,最后两个枚举是否执行任何操作? 【发布时间】:2020-05-21 17:01:43 【问题描述】:

我真的很想了解这一点,但文档并没有让我清楚。假设我想将 32 位整数写入帧缓冲区,我没有任何像素数据要加载到纹理中,我只是创建一个帧缓冲区。

void glTexImage2D(  GLenum target,
    GLint level,
    GLint internalformat,
    GLsizei width,
    GLsizei height,
    GLint border,
    GLenum format,
    GLenum type,
    const void * data);

文档暗示最后两个枚举,格式和类型用于了解正在读取的像素数据是什么类型的数据,而 internalFormat 用于了解以什么格式存储您创建的纹理。我认为在您不提供任何纹理数据的情况下,最后一个参数,或者至少其中一个未使用,但是我尝试将它们更改为其他枚举值并且我得到一个错误,可能是因为它们是完全错误的枚举对于那个特定的论点。

在什么情况下不使用最后两个枚举? 例如,三个枚举值中的哪一个决定了纹理在着色器中的采样方式?

假设我创建了两个示例帧缓冲区。

glTexImage2D(GL_TEXTURE_2D, 0, GL_R32I, width, height, 0, GL_RED_INTEGER, GL_INT, NULL);

我的想法是我想将整数值写入这个帧缓冲区,所以在片段着色器中我这样做:

out int outIntValue

int main()

     outIntValue = 7;
     // not 
     // outIntValue.r = 7; 
     right?

我对它进行采样:

layout (binding = 0) uniform isampler2D texture1;

int main()

    int val = texture(texture1, vec2(0.5, 0.5).r; // .r right?

对于 32 位浮点帧缓冲区,我创建它的方式如下:

glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, width, height, 0, GL_RED, GL_FLOAT, NULL);

我是这样写的:

out int outFloatValue;

int main()

    outFloatValue = 0.7;
    // not
    // outFloatValue.r = 0.7; 


和这样的示例:

layout (binding = 0) uniform sampler2D texture1;

int main()

    float val = texture(texture1, vec2(0.5, 0.5).r; // .r right?

另外,在这两种情况下,最后两个枚举值什么都不做?谢谢。

【问题讨论】:

感谢您的提问。我很确定采样只取决于纹理的internalFormat 和采样器的配置。但是,是的,我仍然错过了大局。我也觉得如果最后一个参数是NULL,则不需要最后两个枚举。您是否尝试通过..., 0, 0, NULL)?在这种情况下你会出错吗? 【参考方案1】:

您必须考虑与整数格式相关的一条重要规则:

来自OpenGL 4.6 API Core Profile Specification - 8.5 Texture Image Specification(第215页):

如果内部格式是整数并且格式不是表 8.3 中列出的整数格式之一,或者如果内部格式不是整数并且格式是整数格式,则会生成 INVALID_OPERATION 错误。

整数格式例如RED_INTEGERRG_INTEGERRGB_INTEGER ...

注意,在某些情况下,internalformatformat 的组合会产生错误。如果没有产生错误,那很好。 formattype 不影响目标缓冲区的内部格式,完全独立于最后一个参数(data)。唯一的问题是您是否收到错误,并且可以在规范中阅读。

【讨论】:

【参考方案2】:

在纹理填充数据的那一刻,内部函数接收原始字节。

因为每种数字类型(short、int、float 等)都有不同的内存表示格式,读取函数必须知道要使用的格式。它还必须知道它正在读取什么(通道 RED,或同时读取多个通道等)。

在什么情况下不使用最后两个枚举?

从来没有。它们总是被使用。

【讨论】:

我问的原因是因为我很确定有人告诉我,也许在这里,当指针为 NULL 时,至少有一个没有被使用,但我可能被误导了。 @Zebrafish 当glTexImage2D(数据)的最后一个参数为NULL时,驱动程序只为数据保留空间,但不会从RAM内存中读取数据。 谢谢@Ripi2,我一直想明白这一点,看来今天可能会发生。很长一段时间以来,我和斑马鱼有着完全相同的怀疑。您说参数在那里是因为“读取函数必须知道”,然后您说当最后一个参数为 NULL 时,“它不读取数据”。这是否意味着在这种情况下不使用它们?谢谢! 即使假设它们被存储在内部供以后使用,也需要在下一次 texImage2DtexSubImage2D 调用中重新指定,所以我认为它们不会被存储。 @damix911 如何在不知道这些参数的情况下计算所需的字节大小?【参考方案3】:

在什么情况下不使用最后两个枚举?

来自 OpenGL 4.6(核心配置文件) - 2019 年 10 月 22 日,第 203 页。

format, type, and data specify the format of
the image data, the type of those data, and a reference to the image data in the 
currently bound pixel unpack buffer or client memory, as described in section

如果dataNULL,它们似乎没有“使用”,但它们总是会根据internalFormat 进行检查,如果您指定了非法组合,则会出现错误。我想这是你可以在 C API 中做的最好的事情。

例如,三个枚举值中的哪一个决定了纹理在着色器中的采样方式?

从着色器的角度来看,只有internalFormat 和采样配置才算在内。

【讨论】:

谢谢你,你是对的,完成了。我想说的是,似乎有多种方法可以设置这两个参数(在 4.6 中甚至比 WebGL 2 中的更多,据我了解,其中一些限制被取消了),最终没关系当dataNULL。我宁愿强迫用户在无数据情况下使用特殊值,例如GL_UNUSED0,而不是允许他们指定几乎任何东西。至少这可以清楚地表明它们是无关紧要的。但我想我在吹毛求疵。 啊,非常感谢您发现我。是的,我想知道如果我不发送图像像素数据,我应该为最后两个枚举传递什么参数,因为我希望函数调用清晰,而不是仅仅放置 GL_RED_INTEGER 和 GL_INT 不客气!我认为你问了一个很好的问题。我发现文档令人困惑,而且我认识的另一位开发人员也对该 API 有类似的疑问。

以上是关于在 OpenGL glTexImage2D() 中,如果“数据”指针为 NULL,最后两个枚举是不是执行任何操作?的主要内容,如果未能解决你的问题,请参考以下文章

C++ OpenGL glTexImage2D 访问冲突

OpenGL 像素在内存中的排列方式

glTexImage2D 中的 ByteBuffer.wrap() 导致过多的垃圾收集

glTexImage2D与glDeleteTextures 求助

关于OpenGL纹理 装载位图的问题

对符号 glTexImage2D 的未定义引用