JOGL v2.6.0-rc-20250706
JOGL, High-Performance Graphics Binding for Java™ (public API).
GraphicsConfigurationFactory.java
Go to the documentation of this file.
1/*
2 * Copyright (c) 2008-2009 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
34package com.jogamp.nativewindow;
35
36import com.jogamp.common.ExceptionUtils;
37import com.jogamp.common.util.ReflectionUtil;
38
39import jogamp.nativewindow.Debug;
40import jogamp.nativewindow.DefaultGraphicsConfigurationFactoryImpl;
41
42import java.util.ArrayList;
43import java.util.Arrays;
44import java.util.Collections;
45import java.util.HashMap;
46import java.util.Iterator;
47import java.util.List;
48import java.util.Map;
49import java.util.Set;
50
51/**
52 * Provides the mechanism by which the graphics configuration for a
53 * window can be chosen before the window is created. The graphics
54 * configuration decides parameters related to hardware accelerated rendering such
55 * as the OpenGL pixel format. <br>
56 * On some window systems (EGL/OpenKODE and X11 in particular) it is necessary to
57 * choose the graphics configuration early at window creation time. <br>
58 * Note that the selection of the graphics configuration is an algorithm which does not have
59 * strong dependencies on the particular Java window toolkit in use
60 * (e.g., AWT) and therefore it is strongly desirable to factor this
61 * functionality out of the core {@link NativeWindowFactory} so that
62 * new window toolkits can replace just the {@link
63 * NativeWindowFactory} and reuse the graphics configuration selection
64 * algorithm provided by, for example, an OpenGL binding.
65 */
66
67public abstract class GraphicsConfigurationFactory {
68 protected static final boolean DEBUG;
69
70 private static class DeviceCapsType {
71 public final Class<?> deviceType;
72 public final Class<?> capsType;
73 private final int hash32;
74
75 public DeviceCapsType(final Class<?> deviceType, final Class<?> capsType) {
76 this.deviceType = deviceType;
77 this.capsType = capsType;
78
79 // 31 * x == (x << 5) - x
80 int hash32 = 31 + deviceType.hashCode();
81 hash32 = ((hash32 << 5) - hash32) + capsType.hashCode();
82 this.hash32 = hash32;
83 }
84
85 @Override
86 public final int hashCode() {
87 return hash32;
88 }
89
90 @Override
91 public final boolean equals(final Object obj) {
92 if(this == obj) { return true; }
93 if (obj instanceof DeviceCapsType) {
94 final DeviceCapsType dct = (DeviceCapsType)obj;
95 return deviceType == dct.deviceType && capsType == dct.capsType;
96 }
97 return false;
98 }
99
100 @Override
101 public final String toString() {
102 return "DeviceCapsType["+deviceType.getName()+", "+capsType.getName()+"]";
103 }
104
105 }
106
107 private static final Map<DeviceCapsType, GraphicsConfigurationFactory> registeredFactories;
108 private static final DeviceCapsType defaultDeviceCapsType;
109 static boolean initialized = false;
110
111 static {
112 DEBUG = Debug.debug("GraphicsConfiguration");
113 if(DEBUG) {
114 System.err.println(Thread.currentThread().getName()+" - Info: GraphicsConfigurationFactory.<init>");
115 // Thread.dumpStack();
116 }
117 registeredFactories = Collections.synchronizedMap(new HashMap<DeviceCapsType, GraphicsConfigurationFactory>());
118 defaultDeviceCapsType = new DeviceCapsType(AbstractGraphicsDevice.class, CapabilitiesImmutable.class);
119 }
120
121 public static synchronized void initSingleton() {
122 if(!initialized) {
123 initialized = true;
124
125 if(DEBUG) {
126 System.err.println(Thread.currentThread().getName()+" - GraphicsConfigurationFactory.initSingleton()");
127 }
128
129 // Register the default no-op factory for arbitrary
130 // AbstractGraphicsDevice implementations, including
131 // AWTGraphicsDevice instances -- the OpenGL binding will take
132 // care of handling AWTGraphicsDevices on X11 platforms (as
133 // well as X11GraphicsDevices in non-AWT situations)
134 registerFactory(defaultDeviceCapsType.deviceType, defaultDeviceCapsType.capsType, new DefaultGraphicsConfigurationFactoryImpl());
135
137 try {
138 ReflectionUtil.callStaticMethod("jogamp.nativewindow.x11.X11GraphicsConfigurationFactory",
139 "registerFactory", null, null, GraphicsConfigurationFactory.class.getClassLoader());
140 } catch (final Exception e) {
141 throw new RuntimeException(e);
142 }
143 if(NativeWindowFactory.isAWTAvailable()) {
144 try {
145 ReflectionUtil.callStaticMethod("jogamp.nativewindow.x11.awt.X11AWTGraphicsConfigurationFactory",
146 "registerFactory", null, null, GraphicsConfigurationFactory.class.getClassLoader());
147 } catch (final Exception e) { /* n/a */ }
148 }
149 }
150 }
151 }
152
153 public static synchronized void shutdown() {
154 if(initialized) {
155 initialized = false;
156 if(DEBUG) {
157 System.err.println(Thread.currentThread().getName()+" - GraphicsConfigurationFactory.shutdown()");
158 }
159 registeredFactories.clear();
160 }
161 }
162
163 protected static String getThreadName() {
164 return Thread.currentThread().getName();
165 }
166
167 protected static String toHexString(final int val) {
168 return "0x" + Integer.toHexString(val);
169 }
170
171 protected static String toHexString(final long val) {
172 return "0x" + Long.toHexString(val);
173 }
174
175 /** Creates a new NativeWindowFactory instance. End users do not
176 need to call this method. */
178 }
179
180 /**
181 * Returns the graphics configuration factory for use with the
182 * given device and capability.
183 *
184 * @see #getFactory(Class, Class)
185 */
187 if (device == null) {
188 throw new IllegalArgumentException("null device");
189 }
190 if (caps == null) {
191 throw new IllegalArgumentException("null caps");
192 }
193 return getFactory(device.getClass(), caps.getClass());
194 }
195
196 /**
197 * Returns the graphics configuration factory for use with the
198 * given device and capability class.
199 * <p>
200 * Note: Registered device types maybe classes or interfaces, where capabilities types are interfaces only.
201 * </p>
202 *
203 * <p>
204 * Pseudo code for finding a suitable factory is:
205 * <pre>
206 For-All devT := getTopDownDeviceTypes(deviceType)
207 For-All capsT := getTopDownCapabilitiesTypes(capabilitiesType)
208 f = factory.get(devT, capsT);
209 if(f) { return f; }
210 end
211 end
212 * </pre>
213 * </p>
214 *
215 * @param deviceType the minimum capabilities class type accepted, must implement or extend {@link AbstractGraphicsDevice}
216 * @param capabilitiesType the minimum capabilities class type accepted, must implement or extend {@link CapabilitiesImmutable}
217 *
218 * @throws IllegalArgumentException if the deviceType does not implement {@link AbstractGraphicsDevice} or
219 * capabilitiesType does not implement {@link CapabilitiesImmutable}
220 */
221 public static GraphicsConfigurationFactory getFactory(final Class<?> deviceType, final Class<?> capabilitiesType)
222 throws IllegalArgumentException, NativeWindowException
223 {
224 if (!(defaultDeviceCapsType.deviceType.isAssignableFrom(deviceType))) {
225 throw new IllegalArgumentException("Given class must implement AbstractGraphicsDevice");
226 }
227 if (!(defaultDeviceCapsType.capsType.isAssignableFrom(capabilitiesType))) {
228 throw new IllegalArgumentException("Given capabilities class must implement CapabilitiesImmutable");
229 }
230 if(DEBUG) {
231 ExceptionUtils.dumpStack(System.err);
232 System.err.println("GraphicsConfigurationFactory.getFactory: "+deviceType.getName()+", "+capabilitiesType.getName());
233 dumpFactories();
234 }
235
236 final List<Class<?>> deviceTypes = getAllAssignableClassesFrom(defaultDeviceCapsType.deviceType, deviceType, false);
237 if(DEBUG) {
238 System.err.println("GraphicsConfigurationFactory.getFactory() deviceTypes: " + deviceTypes);
239 }
240 final List<Class<?>> capabilitiesTypes = getAllAssignableClassesFrom(defaultDeviceCapsType.capsType, capabilitiesType, true);
241 if(DEBUG) {
242 System.err.println("GraphicsConfigurationFactory.getFactory() capabilitiesTypes: " + capabilitiesTypes);
243 }
244 for(int j=0; j<deviceTypes.size(); j++) {
245 final Class<?> interfaceDevice = deviceTypes.get(j);
246 for(int i=0; i<capabilitiesTypes.size(); i++) {
247 final Class<?> interfaceCaps = capabilitiesTypes.get(i);
248 final DeviceCapsType dct = new DeviceCapsType(interfaceDevice, interfaceCaps);
249 final GraphicsConfigurationFactory factory = registeredFactories.get(dct);
250 if (factory != null) {
251 if(DEBUG) {
252 System.err.println("GraphicsConfigurationFactory.getFactory() found "+dct+" -> "+factory);
253 }
254 return factory;
255 }
256 }
257 }
258 // Return the default
259 final GraphicsConfigurationFactory factory = registeredFactories.get(defaultDeviceCapsType);
260 if(DEBUG) {
261 System.err.println("GraphicsConfigurationFactory.getFactory() DEFAULT "+defaultDeviceCapsType+" -> "+factory);
262 }
263 return factory;
264 }
265 private static ArrayList<Class<?>> getAllAssignableClassesFrom(final Class<?> superClassOrInterface, final Class<?> fromClass, final boolean interfacesOnly) {
266 // Using a todo list avoiding a recursive loop!
267 final ArrayList<Class<?>> inspectClasses = new ArrayList<Class<?>>();
268 final ArrayList<Class<?>> resolvedInterfaces = new ArrayList<Class<?>>();
269 inspectClasses.add(fromClass);
270 for(int j=0; j<inspectClasses.size(); j++) {
271 final Class<?> clazz = inspectClasses.get(j);
272 getAllAssignableClassesFrom(superClassOrInterface, clazz, interfacesOnly, resolvedInterfaces, inspectClasses);
273 }
274 return resolvedInterfaces;
275 }
276 private static void getAllAssignableClassesFrom(final Class<?> superClassOrInterface, final Class<?> fromClass, final boolean interfacesOnly, final List<Class<?>> resolvedInterfaces, final List<Class<?>> inspectClasses) {
277 final ArrayList<Class<?>> types = new ArrayList<Class<?>>();
278 if( superClassOrInterface.isAssignableFrom(fromClass) && !resolvedInterfaces.contains(fromClass)) {
279 if( !interfacesOnly || fromClass.isInterface() ) {
280 types.add(fromClass);
281 }
282 }
283 types.addAll(Arrays.asList(fromClass.getInterfaces()));
284
285 for(int i=0; i<types.size(); i++) {
286 final Class<?> iface = types.get(i);
287 if( superClassOrInterface.isAssignableFrom(iface) && !resolvedInterfaces.contains(iface) ) {
288 resolvedInterfaces.add(iface);
289 if( !superClassOrInterface.equals(iface) && !inspectClasses.contains(iface) ) {
290 inspectClasses.add(iface); // safe add to todo list, avoiding a recursive nature
291 }
292 }
293 }
294 final Class<?> parentClass = fromClass.getSuperclass();
295 if( null != parentClass && superClassOrInterface.isAssignableFrom(parentClass) && !inspectClasses.contains(parentClass) ) {
296 inspectClasses.add(parentClass); // safe add to todo list, avoiding a recursive nature
297 }
298 }
299 private static void dumpFactories() {
300 final Set<DeviceCapsType> dcts = registeredFactories.keySet();
301 int i=0;
302 for(final Iterator<DeviceCapsType> iter = dcts.iterator(); iter.hasNext(); ) {
303 final DeviceCapsType dct = iter.next();
304 System.err.println("Factory #"+i+": "+dct+" -> "+registeredFactories.get(dct));
305 i++;
306 }
307 }
308
309 /**
310 * Registers a GraphicsConfigurationFactory handling
311 * the given graphics device and capability class.
312 * <p>
313 * This does not need to be called by end users, only implementors of new
314 * GraphicsConfigurationFactory subclasses.
315 * </p>
316 *
317 * <p>
318 * Note: Registered device types maybe classes or interfaces, where capabilities types are interfaces only.
319 * </p>
320 *
321 * <p>See {@link #getFactory(Class, Class)} for a description of the find algorithm.</p>
322 *
323 * @param deviceType the minimum capabilities class type accepted, must implement or extend interface {@link AbstractGraphicsDevice}
324 * @param capabilitiesType the minimum capabilities class type accepted, must extend interface {@link CapabilitiesImmutable}
325 * @return the previous registered factory, or null if none
326 * @throws IllegalArgumentException if the given class does not implement AbstractGraphicsDevice
327 */
328 protected static GraphicsConfigurationFactory registerFactory(final Class<?> abstractGraphicsDeviceImplementor, final Class<?> capabilitiesType, final GraphicsConfigurationFactory factory)
329 throws IllegalArgumentException
330 {
331 if (!(defaultDeviceCapsType.deviceType.isAssignableFrom(abstractGraphicsDeviceImplementor))) {
332 throw new IllegalArgumentException("Given device class must implement AbstractGraphicsDevice");
333 }
334 if (!(defaultDeviceCapsType.capsType.isAssignableFrom(capabilitiesType))) {
335 throw new IllegalArgumentException("Given capabilities class must implement CapabilitiesImmutable");
336 }
337 final DeviceCapsType dct = new DeviceCapsType(abstractGraphicsDeviceImplementor, capabilitiesType);
338 final GraphicsConfigurationFactory prevFactory;
339 if(null == factory) {
340 prevFactory = registeredFactories.remove(dct);
341 if(DEBUG) {
342 System.err.println("GraphicsConfigurationFactory.registerFactory() remove "+dct+
343 ", deleting: "+prevFactory);
344 }
345 } else {
346 prevFactory = registeredFactories.put(dct, factory);
347 if(DEBUG) {
348 System.err.println("GraphicsConfigurationFactory.registerFactory() put "+dct+" -> "+factory+
349 ", overridding: "+prevFactory);
350 }
351 }
352 return prevFactory;
353 }
354
355 /**
356 * <P> Selects a graphics configuration on the specified graphics
357 * device compatible with the supplied {@link Capabilities}. Some
358 * platforms (e.g.: X11, EGL, KD) require the graphics configuration
359 * to be specified when the native window is created.
360 * These architectures have seperated their device, screen, window and drawable
361 * context and hence are capable of quering the capabilities for each screen.
362 * A fully established window is not required.</P>
363 *
364 * <P>Other platforms (e.g. Windows, MacOSX) don't offer the mentioned seperation
365 * and hence need a fully established window and it's drawable.
366 * Here the validation of the capabilities is performed later.
367 * In this case, the AbstractGraphicsConfiguration implementation
368 * must allow an overwrite of the Capabilites, for example
369 * {@link DefaultGraphicsConfiguration#setChosenCapabilities DefaultGraphicsConfiguration.setChosenCapabilities(..)}.
370 * </P>
371 *
372 * <P>
373 * This method is mainly intended to be both used and implemented by the
374 * OpenGL binding.</P>
375 *
376 * <P> The concrete data type of the passed graphics device and
377 * returned graphics configuration must be specified in the
378 * documentation binding this particular API to the underlying
379 * window toolkit. The Reference Implementation accepts {@link
380 * com.jogamp.nativewindow.awt.AWTGraphicsDevice AWTGraphicsDevice} objects and returns {@link
381 * com.jogamp.nativewindow.awt.AWTGraphicsConfiguration AWTGraphicsConfiguration} objects. On
382 * X11 platforms where the AWT is not in use, it also accepts
383 * {@link com.jogamp.nativewindow.x11.X11GraphicsDevice
384 * X11GraphicsDevice} objects and returns {@link
385 * com.jogamp.nativewindow.x11.X11GraphicsConfiguration
386 * X11GraphicsConfiguration} objects.</P>
387 *
388 * @param capsChosen the intermediate chosen capabilities to be refined by this implementation, may be equal to capsRequested
389 * @param capsRequested the original requested capabilities
390 * @param chooser the choosing implementation
391 * @param screen the referring Screen
392 * @param nativeVisualID if not {@link VisualIDHolder#VID_UNDEFINED} it reflects a pre-chosen visualID of the native platform's windowing system.
393 * @return the complete GraphicsConfiguration
394 *
395 * @throws IllegalArgumentException if the data type of the passed
396 * AbstractGraphicsDevice is not supported by this
397 * NativeWindowFactory.
398 * @throws NativeWindowException if any window system-specific errors caused
399 * the selection of the graphics configuration to fail.
400 *
401 * @see com.jogamp.nativewindow.GraphicsConfigurationFactory#chooseGraphicsConfiguration(Capabilities, CapabilitiesChooser, AbstractGraphicsScreen)
402 * @see com.jogamp.nativewindow.DefaultGraphicsConfiguration#setChosenCapabilities(Capabilities caps)
403 */
406 final CapabilitiesChooser chooser,
407 final AbstractGraphicsScreen screen, final int nativeVisualID)
408 throws IllegalArgumentException, NativeWindowException {
409 if(null==capsChosen) {
410 throw new NativeWindowException("Chosen Capabilities are null");
411 }
412 if(null==capsRequested) {
413 throw new NativeWindowException("Requested Capabilities are null");
414 }
415 if(null==screen) {
416 throw new NativeWindowException("Screen is null");
417 }
418 final AbstractGraphicsDevice device = screen.getDevice();
419 if(null==device) {
420 throw new NativeWindowException("Screen's Device is null");
421 }
422 device.lock();
423 try {
424 return chooseGraphicsConfigurationImpl(capsChosen, capsRequested, chooser, screen, nativeVisualID);
425 } finally {
426 device.unlock();
427 }
428 }
429
430 /**
431 * Called by {@link #chooseGraphicsConfiguration(CapabilitiesImmutable, CapabilitiesImmutable, CapabilitiesChooser, AbstractGraphicsScreen, int)}
432 * post argument validation within {@link AbstractGraphicsDevice#lock()}ed segment.
433 *
434 * @param capsChosen the intermediate chosen capabilities to be refined by this implementation, may be equal to capsRequested
435 * @param capsRequested the original requested capabilities
436 * @param chooser the choosing implementation
437 * @param screen the referring Screen
438 * @param nativeVisualID if not {@link VisualIDHolder#VID_UNDEFINED} it reflects a pre-chosen visualID of the native platform's windowing system.
439 * @return the complete GraphicsConfiguration
440 *
441 * @throws IllegalArgumentException if the data type of the passed
442 * AbstractGraphicsDevice is not supported by this
443 * NativeWindowFactory.
444 * @throws NativeWindowException if any window system-specific errors caused
445 * the selection of the graphics configuration to fail.
446 * @see #chooseGraphicsConfiguration(CapabilitiesImmutable, CapabilitiesImmutable, CapabilitiesChooser, AbstractGraphicsScreen, int)
447 */
448 protected abstract AbstractGraphicsConfiguration
450 CapabilitiesChooser chooser, AbstractGraphicsScreen screen, int nativeVisualID)
451 throws IllegalArgumentException, NativeWindowException;
452
453}
Provides the mechanism by which the graphics configuration for a window can be chosen before the wind...
GraphicsConfigurationFactory()
Creates a new NativeWindowFactory instance.
final AbstractGraphicsConfiguration chooseGraphicsConfiguration(final CapabilitiesImmutable capsChosen, final CapabilitiesImmutable capsRequested, final CapabilitiesChooser chooser, final AbstractGraphicsScreen screen, final int nativeVisualID)
abstract AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl(CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen screen, int nativeVisualID)
Called by chooseGraphicsConfiguration(CapabilitiesImmutable, CapabilitiesImmutable,...
static GraphicsConfigurationFactory getFactory(final Class<?> deviceType, final Class<?> capabilitiesType)
Returns the graphics configuration factory for use with the given device and capability class.
static GraphicsConfigurationFactory registerFactory(final Class<?> abstractGraphicsDeviceImplementor, final Class<?> capabilitiesType, final GraphicsConfigurationFactory factory)
Registers a GraphicsConfigurationFactory handling the given graphics device and capability class.
static GraphicsConfigurationFactory getFactory(final AbstractGraphicsDevice device, final CapabilitiesImmutable caps)
Returns the graphics configuration factory for use with the given device and capability.
A generic exception for OpenGL errors used throughout the binding as a substitute for RuntimeExceptio...
Provides a pluggable mechanism for arbitrary window toolkits to adapt their components to the NativeW...
static final String TYPE_X11
X11 type, as retrieved with getNativeWindowType(boolean).
static String getNativeWindowType(final boolean useCustom)
A marker interface describing a graphics configuration, visual, or pixel format in a toolkit-independ...
A interface describing a graphics device in a toolkit-independent manner.
void lock()
Optionally locking the device, utilizing eg com.jogamp.nativewindow.ToolkitLock#lock().
void unlock()
Optionally unlocking the device, utilizing eg com.jogamp.nativewindow.ToolkitLock#unlock().
A interface describing a graphics screen in a toolkit-independent manner.
Provides a mechanism by which applications can customize the window type selection for a given Capabi...
Specifies an immutable set of capabilities that a window's rendering context must support,...