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,6 +977,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
|||||||
|
|
||||||
private void guardedRun() throws InterruptedException {
|
private void guardedRun() throws InterruptedException {
|
||||||
mEglHelper = new EglHelper();
|
mEglHelper = new EglHelper();
|
||||||
|
try {
|
||||||
mEglHelper.start();
|
mEglHelper.start();
|
||||||
|
|
||||||
GL10 gl = null;
|
GL10 gl = null;
|
||||||
@ -947,7 +1027,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
|||||||
if (mHasSurface && mWaitingForSurface) {
|
if (mHasSurface && mWaitingForSurface) {
|
||||||
changed = true;
|
changed = true;
|
||||||
mWaitingForSurface = false;
|
mWaitingForSurface = false;
|
||||||
mRequestRender = true; // Forces a redraw for RENDERMODE_RENDER_WHEN_DIRTY
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (needStart) {
|
if (needStart) {
|
||||||
@ -978,13 +1057,14 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
|||||||
mEglHelper.swap();
|
mEglHelper.swap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
/*
|
/*
|
||||||
* clean-up everything...
|
* clean-up everything...
|
||||||
*/
|
*/
|
||||||
mEglHelper.destroySurface();
|
mEglHelper.destroySurface();
|
||||||
mEglHelper.finish();
|
mEglHelper.finish();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean needToWait() {
|
private boolean needToWait() {
|
||||||
if (mDone) {
|
if (mDone) {
|
||||||
@ -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