JOGL v2.6.0-rc-20250706
JOGL, High-Performance Graphics Binding for Java™ (public API).
DefaultGLCapabilitiesChooser.java
Go to the documentation of this file.
1/*
2 * Copyright (c) 2003-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 * 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
41package com.jogamp.opengl;
42
43import com.jogamp.nativewindow.NativeWindowException;
44
45import java.util.List;
46
47import com.jogamp.nativewindow.CapabilitiesImmutable;
48
49import com.jogamp.common.ExceptionUtils;
50import com.jogamp.common.util.PropertyAccess;
51
52import jogamp.opengl.Debug;
53
54/** <P> The default implementation of the {@link
55 GLCapabilitiesChooser} interface, which provides consistent visual
56 selection behavior across platforms. The precise algorithm is
57 deliberately left loosely specified. Some properties are: </P>
58
59 <UL>
60
61 <LI> As long as there is at least one available non-null
62 GLCapabilities which matches the "stereo" option, will return a
63 valid index.
64
65 <LI> Attempts to match as closely as possible the given
66 GLCapabilities, but will select one with fewer capabilities (i.e.,
67 lower color depth) if necessary.
68
69 <LI> Prefers hardware-accelerated visuals to
70 non-hardware-accelerated.
71
72 <LI> If there is no exact match, prefers a more-capable visual to
73 a less-capable one.
74
75 <LI> If there is more than one exact match, chooses an arbitrary
76 one.
77
78 <LI> May select the opposite of a double- or single-buffered
79 visual (based on the user's request) in dire situations.
80
81 <LI> Color depth (including alpha) mismatches are weighted higher
82 than depth buffer mismatches, which are in turn weighted higher
83 than accumulation buffer (including alpha) and stencil buffer
84 depth mismatches.
85
86 <LI> If a valid windowSystemRecommendedChoice parameter is
87 supplied, chooses that instead of using the cross-platform code.
88
89 </UL>
90*/
91
93 private static final boolean DEBUG;
94
95 static {
96 Debug.initSingleton();
97 DEBUG = PropertyAccess.isPropertyDefined("jogl.debug.CapabilitiesChooser", true);
98 }
99
100 private final static int NO_SCORE = -9999999;
101 private final static int DOUBLE_BUFFER_MISMATCH_PENALTY = 1000;
102 private final static int OPAQUE_MISMATCH_PENALTY = 750;
103 private final static int STENCIL_MISMATCH_PENALTY = 500;
104 private final static int MULTISAMPLE_MISMATCH_PENALTY = 500;
105 private final static int MULTISAMPLE_EXTENSION_MISMATCH_PENALTY = 250; // just a little drop, no scale
106 // Pseudo attempt to keep equal rank penalties scale-equivalent
107 // (e.g., stencil mismatch is 3 * accum because there are 3 accum
108 // components)
109 private final static int COLOR_MISMATCH_PENALTY_SCALE = 36;
110 private final static int DEPTH_MISMATCH_PENALTY_SCALE = 6;
111 private final static int ACCUM_MISMATCH_PENALTY_SCALE = 1;
112 private final static int STENCIL_MISMATCH_PENALTY_SCALE = 3;
113 private final static int MULTISAMPLE_MISMATCH_PENALTY_SCALE = 3;
114
115 @Override
117 final List<? extends CapabilitiesImmutable> available,
118 final int windowSystemRecommendedChoice) {
119 if ( null == desired ) {
120 throw new NativeWindowException("Null desired capabilities");
121 }
122 if ( 0 == available.size() ) {
123 throw new NativeWindowException("Empty available capabilities");
124 }
125
126 final GLCapabilitiesImmutable gldes = (GLCapabilitiesImmutable) desired;
127 final int availnum = available.size();
128
129 if (DEBUG) {
130 ExceptionUtils.dumpStack(System.err);
131 System.err.println("Desired: " + gldes);
132 System.err.println("Available: " + availnum);
133 for (int i = 0; i < available.size(); i++) {
134 System.err.println(i + ": " + available.get(i));
135 }
136 System.err.println("Window system's recommended choice: " + windowSystemRecommendedChoice);
137 }
138
139 if (windowSystemRecommendedChoice >= 0 &&
140 windowSystemRecommendedChoice < availnum &&
141 null != available.get(windowSystemRecommendedChoice)) {
142 if (DEBUG) {
143 System.err.println("Choosing window system's recommended choice of " + windowSystemRecommendedChoice);
144 System.err.println(available.get(windowSystemRecommendedChoice));
145 }
146 return windowSystemRecommendedChoice;
147 }
148
149 // Create score array
150 final int[] scores = new int[availnum];
151
152 for (int i = 0; i < scores.length; i++) {
153 scores[i] = NO_SCORE;
154 }
155 final int gldes_samples = gldes.getNumSamples();
156
157 // Compute score for each
158 for (int i = 0; i < availnum; i++) {
159 final GLCapabilitiesImmutable cur = (GLCapabilitiesImmutable) available.get(i);
160 if (cur == null) {
161 continue;
162 }
163 if (gldes.isOnscreen() && !cur.isOnscreen()) {
164 continue; // requested onscreen, but n/a
165 }
166 if (!gldes.isOnscreen()) {
167 /** FBO is generic ..
168 if (gldes.isFBO() && !cur.isFBO()) {
169 continue; // requested FBO, but n/a
170 } */
171 if (gldes.isPBuffer() && !cur.isPBuffer()) {
172 continue; // requested pBuffer, but n/a
173 }
174 if (gldes.isBitmap() && !cur.isBitmap()) {
175 continue; // requested pBuffer, but n/a
176 }
177 }
178 if (gldes.getStereo() != cur.getStereo()) {
179 continue;
180 }
181 final int cur_samples = cur.getNumSamples() ;
182 int score = 0;
183
184 // Compute difference in color depth
185 // (Note that this decides the direction of all other penalties)
186 score += (COLOR_MISMATCH_PENALTY_SCALE *
187 ((cur.getRedBits() + cur.getGreenBits() + cur.getBlueBits() + cur.getAlphaBits()) -
188 (gldes.getRedBits() + gldes.getGreenBits() + gldes.getBlueBits() + gldes.getAlphaBits())));
189 // Compute difference in depth buffer depth
190 score += (DEPTH_MISMATCH_PENALTY_SCALE * sign(score) *
191 Math.abs(cur.getDepthBits() - gldes.getDepthBits()));
192 // Compute difference in accumulation buffer depth
193 score += (ACCUM_MISMATCH_PENALTY_SCALE * sign(score) *
194 Math.abs((cur.getAccumRedBits() + cur.getAccumGreenBits() + cur.getAccumBlueBits() + cur.getAccumAlphaBits()) -
195 (gldes.getAccumRedBits() + gldes.getAccumGreenBits() + gldes.getAccumBlueBits() + gldes.getAccumAlphaBits())));
196 // Compute difference in stencil bits
197 score += STENCIL_MISMATCH_PENALTY_SCALE * sign(score) * (cur.getStencilBits() - gldes.getStencilBits());
198 // Compute difference in multisampling bits
199 score += MULTISAMPLE_MISMATCH_PENALTY_SCALE * sign(score) * (cur_samples - gldes_samples);
200 // double buffer
201 if (cur.getDoubleBuffered() != gldes.getDoubleBuffered()) {
202 score += sign(score) * DOUBLE_BUFFER_MISMATCH_PENALTY;
203 }
204 // opaque
205 if (cur.isBackgroundOpaque() != gldes.isBackgroundOpaque()) {
206 score += sign(score) * OPAQUE_MISMATCH_PENALTY;
207 }
208 if ((gldes.getStencilBits() > 0) && (cur.getStencilBits() == 0)) {
209 score += sign(score) * STENCIL_MISMATCH_PENALTY;
210 }
211 if (gldes_samples > 0) {
212 if (cur_samples == 0) {
213 score += sign(score) * MULTISAMPLE_MISMATCH_PENALTY;
214 }
215 if (!gldes.getSampleExtension().equals(cur.getSampleExtension())) {
216 score += sign(score) * MULTISAMPLE_EXTENSION_MISMATCH_PENALTY;
217 }
218 }
219 scores[i] = score;
220 }
221 // Now prefer hardware-accelerated visuals by pushing scores of
222 // non-hardware-accelerated visuals out
223 boolean gotHW = false;
224 int maxAbsoluteHWScore = 0;
225 for (int i = 0; i < availnum; i++) {
226 final int score = scores[i];
227 if (score == NO_SCORE) {
228 continue;
229 }
230 final GLCapabilitiesImmutable cur = (GLCapabilitiesImmutable) available.get(i);
231 if (cur.getHardwareAccelerated()) {
232 final int absScore = Math.abs(score);
233 if (!gotHW ||
234 (absScore > maxAbsoluteHWScore)) {
235 gotHW = true;
236 maxAbsoluteHWScore = absScore;
237 }
238 }
239 }
240 if (gotHW) {
241 for (int i = 0; i < availnum; i++) {
242 int score = scores[i];
243 if (score == NO_SCORE) {
244 continue;
245 }
246 final GLCapabilitiesImmutable cur = (GLCapabilitiesImmutable) available.get(i);
247 if (!cur.getHardwareAccelerated()) {
248 if (score <= 0) {
249 score -= maxAbsoluteHWScore;
250 } else if (score > 0) {
251 score += maxAbsoluteHWScore;
252 }
253 scores[i] = score;
254 }
255 }
256 }
257
258 if (DEBUG) {
259 System.err.print("Scores: [");
260 for (int i = 0; i < availnum; i++) {
261 if (i > 0) {
262 System.err.print(",");
263 }
264 System.err.print(" " + i +": " + scores[i]);
265 }
266 System.err.println(" ]");
267 }
268
269 // Ready to select. Choose score closest to 0.
270 int scoreClosestToZero = NO_SCORE;
271 int chosenIndex = -1;
272 for (int i = 0; i < availnum; i++) {
273 final int score = scores[i];
274 if (score == NO_SCORE) {
275 continue;
276 }
277 // Don't substitute a positive score for a smaller negative score
278 if ((scoreClosestToZero == NO_SCORE) ||
279 (Math.abs(score) < Math.abs(scoreClosestToZero) &&
280 ((sign(scoreClosestToZero) < 0) || (sign(score) > 0)))) {
281 scoreClosestToZero = score;
282 chosenIndex = i;
283 }
284 }
285 if (chosenIndex < 0) {
286 throw new NativeWindowException("Unable to select one of the provided GLCapabilities");
287 }
288 if (DEBUG) {
289 System.err.println("Chosen index: " + chosenIndex);
290 System.err.println("Chosen capabilities:");
291 System.err.println(available.get(chosenIndex));
292 }
293
294 return chosenIndex;
295 }
296
297 private static int sign(final int score) {
298 if (score < 0) {
299 return -1;
300 }
301 return 1;
302 }
303
304}
A generic exception for OpenGL errors used throughout the binding as a substitute for RuntimeExceptio...
int chooseCapabilities(final CapabilitiesImmutable desired, final List<? extends CapabilitiesImmutable > available, final int windowSystemRecommendedChoice)
Chooses the index (0..available.length - 1) of the Capabilities most closely matching the desired one...
Specifies an immutable set of capabilities that a window's rendering context must support,...
int getAlphaBits()
Returns the number of bits for the color buffer's alpha component.
int getBlueBits()
Returns the number of bits for the color buffer's blue component.
boolean isBitmap()
Returns whether bitmap offscreen mode is requested, available or chosen.
int getRedBits()
Returns the number of bits for the color buffer's red component.
int getGreenBits()
Returns the number of bits for the color buffer's green component.
boolean isOnscreen()
Returns whether an on- or offscreen surface is requested, available or chosen.
boolean isBackgroundOpaque()
Returns whether an opaque or translucent surface is requested, supported or chosen.
Provides a mechanism by which applications can customize the window type selection for a given GLCapa...
Specifies an immutable set of OpenGL capabilities.
int getAccumGreenBits()
Returns the number of bits for the accumulation buffer's green component.
String getSampleExtension()
Returns the extension for full-scene antialiasing (FSAA).
int getNumSamples()
Returns the number of sample buffers to be allocated if sample buffers are enabled,...
boolean getHardwareAccelerated()
Returns whether hardware acceleration is requested, available or chosen.
int getDepthBits()
Returns the number of depth buffer bits.
boolean isPBuffer()
Returns whether pbuffer offscreen mode is requested, available or chosen.
int getAccumRedBits()
Returns the number of bits for the accumulation buffer's red component.
int getAccumAlphaBits()
Returns the number of bits for the accumulation buffer's alpha component.
boolean getDoubleBuffered()
Returns whether double-buffering is requested, available or chosen.
int getAccumBlueBits()
Returns the number of bits for the accumulation buffer's blue component.
int getStencilBits()
Returns the number of stencil buffer bits.
boolean getStereo()
Returns whether stereo is requested, available or chosen.