Android OpenGL入門之GLSurfaceView

GLSurfaceView使用

OpenGL ES是是一個開源圖形庫,那麼與之相關的需要一個東西去顯示畫面,在android裡,opengl包裡提供瞭一個View叫GLSurfaceView,它的定義如下:

An implementation of SurfaceView that uses the dedicated surface for
displaying OpenGL rendering.

它的特性如下:

  • Manages a surface, which is a special piece of memory that can be
  • composited into the Android view system.
  • Manages an EGL display, which enables OpenGL to render into a surface.
  • Accepts a user-provided Renderer object that does the actual rendering.
  • Renders on a dedicated thread to decouple rendering performance from the UI thread.
  • Supports both on-demand and continuous rendering.
  • Optionally wraps, traces, and/or error-checks the renderer’s OpenGL calls.

可見系統已封裝好一個View用於渲染畫面並能進行相應設置。

使用步驟如下:

1.創建定義一個GLSurfaceView
2.調用GLSurfaceView的setEGLContextClientVersion設置版本號,可設為2
3.onResume 和 onPause分別調用GLSurfaceView相應的生命周期方法
4.調用GLSurfaceView的setRender設置自己實現GLSurfaceView.Render接口的類
5.Render接口有3個方法,分別是SurfaceCreated時候進行相應的初始化工作,SurfaceChange時候高寬的適配以及具體的DrawFrame方法

  • onSurfaceCreated(GL10 gl, EGLConfig config);
  • onSurfaceChanged(GL10 gl, int width, int height);
  • onDrawFrame(GL10 gl);

GLSurfaceView詳細分析:

1.GLSurfaceView在構造函數中調用init()設置如上3個回掉函數

private void init() {
      SurfaceHolder holder = getHolder();
      holder.addCallback(this);
  }

2.setRender會進行一些默認的設置,並生成一個GLThread的線程進行渲染繪制相關操作,繪制的內容默認情況下依舊是繪制到SurfaceView所提供的Surface上

  public void setRenderer(Renderer renderer) {
      checkRenderThreadState();
      if (mEGLConfigChooser == null) {
          mEGLConfigChooser = new SimpleEGLConfigChooser(true);
      }
      if (mEGLContextFactory == null) {
          mEGLContextFactory = new DefaultContextFactory();
      }
      if (mEGLWindowSurfaceFactory == null) {
          mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
      }
      mRenderer = renderer;
      mGLThread = new GLThread(mThisWeakRef);
      mGLThread.start();
  }

3.GLThread的run()方法裡調用瞭guardedRun()方法,在guardedRun方法裡new 瞭一個EglHelper類,並在一段邏輯判斷後調用瞭EglHelper的start方法。

4.EglHelper.start()方法裡

 public void start() {
    mEgl = (EGL10) EGLContext.getEGL();
    mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);

    if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
       throw new RuntimeException("eglGetDisplay failed");
    }
    int[] version = new int[2];
    if(!mEgl.eglInitialize(mEglDisplay, version)) {
      throw new RuntimeException("eglInitialize failed");
    }
    GLSurfaceView view = mGLSurfaceViewWeakRef.get();
    if (view == null) {
        mEglConfig = null;
        mEglContext = null;
    } else {
        mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
        mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
    }
    ...
}

這裡有如下幾個重要方法,最終會調用到C++層去初始化相關的渲染界面

  • EGLContext.getEGL()
  • eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY)
  • eglInitialize(mEglDisplay, version)
  • createContext()

5.在guardedRun() start()調用後會調用EglHelper.createSurface()方法,最終也會調用到C++層。

public boolean createSurface() {
//Check preconditions.
//window size has changed, create a new surface.
	destroySurfaceImp();
//Create an EGL surface we can render into.
    GLSurfaceView view = mGLSurfaceViewWeakRef.get();
    if (view != null) {
       	mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
                        mEglDisplay, mEglConfig, view.getHolder());
    } else {mEglSurface = null;}
    ...
    int error = mEgl.eglGetError();
	...
    if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
     	logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError());
     	return false;
   	}
    return true;
}
  • createWindowSurface
  • eglGetError
  • eglMakeCurrent

EGL相關知識

EGL用於管理繪圖表面,有如下機制

  • 與設備的原生窗口系統通信
  • 查詢繪圖表面的可用類型和配置
  • 創建繪圖表面
  • 在OpenGL ES 3.0和其他圖形渲染API之間同步渲染
  • 管理紋理貼圖等渲染資源

EGLDisplay:由於每個窗口系統都有不同的語義,所以EGL提供基本的不透明類型EGLDisplay,封裝瞭所有系統相關性,用於和原生窗口系統接口

EGL有如下一些方法:

EGLDisplay eglGetDisplay(Object native_display);
1.打開與EGL顯示服務器的鏈接打開與EGL顯示服務器的鏈接
2.native_display是一個displayId,指定顯示鏈接,默認鏈接為EGL_DEFAULT_DISPLAY

boolean eglInitialize(EGLDisplay display, int[] major_minor)
1.打開鏈接後,需要初始化EGL
2.display:getDisplay返回的值
3.主次版本號

boolean eglChooseConfig(EGLDisplay display, int[] attrib_list, EGLConfig[] configs, int config_size, int[] num_config);
1.讓EGL選擇匹配的EGLConfig
2.具體就是調用選擇配置,配置細節暫不敘述

EGLContext eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext share_context, int[] attrib_list);
1.創建渲染上下文
2.display:指定的顯示鏈接
3.config:指定的配置
4.share_context:允許多個EGL上下文共享特定類型的數據;使用EGL_NO_CONTEXT表示沒有共享
5.attrib_list:指定創建上下文使用的屬性列表;隻有一個可接受的屬性:EGL_CONTEXT_CLIENT_VERSION表示指定與你所使用的OpenGL ES版本

6.eglCreateContext成功時,它返回一個指向新創建上下文的句柄。

EGLSurface eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
1.有瞭符合渲染要求的EGLConfig,就可調用此函數創建一個窗口
2.屬性同上

int eglGetError();
1.EGL函數成功時返回EGL_TRUE,否則返回EGL_FALSE。如果需要查詢故障原因,調用eglGetError()得到返回錯誤碼。

boolean eglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context);
1.因一個應用程序可能創建多個EGLContext用於不同的用途,所以需要關聯特定的EGLContext和渲染表面即:指定當前上下文

整個大概流程就如上所述調用下來。

以上就是Android OpenGL入門之GLSurfaceView的詳細內容,更多關於Android GLSurfaceView的資料請關註WalkonNet其它相關文章!

推薦閱讀:

    None Found