1 /*
2  * Copyright (c) 2002-2008 LWJGL Project
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'LWJGL' nor the names of
17  *   its contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package org.lwjgl.opengl;
33 
34 import org.lwjgl.LWJGLException;
35 import org.lwjgl.LWJGLUtil;
36 import org.lwjgl.Sys;
37 import org.lwjgl.opengles.EGLContext;
38 import org.lwjgl.opengles.GLContext;
39 import org.lwjgl.opengles.GLES20;
40 import org.lwjgl.opengles.PowerManagementEventException;
41 
42 import static org.lwjgl.opengles.EGL.*;
43 
44 /**
45  * <p/>
46  * Context encapsulates an OpenGL ES context.
47  * <p/>
48  * <p/>
49  * This class is thread-safe.
50  *
51  * @author elias_naur <elias_naur@users.sourceforge.net>
52  * @version $Revision: 3332 $
53  *          $Id: Context.java 3332 2010-04-20 18:21:05Z spasi $
54  */
55 final class ContextGLES implements org.lwjgl.opengl.Context {
56 
57 	/** The current Context */
58 	private static final ThreadLocal<ContextGLES> current_context_local = new ThreadLocal<ContextGLES>();
59 
60 	/** Handle to the native GL rendering context */
61 	private final DrawableGLES drawable;
62 	private final EGLContext  eglContext;
63 
64 	private final org.lwjgl.opengles.ContextAttribs contextAttribs;
65 
66 	/** Whether the context has been destroyed */
67 	private boolean destroyed;
68 
69 	private boolean destroy_requested;
70 
71 	/** The thread that has this context current, or null. */
72 	private Thread thread;
73 
74 	static {
Sys.initialize()75 		Sys.initialize();
76 	}
77 
getEGLContext()78 	public EGLContext getEGLContext() {
79 		return eglContext;
80 	}
81 
getContextAttribs()82 	org.lwjgl.opengles.ContextAttribs getContextAttribs() {
83 		return contextAttribs;
84 	}
85 
getCurrentContext()86 	static ContextGLES getCurrentContext() {
87 		return current_context_local.get();
88 	}
89 
90 	/** Create a context with the specified peer info and shared context */
ContextGLES(DrawableGLES drawable, org.lwjgl.opengles.ContextAttribs attribs, ContextGLES shared_context)91 	ContextGLES(DrawableGLES drawable, org.lwjgl.opengles.ContextAttribs attribs, ContextGLES shared_context) throws LWJGLException {
92 		if ( drawable == null )
93 			throw new IllegalArgumentException();
94 
95 		ContextGLES context_lock = shared_context != null ? shared_context : this;
96 		// If shared_context is not null, synchronize on it to make sure it is not deleted
97 		// while this context is created. Otherwise, simply synchronize on ourself to avoid NPE
98 		synchronized ( context_lock ) {
99 			if ( shared_context != null && shared_context.destroyed )
100 				throw new IllegalArgumentException("Shared context is destroyed");
101 
102 			this.drawable = drawable;
103 			this.contextAttribs = attribs;
104 			this.eglContext = drawable.getEGLDisplay().createContext(drawable.getEGLConfig(),
105 			                                                         shared_context == null ? null : shared_context.eglContext,
106 			                                                         attribs == null ? new org.lwjgl.opengles.ContextAttribs(2).getAttribList() : attribs.getAttribList());
107 		}
108 	}
109 
110 	/** Release the current context (if any). After this call, no context is current. */
releaseCurrent()111 	public void releaseCurrent() throws LWJGLException, PowerManagementEventException {
112 		eglReleaseCurrent(drawable.getEGLDisplay());
113 		org.lwjgl.opengles.GLContext.useContext(null);
114 		current_context_local.set(null);
115 
116 		synchronized ( this ) {
117 			thread = null;
118 			checkDestroy();
119 		}
120 	}
121 
122 	/** Swap the buffers on the current context. Only valid for double-buffered contexts */
swapBuffers()123 	public static void swapBuffers() throws LWJGLException, PowerManagementEventException {
124 		ContextGLES current_context = getCurrentContext();
125 		if ( current_context != null )
126 			current_context.drawable.getEGLSurface().swapBuffers();
127 	}
128 
canAccess()129 	private boolean canAccess() {
130 		return thread == null || Thread.currentThread() == thread;
131 	}
132 
checkAccess()133 	private void checkAccess() {
134 		if ( !canAccess() )
135 			throw new IllegalStateException("From thread " + Thread.currentThread() + ": " + thread + " already has the context current");
136 	}
137 
138 	/** Make the context current */
makeCurrent()139 	public synchronized void makeCurrent() throws LWJGLException, PowerManagementEventException {
140 		checkAccess();
141 		if ( destroyed )
142 			throw new IllegalStateException("Context is destroyed");
143 		thread = Thread.currentThread();
144 		current_context_local.set(this);
145 		eglContext.makeCurrent(drawable.getEGLSurface());
146 		org.lwjgl.opengles.GLContext.useContext(this);
147 	}
148 
149 	/** Query whether the context is current */
isCurrent()150 	public synchronized boolean isCurrent() throws LWJGLException {
151 		if ( destroyed )
152 			throw new IllegalStateException("Context is destroyed");
153 		return eglIsCurrentContext(eglContext);
154 	}
155 
checkDestroy()156 	private void checkDestroy() {
157 		if ( !destroyed && destroy_requested ) {
158 			try {
159 				eglContext.destroy();
160 				destroyed = true;
161 				thread = null;
162 			} catch (LWJGLException e) {
163 				LWJGLUtil.log("Exception occurred while destroying context: " + e);
164 			}
165 		}
166 	}
167 
168 	/**
169 	 * Set the buffer swap interval. This call is a best-attempt at changing
170 	 * the monitor swap interval, which is the minimum periodicity of color buffer swaps,
171 	 * measured in video frame periods, and is not guaranteed to be successful.
172 	 * <p/>
173 	 * A video frame period is the time required to display a full frame of video data.
174 	 */
setSwapInterval(int value)175 	public static void setSwapInterval(int value) {
176 		ContextGLES current_context = getCurrentContext();
177 		if ( current_context != null ) {
178 			try {
179 				current_context.drawable.getEGLDisplay().setSwapInterval(value);
180 			} catch (LWJGLException e) {
181 				LWJGLUtil.log("Failed to set swap interval. Reason: " + e.getMessage());
182 			}
183 		}
184 	}
185 
186 	/**
187 	 * Destroy the context. This method behaves the same as destroy() with the extra
188 	 * requirement that the context must be either current to the current thread or not
189 	 * current at all.
190 	 */
forceDestroy()191 	public synchronized void forceDestroy() throws LWJGLException {
192 		checkAccess();
193 		destroy();
194 	}
195 
196 	/**
197 	 * Request destruction of the Context. If the context is current, no context will be current after this call.
198 	 * The context is destroyed when no thread has it current.
199 	 */
destroy()200 	public synchronized void destroy() throws LWJGLException {
201 		if ( destroyed )
202 			return;
203 		destroy_requested = true;
204 		boolean was_current = isCurrent();
205 		int error = GLES20.GL_NO_ERROR;
206 		if ( was_current ) {
207 			if ( org.lwjgl.opengles.GLContext.getCapabilities() != null && GLContext.getCapabilities().OpenGLES20 )
208 				error = GLES20.glGetError();
209 
210 			try {
211 				releaseCurrent();
212 			} catch (PowerManagementEventException e) {
213 				// Ignore
214 			}
215 		}
216 		checkDestroy();
217 		if ( was_current && error != GLES20.GL_NO_ERROR )
218 			throw new OpenGLException(error);
219 	}
220 
releaseDrawable()221 	public void releaseDrawable() throws LWJGLException {
222 	}
223 
224 }
225