【问题标题】:glTexImage2D fails with error 1282 using PBO (bad texture resolution)glTexImage2D 使用 PBO 失败并出现错误 1282(纹理分辨率不佳)
【发布时间】:2014-12-04 13:09:10
【问题描述】:

我在我的 OpenGL 应用程序中实现了像素缓冲区对象 (PBO)。但是,当我尝试使用函数“glTexImage2D”加载纹理时出现错误 1282。这很奇怪,因为问题来自具有特定分辨率的纹理。

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

a) 蓝色.jpg Bpp: 24 分辨率:259x469

b) 绿色.jpg Bpp: 24 分辨率:410x489

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

现在让我们检查不使用 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) 蓝色

b) 绿色

c) 红色

现在让我们检查一下使用这个 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

图形输出当然是一样的:

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

所以使用 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已消失但显示不正确:

我真的迷路了!

有人可以帮助我吗?

【问题讨论】:

  • 也许你应该尝试使用两种纹理的力量?

标签: opengl textures glsl texture-mapping texture2d


【解决方案1】:

很明显,您加载的图像数据被填充为每行生成 4 字节对齐。这是 GL 在默认情况下所期望的,也是您最有可能在非 PBO 案例中使用的。

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

当您最终切换到GL_UNPACK_ALIGNMENT of 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;

【讨论】:

  • 非常感谢您的所有解释!再见。
【解决方案2】:

我遇到了类似的问题,出现错误 1282 和黑色纹理。 据说 glTexImage2D 的第三个参数能够接受值 1,2,3,4 表示每个像素的字节数。但这突然因某种原因停止工作。用“GL​​_RGBA”替换“4”为我解决了这个问题。 希望这对某人有所帮助。

【讨论】:

    猜你喜欢
    • 2015-09-28
    • 2015-04-24
    • 1970-01-01
    • 2013-04-08
    • 2018-08-05
    • 1970-01-01
    • 2018-03-16
    • 2020-08-03
    • 1970-01-01
    相关资源
    最近更新 更多