All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jogamp.opengl.x11.glx.X11GLXGraphicsConfigurationFactory Maven / Gradle / Ivy

/*
 * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
 * Copyright (c) 2010 JogAmp Community. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * - Redistribution of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistribution in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * Neither the name of Sun Microsystems, Inc. or the names of
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
 * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
 * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
 * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
 * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
 * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
 * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 */

package jogamp.opengl.x11.glx;

import javax.media.nativewindow.AbstractGraphicsConfiguration;
import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.AbstractGraphicsScreen;
import javax.media.nativewindow.CapabilitiesChooser;
import javax.media.nativewindow.CapabilitiesImmutable;
import javax.media.nativewindow.GraphicsConfigurationFactory;
import javax.media.nativewindow.VisualIDHolder;
import javax.media.nativewindow.VisualIDHolder.VIDType;
import javax.media.opengl.DefaultGLCapabilitiesChooser;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLCapabilitiesChooser;
import javax.media.opengl.GLCapabilitiesImmutable;
import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLException;
import javax.media.opengl.GLProfile;

import com.jogamp.common.nio.Buffers;
import com.jogamp.common.nio.PointerBuffer;
import com.jogamp.nativewindow.x11.X11GraphicsDevice;
import com.jogamp.nativewindow.x11.X11GraphicsScreen;

import jogamp.nativewindow.x11.X11Lib;
import jogamp.nativewindow.x11.XVisualInfo;
import jogamp.opengl.GLGraphicsConfigurationFactory;
import jogamp.opengl.GLGraphicsConfigurationUtil;

import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


/** Subclass of GraphicsConfigurationFactory used when non-AWT toolkits
    are used on X11 platforms. Toolkits will likely need to delegate
    to this one to change the accepted and returned types of the
    GraphicsDevice and GraphicsConfiguration abstractions. */

public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationFactory {
    static VisualIDHolder.VIDComparator XVisualIDComparator = new VisualIDHolder.VIDComparator(VisualIDHolder.VIDType.X11_XVISUAL);

    static GraphicsConfigurationFactory fallbackX11GraphicsConfigurationFactory = null;
    static void registerFactory() {
        final GraphicsConfigurationFactory newFactory = new X11GLXGraphicsConfigurationFactory();
        final GraphicsConfigurationFactory oldFactory = GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.x11.X11GraphicsDevice.class, GLCapabilitiesImmutable.class, newFactory);
        if(oldFactory == newFactory) {
            throw new InternalError("GraphicsConfigurationFactory lifecycle impl. error");
        }
        if(null != oldFactory) {
            fallbackX11GraphicsConfigurationFactory = oldFactory;
        } else {
            fallbackX11GraphicsConfigurationFactory = GraphicsConfigurationFactory.getFactory(com.jogamp.nativewindow.x11.X11GraphicsDevice.class, CapabilitiesImmutable.class);
            if( null == fallbackX11GraphicsConfigurationFactory ) {
                throw new InternalError("Missing fallback GraphicsConfigurationFactory");
            }
        }
    }
    private X11GLXGraphicsConfigurationFactory() {
    }

    @Override
    protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl(
            CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen, int nativeVisualID) {
        if (!(absScreen instanceof X11GraphicsScreen)) {
            throw new IllegalArgumentException("Only X11GraphicsScreen are allowed here");
        }

        if ( !(capsChosen instanceof GLCapabilitiesImmutable) ) {
            throw new IllegalArgumentException("This NativeWindowFactory accepts only GLCapabilities objects - chosen");
        }

        if ( !(capsRequested instanceof GLCapabilitiesImmutable)) {
            throw new IllegalArgumentException("This NativeWindowFactory accepts only GLCapabilities objects - requested");
        }

        if (chooser != null && !(chooser instanceof GLCapabilitiesChooser)) {
            throw new IllegalArgumentException("This NativeWindowFactory accepts only GLCapabilitiesChooser objects");
        }

        if(!GLXUtil.isGLXAvailableOnServer((X11GraphicsDevice)absScreen.getDevice())) {
            if(null != fallbackX11GraphicsConfigurationFactory) {
                if(DEBUG) {
                    System.err.println("No GLX available, fallback to "+fallbackX11GraphicsConfigurationFactory.getClass().getSimpleName()+" for: "+absScreen);
                }
                return fallbackX11GraphicsConfigurationFactory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, absScreen, VisualIDHolder.VID_UNDEFINED);
            }
            throw new InternalError("No GLX and no fallback GraphicsConfigurationFactory available for: "+absScreen);
        }
        return chooseGraphicsConfigurationStatic((GLCapabilitiesImmutable)capsChosen, (GLCapabilitiesImmutable)capsRequested,
                                                 (GLCapabilitiesChooser)chooser, (X11GraphicsScreen)absScreen, nativeVisualID);
    }

    protected static List getAvailableCapabilities(X11GLXDrawableFactory factory, AbstractGraphicsDevice device) {
        X11GLXDrawableFactory.SharedResource sharedResource = factory.getOrCreateSharedResourceImpl(device);
        if(null == sharedResource) {
            throw new GLException("Shared resource for device n/a: "+device);
        }
        final X11GraphicsScreen sharedScreen = (X11GraphicsScreen) sharedResource.getScreen();
        final X11GraphicsDevice sharedDevice = (X11GraphicsDevice) sharedScreen.getDevice();
        final boolean isMultisampleAvailable = sharedResource.isGLXMultisampleAvailable();
        final GLProfile glp = GLProfile.getDefault(device);

        List availableCaps = null;

        sharedDevice.lock();
        try {
            if( sharedResource.isGLXVersionGreaterEqualOneThree() ) {
                availableCaps = getAvailableGLCapabilitiesFBConfig(sharedScreen, glp, isMultisampleAvailable);
            }
            if( null == availableCaps || availableCaps.isEmpty() ) {
                availableCaps = getAvailableGLCapabilitiesXVisual(sharedScreen, glp, isMultisampleAvailable);
            }
        } finally {
            sharedDevice.unlock();
        }
        if( null != availableCaps && availableCaps.size() > 1 ) {
            Collections.sort(availableCaps, XVisualIDComparator);
        }
        return availableCaps;
    }

    static List getAvailableGLCapabilitiesFBConfig(X11GraphicsScreen x11Screen, GLProfile glProfile, boolean isMultisampleAvailable) {
        PointerBuffer fbcfgsL = null;

        // Utilizing FBConfig
        //
        final X11GraphicsDevice absDevice = (X11GraphicsDevice) x11Screen.getDevice();
        final long display = absDevice.getHandle();

        final int screen = x11Screen.getIndex();
        final IntBuffer count = Buffers.newDirectIntBuffer(1);
        count.put(0, -1);
        final ArrayList availableCaps = new ArrayList();

        fbcfgsL = GLX.glXChooseFBConfig(display, screen, null, count);
        if (fbcfgsL == null || fbcfgsL.limit()<=0) {
            if(DEBUG) {
                System.err.println("X11GLXGraphicsConfiguration.getAvailableGLCapabilitiesFBConfig: Failed glXChooseFBConfig ("+x11Screen+"): "+fbcfgsL+", "+count.get(0));
            }
            return null;
        }
        for (int i = 0; i < fbcfgsL.limit(); i++) {
            final GLCapabilitiesImmutable caps = X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(absDevice, glProfile, fbcfgsL.get(i), GLGraphicsConfigurationUtil.ALL_BITS, isMultisampleAvailable);
            if(null != caps) {
                availableCaps.add(caps);
            } else if(DEBUG) {
                System.err.println("X11GLXGraphicsConfiguration.getAvailableGLCapabilitiesFBConfig: FBConfig invalid (2): ("+x11Screen+"): fbcfg: "+toHexString(fbcfgsL.get(i)));
            }
        }
        return availableCaps;
    }

    static List getAvailableGLCapabilitiesXVisual(X11GraphicsScreen x11Screen, GLProfile glProfile, boolean isMultisampleAvailable) {
        final X11GraphicsDevice absDevice = (X11GraphicsDevice) x11Screen.getDevice();
        final long display = absDevice.getHandle();

        int screen = x11Screen.getIndex();

        int[] count = new int[1];
        XVisualInfo template = XVisualInfo.create();
        template.setScreen(screen);
        XVisualInfo[] infos = X11Lib.XGetVisualInfo(display, X11Lib.VisualScreenMask, template, count, 0);
        if (infos == null || infos.length<1) {
            throw new GLException("Error while enumerating available XVisualInfos");
        }
        ArrayList availableCaps = new ArrayList();
        for (int i = 0; i < infos.length; i++) {
            final GLCapabilitiesImmutable caps = X11GLXGraphicsConfiguration.XVisualInfo2GLCapabilities(absDevice, glProfile, infos[i], GLGraphicsConfigurationUtil.ALL_BITS, isMultisampleAvailable);
            if(null != caps) {
                availableCaps.add(caps);
            } if(DEBUG) {
                System.err.println("X11GLXGraphicsConfiguration.getAvailableGLCapabilitiesXVisual: XVisual invalid: ("+x11Screen+"): fbcfg: "+toHexString(infos[i].getVisualid()));
            }
        }
        return availableCaps;
    }


    static X11GLXGraphicsConfiguration chooseGraphicsConfigurationStatic(GLCapabilitiesImmutable capsChosen,
                                                                         GLCapabilitiesImmutable capsReq,
                                                                         GLCapabilitiesChooser chooser,
                                                                         X11GraphicsScreen x11Screen, int xvisualID) {
        if (x11Screen == null) {
            throw new IllegalArgumentException("AbstractGraphicsScreen is null");
        }
        if (capsChosen == null) {
            capsChosen = new GLCapabilities(null);
        }
        X11GraphicsDevice x11Device = (X11GraphicsDevice) x11Screen.getDevice();
        X11GLXDrawableFactory factory = (X11GLXDrawableFactory) GLDrawableFactory.getDesktopFactory();

        capsChosen = GLGraphicsConfigurationUtil.fixGLCapabilities( capsChosen, factory, x11Device);
        final boolean usePBuffer = !capsChosen.isOnscreen() && capsChosen.isPBuffer();

        X11GLXGraphicsConfiguration res = null;
        x11Device.lock();
        try {
            if( factory.isGLXVersionGreaterEqualOneThree(x11Device) ) {
                res = chooseGraphicsConfigurationFBConfig(capsChosen, capsReq, chooser, x11Screen, xvisualID);
            }
            if(null==res) {
                if(usePBuffer) {
                    throw new GLException("Error: Couldn't create X11GLXGraphicsConfiguration based on FBConfig for visualID "+toHexString(xvisualID)+", "+capsChosen);
                }
                res = chooseGraphicsConfigurationXVisual(capsChosen, capsReq, chooser, x11Screen, xvisualID);
            }
        } finally {
            x11Device.unlock();
        }
        if(null==res) {
            throw new GLException("Error: Couldn't create X11GLXGraphicsConfiguration based on FBConfig and XVisual for visualID "+toHexString(xvisualID)+", "+x11Screen+", "+capsChosen);
        }
        if(DEBUG) {
            System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationStatic(visualID "+toHexString(xvisualID)+", "+x11Screen+","+capsChosen+"): "+res);
        }
        return res;
    }

    static X11GLXGraphicsConfiguration fetchGraphicsConfigurationFBConfig(X11GraphicsScreen x11Screen, int fbID, GLProfile glp) {
        final X11GraphicsDevice x11Device = (X11GraphicsDevice) x11Screen.getDevice();
        final long display = x11Device.getHandle();
        final int screen = x11Screen.getIndex();

        final long fbcfg = X11GLXGraphicsConfiguration.glXFBConfigID2FBConfig(display, screen, fbID);
        if( 0 == fbcfg || !X11GLXGraphicsConfiguration.GLXFBConfigValid( display, fbcfg ) ) {
            if(DEBUG) {
                System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationFBConfig: Failed - GLX FBConfig invalid: ("+x11Screen+","+toHexString(fbID)+"): fbcfg: "+toHexString(fbcfg));
            }
            return null;
        }
        final X11GLXDrawableFactory factory = (X11GLXDrawableFactory) GLDrawableFactory.getDesktopFactory();

        final X11GLCapabilities caps = X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(x11Device, glp, fbcfg, GLGraphicsConfigurationUtil.ALL_BITS, factory.isGLXMultisampleAvailable(x11Device));
        return new X11GLXGraphicsConfiguration(x11Screen, caps, caps, new DefaultGLCapabilitiesChooser());
    }

    private static X11GLXGraphicsConfiguration chooseGraphicsConfigurationFBConfig(GLCapabilitiesImmutable capsChosen,
                                                                                   GLCapabilitiesImmutable capsReq,
                                                                                   GLCapabilitiesChooser chooser,
                                                                                   X11GraphicsScreen x11Screen, int xvisualID) {
        int recommendedIndex = -1;
        PointerBuffer fbcfgsL = null;
        GLProfile glProfile = capsChosen.getGLProfile();

        // Utilizing FBConfig
        //
        X11GraphicsDevice x11Device = (X11GraphicsDevice) x11Screen.getDevice();
        long display = x11Device.getHandle();
        int screen = x11Screen.getIndex();

        final X11GLXDrawableFactory factory = (X11GLXDrawableFactory) GLDrawableFactory.getDesktopFactory();
        final boolean isMultisampleAvailable = factory.isGLXMultisampleAvailable(x11Device);
        final IntBuffer attribs = X11GLXGraphicsConfiguration.GLCapabilities2AttribList(capsChosen, true, isMultisampleAvailable, display, screen);
        final IntBuffer count = Buffers.newDirectIntBuffer(1);
        count.put(0, -1);
        List availableCaps = new ArrayList();
        final int winattrmask = GLGraphicsConfigurationUtil.getExclusiveWinAttributeBits(capsChosen);
        // 1st choice: get GLCapabilities based on users GLCapabilities setting recommendedIndex as preferred choice,
        // skipped if xvisualID is given
        if( VisualIDHolder.VID_UNDEFINED == xvisualID ) {
            fbcfgsL = GLX.glXChooseFBConfig(display, screen, attribs, count);
        }
        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)));
                }
            }
            if(availableCaps.size() > 0) {
                recommendedIndex = capsChosen.isBackgroundOpaque() ? 0 : -1; // only use recommended idx if not translucent
                if (DEBUG) {
                    System.err.println("glXChooseFBConfig recommended fbcfg " + toHexString(fbcfgsL.get(0)) + ", idx " + recommendedIndex);
                    System.err.println("user  caps " + capsChosen);
                    System.err.println("fbcfg caps " + availableCaps.get(0));
                }
            } else if (DEBUG) {
                System.err.println("glXChooseFBConfig no caps for recommended fbcfg " + toHexString(fbcfgsL.get(0)));
                System.err.println("user  caps " + capsChosen);
            }
        }

        // 2nd choice: get all GLCapabilities available, no preferred recommendedIndex available
        if( 0 == availableCaps.size() ) {
            // reset ..
            recommendedIndex = -1;

            fbcfgsL = GLX.glXChooseFBConfig(display, screen, null, count);
            if (fbcfgsL == null || fbcfgsL.limit()<=0) {
                if(DEBUG) {
                    System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationFBConfig: Failed glXChooseFBConfig ("+x11Screen+","+capsChosen+"): "+fbcfgsL+", "+count.get(0));
                }
                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)));
                }
            }
        }

        if(DEBUG) {
            System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationFBConfig: got configs: "+availableCaps.size());
            for(int i=0; i chosenIndex ) {
            if (DEBUG) {
                System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationFBConfig: failed, return null");
                Thread.dumpStack();
            }
            return null;
        }
        X11GLCapabilities chosenCaps = (X11GLCapabilities) availableCaps.get(chosenIndex);

        return new X11GLXGraphicsConfiguration(x11Screen, chosenCaps, capsReq, chooser);
    }

    private static X11GLXGraphicsConfiguration chooseGraphicsConfigurationXVisual(GLCapabilitiesImmutable capsChosen,
                                                                                  GLCapabilitiesImmutable capsReq,
                                                                                  GLCapabilitiesChooser chooser,
                                                                                  X11GraphicsScreen x11Screen, int xvisualID) {
        if (chooser == null) {
            chooser = new DefaultGLCapabilitiesChooser();
        }

        GLProfile glProfile = capsChosen.getGLProfile();
        final int winattrmask = GLGraphicsConfigurationUtil.getExclusiveWinAttributeBits(capsChosen.isOnscreen(), capsChosen.isFBO(), false /* pbuffer */, capsChosen.isBitmap());
        List availableCaps = new ArrayList();
        int recommendedIndex = -1;

        X11GraphicsDevice absDevice = (X11GraphicsDevice) x11Screen.getDevice();
        long display = absDevice.getHandle();
        int screen = x11Screen.getIndex();

        final X11GLXDrawableFactory factory = (X11GLXDrawableFactory) GLDrawableFactory.getDesktopFactory();
        final boolean isMultisampleAvailable = factory.isGLXMultisampleAvailable(absDevice);
        final IntBuffer attribs = X11GLXGraphicsConfiguration.GLCapabilities2AttribList(capsChosen, false, isMultisampleAvailable, display, screen);

        XVisualInfo recommendedVis = null;
        // 1st choice: get GLCapabilities based on users GLCapabilities setting recommendedIndex as preferred choice
        // skipped if xvisualID is given
        if( VisualIDHolder.VID_UNDEFINED == xvisualID ) {
            recommendedVis = GLX.glXChooseVisual(display, screen, attribs);
            if (DEBUG) {
                System.err.print("glXChooseVisual recommended ");
                if (recommendedVis == null) {
                    System.err.println("null visual");
                } else {
                    System.err.println("visual id " + toHexString(recommendedVis.getVisualid()));
                }
            }
        }

        // 2nd choice: get all GLCapabilities available, preferred recommendedIndex might be available if 1st choice was successful
        int[] count = new int[1];
        XVisualInfo template = XVisualInfo.create();
        template.setScreen(screen);
        XVisualInfo[] infos = X11Lib.XGetVisualInfo(display, X11Lib.VisualScreenMask, template, count, 0);
        if (infos == null || infos.length<1) {
            throw new GLException("Error while enumerating available XVisualInfos");
        }

        for (int i = 0; i < infos.length; i++) {
            final GLCapabilitiesImmutable caps = X11GLXGraphicsConfiguration.XVisualInfo2GLCapabilities(absDevice, glProfile, infos[i], winattrmask, isMultisampleAvailable);
            if( null != caps ) {
                availableCaps.add(caps);
                // Attempt to find the visual chosenIndex by glXChooseVisual, if not translucent
                if (capsChosen.isBackgroundOpaque() && recommendedVis != null && recommendedVis.getVisualid() == infos[i].getVisualid()) {
                    recommendedIndex = availableCaps.size() - 1;
                }
            } else if(DEBUG) {
                System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationXVisual: XVisual invalid: ("+x11Screen+"): fbcfg: "+toHexString(infos[i].getVisualid()));
            }
        }

        if(DEBUG) {
            System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationXVisual: got configs: "+availableCaps.size());
            for(int i=0; i chosenIndex ) {
            if (DEBUG) {
                System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationXVisual: failed, return null");
                Thread.dumpStack();
            }
            return null;
        }
        X11GLCapabilities chosenCaps = (X11GLCapabilities) availableCaps.get(chosenIndex);

        return new X11GLXGraphicsConfiguration(x11Screen, chosenCaps, capsReq, chooser);
    }

}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy