Merge change 26317 into eclair

* changes:
  Allow GLSurfaceView clients to customize EGL Surfaces and Contexts.
This commit is contained in:
Android (Google) Code Review
2009-09-21 22:22:18 -04:00

View File

@ -271,17 +271,51 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
* @param renderer the renderer to use to perform OpenGL drawing. * @param renderer the renderer to use to perform OpenGL drawing.
*/ */
public void setRenderer(Renderer renderer) { public void setRenderer(Renderer renderer) {
if (mGLThread != null) { checkRenderThreadState();
throw new IllegalStateException(
"setRenderer has already been called for this instance.");
}
if (mEGLConfigChooser == null) { if (mEGLConfigChooser == null) {
mEGLConfigChooser = new SimpleEGLConfigChooser(true); mEGLConfigChooser = new SimpleEGLConfigChooser(true);
} }
if (mEGLContextFactory == null) {
mEGLContextFactory = new DefaultContextFactory();
}
if (mEGLWindowSurfaceFactory == null) {
mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
}
mGLThread = new GLThread(renderer); mGLThread = new GLThread(renderer);
mGLThread.start(); mGLThread.start();
} }
/**
* @hide
* Install a custom EGLContextFactory.
* <p>If this method is
* called, it must be called before {@link #setRenderer(Renderer)}
* is called.
* <p>
* If this method is not called, then by default
* a context will be created with no shared context and
* with a null attribute list.
*/
public void setContextFactory(EGLContextFactory factory) {
checkRenderThreadState();
mEGLContextFactory = factory;
}
/**
* @hide
* Install a custom EGLWindowSurfaceFactory.
* <p>If this method is
* called, it must be called before {@link #setRenderer(Renderer)}
* is called.
* <p>
* If this method is not called, then by default
* a window surface will be created with a null attribute list.
*/
public void setWindowSurfaceFactory(EGLWindowSurfaceFactory factory) {
checkRenderThreadState();
mEGLWindowSurfaceFactory = factory;
}
/** /**
* Install a custom EGLConfigChooser. * Install a custom EGLConfigChooser.
* <p>If this method is * <p>If this method is
@ -294,10 +328,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
* @param configChooser * @param configChooser
*/ */
public void setEGLConfigChooser(EGLConfigChooser configChooser) { public void setEGLConfigChooser(EGLConfigChooser configChooser) {
if (mGLThread != null) { checkRenderThreadState();
throw new IllegalStateException(
"setRenderer has already been called for this instance.");
}
mEGLConfigChooser = configChooser; mEGLConfigChooser = configChooser;
} }
@ -577,6 +608,56 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
void onDrawFrame(GL10 gl); void onDrawFrame(GL10 gl);
} }
/**
* @hide
* An interface for customizing the eglCreateContext and eglDestroyContext calls.
* <p>
* This interface must be implemented by clients wishing to call
* {@link GLSurfaceView#setEGLContextFactory(EGLContextFactory)}
*/
public interface EGLContextFactory {
EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig);
void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context);
}
private static class DefaultContextFactory implements EGLContextFactory {
public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config) {
return egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT, null);
}
public void destroyContext(EGL10 egl, EGLDisplay display,
EGLContext context) {
egl.eglDestroyContext(display, context);
}
}
/**
* @hide
* An interface for customizing the eglCreateWindowSurface and eglDestroySurface calls.
* <p>
* This interface must be implemented by clients wishing to call
* {@link GLSurfaceView#setEGLContextCreator(EGLContextCreator)}
*/
public interface EGLWindowSurfaceFactory {
EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config,
Object nativeWindow);
void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface);
}
private static class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory {
public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display,
EGLConfig config, Object nativeWindow) {
return egl.eglCreateWindowSurface(display, config, nativeWindow, null);
}
public void destroySurface(EGL10 egl, EGLDisplay display,
EGLSurface surface) {
egl.eglDestroySurface(display, surface);
}
}
/** /**
* An interface for choosing an EGLConfig configuration from a list of * An interface for choosing an EGLConfig configuration from a list of
* potential configurations. * potential configurations.
@ -751,8 +832,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
* Create an OpenGL ES context. This must be done only once, an * Create an OpenGL ES context. This must be done only once, an
* OpenGL context is a somewhat heavy object. * OpenGL context is a somewhat heavy object.
*/ */
mEglContext = mEgl.eglCreateContext(mEglDisplay, mEglConfig, mEglContext = mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
EGL10.EGL_NO_CONTEXT, null);
mEglSurface = null; mEglSurface = null;
} }
@ -774,14 +854,14 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
*/ */
mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
mEgl.eglDestroySurface(mEglDisplay, mEglSurface); mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface);
} }
/* /*
* Create an EGL surface we can render into. * Create an EGL surface we can render into.
*/ */
mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglSurface = mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
mEglConfig, holder, null); mEglDisplay, mEglConfig, holder);
/* /*
* Before we can issue GL commands, we need to make sure * Before we can issue GL commands, we need to make sure
@ -790,7 +870,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
mEglContext); mEglContext);
GL gl = mEglContext.getGL(); GL gl = mEglContext.getGL();
if (mGLWrapper != null) { if (mGLWrapper != null) {
gl = mGLWrapper.wrap(gl); gl = mGLWrapper.wrap(gl);
@ -831,14 +910,14 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_CONTEXT); EGL10.EGL_NO_CONTEXT);
mEgl.eglDestroySurface(mEglDisplay, mEglSurface); mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface);
mEglSurface = null; mEglSurface = null;
} }
} }
public void finish() { public void finish() {
if (mEglContext != null) { if (mEglContext != null) {
mEgl.eglDestroyContext(mEglDisplay, mEglContext); mEGLContextFactory.destroyContext(mEgl, mEglDisplay, mEglContext);
mEglContext = null; mEglContext = null;
} }
if (mEglDisplay != null) { if (mEglDisplay != null) {
@ -898,92 +977,93 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
private void guardedRun() throws InterruptedException { private void guardedRun() throws InterruptedException {
mEglHelper = new EglHelper(); mEglHelper = new EglHelper();
mEglHelper.start(); try {
mEglHelper.start();
GL10 gl = null; GL10 gl = null;
boolean tellRendererSurfaceCreated = true; boolean tellRendererSurfaceCreated = true;
boolean tellRendererSurfaceChanged = true; boolean tellRendererSurfaceChanged = true;
/*
* This is our main activity thread's loop, we go until
* asked to quit.
*/
while (!mDone) {
/* /*
* Update the asynchronous state (window size) * This is our main activity thread's loop, we go until
* asked to quit.
*/ */
int w, h; while (!mDone) {
boolean changed;
boolean needStart = false;
synchronized (this) {
Runnable r;
while ((r = getEvent()) != null) {
r.run();
}
if (mPaused) {
mEglHelper.destroySurface();
mEglHelper.finish();
needStart = true;
}
while (needToWait()) {
if (!mHasSurface) {
if (!mWaitingForSurface) {
mEglHelper.destroySurface();
mWaitingForSurface = true;
notify();
}
}
wait();
}
if (mDone) {
break;
}
changed = mSizeChanged;
w = mWidth;
h = mHeight;
mSizeChanged = false;
mRequestRender = false;
if (mHasSurface && mWaitingForSurface) {
changed = true;
mWaitingForSurface = false;
mRequestRender = true; // Forces a redraw for RENDERMODE_RENDER_WHEN_DIRTY
}
}
if (needStart) {
mEglHelper.start();
tellRendererSurfaceCreated = true;
changed = true;
}
if (changed) {
gl = (GL10) mEglHelper.createSurface(getHolder());
tellRendererSurfaceChanged = true;
}
if (tellRendererSurfaceCreated) {
mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
tellRendererSurfaceCreated = false;
}
if (tellRendererSurfaceChanged) {
mRenderer.onSurfaceChanged(gl, w, h);
tellRendererSurfaceChanged = false;
}
if ((w > 0) && (h > 0)) {
/* draw a frame here */
mRenderer.onDrawFrame(gl);
/* /*
* Once we're done with GL, we need to call swapBuffers() * Update the asynchronous state (window size)
* to instruct the system to display the rendered frame
*/ */
mEglHelper.swap(); int w, h;
} boolean changed;
} boolean needStart = false;
synchronized (this) {
Runnable r;
while ((r = getEvent()) != null) {
r.run();
}
if (mPaused) {
mEglHelper.destroySurface();
mEglHelper.finish();
needStart = true;
}
while (needToWait()) {
if (!mHasSurface) {
if (!mWaitingForSurface) {
mEglHelper.destroySurface();
mWaitingForSurface = true;
notify();
}
}
wait();
}
if (mDone) {
break;
}
changed = mSizeChanged;
w = mWidth;
h = mHeight;
mSizeChanged = false;
mRequestRender = false;
if (mHasSurface && mWaitingForSurface) {
changed = true;
mWaitingForSurface = false;
}
}
if (needStart) {
mEglHelper.start();
tellRendererSurfaceCreated = true;
changed = true;
}
if (changed) {
gl = (GL10) mEglHelper.createSurface(getHolder());
tellRendererSurfaceChanged = true;
}
if (tellRendererSurfaceCreated) {
mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
tellRendererSurfaceCreated = false;
}
if (tellRendererSurfaceChanged) {
mRenderer.onSurfaceChanged(gl, w, h);
tellRendererSurfaceChanged = false;
}
if ((w > 0) && (h > 0)) {
/* draw a frame here */
mRenderer.onDrawFrame(gl);
/* /*
* clean-up everything... * Once we're done with GL, we need to call swapBuffers()
*/ * to instruct the system to display the rendered frame
mEglHelper.destroySurface(); */
mEglHelper.finish(); mEglHelper.swap();
}
}
} finally {
/*
* clean-up everything...
*/
mEglHelper.destroySurface();
mEglHelper.finish();
}
} }
private boolean needToWait() { private boolean needToWait() {
@ -1038,7 +1118,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
synchronized(this) { synchronized(this) {
mHasSurface = false; mHasSurface = false;
notify(); notify();
while(!mWaitingForSurface) { while(!mWaitingForSurface && isAlive()) {
try { try {
wait(); wait();
} catch (InterruptedException e) { } catch (InterruptedException e) {
@ -1149,11 +1229,21 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
private StringBuilder mBuilder = new StringBuilder(); private StringBuilder mBuilder = new StringBuilder();
} }
private void checkRenderThreadState() {
if (mGLThread != null) {
throw new IllegalStateException(
"setRenderer has already been called for this instance.");
}
}
private static final Semaphore sEglSemaphore = new Semaphore(1); private static final Semaphore sEglSemaphore = new Semaphore(1);
private boolean mSizeChanged = true; private boolean mSizeChanged = true;
private GLThread mGLThread; private GLThread mGLThread;
private EGLConfigChooser mEGLConfigChooser; private EGLConfigChooser mEGLConfigChooser;
private EGLContextFactory mEGLContextFactory;
private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
private GLWrapper mGLWrapper; private GLWrapper mGLWrapper;
private int mDebugFlags; private int mDebugFlags;
} }