glTexImage2D使用PBO失败,错误1282(纹理分辨率差)

时间:2014-12-04 13:09:11

标签: opengl textures glsl texture-mapping texture2d

我在OpenGL应用程序中实现了Pixel Buffer Object(PBO)。但是,当我尝试使用函数'glTexImage2D'加载纹理时,我有错误1282。这很奇怪,因为问题来自具有特定分辨率的纹理。

为了更好地理解我的问题,让我们检查3种具有3种不同分辨率的纹理:

a)blue.jpg Bpp:24 决议:259x469

enter image description here

b)green.jpg Bpp:24 决议:410x489

enter image description here

c)red.jpg Bpp:24 分辨率:640x480

enter image description here

现在让我们检查一下没有使用PBO的C ++代码:

FIBITMAP *bitmap = FreeImage_Load(
    FreeImage_GetFIFFromFilename(file.GetFullName().c_str()), file.GetFullName().c_str());
FIBITMAP *pImage = FreeImage_ConvertTo32Bits(bitmap);

char *pPixels = (char*)FreeImage_GetBits(bitmap);
uint32_t width = FreeImage_GetWidth(bitmap);
uint32_t height = FreeImage_GetHeight(bitmap);
uint32_t byteSize = width * height * (FreeImage_GetBPP(bitmap)/8); //24 bits / 8 bits = 3 bytes)

glGenTextures(1, &this->m_Handle);
glBindTexture(GL_TEXTURE_2D, this->m_Handle);
{
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    std::cout << "ERROR: " << glGetError() << std::endl;

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width,
        height, 0, GL_BGR, GL_UNSIGNED_BYTE, pPixels);

    std::cout << "ERROR: " << glGetError() << std::endl;

    if (this->m_IsMipmap)
        glGenerateMipmap(this->m_Target);
}
glBindTexture(GL_TEXTURE_2D, 0);

对于3个纹理,输出始终相同(因此加载已正确执行):

$> ERROR: 0
$> ERROR: 0

图形结果也是正确的:

a)蓝色

enter image description here

b)绿色

enter image description here

c)红色

enter image description here

现在让我们使用这次PBO来检查C ++代码:

FIBITMAP *bitmap = FreeImage_Load(
    FreeImage_GetFIFFromFilename(file.GetFullName().c_str()), file.GetFullName().c_str());
FIBITMAP *pImage = FreeImage_ConvertTo32Bits(bitmap);

char *pPixels = (char*)FreeImage_GetBits(bitmap);
uint32_t width = FreeImage_GetWidth(bitmap);
uint32_t height = FreeImage_GetHeight(bitmap);
uint32_t byteSize = width * height * (FreeImage_GetBPP(bitmap)/8);

uint32_t  pboID;

glGenTextures(1, &this->m_Handle);
glBindTexture(GL_TEXTURE_2D, this->m_Handle);
{
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glGenBuffers(1, &pboID);
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboID);
    {
        unsigned int bufferSize = width * height * 3;

        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

        glBufferData(GL_PIXEL_UNPACK_BUFFER, bufferSize, 0, GL_STATIC_DRAW);
        glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, bufferSize, pPixels);

        std::cout << "ERROR: " << glGetError() << std::endl;

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width,
            height, 0, GL_BGR, GL_UNSIGNED_BYTE, OFFSET_BUFFER(0));

        std::cout << "ERROR: " << glGetError() << std::endl;

        if (this->m_IsMipmap)
            glGenerateMipmap(this->m_Target);
    }
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}
glBindTexture(GL_TEXTURE_2D, 0);

blue.jpg(259x469)和green.jpg(410x489)的输出如下:

$> ERROR: 0
$> ERROR: 1282

图形输出当然都是相同的:

enter image description here

但现在最有趣的是如果纹理red.jpg(640x480)没有错误,图形输出是正确的:

enter image description here

因此使用PBO方法1282错误似乎是指纹理分辨率问题!

OpenGL文档说明了关于PBO的错误1282(GL_INVALID_OPERATION):

GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER target and the buffer object's data store is currently mapped.

GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER target and the data would be unpacked from the buffer object such that the memory reads required would exceed the data store size.

GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER target and data is not evenly divisible into the number of bytes needed to store in memory a datum indicated by type.

但我不明白我的代码实现有什么问题!

我想也许如果我需要使用PBO我可以加载具有8的倍数的分辨率的纹理......但我希望不会!

更新

我试图添加一行:

glPixelStorei(GL_UNPACK_ALIGNMENT,1); // 1:字节对齐

在调用'glTexImage2D'之前

错误1282消失但显示不正确:

enter image description here

我真的输了!

有人可以帮助我吗?

2 个答案:

答案 0 :(得分:1)

您加载的图像数据被填充以生成每行的4字节对齐。这是GL默认的预期,以及您最可能在非PBO案例中使用的内容。

当您切换到PBO时,您忽略了每行的填充字节,因此您的缓冲区很小,并且GL检测到了超出范围的访问。

当你最终切换到GL_UNPACK_ALIGNMENT为1时,不再有超出范围的访问,并且错误消失了。但是你现在对你的数据格式撒谎。它仍然是填充的,但你告诉GL它不是。对于640x480图像,填充为零字节(因为640 * 3可以除以4),但对于其他两个图像,每行末尾都有填充字节。

正确的解决方案是将GL_UNPACK_ALIGNMENT保留为默认值4,并修复bufferSize的计算。您需要找出每行必须添加多少字节,以便该行的总字节数再次被4整除(这意味着,最多可添加3个字节):

unsigned int padding = ( 4 - (width * 3) % 4 ) % 4;

现在,你可以考虑这些额外的字节,并获得缓冲区的最终大小(以及你在内存中的图像):

unsigned int bufferSize = (width *  3 + padding) * height;

答案 1 :(得分:0)

我有一个类似的问题,我得到错误1282和黑色纹理。 据说glTexImage2D的第三个参数能够接受1,2,3,4的值,即每个像素的字节数。但由于某种原因,这突然停止了工作。替换&#39; 4&#39;与&#39; GL_RGBA&#39;为我解决了这个问题。 希望这有助于某人。