简体   繁体   English

Mac OS X上的OpenGL纹理损坏

[英]OpenGL texture corruption on Mac OS X

I have a program that runs fine on both Windows and Linux on many different machines. 我有一个程序,可以在许多不同的计算机上的Windows和Linux上正常运行。 It doesn't work correctly on any mac I've tried (few different machines with OS X 10.9 and 10.10). 它在我尝试过的任何Mac上均无法正常工作(很少有其他机器使用OS X 10.9和10.10)。 The program basically just renders a textured quad on the screen. 该程序基本上只是在屏幕上渲染带纹理的四边形。 The texture format is floating point. 纹理格式为浮点数。

It looks like this on Windows and Linux: 在Windows和Linux上看起来像这样:

视窗

This is what it looks like on Mac: 这是在Mac上的样子:

苹果电脑

So the texture data gets to the GPU but gets weirdly distorted. 因此纹理数据到达了GPU,但是却发生了奇怪的变形。 Texture wrap mode is set to clamp and you can see how it behaves from the picture. 纹理环绕模式设置为钳制,您可以从图片中看到它的行为。

Here's the minimal drawing code: 这是最小的绘图代码:

void Framebuffer::initialize()
{
    Settings& settings = App::getSettings();

    glGenTextures(1, &imageTextureId);
    glBindTexture(GL_TEXTURE_2D, imageTextureId);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    resampleProgramId = GLHelper::buildProgram(settings.framebuffer.resampleVertexShader, settings.framebuffer.resampleFragmentShader);

    resampleTextureUniformId = glGetUniformLocation(resampleProgramId, "texture0");
    resampleTextureWidthUniformId = glGetUniformLocation(resampleProgramId, "textureWidth");
    resampleTextureHeightUniformId = glGetUniformLocation(resampleProgramId, "textureHeight");
    resampleTexelWidthUniformId = glGetUniformLocation(resampleProgramId, "texelWidth");
    resampleTexelHeightUniformId = glGetUniformLocation(resampleProgramId, "texelHeight");

    const GLfloat vertexData[] = {
        -1.0f, -1.0f, 0.0f, 0.0f,
        1.0f, -1.0f, 1.0f, 0.0f,
        1.0f, 1.0f, 1.0f, 1.0f,
        -1.0f, -1.0f, 0.0f, 0.0f,
        1.0f, 1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f, 0.0f, 1.0f,
    };

    glGenBuffers(1, &vertexBufferId);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);

    glGenVertexArrays(1, &vaoId);
    glBindVertexArray(vaoId);
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));
    glBindVertexArray(0);

    resize(settings.window.width, settings.window.height);
}

void Framebuffer::resize(int width, int height)
{
    image.resize(width, height);
    floatPixelData.resize(width * height * sizeof(float) * 4);

    // reserve the texture memory on the device
    glBindTexture(GL_TEXTURE_2D, imageTextureId);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, (GLsizei)width, (GLsizei)height, 0, GL_RGBA, GL_FLOAT, 0);
    glGenerateMipmap(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, 0);
}

void Framebuffer::render()
{
    int imageWidth = image.getWidth();
    int imageHeight = image.getHeight();

    glUseProgram(resampleProgramId);
    glUniform1i(resampleTextureUniformId, 0);

    std::vector<Color>& imagePixelData = image.getPixelData();

    // convert image data from Color to float array
    for (int i = 0; i < (int)imagePixelData.size(); ++i)
    {
        int pixelIndex = i * 4;

        floatPixelData[pixelIndex] = (float)imagePixelData[i].r;
        floatPixelData[pixelIndex + 1] = (float)imagePixelData[i].g;
        floatPixelData[pixelIndex + 2] = (float)imagePixelData[i].b;
        floatPixelData[pixelIndex + 3] = (float)imagePixelData[i].a;
    }

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, imageTextureId);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, (GLsizei)imageWidth, (GLsizei)imageHeight, GL_RGBA, GL_FLOAT, &floatPixelData[0]);
    glGenerateMipmap(GL_TEXTURE_2D);

    glBindVertexArray(vaoId);
    glDrawArrays(GL_TRIANGLES, 0, 6);
    glBindVertexArray(0);

    glBindTexture(GL_TEXTURE_2D, 0);
    glUseProgram(0);

    GLHelper::checkError("Could not render the framebuffer");
}

For the sake of testing all shaders were replaced with minimal color pass-through versions. 为了进行测试,所有着色器都替换为最小的颜色传递版本。

Here's what I've tried with no luck: 这是我没有运气尝试过的方法:

  • different internal texture formats 不同的内部纹理格式
  • different combinations of calling glGenerateMipmap 调用glGenerateMipmap不同组合
  • different vertex and texcoord values 不同的顶点和texcoord值
  • different texture clamp and min/max filter settings (mipmap on/off) 不同的纹理钳位和最小/最大滤镜设置(开/关mipmap)
  • different viewport values 不同的视口值

The same code works fine on Windows and Linux. 在Windows和Linux上,相同的代码也可以正常工作。

What could cause such corruption only Mac? 什么会导致仅Mac这样的损坏?

I'm not sure if this is the only problem in your code (if the problem is in your code at all), but there is definitely a problem with your mipmap generation. 我不确定这是否是您代码中的唯一问题(如果问题完全在您的代码中),但是您的mipmap生成肯定存在问题。 You have this sequence of calls: 您有以下呼叫顺序:

glBindTexture(GL_TEXTURE_2D, framebufferTextureId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)windowWidth, (GLsizei)windowHeight, 0, GL_RGBA, GL_FLOAT, 0);
glGenerateMipmap(GL_TEXTURE_2D);

glGenerateMipmap() is not a state setting call that specifies that you will want to have mipmaps generated once the texture is filled with data. glGenerateMipmap() 不是一个状态设置调用,它指定一旦纹理填充了数据,您将希望生成glGenerateMipmap() What it does is generate mipmaps from the data in the texture at the time of the call . 它的作用是在调用时从纹理中的数据生成mipmap。 Since you just allocated the texture data in the previous call, and do not have data in the texture yet, glGenerateMipmap() will do nothing. 由于您只是在上一个调用中分配了纹理数据,并且尚未在纹理中包含数据,因此glGenerateMipmap()不会执行任何操作。

Later, you use this texture: 稍后,您将使用以下纹理:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, framebufferTextureId);

At this point, the texture does not have mipmaps, even though the sampling mode is set to use mipmaps. 此时,即使采样模式设置为使用mipmap,纹理也没有mipmap。

What you need to do is generate mipmaps after the texture has been filled with data. 您需要做的是在纹理中填充数据后生成mipmap。 You can remove the glGenerateMipmap() call from its current place in setWindowSize() , and for example move it just below the second coder fragment above: 您可以删除glGenerateMipmap()从当前位置呼叫setWindowSize()例如移动它正上方的第二编码片段如下:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, framebufferTextureId);

glGenerateMipmap(GL_TEXTURE_2D);

Ok, I finally figured it out. 好吧,我终于明白了。 The attribute locations inside the vertex shader were switched on Mac OS X. By just good luck it rendered something on the screen with texcoords as vertex positions and vice versa. 顶点着色器内部的属性位置已在Mac OS X上进行了切换。幸运的是,它使用texcoords作为顶点位置在屏幕上渲染了东西,反之亦然。

I could have used glBindAttribLocation to fix it, but I updated the shaders to version 330 and used the layout(location = 0) attribute. 我本可以使用glBindAttribLocation进行修复,但是我将着色器更新为版本330,并使用layout(location = 0)属性。 That worked fine too. 那也很好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM