1 /*
2  * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
3  * Copyright (c) 2010 JogAmp Community. 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  * - Redistribution of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * - Redistribution 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 Sun Microsystems, Inc. or the names of
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * This software is provided "AS IS," without a warranty of any kind. ALL
21  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
22  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
23  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
24  * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
25  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
26  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
27  * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
28  * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
29  * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
30  * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
31  * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
32  *
33  * You acknowledge that this software is not designed or intended for use
34  * in the design, construction, operation or maintenance of any nuclear
35  * facility.
36  *
37  * Sun gratefully acknowledges that this software was originally authored
38  * and developed by Kenneth Bradley Russell and Christopher John Kline.
39  */
40 
41 package jogamp.opengl;
42 
43 import java.lang.reflect.Method;
44 import java.nio.IntBuffer;
45 import java.security.AccessController;
46 import java.security.PrivilegedAction;
47 import java.util.HashMap;
48 import java.util.IdentityHashMap;
49 import java.util.Iterator;
50 import java.util.Map;
51 import java.util.Set;
52 
53 import com.jogamp.common.ExceptionUtils;
54 import com.jogamp.common.os.DynamicLookupHelper;
55 import com.jogamp.common.os.Platform;
56 import com.jogamp.common.util.ReflectionUtil;
57 import com.jogamp.common.util.VersionNumber;
58 import com.jogamp.common.util.VersionNumberString;
59 import com.jogamp.common.util.locks.RecursiveLock;
60 import com.jogamp.gluegen.runtime.ProcAddressTable;
61 import com.jogamp.gluegen.runtime.opengl.GLNameResolver;
62 import com.jogamp.gluegen.runtime.opengl.GLProcAddressResolver;
63 import com.jogamp.opengl.GLExtensions;
64 import com.jogamp.opengl.GLRendererQuirks;
65 import com.jogamp.nativewindow.AbstractGraphicsConfiguration;
66 import com.jogamp.nativewindow.AbstractGraphicsDevice;
67 import com.jogamp.nativewindow.NativeSurface;
68 import com.jogamp.nativewindow.NativeWindowFactory;
69 import com.jogamp.nativewindow.ProxySurface;
70 import com.jogamp.nativewindow.egl.EGLGraphicsDevice;
71 import com.jogamp.opengl.GL;
72 import com.jogamp.opengl.GL2ES2;
73 import com.jogamp.opengl.GL2ES3;
74 import com.jogamp.opengl.GL2GL3;
75 import com.jogamp.opengl.GLCapabilitiesImmutable;
76 import com.jogamp.opengl.GLContext;
77 import com.jogamp.opengl.GLDebugListener;
78 import com.jogamp.opengl.GLDebugMessage;
79 import com.jogamp.opengl.GLDrawable;
80 import com.jogamp.opengl.GLDrawableFactory;
81 import com.jogamp.opengl.GLException;
82 import com.jogamp.opengl.GLPipelineFactory;
83 import com.jogamp.opengl.GLProfile;
84 
85 public abstract class GLContextImpl extends GLContext {
86   /**
87    * Context full qualified name: display_type + display_connection + major + minor + ctp.
88    * This is the key for all cached GL ProcAddressTables, etc, to support multi display/device setups.
89    */
90   private String contextFQN;
91 
92   private int additionalCtxCreationFlags;
93 
94   // Cache of the functions that are available to be called at the current
95   // moment in time
96   protected ExtensionAvailabilityCache extensionAvailability;
97   // Table that holds the addresses of the native C-language entry points for
98   // OpenGL functions.
99   private ProcAddressTable glProcAddressTable;
100 
101   private String glVendor;
102   private String glRenderer;
103   private String glRendererLowerCase;
104   private String glVersion;
105   private boolean glGetPtrInit = false;
106   private long glGetStringPtr = 0;
107   private long glGetIntegervPtr = 0;
108 
109   // Tracks lifecycle of buffer objects to avoid
110   // repeated glGet calls upon glMapBuffer operations
111   private final GLBufferObjectTracker bufferObjectTracker;
112   private final GLBufferStateTracker bufferStateTracker;
113   private final GLStateTracker glStateTracker = new GLStateTracker();
114   private GLDebugMessageHandler glDebugHandler = null;
115   private final int[] boundFBOTarget = new int[] { 0, 0 }; // { draw, read }
116   private int defaultVAO = 0;
117 
118   /**
119    * <ul>
120    *   <li>[GLAutoDrawable.upstreamLock].lock()</li>
121    *   <li>drawable.surface.lock()</li>
122    *   <li>contextLock.lock()</li>
123    * </ul>
124    */
125   protected GLDrawableImpl drawable;
126   protected GLDrawableImpl drawableRead;
127 
128   /**
129    * If GL >= 3.0 (ES or desktop) and not having {@link GLRendererQuirks#NoSurfacelessCtx},
130    * being evaluated if not surface-handle is null and not yet set at makeCurrent(..).
131    */
132   private boolean isSurfaceless = false;
133 
134   private boolean pixelDataEvaluated;
135   private int /* pixelDataInternalFormat, */ pixelDataFormat, pixelDataType;
136 
137   private int currentSwapInterval;
138 
139   protected GL gl;
140 
141   protected static final Object mappedContextTypeObjectLock;
142   protected static final HashMap<String, ExtensionAvailabilityCache> mappedExtensionAvailabilityCache;
143   protected static final HashMap<String, ProcAddressTable> mappedGLProcAddress;
144   protected static final HashMap<String, ProcAddressTable> mappedGLXProcAddress;
145 
146   static {
147       mappedContextTypeObjectLock = new Object();
148       mappedExtensionAvailabilityCache = new HashMap<String, ExtensionAvailabilityCache>();
149       mappedGLProcAddress = new HashMap<String, ProcAddressTable>();
150       mappedGLXProcAddress = new HashMap<String, ProcAddressTable>();
151   }
152 
shutdownImpl()153   public static void shutdownImpl() {
154       mappedExtensionAvailabilityCache.clear();
155       mappedGLProcAddress.clear();
156       mappedGLXProcAddress.clear();
157   }
158 
GLContextImpl(final GLDrawableImpl drawable, final GLContext shareWith)159   public GLContextImpl(final GLDrawableImpl drawable, final GLContext shareWith) {
160     super();
161 
162     if( null == drawable ) {
163         throw new IllegalArgumentException("Null drawable");
164     }
165     bufferStateTracker = new GLBufferStateTracker();
166     if ( null != shareWith ) {
167       GLContextShareSet.registerSharing(this, shareWith);
168       bufferObjectTracker = ((GLContextImpl)shareWith).getBufferObjectTracker();
169       if( null == bufferObjectTracker ) {
170           throw new InternalError("shared-master context hash null GLBufferObjectTracker: "+toHexString(shareWith.hashCode()));
171       }
172     } else {
173       bufferObjectTracker = new GLBufferObjectTracker();
174     }
175 
176     this.drawable = drawable;
177     this.drawableRead = drawable;
178 
179     this.glDebugHandler = new GLDebugMessageHandler(this);
180   }
181 
clearStates()182   private final void clearStates() {
183       if( !GLContextShareSet.hasCreatedSharedLeft(this) ) {
184         bufferObjectTracker.clear();
185       }
186       bufferStateTracker.clear();
187       glStateTracker.setEnabled(false);
188       glStateTracker.clearStates();
189   }
190 
191   @Override
resetStates(final boolean isInit)192   protected void resetStates(final boolean isInit) {
193       if( !isInit ) {
194           clearStates();
195       }
196       extensionAvailability = null;
197       glProcAddressTable = null;
198       gl = null;
199       contextFQN = null;
200       additionalCtxCreationFlags = 0;
201 
202       glVendor = "";
203       glRenderer = glVendor;
204       glRendererLowerCase = glRenderer;
205       glVersion = glVendor;
206       glGetPtrInit = false;
207       glGetStringPtr = 0;
208       glGetIntegervPtr = 0;
209 
210       if ( !isInit && null != boundFBOTarget ) { // <init>: boundFBOTarget is not written yet
211           boundFBOTarget[0] = 0; // draw
212           boundFBOTarget[1] = 0; // read
213       }
214 
215       isSurfaceless = false;
216       pixelDataEvaluated = false;
217       currentSwapInterval = 0;
218 
219       super.resetStates(isInit);
220   }
221 
222   @Override
setGLReadDrawable(final GLDrawable read)223   public final GLDrawable setGLReadDrawable(final GLDrawable read) {
224       // Validate constraints first!
225       if(!isGLReadDrawableAvailable()) {
226           throw new GLException("Setting read drawable feature not available");
227       }
228       final Thread currentThread = Thread.currentThread();
229       if( lock.isLockedByOtherThread() ) {
230           throw new GLException("GLContext current by other thread "+lock.getOwner().getName()+", operation not allowed on this thread "+currentThread.getName());
231       }
232       final boolean lockHeld = lock.isOwner(currentThread);
233       if( lockHeld && lock.getHoldCount() > 1 ) {
234           // would need to makeCurrent * holdCount
235           throw new GLException("GLContext is recursively locked - unsupported for setGLDrawable(..)");
236       }
237       if(lockHeld) {
238           release(false);
239       }
240       final GLDrawable old = drawableRead;
241       drawableRead = ( null != read ) ? (GLDrawableImpl) read : drawable;
242       if(lockHeld) {
243           makeCurrent();
244       }
245       return old;
246   }
247 
248   @Override
getGLReadDrawable()249   public final GLDrawable getGLReadDrawable() {
250     return drawableRead;
251   }
252 
253   @Override
setGLDrawable(final GLDrawable readWrite, final boolean setWriteOnly)254   public final GLDrawable setGLDrawable(final GLDrawable readWrite, final boolean setWriteOnly) {
255       // Validate constraints first!
256       final Thread currentThread = Thread.currentThread();
257       if( lock.isLockedByOtherThread() ) {
258           throw new GLException("GLContext current by other thread "+lock.getOwner().getName()+", operation not allowed on this thread "+currentThread.getName());
259       }
260       final boolean lockHeld = lock.isOwner(currentThread);
261       if( lockHeld && lock.getHoldCount() > 1 ) {
262           // would need to makeCurrent * holdCount
263           throw new GLException("GLContext is recursively locked - unsupported for setGLDrawable(..)");
264       }
265       if( drawable == readWrite && ( setWriteOnly || drawableRead == readWrite ) ) {
266           return drawable; // no change.
267       }
268       final GLDrawableImpl oldDrawableWrite = drawable;
269       final GLDrawableImpl oldDrawableRead = drawableRead;
270       if( isCreated() && null != oldDrawableWrite && oldDrawableWrite.isRealized() ) {
271           if(!lockHeld) {
272               makeCurrent();
273           }
274           // sync GL ctx w/ drawable's framebuffer before de-association
275           gl.glFinish();
276           associateDrawable(false);
277           if(!lockHeld) {
278               release(false);
279           }
280       }
281       if(lockHeld) {
282           release(false);
283       }
284       if( !setWriteOnly || drawableRead == drawable ) { // if !setWriteOnly || !explicitReadDrawable
285           drawableRead = (GLDrawableImpl) readWrite;
286       }
287       drawableRetargeted |= null != drawable && readWrite != drawable;
288       drawable = (GLDrawableImpl) readWrite ;
289       if( isCreated() && null != drawable && drawable.isRealized() ) {
290           int res = CONTEXT_NOT_CURRENT;
291           Throwable gle = null;
292           try {
293               res = makeCurrent(true); // implicit: associateDrawable(true)
294           } catch ( final Throwable t ) {
295               gle = t;
296           } finally {
297               if( CONTEXT_NOT_CURRENT == res ) {
298                   // Failure, recover and bail out w/ GLException
299                   drawableRead = oldDrawableRead;
300                   drawable     = oldDrawableWrite;
301                   if( drawable.isRealized() ) {
302                       makeCurrent(true); // implicit: associateDrawable(true)
303                   }
304                   if( !lockHeld ) {
305                       release(false);
306                   }
307                   final String msg = "Error: makeCurrent() failed with new drawable "+readWrite;
308                   if( null != gle ) {
309                       throw new GLException(msg, gle);
310                   } else {
311                       throw new GLException(msg);
312                   }
313               }
314           }
315           if( !lockHeld ) {
316               release(false);
317           }
318       }
319       return oldDrawableWrite;
320   }
321 
322   @Override
getGLDrawable()323   public final GLDrawable getGLDrawable() {
324     return drawable;
325   }
326 
getDrawableImpl()327   public final GLDrawableImpl getDrawableImpl() {
328     return drawable;
329   }
330 
331   @Override
getRootGL()332   public final GL getRootGL() {
333       GL _gl = gl;
334       GL _parent = _gl.getDownstreamGL();
335       while ( null != _parent ) {
336           _gl = _parent;
337           _parent = _gl.getDownstreamGL();
338       }
339       return _gl;
340   }
341 
342   @Override
getGL()343   public final GL getGL() {
344     return gl;
345   }
346 
347   @Override
setGL(final GL gl)348   public GL setGL(final GL gl) {
349     if( DEBUG ) {
350         final String sgl1 = (null!=this.gl)?this.gl.getClass().getSimpleName()+", "+this.gl.toString():"<null>";
351         final String sgl2 = (null!=gl)?gl.getClass().getSimpleName()+", "+gl.toString():"<null>";
352         System.err.println("Info: setGL (OpenGL "+getGLVersion()+"): "+getThreadName()+", "+sgl1+" -> "+sgl2);
353         ExceptionUtils.dumpStack(System.err);
354     }
355     this.gl = gl;
356     return gl;
357   }
358 
359   @Override
getDefaultVAO()360   public final int getDefaultVAO() {
361       return defaultVAO;
362   }
363 
364   /**
365    * Call this method to notify the OpenGL context
366    * that the drawable has changed (size or position).
367    *
368    * <p>
369    * This is currently being used and overridden by Mac OSX,
370    * which issues the {@link jogamp.opengl.macosx.cgl.CGL#updateContext(long) NSOpenGLContext update()} call.
371    * </p>
372    *
373    * @throws GLException
374    */
drawableUpdatedNotify()375   protected void drawableUpdatedNotify() throws GLException { }
376 
getPlatformGLExtensions()377   public abstract Object getPlatformGLExtensions();
378 
379   // Note: the surface is locked within [makeCurrent .. swap .. release]
380   @Override
release()381   public void release() throws GLException {
382     release(false);
383   }
getTraceSwitchMsg()384   private String getTraceSwitchMsg() {
385       final long drawH = null != drawable ? drawable.getHandle() : 0;
386       return "obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+", isShared "+GLContextShareSet.isShared(this)+", surf "+(null!=drawable)+" "+toHexString(drawH)+", "+lock;
387   }
release(final boolean inDestruction)388   private void release(final boolean inDestruction) throws GLException {
389       if( TRACE_SWITCH ) {
390           System.err.println(getThreadName() +": GLContext.ContextSwitch[release.0, inDestruction: "+inDestruction+"]: "+getTraceSwitchMsg());
391       }
392       if ( !lock.isOwner(Thread.currentThread()) ) {
393           final String msg = getThreadName() +": Context not current on thread, inDestruction: "+inDestruction+", "+getTraceSwitchMsg();
394           if( DEBUG_TRACE_SWITCH ) {
395               System.err.println(msg);
396               if( null != lastCtxReleaseStack ) {
397                   System.err.print("Last release call: ");
398                   lastCtxReleaseStack.printStackTrace();
399               } else {
400                   System.err.println("Last release call: NONE");
401               }
402           }
403           throw new GLException(msg);
404       }
405 
406       Throwable drawableContextMadeCurrentException = null;
407       final boolean actualRelease = ( inDestruction || lock.getHoldCount() == 1 ) && 0 != contextHandle;
408       try {
409           if( actualRelease ) {
410               if( !inDestruction ) {
411                   try {
412                       contextMadeCurrent(false);
413                   } catch (final Throwable t) {
414                       drawableContextMadeCurrentException = t;
415                   }
416               }
417               releaseImpl();
418           }
419       } finally {
420           // exception prone ..
421           if( actualRelease ) {
422               setCurrent(null);
423           }
424           lock.unlock();
425           drawable.unlockSurface();
426           if( DEBUG_TRACE_SWITCH ) {
427               final String msg = getThreadName() +": GLContext.ContextSwitch[release.X]: "+(actualRelease?"switch":"keep  ")+" - "+getTraceSwitchMsg();
428               lastCtxReleaseStack = new Throwable(msg);
429               if( TRACE_SWITCH ) {
430                   System.err.println(msg);
431                   // ExceptionUtils.dumpStack(System.err, 0, 10);
432               }
433           }
434       }
435       if(null != drawableContextMadeCurrentException) {
436           throw new GLException("GLContext.release(false) during GLDrawableImpl.contextMadeCurrent(this, false)", drawableContextMadeCurrentException);
437       }
438   }
439   private Throwable lastCtxReleaseStack = null;
releaseImpl()440   protected abstract void releaseImpl() throws GLException;
441 
442   @Override
destroy()443   public final void destroy() {
444       if ( DEBUG_TRACE_SWITCH ) {
445           System.err.println(getThreadName() + ": GLContextImpl.destroy.0: "+getTraceSwitchMsg());
446       }
447       if ( 0 != contextHandle ) { // isCreated() ?
448           if ( null == drawable ) {
449               throw new GLException("GLContext created but drawable is null: "+toString());
450           }
451           final int lockRes = drawable.lockSurface();
452           if ( NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes ) {
453                 // this would be odd ..
454                 throw new GLException("Surface not ready to lock: "+drawable);
455           }
456           Throwable associateDrawableException = null;
457           try {
458               if ( !drawable.isRealized() ) {
459                   throw new GLException("GLContext created but drawable not realized: "+toString());
460               }
461               // Must hold the lock around the destroy operation to make sure we
462               // don't destroy the context while another thread renders to it.
463               lock.lock(); // holdCount++ -> 1 - n (1: not locked, 2-n: destroy while rendering)
464               if ( DEBUG_TRACE_SWITCH ) {
465                   if ( lock.getHoldCount() > 2 ) {
466                       System.err.println(getThreadName() + ": GLContextImpl.destroy: Lock was hold more than once - makeCurrent/release imbalance: "+getTraceSwitchMsg());
467                       ExceptionUtils.dumpStack(System.err);
468                   }
469               }
470               try {
471                   // if not current, makeCurrent(), to call associateDrawable(..) and to disable debug handler
472                   if ( lock.getHoldCount() == 1 ) {
473                       if ( GLContext.CONTEXT_NOT_CURRENT == makeCurrent() ) {
474                           throw new GLException("GLContext.makeCurrent() failed: "+toString());
475                       }
476                   }
477                   try {
478                       associateDrawable(false);
479                   } catch (final Throwable t) {
480                       associateDrawableException = t;
481                   }
482                   if ( 0 != defaultVAO ) {
483                       final int[] tmp = new int[] { defaultVAO };
484                       final GL2ES3 gl2es3 = gl.getRootGL().getGL2ES3();
485                       gl2es3.glBindVertexArray(0);
486                       gl2es3.glDeleteVertexArrays(1, tmp, 0);
487                       defaultVAO = 0;
488                   }
489                   glDebugHandler.enable(false);
490                   if(lock.getHoldCount() > 1) {
491                       // pending release() after makeCurrent()
492                       release(true);
493                   }
494                   destroyImpl();
495                   contextHandle = 0;
496                   glDebugHandler = null;
497                   // this maybe impl. in a platform specific way to release remaining shared ctx.
498                   if( GLContextShareSet.contextDestroyed(this) && !GLContextShareSet.hasCreatedSharedLeft(this) ) {
499                       GLContextShareSet.unregisterSharing(this);
500                   }
501                   resetStates(false);
502               } finally {
503                   lock.unlock();
504                   if ( DEBUG_TRACE_SWITCH ) {
505                       System.err.println(getThreadName() + ": GLContextImpl.destroy.X: "+getTraceSwitchMsg());
506                   }
507               }
508           } finally {
509               drawable.unlockSurface();
510           }
511           if( null != associateDrawableException ) {
512               throw new GLException("Exception @ destroy's associateDrawable(false)", associateDrawableException);
513           }
514       } else {
515           resetStates(false);
516       }
517   }
destroyImpl()518   protected abstract void destroyImpl() throws GLException;
519 
520   @Override
copy(final GLContext source, final int mask)521   public final void copy(final GLContext source, final int mask) throws GLException {
522     if (source.getHandle() == 0) {
523       throw new GLException("Source OpenGL context has not been created");
524     }
525     if (getHandle() == 0) {
526       throw new GLException("Destination OpenGL context has not been created");
527     }
528 
529     final int lockRes = drawable.lockSurface();
530     if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) {
531         // this would be odd ..
532         throw new GLException("Surface not ready to lock");
533     }
534     try {
535         copyImpl(source, mask);
536     } finally {
537       drawable.unlockSurface();
538     }
539   }
copyImpl(GLContext source, int mask)540   protected abstract void copyImpl(GLContext source, int mask) throws GLException;
541 
542   //----------------------------------------------------------------------
543   //
544 
isSurfaceless()545   protected final boolean isSurfaceless() { return isSurfaceless; }
546 
547   /**
548    * {@inheritDoc}
549    * <p>
550    * MakeCurrent functionality, which also issues the creation of the actual OpenGL context.
551    * </p>
552    * The complete callgraph for general OpenGL context creation is:<br>
553    * <ul>
554    *    <li> {@link #makeCurrent} <i>GLContextImpl</i></li>
555    *    <li> {@link #makeCurrentImpl} <i>Platform Implementation</i></li>
556    *    <li> {@link #create} <i>Platform Implementation</i></li>
557    *    <li> If <code>ARB_create_context</code> is supported:
558    *    <ul>
559    *        <li> {@link #createContextARB} <i>GLContextImpl</i></li>
560    *        <li> {@link #createContextARBImpl} <i>Platform Implementation</i></li>
561    *    </ul></li>
562    * </ul><br>
563    *
564    * Once at startup, ie triggered by the singleton constructor of a {@link GLDrawableFactoryImpl} specialization,
565    * calling {@link #createContextARB} will query all available OpenGL versions:<br>
566    * <ul>
567    *    <li> <code>FOR ALL GL* DO</code>:
568    *    <ul>
569    *        <li> {@link #createContextARBMapVersionsAvailable}
570    *        <ul>
571    *            <li> {@link #createContextARBVersions}</li>
572    *        </ul></li>
573    *        <li> {@link #mapVersionAvailable}</li>
574    *    </ul></li>
575    * </ul><br>
576    *
577    * @see #makeCurrentImpl
578    * @see #create
579    * @see #createContextARB
580    * @see #createContextARBImpl
581    * @see #mapVersionAvailable
582    * @see #destroyContextARBImpl
583    */
584   @Override
makeCurrent()585   public final int makeCurrent() throws GLException {
586       return makeCurrent(false);
587   }
588 
makeCurrent(boolean forceDrawableAssociation)589   protected final int makeCurrent(boolean forceDrawableAssociation) throws GLException {
590     final boolean hasDrawable = null != drawable;
591     if( TRACE_SWITCH ) {
592         System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.0]: "+getTraceSwitchMsg());
593     }
594     if( !hasDrawable ) {
595         if( DEBUG_TRACE_SWITCH ) {
596             System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.X0]: NULL Drawable - CONTEXT_NOT_CURRENT - "+getTraceSwitchMsg());
597         }
598         return CONTEXT_NOT_CURRENT;
599     }
600 
601     // Note: the surface is locked within [makeCurrent .. swap .. release]
602     final int lockRes = drawable.lockSurface();
603     if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) {
604         if( DEBUG_TRACE_SWITCH ) {
605             System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.X1]: Surface Not Ready - CONTEXT_NOT_CURRENT - "+getTraceSwitchMsg());
606         }
607         return CONTEXT_NOT_CURRENT;
608     }
609 
610     boolean unlockResources = true; // Must be cleared if successful, otherwise finally block will release context and/or surface!
611     int res = CONTEXT_NOT_CURRENT;
612     try {
613         if ( drawable.isRealized() ) {
614             lock.lock();
615             try {
616                 if ( 0 == drawable.getHandle() && !isSurfaceless ) {
617                     if( DEBUG ) {
618                         System.err.println(getThreadName() +": GLContext.makeCurrent: Surfaceless evaluate");
619                     }
620                     if( hasRendererQuirk(GLRendererQuirks.NoSurfacelessCtx) ) {
621                         throw new GLException(String.format("Surfaceless not supported due to quirk %s: %s",
622                                 GLRendererQuirks.toString(GLRendererQuirks.NoSurfacelessCtx), toString()));
623                     }
624                     // Allow probing if ProxySurface && OPT_UPSTREAM_SURFACELESS
625                     final NativeSurface surface = drawable.getNativeSurface();
626                     if( !(surface instanceof ProxySurface) ||
627                         !((ProxySurface)surface).containsUpstreamOptionBits( ProxySurface.OPT_UPSTREAM_SURFACELESS ) ) {
628                         throw new GLException(String.format("non-surfaceless drawable has zero-handle: %s", drawable.toString()));
629                     }
630                 }
631                 // One context can only be current by one thread,
632                 // and one thread can only have one context current!
633                 final GLContext current = getCurrent();
634                 if (current != null) {
635                     if (current == this) { // implicit recursive locking!
636                         // Assume we don't need to make this context current again
637                         // For Mac OS X, however, we need to update the context to track resizes
638                         drawableUpdatedNotify();
639                         unlockResources = false; // success
640                         if( TRACE_SWITCH ) {
641                             System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.X2]: KEEP - CONTEXT_CURRENT - "+getTraceSwitchMsg());
642                         }
643                         return CONTEXT_CURRENT;
644                     } else {
645                         current.release();
646                     }
647                 }
648                 res = makeCurrentWithinLock(lockRes);
649                 unlockResources = CONTEXT_NOT_CURRENT == res; // success ?
650 
651                 /**
652                  * FIXME: refactor dependence on Java 2D / JOGL bridge
653                     if ( tracker != null && res == CONTEXT_CURRENT_NEW ) {
654                         // Increase reference count of GLObjectTracker
655                         tracker.ref();
656                     }
657                  */
658             } catch (final RuntimeException e) {
659                 unlockResources = true;
660                 throw e;
661             } finally {
662                 if (unlockResources) {
663                     if( DEBUG_TRACE_SWITCH ) {
664                         System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.1]: Context lock.unlock() due to error, res "+makeCurrentResultToString(res)+", "+lock);
665                     }
666                     lock.unlock();
667                 }
668             }
669         } /* if ( drawable.isRealized() ) */
670     } catch (final RuntimeException e) {
671       unlockResources = true;
672       throw e;
673     } finally {
674       if (unlockResources) {
675         drawable.unlockSurface();
676       }
677     }
678 
679     if ( CONTEXT_NOT_CURRENT != res ) { // still locked!
680       if( 0 == drawable.getHandle() && !isSurfaceless ) {
681           if( hasRendererQuirk(GLRendererQuirks.NoSurfacelessCtx) ) {
682               throw new GLException(String.format("Surfaceless not supported due to quirk %s: %s",
683                       GLRendererQuirks.toString(GLRendererQuirks.NoSurfacelessCtx), toString()));
684           }
685           if( DEBUG ) {
686               System.err.println(getThreadName() +": GLContext.makeCurrent: Surfaceless OK - validated");
687           }
688           isSurfaceless = true;
689       }
690       setCurrent(this);
691       if( CONTEXT_CURRENT_NEW == res ) {
692         // check if the drawable's and the GL's GLProfile are equal
693         // throws an GLException if not
694         // FIXME: drawable.getGLProfile().verifyEquality(gl.getGLProfile());
695 
696         glDebugHandler.init( isGLDebugEnabled() );
697 
698         if(DEBUG_GL) {
699             setGL( GLPipelineFactory.create("com.jogamp.opengl.Debug", null, gl, null) );
700             if(glDebugHandler.isEnabled()) {
701                 glDebugHandler.addListener(new GLDebugMessageHandler.StdErrGLDebugListener(true));
702             }
703         }
704         if(TRACE_GL) {
705             setGL( GLPipelineFactory.create("com.jogamp.opengl.Trace", null, gl, new Object[] { System.err } ) );
706         }
707 
708         forceDrawableAssociation = true;
709       }
710 
711       if( forceDrawableAssociation ) {
712           associateDrawable(true);
713       }
714 
715       contextMadeCurrent(true);
716 
717       /* FIXME: refactor dependence on Java 2D / JOGL bridge
718 
719       // Try cleaning up any stale server-side OpenGL objects
720       // FIXME: not sure what to do here if this throws
721       if (deletedObjectTracker != null) {
722         deletedObjectTracker.clean(getGL());
723       }
724       */
725     }
726     if( TRACE_SWITCH ) {
727         System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.X3]: SWITCH - "+makeCurrentResultToString(res)+" - stateTracker.on "+glStateTracker.isEnabled()+" - "+getTraceSwitchMsg());
728     }
729     return res;
730   }
731 
getOtherSharedMaster()732   private final GLContextImpl getOtherSharedMaster() {
733       final GLContextImpl sharedMaster = (GLContextImpl) GLContextShareSet.getSharedMaster(this);
734       return this != sharedMaster ? sharedMaster : null;
735   }
makeCurrentWithinLock(final int surfaceLockRes)736   private final int makeCurrentWithinLock(final int surfaceLockRes) throws GLException {
737       if (!isCreated()) {
738         if( 0 >= drawable.getSurfaceWidth() || 0 >= drawable.getSurfaceHeight() ) {
739             if ( DEBUG_TRACE_SWITCH ) {
740                 System.err.println(getThreadName() + ": Create GL context REJECTED (zero surface size) for " + getClass().getName()+" - "+getTraceSwitchMsg());
741                 System.err.println(drawable.toString());
742             }
743             return CONTEXT_NOT_CURRENT;
744         }
745         if(DEBUG_GL) {
746             // only impacts w/ createContextARB(..)
747             additionalCtxCreationFlags |= GLContext.CTX_OPTION_DEBUG ;
748         }
749 
750         final boolean created;
751         final GLContextImpl sharedMaster = getOtherSharedMaster();
752         if ( null != sharedMaster ) {
753             if ( NativeSurface.LOCK_SURFACE_NOT_READY >= sharedMaster.drawable.lockSurface() ) {
754                 throw new GLException("GLContextShareSet could not lock sharedMaster surface: "+sharedMaster.drawable);
755             }
756         }
757         try {
758             if ( null != sharedMaster ) {
759                 final long sharedMasterHandle = sharedMaster.getHandle();
760                 if ( 0 == sharedMasterHandle ) {
761                     throw new GLException("GLContextShareSet returned an invalid sharedMaster context: "+sharedMaster);
762                 }
763                 created = createImpl(sharedMasterHandle); // may throws exception if fails
764             } else {
765                 created = createImpl(0); // may throws exception if fails
766             }
767             if( created && hasNoDefaultVAO() ) {
768                 final int[] tmp = new int[1];
769                 final GL rootGL = gl.getRootGL();
770                 final GL2ES3 gl2es3 = rootGL.getGL2ES3();
771                 gl2es3.glGenVertexArrays(1, tmp, 0);
772                 defaultVAO = tmp[0];
773                 gl2es3.glBindVertexArray(defaultVAO);
774             }
775         } finally {
776             if ( null != sharedMaster ) {
777                 sharedMaster.drawable.unlockSurface();
778             }
779         }
780         if ( DEBUG_TRACE_SWITCH ) {
781             System.err.println(getThreadName() + ": Create GL context "+(created?"OK":"FAILED")+": For " + getClass().getName()+" - "+getGLVersion()+" - "+getTraceSwitchMsg());
782             // ExceptionUtils.dumpStack(System.err, 0, 10);
783         }
784         if(!created) {
785             return CONTEXT_NOT_CURRENT;
786         }
787 
788         // finalize mapping the available GLVersions, in case it's not done yet
789         {
790             final AbstractGraphicsConfiguration config = drawable.getNativeSurface().getGraphicsConfiguration();
791             final AbstractGraphicsDevice device = config.getScreen().getDevice();
792 
793             // Non ARB desktop profiles may not have been registered
794             if( !GLContext.getAvailableGLVersionsSet(device) ) {        // not yet set
795                 if( 0 == ( ctxOptions & GLContext.CTX_PROFILE_ES) ) {   // not ES profile
796                     final int reqMajor;
797                     final int reqProfile;
798                     if( ctxVersion.compareTo(Version3_0) <= 0 ) {
799                         reqMajor = 2;
800                     } else {
801                         reqMajor = ctxVersion.getMajor();
802                     }
803                     final boolean isCompat;
804                     if( 0 != ( ctxOptions & GLContext.CTX_PROFILE_CORE) ) {
805                         reqProfile = GLContext.CTX_PROFILE_CORE;
806                         isCompat = false;
807                     } else {
808                         reqProfile = GLContext.CTX_PROFILE_COMPAT;
809                         isCompat = true;
810                     }
811                     final MappedGLVersion me = mapAvailableGLVersion(device, reqMajor, reqProfile, ctxVersion, ctxOptions, glRendererQuirks);
812                     // Perform all required profile mappings
813                     if( isCompat ) {
814                         // COMPAT via non ARB
815                         mapAvailableGLVersion(device, reqMajor, GLContext.CTX_PROFILE_CORE, ctxVersion, ctxOptions, glRendererQuirks);
816                         if( reqMajor >= 4 ) {
817                             mapAvailableGLVersion(device, 3, reqProfile, ctxVersion, ctxOptions, glRendererQuirks);
818                             mapAvailableGLVersion(device, 3, GLContext.CTX_PROFILE_CORE, ctxVersion, ctxOptions, glRendererQuirks);
819                         }
820                         if( reqMajor >= 3 ) {
821                             mapAvailableGLVersion(device, 2, reqProfile, ctxVersion, ctxOptions, glRendererQuirks);
822                         }
823                     } else {
824                         // CORE via non ARB, unlikely, however ..
825                         if( reqMajor >= 4 ) {
826                             mapAvailableGLVersion(device, 3, reqProfile, ctxVersion, ctxOptions, glRendererQuirks);
827                         }
828                     }
829                     GLContext.setAvailableGLVersionsSet(device, true);
830 
831                     if (DEBUG) {
832                       System.err.println(getThreadName() + ": createContextOLD-MapGLVersions HAVE: " + me);
833                     }
834                 }
835             }
836         }
837         GLContextShareSet.contextCreated(this);
838         return CONTEXT_CURRENT_NEW;
839       }
840       makeCurrentImpl();
841       return CONTEXT_CURRENT;
842   }
makeCurrentImpl()843   protected abstract void makeCurrentImpl() throws GLException;
844 
845   /**
846    * Calls {@link GLDrawableImpl#associateContext(GLContext, boolean)}
847    */
associateDrawable(final boolean bound)848   protected void associateDrawable(final boolean bound) {
849       drawable.associateContext(this, bound);
850   }
851 
852   /**
853    * Calls {@link GLDrawableImpl#contextMadeCurrent(GLContext, boolean)}
854    */
contextMadeCurrent(final boolean current)855   protected void contextMadeCurrent(final boolean current) {
856       drawable.contextMadeCurrent(this, current);
857   }
858 
859   /**
860    * Platform dependent entry point for context creation.
861    * <p>
862    * This method is called from {@link #makeCurrentWithinLock()} .. {@link #makeCurrent()} .
863    * </p>
864    * <p>
865    * The implementation shall verify this context with a
866    * <code>MakeContextCurrent</code> call.
867    * </p>
868    * <p>
869    * The implementation <b>must</b> leave the context current.
870    * </p>
871    * <p>
872    * Non fatal context creation failure via return {@code false}
873    * is currently implemented for: {@code MacOSXCGLContext}.
874    * </p>
875    * @param sharedWithHandle the shared context handle or 0
876    * @return {@code true} if successful. Method returns {@code false} if the context creation failed non fatally,
877    * hence it may be created at a later time. Otherwise method throws {@link GLException}.
878    * @throws GLException if method fatally fails creating the context and no attempt shall be made at a later time.
879    */
createImpl(long sharedWithHandle)880   protected abstract boolean createImpl(long sharedWithHandle) throws GLException ;
881 
882   /**
883    * Platform dependent but harmonized implementation of the <code>ARB_create_context</code>
884    * mechanism to create a context.<br>
885    *
886    * This method is called from {@link #createContextARB}, {@link #createImpl(long)} .. {@link #makeCurrent()} .<br>
887    *
888    * The implementation shall verify this context with a
889    * <code>MakeContextCurrent</code> call.<br>
890    *
891    * The implementation <b>must</b> leave the context current.<br>
892    *
893    * @param share the shared context or null
894    * @param direct flag if direct is requested
895    * @param ctxOptionFlags <code>ARB_create_context</code> related, see references below
896    * @param major major number
897    * @param minor minor number
898    * @return the valid and current context if successful, or null
899    *
900    * @see #makeCurrent
901    * @see #CTX_PROFILE_COMPAT
902    * @see #CTX_OPTION_FORWARD
903    * @see #CTX_OPTION_DEBUG
904    * @see #makeCurrentImpl
905    * @see #create
906    * @see #createContextARB
907    * @see #createContextARBImpl
908    * @see #destroyContextARBImpl
909    */
createContextARBImpl(long share, boolean direct, int ctxOptionFlags, int major, int minor)910   protected abstract long createContextARBImpl(long share, boolean direct, int ctxOptionFlags, int major, int minor);
911 
912   /**
913    * Destroy the context created by {@link #createContextARBImpl}.
914    *
915    * @see #makeCurrent
916    * @see #makeCurrentImpl
917    * @see #create
918    * @see #createContextARB
919    * @see #createContextARBImpl
920    * @see #destroyContextARBImpl
921    */
destroyContextARBImpl(long context)922   protected abstract void destroyContextARBImpl(long context);
923 
isCreateContextARBAvail(final AbstractGraphicsDevice device)924   protected final boolean isCreateContextARBAvail(final AbstractGraphicsDevice device) {
925     return !GLProfile.disableOpenGLARBContext &&
926            !GLRendererQuirks.existStickyDeviceQuirk(device, GLRendererQuirks.NoARBCreateContext);
927   }
getCreateContextARBAvailStr(final AbstractGraphicsDevice device)928   protected final String getCreateContextARBAvailStr(final AbstractGraphicsDevice device) {
929     final boolean noARBCreateContext = GLRendererQuirks.existStickyDeviceQuirk(device, GLRendererQuirks.NoARBCreateContext);
930     return "disabled "+GLProfile.disableOpenGLARBContext+", quirk "+noARBCreateContext;
931   }
932 
933   /**
934    * Platform independent part of using the <code>ARB_create_context</code>
935    * mechanism to create a context.<br>
936    *
937    * The implementation of {@link #create} shall use this protocol in case the platform supports <code>ARB_create_context</code>.<br>
938    *
939    * This method may call {@link #createContextARBImpl} and {@link #destroyContextARBImpl}. <br>
940    *
941    * This method will also query all available native OpenGL context when first called,<br>
942    * usually the first call should happen with the shared GLContext of the DrawableFactory.<br>
943    *
944    * The implementation makes the context current, if successful<br>
945    *
946    * @see #makeCurrentImpl
947    * @see #create
948    * @see #createContextARB
949    * @see #createContextARBImpl
950    * @see #destroyContextARBImpl
951    */
createContextARB(final long share, final boolean direct)952   protected final long createContextARB(final long share, final boolean direct)
953   {
954     final AbstractGraphicsConfiguration config = drawable.getNativeSurface().getGraphicsConfiguration();
955     final AbstractGraphicsDevice device = config.getScreen().getDevice();
956     final GLCapabilitiesImmutable glCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities();
957     final GLProfile glp = glCaps.getGLProfile();
958 
959     if (DEBUG) {
960       System.err.println(getThreadName() + ": createContextARB-MapGLVersions is SET ("+device.getConnection()+"): "+
961                GLContext.getAvailableGLVersionsSet(device));
962     }
963     if ( !GLContext.getAvailableGLVersionsSet(device) ) {
964         if( !mapGLVersions(device) ) {
965             // none of the ARB context creation calls was successful, bail out
966             return 0;
967         }
968     }
969 
970     final int[] reqMajorCTP = new int[] { 0, 0 };
971     GLContext.getRequestMajorAndCompat(glp, reqMajorCTP);
972 
973     if(DEBUG) {
974         System.err.println(getThreadName() + ": createContextARB-MapGLVersions Requested "+glp+" -> "+GLContext.getGLVersion(reqMajorCTP[0], 0, reqMajorCTP[1], null));
975     }
976     final int _major[] = { 0 };
977     final int _minor[] = { 0 };
978     final int _ctp[] = { 0 };
979     long _ctx = 0;
980     if( GLContext.getAvailableGLVersion(device, reqMajorCTP[0], reqMajorCTP[1],
981                                         _major, _minor, _ctp)) {
982         _ctp[0] |= additionalCtxCreationFlags;
983         if(DEBUG) {
984             System.err.println(getThreadName() + ": createContextARB-MapGLVersions Mapped "+GLContext.getGLVersion(_major[0], _minor[0], _ctp[0], null));
985         }
986         _ctx = createContextARBImpl(share, direct, _ctp[0], _major[0], _minor[0]);
987         if(0!=_ctx) {
988             if( !setGLFunctionAvailability(true, _major[0], _minor[0], _ctp[0], false /* strictMatch */, false /* withinGLVersionsMapping */) ) {
989                 throw new InternalError("setGLFunctionAvailability !strictMatch failed");
990             }
991         }
992     }
993     return _ctx;
994   }
995 
996   //----------------------------------------------------------------------
997   //
998 
999   public static class MappedGLVersion {
1000       public final AbstractGraphicsDevice device;
1001       public final int reqMajorVersion;
1002       public final int reqProfile;
1003       public final VersionNumber ctxVersion;
1004       public final int ctxOptions;
1005       public final GLRendererQuirks quirks;
1006       public final VersionNumber preCtxVersion;
1007       public final int preCtxOptions;
MappedGLVersion(final AbstractGraphicsDevice device, final int reqMajorVersion, final int reqProfile, final VersionNumber ctxVersion, final int ctxOptions, final GLRendererQuirks quirks, final VersionNumber preCtxVersion, final int preCtxOptions)1008       public MappedGLVersion(final AbstractGraphicsDevice device, final int reqMajorVersion, final int reqProfile,
1009                              final VersionNumber ctxVersion, final int ctxOptions, final GLRendererQuirks quirks,
1010                              final VersionNumber preCtxVersion, final int preCtxOptions) {
1011           this.device = device;
1012           this.reqMajorVersion = reqMajorVersion;
1013           this.reqProfile = reqProfile;
1014           this.ctxVersion = ctxVersion;
1015           this.ctxOptions = ctxOptions;
1016           this.quirks = quirks;
1017           this.preCtxVersion = preCtxVersion;
1018           this.preCtxOptions = preCtxOptions;
1019       }
toString()1020       public final String toString() {
1021           return toString(new StringBuilder(), -1, -1, -1, -1).toString();
1022       }
toString(final StringBuilder sb, final int minMajor, final int minMinor, final int maxMajor, final int maxMinor)1023       public final StringBuilder toString(final StringBuilder sb, final int minMajor, final int minMinor, final int maxMajor, final int maxMinor) {
1024           sb.append(device.toString()).append(" ").append(reqMajorVersion).append(" (");
1025           GLContext.getGLProfile(sb, reqProfile).append(")");
1026           if( minMajor >=0 && minMinor >=0 && maxMajor >= 0 && maxMinor >= 0) {
1027               sb.append("[").append(minMajor).append(".").append(minMinor).append(" .. ").append(maxMajor).append(".").append(maxMinor).append("]");
1028           }
1029           sb.append(": [");
1030           if( null != preCtxVersion ) {
1031               GLContext.getGLVersion(sb, preCtxVersion, preCtxOptions, null);
1032           } else {
1033               sb.append("None");
1034           }
1035           sb.append("] -> [");
1036           GLContext.getGLVersion(sb, ctxVersion, ctxOptions, null).append("]");
1037           return sb;
1038       }
1039   }
1040   public static interface MappedGLVersionListener {
glVersionMapped(final MappedGLVersion e)1041       void glVersionMapped(final MappedGLVersion e);
1042   }
1043   private static MappedGLVersionListener mapGLVersionListener = null;
setMappedGLVersionListener(final MappedGLVersionListener mvl)1044   protected static synchronized void setMappedGLVersionListener(final MappedGLVersionListener mvl) {
1045       mapGLVersionListener = mvl;
1046   }
1047 
1048   /**
1049    * Called by {@link jogamp.opengl.GLContextImpl#createContextARBMapVersionsAvailable(int,int)} not intended to be used by
1050    * implementations. However, if {@link jogamp.opengl.GLContextImpl#createContextARB(long, boolean)} is not being used within
1051    * {@link com.jogamp.opengl.GLDrawableFactory#getOrCreateSharedContext(com.jogamp.nativewindow.AbstractGraphicsDevice)},
1052    * GLProfile has to map the available versions.
1053    *
1054    * @param reqMajor Key Value either 1, 2, 3 or 4
1055    * @param profile Key Value either {@link #CTX_PROFILE_COMPAT}, {@link #CTX_PROFILE_CORE} or {@link #CTX_PROFILE_ES}
1056    * @param resVersion the resulting version number
1057    * @param resCtp the resulting context options
1058    * @return the old mapped value
1059    *
1060    * @see #createContextARBMapVersionsAvailable
1061    */
mapAvailableGLVersion(final AbstractGraphicsDevice device, final int reqMajor, final int profile, final VersionNumber resVersion, final int resCtp, final GLRendererQuirks resQuirks)1062   protected static MappedGLVersion mapAvailableGLVersion(final AbstractGraphicsDevice device,
1063                                                            final int reqMajor, final int profile,
1064                                                            final VersionNumber resVersion, final int resCtp, final GLRendererQuirks resQuirks)
1065   {
1066       @SuppressWarnings("deprecation")
1067       final Integer preVal = mapAvailableGLVersion(device, reqMajor, profile, resVersion.getMajor(), resVersion.getMinor(), resCtp);
1068       final int[] preCtp = { 0 };
1069       final VersionNumber preVersion = null != preVal ? decomposeBits(preVal.intValue(), preCtp) : null;
1070       final MappedGLVersion res = new MappedGLVersion(device, reqMajor, profile, resVersion, resCtp, resQuirks, preVersion, preCtp[0]);
1071       if( null != mapGLVersionListener ) {
1072           mapGLVersionListener.glVersionMapped(res);
1073       }
1074       return res;
1075   }
1076 
remapAvailableGLVersions(final AbstractGraphicsDevice fromDevice, final AbstractGraphicsDevice toDevice)1077   protected static void remapAvailableGLVersions(final AbstractGraphicsDevice fromDevice, final AbstractGraphicsDevice toDevice) {
1078     if( fromDevice == toDevice || fromDevice.getUniqueID() == toDevice.getUniqueID() ) {
1079         return; // NOP
1080     }
1081     synchronized(deviceVersionAvailable) {
1082         if(DEBUG) {
1083             System.err.println(getThreadName() + ": createContextARB-MapGLVersions REMAP "+fromDevice+" -> "+toDevice);
1084         }
1085         final IdentityHashMap<String, Integer> newDeviceVersionAvailable = new IdentityHashMap<String, Integer>();
1086         final Set<String> keys = deviceVersionAvailable.keySet();
1087         for(final Iterator<String> keyI = keys.iterator(); keyI.hasNext(); ) {
1088             final String origKey = keyI.next();
1089             final Integer valI = deviceVersionAvailable.get(origKey);
1090             if( null != valI ) {
1091                 if(DEBUG) {
1092                     final int[] ctp = { 0 };
1093                     final VersionNumber version = decomposeBits(valI.intValue(), ctp);
1094                     System.err.println(" MapGLVersions REMAP OLD "+origKey+" -> "+GLContext.getGLVersion(new StringBuilder(), version, ctp[0], null).toString());
1095                 }
1096                 newDeviceVersionAvailable.put(origKey, valI);
1097                 final int devSepIdx = origKey.lastIndexOf('-');
1098                 if( 0 >= devSepIdx ) {
1099                     throw new InternalError("device-separator '-' at "+devSepIdx+" of "+origKey);
1100                 }
1101                 final String devUniqueID = origKey.substring(0, devSepIdx);
1102                 if( fromDevice.getUniqueID().equals(devUniqueID) ) {
1103                     final String profileReq = origKey.substring(devSepIdx);
1104                     final String newKey = (toDevice.getUniqueID()+profileReq).intern();
1105                     if(DEBUG) {
1106                         System.err.println(" MapGLVersions REMAP NEW "+newKey+" -> (ditto)");
1107                     }
1108                     newDeviceVersionAvailable.put(newKey, valI);
1109                 }
1110             }
1111         }
1112         deviceVersionAvailable.clear();
1113         deviceVersionAvailable.putAll(newDeviceVersionAvailable);
1114         GLContext.setAvailableGLVersionsSet(toDevice, true);
1115     }
1116   }
1117 
mapGLVersions(final AbstractGraphicsDevice device)1118   private final boolean mapGLVersions(final AbstractGraphicsDevice device) {
1119     synchronized (GLContext.deviceVersionAvailable) {
1120         final boolean hasOpenGLESSupport = drawable.getFactory().hasOpenGLESSupport();
1121         final boolean hasOpenGLDesktopSupport = drawable.getFactory().hasOpenGLDesktopSupport();
1122         final boolean hasMinorVersionSupport = drawable.getFactoryImpl().hasMajorMinorCreateContextARB();
1123         if (DEBUG) {
1124             System.err.println(getThreadName() + ": createContextARB-MapGLVersions START (GLDesktop "+hasOpenGLDesktopSupport+", GLES "+hasOpenGLESSupport+", minorVersion "+hasMinorVersionSupport+") on "+device);
1125         }
1126         final long t0 = ( DEBUG ) ? System.nanoTime() : 0;
1127         boolean success = false;
1128         // Following GLProfile.GL_PROFILE_LIST_ALL order of profile detection { GL4bc, GL3bc, GL2, GL4, GL3, GL2GL3, GLES2, GL2ES2, GLES1, GL2ES1 }
1129         boolean hasGL4bc = false;
1130         boolean hasGL3bc = false;
1131         boolean hasGL2   = false;
1132         boolean hasGL4   = false;
1133         boolean hasGL3   = false;
1134         boolean hasES3   = false;
1135         boolean hasES2   = false;
1136         boolean hasES1   = false;
1137 
1138         if( hasOpenGLESSupport && !GLProfile.disableOpenGLES ) {
1139             if( !hasES3) {
1140                 hasES3   = createContextARBMapVersionsAvailable(device, 3, CTX_PROFILE_ES, hasMinorVersionSupport);    // ES3
1141                 success |= hasES3;
1142                 if( hasES3 ) {
1143                     if( 0 == ( CTX_IMPL_ACCEL_SOFT & ctxOptions ) ) {
1144                         // Map hw-accel ES3 to all lower core profiles: ES2
1145                         mapAvailableGLVersion(device, 2, CTX_PROFILE_ES, ctxVersion, ctxOptions, glRendererQuirks);
1146                         if( PROFILE_ALIASING ) {
1147                             hasES2   = true;
1148                         }
1149                     }
1150                     resetStates(false); // clean context states, since creation was temporary
1151                 }
1152             }
1153             if( !hasES2) {
1154                 hasES2   = createContextARBMapVersionsAvailable(device, 2, CTX_PROFILE_ES, hasMinorVersionSupport);    // ES2
1155                 success |= hasES2;
1156                 if( hasES2 ) {
1157                     if( ctxVersion.getMajor() >= 3 && hasRendererQuirk(GLRendererQuirks.GLES3ViaEGLES2Config)) {
1158                         mapAvailableGLVersion(device, 3, CTX_PROFILE_ES, ctxVersion, ctxOptions, glRendererQuirks);
1159                     }
1160                     resetStates(false); // clean context states, since creation was temporary
1161                 }
1162             }
1163             if( !hasES1) {
1164                 hasES1   = createContextARBMapVersionsAvailable(device, 1, CTX_PROFILE_ES, hasMinorVersionSupport);    // ES1
1165                 success |= hasES1;
1166                 if( hasES1 ) {
1167                     resetStates(false); // clean context states, since creation was temporary
1168                 }
1169             }
1170         }
1171 
1172         // Even w/ PROFILE_ALIASING, try to use true core GL profiles
1173         // ensuring proper user behavior across platforms due to different feature sets!
1174         //
1175         if( Platform.OSType.MACOS == Platform.getOSType() &&
1176             Platform.getOSVersionNumber().compareTo(Platform.OSXVersion.Mavericks) >= 0 ) {
1177             /**
1178              * OSX 10.9 GLRendererQuirks.GL4NeedsGL3Request, quirk is added as usual @ setRendererQuirks(..)
1179              */
1180             if( hasOpenGLDesktopSupport && !GLProfile.disableOpenGLDesktop && !GLProfile.disableOpenGLCore && !hasGL4 && !hasGL3 ) {
1181                 hasGL3   = createContextARBMapVersionsAvailable(device, 3, CTX_PROFILE_CORE, hasMinorVersionSupport);    // GL3
1182                 success |= hasGL3;
1183                 if( hasGL3 ) {
1184                     final boolean isHWAccel = 0 == ( CTX_IMPL_ACCEL_SOFT & ctxOptions );
1185                     if( isHWAccel && ctxVersion.getMajor() >= 4 ) {
1186                         // Gotcha: Creating a '3.2' ctx delivers a >= 4 ctx.
1187                         mapAvailableGLVersion(device, 4, CTX_PROFILE_CORE, ctxVersion, ctxOptions, glRendererQuirks);
1188                         hasGL4   = true;
1189                         if(DEBUG) {
1190                             System.err.println(getThreadName() + ": createContextARB-MapGLVersions: Quirk Triggerd: "+GLRendererQuirks.toString(GLRendererQuirks.GL4NeedsGL3Request)+": cause: OS "+Platform.getOSType()+", OS Version "+Platform.getOSVersionNumber());
1191                         }
1192                     }
1193                     resetStates(false); // clean the context states, since creation was temporary
1194                 }
1195             }
1196         }
1197         if( hasOpenGLDesktopSupport && !GLProfile.disableOpenGLDesktop && !GLProfile.disableOpenGLCore ) {
1198             if( !hasGL4 ) {
1199                 hasGL4   = createContextARBMapVersionsAvailable(device, 4, CTX_PROFILE_CORE, hasMinorVersionSupport);    // GL4
1200                 success |= hasGL4;
1201                 if( hasGL4 ) {
1202                     if( 0 == ( CTX_IMPL_ACCEL_SOFT & ctxOptions ) ) {
1203                         // Map hw-accel GL4 to all lower core profiles: GL3
1204                         mapAvailableGLVersion(device, 3, CTX_PROFILE_CORE, ctxVersion, ctxOptions, glRendererQuirks);
1205                         if( PROFILE_ALIASING ) {
1206                             hasGL3   = true;
1207                         }
1208                     }
1209                     resetStates(false); // clean context states, since creation was temporary
1210                 }
1211             }
1212             if( !hasGL3 ) {
1213                 hasGL3   = createContextARBMapVersionsAvailable(device, 3, CTX_PROFILE_CORE, hasMinorVersionSupport);    // GL3
1214                 success |= hasGL3;
1215                 if( hasGL3 ) {
1216                     resetStates(false); // clean this context states, since creation was temporary
1217                 }
1218             }
1219         }
1220         if( hasOpenGLDesktopSupport && !GLProfile.disableOpenGLDesktop ) {
1221             if( !hasGL4bc ) {
1222                 hasGL4bc = createContextARBMapVersionsAvailable(device, 4, CTX_PROFILE_COMPAT, hasMinorVersionSupport);  // GL4bc
1223                 success |= hasGL4bc;
1224                 if( hasGL4bc ) {
1225                     if( !hasGL4 ) { // last chance .. ignore hw-accel
1226                         mapAvailableGLVersion(device, 4, CTX_PROFILE_CORE, ctxVersion, ctxOptions, glRendererQuirks);
1227                         hasGL4   = true;
1228                     }
1229                     if( !hasGL3 ) { // last chance .. ignore hw-accel
1230                         mapAvailableGLVersion(device, 3, CTX_PROFILE_CORE, ctxVersion, ctxOptions, glRendererQuirks);
1231                         hasGL3   = true;
1232                     }
1233                     if( 0 == ( CTX_IMPL_ACCEL_SOFT & ctxOptions ) ) {
1234                         // Map hw-accel GL4bc to all lower compatible profiles: GL3bc, GL2
1235                         mapAvailableGLVersion(device, 3, CTX_PROFILE_COMPAT, ctxVersion, ctxOptions, glRendererQuirks);
1236                         mapAvailableGLVersion(device, 2, CTX_PROFILE_COMPAT, ctxVersion, ctxOptions, glRendererQuirks);
1237                         if(PROFILE_ALIASING) {
1238                             hasGL3bc = true;
1239                             hasGL2   = true;
1240                         }
1241                     }
1242                     resetStates(false); // clean this context states, since creation was temporary
1243                 }
1244             }
1245             if( !hasGL3bc ) {
1246                 hasGL3bc = createContextARBMapVersionsAvailable(device, 3, CTX_PROFILE_COMPAT, hasMinorVersionSupport);  // GL3bc
1247                 success |= hasGL3bc;
1248                 if( hasGL3bc ) {
1249                     if(!hasGL3) {  // last chance .. ignore hw-accel
1250                         mapAvailableGLVersion(device, 3, CTX_PROFILE_CORE, ctxVersion, ctxOptions, glRendererQuirks);
1251                         hasGL3   = true;
1252                     }
1253                     if( 0 == ( CTX_IMPL_ACCEL_SOFT & ctxOptions ) ) {
1254                         // Map hw-accel GL3bc to all lower compatible profiles: GL2
1255                         mapAvailableGLVersion(device, 2, CTX_PROFILE_COMPAT, ctxVersion, ctxOptions, glRendererQuirks);
1256                         if(PROFILE_ALIASING) {
1257                             hasGL2   = true;
1258                         }
1259                     }
1260                     resetStates(false); // clean this context states, since creation was temporary
1261                 }
1262             }
1263             if( !hasGL2 ) {
1264                 hasGL2   = createContextARBMapVersionsAvailable(device, 2, CTX_PROFILE_COMPAT, hasMinorVersionSupport);  // GL2
1265                 success |= hasGL2;
1266                 if( hasGL2 ) {
1267                     resetStates(false); // clean this context states, since creation was temporary
1268                 }
1269             }
1270         }
1271         if(success) {
1272             // only claim GL versions set [and hence detected] if ARB context creation was successful
1273             GLContext.setAvailableGLVersionsSet(device, true);
1274         }
1275         if(DEBUG) {
1276             final long t1 = System.nanoTime();
1277             System.err.println(getThreadName() + ": createContextARB-MapGLVersions END (success "+success+") on "+device+", profileAliasing: "+PROFILE_ALIASING+", total "+(t1-t0)/1e6 +"ms");
1278             if( success ) {
1279                 System.err.println(GLContext.dumpAvailableGLVersions(null).toString());
1280             }
1281         }
1282         return success;
1283     }
1284   }
1285 
1286   /**
1287    * Note: Since context creation is temporary, caller need to issue {@link #resetStates(boolean)}, if creation was successful, i.e. returns true.
1288    * This method does not reset the states, allowing the caller to utilize the state variables.
1289    **/
createContextARBMapVersionsAvailable(final AbstractGraphicsDevice device, final int reqMajor, final int reqProfile, final boolean hasMinorVersionSupport)1290   private final boolean createContextARBMapVersionsAvailable(final AbstractGraphicsDevice device, final int reqMajor, final int reqProfile,
1291                                                              final boolean hasMinorVersionSupport) {
1292     long _context;
1293     int ctp = CTX_IS_ARB_CREATED | reqProfile;
1294 
1295     // To ensure GL profile compatibility within the JOGL application
1296     // we always try to map against the highest GL version,
1297     // so the user can always cast to the highest available one.
1298     int maxMajor, maxMinor;
1299     int minMajor, minMinor;
1300     final int major[] = new int[1];
1301     final int minor[] = new int[1];
1302 
1303     if( hasMinorVersionSupport ) {
1304         if( CTX_PROFILE_ES == reqProfile ) {
1305             // ES3, ES2 or ES1
1306             maxMajor=reqMajor; maxMinor=GLContext.getMaxMinor(ctp, maxMajor);
1307             minMajor=reqMajor; minMinor=0;
1308         } else {
1309             if( 4 == reqMajor ) {
1310                 maxMajor=4; maxMinor=GLContext.getMaxMinor(ctp, maxMajor);
1311                 minMajor=4; minMinor=0;
1312             } else if( 3 == reqMajor ) {
1313                 maxMajor=3; maxMinor=GLContext.getMaxMinor(ctp, maxMajor);
1314                 minMajor=3; minMinor=1;
1315             } else /* if( glp.isGL2() ) */ {
1316                 // our minimum desktop OpenGL runtime requirements are 1.1,
1317                 // nevertheless we restrict ARB context creation to 2.0 to spare us futile attempts
1318                 maxMajor=3; maxMinor=0;
1319                 minMajor=2; minMinor=0;
1320             }
1321         }
1322     } else {
1323         if( CTX_PROFILE_ES == reqProfile ) {
1324             // ES3, ES2 or ES1
1325             maxMajor=reqMajor; maxMinor=0;
1326             minMajor=reqMajor; minMinor=0;
1327         } else {
1328             if( 4 == reqMajor ) {
1329                 maxMajor=4; maxMinor=0;
1330                 minMajor=4; minMinor=0;
1331             } else if( 3 == reqMajor ) {
1332                 maxMajor=3; maxMinor=1;
1333                 minMajor=3; minMinor=1;
1334             } else /* if( glp.isGL2() ) */ {
1335                 // our minimum desktop OpenGL runtime requirements are 1.1,
1336                 // nevertheless we restrict ARB context creation to 2.0 to spare us futile attempts
1337                 maxMajor=2; maxMinor=0;
1338                 minMajor=2; minMinor=0;
1339             }
1340         }
1341     }
1342     _context = createContextARBVersions(0, true, ctp,
1343                                         /* max */ maxMajor, maxMinor,
1344                                         /* min */ minMajor, minMinor,
1345                                         /* res */ major, minor);
1346 
1347     if( 0 == _context && CTX_PROFILE_CORE == reqProfile && !PROFILE_ALIASING ) {
1348         // try w/ FORWARD instead of CORE
1349         ctp &= ~CTX_PROFILE_CORE ;
1350         ctp |=  CTX_OPTION_FORWARD ;
1351         _context = createContextARBVersions(0, true, ctp,
1352                                             /* max */ maxMajor, maxMinor,
1353                                             /* min */ minMajor, minMinor,
1354                                             /* res */ major, minor);
1355        if( 0 == _context ) {
1356             // Try a compatible one .. even though not requested .. last resort
1357             ctp &= ~CTX_PROFILE_CORE ;
1358             ctp &= ~CTX_OPTION_FORWARD ;
1359             ctp |=  CTX_PROFILE_COMPAT ;
1360             _context = createContextARBVersions(0, true, ctp,
1361                                        /* max */ maxMajor, maxMinor,
1362                                        /* min */ minMajor, minMinor,
1363                                        /* res */ major, minor);
1364        }
1365     }
1366     final boolean res;
1367     if( 0 != _context ) {
1368         // ctxMajorVersion, ctxMinorVersion, ctxOptions is being set by
1369         //   createContextARBVersions(..) -> setGLFunctionAvailbility(..) -> setContextVersion(..)
1370         final MappedGLVersion me = mapAvailableGLVersion(device, reqMajor, reqProfile, ctxVersion, ctxOptions, glRendererQuirks);
1371         destroyContextARBImpl(_context);
1372         if (DEBUG) {
1373           System.err.println(getThreadName() + ": createContextARB-MapGLVersions HAVE "+me.toString(new StringBuilder(), minMajor, minMinor, maxMajor, maxMinor).toString());
1374         }
1375         res = true;
1376     } else {
1377         if (DEBUG) {
1378           System.err.println(getThreadName() + ": createContextARB-MapGLVersions NOPE "+device+", "+reqMajor+" ("+GLContext.getGLProfile(new StringBuilder(), reqProfile).toString()+ ") ["+maxMajor+"."+maxMinor+" .. "+minMajor+"."+minMinor+"]");
1379         }
1380         res = false;
1381     }
1382     return res;
1383   }
1384 
createContextARBVersions(final long share, final boolean direct, final int ctxOptionFlags, final int maxMajor, final int maxMinor, final int minMajor, final int minMinor, final int major[], final int minor[])1385   private final long createContextARBVersions(final long share, final boolean direct, final int ctxOptionFlags,
1386                                               final int maxMajor, final int maxMinor,
1387                                               final int minMajor, final int minMinor,
1388                                               final int major[], final int minor[]) {
1389     major[0]=maxMajor;
1390     minor[0]=maxMinor;
1391     long _context=0;
1392     int i=0;
1393 
1394     do {
1395         if (DEBUG) {
1396             i++;
1397             System.err.println(getThreadName() + ": createContextARBVersions."+i+": share "+share+", direct "+direct+
1398                     ", version "+major[0]+"."+minor[0]+" ["+maxMajor+"."+maxMinor+" .. "+minMajor+"."+minMinor+"]");
1399         }
1400         _context = createContextARBImpl(share, direct, ctxOptionFlags, major[0], minor[0]);
1401 
1402         if(0 != _context) {
1403             if( setGLFunctionAvailability(true, major[0], minor[0], ctxOptionFlags, true /* strictMatch */, true /* withinGLVersionsMapping */) ) {
1404                 break;
1405             } else {
1406                 destroyContextARBImpl(_context);
1407                 _context = 0;
1408             }
1409         }
1410 
1411     } while ( ( major[0]>minMajor || major[0]==minMajor && minor[0] >minMinor ) &&  // #1 check whether version is above lower limit
1412               GLContext.decrementGLVersion(ctxOptionFlags, major, minor)            // #2 decrement version
1413             );
1414     if (DEBUG) {
1415         System.err.println(getThreadName() + ": createContextARBVersions.X: ctx "+toHexString(_context)+", share "+share+", direct "+direct+
1416                 ", version "+major[0]+"."+minor[0]+" ["+maxMajor+"."+maxMinor+" .. "+minMajor+"."+minMinor+"]");
1417     }
1418     return _context;
1419   }
1420 
1421   //----------------------------------------------------------------------
1422   // Managing the actual OpenGL version, usually figured at creation time.
1423   // As a last resort, the GL_VERSION string may be used ..
1424   //
1425 
1426   /**
1427    * If major > 0 || minor > 0 : Use passed values, determined at creation time
1428    * Otherwise .. don't touch ..
1429    */
setContextVersion(final int major, final int minor, final int ctp, final VersionNumberString glVendorVersion, final boolean useGL)1430   private final void setContextVersion(final int major, final int minor, final int ctp, final VersionNumberString glVendorVersion, final boolean useGL) {
1431       if ( 0 == ctp ) {
1432         throw new GLException("Invalid GL Version "+major+"."+minor+", ctp "+toHexString(ctp));
1433       }
1434       ctxVersion = new VersionNumber(major, minor, 0);
1435       ctxVersionString = getGLVersion(major, minor, ctp, glVersion);
1436       ctxVendorVersion = glVendorVersion;
1437       ctxOptions = ctp;
1438       if(useGL) {
1439           ctxGLSLVersion = VersionNumber.zeroVersion;
1440           if( hasGLSL() ) { // >= ES2 || GL2.0
1441               final String glslVersion = isGLES() ? null : gl.glGetString(GL2ES2.GL_SHADING_LANGUAGE_VERSION) ; // Use static GLSL version for ES to be safe!
1442               if( null != glslVersion ) {
1443                   ctxGLSLVersion = new VersionNumber(glslVersion);
1444                   if( ctxGLSLVersion.getMajor() < 1 ) {
1445                       ctxGLSLVersion = VersionNumber.zeroVersion; // failed ..
1446                   }
1447               }
1448               if( ctxGLSLVersion.isZero() ) {
1449                   ctxGLSLVersion = getStaticGLSLVersionNumber(major, minor, ctxOptions);
1450               }
1451           }
1452       }
1453   }
1454 
1455   //----------------------------------------------------------------------
1456   // Helpers for various context implementations
1457   //
1458 
verifyInstance(final GLProfile glp, final String suffix, final Object instance)1459   private final boolean verifyInstance(final GLProfile glp, final String suffix, final Object instance) {
1460       return ReflectionUtil.instanceOf(instance, glp.getGLImplBaseClassName()+suffix);
1461   }
createInstance(final AbstractGraphicsDevice adevice, final int majorVersion, final int minorVersion, final int contextOption, final boolean glObject, final Object[] cstrArgs)1462   private final Object createInstance(final AbstractGraphicsDevice adevice, final int majorVersion, final int minorVersion, final int contextOption,
1463                                       final boolean glObject, final Object[] cstrArgs) {
1464       final String profileString = GLContext.getGLProfile(majorVersion, minorVersion, contextOption);
1465       final GLProfile glp = GLProfile.get(adevice, profileString) ;
1466       return ReflectionUtil.createInstance(glp.getGLCtor(glObject), cstrArgs);
1467   }
verifyInstance(final AbstractGraphicsDevice adevice, final int majorVersion, final int minorVersion, final int contextOption, final String suffix, final Object instance)1468   private final boolean verifyInstance(final AbstractGraphicsDevice adevice, final int majorVersion, final int minorVersion, final int contextOption,
1469                                        final String suffix, final Object instance) {
1470       final String profileString = GLContext.getGLProfile(majorVersion, minorVersion, contextOption);
1471       final GLProfile glp = GLProfile.get(adevice, profileString) ;
1472       return ReflectionUtil.instanceOf(instance, glp.getGLImplBaseClassName()+suffix);
1473   }
1474 
1475   /**
1476    * Create the GL instance for this context,
1477    * requires valid {@link #getGLProcAddressTable()} result!
1478    */
createGL(final AbstractGraphicsDevice adevice, final int majorVersion, final int minorVersion, final int contextOption)1479   private final GL createGL(final AbstractGraphicsDevice adevice, final int majorVersion, final int minorVersion, final int contextOption) {
1480     final String profileString = GLContext.getGLProfile(majorVersion, minorVersion, contextOption);
1481     final GLProfile glp = GLProfile.get(adevice, profileString);
1482     final GL gl = (GL) ReflectionUtil.createInstance(glp.getGLCtor(true), new Object[] { glp, this });
1483     //nal GL gl = (GL) createInstance(glp, true, new Object[] { glp, this } );
1484 
1485     /* FIXME: refactor dependence on Java 2D / JOGL bridge
1486     if (tracker != null) {
1487       gl.setObjectTracker(tracker);
1488     }
1489     */
1490     return gl;
1491   }
1492 
1493   /**
1494    * Finalizes GL instance initialization after this context has been initialized.
1495    * <p>
1496    * Method calls 'void finalizeInit()' of instance 'gl' as retrieved by reflection, if exist.
1497    * </p>
1498    */
finalizeInit(final GL gl)1499   private void finalizeInit(final GL gl) {
1500       Method finalizeInit = null;
1501       try {
1502           finalizeInit = ReflectionUtil.getMethod(gl.getClass(), "finalizeInit", new Class<?>[]{ });
1503       } catch ( final Throwable t ) {
1504           if(DEBUG) {
1505               System.err.println("Caught "+t.getClass().getName()+": "+t.getMessage());
1506               t.printStackTrace();
1507           }
1508       }
1509       if( null != finalizeInit ) {
1510           ReflectionUtil.callMethod(gl, finalizeInit, new Object[]{ });
1511       } else {
1512           throw new InternalError("Missing 'void finalizeInit(ProcAddressTable)' in "+gl.getClass().getName());
1513       }
1514   }
1515 
getGLProcAddressTable()1516   public final ProcAddressTable getGLProcAddressTable() {
1517     return glProcAddressTable;
1518   }
1519 
1520   /**
1521    * Shall return the platform extension ProcAddressTable,
1522    * ie for GLXExt, EGLExt, ..
1523    */
getPlatformExtProcAddressTable()1524   public abstract ProcAddressTable getPlatformExtProcAddressTable();
1525 
1526   /** Maps the given "platform-independent" function name to a real function
1527       name. Currently not used. */
mapToRealGLFunctionName(final String glFunctionName)1528   protected final String mapToRealGLFunctionName(final String glFunctionName) {
1529     final Map<String, String> map = getFunctionNameMap();
1530     if( null != map ) {
1531         final String lookup = map.get(glFunctionName);
1532         if (lookup != null) {
1533           return lookup;
1534         }
1535     }
1536     return glFunctionName;
1537   }
getFunctionNameMap()1538   protected abstract Map<String, String> getFunctionNameMap() ;
1539 
1540   /** Maps the given "platform-independent" extension name to a real
1541       function name. Currently this is only used to map
1542       "GL_ARB_pbuffer"      to  "WGL_ARB_pbuffer/GLX_SGIX_pbuffer" and
1543       "GL_ARB_pixel_format" to  "WGL_ARB_pixel_format/n.a."
1544    */
mapToRealGLExtensionName(final String glExtensionName)1545   protected final String mapToRealGLExtensionName(final String glExtensionName) {
1546     final Map<String, String> map = getExtensionNameMap();
1547     if( null != map ) {
1548         final String lookup = map.get(glExtensionName);
1549         if (lookup != null) {
1550           return lookup;
1551         }
1552     }
1553     return glExtensionName;
1554   }
getExtensionNameMap()1555   protected abstract Map<String, String> getExtensionNameMap() ;
1556 
1557   /**
1558    * Returns the DynamicLookupHelper
1559    */
getGLDynamicLookupHelper()1560   public final GLDynamicLookupHelper getGLDynamicLookupHelper() {
1561       return drawable.getFactoryImpl().getGLDynamicLookupHelper( ctxVersion.getMajor(), ctxOptions );
1562   }
getGLDynamicLookupHelper(final int majorVersion, final int contextOptions)1563   public final GLDynamicLookupHelper getGLDynamicLookupHelper(final int majorVersion, final int contextOptions) {
1564       return drawable.getFactoryImpl().getGLDynamicLookupHelper( majorVersion, contextOptions );
1565   }
1566 
1567   /** Helper routine which resets a ProcAddressTable generated by the
1568       GLEmitter by looking up anew all of its function pointers
1569       using the given {@link GLDynamicLookupHelper}. */
resetProcAddressTable(final ProcAddressTable table, final GLDynamicLookupHelper dlh)1570   protected final void resetProcAddressTable(final ProcAddressTable table, final GLDynamicLookupHelper dlh) {
1571     AccessController.doPrivileged(new PrivilegedAction<Object>() {
1572         @Override
1573         public Object run() {
1574             table.reset( dlh );
1575             return null;
1576         }
1577     } );
1578   }
1579 
1580   /**
1581    * Updates the platform's 'GLX' function cache
1582    * @param contextFQN provides a fully qualified key of the context including device and GL profile
1583    * @param dlh {@link GLDynamicLookupHelper} used to {@link #resetProcAddressTable(ProcAddressTable, GLDynamicLookupHelper)} instance.
1584    */
updateGLXProcAddressTable(final String contextFQN, final GLDynamicLookupHelper dlh)1585   protected abstract void updateGLXProcAddressTable(final String contextFQN, final GLDynamicLookupHelper dlh);
1586 
initGLRendererAndGLVersionStrings(final int majorVersion, final int contextOptions)1587   private final boolean initGLRendererAndGLVersionStrings(final int majorVersion, final int contextOptions)  {
1588     if( !glGetPtrInit ) {
1589         AccessController.doPrivileged(new PrivilegedAction<Object>() {
1590             @Override
1591             public Object run() {
1592                 final GLDynamicLookupHelper glDynLookupHelper = getGLDynamicLookupHelper(majorVersion, contextOptions);
1593                 if( null != glDynLookupHelper ) {
1594                     glDynLookupHelper.claimAllLinkPermission();
1595                     try {
1596                         glGetStringPtr = glDynLookupHelper.dynamicLookupFunction("glGetString");
1597                         glGetIntegervPtr = glDynLookupHelper.dynamicLookupFunction("glGetIntegerv");
1598                     } finally {
1599                         glDynLookupHelper.releaseAllLinkPermission();
1600                     }
1601                 }
1602                 return null;
1603             } } );
1604         glGetPtrInit = true;
1605     }
1606     if( 0 == glGetStringPtr || 0 == glGetIntegervPtr ) {
1607         System.err.println("Error: Could not lookup: glGetString "+toHexString(glGetStringPtr)+", glGetIntegerv "+toHexString(glGetIntegervPtr));
1608         if(DEBUG) {
1609             ExceptionUtils.dumpStack(System.err);
1610         }
1611         return false;
1612     } else {
1613         final String _glVendor = glGetStringInt(GL.GL_VENDOR, glGetStringPtr);
1614         if(null == _glVendor) {
1615             if(DEBUG) {
1616                 System.err.println("Warning: GL_VENDOR is NULL.");
1617                 ExceptionUtils.dumpStack(System.err);
1618             }
1619             return false;
1620         }
1621         glVendor = _glVendor;
1622 
1623         final String _glRenderer = glGetStringInt(GL.GL_RENDERER, glGetStringPtr);
1624         if(null == _glRenderer) {
1625             if(DEBUG) {
1626                 System.err.println("Warning: GL_RENDERER is NULL.");
1627                 ExceptionUtils.dumpStack(System.err);
1628             }
1629             return false;
1630         }
1631         glRenderer = _glRenderer;
1632         glRendererLowerCase = glRenderer.toLowerCase();
1633 
1634         final String _glVersion = glGetStringInt(GL.GL_VERSION, glGetStringPtr);
1635         if(null == _glVersion) {
1636             // FIXME
1637             if(DEBUG) {
1638                 System.err.println("Warning: GL_VERSION is NULL.");
1639                 ExceptionUtils.dumpStack(System.err);
1640             }
1641             return false;
1642         }
1643         glVersion = _glVersion;
1644 
1645         return true;
1646     }
1647   }
1648 
1649   /**
1650    * Returns false if <code>glGetIntegerv</code> is inaccessible, otherwise queries major.minor
1651    * version for given arrays.
1652    * <p>
1653    * If the GL query fails, major will be zero.
1654    * </p>
1655    */
getGLIntVersion(final int[] glIntMajor, final int[] glIntMinor)1656   private final void getGLIntVersion(final int[] glIntMajor, final int[] glIntMinor)  {
1657     glIntMajor[0] = 0; // clear
1658     glIntMinor[0] = 0; // clear
1659     if( 0 == glGetIntegervPtr ) {
1660         // should not be reached, since initGLRendererAndGLVersionStrings(..)'s failure should abort caller!
1661         throw new InternalError("Not initialized: glGetString "+toHexString(glGetStringPtr)+", glGetIntegerv "+toHexString(glGetIntegervPtr));
1662     } else {
1663         glGetIntegervInt(GL2ES3.GL_MAJOR_VERSION, glIntMajor, 0, glGetIntegervPtr);
1664         glGetIntegervInt(GL2ES3.GL_MINOR_VERSION, glIntMinor, 0, glGetIntegervPtr);
1665     }
1666   }
1667 
1668 
1669   /**
1670    * Returns null if version string is invalid, otherwise a valid instance.
1671    * <p>
1672    * Note: Non ARB ctx is limited to GL 3.0.
1673    * </p>
1674    */
getGLVersionNumber(final int ctp, final String glVersionStr)1675   private static final VersionNumber getGLVersionNumber(final int ctp, final String glVersionStr) {
1676       if( null != glVersionStr ) {
1677           final GLVersionNumber version = GLVersionNumber.create(glVersionStr);
1678           if ( version.isValid() ) {
1679               final int[] major = new int[] { version.getMajor() };
1680               final int[] minor = new int[] { version.getMinor() };
1681               if ( GLContext.isValidGLVersion(ctp, major[0], minor[0]) ) {
1682                   return new VersionNumber(major[0], minor[0], 0);
1683               }
1684           }
1685       }
1686       return null;
1687   }
1688 
getCtxOptions()1689   protected final int getCtxOptions() {
1690       return ctxOptions;
1691   }
1692 
1693 
1694   /**
1695    * Sets the OpenGL implementation class and
1696    * the cache of which GL functions are available for calling through this
1697    * context. See {@link #isFunctionAvailable(String)} for more information on
1698    * the definition of "available".
1699    * <p>
1700    * All ProcaddressTables are being determined and cached, the GL version is being set
1701    * and the extension cache is determined as well.
1702    * </p>
1703    * <p>
1704    * It is the callers responsibility to issue {@link #resetStates(boolean)}
1705    * in case this method returns {@code false} or throws a {@link GLException}.
1706    * </p>
1707    *
1708    * @param force force the setting, even if is already being set.
1709    *              This might be useful if you change the OpenGL implementation.
1710    * @param major requested OpenGL major version
1711    * @param minor requested OpenGL minor version
1712    * @param ctxProfileBits OpenGL context profile and option bits, see {@link com.jogamp.opengl.GLContext#CTX_OPTION_ANY}
1713    * @param strictMatch if <code>true</code> the ctx must
1714    *                    <ul>
1715    *                      <li>be greater or equal than the requested <code>major.minor</code> version, and</li>
1716    *                      <li>match the ctxProfileBits</li>
1717    *                      <li>match ES major versions</li>
1718    *                    </ul>, otherwise method aborts and returns <code>false</code>.<br>
1719    *                    if <code>false</code> no version check is performed.
1720    * @param withinGLVersionsMapping if <code>true</code> GL version mapping is in process, i.e. querying avail versions.
1721    *                                Otherwise normal user context creation.
1722    * @return returns <code>true</code> if successful, otherwise <code>false</code>.<br>
1723    *                 If <code>strictMatch</code> is <code>false</code> method shall always return <code>true</code> or throw an exception.
1724    *                 If <code>false</code> is returned, no data has been cached or mapped, i.e. ProcAddressTable, Extensions, Version, etc.
1725    * @throws GLException in case of an unexpected OpenGL related issue, e.g. missing expected GL function pointer.
1726    * @see #setContextVersion
1727    * @see com.jogamp.opengl.GLContext#CTX_OPTION_ANY
1728    * @see com.jogamp.opengl.GLContext#CTX_PROFILE_COMPAT
1729    * @see com.jogamp.opengl.GLContext#CTX_IMPL_ES2_COMPAT
1730    */
setGLFunctionAvailability(final boolean force, int major, int minor, int ctxProfileBits, final boolean strictMatch, final boolean withinGLVersionsMapping)1731   protected final boolean setGLFunctionAvailability(final boolean force, int major, int minor, int ctxProfileBits,
1732                                                     final boolean strictMatch, final boolean withinGLVersionsMapping)
1733                                                     throws GLException
1734   {
1735     if( null != this.gl && null != glProcAddressTable && !force ) {
1736         return true; // already done and not forced
1737     }
1738 
1739     if ( 0 < major && !GLContext.isValidGLVersion(ctxProfileBits, major, minor) ) {
1740         throw new GLException("Invalid GL Version Request "+GLContext.getGLVersion(major, minor, ctxProfileBits, null));
1741     }
1742 
1743     final AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration();
1744     final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice();
1745     final int reqCtxProfileBits = ctxProfileBits;
1746     final VersionNumber reqGLVersion = new VersionNumber(major, minor, 0);
1747     final VersionNumber hasGLVersionByString;
1748     {
1749         final boolean initGLRendererAndGLVersionStringsOK = initGLRendererAndGLVersionStrings(major, ctxProfileBits);
1750         if( !initGLRendererAndGLVersionStringsOK ) {
1751             final String errMsg = "Intialization of GL renderer strings failed. "+adevice+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, null);
1752             if( strictMatch ) {
1753                 // query mode .. simply fail
1754                 if(DEBUG) {
1755                     System.err.println("Warning: setGLFunctionAvailability: "+errMsg);
1756                 }
1757                 return false;
1758             } else {
1759                 // unusable GL context - non query mode - hard fail!
1760                 throw new GLException(errMsg);
1761             }
1762         } else {
1763             hasGLVersionByString = getGLVersionNumber(ctxProfileBits, glVersion);
1764             if(DEBUG) {
1765                 System.err.println(getThreadName() + ": GLContext.setGLFuncAvail: Given "+adevice+
1766                                    " - "+GLContext.getGLVersion(major, minor, ctxProfileBits, glVersion)+
1767                                    ", Number(Str) "+hasGLVersionByString);
1768             }
1769         }
1770     }
1771 
1772     final boolean isES = 0 != ( CTX_PROFILE_ES & ctxProfileBits );
1773 
1774     //
1775     // Validate GL version either by GL-Integer or GL-String
1776     //
1777     if (DEBUG) {
1778         System.err.println(getThreadName() + ": GLContext.setGLFuncAvail: Pre version verification - expected "+GLContext.getGLVersion(major, minor, ctxProfileBits, null)+", strictMatch "+strictMatch+", glVersionsMapping " +withinGLVersionsMapping);
1779     }
1780 
1781     final boolean versionGL3IntOK;
1782     {
1783         // Validate the requested version w/ the GL-version from an integer query,
1784         // as supported by GL [ES] >= 3.0 implementation.
1785         //
1786         // Only validate integer based version if:
1787         //    - ctx >= 3.0 is requested _or_ string-version >= 3.0
1788         //    - _and_ a valid int version was fetched,
1789         // otherwise cont. w/ version-string method -> 3.0 > Version || Version > MAX!
1790         //
1791         final VersionNumber hasGLVersionByInt;
1792         if ( major >= 3 || hasGLVersionByString.compareTo(Version3_0) >= 0 ) {
1793             final int[] glIntMajor = new int[] { 0 }, glIntMinor = new int[] { 0 };
1794             getGLIntVersion(glIntMajor, glIntMinor);
1795             hasGLVersionByInt = new VersionNumber(glIntMajor[0], glIntMinor[0], 0);
1796             if (DEBUG) {
1797                 System.err.println(getThreadName() + ": GLContext.setGLFuncAvail: Version verification (Int): String "+glVersion+", Number(Int) "+hasGLVersionByInt);
1798             }
1799             if ( GLContext.isValidGLVersion(ctxProfileBits, hasGLVersionByInt.getMajor(), hasGLVersionByInt.getMinor()) ) {
1800                 // Strict Match (GLVersionMapping):
1801                 //   Relaxed match for versions ( !isES && major < 3 ) requests, last resort!
1802                 //   Otherwise:
1803                 //     - fail if hasVersion < reqVersion (desktop and ES)
1804                 //     - fail if ES major-version mismatch:
1805                 //       - request 1, >= 3 must be equal
1806                 //       - request 2 must be [2..3]
1807                 //
1808                 final int hasMajor = hasGLVersionByInt.getMajor();
1809                 if( strictMatch &&
1810                     ( ( ( isES || major >= 3 ) && hasGLVersionByInt.compareTo(reqGLVersion) < 0 ) ||
1811                       ( isES &&
1812                         (
1813                           ( 2 == major && ( 2 > hasMajor || hasMajor > 3 ) ) ||  // 2      -> [2..3]
1814                           ( ( 1 == major || 3 <= major ) && major != hasMajor )  // 1,3,.. -> equal
1815                         )
1816                       )
1817                     ) ) {
1818                     if(DEBUG) {
1819                         System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.X: FAIL, GL version mismatch (Int): "+GLContext.getGLVersion(major, minor, ctxProfileBits, null)+" -> "+glVersion+", "+hasGLVersionByInt);
1820                     }
1821                     return false;
1822                 }
1823                 // Use returned GL version!
1824                 major = hasGLVersionByInt.getMajor();
1825                 minor = hasGLVersionByInt.getMinor();
1826                 versionGL3IntOK = true;
1827             } else {
1828                 versionGL3IntOK = false;
1829             }
1830         } else {
1831             versionGL3IntOK = false;
1832         }
1833     }
1834     final boolean versionValidated;
1835 
1836     if( versionGL3IntOK ) {
1837         versionValidated = true;
1838     } else {
1839         // Validate the requested version w/ the GL-version from the version string.
1840         if (DEBUG) {
1841             System.err.println(getThreadName() + ": GLContext.setGLFuncAvail: Version verification (String): String "+glVersion+", Number(Str) "+hasGLVersionByString);
1842         }
1843 
1844         // Only validate if a valid string version was fetched -> MIN > Version || Version > MAX!
1845         if( null != hasGLVersionByString ) {
1846             // Strict Match (GLVersionMapping):
1847             //   Relaxed match for versions ( !isES && major < 3 ) requests, last resort!
1848             //   Otherwise:
1849             //     - fail if hasVersion < reqVersion (desktop and ES)
1850             //     - fail if ES major-version mismatch:
1851             //       - request 1, >= 3 must be equal
1852             //       - request 2 must be [2..3]
1853             //
1854             final int hasMajor = hasGLVersionByString.getMajor();
1855             if( strictMatch &&
1856                 ( ( ( isES || major >= 3 ) && hasGLVersionByString.compareTo(reqGLVersion) < 0 ) ||
1857                   ( isES &&
1858                     (
1859                       ( 2 == major && ( 2 > hasMajor || hasMajor > 3 ) ) ||  // 2      -> [2..3]
1860                       ( ( 1 == major || 3 <= major ) && major != hasMajor )  // 1,3,.. -> equal
1861                     )
1862                   )
1863                 ) ) {
1864                 if(DEBUG) {
1865                     System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.X: FAIL, GL version mismatch (String): "+GLContext.getGLVersion(major, minor, ctxProfileBits, null)+" -> "+glVersion+", "+hasGLVersionByString);
1866                 }
1867                 return false;
1868             }
1869             if( strictMatch && !versionGL3IntOK && major >= 3 ) {
1870                 if(DEBUG) {
1871                     System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.X: FAIL, GL3/ES3 version Int failed, String: "+GLContext.getGLVersion(major, minor, ctxProfileBits, null)+" -> "+glVersion+", "+hasGLVersionByString);
1872                 }
1873                 return false;
1874             }
1875             // Use returned GL version!
1876             major = hasGLVersionByString.getMajor();
1877             minor = hasGLVersionByString.getMinor();
1878             versionValidated = true;
1879         } else {
1880             versionValidated = false;
1881         }
1882     }
1883     if( strictMatch && !versionValidated ) {
1884         if(DEBUG) {
1885             System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.X: FAIL, No GL version validation possible: "+GLContext.getGLVersion(major, minor, ctxProfileBits, null)+" -> "+glVersion);
1886         }
1887         return false;
1888     }
1889     if (DEBUG) {
1890         System.err.println(getThreadName() + ": GLContext.setGLFuncAvail: Post version verification req "+
1891                 GLContext.getGLVersion(reqGLVersion.getMajor(), reqGLVersion.getMinor(), reqCtxProfileBits, null)+" -> has "+
1892                 GLContext.getGLVersion(major, minor, ctxProfileBits, null)+
1893                 ", strictMatch "+strictMatch+", versionValidated "+versionValidated+", versionGL3IntOK "+versionGL3IntOK);
1894     }
1895 
1896     if( major < 2 ) { // there is no ES2/3-compat for a profile w/ major < 2
1897         ctxProfileBits &= ~ ( GLContext.CTX_IMPL_ES2_COMPAT | GLContext.CTX_IMPL_ES3_COMPAT |
1898                               GLContext.CTX_IMPL_ES31_COMPAT | GLContext.CTX_IMPL_ES32_COMPAT ) ;
1899     }
1900 
1901     if(!isCurrentContextHardwareRasterizer()) {
1902         ctxProfileBits |= GLContext.CTX_IMPL_ACCEL_SOFT;
1903     }
1904 
1905     final VersionNumberString vendorVersion = GLVersionNumber.createVendorVersion(glVersion);
1906 
1907     setRendererQuirks(adevice, getDrawableImpl().getFactoryImpl(),
1908                       reqGLVersion.getMajor(), reqGLVersion.getMinor(), reqCtxProfileBits,
1909                       major, minor, ctxProfileBits, vendorVersion, withinGLVersionsMapping);
1910 
1911     if( strictMatch && glRendererQuirks.exist(GLRendererQuirks.GLNonCompliant) ) {
1912         if(DEBUG) {
1913             System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.X: FAIL, GL is not compliant: "+GLContext.getGLVersion(major, minor, ctxProfileBits, glVersion)+", "+glRenderer);
1914         }
1915         return false;
1916     }
1917 
1918     contextFQN = getContextFQN(adevice, major, minor, ctxProfileBits);
1919     if (DEBUG) {
1920         System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.0 validated FQN: "+contextFQN+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, glVersion));
1921     }
1922     final GLDynamicLookupHelper dynamicLookup = getGLDynamicLookupHelper(major, ctxProfileBits);
1923     if( null == dynamicLookup ) {
1924         if(DEBUG) {
1925             System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.X: FAIL, No GLDynamicLookupHelper for request: "+GLContext.getGLVersion(major, minor, ctxProfileBits, null));
1926         }
1927         return false;
1928     }
1929     updateGLXProcAddressTable(contextFQN, dynamicLookup);
1930 
1931     //
1932     // UpdateGLProcAddressTable functionality
1933     // _and_ setup GL instance, which ctor requires valid getGLProcAddressTable() result!
1934     //
1935     {
1936         final GLProfile glp = drawable.getGLProfile(); // !withinGLVersionsMapping
1937 
1938         ProcAddressTable table = null;
1939         synchronized(mappedContextTypeObjectLock) {
1940             table = mappedGLProcAddress.get( contextFQN );
1941             if(null != table) {
1942                 if( !verifyInstance(adevice, major, minor, ctxProfileBits, "ProcAddressTable", table) ) {
1943                     throw new GLException("GLContext GL ProcAddressTable mapped key("+contextFQN+" - " + GLContext.getGLVersion(major, minor, ctxProfileBits, null)+
1944                           ") -> "+ toHexString(table.hashCode()) +" not matching "+table.getClass().getName());
1945                 }
1946                 if( !withinGLVersionsMapping && !verifyInstance(glp, "ProcAddressTable", table) ) {
1947                     throw new GLException("GLContext GL ProcAddressTable mapped key("+contextFQN+" - " + GLContext.getGLVersion(major, minor, ctxProfileBits, null)+
1948                           ") -> "+ toHexString(table.hashCode()) +": "+table.getClass().getName()+" not matching "+glp.getGLImplBaseClassName()+"/"+glp);
1949                 }
1950             }
1951         }
1952         if(null != table) {
1953             glProcAddressTable = table;
1954             if(DEBUG) {
1955                 if( withinGLVersionsMapping ) {
1956                     System.err.println(getThreadName() + ": GLContext GL ProcAddressTable reusing key("+contextFQN+" - " + GLContext.getGLVersion(major, minor, ctxProfileBits, null)+
1957                           ") -> "+ toHexString(table.hashCode()) +": "+table.getClass().getName());
1958                 } else {
1959                     System.err.println(getThreadName() + ": GLContext GL ProcAddressTable reusing key("+contextFQN+" - " + GLContext.getGLVersion(major, minor, ctxProfileBits, null)+
1960                           ") -> "+ toHexString(table.hashCode()) +": "+table.getClass().getName()+" -> "+glp.getGLImplBaseClassName());
1961                 }
1962             }
1963         } else {
1964             glProcAddressTable = (ProcAddressTable) createInstance(adevice, major, minor, ctxProfileBits, false,
1965                                                                    new Object[] { new GLProcAddressResolver() } );
1966             resetProcAddressTable(glProcAddressTable, dynamicLookup);
1967 
1968             synchronized(mappedContextTypeObjectLock) {
1969                 mappedGLProcAddress.put(contextFQN, glProcAddressTable);
1970                 if(DEBUG) {
1971                     if( withinGLVersionsMapping ) {
1972                         System.err.println(getThreadName() + ": GLContext GL ProcAddressTable mapping key("+contextFQN+" - " + GLContext.getGLVersion(major, minor, ctxProfileBits, null)+
1973                           ") -> "+toHexString(glProcAddressTable.hashCode()) +": "+glProcAddressTable.getClass().getName());
1974                     } else {
1975                         System.err.println(getThreadName() + ": GLContext GL ProcAddressTable mapping key("+contextFQN+" - " + GLContext.getGLVersion(major, minor, ctxProfileBits, null)+
1976                           ") -> "+toHexString(glProcAddressTable.hashCode()) +": "+glProcAddressTable.getClass().getName()+" -> "+glp.getGLImplBaseClassName());
1977                     }
1978                 }
1979             }
1980         }
1981 
1982         if( null == this.gl || !verifyInstance(adevice, major, minor, ctxProfileBits, "Impl", this.gl) ) {
1983             setGL( createGL( adevice, major, minor, ctxProfileBits ) );
1984         }
1985         if( !withinGLVersionsMapping && !verifyInstance(glp, "Impl", this.gl) ) {
1986             throw new GLException("GLContext GL Object mismatch: "+GLContext.getGLVersion(major, minor, ctxProfileBits, null)+
1987                     ") -> "+": "+this.gl.getClass().getName()+" not matching "+glp.getGLImplBaseClassName()+"/"+glp);
1988         }
1989     }
1990 
1991     //
1992     // Update ExtensionAvailabilityCache
1993     //
1994     {
1995         ExtensionAvailabilityCache eCache;
1996         synchronized(mappedContextTypeObjectLock) {
1997             eCache = mappedExtensionAvailabilityCache.get( contextFQN );
1998         }
1999         if(null !=  eCache) {
2000             extensionAvailability = eCache;
2001             if(DEBUG) {
2002                 System.err.println(getThreadName() + ": GLContext GL ExtensionAvailabilityCache reusing key("+contextFQN+") -> "+toHexString(eCache.hashCode()) + " - entries: "+eCache.getTotalExtensionCount());
2003             }
2004         } else {
2005             extensionAvailability = new ExtensionAvailabilityCache();
2006             setContextVersion(major, minor, ctxProfileBits, vendorVersion, false); // pre-set of GL version, required for extension cache usage
2007             extensionAvailability.reset(this);
2008             synchronized(mappedContextTypeObjectLock) {
2009                 mappedExtensionAvailabilityCache.put(contextFQN, extensionAvailability);
2010                 if(DEBUG) {
2011                     System.err.println(getThreadName() + ": GLContext GL ExtensionAvailabilityCache mapping key("+contextFQN+") -> "+toHexString(extensionAvailability.hashCode()) + " - entries: "+extensionAvailability.getTotalExtensionCount());
2012                 }
2013             }
2014         }
2015     }
2016 
2017     if( isES ) {
2018         if( major >= 3 ) {
2019             ctxProfileBits |= CTX_IMPL_ES3_COMPAT | CTX_IMPL_ES2_COMPAT ;
2020             ctxProfileBits |= CTX_IMPL_FBO;
2021             if( minor >= 2 ) {
2022                 ctxProfileBits |= CTX_IMPL_ES32_COMPAT | CTX_IMPL_ES31_COMPAT;
2023             } else if( minor >= 1 ) {
2024                 ctxProfileBits |= CTX_IMPL_ES31_COMPAT;
2025             }
2026         } else if( major >= 2 ) {
2027             ctxProfileBits |= CTX_IMPL_ES2_COMPAT;
2028             ctxProfileBits |= CTX_IMPL_FBO;
2029         }
2030     } else if( ( major > 4 || major == 4 && minor >= 5 ) ||
2031                ( major > 3 || major == 3 && minor >= 1 ) ) {
2032         // See GLContext.isGLES31CompatibleAvailable(..)/isGLES3[12]Compatible()
2033         //   Includes [ GL &ge; 4.5, GL &ge; 3.1 w/ GL_ARB_ES3_[12]_compatibility and GLES &ge; 3.[12] ]
2034         if( isExtensionAvailable( GLExtensions.ARB_ES3_2_compatibility ) ) {
2035             ctxProfileBits |= CTX_IMPL_ES32_COMPAT | CTX_IMPL_ES31_COMPAT;
2036         } else if( isExtensionAvailable( GLExtensions.ARB_ES3_1_compatibility ) ) {
2037             ctxProfileBits |= CTX_IMPL_ES31_COMPAT;
2038         }
2039         ctxProfileBits |= CTX_IMPL_ES3_COMPAT | CTX_IMPL_ES2_COMPAT;
2040         ctxProfileBits |= CTX_IMPL_FBO;
2041     } else if( ( major > 4 || major == 4 && minor >= 3 ) ||
2042                ( ( major > 3 || major == 3 && minor >= 1 ) && isExtensionAvailable( GLExtensions.ARB_ES3_compatibility ) ) ) {
2043         // See GLContext.isGLES3CompatibleAvailable(..)/isGLES3Compatible()
2044         //   Includes [ GL &ge; 4.3, GL &ge; 3.1 w/ GL_ARB_ES3_compatibility and GLES3 ]
2045         ctxProfileBits |= CTX_IMPL_ES3_COMPAT | CTX_IMPL_ES2_COMPAT ;
2046         ctxProfileBits |= CTX_IMPL_FBO;
2047     } else if( isExtensionAvailable( GLExtensions.ARB_ES2_compatibility ) ) {
2048         ctxProfileBits |= CTX_IMPL_ES2_COMPAT;
2049         ctxProfileBits |= CTX_IMPL_FBO;
2050     } else if( hasFBOImpl(major, ctxProfileBits, extensionAvailability) ) {
2051         ctxProfileBits |= CTX_IMPL_FBO;
2052     }
2053 
2054     if( ( isES && major == 1 ) ||  isExtensionAvailable(GLExtensions.OES_single_precision) ) {
2055         ctxProfileBits |= CTX_IMPL_FP32_COMPAT_API;
2056     }
2057 
2058     if(FORCE_NO_FBO_SUPPORT) {
2059         ctxProfileBits &= ~CTX_IMPL_FBO ;
2060     }
2061 
2062     //
2063     // Set GL Version (complete w/ version string)
2064     //
2065     setContextVersion(major, minor, ctxProfileBits, vendorVersion, true);
2066 
2067     finalizeInit(gl);
2068 
2069     setDefaultSwapInterval();
2070 
2071     final int glErrX = gl.glGetError(); // clear GL error, maybe caused by above operations
2072 
2073     if(DEBUG) {
2074         System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.X: OK "+contextFQN+" - "+GLContext.getGLVersion(ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions, null)+" - glErr "+toHexString(glErrX));
2075     }
2076     return true;
2077   }
2078 
addStickyQuirkAlways(final AbstractGraphicsDevice adevice, final GLRendererQuirks quirks, final int quirk, final boolean withinGLVersionsMapping)2079   private static final void addStickyQuirkAlways(final AbstractGraphicsDevice adevice,
2080                                                  final GLRendererQuirks quirks,
2081                                                  final int quirk,
2082                                                  final boolean withinGLVersionsMapping) {
2083         quirks.addQuirk( quirk );
2084         if( withinGLVersionsMapping ) {
2085             // Thread safe due to single threaded initialization!
2086             GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk);
2087         } else {
2088             // FIXME: Remove when moving EGL/ES to ARB ctx creation
2089             synchronized(GLContextImpl.class) {
2090                 GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk);
2091             }
2092         }
2093   }
addStickyQuirkAtMapping(final AbstractGraphicsDevice adevice, final GLRendererQuirks quirks, final int quirk, final boolean withinGLVersionsMapping)2094   private static final void addStickyQuirkAtMapping(final AbstractGraphicsDevice adevice,
2095                                                     final GLRendererQuirks quirks,
2096                                                     final int quirk,
2097                                                     final boolean withinGLVersionsMapping) {
2098         quirks.addQuirk( quirk );
2099         if( withinGLVersionsMapping ) {
2100             // Thread safe due to single threaded initialization!
2101             GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk);
2102         }
2103   }
setRendererQuirks(final AbstractGraphicsDevice adevice, final GLDrawableFactoryImpl factory, final int reqMajor, final int reqMinor, final int reqCTP, final int major, final int minor, final int ctp, final VersionNumberString vendorVersion, final boolean withinGLVersionsMapping)2104   private final void setRendererQuirks(final AbstractGraphicsDevice adevice, final GLDrawableFactoryImpl factory,
2105                                        final int reqMajor, final int reqMinor, final int reqCTP,
2106                                        final int major, final int minor, final int ctp, final VersionNumberString vendorVersion,
2107                                        final boolean withinGLVersionsMapping) {
2108     final String MesaSP = "Mesa ";
2109     // final String MesaRendererAMDsp = " AMD ";
2110     final String MesaRendererIntelsp = "Intel(R)";
2111     final boolean hwAccel = 0 == ( ctp & GLContext.CTX_IMPL_ACCEL_SOFT );
2112     final boolean compatCtx = 0 != ( ctp & GLContext.CTX_PROFILE_COMPAT );
2113     final boolean isES = 0 != ( ctp & GLContext.CTX_PROFILE_ES );
2114     final boolean isX11 = NativeWindowFactory.TYPE_X11 == NativeWindowFactory.getNativeWindowType(true);
2115     final boolean isWindows = Platform.getOSType() == Platform.OSType.WINDOWS;
2116     final boolean isDriverMesa = glRenderer.contains(MesaSP) || glRenderer.contains("Gallium ");
2117 
2118     final boolean isDriverATICatalyst;
2119     final boolean isDriverNVIDIAGeForce;
2120     final boolean isDriverIntel;
2121     if( !isDriverMesa ) {
2122         isDriverATICatalyst = glVendor.contains("ATI Technologies") || glRenderer.startsWith("ATI ");
2123         isDriverNVIDIAGeForce = glVendor.contains("NVIDIA Corporation") || glRenderer.contains("NVIDIA ");
2124         isDriverIntel = glVendor.startsWith("Intel");
2125     } else {
2126         isDriverATICatalyst = false;
2127         isDriverNVIDIAGeForce = false;
2128         isDriverIntel = false;
2129     }
2130 
2131     final GLRendererQuirks quirks = new GLRendererQuirks();
2132 
2133     //
2134     // General Quirks
2135     //
2136     if( isES ) {
2137         if( 2 == reqMajor && 2 < major ) {
2138             final int quirk = GLRendererQuirks.GLES3ViaEGLES2Config;
2139             if(DEBUG) {
2140                 System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: ES req "+reqMajor+" and 2 < "+major);
2141             }
2142             addStickyQuirkAlways(adevice, quirks, quirk, withinGLVersionsMapping);
2143         }
2144     }
2145     if( GLProfile.disableSurfacelessContext ) {
2146         final int quirk = GLRendererQuirks.NoSurfacelessCtx;
2147         if(DEBUG) {
2148             System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: disabled");
2149         }
2150         addStickyQuirkAlways(adevice, quirks, quirk, withinGLVersionsMapping);
2151     }
2152     if( GLProfile.disableOpenGLARBContext ) {
2153         final int quirk = GLRendererQuirks.NoARBCreateContext;
2154         if(DEBUG) {
2155             System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: disabled");
2156         }
2157         addStickyQuirkAlways(adevice, quirks, quirk, withinGLVersionsMapping);
2158     }
2159 
2160     //
2161     // OS related quirks
2162     //
2163     if( Platform.getOSType() == Platform.OSType.MACOS ) {
2164         //
2165         // OSX
2166         //
2167         {
2168             final int quirk = GLRendererQuirks.NoOffscreenBitmap;
2169             if(DEBUG) {
2170                 System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType());
2171             }
2172             quirks.addQuirk( quirk );
2173         }
2174         {
2175             final int quirk = GLRendererQuirks.NeedSharedObjectSync;
2176             if(DEBUG) {
2177                 System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType());
2178             }
2179             quirks.addQuirk( quirk );
2180         }
2181         if( Platform.getOSVersionNumber().compareTo(Platform.OSXVersion.Mavericks) >= 0 && 3==reqMajor && 4==major ) {
2182             final int quirk = GLRendererQuirks.GL4NeedsGL3Request;
2183             if(DEBUG) {
2184                 System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()+", OS Version "+Platform.getOSVersionNumber()+", req "+reqMajor+"."+reqMinor);
2185             }
2186             addStickyQuirkAtMapping(adevice, quirks, quirk, withinGLVersionsMapping);
2187         }
2188         if( isDriverNVIDIAGeForce ) {
2189             final VersionNumber osxVersionNVFlushClean = new VersionNumber(10,7,3); // < OSX 10.7.3 w/ NV needs glFlush
2190             if( Platform.getOSVersionNumber().compareTo(osxVersionNVFlushClean) < 0 ) {
2191                 final int quirk = GLRendererQuirks.GLFlushBeforeRelease;
2192                 if(DEBUG) {
2193                     System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()+", OS Version "+Platform.getOSVersionNumber()+", Renderer "+glRenderer);
2194                 }
2195                 quirks.addQuirk( quirk );
2196             }
2197             if( Platform.getOSVersionNumber().compareTo(Platform.OSXVersion.Lion) < 0 ) { // < OSX 10.7.0 w/ NV has unstable GLSL
2198                 final int quirk = GLRendererQuirks.GLSLNonCompliant;
2199                 if(DEBUG) {
2200                     System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()+", OS Version "+Platform.getOSVersionNumber()+", Renderer "+glRenderer);
2201                 }
2202                 quirks.addQuirk( quirk );
2203             }
2204         }
2205     } else if( isWindows ) {
2206         //
2207         // WINDOWS
2208         //
2209         {
2210             final int quirk = GLRendererQuirks.NoDoubleBufferedBitmap;
2211             if(DEBUG) {
2212                 System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType());
2213             }
2214             quirks.addQuirk( quirk );
2215         }
2216 
2217         if( isDriverATICatalyst ) {
2218             final VersionNumber winXPVersionNumber = new VersionNumber ( 5, 1, 0);
2219             final VersionNumber amdSafeMobilityVersion = new VersionNumber(12, 102, 3);
2220 
2221             if ( vendorVersion.compareTo(amdSafeMobilityVersion) < 0 ) { // includes: vendorVersion.isZero()
2222                 final int quirk = GLRendererQuirks.NeedCurrCtx4ARBCreateContext;
2223                 if(DEBUG) {
2224                     System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()+", [Vendor "+glVendor+" or Renderer "+glRenderer+"], driverVersion "+vendorVersion);
2225                 }
2226                 quirks.addQuirk( quirk );
2227             }
2228 
2229             if( Platform.getOSVersionNumber().compareTo(winXPVersionNumber) <= 0 ) {
2230                 final int quirk = GLRendererQuirks.NeedCurrCtx4ARBPixFmtQueries;
2231                 if(DEBUG) {
2232                     System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS-Version "+Platform.getOSType()+" "+Platform.getOSVersionNumber()+", [Vendor "+glVendor+" or Renderer "+glRenderer+"]");
2233                 }
2234                 quirks.addQuirk( quirk );
2235             }
2236 
2237             if (  vendorVersion.compareTo(VersionNumberString.zeroVersion) == 0 ) {
2238                 final VersionNumber glVersionNumber = new VersionNumber(glVersion);
2239                 if ( glVersionNumber.getSub() <= 8787 && glRenderer.equals("ATI Radeon 3100 Graphics") ) { // "old" driver -> sub-minor = vendor version
2240                     final int quirk = GLRendererQuirks.NoARBCreateContext;
2241                     if(DEBUG) {
2242                         System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()+", [Vendor "+glVendor+", Renderer "+glRenderer+" and Version "+glVersion+"]");
2243                     }
2244                     addStickyQuirkAtMapping(adevice, quirks, quirk, withinGLVersionsMapping);
2245                 }
2246             }
2247         } else if( isDriverIntel && glRenderer.equals("Intel Bear Lake B") ) {
2248           	final int quirk = GLRendererQuirks.NoPBufferWithAccum;
2249           	if(DEBUG) {
2250                 System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()+", [Vendor "+glVendor+" and Renderer "+glRenderer+"]");
2251             }
2252            	quirks.addQuirk( quirk );
2253         }
2254     } else if( Platform.OSType.ANDROID == Platform.getOSType() ) {
2255         //
2256         // ANDROID
2257         //
2258         // Renderer related quirks, may also involve OS
2259         if( glRenderer.contains("PowerVR") ) {
2260             final int quirk = GLRendererQuirks.NoSetSwapInterval;
2261             if(DEBUG) {
2262                 System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType() + ", Renderer " + glRenderer);
2263             }
2264             quirks.addQuirk( quirk );
2265         }
2266         if( glRenderer.contains("Immersion.16") ) {
2267             final int quirk = GLRendererQuirks.GLSharedContextBuggy;
2268             if(DEBUG) {
2269                 System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType() + ", Renderer " + glRenderer);
2270             }
2271             quirks.addQuirk( quirk );
2272         }
2273     }
2274 
2275     //
2276     // Windowing Toolkit related quirks
2277     //
2278     if( isX11 ) {
2279         //
2280         // X11
2281         //
2282         {
2283             //
2284             // Quirk: DontCloseX11Display
2285             //
2286             final int quirk = GLRendererQuirks.DontCloseX11Display;
2287             if( glRenderer.contains(MesaSP) ) {
2288                 if ( glRenderer.contains("X11") && vendorVersion.compareTo(Version8_0) < 0 ) {
2289                     if(DEBUG) {
2290                         System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: X11 Renderer=" + glRenderer + ", Version=[vendor " + vendorVersion + ", GL " + glVersion+"]");
2291                     }
2292                     quirks.addQuirk( quirk );
2293                 }
2294             } else if( isDriverATICatalyst ) {
2295                 {
2296                     if(DEBUG) {
2297                         System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: X11 Renderer=" + glRenderer);
2298                     }
2299                     quirks.addQuirk( quirk );
2300                 }
2301             } else if( jogamp.nativewindow.x11.X11Util.getMarkAllDisplaysUnclosable() ) {
2302                 {
2303                     if(DEBUG) {
2304                         System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: X11Util Downstream");
2305                     }
2306                     quirks.addQuirk( quirk );
2307                 }
2308             }
2309         }
2310         if( isDriverNVIDIAGeForce ) {
2311             // Bug 1200: Crash on GNU/Linux x86_64 'NVidia beta driver 355.06' @ probeSurfacelessCtx
2312             // final VersionNumber nvSafeVersion = new VersionNumber(356, 0, 0); // FIXME: Add safe version!
2313             if( !isES && !(adevice instanceof EGLGraphicsDevice) /* &&  vendorVersion.compareTo(nvSafeVersion) < 0 */ ) {
2314                 final int quirk = GLRendererQuirks.NoSurfacelessCtx;
2315                 if(DEBUG) {
2316                     System.err.print("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: !ES, !EGL, Vendor " + glVendor +", X11 Renderer " + glRenderer+", Version=[vendor " + vendorVersion + ", GL " + glVersion+"]");
2317                 }
2318                 addStickyQuirkAtMapping(adevice, quirks, quirk, withinGLVersionsMapping);
2319             }
2320         }
2321     }
2322 
2323 
2324     //
2325     // RENDERER related quirks
2326     //
2327     if( isDriverMesa ) {
2328         final VersionNumber mesaSafeFBOVersion = new VersionNumber(8, 0, 0);
2329         final VersionNumber mesaIntelBuggySharedCtx921 = new VersionNumber(9, 2, 1);
2330 
2331         {
2332             final int quirk = GLRendererQuirks.NoSetSwapIntervalPostRetarget;
2333             if(DEBUG) {
2334                 System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: Renderer " + glRenderer);
2335             }
2336             quirks.addQuirk( quirk );
2337         }
2338         if( hwAccel ) {
2339             // hardware-acceleration
2340             final int quirk = GLRendererQuirks.NoDoubleBufferedPBuffer;
2341             if(DEBUG) {
2342                 System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: Renderer " + glRenderer);
2343             }
2344             quirks.addQuirk( quirk );
2345         } else {
2346             // software
2347             if( vendorVersion.compareTo(mesaSafeFBOVersion) < 0 ) { // FIXME: Is it fixed in >= 8.0.0 ?
2348                 final int quirk = GLRendererQuirks.BuggyColorRenderbuffer;
2349                 if(DEBUG) {
2350                     System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: Renderer " + glRenderer + " / Mesa-Version "+vendorVersion);
2351                 }
2352                 quirks.addQuirk( quirk );
2353             }
2354         }
2355         if (compatCtx && (major > 3 || (major == 3 && minor >= 1))) {
2356             // FIXME: Apply vendor version constraints!
2357             final int quirk = GLRendererQuirks.GLNonCompliant;
2358             if(DEBUG) {
2359                 System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: Renderer " + glRenderer);
2360             }
2361             quirks.addQuirk( quirk );
2362         }
2363         if( glRenderer.contains( MesaRendererIntelsp ) &&
2364             vendorVersion.compareTo(mesaIntelBuggySharedCtx921) >= 0 && isX11 ) { // FIXME: When is it fixed ?
2365             final int quirk = GLRendererQuirks.GLSharedContextBuggy;
2366             if(DEBUG) {
2367                 System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: X11 / Renderer " + glRenderer + " / Mesa-Version "+vendorVersion);
2368             }
2369             quirks.addQuirk( quirk );
2370         }
2371         if( glVendor.contains( "nouveau" )
2372             // FIXME: && vendorVersion.compareTo(nouveauBuggyMSAAFixed) < 0
2373           ) {
2374             final int quirk = GLRendererQuirks.NoMultiSamplingBuffers;
2375             if(DEBUG) {
2376                 System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: X11 / Renderer " + glRenderer + " / Vendor "+glVendor);
2377             }
2378             addStickyQuirkAtMapping(adevice, quirks, quirk, withinGLVersionsMapping);
2379         }
2380         if( isWindows && glRenderer.contains("SVGA3D") && vendorVersion.compareTo(mesaSafeFBOVersion) < 0 ) {
2381             final int quirk = GLRendererQuirks.NoFullFBOSupport;
2382             if(DEBUG) {
2383                 System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType() + " / Renderer " + glRenderer + " / Mesa-Version "+vendorVersion);
2384             }
2385             quirks.addQuirk( quirk );
2386         }
2387     }
2388 
2389     //
2390     // Property related quirks
2391     //
2392     if( FORCE_NO_COLOR_RENDERBUFFER ) {
2393         final int quirk = GLRendererQuirks.BuggyColorRenderbuffer;
2394         if(DEBUG) {
2395             System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: property");
2396         }
2397         quirks.addQuirk( quirk );
2398     }
2399     if( FORCE_MIN_FBO_SUPPORT || quirks.exist(GLRendererQuirks.BuggyColorRenderbuffer) ) {
2400         final int quirk = GLRendererQuirks.NoFullFBOSupport;
2401         if(DEBUG) {
2402             final String causeProps = FORCE_MIN_FBO_SUPPORT ? "property, " : "";
2403             final String causeQuirk = quirks.exist(GLRendererQuirks.BuggyColorRenderbuffer) ? "BuggyColorRenderbuffer" : "";
2404             System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: "+causeProps+causeQuirk);
2405         }
2406         quirks.addQuirk( quirk );
2407     }
2408 
2409     if(DEBUG) {
2410         System.err.println("Quirks local.0: "+quirks);
2411     }
2412     {
2413         // Merge sticky quirks, thread safe due to single threaded initialization!
2414         GLRendererQuirks.pushStickyDeviceQuirks(adevice, quirks);
2415 
2416         final AbstractGraphicsDevice factoryDefaultDevice = factory.getDefaultDevice();
2417         if( !GLRendererQuirks.areSameStickyDevice(factoryDefaultDevice, adevice) ) {
2418             GLRendererQuirks.pushStickyDeviceQuirks(factoryDefaultDevice, quirks);
2419         }
2420         if( isES ) {
2421             final AbstractGraphicsDevice eglFactoryDefaultDevice = GLDrawableFactory.getEGLFactory().getDefaultDevice();
2422             if( !GLRendererQuirks.areSameStickyDevice(eglFactoryDefaultDevice, adevice) &&
2423                 !GLRendererQuirks.areSameStickyDevice(eglFactoryDefaultDevice, factoryDefaultDevice) ) {
2424                 GLRendererQuirks.pushStickyDeviceQuirks(eglFactoryDefaultDevice, quirks);
2425             }
2426         }
2427     }
2428     glRendererQuirks = quirks;
2429     if(DEBUG) {
2430         System.err.println("Quirks local.X: "+glRendererQuirks);
2431         System.err.println("Quirks sticky on "+adevice+": "+GLRendererQuirks.getStickyDeviceQuirks(adevice));
2432     }
2433   }
2434 
hasFBOImpl(final int major, final int ctp, final ExtensionAvailabilityCache extCache)2435   private static final boolean hasFBOImpl(final int major, final int ctp, final ExtensionAvailabilityCache extCache) {
2436     return ( 0 != (ctp & CTX_PROFILE_ES) && major >= 2 ) ||                           // ES >= 2.0
2437 
2438            major >= 3 ||                                                              // any >= 3.0 GL ctx (core, compat and ES)
2439 
2440            ( null != extCache &&
2441              (
2442                extCache.isExtensionAvailable(GLExtensions.ARB_ES2_compatibility)  ||  // ES 2.0 compatible
2443 
2444                extCache.isExtensionAvailable(GLExtensions.ARB_framebuffer_object) ||  // ARB_framebuffer_object
2445 
2446                extCache.isExtensionAvailable(GLExtensions.EXT_framebuffer_object) ||  // EXT_framebuffer_object
2447 
2448                extCache.isExtensionAvailable(GLExtensions.OES_framebuffer_object)     // OES_framebuffer_object
2449              ) );
2450   }
2451 
removeCachedVersion(final int major, final int minor, int ctxProfileBits)2452   private final void removeCachedVersion(final int major, final int minor, int ctxProfileBits) {
2453     if(!isCurrentContextHardwareRasterizer()) {
2454         ctxProfileBits |= GLContext.CTX_IMPL_ACCEL_SOFT;
2455     }
2456     final AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration();
2457     final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice();
2458 
2459     contextFQN = getContextFQN(adevice, major, minor, ctxProfileBits);
2460     if (DEBUG) {
2461       System.err.println(getThreadName() + ": RM Context FQN: "+contextFQN+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, null));
2462     }
2463 
2464     synchronized(mappedContextTypeObjectLock) {
2465         final ProcAddressTable table = mappedGLProcAddress.remove( contextFQN );
2466         if(DEBUG) {
2467             final int hc = null != table ? table.hashCode() : 0;
2468             System.err.println(getThreadName() + ": RM GLContext GL ProcAddressTable mapping key("+contextFQN+") -> "+toHexString(hc));
2469         }
2470     }
2471 
2472     synchronized(mappedContextTypeObjectLock) {
2473         final ExtensionAvailabilityCache  eCache = mappedExtensionAvailabilityCache.remove( contextFQN );
2474         if(DEBUG) {
2475             final int hc = null != eCache ? eCache.hashCode() : 0;
2476             System.err.println(getThreadName() + ": RM GLContext GL ExtensionAvailabilityCache mapping key("+contextFQN+") -> "+toHexString(hc));
2477         }
2478     }
2479   }
2480 
isCurrentContextHardwareRasterizer()2481   private final boolean isCurrentContextHardwareRasterizer()  {
2482     boolean isHardwareRasterizer = true;
2483 
2484     if(!drawable.getChosenGLCapabilities().getHardwareAccelerated()) {
2485         isHardwareRasterizer = false;
2486     } else {
2487         isHardwareRasterizer = ! ( glRendererLowerCase.contains("software") /* Mesa3D, Apple */ ||
2488                                    glRendererLowerCase.contains("mesa x11") /* Mesa3D  */ ||
2489                                    glRendererLowerCase.contains("softpipe") /* Gallium */ ||
2490                                    glRendererLowerCase.contains("llvmpipe") /* Gallium */
2491                                  );
2492     }
2493     return isHardwareRasterizer;
2494   }
2495 
getPlatformExtensionsStringImpl()2496   protected abstract StringBuilder getPlatformExtensionsStringImpl();
2497 
2498   @Override
isFunctionAvailable(final String glFunctionName)2499   public final boolean isFunctionAvailable(final String glFunctionName) {
2500     // Check GL 1st (cached)
2501     if( null != glProcAddressTable ) { // null if this context wasn't not created
2502         try {
2503             if( glProcAddressTable.isFunctionAvailable( glFunctionName ) ) {
2504                 return true;
2505             }
2506         } catch (final Exception e) {}
2507     }
2508 
2509     // Check platform extensions 2nd (cached) - context had to be enabled once
2510     final ProcAddressTable pTable = getPlatformExtProcAddressTable();
2511     if(null!=pTable) {
2512         try {
2513             if( pTable.isFunctionAvailable( glFunctionName ) ) {
2514                 return true;
2515             }
2516         } catch (final Exception e) {}
2517     }
2518 
2519     // dynamic function lookup at last incl name aliasing (not cached)
2520     final DynamicLookupHelper dynLookup = getGLDynamicLookupHelper(ctxVersion.getMajor(), ctxOptions);
2521     if( null == dynLookup ) {
2522         throw new GLException("No GLDynamicLookupHelper for "+this);
2523     }
2524     final String tmpBase = GLNameResolver.normalizeVEN(GLNameResolver.normalizeARB(glFunctionName, true), true);
2525     return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
2526         @Override
2527         public Boolean run() {
2528             boolean res = false;
2529             dynLookup.claimAllLinkPermission();
2530             try {
2531                 final int  variants = GLNameResolver.getFuncNamePermutationNumber(tmpBase);
2532                 for(int i = 0; !res && i < variants; i++) {
2533                     final String tmp = GLNameResolver.getFuncNamePermutation(tmpBase, i);
2534                     try {
2535                         res = dynLookup.isFunctionAvailable(tmp);
2536                     } catch (final Exception e) { }
2537                 }
2538             } finally {
2539                 dynLookup.releaseAllLinkPermission();
2540             }
2541             return Boolean.valueOf(res);
2542         } } ).booleanValue();
2543   }
2544 
2545   @Override
2546   public final boolean isExtensionAvailable(final String glExtensionName) {
2547       if(null!=extensionAvailability) {
2548         return extensionAvailability.isExtensionAvailable(mapToRealGLExtensionName(glExtensionName));
2549       }
2550       return false;
2551   }
2552 
2553   @Override
2554   public final int getPlatformExtensionCount() {
2555       return null != extensionAvailability ? extensionAvailability.getPlatformExtensionCount() : 0;
2556   }
2557 
2558   @Override
2559   public final String getPlatformExtensionsString() {
2560       if(null!=extensionAvailability) {
2561         return extensionAvailability.getPlatformExtensionsString();
2562       }
2563       return null;
2564   }
2565 
2566   @Override
2567   public final int getGLExtensionCount() {
2568       return null != extensionAvailability ? extensionAvailability.getGLExtensionCount() : 0;
2569   }
2570 
2571   @Override
2572   public final String getGLExtensionsString() {
2573       if(null!=extensionAvailability) {
2574         return extensionAvailability.getGLExtensionsString();
2575       }
2576       return null;
2577   }
2578 
2579   public final boolean isExtensionCacheInitialized() {
2580       if(null!=extensionAvailability) {
2581         return extensionAvailability.isInitialized();
2582       }
2583       return false;
2584   }
2585 
2586   protected static String getContextFQN(final AbstractGraphicsDevice device, final int major, final int minor, int ctxProfileBits) {
2587       // remove non-key values
2588       ctxProfileBits &= CTX_IMPL_CACHE_MASK;
2589 
2590       return device.getUniqueID() + "-" + toHexString(composeBits(major, minor, ctxProfileBits));
2591   }
2592 
2593   protected final String getContextFQN() {
2594       return contextFQN;
2595   }
2596 
2597   @Override
2598   public int getDefaultPixelDataType() {
2599       evalPixelDataType();
2600       return pixelDataType;
2601   }
2602 
2603   @Override
2604   public int getDefaultPixelDataFormat() {
2605       evalPixelDataType();
2606       return pixelDataFormat;
2607   }
2608 
2609   private final void evalPixelDataType() {
2610     if(!pixelDataEvaluated) { // only valid while context is made current
2611         boolean ok = false;
2612         /* if(isGL2GL3() && 3 == components) {
2613             pixelDataInternalFormat=GL.GL_RGB;
2614             pixelDataFormat=GL.GL_RGB;
2615             pixelDataType = GL.GL_UNSIGNED_BYTE;
2616             ok = true;
2617         } else */ if( isGLES2Compatible() || isExtensionAvailable(GLExtensions.OES_read_format) ) {
2618             final int[] glImplColorReadVals = new int[] { 0, 0 };
2619             gl.glGetIntegerv(GL.GL_IMPLEMENTATION_COLOR_READ_FORMAT, glImplColorReadVals, 0);
2620             gl.glGetIntegerv(GL.GL_IMPLEMENTATION_COLOR_READ_TYPE, glImplColorReadVals, 1);
2621             // pixelDataInternalFormat = (4 == components) ? GL.GL_RGBA : GL.GL_RGB;
2622             pixelDataFormat = glImplColorReadVals[0];
2623             pixelDataType = glImplColorReadVals[1];
2624             ok = 0 != pixelDataFormat && 0 != pixelDataType;
2625         }
2626         if( !ok ) {
2627             // RGBA read is safe for all GL profiles
2628             // pixelDataInternalFormat = (4 == components) ? GL.GL_RGBA : GL.GL_RGB;
2629             pixelDataFormat=GL.GL_RGBA;
2630             pixelDataType = GL.GL_UNSIGNED_BYTE;
2631         }
2632         // TODO: Consider:
2633         // return gl.isGL2GL3()?GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV:GL.GL_UNSIGNED_SHORT_5_5_5_1;
2634         pixelDataEvaluated = true;
2635     }
2636   }
2637 
2638   //----------------------------------------------------------------------
2639   // SwapBuffer
2640 
2641   @Override
2642   public final boolean setSwapInterval(final int interval) throws GLException {
2643     validateCurrent();
2644     return setSwapIntervalNC(interval);
2645   }
2646   protected final boolean setSwapIntervalNC(final int interval) throws GLException {
2647     if( !drawableRetargeted ||
2648         !hasRendererQuirk(GLRendererQuirks.NoSetSwapIntervalPostRetarget)
2649       )
2650     {
2651         final Integer usedInterval = setSwapIntervalImpl2(interval);
2652         if( null != usedInterval ) {
2653             currentSwapInterval = usedInterval.intValue();
2654             return true;
2655         }
2656     }
2657     return false;
2658   }
2659   protected abstract Integer setSwapIntervalImpl2(final int interval);
2660 
2661   @Override
2662   public final int getSwapInterval() {
2663     return currentSwapInterval;
2664   }
2665   @Override
2666   protected final void setDefaultSwapInterval() {
2667     currentSwapInterval = 0;
2668     setSwapIntervalNC(1);
2669   }
2670 
2671 
2672   //----------------------------------------------------------------------
2673   // Helpers for buffer object optimizations
2674 
2675   public final GLBufferObjectTracker getBufferObjectTracker() {
2676     return bufferObjectTracker;
2677   }
2678 
2679   public final GLBufferStateTracker getBufferStateTracker() {
2680     return bufferStateTracker;
2681   }
2682 
2683   public final GLStateTracker getGLStateTracker() {
2684     return glStateTracker;
2685   }
2686 
2687   //---------------------------------------------------------------------------
2688   // Helpers for context optimization where the last context is left
2689   // current on the OpenGL worker thread
2690   //
2691 
2692   /**
2693    * Returns true if the given thread is owner, otherwise false.
2694    * <p>
2695    * Method exists merely for code validation of {@link #isCurrent()}.
2696    * </p>
2697    */
2698   public final boolean isOwner(final Thread thread) {
2699       return lock.isOwner(thread);
2700   }
2701 
2702   /**
2703    * Returns true if there are other threads waiting for this GLContext to {@link #makeCurrent()}, otherwise false.
2704    * <p>
2705    * Since method does not perform any synchronization, accurate result are returned if lock is hold - only.
2706    * </p>
2707    */
2708   public final boolean hasWaiters() {
2709     return lock.getQueueLength()>0;
2710   }
2711 
2712   /**
2713    * Returns the number of hold locks. See {@link RecursiveLock#getHoldCount()} for semantics.
2714    * <p>
2715    * Since method does not perform any synchronization, accurate result are returned if lock is hold - only.
2716    * </p>
2717    */
2718   public final int getLockCount() {
2719       return lock.getHoldCount();
2720   }
2721 
2722   //---------------------------------------------------------------------------
2723   // Special FBO hook
2724   //
2725 
2726   /**
2727    * Tracks {@link GL#GL_FRAMEBUFFER}, {@link GL2GL3#GL_DRAW_FRAMEBUFFER} and {@link GL2GL3#GL_READ_FRAMEBUFFER}
2728    * to be returned via {@link #getBoundFramebuffer(int)}.
2729    *
2730    * <p>Invoked by {@link GL#glBindFramebuffer(int, int)}. </p>
2731    *
2732    * <p>Assumes valid <code>framebufferName</code> range of [0..{@link Integer#MAX_VALUE}]</p>
2733    *
2734    * <p>Does not throw an exception if <code>target</code> is unknown or <code>framebufferName</code> invalid.</p>
2735    */
2736   public final void setBoundFramebuffer(final int target, final int framebufferName) {
2737       if(0 > framebufferName) {
2738           return; // ignore invalid name
2739       }
2740       switch(target) {
2741           case GL.GL_FRAMEBUFFER:
2742           case GL.GL_DRAW_FRAMEBUFFER:
2743               boundFBOTarget[0] = framebufferName; // draw
2744               break;
2745           case GL.GL_READ_FRAMEBUFFER:
2746               boundFBOTarget[1] = framebufferName; // read
2747               break;
2748           default: // ignore untracked target
2749       }
2750   }
2751   @Override
2752   public final int getBoundFramebuffer(final int target) {
2753       switch(target) {
2754           case GL.GL_FRAMEBUFFER:
2755           case GL.GL_DRAW_FRAMEBUFFER:
2756               return boundFBOTarget[0]; // draw
2757           case GL.GL_READ_FRAMEBUFFER:
2758               return boundFBOTarget[1]; // read
2759           default:
2760               throw new InternalError("Invalid FBO target name: "+toHexString(target));
2761       }
2762   }
2763 
2764   @Override
2765   public final int getDefaultDrawFramebuffer() { return drawable.getDefaultDrawFramebuffer(); }
2766   @Override
2767   public final int getDefaultReadFramebuffer() { return drawable.getDefaultReadFramebuffer(); }
2768   @Override
2769   public final int getDefaultReadBuffer() { return drawable.getDefaultReadBuffer(gl, drawableRead != drawable); }
2770 
2771   //---------------------------------------------------------------------------
2772   // GL_ARB_debug_output, GL_AMD_debug_output helpers
2773   //
2774 
2775   @Override
2776   public final String getGLDebugMessageExtension() {
2777       return glDebugHandler.getExtension();
2778   }
2779 
2780   @Override
2781   public final boolean isGLDebugMessageEnabled() {
2782       return glDebugHandler.isEnabled();
2783   }
2784 
2785   @Override
2786   public final int getContextCreationFlags() {
2787       return additionalCtxCreationFlags;
2788   }
2789 
2790   @Override
2791   public final void setContextCreationFlags(final int flags) {
2792       if(!isCreated()) {
2793           additionalCtxCreationFlags = flags & GLContext.CTX_OPTION_DEBUG;
2794       }
2795   }
2796 
2797   @Override
2798   public final boolean isGLDebugSynchronous() { return glDebugHandler.isSynchronous(); }
2799 
2800   @Override
2801   public final void setGLDebugSynchronous(final boolean synchronous) {
2802       glDebugHandler.setSynchronous(synchronous);
2803   }
2804 
2805   @Override
2806   public final void enableGLDebugMessage(final boolean enable) throws GLException {
2807       if(!isCreated()) {
2808           if(enable) {
2809               additionalCtxCreationFlags |=  GLContext.CTX_OPTION_DEBUG;
2810           } else {
2811               additionalCtxCreationFlags &= ~GLContext.CTX_OPTION_DEBUG;
2812           }
2813       } else if(0 != (additionalCtxCreationFlags & GLContext.CTX_OPTION_DEBUG) &&
2814                 null != getGLDebugMessageExtension()) {
2815           glDebugHandler.enable(enable);
2816       }
2817   }
2818 
2819   @Override
2820   public final void addGLDebugListener(final GLDebugListener listener) {
2821       glDebugHandler.addListener(listener);
2822   }
2823 
2824   @Override
2825   public final void removeGLDebugListener(final GLDebugListener listener) {
2826       glDebugHandler.removeListener(listener);
2827   }
2828 
2829   @Override
2830   public final void glDebugMessageControl(final int source, final int type, final int severity, final int count, final IntBuffer ids, final boolean enabled) {
2831       if(glDebugHandler.isExtensionKHRARB()) {
2832           gl.getGL2ES2().glDebugMessageControl(source, type, severity, count, ids, enabled);
2833       } else if(glDebugHandler.isExtensionAMD()) {
2834           gl.getGL2GL3().glDebugMessageEnableAMD(GLDebugMessage.translateARB2AMDCategory(source, type), severity, count, ids, enabled);
2835       }
2836   }
2837 
2838   @Override
2839   public final void glDebugMessageControl(final int source, final int type, final int severity, final int count, final int[] ids, final int ids_offset, final boolean enabled) {
2840       if(glDebugHandler.isExtensionKHRARB()) {
2841           gl.getGL2ES2().glDebugMessageControl(source, type, severity, count, ids, ids_offset, enabled);
2842       } else if(glDebugHandler.isExtensionAMD()) {
2843           gl.getGL2GL3().glDebugMessageEnableAMD(GLDebugMessage.translateARB2AMDCategory(source, type), severity, count, ids, ids_offset, enabled);
2844       }
2845   }
2846 
2847   @Override
2848   public final void glDebugMessageInsert(final int source, final int type, final int id, final int severity, final String buf) {
2849       final int len = (null != buf) ? buf.length() : 0;
2850       if(glDebugHandler.isExtensionKHRARB()) {
2851           gl.getGL2ES2().glDebugMessageInsert(source, type, id, severity, len, buf);
2852       } else if(glDebugHandler.isExtensionAMD()) {
2853           gl.getGL2GL3().glDebugMessageInsertAMD(GLDebugMessage.translateARB2AMDCategory(source, type), severity, id, len, buf);
2854       }
2855   }
2856 
2857   /** Internal bootstraping glGetString(GL_RENDERER) */
2858   private static native String glGetStringInt(int name, long procAddress);
2859 
2860   /** Internal bootstraping glGetIntegerv(..) for version */
2861   private static native void glGetIntegervInt(int pname, int[] params, int params_offset, long procAddress);
2862 }
2863