0%

OpenGL二次渲染与BlitFramebuffer的区别

上一篇中我们介绍了如何自己创建一个渲染线程,并在该线程上构建EGL环境,本文我们分别介绍一下在渲染线程中如何通过二次渲染法进行离屏渲染以及如何通过BlitFramebuffer实现离屏渲染。

二次渲染的实现

首先我们来看一下如何通过二次渲染法实现离屏渲染。

每当我们收到新的视频帧时,都会调用doFrame()方法进行渲染,其代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private void doFrame() {
...
//使用OpenGL绘制模型
draw();
//将绘制好的结果输出到屏幕上
swapResult = mWindowSurface.swapBuffers();

...
//切换Surface,将其切到MediaCodec的Surface上
mInputWindowSurface.makeCurrent();
...
//第二次使用OpenGL绘制模型
draw();
...
//将绘制好的结果输出给编码器
mInputWindowSurface.swapBuffers();
...
//再次切换Surface,将其切到SurfaceView的Surface上
mWindowSurface.makeCurrent();
...
}

上述代码的逻辑非常清晰,首先调用draw()方法通过OpenGL绘制模型,然后调用swapBuffers()方法将draw()绘制好的结果输出到屏幕上(注意,默认情况下使用的是SurfaceView的Surface)。

接下来调用makeCurrent()方法将当前Surface切到MediaCodec的Surface上,再次调用draw()方法绘制模型。当模型绘制好后,调用mInputWindowSurface.swapBuffers()方法将结果输出绘MediaCodec进行编码。

最后,调用mWindowSurface.makeCurrent()方法将Surface恢复为SurfaceView的Surface为下一帧的绘制作好准备。

以上就是通过二次渲染法进行离屏渲染的具体做法。下面我们再来看看如何通过BlitFramebuffer实现离屏渲染。

BlitFramebuffer

通过BlitFramebuffer实现离屏渲染的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private void doFrame() {
...
//使用OpenGL绘制模型
draw();
//将写入的Surface切换为MediaCodec的Surface,而将读取的Surface设置为SurfaceView的Surface
mInputWindowSurface.makeCurrentReadFrom(mWindowSurface);
...
//从SurfaceView的Surface读数据,写入到MediaCodec的Surface中
GLES30.glBlitFramebuffer(
0, 0, mWindowSurface.getWidth(), mWindowSurface.getHeight(),
mVideoRect.left, mVideoRect.top, mVideoRect.right, mVideoRect.bottom,
GLES30.GL_COLOR_BUFFER_BIT, GLES30.GL_NEAREST);
...
//将MediaCodec Surface中的内容送编码器编码
mInputWindowSurface.swapBuffers();

//将当前Surface切回SurfaceView的Surface
mWindowSurface.makeCurrent();
//将SurfaceView Surface中的内容送屏幕显示
swapResult = mWindowSurface.swapBuffers();
...
}

从代码中我们可以看到,一开始它也是调用draw()方法渲染模型,但接下来并没有直接将渲染后的结果输出到屏幕上,而是调用了mInputWindowSurface.makeCurrentReadFrom(mWindowSurface)方法来切换Surface。需要注意的是,makeCurrentReadFrom()方法与makeCurrent()方法不同,makeCurrent()方法会将读取的Surface和写入的Surface同时切换成同一个Surface,而makeCurrentReadFrom()方法可以让读取与写入的Surface不同。在这个例子中,它将写入的Surface换成了MediaCodec的Surface,而将读取的Surface的是成了SurfaceView的Surface,其含义就是从SurfaceView的Surface中读数据写到MediaCodec的Surface中。

当设置好Surface后,就调用glBlitFramebuffer方法完成具体的拷贝工作。之后调用mWindowSurface.makeCurrent()方法先将Surface中的内容送编码器进行编码,然后调用mWindowSurface.makeCurrent()方法将当前Surface切回到SurfaceView的Surface上,最后调用mWindowSurface.swapBuffers()方法将渲染结果显示到屏幕上。

小结

本文我向你分别讲述了二次渲染和BlitFramebuffer两种不同的离屏渲染技术对渲染结果进行屏幕展示和编码的过程。

这两种方法实现起来都比较简单,只要我们熟悉EGL环境,知道如何切换Surface,那么对上面的内容都可以轻松理解。

参考资料

系统玩转OpenGL+AI,实现各种酷炫视频特效

欢迎关注我的其它发布渠道