OpenGL显示函数中使用static变量的性能顾虑及与全局变量的对比
关于OpenGL渲染函数中static变量与全局变量的性能疑问
我正在学习OpenGL 4,目前阅读电子书《Computer Graphics Programming in OpenGL with C++ Second Edition》。书中提到,在处理绘图操作的display函数中,应避免实例化对象或声明变量以最大化性能、减少开销,因此此前一直将display函数中用到的变量声明为全局变量,以此避免局部内存分配。
我选择在display函数中使用static变量,示例代码如下:
void display(GLFWwindow* window, double currentTime) { static float cameraX = 0.0f, cameraY = 0.0f, cameraZ = 20.0f; // <-- statically assigned glm::mat4 mMat, vMat, pMat, mvMat; int width, height; std::stack<glm::mat4> mvStack; glfwGetFramebufferSize(window, &width, &height); float aspect = static_cast<float>(width) / static_cast<float>(height); glClear(GL_DEPTH_BUFFER_BIT); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glUseProgram(renderingProgram); GLuint mvLoc = glGetUniformLocation(renderingProgram, "mv_matrix"); GLuint pLoc = glGetUniformLocation(renderingProgram, "p_matrix"); pMat = glm::perspective(1.0472f, aspect, 0.1f, 1000.0f); vMat = glm::translate( glm::mat4(1.0f), glm::vec3(-cameraX, -cameraY, -cameraZ) ); mvStack.push(vMat); glUniformMatrix4fv(pLoc, 1, GL_FALSE, glm::value_ptr(pMat)); mvStack.push(mvStack.top()); mvStack.top() *= glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f)); mvStack.push(mvStack.top()); mvStack.top() *= glm::rotate(glm::mat4(1.0f), static_cast<float>(currentTime), glm::vec3(1.0f, 0.0f, 0.0f)); glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvStack.top())); glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(0); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glDrawArrays(GL_TRIANGLES, 0, 18); mvStack.pop(); mvStack.push(mvStack.top()); mvStack.top() *= glm::translate(glm::mat4(1.0f), glm::vec3( sin(static_cast<float>(currentTime)) * 4.0f, 0.0f, cos(static_cast<float>(currentTime)) * 4.0f )); mvStack.push(mvStack.top()); mvStack.top() *= glm::rotate(glm::mat4(1.0f), static_cast<float>(currentTime), glm::vec3(0.0f, 1.0f, 0.0f)); glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvStack.top())); glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLES, 0, 36); mvStack.pop(); mvStack.push(mvStack.top()); mvStack.top() *= glm::translate(glm::mat4(1.0f), glm::vec3( 0.0f, sin(static_cast<float>(currentTime) * 0.5) * 2.0f, cos(static_cast<float>(currentTime) * 0.5) * 2.0f )); mvStack.push(mvStack.top()); mvStack.top() *= glm::rotate(glm::mat4(1.0f), static_cast<float>(currentTime), glm::vec3(-1.0f, 0.0f, 0.0f)); mvStack.push(mvStack.top()); mvStack.top() *= glm::scale(glm::mat4(1.0f), glm::vec3(0.25f)); glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvStack.top())); glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLES, 0, 36); mvStack.pop(); mvStack.pop(); mvStack.pop(); mvStack.pop(); }
我理解static变量在函数中仅初始化一次,在函数作用域内保持其值。我认为它仅分配和赋值一次,内存地址与值保持不变,除了函数第一次调用时的实例化外,不会有太多性能问题。
请问需要注意哪些性能顾虑?全局变量在性能方面是否是更好的选择?
解答
一、static变量的性能注意点
- 初始化的线程安全开销:C++11及以后,函数内static变量的初始化是线程安全的,编译器会插入同步检查代码(比如锁)确保只初始化一次。单线程渲染场景下这点开销可以忽略,但多线程环境中第一次调用的同步操作会有细微性能影响。
- 缓存友好性:static变量存放在全局/静态存储区,和全局变量的内存区域一致,缓存行为没有本质区别。除非多个函数的static变量在内存中分散布局,才可能影响缓存命中率,但普通渲染流程中感知不到这种差异。
- 不可重入风险:如果display函数存在多线程调用场景(尽管OpenGL通常是单线程上下文,但部分框架可能有特殊情况),static变量会成为共享状态,引发数据竞争——这是正确性问题,而非纯性能问题,但必须重视。
二、全局变量vs static变量的性能对比
从纯性能角度看,两者几乎没有差异:
- 内存分配:两者都在程序加载阶段完成内存分配(static变量的初始化是第一次访问时执行,但内存空间提前预留),运行时都不需要栈上分配,也没有重复的构造/析构开销。
- 访问速度:都是直接内存访问,现代编译器对栈变量的优化已经非常成熟,即便和栈变量比,全局/静态变量的访问速度优势也微乎其微。
全局变量唯一的“性能优势”是避免了static变量第一次初始化的同步锁,但仅在多线程环境下有意义;而static变量的优势是作用域局限在函数内,不污染全局命名空间,代码更易维护。
三、代码中的额外性能优化建议
- 你代码中的
std::stack<glm::mat4> mvStack是局部变量,每次调用都会构造和析构,可以改为static std::stack<glm::mat4> mvStack;,每次调用前用mvStack.clear()清空,避免重复的容器构造和内存分配开销。 glGetUniformLocation可以提前在初始化阶段获取,而非每次display调用都执行——这个函数的开销远大于变量分配,是更值得优先优化的点。
内容的提问来源于stack exchange,提问作者Edward Severinsen
相关产品推荐
相关产品推荐

