我主要使用SDL2和OpenGL 3.3在Linux(Mint)和Windows上进行开发,几乎没有关于绘图对象的问题。 CPU使用量从未超过~40%。
那就是,直到我尝试将我所拥有的东西移植到OSX(Sierra)。 利用在Linux和Windows上运行的完全相同的着色器和代码,可以将OSX上的CPU使用率持续增加到99%。
起初,我认为这是一个批处理问题,所以我将我的绘制调用一起批处理,以最大限度地减少对glDrawElements的调用次数,但这并没有用。
然后,我认为这是一个涉及不在顶点/片段着色器中使用属性的问题(如:OpenGL core profile incredible slowdown on OS X)
另外,我保持帧速率为60 fps。
排序后,没有运气。尝试记录我能做的一切,glGetError()和着色器日志都没有。
因此,我从顶点/片段着色器中删除了一些碎片,以查看特别是减慢绘制调用的速度。我设法将其简化为:在我的顶点/片段着色器中对texture()函数的任何调用都将使cpu运行到高使用率。
纹理加载代码:
// Texture loading
void PCShaderSurface::AddTexturePairing(HashString const &aName)
{
GLint minFilter = GL_LINEAR;
GLint magFilter = GL_LINEAR;
GLint wrapS = GL_REPEAT;
GLint wrapT = GL_REPEAT;
if(Constants::GetString("OpenGLMinFilter") == "GL_NEAREST")
{
minFilter = GL_NEAREST;
}
if(Constants::GetString("OpenGLMagFilter") == "GL_NEAREST")
{
magFilter = GL_NEAREST;
}
if(Constants::GetString("OpenGLWrapModeS") == "GL_CLAMP_TO_EDGE")
{
wrapS = GL_CLAMP_TO_EDGE;
}
if(Constants::GetString("OpenGLWrapModeT") == "GL_CLAMP_TO_EDGE")
{
wrapT = GL_CLAMP_TO_EDGE;
}
glGenTextures(1, &mTextureID);
glBindTexture(GL_TEXTURE_2D, mTextureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mSurface->w, mSurface->h, 0, mTextureFormat, GL_UNSIGNED_BYTE, mSurface->pixels);
GetManager()->AddTexturePairing(aName, TextureData(mTextureID, mSurface->w, mSurface->h));
}
绘制代码:
// I batch objects that use the same program and texture id to draw in the same call.
glUseProgram(program);
int activeTexture = texture % mMaxTextures;
int vertexPosLocation = glGetAttribLocation(program, "vertexPos");
int texCoordPosLocation = glGetAttribLocation(program, "texCoord");
int objectPosLocation = glGetAttribLocation(program, "objectPos");
int colorPosLocation = glGetAttribLocation(program, "primaryColor");
// Calculate matrices and push vertex, color, position, texCoord data
// ...
// Enable textures and set uniforms.
glBindVertexArray(mVertexArrayObjectID);
glActiveTexture(GL_TEXTURE0 + activeTexture);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(glGetUniformLocation(program, "textureUnit"), activeTexture);
glUniform3f(glGetUniformLocation(program, "cameraDiff"), cameraTranslation.x, cameraTranslation.y, cameraTranslation.z);
glUniform3f(glGetUniformLocation(program, "cameraSize"), cameraSize.x, cameraSize.y, cameraSize.z);
glUniformMatrix3fv(glGetUniformLocation(program, "cameraTransform"), 1, GL_TRUE, cameraMatrix);
// Set shader properties. Due to batching, done on a per surface / shader basis.
// Shader uniforms are reset upon relinking.
SetShaderProperties(surface, true);
// Set VBO and buffer data.
glBindVertexArray(mVertexArrayObjectID);
BindAttributeV3(GL_ARRAY_BUFFER, mVertexBufferID, vertexPosLocation, vertexData);
BindAttributeV3(GL_ARRAY_BUFFER, mTextureBufferID, texCoordPosLocation, textureData);
BindAttributeV3(GL_ARRAY_BUFFER, mPositionBufferID, objectPosLocation, positionData);
BindAttributeV4(GL_ARRAY_BUFFER, mColorBufferID, colorPosLocation, colorData);
// Set index data
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), &indices[0], GL_DYNAMIC_DRAW);
// Draw and disable
glDrawElements(GL_TRIANGLES, static_cast<unsigned>(vertexData.size()), GL_UNSIGNED_INT, 0);
DisableVertexAttribArray(vertexPosLocation);
DisableVertexAttribArray(texCoordPosLocation);
DisableVertexAttribArray(objectPosLocation);
DisableVertexAttribArray(colorPosLocation);
// Reset shader property values.
SetShaderProperties(surface, false);
// Reset to default texture
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glUseProgram(0);
示例绑定代码:
void PCShaderScreen::BindAttributeV3(GLenum aTarget, int const aBufferID, int const aAttributeLocation, std::vector<Vector3> &aData)
{
if(aAttributeLocation != -1)
{
glEnableVertexAttribArray(aAttributeLocation);
glBindBuffer(aTarget, aBufferID);
glBufferData(aTarget, sizeof(Vector3) * aData.size(), &aData[0], GL_DYNAMIC_DRAW);
glVertexAttribPointer(aAttributeLocation, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3), 0);
glBindBuffer(aTarget, 0);
}
}
VS代码:
#version 330
in vec4 vertexPos;
in vec4 texCoord;
in vec4 objectPos;
in vec4 primaryColor;
uniform vec3 cameraDiff;
uniform vec3 cameraSize;
uniform mat3 cameraTransform;
out vec2 texValues;
out vec4 texColor;
void main()
{
texColor = primaryColor;
texValues = texCoord.xy;
vec3 vertex = vertexPos.xyz + objectPos.xyz;
vertex = (cameraTransform * vertex) - cameraDiff;
vertex.x /= cameraSize.x;
vertex.y /= -cameraSize.y;
vertex.y += 1.0;
vertex.x -= 1.0;
gl_Position.xyz = vertex;
gl_Position.w = 1.0;
}
FS代码:
#version 330
uniform sampler2D textureUnit;
in vec2 texValues;
in vec4 texColor;
out vec4 fragColor;
void main()
{
// Slow, 99% CPU usage on OSX only
fragColor = texture(textureUnit, texValues) * texColor;
// Fine on everything
fragColor = vec4(1,1,1,1);
}
我真的没有想法,我甚至尽可能地遵循Apple的最佳做法(https://developer.apple.com/library/content/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_texturedata/opengl_texturedata.html),没有运气。
我使用的Windows和Linux驱动程序是否只是向我提供了一些我不知道的宽恕形式? OSX驱动程序真的那么敏感吗?我肯定错过了什么。任何帮助和见解将不胜感激。感谢您阅读我冗长的演讲。
答案 0 :(得分:1)
所有归功于@keltar找到这个,但我的问题出在glActiveTexture调用中。
我将调用从glActiveTexture(GL_TEXTURE0 + activeTexture)更改为glActiveTexture(GL_TEXTURE0)。
解释@keltar:&#34;不断更改纹理槽号可能会强制驱动程序每次重新编译着色器。我不认为只要它没有变化(并且在GL限制范围内),它将具有多大的确切价值。我认为你使用的硬件可以有效地(或者根本)从均匀变量指定的任何槽中对纹理进行采样 - 但GL意味着这样。在某些硬件上获取顶点属性也是着色器的内部部分。当状态发生变化时,驱动程序会尝试修补着色器,但如果更改太大(或者驱动程序不知道如何修补) - 则会重新编译。可悲的是,据我所知,OSX显卡驱动程序并不是很好。&#34;
答案 1 :(得分:0)
你在绘图代码中做了很多gl调用:绑定缓冲区,将数据上传到缓冲区等。在准备或上传数据时,大多数都会更好。
我更喜欢在绘图代码中执行:
glBindVertexArray
glActiveTexture