Mac OS X 上的 OpenGL 纹理损坏
Posted
技术标签:
【中文标题】Mac OS X 上的 OpenGL 纹理损坏【英文标题】:OpenGL texture corruption on Mac OS X 【发布时间】:2015-09-09 17:12:46 【问题描述】:我有一个程序可以在许多不同机器上的 Windows 和 Linux 上运行良好。它在我尝试过的任何 Mac 上都无法正常工作(很少有不同的机器使用 OS X 10.9 和 10.10)。该程序基本上只是在屏幕上渲染一个带纹理的四边形。纹理格式为浮点数。
在 Windows 和 Linux 上看起来像这样:
这是它在 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
的不同组合
不同的顶点和纹理坐标值
不同的纹理钳位和最小/最大过滤器设置(mipmap 开/关)
不同的视口值
相同的代码在 Windows 和 Linux 上运行良好。
只有 Mac 可能导致这种损坏?
【问题讨论】:
由于实际的纹理存储是通过glTexImage()
创建的,因此不清楚您的代码是否创建了有效的纹理。 framebufferTextureID
的存储是在setWindowSize()
中创建的,它在Initialize()
期间被调用,但只有在保证在您尝试渲染之前调用Frambuffer::resize()
时才会创建存储imageTextureID
,这可能只是不会就是这样。另请注意,您不使用浮点纹理。您使用内部格式GL_RGBA
,这是一种标准化整数格式,每通道 8 位。
文本是在纹理的左上角部分,还是在绘制纹理四边形后将其渲染在顶部?
@derhass resize
保证会被调用。内部格式的东西很好,我会尝试改变它。 @reto 是的,文本被渲染为另一个带有 freetype-gl 的纹理四边形。 -- 我只是想知道这种渲染错误是否是一些已知问题。
【参考方案1】:
我不确定这是否是您代码中的唯一问题(如果问题完全出在您的代码中),但您的 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。您可以从setWindowSize()
中的当前位置删除glGenerateMipmap()
调用,例如将其移动到上面第二个编码器片段的下方:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, framebufferTextureId);
glGenerateMipmap(GL_TEXTURE_2D);
【讨论】:
在测试了这个和许多其他东西之后,我已经编辑了我的问题。不幸的是,还没有解决它。【参考方案2】:好吧,我终于想通了。顶点着色器内的属性位置在 Mac OS X 上被切换。幸运的是,它在屏幕上渲染了一些东西,使用 texcoords 作为顶点位置,反之亦然。
我本可以使用glBindAttribLocation
来修复它,但我将着色器更新到版本 330 并使用了layout(location = 0)
属性。这也很好用。
【讨论】:
以上是关于Mac OS X 上的 OpenGL 纹理损坏的主要内容,如果未能解决你的问题,请参考以下文章