Merge change 26317 into eclair
* changes: Allow GLSurfaceView clients to customize EGL Surfaces and Contexts.
This commit is contained in:
@ -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;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user