一、
GLSurfaceView 如果我们没有使用过,从名字可以看出其与OpenGL以及Surfaceview有关,GLSurfaceView有以下特点:
1、管理surface,一块特别的内存区域给Android 视图系统。
2、管理EGL展示,能够保证OpenGL渲染到Surface上。
3、接收自定义的Render,这个Render做实际的渲染。
4、渲染是在专门的GL线程,从UI线程中分离出来。
5、支持按需或者不间断的渲染模式。
我这里先展示下初步学习使用绘制一个三角形
1、xml 中引用
2、MainActivity
public class MainActivity extends AppCompatActivity {
private GLSurfaceView mGLSurfaceView;
private MyRender myRender;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mGLSurfaceView = findViewById(R.id.glview);
myRender = new MyRender();
//设置渲染
mGLSurfaceView.setRenderer(myRender);
//设置按需渲染模式
mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
@Override
protected void onPause() {
mGLSurfaceView.onPause();
super.onPause();
}
@Override
protected void onResume() {
mGLSurfaceView.onResume();
super.onResume();
}
@Override
protected void onStop() {
super.onStop();
}
}
MyRender.java
public class MyRender implements GLSurfaceView.Renderer {
private static final String TAG = MyRender.class.getSimpleName();
private float[] mTriangleArray = {
// X, Y, Z 这是一个等边三角形
-0.5f, -0.25f, 0, 0.5f, -0.25f, 0, 0.0f, 0.559016994f, 0};
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// 设置背景颜色
gl.glClearColor(1.0f, 1.0f, 1.0f, 0.5f);
// 启用顶点数组(否则glDrawArrays不起作用)
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
Log.d(TAG, " onSurfaceChanged width " + width + " height : " + height);
gl.glViewport(0, 0, width, height);
}
@Override
public void onDrawFrame(GL10 gl) {
Log.d(TAG, "onDrawFrame ");
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
gl.glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
FloatBuffer mTriangleBuffer = BufferUtil
.floatToBuffer(mTriangleArray);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mTriangleBuffer);
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
//
gl.glLoadIdentity();
// 平移 (矩阵相乘)
// gl.glTranslatef(-0.2f, 0.3f, 0f);
}
static class BufferUtil {
public static FloatBuffer mBuffer;
public static FloatBuffer floatToBuffer(float[] a) {
// 先初始化buffer,数组的长度*4,因为一个float占4个字节
ByteBuffer mbb = ByteBuffer.allocateDirect(a.length * 4);
// 数组排序用nativeOrder
mbb.order(ByteOrder.nativeOrder());
mBuffer = mbb.asFloatBuffer();
mBuffer.put(a);
mBuffer.position(0);
return mBuffer;
}
}
效果图如下:
源码分析:
public void setRenderer(Renderer renderer) {
// 检测渲染线程状态,如果已经创建了,直接抛出异常
checkRenderThreadState();
if (mEGLConfigChooser == null) {
mEGLConfigChooser = new SimpleEGLConfigChooser(true);
}
//创建EGL 上下文环境
if (mEGLContextFactory == null) {
mEGLContextFactory = new DefaultContextFactory();
}
// 创建承载Surface的window factory
if (mEGLWindowSurfaceFactory == null) {
mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
}
mRenderer = renderer;
//开启渲染线程
//mThisWeakRef 是弱引用,持有当前的GLSurfaceView对象
mGLThread = new GLThread(mThisWeakRef);
mGLThread.start();
}
GLThread 的run方法中主要调用了guardedRun方法,看下其实现:
private void guardedRun() throws InterruptedException {
while (true) {
synchronized (sGLThreadManager) {
while (true) {
//是否应该退出
if (mShouldExit) {
return;
}
//队列不空,取出
if (! mEventQueue.isEmpty()) {
event = mEventQueue.remove(0);
break;
}
// Update the pause state.
boolean pausing = false;
if (mPaused != mRequestPaused) {
pausing = mRequestPaused;
mPaused = mRequestPaused;
sGLThreadManager.notifyAll();
if (LOG_PAUSE_RESUME) {
Log.i("GLThread", "mPaused is now " + mPaused + " tid=" + getId());
}
}
// Do we need to give up the EGL context?
if (mShouldReleaseEglContext) {
if (LOG_SURFACE) {
Log.i("GLThread", "releasing EGL context because asked to tid=" + getId());
}
stopEglSurfaceLocked();
stopEglContextLocked();
mShouldReleaseEglContext = false;
askedToReleaseEglContext = true;
}
// Have we lost the EGL context?
if (lostEglContext) {
stopEglSurfaceLocked();
stopEglContextLocked();
lostEglContext = false;
}
// When pausing, release the EGL surface:
if (pausing && mHaveEglSurface) {
if (LOG_SURFACE) {
Log.i("GLThread", "releasing EGL surface because paused tid=" + getId());
}
stopEglSurfaceLocked();
}
// When pausing, optionally release the EGL Context:
if (pausing && mHaveEglContext) {
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
boolean preserveEglContextOnPause = view == null ?
false : view.mPreserveEGLContextOnPause;
if (!preserveEglContextOnPause) {
stopEglContextLocked();
if (LOG_SURFACE) {
Log.i("GLThread", "releasing EGL context because paused tid=" + getId());
}
}
}
// Have we lost the SurfaceView surface?
if ((! mHasSurface) && (! mWaitingForSurface)) {
if (LOG_SURFACE) {
Log.i("GLThread", "noticed surfaceView surface lost tid=" + getId());
}
if (mHaveEglSurface) {
stopEglSurfaceLocked();
}
mWaitingForSurface = true;
mSurfaceIsBad = false;
sGLThreadManager.notifyAll();
}
// Have we acquired the surface view surface?
if (mHasSurface && mWaitingForSurface) {
if (LOG_SURFACE) {
Log.i("GLThread", "noticed surfaceView surface acquired tid=" + getId());
}
mWaitingForSurface = false;
sGLThreadManager.notifyAll();
}
if (doRenderNotification) {
if (LOG_SURFACE) {
Log.i("GLThread", "sending render notification tid=" + getId());
}
mWantRenderNotification = false;
doRenderNotification = false;
mRenderComplete = true;
sGLThreadManager.notifyAll();
}
// Ready to draw?
if (readyToDraw()) {
// If we don't have an EGL context, try to acquire one.
if (! mHaveEglContext) {
if (askedToReleaseEglContext) {
askedToReleaseEglContext = false;
} else {
try {
mEglHelper.start();
} catch (RuntimeException t) {
sGLThreadManager.releaseEglContextLocked(this);
throw t;
}
mHaveEglContext = true;
createEglContext = true;
sGLThreadManager.notifyAll();
}
}
if (mHaveEglContext && !mHaveEglSurface) {
mHaveEglSurface = true;
createEglSurface = true;
createGlInterface = true;
sizeChanged = true;
}
if (mHaveEglSurface) {
if (mSizeChanged) {
sizeChanged = true;
w = mWidth;
h = mHeight;
mWantRenderNotification = true;
if (LOG_SURFACE) {
Log.i("GLThread",
"noticing that we want render notification tid="
+ getId());
}
// Destroy and recreate the EGL surface.
createEglSurface = true;
mSizeChanged = false;
}
mRequestRender = false;
sGLThreadManager.notifyAll();
if (mWantRenderNotification) {
wantRenderNotification = true;
}
break;
}
}
// By design, this is the only place in a GLThread thread where we wait().
if (LOG_THREADS) {
Log.i("GLThread", "waiting tid=" + getId()
+ " mHaveEglContext: " + mHaveEglContext
+ " mHaveEglSurface: " + mHaveEglSurface
+ " mFinishedCreatingEglSurface: " + mFinishedCreatingEglSurface
+ " mPaused: " + mPaused
+ " mHasSurface: " + mHasSurface
+ " mSurfaceIsBad: " + mSurfaceIsBad
+ " mWaitingForSurface: " + mWaitingForSurface
+ " mWidth: " + mWidth
+ " mHeight: " + mHeight
+ " mRequestRender: " + mRequestRender
+ " mRenderMode: " + mRenderMode);
}
sGLThreadManager.wait();
}
} // end of synchronized(sGLThreadManager)
if (event != null) {
event.run();
event = null;
continue;
}
if (createEglSurface) {
if (LOG_SURFACE) {
Log.w("GLThread", "egl createSurface");
}
if (mEglHelper.createSurface()) {
synchronized(sGLThreadManager) {
mFinishedCreatingEglSurface = true;
sGLThreadManager.notifyAll();
}
} else {
synchronized(sGLThreadManager) {
mFinishedCreatingEglSurface = true;
mSurfaceIsBad = true;
sGLThreadManager.notifyAll();
}
continue;
}
createEglSurface = false;
}
if (createGlInterface) {
gl = (GL10) mEglHelper.createGL();
createGlInterface = false;
}
if (createEglContext) {
if (LOG_RENDERER) {
Log.w("GLThread", "onSurfaceCreated");
}
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onSurfaceCreated");
view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
createEglContext = false;
}
if (sizeChanged) {
if (LOG_RENDERER) {
Log.w("GLThread", "onSurfaceChanged(" + w + ", " + h + ")");
}
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onSurfaceChanged");
view.mRenderer.onSurfaceChanged(gl, w, h);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
sizeChanged = false;
}
if (LOG_RENDERER_DRAW_FRAME) {
Log.w("GLThread", "onDrawFrame tid=" + getId());
}
{
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onDrawFrame");
view.mRenderer.onDrawFrame(gl);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
}
int swapError = mEglHelper.swap();
switch (swapError) {
case EGL10.EGL_SUCCESS:
break;
case EGL11.EGL_CONTEXT_LOST:
if (LOG_SURFACE) {
Log.i("GLThread", "egl context lost tid=" + getId());
}
lostEglContext = true;
break;
default:
// Other errors typically mean that the current surface is bad,
// probably because the SurfaceView surface has been destroyed,
// but we haven't been notified yet.
// Log the error to help developers understand why rendering stopped.
EglHelper.logEglErrorAsWarning("GLThread", "eglSwapBuffers", swapError);
synchronized(sGLThreadManager) {
mSurfaceIsBad = true;
sGLThreadManager.notifyAll();
}
break;
}
if (wantRenderNotification) {
doRenderNotification = true;
wantRenderNotification = false;
}
}
} finally {
/*
* clean-up everything...
*/
synchronized (sGLThreadManager) {
stopEglSurfaceLocked();
stopEglContextLocked();
}
}
}
1、方法中加了 synchronized (sGLThreadManager) ,进行线程控制
2、if (! mEventQueue.isEmpty()) {
event = mEventQueue.remove(0);
break;
}
队列中取出一个元素,break跳出内循环。
3、 if (readyToDraw()) 满足该条件,进行是否满足条件准备绘制
rivate boolean readyToDraw() {
return (!mPaused) && mHasSurface && (!mSurfaceIsBad)
&& (mWidth > 0) && (mHeight > 0)
&& (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY));
}
同时要满足这么多条件,尤其注重最后一个条件,如果渲染模式是RENDERMODE_CONTINUOUSLY(不设置默认就是这种情形)或者请求绘制(mRequestRender 为 true)
如果不满足该条件,调用 sGLThreadManager.wait(),阻塞该线程。
4、回调onSurfaceOnCreated方法
if (createEglContext) {
if (LOG_RENDERER) {
Log.w("GLThread", "onSurfaceCreated");
}
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onSurfaceCreated");
view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
createEglContext = false;
}
第9行回调 渲染回调 的 onSurfaceCreated 方法,createEglContext = false,说明只回调一次。
5、onSurfaceChanged
if (sizeChanged) {
if (LOG_RENDERER) {
Log.w("GLThread", "onSurfaceChanged(" + w + ", " + h + ")");
}
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onSurfaceChanged");
view.mRenderer.onSurfaceChanged(gl, w, h);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
sizeChanged = false;
}
6、onDrawFrame:
view.mRenderer.onDrawFrame(gl)
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onDrawFrame");
view.mRenderer.onDrawFrame(gl);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
7、渲染到surface
int swapError = mEglHelper.swap();
/**
* Display the current render surface.
* @return the EGL error code from eglSwapBuffers.
*/
public int swap() {
if (! mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
return mEgl.eglGetError();
}
return EGL10.EGL_SUCCESS;
}
这个EglSurface是什么?
传入的是Surfaceview的getHolder
if (view != null) {
mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
mEglDisplay, mEglConfig, view.getHolder());
}
最后注意,实现onPause,以及onResume方法,阻塞以及恢复GL渲染线程。
public void onPause() {
synchronized (sGLThreadManager) {
if (LOG_PAUSE_RESUME) {
Log.i("GLThread", "onPause tid=" + getId());
}
mRequestPaused = true;
sGLThreadManager.notifyAll();
while ((! mExited) && (! mPaused)) {
if (LOG_PAUSE_RESUME) {
Log.i("Main thread", "onPause waiting for mPaused.");
}
try {
sGLThreadManager.wait();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
}
先唤醒线程再阻塞。