/FallingSandpaper/src/android/opengl/GLWallpaperService.java

http://thelements.googlecode.com/ · Java · 1110 lines · 833 code · 133 blank · 144 comment · 108 complexity · 8f9629475aec7ad0b4f0c49ea6f65ef0 MD5 · raw file

  1. package android.opengl;
  2. import java.io.Writer;
  3. import java.util.ArrayList;
  4. import javax.microedition.khronos.egl.EGL10;
  5. import javax.microedition.khronos.egl.EGL11;
  6. import javax.microedition.khronos.egl.EGLConfig;
  7. import javax.microedition.khronos.egl.EGLContext;
  8. import javax.microedition.khronos.egl.EGLDisplay;
  9. import javax.microedition.khronos.egl.EGLSurface;
  10. import javax.microedition.khronos.opengles.GL;
  11. import javax.microedition.khronos.opengles.GL10;
  12. import android.opengl.BaseConfigChooser.ComponentSizeChooser;
  13. import android.opengl.BaseConfigChooser.SimpleEGLConfigChooser;
  14. import android.service.wallpaper.WallpaperService;
  15. import android.util.Log;
  16. import android.view.SurfaceHolder;
  17. public class GLWallpaperService extends WallpaperService
  18. {
  19. private static final String TAG = "GLWallpaperService";
  20. @Override
  21. public Engine onCreateEngine()
  22. {
  23. return new GLEngine();
  24. }
  25. public class GLEngine extends Engine
  26. {
  27. public final static int RENDERMODE_WHEN_DIRTY = 0;
  28. public final static int RENDERMODE_CONTINUOUSLY = 1;
  29. private GLThread mGLThread;
  30. private EGLConfigChooser mEGLConfigChooser;
  31. private EGLContextFactory mEGLContextFactory;
  32. private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
  33. private GLWrapper mGLWrapper;
  34. private int mDebugFlags;
  35. public GLEngine()
  36. {
  37. super();
  38. }
  39. @Override
  40. public void onVisibilityChanged(boolean visible)
  41. {
  42. if (visible)
  43. {
  44. onResume();
  45. }
  46. else
  47. {
  48. onPause();
  49. }
  50. super.onVisibilityChanged(visible);
  51. }
  52. @Override
  53. public void onCreate(SurfaceHolder surfaceHolder)
  54. {
  55. super.onCreate(surfaceHolder);
  56. // Log.d(TAG, "GLEngine.onCreate()");
  57. }
  58. @Override
  59. public void onDestroy()
  60. {
  61. super.onDestroy();
  62. // Log.d(TAG, "GLEngine.onDestroy()");
  63. mGLThread.requestExitAndWait();
  64. }
  65. @Override
  66. public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height)
  67. {
  68. // Log.d(TAG, "onSurfaceChanged()");
  69. mGLThread.onWindowResize(width, height);
  70. super.onSurfaceChanged(holder, format, width, height);
  71. }
  72. @Override
  73. public void onSurfaceCreated(SurfaceHolder holder)
  74. {
  75. //Log.d(TAG, "onSurfaceCreated()");
  76. mGLThread.surfaceCreated(holder);
  77. super.onSurfaceCreated(holder);
  78. }
  79. @Override
  80. public void onSurfaceDestroyed(SurfaceHolder holder)
  81. {
  82. //Log.d(TAG, "onSurfaceDestroyed()");
  83. mGLThread.surfaceDestroyed();
  84. super.onSurfaceDestroyed(holder);
  85. }
  86. /**
  87. * An EGL helper class.
  88. */
  89. public void setGLWrapper(GLWrapper glWrapper)
  90. {
  91. mGLWrapper = glWrapper;
  92. }
  93. public void setDebugFlags(int debugFlags)
  94. {
  95. mDebugFlags = debugFlags;
  96. }
  97. public int getDebugFlags()
  98. {
  99. return mDebugFlags;
  100. }
  101. public void setRenderer(Renderer renderer)
  102. {
  103. checkRenderThreadState();
  104. if (mEGLConfigChooser == null)
  105. {
  106. mEGLConfigChooser = new SimpleEGLConfigChooser(true);
  107. }
  108. if (mEGLContextFactory == null)
  109. {
  110. mEGLContextFactory = new DefaultContextFactory();
  111. }
  112. if (mEGLWindowSurfaceFactory == null)
  113. {
  114. mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
  115. }
  116. mGLThread = new GLThread(renderer, mEGLConfigChooser, mEGLContextFactory, mEGLWindowSurfaceFactory, mGLWrapper);
  117. mGLThread.start();
  118. }
  119. public void setEGLContextFactory(EGLContextFactory factory)
  120. {
  121. checkRenderThreadState();
  122. mEGLContextFactory = factory;
  123. }
  124. public void setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory factory)
  125. {
  126. checkRenderThreadState();
  127. mEGLWindowSurfaceFactory = factory;
  128. }
  129. public void setEGLConfigChooser(EGLConfigChooser configChooser)
  130. {
  131. checkRenderThreadState();
  132. mEGLConfigChooser = configChooser;
  133. }
  134. public void setEGLConfigChooser(boolean needDepth)
  135. {
  136. setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth));
  137. }
  138. public void setEGLConfigChooser(int redSize, int greenSize, int blueSize, int alphaSize, int depthSize, int stencilSize)
  139. {
  140. setEGLConfigChooser(new ComponentSizeChooser(redSize, greenSize, blueSize, alphaSize, depthSize, stencilSize));
  141. }
  142. public void setRenderMode(int renderMode)
  143. {
  144. mGLThread.setRenderMode(renderMode);
  145. }
  146. public int getRenderMode()
  147. {
  148. return mGLThread.getRenderMode();
  149. }
  150. public void requestRender()
  151. {
  152. mGLThread.requestRender();
  153. }
  154. public void onPause()
  155. {
  156. mGLThread.onPause();
  157. }
  158. public void onResume()
  159. {
  160. mGLThread.onResume();
  161. }
  162. public void queueEvent(Runnable r)
  163. {
  164. mGLThread.queueEvent(r);
  165. }
  166. private void checkRenderThreadState()
  167. {
  168. if (mGLThread != null)
  169. {
  170. throw new IllegalStateException("setRenderer has already been called for this instance.");
  171. }
  172. }
  173. }
  174. public interface Renderer
  175. {
  176. public void onSurfaceCreated(GL10 gl, EGLConfig config);
  177. public void onSurfaceChanged(GL10 gl, int width, int height);
  178. public void onDrawFrame(GL10 gl);
  179. }
  180. }
  181. class LogWriter extends Writer
  182. {
  183. private StringBuilder mBuilder = new StringBuilder();
  184. @Override
  185. public void close()
  186. {
  187. flushBuilder();
  188. }
  189. @Override
  190. public void flush()
  191. {
  192. flushBuilder();
  193. }
  194. @Override
  195. public void write(char[] buf, int offset, int count)
  196. {
  197. for (int i = 0; i < count; i++)
  198. {
  199. char c = buf[offset + i];
  200. if (c == '\n')
  201. {
  202. flushBuilder();
  203. }
  204. else
  205. {
  206. mBuilder.append(c);
  207. }
  208. }
  209. }
  210. private void flushBuilder()
  211. {
  212. if (mBuilder.length() > 0)
  213. {
  214. Log.v("GLSurfaceView", mBuilder.toString());
  215. mBuilder.delete(0, mBuilder.length());
  216. }
  217. }
  218. }
  219. // ----------------------------------------------------------------------
  220. /**
  221. * An interface for customizing the eglCreateContext and eglDestroyContext
  222. * calls.
  223. *
  224. *
  225. * This interface must be implemented by clients wishing to call
  226. * {@link GLWallpaperService#setEGLContextFactory(EGLContextFactory)}
  227. */
  228. interface EGLContextFactory
  229. {
  230. EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig);
  231. void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context);
  232. }
  233. class DefaultContextFactory implements EGLContextFactory
  234. {
  235. public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config)
  236. {
  237. return egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT, null);
  238. }
  239. public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context)
  240. {
  241. egl.eglDestroyContext(display, context);
  242. }
  243. }
  244. /**
  245. * An interface for customizing the eglCreateWindowSurface and eglDestroySurface
  246. * calls.
  247. *
  248. *
  249. * This interface must be implemented by clients wishing to call
  250. * {@link GLWallpaperService#setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory)}
  251. */
  252. interface EGLWindowSurfaceFactory
  253. {
  254. EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config, Object nativeWindow);
  255. void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface);
  256. }
  257. class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory
  258. {
  259. public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config, Object nativeWindow)
  260. {
  261. // this is a bit of a hack to work around Droid init problems - if you
  262. // don't have this, it'll get hung up on orientation changes
  263. EGLSurface eglSurface = null;
  264. while (eglSurface == null)
  265. {
  266. try
  267. {
  268. eglSurface = egl.eglCreateWindowSurface(display, config, nativeWindow, null);
  269. } catch (Throwable t)
  270. {
  271. } finally
  272. {
  273. if (eglSurface == null)
  274. {
  275. try
  276. {
  277. Thread.sleep(10);
  278. } catch (InterruptedException t)
  279. {
  280. }
  281. }
  282. }
  283. }
  284. return eglSurface;
  285. }
  286. public void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface)
  287. {
  288. egl.eglDestroySurface(display, surface);
  289. }
  290. }
  291. interface GLWrapper
  292. {
  293. /**
  294. * Wraps a gl interface in another gl interface.
  295. *
  296. * @param gl
  297. * a GL interface that is to be wrapped.
  298. * @return either the input argument or another GL object that wraps the
  299. * input argument.
  300. */
  301. GL wrap(GL gl);
  302. }
  303. class EglHelper
  304. {
  305. private EGL10 mEgl;
  306. private EGLDisplay mEglDisplay;
  307. private EGLSurface mEglSurface;
  308. private EGLContext mEglContext;
  309. EGLConfig mEglConfig;
  310. private EGLConfigChooser mEGLConfigChooser;
  311. private EGLContextFactory mEGLContextFactory;
  312. private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
  313. private GLWrapper mGLWrapper;
  314. public EglHelper(EGLConfigChooser chooser, EGLContextFactory contextFactory, EGLWindowSurfaceFactory surfaceFactory, GLWrapper wrapper)
  315. {
  316. this.mEGLConfigChooser = chooser;
  317. this.mEGLContextFactory = contextFactory;
  318. this.mEGLWindowSurfaceFactory = surfaceFactory;
  319. this.mGLWrapper = wrapper;
  320. }
  321. /**
  322. * Initialize EGL for a given configuration spec.
  323. *
  324. * @param configSpec
  325. */
  326. public void start()
  327. {
  328. if (mEgl == null)
  329. {
  330. /*
  331. * Get an EGL instance
  332. */
  333. mEgl = (EGL10) EGLContext.getEGL();
  334. }
  335. else
  336. {
  337. }
  338. if (mEglDisplay == null)
  339. {
  340. /*
  341. * Get to the default display.
  342. */
  343. mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
  344. }
  345. else
  346. {
  347. }
  348. if (mEglConfig == null)
  349. {
  350. /*
  351. * We can now initialize EGL for that display
  352. */
  353. int[] version = new int[2];
  354. mEgl.eglInitialize(mEglDisplay, version);
  355. mEglConfig = mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
  356. }
  357. else
  358. {
  359. }
  360. if (mEglContext == null)
  361. {
  362. /*
  363. * Create an OpenGL ES context. This must be done only once, an
  364. * OpenGL context is a somewhat heavy object.
  365. */
  366. mEglContext = mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
  367. if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT)
  368. {
  369. throw new RuntimeException("createContext failed");
  370. }
  371. }
  372. else
  373. {
  374. }
  375. mEglSurface = null;
  376. }
  377. /*
  378. * React to the creation of a new surface by creating and returning an
  379. * OpenGL interface that renders to that surface.
  380. */
  381. public GL createSurface(SurfaceHolder holder)
  382. {
  383. /*
  384. * The window size has changed, so we need to create a new surface.
  385. */
  386. if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE)
  387. {
  388. /*
  389. * Unbind and destroy the old EGL surface, if there is one.
  390. */
  391. mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
  392. mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface);
  393. }
  394. /*
  395. * Create an EGL surface we can render into.
  396. */
  397. mEglSurface = mEGLWindowSurfaceFactory.createWindowSurface(mEgl, mEglDisplay, mEglConfig, holder);
  398. if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE)
  399. {
  400. throw new RuntimeException("createWindowSurface failed");
  401. }
  402. /*
  403. * Before we can issue GL commands, we need to make sure the context is
  404. * current and bound to a surface.
  405. */
  406. if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext))
  407. {
  408. throw new RuntimeException("eglMakeCurrent failed.");
  409. }
  410. GL gl = mEglContext.getGL();
  411. if (mGLWrapper != null)
  412. {
  413. gl = mGLWrapper.wrap(gl);
  414. }
  415. /*
  416. * if ((mDebugFlags & (DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS))!= 0)
  417. * { int configFlags = 0; Writer log = null; if ((mDebugFlags &
  418. * DEBUG_CHECK_GL_ERROR) != 0) { configFlags |=
  419. * GLDebugHelper.CONFIG_CHECK_GL_ERROR; } if ((mDebugFlags &
  420. * DEBUG_LOG_GL_CALLS) != 0) { log = new LogWriter(); } gl =
  421. * GLDebugHelper.wrap(gl, configFlags, log); }
  422. */
  423. return gl;
  424. }
  425. /**
  426. * Display the current render surface.
  427. *
  428. * @return false if the context has been lost.
  429. */
  430. public boolean swap()
  431. {
  432. mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
  433. /*
  434. * Always check for EGL_CONTEXT_LOST, which means the context and all
  435. * associated data were lost (For instance because the device went to
  436. * sleep). We need to sleep until we get a new surface.
  437. */
  438. return mEgl.eglGetError() != EGL11.EGL_CONTEXT_LOST;
  439. }
  440. public void destroySurface()
  441. {
  442. if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE)
  443. {
  444. mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
  445. mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface);
  446. mEglSurface = null;
  447. }
  448. }
  449. public void finish()
  450. {
  451. if (mEglContext != null)
  452. {
  453. mEGLContextFactory.destroyContext(mEgl, mEglDisplay, mEglContext);
  454. mEglContext = null;
  455. }
  456. if (mEglDisplay != null)
  457. {
  458. mEgl.eglTerminate(mEglDisplay);
  459. mEglDisplay = null;
  460. }
  461. }
  462. }
  463. class GLThread extends Thread
  464. {
  465. private final static boolean LOG_THREADS = false;
  466. public final static int DEBUG_CHECK_GL_ERROR = 1;
  467. public final static int DEBUG_LOG_GL_CALLS = 2;
  468. private final GLThreadManager sGLThreadManager = new GLThreadManager();
  469. private GLThread mEglOwner;
  470. private EGLConfigChooser mEGLConfigChooser;
  471. private EGLContextFactory mEGLContextFactory;
  472. private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
  473. private GLWrapper mGLWrapper;
  474. public SurfaceHolder mHolder;
  475. private boolean mSizeChanged = true;
  476. // Once the thread is started, all accesses to the following member
  477. // variables are protected by the sGLThreadManager monitor
  478. public boolean mDone;
  479. private boolean mPaused;
  480. private boolean mHasSurface;
  481. private boolean mWaitingForSurface;
  482. private boolean mHaveEgl;
  483. private int mWidth;
  484. private int mHeight;
  485. private int mRenderMode;
  486. private boolean mRequestRender;
  487. private boolean mEventsWaiting;
  488. // End of member variables protected by the sGLThreadManager monitor.
  489. private GLWallpaperService.Renderer mRenderer;
  490. private ArrayList mEventQueue = new ArrayList();
  491. private EglHelper mEglHelper;
  492. GLThread(GLWallpaperService.Renderer renderer, EGLConfigChooser chooser, EGLContextFactory contextFactory, EGLWindowSurfaceFactory surfaceFactory, GLWrapper wrapper)
  493. {
  494. super();
  495. mDone = false;
  496. mWidth = 0;
  497. mHeight = 0;
  498. mRequestRender = true;
  499. mRenderMode = GLWallpaperService.GLEngine.RENDERMODE_CONTINUOUSLY;
  500. mRenderer = renderer;
  501. this.mEGLConfigChooser = chooser;
  502. this.mEGLContextFactory = contextFactory;
  503. this.mEGLWindowSurfaceFactory = surfaceFactory;
  504. this.mGLWrapper = wrapper;
  505. }
  506. @Override
  507. public void run()
  508. {
  509. setName("GLThread " + getId());
  510. if (LOG_THREADS)
  511. {
  512. Log.i("GLThread", "starting tid=" + getId());
  513. }
  514. try
  515. {
  516. guardedRun();
  517. } catch (InterruptedException e)
  518. {
  519. // fall thru and exit normally
  520. } finally
  521. {
  522. sGLThreadManager.threadExiting(this);
  523. }
  524. }
  525. /*
  526. * This private method should only be called inside a
  527. * synchronized(sGLThreadManager) block.
  528. */
  529. private void stopEglLocked()
  530. {
  531. if (mHaveEgl)
  532. {
  533. mHaveEgl = false;
  534. mEglHelper.destroySurface();
  535. sGLThreadManager.releaseEglSurface(this);
  536. }
  537. }
  538. private void guardedRun() throws InterruptedException
  539. {
  540. mEglHelper = new EglHelper(mEGLConfigChooser, mEGLContextFactory, mEGLWindowSurfaceFactory, mGLWrapper);
  541. try
  542. {
  543. GL10 gl = null;
  544. boolean tellRendererSurfaceCreated = true;
  545. boolean tellRendererSurfaceChanged = true;
  546. /*
  547. * This is our main activity thread's loop, we go until asked to
  548. * quit.
  549. */
  550. while (!isDone())
  551. {
  552. /*
  553. * Update the asynchronous state (window size)
  554. */
  555. int w = 0;
  556. int h = 0;
  557. boolean changed = false;
  558. boolean needStart = false;
  559. boolean eventsWaiting = false;
  560. synchronized (sGLThreadManager)
  561. {
  562. while (true)
  563. {
  564. // Manage acquiring and releasing the SurfaceView
  565. // surface and the EGL surface.
  566. if (mPaused)
  567. {
  568. stopEglLocked();
  569. }
  570. if (!mHasSurface)
  571. {
  572. if (!mWaitingForSurface)
  573. {
  574. stopEglLocked();
  575. mWaitingForSurface = true;
  576. sGLThreadManager.notifyAll();
  577. }
  578. }
  579. else
  580. {
  581. if (!mHaveEgl)
  582. {
  583. if (sGLThreadManager.tryAcquireEglSurface(this))
  584. {
  585. mHaveEgl = true;
  586. mEglHelper.start();
  587. mRequestRender = true;
  588. needStart = true;
  589. }
  590. }
  591. }
  592. // Check if we need to wait. If not, update any state
  593. // that needs to be updated, copy any state that
  594. // needs to be copied, and use "break" to exit the
  595. // wait loop.
  596. if (mDone)
  597. {
  598. return;
  599. }
  600. if (mEventsWaiting)
  601. {
  602. eventsWaiting = true;
  603. mEventsWaiting = false;
  604. break;
  605. }
  606. if ((!mPaused) && mHasSurface && mHaveEgl && (mWidth > 0) && (mHeight > 0) && (mRequestRender || (mRenderMode == GLWallpaperService.GLEngine.RENDERMODE_CONTINUOUSLY)))
  607. {
  608. changed = mSizeChanged;
  609. w = mWidth;
  610. h = mHeight;
  611. mSizeChanged = false;
  612. mRequestRender = false;
  613. if (mHasSurface && mWaitingForSurface)
  614. {
  615. changed = true;
  616. mWaitingForSurface = false;
  617. sGLThreadManager.notifyAll();
  618. }
  619. break;
  620. }
  621. // By design, this is the only place where we wait().
  622. if (LOG_THREADS)
  623. {
  624. Log.i("GLThread", "waiting tid=" + getId());
  625. }
  626. sGLThreadManager.wait();
  627. }
  628. } // end of synchronized(sGLThreadManager)
  629. /*
  630. * Handle queued events
  631. */
  632. if (eventsWaiting)
  633. {
  634. Runnable r;
  635. while ((r = getEvent()) != null)
  636. {
  637. r.run();
  638. if (isDone())
  639. {
  640. return;
  641. }
  642. }
  643. // Go back and see if we need to wait to render.
  644. continue;
  645. }
  646. if (needStart)
  647. {
  648. tellRendererSurfaceCreated = true;
  649. changed = true;
  650. }
  651. if (changed)
  652. {
  653. gl = (GL10) mEglHelper.createSurface(mHolder);
  654. tellRendererSurfaceChanged = true;
  655. }
  656. if (tellRendererSurfaceCreated)
  657. {
  658. mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
  659. tellRendererSurfaceCreated = false;
  660. }
  661. if (tellRendererSurfaceChanged)
  662. {
  663. mRenderer.onSurfaceChanged(gl, w, h);
  664. tellRendererSurfaceChanged = false;
  665. }
  666. if ((w > 0) && (h > 0))
  667. {
  668. /* draw a frame here */
  669. mRenderer.onDrawFrame(gl);
  670. /*
  671. * Once we're done with GL, we need to call swapBuffers() to
  672. * instruct the system to display the rendered frame
  673. */
  674. mEglHelper.swap();
  675. }
  676. }
  677. } finally
  678. {
  679. /*
  680. * clean-up everything...
  681. */
  682. synchronized (sGLThreadManager)
  683. {
  684. stopEglLocked();
  685. mEglHelper.finish();
  686. }
  687. }
  688. }
  689. private boolean isDone()
  690. {
  691. synchronized (sGLThreadManager)
  692. {
  693. return mDone;
  694. }
  695. }
  696. public void setRenderMode(int renderMode)
  697. {
  698. if (!((GLWallpaperService.GLEngine.RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= GLWallpaperService.GLEngine.RENDERMODE_CONTINUOUSLY)))
  699. {
  700. throw new IllegalArgumentException("renderMode");
  701. }
  702. synchronized (sGLThreadManager)
  703. {
  704. mRenderMode = renderMode;
  705. if (renderMode == GLWallpaperService.GLEngine.RENDERMODE_CONTINUOUSLY)
  706. {
  707. sGLThreadManager.notifyAll();
  708. }
  709. }
  710. }
  711. public int getRenderMode()
  712. {
  713. synchronized (sGLThreadManager)
  714. {
  715. return mRenderMode;
  716. }
  717. }
  718. public void requestRender()
  719. {
  720. synchronized (sGLThreadManager)
  721. {
  722. mRequestRender = true;
  723. sGLThreadManager.notifyAll();
  724. }
  725. }
  726. public void surfaceCreated(SurfaceHolder holder)
  727. {
  728. mHolder = holder;
  729. synchronized (sGLThreadManager)
  730. {
  731. if (LOG_THREADS)
  732. {
  733. Log.i("GLThread", "surfaceCreated tid=" + getId());
  734. }
  735. mHasSurface = true;
  736. sGLThreadManager.notifyAll();
  737. }
  738. }
  739. public void surfaceDestroyed()
  740. {
  741. synchronized (sGLThreadManager)
  742. {
  743. if (LOG_THREADS)
  744. {
  745. Log.i("GLThread", "surfaceDestroyed tid=" + getId());
  746. }
  747. mHasSurface = false;
  748. sGLThreadManager.notifyAll();
  749. while (!mWaitingForSurface && isAlive() && !mDone)
  750. {
  751. try
  752. {
  753. sGLThreadManager.wait();
  754. } catch (InterruptedException e)
  755. {
  756. Thread.currentThread().interrupt();
  757. }
  758. }
  759. }
  760. }
  761. public void onPause()
  762. {
  763. synchronized (sGLThreadManager)
  764. {
  765. mPaused = true;
  766. sGLThreadManager.notifyAll();
  767. }
  768. }
  769. public void onResume()
  770. {
  771. synchronized (sGLThreadManager)
  772. {
  773. mPaused = false;
  774. mRequestRender = true;
  775. sGLThreadManager.notifyAll();
  776. }
  777. }
  778. public void onWindowResize(int w, int h)
  779. {
  780. synchronized (sGLThreadManager)
  781. {
  782. mWidth = w;
  783. mHeight = h;
  784. mSizeChanged = true;
  785. sGLThreadManager.notifyAll();
  786. }
  787. }
  788. public void requestExitAndWait()
  789. {
  790. // don't call this from GLThread thread or it is a guaranteed
  791. // deadlock!
  792. synchronized (sGLThreadManager)
  793. {
  794. mDone = true;
  795. sGLThreadManager.notifyAll();
  796. }
  797. try
  798. {
  799. join();
  800. } catch (InterruptedException ex)
  801. {
  802. Thread.currentThread().interrupt();
  803. }
  804. }
  805. /**
  806. * Queue an "event" to be run on the GL rendering thread.
  807. *
  808. * @param r
  809. * the runnable to be run on the GL rendering thread.
  810. */
  811. public void queueEvent(Runnable r)
  812. {
  813. synchronized (this)
  814. {
  815. mEventQueue.add(r);
  816. synchronized (sGLThreadManager)
  817. {
  818. mEventsWaiting = true;
  819. sGLThreadManager.notifyAll();
  820. }
  821. }
  822. }
  823. private Runnable getEvent()
  824. {
  825. synchronized (this)
  826. {
  827. if (mEventQueue.size() > 0)
  828. {
  829. return (Runnable) mEventQueue.remove(0);
  830. }
  831. }
  832. return null;
  833. }
  834. private class GLThreadManager
  835. {
  836. public synchronized void threadExiting(GLThread thread)
  837. {
  838. if (LOG_THREADS)
  839. {
  840. Log.i("GLThread", "exiting tid=" + thread.getId());
  841. }
  842. thread.mDone = true;
  843. if (mEglOwner == thread)
  844. {
  845. mEglOwner = null;
  846. }
  847. notifyAll();
  848. }
  849. /*
  850. * Tries once to acquire the right to use an EGL surface. Does not
  851. * block.
  852. *
  853. * @return true if the right to use an EGL surface was acquired.
  854. */
  855. public synchronized boolean tryAcquireEglSurface(GLThread thread)
  856. {
  857. if (mEglOwner == thread || mEglOwner == null)
  858. {
  859. mEglOwner = thread;
  860. notifyAll();
  861. return true;
  862. }
  863. return false;
  864. }
  865. public synchronized void releaseEglSurface(GLThread thread)
  866. {
  867. if (mEglOwner == thread)
  868. {
  869. mEglOwner = null;
  870. }
  871. notifyAll();
  872. }
  873. }
  874. }
  875. interface EGLConfigChooser
  876. {
  877. EGLConfig chooseConfig(EGL10 egl, EGLDisplay display);
  878. }
  879. abstract class BaseConfigChooser implements EGLConfigChooser
  880. {
  881. public BaseConfigChooser(int[] configSpec)
  882. {
  883. mConfigSpec = configSpec;
  884. }
  885. public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display)
  886. {
  887. int[] num_config = new int[1];
  888. egl.eglChooseConfig(display, mConfigSpec, null, 0, num_config);
  889. int numConfigs = num_config[0];
  890. if (numConfigs <= 0)
  891. {
  892. throw new IllegalArgumentException("No configs match configSpec");
  893. }
  894. EGLConfig[] configs = new EGLConfig[numConfigs];
  895. egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, num_config);
  896. EGLConfig config = chooseConfig(egl, display, configs);
  897. if (config == null)
  898. {
  899. throw new IllegalArgumentException("No config chosen");
  900. }
  901. return config;
  902. }
  903. abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs);
  904. protected int[] mConfigSpec;
  905. public static class ComponentSizeChooser extends BaseConfigChooser
  906. {
  907. public ComponentSizeChooser(int redSize, int greenSize, int blueSize, int alphaSize, int depthSize, int stencilSize)
  908. {
  909. super(new int[] {EGL10.EGL_RED_SIZE, redSize, EGL10.EGL_GREEN_SIZE, greenSize, EGL10.EGL_BLUE_SIZE, blueSize, EGL10.EGL_ALPHA_SIZE, alphaSize, EGL10.EGL_DEPTH_SIZE, depthSize, EGL10.EGL_STENCIL_SIZE, stencilSize, EGL10.EGL_NONE});
  910. mValue = new int[1];
  911. mRedSize = redSize;
  912. mGreenSize = greenSize;
  913. mBlueSize = blueSize;
  914. mAlphaSize = alphaSize;
  915. mDepthSize = depthSize;
  916. mStencilSize = stencilSize;
  917. }
  918. @Override
  919. public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs)
  920. {
  921. EGLConfig closestConfig = null;
  922. int closestDistance = 1000;
  923. for (EGLConfig config : configs)
  924. {
  925. int d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0);
  926. int s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0);
  927. if (d >= mDepthSize && s >= mStencilSize)
  928. {
  929. int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0);
  930. int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0);
  931. int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0);
  932. int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0);
  933. int distance = Math.abs(r - mRedSize) + Math.abs(g - mGreenSize) + Math.abs(b - mBlueSize) + Math.abs(a - mAlphaSize);
  934. if (distance < closestDistance)
  935. {
  936. closestDistance = distance;
  937. closestConfig = config;
  938. }
  939. }
  940. }
  941. return closestConfig;
  942. }
  943. private int findConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config, int attribute, int defaultValue)
  944. {
  945. if (egl.eglGetConfigAttrib(display, config, attribute, mValue))
  946. {
  947. return mValue[0];
  948. }
  949. return defaultValue;
  950. }
  951. private int[] mValue;
  952. // Subclasses can adjust these values:
  953. protected int mRedSize;
  954. protected int mGreenSize;
  955. protected int mBlueSize;
  956. protected int mAlphaSize;
  957. protected int mDepthSize;
  958. protected int mStencilSize;
  959. }
  960. /**
  961. * This class will choose a supported surface as close to RGB565 as
  962. * possible, with or without a depth buffer.
  963. *
  964. */
  965. public static class SimpleEGLConfigChooser extends ComponentSizeChooser
  966. {
  967. public SimpleEGLConfigChooser(boolean withDepthBuffer)
  968. {
  969. super(4, 4, 4, 0, withDepthBuffer ? 16 : 0, 0);
  970. // Adjust target values. This way we'll accept a 4444 or
  971. // 555 buffer if there's no 565 buffer available.
  972. mRedSize = 5;
  973. mGreenSize = 6;
  974. mBlueSize = 5;
  975. }
  976. }
  977. }