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 ≥ 4.5, GL ≥ 3.1 w/ GL_ARB_ES3_[12]_compatibility and GLES ≥ 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 ≥ 4.3, GL ≥ 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