Mac OS X上的OpenGL纹理损坏

时间:2015-09-09 17:12:47

标签: c++ macos opengl

我有一个程序可以在许多不同的机器上运行在Windows和Linux上。它在我尝试的任何mac上都无法正常工作(OS X 10.9和10.10的几台不同机器)。该程序基本上只是在屏幕上呈现纹理四边形。纹理格式是浮点。

在Windows和Linux上看起来像这样:

windows

这就是Mac上的样子:

mac

因此,纹理数据会进入GPU,但却会出现奇怪的扭曲现象。纹理包装模式设置为钳位,您可以从图片中看到它的行为方式。

这是最小的绘图代码:

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");
}

为了测试,所有着色器都替换为最小颜色传递版本。

这是我尝试过没有运气的事情:

  • 不同的内部纹理格式
  • 调用glGenerateMipmap
  • 的不同组合
  • 不同的顶点和texcoord值
  • 不同的纹理裁剪和最小/最大滤镜设置(mipmap开/关)
  • 不同的视口值

相同的代码在Windows和Linux上运行良好。

什么可能导致这种腐败只有Mac?

2 个答案:

答案 0 :(得分:0)

我不确定这是否是您代码中唯一的问题(如果问题完全在您的代码中),但您的mipmap生成肯定存在问题。你有这样一系列的电话:

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() 状态设置调用,指定在纹理填充数据后您希望生成mipmap。它的作用是从调用时纹理中的数据生成mipmap 。由于您刚刚在上一次调用中分配了纹理数据,并且纹理中还没有数据,glGenerateMipmap()将不执行任何操作。

稍后,您使用此纹理:

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

此时,即使采样模式设置为使用mipmap,纹理也没有mipmap。

您需要做的是在纹理填充数据后生成mipmap。您可以从glGenerateMipmap()中的当前位置移除setWindowSize()来电,例如将其移至上方第二个编码器片段下方:

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

glGenerateMipmap(GL_TEXTURE_2D);

答案 1 :(得分:0)

好的,我终于明白了。顶点着色器内的属性位置在Mac OS X上切换。幸运的是,它在屏幕上呈现了一些东西,其中texcoords作为顶点位置,反之亦然。

我本可以使用glBindAttribLocation来修复它,但我将着色器更新到版本330并使用了layout(location = 0)属性。这也很好。