OpenGL ES中的offscreen rendering与iOS中的offscreening rendering
离屏渲染的概念
OpenGL 中,GPU 屏幕渲染有以下两种方式:
• On-Screen Rendering 意为当前屏幕渲染,指的是 GPU 的渲染操作是在当前用于显示的屏幕缓冲区中进行。
• Off-Screen Rendering 意为离屏渲染,指的是 GPU 在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作。
相比于当前屏幕渲染,离屏渲染的代价是很高的,主要体现在两个方面:
• 创建新缓冲区 要想进行离屏渲染,首先要创建一个新的缓冲区。
• 上下文切换 离屏渲染的整个过程,需要多次切换上下文环境:先是从当前屏幕(On-Screen)切换到离屏(Off-Screen);等到离屏渲染结束以后,将离屏缓冲区的渲染结果显示到屏幕上有需要将上下文环境从离屏切换到当前屏幕。而上下文环境的切换是要付出很大代价的。
问题1,为什么需要离屏渲染?
Swapping is useful when making multiple changes to a rendered image, such as switching color, depth, or stencil attachments. The recommendation is to use dedicated FBOs for each set in use, rather than sharing an FBO among all attachments. Switching an entire FBO is more efficient than switching individual surfaces one at a time.
Many of today’s visual effects in modern graphic games require multiple passes to render. For example, shadowing requires at least two passes: the first pass creates the shadow data (map or volume), and the second one uses that data in the scene. An additional pass is required if you want post-processing effects like screen space ambient occlusion. Add in effects like blurring and the number of passes continues to increase.
翻译一下就是多个framerbuffer通过swapbuffer会比只使用一个frambuffer然后更换attachment处理更有效率。
有一篇文章www.songho.ca/opengl/gl_f… 里面提到了Framebuffer object (FBO) provides an efficient switching mechanism; detach the previous framebuffer-attachable image from a FBO, and attach a new framebuffer-attachable image to the FBO. Switching framebuffer-attachable images is much faster than switching between FBOs. FBO provides glFramebufferTexture2D() to switch 2D texture objects, and glFramebufferRenderbuffer() to switch renderbuffer objects.
这句话是完全错误的。
不幸的是这篇文章流传非常广。
如果想更深入了解可以看reddit的这篇讨论。https://www.reddit.com/r/opengl/comments/1rsnhy/most_efficient_fbo_usage_in_multipass_pipeline/
问题2:Open GL如何切换offscreen framebuffer和onscreen framebuffer?
实际上OpenGL里切换framebuffer异常简单。
比如。
glBindFramebuffer( GL_FRAMEBUFFER, fb1 );
// pass 1
glBindFramebuffer( GL_FRAMEBUFFER, fb2 );
// pass 2fb1 和 fb2是两个之前生成的framebuffer。切换framebuffer就是重新执行bind操作。
我从这里完全看不出切换上下文有什么性能损耗。
问题3: 切换上下文到底是不是导致性能损耗的原因?
我在stackoverflow看到了一篇比较有意思的说法。
https://stackoverflow.com/questions/6731545/when-does-a-view-or-layer-require-offscreen-rendering
117
down vote
accepted
+50
I don't think there is a rule written down anywhere, but hopefully this will help:
First, let's clear up some definitions. I think offscreen vs onscreen rendering is not the overriding concern most of the time, because offscreen rendering can be as fast as onscreen. The main issue is whether the rendering is done in hardware or software.
There is also very little practical difference between using layers and views. Views are just a thin wrapper around CALayer and they don't introduce a significant performance penalty most of the time. You can override the type of layer used by a view using the +layerClass method if you want to have a view backed by a CAShapeLayer or CATileLayer, etc.
Generally, on iOS, pixel effects and Quartz / Core Graphics drawing are not hardware accelerated, and most other things are.
The following things are not hardware accelerated, which means that they need to be done in software (offscreen):
1 Anything done in a drawRect. If your view has a drawRect, even an empty one, the drawing is not done in hardware, and there is a performance penalty.
2 Any layer with the shouldRasterize property set to YES.
3 Any layer with a mask or drop shadow.
4 Text (any kind, including UILabels, CATextLayers, Core Text, etc).
5 Any drawing you do yourself (either onscreen or offscreen) using a CGContext.
Most other things are hardware accelerated, so they are much faster. However, this may not mean what you think it does.
Any of the above types of drawing are slow compared to hardware accelerated drawing, however they don't necessarily slow down your app because they don't need to happen every frame. For example, drawing a drop shadow on a view is slow the first time, but after it is drawn it is cached, and is only redrawn if the view changes size or shape.
The same goes for rasterised views or views with a custom drawRect: the view typically isn't redrawn every frame, it is drawn once and then cached, so the performance after the view is first set up is no worse, unless the bounds change or you call setNeedsDisplay on it.
For good performance, the trick is to avoid using software drawing for views that change every frame. For example, if you need an animated vector shape you'll get better performance using CAShapeLayer or OpenGL than drawRect and Core Graphics. But if you draw a shape once and then don't need to change it, it won't make much difference.
Similarly, don't put a drop shadow on an animated view because it will slow down your frame rate. But a shadow on a view that doesn't change from frame to frame won't have much negative impact.
Another thing to watch out for is slowing down the view setup time. For example, suppose you have a page of text with drop shadows on all the text; this will take a very long time to draw initially since both the text and shadows all need to be rendered in software, but once drawn it will be fast. You will therefore want to set up this view in advance when your application loads, and keep a copy of it in memory so that the user doesn't have to wait ages for the view to display when it first appears on screen.
This is probably the reason for the apparent contradiction in the WWDC videos. For large, complex views that don't change every frame, drawing them once in software (after which they are cached and don't need to be redrawn) will yield better performance than having the hardware re-composite them every frame, even though it will be slower to draw the first time.
But for views that must be redrawn constantly, like table cells (the cells are recycled so they must be redrawn each time one cell scrolls offscreen and is re-used as it scrolls back onto the other side as a different row), software drawing may slow things down a lot.
这个作者认为导致性能低下的原因并不是因为离屏渲染,因为offscreen 和 onscreen 几乎一样快。
重要的是,在渲染的时候是否使用了硬件加速。
其他的原因可以看回答。
这篇文章抛砖引玉,希望大家提出问题和想法。