glTexImage2D 读取超出缓冲区范围 (iOS)

glTexImage2D reads beyond bounds of buffer (iOS)

在下面的简单代码中,我将 1 通道数据加载到纹理中。我将 glTexImage2D()GL_LUMINANCE(一种单通道格式)和 GL_UNSIGNED_BYTE 一起使用,因此每个像素应该占用一个字节。我分配了一个缓冲区,其大小等于代表输入像素数据的像素数 (2 x 2)(像素值对我们的目的无关紧要)。

当您 运行 以下代码启用了 Address Sanitizer 时,它会在对 glTexImage2D() 的调用中检测到堆缓冲区溢出,表示它试图读取超出堆分配范围的内容缓冲区:

#import <OpenGLES/ES2/gl.h>

//...

EAGLContext* context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
[EAGLContext setCurrentContext:context];

GLsizei width = 2, height = 2;
void *data = malloc(width * height); // contents don't matter for now
glTexImage2D(GL_TEXTURE_2D,
             0,
             GL_LUMINANCE,
             width,
             height,
             0,
             GL_LUMINANCE,
             GL_UNSIGNED_BYTE,
             data);

这是 100% 可重现的,并且发生在 iOS 模拟器和设备上。只有将缓冲区的大小增加到 6 才不会溢出(2 比预期大小 4 大)。

1x1 和 4x4 的尺寸似乎没有这个问题,但是 2x2 和 3x3 有。好像有点武断。

怎么了?

感谢@genpfault 的评论,我已经解决了。

我需要将解包对齐设置为 1:

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

具体来说,解包对齐方式决定了每行开头的对齐方式。默认值为4。由于我的行没有任何特殊的对齐方式,并且行字节之间没有间隙,因此对齐方式应为1。

第一行将始终对齐,因为 malloc 分配了 16 位对齐的缓冲区。但是第二行和后续行与默认对齐方式 4 不对齐,除非行长度是 4 的倍数(这解释了为什么 2x2 和 3x3 不起作用,但 4x4 起作用)。 1x1 正好可以工作,因为它没有第二行。