GLSurfaceView、SurfaceView和SurfaceTexture,TextureView比较
SurfaceView
SurfaceTexture
SurfaceTexture不是直接显示的地方,而是转化成openGL的纹理。因此可以用来进行图像流数据的二次处理,比如Camera照相的滤镜功能。
比如Camera的预览数据,变成纹理后可以交给GLSurfaceView直接显示,也能够通过SurfaceTexture交给TextureView作为View heirachy中的1个硬件加速层来显示。
具体的流程是这样的:
SurfaceTexture首先获取帧数据,可以来源于Camera预览,视频解码,GL绘制场景等;然后调用SurfaceTexture里的updateTexImage()方法来更新openGL的纹理对象。这里的关键方法updateTexImage()
:
/**
* Update the texture image to the most recent frame from the image stream. This may only be
* called while the OpenGL ES context that owns the texture is current on the calling thread.
* It will implicitly bind its texture to the GL_TEXTURE_EXTERNAL_OES texture target.
*/
public void updateTexImage() {
nativeUpdateTexImage();
}
这个方法的主要作用就是从最近的帧中的图象流更新纹理数据。
更深的原理是:
SurfaceTexture管理着一个BufferQueue,它具体的包含2个部分:BufferQueueProducer和BufferQueueConsumer两块,BufferQueueProducer用于内容流的源输出数据,BufferQueueConsumer端用于拿GraphicBuffer并生成纹理。
SurfaceTexture.OnFrameAvailableListener用于让SurfaceTexture的使用者知道有新数据到来。JNISurfaceTextureContext是OnFrameAvailableListener从Native到Java的JNI跳板。其中SurfaceTexture中的attachToGLContext()和detachToGLContext()可让多个GL context同享同一个内容源。
public void attachToGLContext(int texName) {
int err = nativeAttachToGLContext(texName);
if (err != 0) {
throw new RuntimeException("Error during attachToGLContext (see logcat for details)");
}
}
这个是将SurfaceTexture附着到当前调用线程的openGL的上下文中,新的openGL纹理对象将会创建,并且和SurfaceTexture图像流一起扩展开来。This new texture is bound to the `GL_TEXTURE_EXTERNAL_OES
texture targe。
这个可以用来从不同的openGL上下文来访问SurfaceTexture图像流。
public void detachFromGLContext() {
int err = nativeDetachFromGLContext();
if (err != 0) {
throw new RuntimeException("Error during detachFromGLContext (see logcat for details)");
}
}
将SurfaceTexture从当前openGL上下文中的openGL纹理上剥离掉,openGL纹理也将被清除掉。这个方法被调用后,再去调用updateTexImage()
方法都将抛出异常。
关于BufferQueue的整个流程:
TextureView
GLSurfaceView
GLSurfaceView是继承自SurfaceView的,是作为SurfaceView的扩展。相比于SurfaceView,GLSurfaceView提供了自己的特性:
- 提供了GLThread(EGLContext创建GL环境所在线程即为GL线程),绘制的工作直接通过OpenGL来进行,绘制的内容默认情况下依旧是绘制到SurfaceView所提供的Surface上。这样就能较少主线程的绘制损耗。
主要用于3D??
看看如何使用吧:
就是一个通过在屏幕上互动来改变界面的颜色的功能。
public class InteractiveDemo extends AppCompatActivity {
private GLSurfaceView mGLView;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGLView = new DemoGLSurfaceView(this);
setContentView(mGLView);
}
public void onPause() {
super.onPause();
mGLView.onPause();
}
public void onResume() {
super.onResume();
mGLView.onResume();
}
}
class DemoGLSurfaceView extends GLSurfaceView {
DemoRenderer2 mRenderer;
public DemoGLSurfaceView(Context context) {
super(context);
//为了可以激活log和错误检查,帮助调试3D应用,需要调用setDebugFlags()。
this.setDebugFlags(DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS);
mRenderer = new DemoRenderer2();
this.setRenderer(mRenderer);
}
public boolean onTouchEvent(final MotionEvent event) {
//由于DemoRenderer2对象运行在另一个线程中,这里采用跨线程的机制进行处理。使用queueEvent方法
//当然也可以使用其他像Synchronized来进行UI线程和渲染线程进行通信。
this.queueEvent(new Runnable() {
@Override
public void run() {
mRenderer.setColor(event.getX() / getWidth(), event.getY() / getHeight(), 1.0f);
}
});
return true;
}
}
/**
* 这个应用在每一帧中清空屏幕,当tap屏幕时,改变屏幕的颜色。
*
* @author Administrator
*/
class DemoRenderer2 implements GLSurfaceView.Renderer {
private float mRed;
private float mGreen;
private float mBlue;
@Override
public void onDrawFrame(GL10 gl) {
// TODO Auto-generated method stub
gl.glClearColor(mRed, mGreen, mBlue, 1.0f);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
}
@Override
public void onSurfaceChanged(GL10 gl, int w, int h) {
// TODO Auto-generated method stub
gl.glViewport(0, 0, w, h);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// TODO Auto-generated method stub
}
public void setColor(float r, float g, float b) {
this.mRed = r;
this.mGreen = g;
this.mBlue = b;
}
}
原理分析
//渲染器接口
public interface Renderer {
//Surface被创建时被调用,通常在此进行渲染的初始化
void onSurfaceCreated(GL10 gl, EGLConfig config);
//Surface大小被改变时被调用
void onSurfaceChanged(GL10 gl, int width, int height);
//执行渲染时被调用,以完成用户渲染工作
void onDrawFrame(GL10 gl);
}
EglHelper
类是来创建EGLSurface的类。
GLThread
是主要的执行类。
//销毁EglSurface
private void stopEglSurfaceLocked();
//销毁EglContext
private void stopEglContextLocked();
//设置渲染方法,见GLSurfaceView的setRenderMode
public void setRenderMode(int renderMode);
public int getRenderMode();
//请求一次渲染
public void requestRender();
//请求一次渲染,并等待渲染完成
public void requestRenderAndWait();
//创建Surface
public void surfaceCreated();
//销毁Surface
public void surfaceDestroyed();
//Surface的大小被改变时调用
public void onWindowResize(int w, int h);
//请求退出渲染线程,并等待退出
public void requestExitAndWait();
//请求是否EglContext
public void requestReleaseEglContextLocked();
//向GL线程发送一个任务
public void queueEvent(Runnable r);