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);

使用上的建议

results matching ""

    No results matching ""