1 /** 2 * Copyright 2012 JogAmp Community. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without modification, are 5 * permitted provided that the following conditions are met: 6 * 7 * 1. Redistributions of source code must retain the above copyright notice, this list of 8 * conditions and the following disclaimer. 9 * 10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 * of conditions and the following disclaimer in the documentation and/or other materials 12 * provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED 15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * 24 * The views and conclusions contained in the software and documentation are those of the 25 * authors and should not be interpreted as representing official policies, either expressed 26 * or implied, of JogAmp Community. 27 */ 28 package com.jogamp.opengl; 29 30 import java.util.IdentityHashMap; 31 32 import com.jogamp.nativewindow.AbstractGraphicsDevice; 33 import com.jogamp.opengl.GLCapabilitiesImmutable; 34 35 import com.jogamp.common.os.Platform; 36 import com.jogamp.opengl.egl.EGL; 37 import com.jogamp.opengl.egl.EGLExt; 38 39 /** 40 * GLRendererQuirks contains information of known bugs of various GL renderer. 41 * This information allows us to workaround them. 42 * <p> 43 * Using centralized quirk identifier enables us to 44 * locate code dealing w/ it and hence eases it's maintenance. 45 * </p> 46 * <p> 47 * <i>Some</i> <code>GL_VENDOR</code> and <code>GL_RENDERER</code> strings are 48 * listed here <http://feedback.wildfiregames.com/report/opengl/feature/GL_VENDOR>. 49 * </p> 50 */ 51 public class GLRendererQuirks { 52 /** 53 * Crashes XServer when using double buffered PBuffer with GL_RENDERER: 54 * <ul> 55 * <li>Mesa DRI Intel(R) Sandybridge Desktop</li> 56 * <li>Mesa DRI Intel(R) Ivybridge Mobile - 3.0 Mesa 8.0.4</li> 57 * <li>Gallium 0.4 on AMD CYPRESS</li> 58 * </ul> 59 * For now, it is safe to disable it w/ hw-acceleration. 60 */ 61 public static final int NoDoubleBufferedPBuffer = 0; 62 63 /** On Windows no double buffered bitmaps are guaranteed to be available. */ 64 public static final int NoDoubleBufferedBitmap = 1; 65 66 /** Crashes application when trying to set EGL swap interval on Android 4.0.3 / Pandaboard ES / PowerVR SGX 540 */ 67 public static final int NoSetSwapInterval = 2; 68 69 /** No offscreen bitmap available, currently true for JOGL's OSX implementation. */ 70 public static final int NoOffscreenBitmap = 3; 71 72 /** SIGSEGV on setSwapInterval() after changing the context's drawable w/ 'Mesa 8.0.4' dri2SetSwapInterval/DRI2 (soft & intel) */ 73 public static final int NoSetSwapIntervalPostRetarget = 4; 74 75 /** 76 * GLSL <code>discard</code> command leads to undefined behavior or won't get compiled if being used. 77 * <p> 78 * Appears to <i>have</i> happened on Nvidia Tegra2, but seems to be fine now.<br/> 79 * FIXME: Constrain version. 80 * </p> 81 */ 82 public static final int GLSLBuggyDiscard = 5; 83 84 /** 85 * Non compliant GL context due to a buggy implementation not suitable for use. 86 * <p> 87 * Currently, Mesa >= 9.1.3 (may extend back as far as 9.0) OpenGL 3.1 compatibility 88 * context is not compliant. Most programs will give completely broken output (or no 89 * output at all. For now, this context is not trusted. 90 * </p> 91 * The above has been confirmed for the following Mesa 9.* GL_RENDERER strings: 92 * <ul> 93 * <li>Mesa .* Intel(R) Sandybridge Desktop</li> 94 * <li>Gallium 0.4 on AMD RS880</li> 95 * </ul> 96 * </p> 97 * <p> 98 * It still has to be verified whether the AMD OpenGL 3.1 core driver is compliant enought. 99 */ 100 public static final int GLNonCompliant = 6; 101 102 /** 103 * The OpenGL context needs a <code>glFlush()</code> before releasing it, otherwise driver may freeze: 104 * <ul> 105 * <li>OSX < 10.7.3 - NVidia Driver. Bug 533 and Bug 548 @ https://jogamp.org/bugzilla/.</li> 106 * </ul> 107 */ 108 public static final int GLFlushBeforeRelease = 7; 109 110 /** 111 * Closing X11 displays may cause JVM crashes or X11 errors with some buggy drivers 112 * while being used in concert w/ OpenGL. 113 * <p> 114 * Some drivers may require X11 displays to be closed in the same order as they were created, 115 * some may not allow them to be closed at all while resources are being used somehow. 116 * </p> 117 * <p> 118 * Drivers known exposing such bug: 119 * <ul> 120 * <li>Mesa < 8.0 _with_ X11 software renderer <code>Mesa X11</code>, not with GLX/DRI renderer.</li> 121 * <li>ATI proprietary Catalyst X11 driver versions: 122 * <ul> 123 * <li>8.78.6</li> 124 * <li>8.881</li> 125 * <li>8.911</li> 126 * <li>9.01.8</li> 127 * </ul></li> 128 * </ul> 129 * </p> 130 * <p> 131 * See Bug 515 - https://jogamp.org/bugzilla/show_bug.cgi?id=515 132 * and {@link jogamp.nativewindow.x11.X11Util#ATI_HAS_XCLOSEDISPLAY_BUG}. 133 * </p> 134 * <p> 135 * See Bug 705 - https://jogamp.org/bugzilla/show_bug.cgi?id=705 136 * </p> 137 */ 138 public static final int DontCloseX11Display = 8; 139 140 /** 141 * Need current GL context when calling new ARB <i>pixel format query</i> functions, 142 * otherwise driver crashes the VM. 143 * <p> 144 * Drivers known exposing such bug: 145 * <ul> 146 * <li>ATI proprietary Catalyst driver on Windows version ≤ XP. 147 * TODO: Validate if bug actually relates to 'old' ATI Windows drivers for old GPU's like X300 148 * regardless of the Windows version.</li> 149 * </ul> 150 * <p> 151 * See Bug 480 - https://jogamp.org/bugzilla/show_bug.cgi?id=480 152 * </p> 153 */ 154 public static final int NeedCurrCtx4ARBPixFmtQueries = 9; 155 156 /** 157 * Need current GL context when calling new ARB <i>CreateContext</i> function, 158 * otherwise driver crashes the VM. 159 * <p> 160 * Drivers known exposing such bug: 161 * <ul> 162 * <li>ATI proprietary Catalyst Windows driver on laptops with a driver version as reported in <i>GL_VERSION</i>: 163 * <ul> 164 * <li> <i>null</i> </li> 165 * <li> < <code>12.102.3.0</code> ( <i>amd_catalyst_13.5_mobility_beta2</i> ) </li> 166 * </ul></li> 167 * </ul> 168 * </p> 169 * <p> 170 * See Bug 706 - https://jogamp.org/bugzilla/show_bug.cgi?id=706<br/> 171 * See Bug 520 - https://jogamp.org/bugzilla/show_bug.cgi?id=520 172 * </p> 173 */ 174 public static final int NeedCurrCtx4ARBCreateContext = 10; 175 176 /** 177 * No full FBO support, i.e. not compliant w/ 178 * <ul> 179 * <li>GL_ARB_framebuffer_object</li> 180 * <li>EXT_framebuffer_object</li> 181 * <li>EXT_framebuffer_multisample</li> 182 * <li>EXT_framebuffer_blit</li> 183 * <li>EXT_packed_depth_stencil</li> 184 * </ul>. 185 * Drivers known exposing such bug: 186 * <ul> 187 * <li>Mesa <i>7.12-devel</i> on Windows with VMware <i>SVGA3D</i> renderer: 188 * <ul> 189 * <li>GL_VERSION: <i>2.1 Mesa 7.12-devel (git-d6c318e)</i> </li> 190 * <li>GL_RENDERER: <i>Gallium 0.4 on SVGA3D; build: RELEASE;</i> </li> 191 * </ul></li> 192 * </ul> 193 * <p> 194 * Also enabled via {@link #BuggyColorRenderbuffer}. 195 * </p> 196 * <p> 197 * Quirk can also be enabled via property: <code>jogl.fbo.force.min</code>. 198 * </p> 199 */ 200 public static final int NoFullFBOSupport = 11; 201 202 /** 203 * GLSL is not compliant or even not stable (crash) 204 * <ul> 205 * <li>OSX < 10.7.0 (?) - NVidia Driver. Bug 818 @ https://jogamp.org/bugzilla/.</li> 206 * </ul> 207 */ 208 public static final int GLSLNonCompliant = 12; 209 210 /** 211 * GL4 context needs to be requested via GL3 profile attribute 212 * <ul> 213 * <li>OSX >= 10.9.0 - kCGLOGLPVersion_GL4_Core may not produce hw-accel context. Bug 867 @ https://jogamp.org/bugzilla/.</li> 214 * </ul> 215 */ 216 public static final int GL4NeedsGL3Request = 13; 217 218 /** 219 * Buggy shared OpenGL context support within a multithreaded use-case, not suitable for stable usage. 220 * <p> 221 * <i>X11 Mesa DRI Intel(R) driver >= 9.2.1</i> cannot handle multithreaded shared GLContext usage 222 * with non-blocking exclusive X11 display connections. 223 * References: 224 * <ul> 225 * <li>Bug 873: https://jogamp.org/bugzilla/show_bug.cgi?id=873</li> 226 * <li>https://bugs.freedesktop.org/show_bug.cgi?id=41736#c8</li> 227 * </ul> 228 * <p> 229 * However, not all multithreaded use-cases are broken, e.g. our GLMediaPlayer does work. 230 * </p> 231 * The above has been confirmed for the following Mesa 9.* strings: 232 * <ul> 233 * <li>GL_VENDOR Intel Open Source Technology Center</li> 234 * <li>GL_RENDERER Mesa DRI Intel(R) Sandybridge Desktop</li> 235 * <li>GL_RENDERER Mesa DRI Intel(R) Ivybridge Mobile</li> 236 * <li>GL_VERSION 3.1 (Core Profile) Mesa 9.2.1</li> 237 * </ul> 238 * </p> 239 * <p> 240 * On Android 4.*, <i>Huawei's Ascend G615 w/ Immersion.16</i> could not make a shared context 241 * current, which uses a pbuffer drawable: 242 * <ul> 243 * <li>Android 4.*</li> 244 * <li>GL_VENDOR Hisilicon Technologies</li> 245 * <li>GL_RENDERER Immersion.16</li> 246 * <li>GL_VERSION OpenGL ES 2.0</li> 247 * </ul> 248 * </p> 249 * <p> 250 * </p> 251 */ 252 public static final int GLSharedContextBuggy = 14; 253 254 /** 255 * Bug 925 - Accept an ES3 Context, if reported via GL-Version-String w/o {@link EGLExt#EGL_OPENGL_ES3_BIT_KHR}. 256 * <p> 257 * The ES3 Context can be used via {@link EGL#EGL_OPENGL_ES2_BIT}. 258 * </p> 259 * <p> 260 * The ES3 Context {@link EGL#eglCreateContext(long, long, long, java.nio.IntBuffer) must be created} with version attributes: 261 * <pre> 262 * EGL.EGL_CONTEXT_CLIENT_VERSION, 2, .. 263 * </pre> 264 * </p> 265 * <ul> 266 * <li>Mesa/AMD >= 9.2.1</li> 267 * <li>Some Android ES3 drivers ..</li> 268 * </ul> 269 */ 270 public static final int GLES3ViaEGLES2Config = 15; 271 272 /** 273 * Bug 948 - NVIDIA 331.38 (Linux X11) EGL impl. only supports _one_ EGL Device via {@link EGL#eglGetDisplay(long)}. 274 * <p> 275 * Subsequent calls to {@link EGL#eglGetDisplay(long)} fail. 276 * </p> 277 * <p> 278 * Reusing global EGL display works. 279 * </p> 280 * <p> 281 * The quirk is autodetected within EGLDrawableFactory's initial default device setup! 282 * </p> 283 * <p> 284 * Appears on: 285 * <ul> 286 * <li>EGL_VENDOR NVIDIA</li> 287 * <li>EGL_VERSION 1.4</li> 288 * <li>GL_VENDOR NVIDIA Corporation</li> 289 * <li>GL_VERSION OpenGL ES 3.0 331.38 (probably w/ 1st NV EGL lib on x86)</li> 290 * <li>GL_VERSION OpenGL ES 3.1 NVIDIA 355.06 (unstable)</li> 291 * <li>Platform X11</li> 292 * <li>CPU Family {@link Platform.CPUFamily#X86}</li> 293 * </ul> 294 * </p> 295 */ 296 public static final int SingletonEGLDisplayOnly = 16; 297 298 /** 299 * No reliable MSAA / FSAA {@link GLCapabilitiesImmutable#getSampleBuffers() multi} 300 * {@link GLCapabilitiesImmutable#getNumSamples() sampling} available, 301 * i.e. driver <i>may crash</i>. 302 * <p> 303 * Appears on: 304 * <ul> 305 * <li>GL_VENDOR nouveau</li> 306 * <li>GL_RENDERER Gallium 0.4 on NV34</li> 307 * </ul> 308 * TODO: We have to determine the exact version range, i.e. not adding the quirk with fixed driver version! 309 * </p> 310 * TODO: Since we currently don't handle this quirk internally, a user may need to do the following: 311 * <pre> 312 * final AbstractGraphicsDevice adevice = GLDrawableFactory.getDesktopFactory(); // or similar 313 * if( GLRendererQuirks.existStickyDeviceQuirk(adevice, GLRendererQuirks.NoMultiSamplingBuffers) ) { 314 * // don't use MSAA 315 * } 316 * </pre> 317 */ 318 public static final int NoMultiSamplingBuffers = 17; 319 320 /** 321 * Buggy FBO color renderbuffer target, 322 * i.e. driver <i>may crash</i>. 323 * <p> 324 * Appears on: 325 * <ul> 326 * <li>GL_VENDOR Brian Paul</li> 327 * <li>GL_RENDERER Mesa X11</li> 328 * <li>GL_VERSION 2.1 Mesa 7.2</li> 329 * </ul> 330 * TODO: We have to determine the exact version range, i.e. not adding the quirk with fixed driver version! 331 * </p> 332 * <p> 333 * Note: Also enables {@link #NoFullFBOSupport}. 334 * </p> 335 * <p> 336 * Note: GLFBODrawable always uses texture attachments if set. 337 * </p> 338 * <p> 339 * Quirk can also be enabled via property: <code>jogl.fbo.force.nocolorrenderbuffer</code>. 340 * </p> 341 */ 342 public static final int BuggyColorRenderbuffer = 18; 343 344 /** 345 * No pbuffer supporting accumulation buffers available, 346 * even if driver claims otherwise. 347 * <p> 348 * Some drivers wrongly claim to support pbuffers 349 * with accumulation buffers. However, the creation of such pbuffer fails: 350 * <pre> 351 * com.jogamp.opengl.GLException: pbuffer creation error: Couldn't find a suitable pixel format 352 * </pre> 353 * </p> 354 * <p> 355 * Appears on: 356 * <ul> 357 * <li>GL_VENDOR Intel</li> 358 * <li>GL_RENDERER Intel Bear Lake B</li> 359 * <li>GL_VERSION 1.4.0 - Build 8.14.10.1930</li> 360 * <li>Platform Windows</li> 361 * </ul> 362 * </p> 363 */ 364 public static final int NoPBufferWithAccum = 19; 365 366 /** 367 * Need GL objects (VBO, ..) to be synchronized when utilized 368 * concurrently from multiple threads via a shared GL context, 369 * otherwise driver crashes the VM. 370 * <p> 371 * Usually synchronization should not be required, if the shared GL objects 372 * are created and immutable before concurrent usage.<br> 373 * However, using drivers exposing this issue always require the user to 374 * synchronize access of shared GL objects. 375 * </p> 376 * <p> 377 * Synchronization can be avoided if accessing the shared GL objects 378 * exclusively via a queue or {@link com.jogamp.common.util.Ringbuffer Ringbuffer}, see GLMediaPlayerImpl as an example. 379 * </p> 380 * <p> 381 * Appears on: 382 * <ul> 383 * <li>Platform OSX 384 * <ul> 385 * <li>detected on OSX 10.9.5 first</li> 386 * <li>any driver</li> 387 * <li>enabled for all OSX versions</li> 388 * </ul> 389 * </li> 390 * </ul> 391 * </p> 392 * <p> 393 * See Bug 1088 - https://jogamp.org/bugzilla/show_bug.cgi?id=1088 394 * </p> 395 */ 396 public static final int NeedSharedObjectSync = 20; 397 398 /** 399 * No reliable ARB_create_context implementation, 400 * even if driver claims otherwise. 401 * <p> 402 * Some drivers wrongly claim to support ARB_create_context. 403 * However, the creation of such context fails: 404 * <pre> 405 * com.jogamp.opengl.GLException: AWT-EventQueue-0: WindowsWGLContex.createContextImpl ctx !ARB, profile > GL2 406 * requested (OpenGL >= 3.0.1). Requested: GLProfile[GL3bc/GL3bc.hw], current: 2.1 (Compat profile, FBO, hardware) 407 * - 2.1.8787 408 * </pre> 409 * </p> 410 * <p> 411 * Appears on: 412 * <ul> 413 * <li>GL_VENDOR ATI Technologies Inc.</li> 414 * <li>GL_RENDERER ATI Radeon 3100 Graphics</li> 415 * <li>GL_VERSION 2.1.8787</li> 416 * <li>Platform Windows</li> 417 * </ul> 418 * </p> 419 */ 420 public static final int NoARBCreateContext = 21; 421 422 /** 423 * No support for ES or desktop GL >= 3.0 current context without surface, 424 * i.e. without a default framebuffer as read- and write drawables. 425 * <p> 426 * See <i>OpenGL spec 3.0, chapter 2.1 OpenGL Fundamentals, page 7</i> or<br> 427 * <i>OpenGL ES spec 3.0.2, chapter 2.1 OpenGL Fundamentals, page 6</i>: 428 * <pre> 429 * It is possible to use a GL context without a default framebuffer, in which case 430 * a framebuffer object must be used to perform all rendering. This is useful for 431 * applications neeting to perform offscreen rendering. 432 * </pre> 433 * </p> 434 * <p> 435 * The feature will be attempted at initialization and this quirk will be set if failing. 436 * </p> 437 * <p> 438 * Known drivers failing the specification: 439 * <ul> 440 * <li>GNU/Linux X11 Nvidia proprietary driver 441 * <ul> 442 * <li>GL_VERSION 4.4.0 NVIDIA 340.24</li> 443 * <li>Platform GNU/Linux X11</li> 444 * </ul></li> 445 * </ul> 446 * </p> 447 */ 448 public static final int NoSurfacelessCtx = 22; 449 450 /** Return the number of known quirks. */ getCount()451 public static final int getCount() { return 23; } 452 453 private static final String[] _names = new String[] { "NoDoubleBufferedPBuffer", "NoDoubleBufferedBitmap", "NoSetSwapInterval", 454 "NoOffscreenBitmap", "NoSetSwapIntervalPostRetarget", "GLSLBuggyDiscard", 455 "GLNonCompliant", "GLFlushBeforeRelease", "DontCloseX11Display", 456 "NeedCurrCtx4ARBPixFmtQueries", "NeedCurrCtx4ARBCreateContext", 457 "NoFullFBOSupport", "GLSLNonCompliant", "GL4NeedsGL3Request", 458 "GLSharedContextBuggy", "GLES3ViaEGLES2Config", "SingletonEGLDisplayOnly", 459 "NoMultiSamplingBuffers", "BuggyColorRenderbuffer", "NoPBufferWithAccum", 460 "NeedSharedObjectSync", "NoARBCreateContext", "NoSurfacelessCtx" 461 }; 462 463 private static final IdentityHashMap<String, GLRendererQuirks> stickyDeviceQuirks = new IdentityHashMap<String, GLRendererQuirks>(); 464 465 /** 466 * Retrieval of sticky {@link AbstractGraphicsDevice}'s {@link GLRendererQuirks}. 467 * <p> 468 * The {@link AbstractGraphicsDevice}s are mapped via their {@link AbstractGraphicsDevice#getUniqueID()}. 469 * </p> 470 * <p> 471 * Not thread safe. 472 * </p> 473 * @see #areSameStickyDevice(AbstractGraphicsDevice, AbstractGraphicsDevice) 474 */ getStickyDeviceQuirks(final AbstractGraphicsDevice device)475 public static GLRendererQuirks getStickyDeviceQuirks(final AbstractGraphicsDevice device) { 476 final String key = device.getUniqueID(); 477 final GLRendererQuirks has = stickyDeviceQuirks.get(key); 478 final GLRendererQuirks res; 479 if( null == has ) { 480 res = new GLRendererQuirks(); 481 stickyDeviceQuirks.put(key, res); 482 } else { 483 res = has; 484 } 485 return res; 486 } 487 488 /** 489 * Returns true if both devices have the same {@link AbstractGraphicsDevice#getUniqueID()}, 490 * otherwise false. 491 */ areSameStickyDevice(final AbstractGraphicsDevice device1, final AbstractGraphicsDevice device2)492 public static boolean areSameStickyDevice(final AbstractGraphicsDevice device1, final AbstractGraphicsDevice device2) { 493 return device1.getUniqueID() == device2.getUniqueID(); // uses .intern()! 494 } 495 496 /** 497 * {@link #addQuirk(int) Adding given quirk} of sticky {@link AbstractGraphicsDevice}'s {@link GLRendererQuirks}. 498 * <p> 499 * Not thread safe. 500 * </p> 501 * @see #getStickyDeviceQuirks(AbstractGraphicsDevice) 502 */ addStickyDeviceQuirk(final AbstractGraphicsDevice device, final int quirk)503 public static void addStickyDeviceQuirk(final AbstractGraphicsDevice device, final int quirk) throws IllegalArgumentException { 504 final GLRendererQuirks sq = getStickyDeviceQuirks(device); 505 sq.addQuirk(quirk); 506 } 507 /** 508 * {@link #addQuirks(int[], int, int) Adding given quirks} of sticky {@link AbstractGraphicsDevice}'s {@link GLRendererQuirks}. 509 * <p> 510 * Not thread safe. 511 * </p> 512 * @see #getStickyDeviceQuirks(AbstractGraphicsDevice) 513 */ addStickyDeviceQuirks(final AbstractGraphicsDevice device, final int[] quirks, final int offset, final int len)514 public static void addStickyDeviceQuirks(final AbstractGraphicsDevice device, final int[] quirks, final int offset, final int len) throws IllegalArgumentException { 515 final GLRendererQuirks sq = getStickyDeviceQuirks(device); 516 sq.addQuirks(quirks, offset, len); 517 } 518 /** 519 * {@link #addQuirks(GLRendererQuirks) Adding given quirks} of sticky {@link AbstractGraphicsDevice}'s {@link GLRendererQuirks}. 520 * <p> 521 * Not thread safe. 522 * </p> 523 * @see #getStickyDeviceQuirks(AbstractGraphicsDevice) 524 */ addStickyDeviceQuirks(final AbstractGraphicsDevice device, final GLRendererQuirks quirks)525 public static void addStickyDeviceQuirks(final AbstractGraphicsDevice device, final GLRendererQuirks quirks) throws IllegalArgumentException { 526 final GLRendererQuirks sq = getStickyDeviceQuirks(device); 527 sq.addQuirks(quirks); 528 } 529 /** 530 * {@link #exist(int) Query} of sticky {@link AbstractGraphicsDevice}'s {@link GLRendererQuirks}. 531 * <p> 532 * Not thread safe. However, use after changing the sticky quirks is safe. 533 * </p> 534 * @see #getStickyDeviceQuirks(AbstractGraphicsDevice) 535 */ existStickyDeviceQuirk(final AbstractGraphicsDevice device, final int quirk)536 public static boolean existStickyDeviceQuirk(final AbstractGraphicsDevice device, final int quirk) { 537 return getStickyDeviceQuirks(device).exist(quirk); 538 } 539 /** 540 * {@link #addQuirks(GLRendererQuirks) Pushing} the sticky {@link AbstractGraphicsDevice}'s {@link GLRendererQuirks} 541 * to the given {@link GLRendererQuirks destination}. 542 * <p> 543 * Not thread safe. However, use after changing the sticky quirks is safe. 544 * </p> 545 * @see #getStickyDeviceQuirks(AbstractGraphicsDevice) 546 */ pushStickyDeviceQuirks(final AbstractGraphicsDevice device, final GLRendererQuirks dest)547 public static void pushStickyDeviceQuirks(final AbstractGraphicsDevice device, final GLRendererQuirks dest) { 548 dest.addQuirks(getStickyDeviceQuirks(device)); 549 } 550 551 private int _bitmask; 552 GLRendererQuirks()553 public GLRendererQuirks() { 554 _bitmask = 0; 555 } 556 557 /** 558 * @param quirks an array of valid quirks 559 * @param offset offset in quirks array to start reading 560 * @param len number of quirks to read from offset within quirks array 561 * @throws IllegalArgumentException if one of the quirks is out of range 562 */ GLRendererQuirks(final int[] quirks, final int offset, final int len)563 public GLRendererQuirks(final int[] quirks, final int offset, final int len) throws IllegalArgumentException { 564 this(); 565 addQuirks(quirks, offset, len); 566 } 567 568 /** 569 * @param quirk valid quirk to be added 570 * @throws IllegalArgumentException if the quirk is out of range 571 */ addQuirk(final int quirk)572 public final void addQuirk(final int quirk) throws IllegalArgumentException { 573 validateQuirk(quirk); 574 _bitmask |= 1 << quirk; 575 } 576 577 /** 578 * @param quirks an array of valid quirks to be added 579 * @param offset offset in quirks array to start reading 580 * @param len number of quirks to read from offset within quirks array 581 * @throws IllegalArgumentException if one of the quirks is out of range 582 */ addQuirks(final int[] quirks, final int offset, final int len)583 public final void addQuirks(final int[] quirks, final int offset, final int len) throws IllegalArgumentException { 584 int bitmask = 0; 585 if( !( 0 <= offset + len && offset + len <= quirks.length ) ) { 586 throw new IllegalArgumentException("offset and len out of bounds: offset "+offset+", len "+len+", array-len "+quirks.length); 587 } 588 for(int i=offset; i<offset+len; i++) { 589 final int quirk = quirks[i]; 590 validateQuirk(quirk); 591 bitmask |= 1 << quirk; 592 } 593 _bitmask |= bitmask; 594 } 595 596 /** 597 * @param quirks valid GLRendererQuirks to be added 598 */ addQuirks(final GLRendererQuirks quirks)599 public final void addQuirks(final GLRendererQuirks quirks) { 600 _bitmask |= quirks._bitmask; 601 } 602 603 /** 604 * @param quirk the quirk to be tested 605 * @return true if quirk exist, otherwise false 606 * @throws IllegalArgumentException if quirk is out of range 607 */ exist(final int quirk)608 public final boolean exist(final int quirk) throws IllegalArgumentException { 609 validateQuirk(quirk); 610 return 0 != ( ( 1 << quirk ) & _bitmask ); 611 } 612 toString(StringBuilder sb)613 public final StringBuilder toString(StringBuilder sb) { 614 if(null == sb) { 615 sb = new StringBuilder(); 616 } 617 sb.append("["); 618 boolean first=true; 619 for(int i=0; i<getCount(); i++) { 620 final int testmask = 1 << i; 621 if( 0 != ( _bitmask & testmask ) ) { 622 if(!first) { sb.append(", "); } 623 sb.append(toString(i)); 624 first=false; 625 } 626 } 627 sb.append("]"); 628 return sb; 629 } 630 631 @Override toString()632 public final String toString() { 633 return toString(null).toString(); 634 } 635 636 /** 637 * @param quirk the quirk to be validated, i.e. whether it is out of range 638 * @throws IllegalArgumentException if quirk is out of range 639 */ validateQuirk(final int quirk)640 public static void validateQuirk(final int quirk) throws IllegalArgumentException { 641 if( !( 0 <= quirk && quirk < getCount() ) ) { 642 throw new IllegalArgumentException("Quirks must be in range [0.."+getCount()+"[, but quirk: "+quirk); 643 } 644 } 645 646 /** 647 * @param quirk the quirk to be converted to String 648 * @return the String equivalent of this quirk 649 * @throws IllegalArgumentException if quirk is out of range 650 */ toString(final int quirk)651 public static final String toString(final int quirk) throws IllegalArgumentException { 652 validateQuirk(quirk); 653 return _names[quirk]; 654 } 655 } 656