Opengl - "fullscreen"纹理渲染性能问题



我正在用OpenGL编写一个2D游戏,我遇到了一些性能问题,同时呈现覆盖整个窗口的几个纹理。

我实际上是创建一个带有屏幕大小的纹理,使用FBO将我的场景渲染到该纹理上,然后用不同的偏移来渲染几次纹理,以使某种"阴影"进行。但是当我这样做时,我在使用集成视频卡时会降低性能。

因此,总的来说,我将7个四元组渲染到整个屏幕上(背景图像,5个带有黑色"色彩"的"阴影图像",以及具有真实颜色的相同纹理)。我正在使用尺寸为1024x1024的RGBA纹理,并将其安装在900x700窗口中。当我不呈现纹理时,我会得到200 fps,而当我这样做时,我会得到34 fps(在这两种情况下,我实际上创建纹理并将场景渲染到它上)。我觉得这很奇怪,因为我本质上只渲染了7个四边形。一个奇怪的事情也是,当我运行CPU参考器时,这并不意味着这是瓶颈(我知道OpenGL使用管道架构,这可能会发生,但是在大多数情况下,它没有)。

当我使用外部视频卡时,我在上述测试时会获得一致的200 fps。但是,当我禁用场景时,呈现到纹理上并禁用呈现到屏幕上的纹理时,我会得到约1000 fps。这仅发生在我的外部视频卡上 - 当我使用集成的fbo禁用FBO时,我得到的200 fps。这确实使我感到困惑。

任何人都可以解释发生了什么,如果上述数字听起来正确吗?

集成视频卡 - 英特尔高清图形4000

外部视频卡-NVIDIA GEFORCE GTX 660M

P.S。我在C#上写游戏 - 因此,如果有任何帮助,我会使用Opentk。

编辑:

首先要感谢所有响应 - 它们在某种程度上都非常有帮助,但不幸的是,我认为它不仅仅是"简化/优化您的代码"。让我分享一些渲染代码:

//fields defined when the program is initialized
Rectangle viewport;
//Texture with the size of the viewport
Texture fboTexture;
FBO fbo;
//called every frame
public void Render()
{
    //bind the texture to the fbo
    GL.BindFramebuffer(FramebufferTarget.Framebuffer, fbo.handle);
    GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, fboTexture,
       TextureTarget.Texture2D, texture.TextureID, level: 0);
    //Begin rendering in Ortho 2D space
    GL.MatrixMode(MatrixMode.Projection);
    GL.PushMatrix();
    GL.LoadIdentity();
    GL.Ortho(viewport.Left, viewport.Right, viewport.Top, viewport.Bottom, -1.0, 1.0);
    GL.MatrixMode(MatrixMode.Modelview);
    GL.PushMatrix();
    GL.LoadIdentity();
    GL.PushAttrib(AttribMask.ViewportBit);
    GL.Viewport(viewport);
    //Render the scene - this is really simple I render some quads using shaders
    RenderScene();
    //Back to Perspective
    GL.PopAttrib(); // pop viewport
    GL.MatrixMode(MatrixMode.Projection);
    GL.PopMatrix();
    GL.MatrixMode(MatrixMode.Modelview);
    GL.PopMatrix();
    //Detach the texture
    GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, fboTexture, 0,
                    0, level: 0);
    //Unbind the fbo
    GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
    GL.PushMatrix();
    GL.Color4(Color.Black.WithAlpha(128)); //Sets the color to (0,0,0,128) in a RGBA format
    for (int i = 0; i < 5; i++)
    {
        GL.Translate(-1, -1, 0);
        //Simple Draw method which binds the texture and draws a quad at (0;0) with
        //its size
        fboTexture.Draw();
    }
    GL.PopMatrix();
    GL.Color4(Color.White);
    fboTexture.Draw();
}

所以我认为FBO实际上没有任何问题并呈现到纹理上,因为这并不是导致该程序在我的这两张卡上都放慢速度。以前,我正在初始化FBO的每一帧,这可能是我的NVIDIA卡放慢速度的原因,但是现在,当我将所有内容预先定位时,我都会在有没有FBO的情况下获得相同的FPS。

我认为问题通常不是纹理,因为如果我禁用纹理并呈现未纹理的四边形,我会得到相同的结果。而且我认为,我的集成卡在屏幕上仅渲染7个四倍时的运行速度也比40 fps快,即使它们覆盖了全部。

您能否给我一些有关如何实际介绍此内容并发布结果的提示?那真的很有用。

编辑2:

好吧,我进行了一些试验,并设法获得了更好的性能。首先,我尝试用着色器渲染最终的四边形 - 这对我预期的表现没有任何影响。

然后我试图运行一个剖面。但是我据我所知,Slimtune只是一名CPU分析器,它并没有给我带来我想要的结果。然后我尝试了gdebugger。它与Visual Studio具有集成,后来我发现它不支持.NET项目。我尝试运行外部版本,但它似乎不起作用(但也许我只是没有玩过它)。

真正解决问题的事情是,我首先使用FBO将它们渲染到屏幕上,而不是直接将7个四边形渲染到屏幕上,然后将最终纹理渲染到屏幕上。这使我的FPS从40到120。至少可以说,这似乎是一种古怪。为什么渲染效果比直接渲染到屏幕更快?尽管如此,感谢所有人的帮助 - 似乎我已经解决了问题。如果有人对情况进行合理的解释,我真的很感激。

显然这是一个猜测您的"影子"效果)。

我不知道您对这些概念的熟悉程度,对不起,如果我在这里有些冗长。

关于后处理

后处理是在屏幕上显示完整的场景,呈现为纹理并将效果应用于图像的过程。后处理的典型用途包括:

  • bloom-通过"出血"更自然地模拟亮度明亮的像素进入相邻的深色。

  • 高动态范围渲染 - 布鲁姆的老大哥。该场景呈现为浮点纹理,允许更大的颜色范围(与黑色的常规0相反,1幅亮度为1)。屏幕上显示的最终颜色是使用屏幕上所有像素的平均亮度计算的。所有这一切的效果是,相机的作用类似于人的眼睛 - 在黑暗的房间里,明亮的光线(例如,窗户)看起来非常明亮,但是一旦户外如果您直接凝视阳光,明亮。

  • cel Shading-修改颜色以产生类似卡通的外观。

  • 运动模糊

  • 野外深度 - 游戏中的相机近似于真实的摄像机(或您的眼睛),其中只有一定距离的对象是对聚焦的,其余的都是模糊的。

  • 推迟阴影 - 后处理的相当高级应用,在现场渲染后计算照明。这会花费大量视频RAM(通常使用几个全屏纹理),但可以迅速添加大量的灯光。

简而言之,您可以将后处理用于许多整洁的技巧。不幸的是...

后处理的成本

关于后处理的很酷的事情是,它的成本与场景的几何复杂性无关 - 无论您是绘制了一百万个三角形还是绘制了十几个,它将花费相同的时间。但是,这也是它的缺点。即使您只是一遍又一遍地渲染四边形进行后处理,但渲染每个像素的成本也是如此。如果要使用较大的质地,成本将更大。

专用的图形卡显然具有更多的计算资源来应用后处理,而集成卡通常具有更少的资源可以应用。出于这个原因,"低"视频游戏上的图形设置通常会禁用许多后处理效果。由于延迟发生在图形卡上,因此这不会在CPU剖面上显示为瓶颈。CPU正在等待图形卡在继续您的程序之前完成(或更准确地说,CPU在等待图形卡完成时正在运行另一个程序)。

您如何加快速度?

  • 使用较少的通行证。如果您将通行证减半,则将进行后处理所需的时间减半。为此,

  • 使用着色器。由于我没有看到您在任何地方提到它们,因此我不确定您是否正在使用着色器进行后处理。着色器本质上允许您以类似C的语言编写功能(由于您在OpenGL中,可以使用GLSL或CG),该功能在对象的每个渲染像素上都运行。他们可以采用您喜欢的任何参数,并且对于后处理非常有用。您将使用着色器设置为要绘制的四边形,然后可以插入要在场景的每个像素上运行的任何算法。

看到一些代码会很好。如果两者之间的唯一区别是使用外部GPU,则区别可能在内存管理中(即如何以及何时创建FBO等),因为将数据流到GPU可能会很慢。尝试移动任何创建任何形式的OpenGL缓冲区或将任何类型的数据发送给初始化的内容。我真的不能在不明确地做什么的情况下提供更多详细的建议。

它不仅仅是您渲染的四边形数量,我相信在您的情况下,这与填充您的视频卡的三角形有关。

如前所述,进行全屏后处理的常见方法是与着色器一起进行。如果您想要在集成卡上更好的性能并且不能使用着色器,则应简化渲染程序。

确保您确实需要α混合。在某些卡/驱动器上,使用Alpha频道渲染纹理可以大大降低性能。

减少全屏填充量的一种低质量的方法是首先对另一个较小的质地进行所有阴影绘制(例如256x256而不是1024x1024)。然后,您将带有该复合阴影纹理的四边形在缓冲区上。这样,您只需要6 256x256和一个1024x1024而不是7个1024x1024 Quads。但是您将输掉分辨率。

另一种技术,我不确定它是否可以在您的情况下使用,是预渲染复杂的背景,因此您必须在渲染循环中进行更少的绘画。

最新更新