使用 VBO 和 CPU 使用率非常高
Posted
技术标签:
【中文标题】使用 VBO 和 CPU 使用率非常高【英文标题】:Using VBO's and CPU usage is very high 【发布时间】:2010-06-28 16:05:05 【问题描述】:我真的不知道该怎么办了。我已经让我的应用程序使用 VBO,而我的 cpu 使用率仍然进入 70 年代和 80 年代。我的渲染过程是这样的:
设置相机变换 如果形状尚未被细分,则对其进行细分。 创建它的 VBO 如果它有 VBO,请使用它。
你会注意到我也有显示列表,如果不支持 VBO,我可能会使用这些。我去找了一个 OpenGL 演示,它可以在我的 PC 上以 60fps 的速度渲染一个 32000 多边形网格,并使用 4% 的 cpu。我正在使用 vbos 以 60fps 的速度渲染大约 10,000 个多边形,并且使用 70-80%。
这是我的渲染过程:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
POINT hh = controls.MainGlFrame.GetMousePos();
POINTFLOAT S;
S.x = static_cast<float>(hh.x);
S.y = static_cast<float>(hh.y);
POINTFLOAT t;
t.x = 256;
t.y = 256;
POINT dimensions;
dimensions.x = 512;
dimensions.y = 512;
glDeleteTextures(1,&texName);
texName = functions.CreateGradient(col,t,S,512,512,true);
itt = true;
HDC hdc;
PAINTSTRUCT ps;
glEnable(GL_MULTISAMPLE_ARB);
glEnable(GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
hdc = BeginPaint(controls.MainGlContext.mhWnd,&ps);
//start OGL code
glClearColor( 1.0f, 1.0f, 1.0f, 0.0f );
if(!current.isdrawing)
glClear( GL_COLOR_BUFFER_BIT );
glPushMatrix();
glTranslatef(controls.MainGlFrame.GetCameraX(),
controls.MainGlFrame.GetCameraY(),0);
//glTranslatef(current.ScalePoint.x,current.ScalePoint.y,0);
glScalef(current.ScaleFactor,current.ScaleFactor,current.ScaleFactor);
//glTranslatef(-current.ScalePoint.x,-current.ScalePoint.y,0);
if(!current.isdrawing)
for(unsigned int currentlayer = 0; currentlayer < layer.size(); ++currentlayer)
PolygonTesselator.Init();
for(unsigned int i = 0; i < layer[currentlayer].Shapes.size(); i++)
if(layer[currentlayer].Shapes[i].DisplayListInt == -999)
gluTessNormal(PolygonTesselator.tobj, 0, 0, 1);
PolygonTesselator.Set_Winding_Rule(layer[currentlayer].Shapes[i].WindingRule);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texName);
layer[currentlayer].Shapes[i].DisplayListInt = glGenLists(1);
glNewList(layer[currentlayer].Shapes[i].DisplayListInt,GL_COMPILE);
PolygonTesselator.SetDimensions(layer[currentlayer].Shapes[i].Dimensions,layer[currentlayer].Shapes[i].minima);
PolygonTesselator.Begin_Polygon();
for(unsigned int c = 0; c < layer[currentlayer].Shapes[i].Contour.size(); ++c)
if(layer[currentlayer].Shapes[i].Color.a != 0)
PolygonTesselator.Begin_Contour();
for(unsigned int j = 0; j < layer[currentlayer].Shapes[i].Contour[c].DrawingPoints.size(); ++j)
gluTessVertex(PolygonTesselator.tobj,&layer[currentlayer].Shapes[i].Contour[c].DrawingPoints[j][0],
&layer[currentlayer].Shapes[i].Contour[c].DrawingPoints[j][0]);
PolygonTesselator.End_Contour();
PolygonTesselator.End_Polygon();
glEndList();
PolygonTesselator.TransferVerticies(layer[currentlayer].Shapes[i].OutPoints);
glGenBuffersARB(1,&layer[currentlayer].Shapes[i].VBOInt);
glBindBufferARB(GL_ARRAY_BUFFER_ARB,layer[currentlayer].Shapes[i].VBOInt);
glBufferDataARB(GL_ARRAY_BUFFER_ARB,sizeof(GLfloat) * layer[currentlayer].Shapes[i].OutPoints.size(),
&layer[currentlayer].Shapes[i].OutPoints[0], GL_STATIC_DRAW_ARB);
InvalidateRect(controls.MainGlFrame.framehWnd,NULL,false);
else //run vbo
//glEnable(GL_TEXTURE_2D);
//glDisable(GL_TEXTURE_2D);
//glBindTexture(GL_TEXTURE_2D, texName);
glColor4f(layer[currentlayer].Shapes[i].Color.r,
layer[currentlayer].Shapes[i].Color.g,
layer[currentlayer].Shapes[i].Color.b,
layer[currentlayer].Shapes[i].Color.a);
//glColor4f(1,1,1,1);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, layer[currentlayer].Shapes[i].VBOInt);
//glCallList(layer[currentlayer].Shapes[i].DisplayListInt);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, layer[currentlayer].Shapes[i].OutPoints.size() / 2);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glDisable(GL_TEXTURE_2D);
//Draw outlines
if(layer[currentlayer].Shapes[i].Outline.OutlinePoints.size() > 4)
glColor4f(layer[currentlayer].Shapes[i].Outline.OutlineColor.r
,layer[currentlayer].Shapes[i].Outline.OutlineColor.g
,layer[currentlayer].Shapes[i].Outline.OutlineColor.b
,layer[currentlayer].Shapes[i].Outline.OutlineColor.a);
PolygonTesselator.End();
glPopMatrix();
//end OGL code
glFlush();
SwapBuffers(hdc);
glDisable(GL_MULTISAMPLE_ARB);
EndPaint(controls.MainGlContext.mhWnd,&ps);
为什么我的 CPU 使用率会这么高?
【问题讨论】:
获取分析器。它将立即回答您的问题。 vtune 可供试用:通过调用图抽样测试进行尝试,您将确切地看到 CPU 时间花费在哪里。 上面的代码sn-p已经被剪掉了。您可以编辑您的问题以包含缺少的代码(或至少描述那里的内容)吗?特别是,有一个
大约 18 行;是接近if
吗?一个循环?还有什么?
【参考方案1】:
第一段代码在什么条件下运行?里面有几行看起来很可疑:
glDeleteTextures(1,&texName);
texName = functions.CreateGradient(col,t,S,512,512,true);
如果您在每次绘画时都删除并重新创建纹理,那可能会很昂贵。我不能说 OpenGL 部件会有多昂贵——我希望上传纹理数据相当有效,即使删除和创建纹理名称可能不那么有效——但也许 CreateGradient
本身就很慢。或者,也许您不小心为您的显卡遇到了某种缓慢的路径。或者该函数正在创建所有 mipmap 级别。以此类推。
除此之外,还有一些随机的想法:
当前间隔是多少?如果缓冲区交换设置为与监视器同步,您可能会因此而产生延迟。 (您可以使用 WGL_EXT_swap_control 扩展来调整此值。)
如果所有这些都是为了响应 WM_PAINT 而运行的,请检查您是否因为某种原因没有收到意外的额外 WM_PAINT。
检查多边形 tesselator Init
和 End
函数没有做任何事情,因为它们每次都被调用,即使没有要进行的镶嵌。
【讨论】:
纹理只是一个测试,只运行一次。我修复了初始化和结束问题,我已经在使用 wgl_ext_swap_control,当我滚动时它会进行 wm 绘制。使用 2-3 个多边形,它的速度非常快,但添加更多多边形会成倍地慢,而且 NeHe 使用 2-3% 的 cpu 渲染 32k 多边形@60fps 所以我很困惑【参考方案2】:根据您提供的代码 sn-p,您(在某一时刻)有四层深度嵌套的循环。由于运行这些循环中的每一个的次数非常多,您可能会看到高 CPU 负载。你能告诉我们这些循环需要经过多少次迭代吗?
尝试在每次循环迭代中获取时间戳,并将其与之前的进行比较,以查看运行每个特定循环的一次迭代需要多长时间。这应该可以帮助您确定函数的哪一部分占用了大部分 CPU 时间。
【讨论】:
好吧,我删除了所有这些循环,仅清除和交换就可以让我达到大约 30%。 添加 Sleep(1) 解决了 SwapBuffers 问题,但形状仍然是瓶颈 您尝试使用多少种形状?如果调整形状的数量会发生什么? CPU 使用率是否随形状的数量而变化? 它保持在 3-4% 左右,然后突然跃升至 30%,并且在大约 15 个形状之后再也不会回头。作为测试,我创建了 1 个大的 30,000 三角形,它滞后了很多,但 NeHe 得到了 32000 没有滞后。可能是因为这些是 2D 形状而我没有使用深度测试? 我建议计时运行第二个循环的一次迭代(循环遍历当前层中的所有形状)所需的时间。看看时间如何在 5/10/15/20 形状之间变化。当您看到 CPU 使用率达到峰值时,开始缩小范围,查看代码的循环和计时部分,看看哪个部分运行时间最长。以上是关于使用 VBO 和 CPU 使用率非常高的主要内容,如果未能解决你的问题,请参考以下文章
最简单的动画会导致高 CPU 使用率和非常高的能量影响 SpriteKit
最简单的动画导致高CPU使用率和非常高的能量影响SpriteKit
在 R 中使用 doParallel 的 foreach 时,Windows Defender 的 CPU 使用率非常高