From 613e33ee8ffc1f2b9c5db1e1b5bb5253a159ed6d Mon Sep 17 00:00:00 2001
From: Sven Gothel <sgothel@jausoft.com>
Date: Mon, 4 Nov 2013 15:07:14 +0100
Subject: Bug 888 - Validate CPU Runtime Performance:
 X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(..)

X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(..) ran over all FB configs and for each it grabbed
native config values separately. Fetching them in bulk mode saves around 7% of this function's cost.

Also reuse XRenderPictFormat instance for 'XRenderDirectFormat XRenderFindVisualFormat(..)' call,
saving a few NIO creation cycles w/ StructAccessor.

Biggest savior is X11GLXGraphicsConfigurationFactory.chooseGraphicsConfigurationFBConfig()'s
fast path w/o chooser and usable 1st FBConfig. Here we only issue 'GLXFBConfig2GLCapabilities(..)'
on the first valid entry.

Test w/ 50 X11GLXGraphicsConfigurationFactory.chooseGraphicsConfigurationFBConfig() invocations:
  - pre change:  1.708 ms
  - post change:   650 ms

Time is no spent almost solely on native glXChooseFBConfig (546ms).
---
 .../x11/glx/X11GLXGraphicsConfiguration.java       | 144 +++++++++++++++------
 .../glx/X11GLXGraphicsConfigurationFactory.java    |  46 ++++---
 2 files changed, 129 insertions(+), 61 deletions(-)

(limited to 'src/jogl/classes/jogamp/opengl/x11')

diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java
index 4d1ed3985..ee3e1a3d7 100644
--- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java
+++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java
@@ -34,6 +34,8 @@
 package jogamp.opengl.x11.glx;
 
 import java.nio.IntBuffer;
+import java.util.ArrayList;
+import java.util.List;
 
 import javax.media.nativewindow.CapabilitiesImmutable;
 import javax.media.nativewindow.GraphicsConfigurationFactory;
@@ -61,7 +63,7 @@ import com.jogamp.nativewindow.x11.X11GraphicsScreen;
 
 public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implements Cloneable {
     public static final int MAX_ATTRIBS = 128;
-    private GLCapabilitiesChooser chooser;
+    private final GLCapabilitiesChooser chooser;
 
     X11GLXGraphicsConfiguration(X11GraphicsScreen screen,
                                 X11GLCapabilities capsChosen, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser) {
@@ -274,15 +276,47 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem
     }
     return renderPictFmt.getDirect();
   }
+  static XRenderDirectFormat XVisual2XRenderMask(long dpy, long visual, XRenderPictFormat dest) {
+    if( !X11Lib.XRenderFindVisualFormat(dpy, visual, dest) ) {
+        return null;
+    } else {
+        return dest.getDirect();
+    }
+  }
+
+  static X11GLCapabilities GLXFBConfig2GLCapabilities(final X11GraphicsDevice device, final GLProfile glp, final long fbcfg,
+                                                      final int winattrmask, final boolean isMultisampleAvailable) {
+    final IntBuffer tmp = Buffers.newDirectIntBuffer(1);
+    final XRenderPictFormat xRenderPictFormat= XRenderPictFormat.create();
+    return GLXFBConfig2GLCapabilities(device, glp, fbcfg, winattrmask, isMultisampleAvailable, tmp, xRenderPictFormat);
+  }
 
-  static X11GLCapabilities GLXFBConfig2GLCapabilities(X11GraphicsDevice device, GLProfile glp, long fbcfg,
-                                                      int winattrmask, boolean isMultisampleAvailable) {
+  static List<GLCapabilitiesImmutable> GLXFBConfig2GLCapabilities(final X11GraphicsDevice device, final GLProfile glp, final PointerBuffer fbcfgsL,
+                                                                  final int winattrmask, final boolean isMultisampleAvailable, boolean onlyFirstValid) {
+    final IntBuffer tmp = Buffers.newDirectIntBuffer(1);
+    final XRenderPictFormat xRenderPictFormat= XRenderPictFormat.create();
+    final List<GLCapabilitiesImmutable> result = new ArrayList<GLCapabilitiesImmutable>();
+    for (int i = 0; i < fbcfgsL.limit(); i++) {
+        final long fbcfg = fbcfgsL.get(i);
+        final GLCapabilitiesImmutable c = GLXFBConfig2GLCapabilities(device, glp, fbcfg, winattrmask, isMultisampleAvailable, tmp, xRenderPictFormat);
+        if( null != c ) {
+            result.add(c);
+            if( onlyFirstValid ) {
+                break;
+            }
+        }
+    }
+    return result;
+  }
+  static X11GLCapabilities GLXFBConfig2GLCapabilities(final X11GraphicsDevice device, final GLProfile glp, final long fbcfg,
+                                                      final int winattrmask, final boolean isMultisampleAvailable,
+                                                      final IntBuffer tmp, final XRenderPictFormat xRenderPictFormat) {
+    final long display = device.getHandle();
     final int allDrawableTypeBits = FBCfgDrawableTypeBits(device, fbcfg);
     int drawableTypeBits = winattrmask & allDrawableTypeBits;
 
-    final long display = device.getHandle();
-    int fbcfgid = X11GLXGraphicsConfiguration.glXFBConfig2FBConfigID(display, fbcfg);
-    XVisualInfo visualInfo = GLX.glXGetVisualFromFBConfig(display, fbcfg);
+    final int fbcfgid = X11GLXGraphicsConfiguration.glXFBConfig2FBConfigID(display, fbcfg);
+    final XVisualInfo visualInfo = GLX.glXGetVisualFromFBConfig(display, fbcfg);
     if(null == visualInfo) {
         if(DEBUG) {
             System.err.println("X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities: Null XVisualInfo for FBConfigID 0x" + Integer.toHexString(fbcfgid));
@@ -290,51 +324,87 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem
         // onscreen must have an XVisualInfo
         drawableTypeBits &= ~(GLGraphicsConfigurationUtil.WINDOW_BIT | GLGraphicsConfigurationUtil.FBO_BIT);
     }
-
     if( 0 == drawableTypeBits ) {
-        return null;
+      if(DEBUG) {
+          System.err.println("X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities: zero drawablebits: winattrmask: "+toHexString(winattrmask)+", offscreen "+(null == visualInfo));
+      }
+      return null;
     }
 
-    final IntBuffer tmp = Buffers.newDirectIntBuffer(1);
     if(GLX.GLX_BAD_ATTRIBUTE == GLX.glXGetFBConfigAttrib(display, fbcfg, GLX.GLX_RENDER_TYPE, tmp)) {
+      if(DEBUG) {
+          System.err.println("X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities: FBConfig invalid (1): fbcfg: "+toHexString(fbcfg));
+      }
       return null;
     }
     if( 0 == ( GLX.GLX_RGBA_BIT & tmp.get(0) ) ) {
-      return null; // no RGBA -> color index not supported
+      // no RGBA -> color index not supported
+      if(DEBUG) {
+          System.err.println("X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities: FBConfig not RGBA (2): fbcfg: "+toHexString(fbcfg));
+      }
+      return null;
     }
 
-    final X11GLCapabilities res = new X11GLCapabilities(visualInfo, fbcfg, fbcfgid, glp);
-    if (isMultisampleAvailable) {
-      res.setSampleBuffers(glXGetFBConfig(display, fbcfg, GLX.GLX_SAMPLE_BUFFERS, tmp) != 0);
-      res.setNumSamples   (glXGetFBConfig(display, fbcfg, GLX.GLX_SAMPLES,        tmp));
-    }
+    final X11GLCapabilities caps = new X11GLCapabilities(visualInfo, fbcfg, fbcfgid, glp);
+
     final XRenderDirectFormat xrmask = ( null != visualInfo ) ?
-                                         XVisual2XRenderMask( display, visualInfo.getVisual() ) :
+                                         XVisual2XRenderMask( display, visualInfo.getVisual(), xRenderPictFormat) :
                                          null ;
+
+    final int _attributes[] = {
+            GLX.GLX_SAMPLE_BUFFERS,
+            GLX.GLX_SAMPLES,
+            GLX.GLX_DOUBLEBUFFER,
+            GLX.GLX_STEREO,
+            GLX.GLX_CONFIG_CAVEAT,
+            GLX.GLX_RED_SIZE,
+            GLX.GLX_GREEN_SIZE,
+            GLX.GLX_BLUE_SIZE,
+            GLX.GLX_ALPHA_SIZE,
+            GLX.GLX_ACCUM_RED_SIZE,
+            GLX.GLX_ACCUM_GREEN_SIZE,
+            GLX.GLX_ACCUM_BLUE_SIZE,
+            GLX.GLX_ACCUM_ALPHA_SIZE,
+            GLX.GLX_DEPTH_SIZE,
+            GLX.GLX_STENCIL_SIZE
+    };
+    final int offset = isMultisampleAvailable ? 0 : 2;
+    final IntBuffer attributes = Buffers.newDirectIntBuffer(_attributes);
+    attributes.position(offset);
+    final IntBuffer values = Buffers.newDirectIntBuffer(attributes.remaining());
+    final int err = GLX.glXGetFBConfigAttributes(display, fbcfg, attributes, values);
+    if (0 != err) {
+      throw new GLException("glXGetFBConfig("+toHexString(attributes.get(offset+values.get(0)))+") failed: error code " + glXGetFBConfigErrorCode(err));
+    }
+    int j=0;
+    if (isMultisampleAvailable) {
+      caps.setSampleBuffers(values.get(j++) != 0);
+      caps.setNumSamples   (values.get(j++));
+    }
     final int alphaMask = ( null != xrmask ) ? xrmask.getAlphaMask() : 0;
-    res.setBackgroundOpaque( 0 >= alphaMask );
-    if( !res.isBackgroundOpaque() ) {
-        res.setTransparentRedValue(xrmask.getRedMask());
-        res.setTransparentGreenValue(xrmask.getGreenMask());
-        res.setTransparentBlueValue(xrmask.getBlueMask());
-        res.setTransparentAlphaValue(alphaMask);
+    caps.setBackgroundOpaque( 0 >= alphaMask );
+    if( !caps.isBackgroundOpaque() ) {
+        caps.setTransparentRedValue(xrmask.getRedMask());
+        caps.setTransparentGreenValue(xrmask.getGreenMask());
+        caps.setTransparentBlueValue(xrmask.getBlueMask());
+        caps.setTransparentAlphaValue(alphaMask);
     }
     // ALPHA shall be set at last - due to it's auto setting by the above (!opaque / samples)
-    res.setDoubleBuffered(glXGetFBConfig(display, fbcfg, GLX.GLX_DOUBLEBUFFER,     tmp) != 0);
-    res.setStereo        (glXGetFBConfig(display, fbcfg, GLX.GLX_STEREO,           tmp) != 0);
-    res.setHardwareAccelerated(glXGetFBConfig(display, fbcfg, GLX.GLX_CONFIG_CAVEAT, tmp) != GLX.GLX_SLOW_CONFIG);
-    res.setRedBits       (glXGetFBConfig(display, fbcfg, GLX.GLX_RED_SIZE,         tmp));
-    res.setGreenBits     (glXGetFBConfig(display, fbcfg, GLX.GLX_GREEN_SIZE,       tmp));
-    res.setBlueBits      (glXGetFBConfig(display, fbcfg, GLX.GLX_BLUE_SIZE,        tmp));
-    res.setAlphaBits     (glXGetFBConfig(display, fbcfg, GLX.GLX_ALPHA_SIZE,       tmp));
-    res.setAccumRedBits  (glXGetFBConfig(display, fbcfg, GLX.GLX_ACCUM_RED_SIZE,   tmp));
-    res.setAccumGreenBits(glXGetFBConfig(display, fbcfg, GLX.GLX_ACCUM_GREEN_SIZE, tmp));
-    res.setAccumBlueBits (glXGetFBConfig(display, fbcfg, GLX.GLX_ACCUM_BLUE_SIZE,  tmp));
-    res.setAccumAlphaBits(glXGetFBConfig(display, fbcfg, GLX.GLX_ACCUM_ALPHA_SIZE, tmp));
-    res.setDepthBits     (glXGetFBConfig(display, fbcfg, GLX.GLX_DEPTH_SIZE,       tmp));
-    res.setStencilBits   (glXGetFBConfig(display, fbcfg, GLX.GLX_STENCIL_SIZE,     tmp));
-
-    return (X11GLCapabilities) GLGraphicsConfigurationUtil.fixWinAttribBitsAndHwAccel(device, drawableTypeBits, res);
+    caps.setDoubleBuffered(values.get(j++) != 0);
+    caps.setStereo        (values.get(j++) != 0);
+    caps.setHardwareAccelerated(values.get(j++) != GLX.GLX_SLOW_CONFIG);
+    caps.setRedBits       (values.get(j++));
+    caps.setGreenBits     (values.get(j++));
+    caps.setBlueBits      (values.get(j++));
+    caps.setAlphaBits     (values.get(j++));
+    caps.setAccumRedBits  (values.get(j++));
+    caps.setAccumGreenBits(values.get(j++));
+    caps.setAccumBlueBits (values.get(j++));
+    caps.setAccumAlphaBits(values.get(j++));
+    caps.setDepthBits     (values.get(j++));
+    caps.setStencilBits   (values.get(j++));
+
+    return (X11GLCapabilities) GLGraphicsConfigurationUtil.fixWinAttribBitsAndHwAccel(device, drawableTypeBits, caps);
   }
 
   private static String glXGetFBConfigErrorCode(int err) {
diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java
index 6050dabbb..5c84597d5 100644
--- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java
+++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java
@@ -287,24 +287,23 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF
         final IntBuffer attribs = X11GLXGraphicsConfiguration.GLCapabilities2AttribList(capsChosen, true, isMultisampleAvailable, display, screen);
         final IntBuffer count = Buffers.newDirectIntBuffer(1);
         count.put(0, -1);
-        List<GLCapabilitiesImmutable> availableCaps = new ArrayList<GLCapabilitiesImmutable>();
         final int winattrmask = GLGraphicsConfigurationUtil.getExclusiveWinAttributeBits(capsChosen);
+        List<GLCapabilitiesImmutable> availableCaps;
         // 1st choice: get GLCapabilities based on users GLCapabilities setting recommendedIndex as preferred choice,
         // skipped if xvisualID is given
+        final boolean hasGLXChosenCaps;
         if( VisualIDHolder.VID_UNDEFINED == xvisualID ) {
             fbcfgsL = GLX.glXChooseFBConfig(display, screen, attribs, count);
+            hasGLXChosenCaps = fbcfgsL != null && fbcfgsL.limit()>0;
+        } else {
+            hasGLXChosenCaps = false;
         }
-        if (fbcfgsL != null && fbcfgsL.limit()>0) {
-            for (int i = 0; i < fbcfgsL.limit(); i++) {
-                final GLCapabilitiesImmutable caps = X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(x11Device, glProfile, fbcfgsL.get(i), winattrmask, isMultisampleAvailable);
-                if( null != caps ) {
-                    availableCaps.add(caps);
-                } else if(DEBUG) {
-                    System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationFBConfig: FBConfig invalid (1): ("+x11Screen+","+capsChosen+"): fbcfg: "+toHexString(fbcfgsL.get(i)));
-                }
-            }
+        final boolean useRecommendedIndex = hasGLXChosenCaps && capsChosen.isBackgroundOpaque(); // only use recommended idx if not translucent
+        final boolean skipCapsChooser = null == chooser && useRecommendedIndex; // fast path: skip choosing if using recommended idx and null chooser is used
+        if (hasGLXChosenCaps) {
+            availableCaps = X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(x11Device, glProfile, fbcfgsL, winattrmask, isMultisampleAvailable, skipCapsChooser /* onlyFirstValid */);
             if(availableCaps.size() > 0) {
-                recommendedIndex = capsChosen.isBackgroundOpaque() ? 0 : -1; // only use recommended idx if not translucent
+                recommendedIndex = useRecommendedIndex ? 0 : -1;
                 if (DEBUG) {
                     System.err.println("glXChooseFBConfig recommended fbcfg " + toHexString(fbcfgsL.get(0)) + ", idx " + recommendedIndex);
                     System.err.println("user  caps " + capsChosen);
@@ -314,6 +313,8 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF
                 System.err.println("glXChooseFBConfig no caps for recommended fbcfg " + toHexString(fbcfgsL.get(0)));
                 System.err.println("user  caps " + capsChosen);
             }
+        } else {
+            availableCaps = new ArrayList<GLCapabilitiesImmutable>();
         }
 
         // 2nd choice: get all GLCapabilities available, no preferred recommendedIndex available
@@ -328,15 +329,7 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF
                 }
                 return null;
             }
-
-            for (int i = 0; i < fbcfgsL.limit(); i++) {
-                final GLCapabilitiesImmutable caps = X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(x11Device, glProfile, fbcfgsL.get(i), winattrmask, isMultisampleAvailable);
-                if( null != caps ) {
-                    availableCaps.add(caps);
-                } else if(DEBUG) {
-                    System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationFBConfig: FBConfig invalid (2): ("+x11Screen+"): fbcfg: "+toHexString(fbcfgsL.get(i)));
-                }
-            }
+            availableCaps = X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(x11Device, glProfile, fbcfgsL, winattrmask, isMultisampleAvailable, false /* onlyOneValid */);
         }
 
         if(DEBUG) {
@@ -346,9 +339,9 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF
             }
         }
 
-        if( VisualIDHolder.VID_UNDEFINED != xvisualID ) {
+        if( VisualIDHolder.VID_UNDEFINED != xvisualID ) { // implies !hasGLXChosenCaps
             for(int i=0; i<availableCaps.size(); ) {
-                VisualIDHolder vidh = (VisualIDHolder) availableCaps.get(i);
+                final VisualIDHolder vidh = availableCaps.get(i);
                 if(vidh.getVisualID(VIDType.X11_XVISUAL) != xvisualID ) {
                     availableCaps.remove(i);
                 } else {
@@ -365,7 +358,12 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF
             }
         }
 
-        int chosenIndex = chooseCapabilities(chooser, capsChosen, availableCaps, recommendedIndex);
+        final int chosenIndex;
+        if( skipCapsChooser && 0 <= recommendedIndex ) {
+            chosenIndex = recommendedIndex;
+        } else {
+            chosenIndex = chooseCapabilities(chooser, capsChosen, availableCaps, recommendedIndex);
+        }
         if ( 0 > chosenIndex ) {
             if (DEBUG) {
                 System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationFBConfig: failed, return null");
@@ -445,7 +443,7 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF
 
         if( VisualIDHolder.VID_UNDEFINED != xvisualID ) {
             for(int i=0; i<availableCaps.size(); ) {
-                VisualIDHolder vidh = (VisualIDHolder) availableCaps.get(i);
+                VisualIDHolder vidh = availableCaps.get(i);
                 if(vidh.getVisualID(VIDType.X11_XVISUAL) != xvisualID ) {
                     availableCaps.remove(i);
                 } else {
-- 
cgit v1.2.3