1 /*
2  * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * - Redistribution of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  *
11  * - Redistribution in binary form must reproduce the above copyright
12  *   notice, this list of conditions and the following disclaimer in the
13  *   documentation and/or other materials provided with the distribution.
14  *
15  * Neither the name of Sun Microsystems, Inc. or the names of
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * This software is provided "AS IS," without a warranty of any kind. ALL
20  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
23  * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
24  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
25  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
26  * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
27  * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
28  * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
29  * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
30  * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  *
32  * You acknowledge that this software is not designed or intended for use
33  * in the design, construction, operation or maintenance of any nuclear
34  * facility.
35  *
36  * Sun gratefully acknowledges that this software was originally authored
37  * and developed by Kenneth Bradley Russell and Christopher John Kline.
38  */
39 
40 package com.sun.opengl.impl.windows;
41 
42 import javax.media.opengl.*;
43 import com.sun.opengl.impl.*;
44 
45 public abstract class WindowsGLDrawable extends GLDrawableImpl {
46   protected static final boolean DEBUG = Debug.debug("WindowsGLDrawable");
47 
48   protected long hdc;
49   protected GLCapabilities capabilities;
50   protected GLCapabilitiesChooser chooser;
51   protected boolean pixelFormatChosen;
52 
53   protected static final int MAX_PFORMATS = 256;
54   protected static final int MAX_ATTRIBS  = 256;
55 
WindowsGLDrawable(GLCapabilities capabilities, GLCapabilitiesChooser chooser)56   public WindowsGLDrawable(GLCapabilities capabilities,
57                            GLCapabilitiesChooser chooser) {
58     this.capabilities = (GLCapabilities) capabilities.clone();
59     this.chooser = chooser;
60   }
61 
setRealized(boolean val)62   public void setRealized(boolean val) {
63     throw new GLException("Should not call this (should only be called for onscreen GLDrawables)");
64   }
65 
destroy()66   public void destroy() {
67     throw new GLException("Should not call this (should only be called for offscreen GLDrawables)");
68   }
69 
swapBuffers()70   public void swapBuffers() throws GLException {
71   }
72 
getHDC()73   public long getHDC() {
74     return hdc;
75   }
76 
choosePixelFormat(boolean onscreen)77   protected void choosePixelFormat(boolean onscreen) {
78     PIXELFORMATDESCRIPTOR pfd = null;
79     int pixelFormat = 0;
80     GLCapabilities chosenCaps = null;
81     if (onscreen) {
82       if ((pixelFormat = WGL.GetPixelFormat(hdc)) != 0) {
83         // The Java2D/OpenGL pipeline probably already set a pixel
84         // format for this canvas.
85         if (DEBUG) {
86           System.err.println("NOTE: pixel format already chosen (by Java2D/OpenGL pipeline?) for window: " +
87                              WGL.GetPixelFormat(hdc));
88         }
89         pfd = newPixelFormatDescriptor();
90         if (WGL.DescribePixelFormat(hdc, pixelFormat, pfd.size(), pfd) == 0) {
91           // FIXME: should this just be a warning? Not really critical...
92           throw new GLException("Unable to describe pixel format " + pixelFormat +
93                                 " of window set by Java2D/OpenGL pipeline");
94         }
95         setChosenGLCapabilities(pfd2GLCapabilities(pfd));
96         pixelFormatChosen = true;
97         return;
98       }
99 
100       GLCapabilities[] availableCaps = null;
101       int numFormats = 0;
102       pfd = newPixelFormatDescriptor();
103       // Produce a recommended pixel format selection for the GLCapabilitiesChooser.
104       // Use wglChoosePixelFormatARB if user requested multisampling and if we have it available
105       WindowsGLDrawable dummyDrawable = null;
106       GLContextImpl     dummyContext  = null;
107       WGLExt            dummyWGLExt   = null;
108       if (capabilities.getSampleBuffers()) {
109         dummyDrawable = new WindowsDummyGLDrawable();
110         dummyContext  = (GLContextImpl) dummyDrawable.createContext(null);
111         if (dummyContext != null) {
112           dummyContext.makeCurrent();
113           dummyWGLExt = (WGLExt) dummyContext.getPlatformGLExtensions();
114         }
115       }
116       int recommendedPixelFormat = -1;
117       boolean haveWGLChoosePixelFormatARB = false;
118       boolean haveWGLARBMultisample = false;
119       boolean gotAvailableCaps = false;
120       if (dummyWGLExt != null) {
121         try {
122           haveWGLChoosePixelFormatARB = dummyWGLExt.isExtensionAvailable("WGL_ARB_pixel_format");
123           if (haveWGLChoosePixelFormatARB) {
124             haveWGLARBMultisample = dummyWGLExt.isExtensionAvailable("WGL_ARB_multisample");
125 
126             int[]   iattributes = new int  [2 * MAX_ATTRIBS];
127             int[]   iresults    = new int  [2 * MAX_ATTRIBS];
128             float[] fattributes = new float[1];
129 
130             if (glCapabilities2iattributes(capabilities,
131                                            iattributes,
132                                            dummyWGLExt,
133                                            false,
134                                            null)) {
135               int[] pformats = new int[MAX_PFORMATS];
136               int[] numFormatsTmp = new int[1];
137               if (dummyWGLExt.wglChoosePixelFormatARB(hdc,
138                                                       iattributes, 0,
139                                                       fattributes, 0,
140                                                       MAX_PFORMATS,
141                                                       pformats, 0,
142                                                       numFormatsTmp, 0)) {
143                 numFormats = numFormatsTmp[0];
144                 if (numFormats > 0) {
145                   // Remove one-basing of pixel format (added on later)
146                   recommendedPixelFormat = pformats[0] - 1;
147                   if (DEBUG) {
148                     System.err.println(getThreadName() + ": Used wglChoosePixelFormatARB to recommend pixel format " + recommendedPixelFormat);
149                   }
150                 }
151               } else {
152                 if (DEBUG) {
153                   System.err.println(getThreadName() + ": wglChoosePixelFormatARB failed: " + WGL.GetLastError() );
154                   Thread.dumpStack();
155                 }
156               }
157               if (DEBUG) {
158                 if (recommendedPixelFormat < 0) {
159                   System.err.print(getThreadName() + ": wglChoosePixelFormatARB didn't recommend a pixel format");
160                   if (capabilities.getSampleBuffers()) {
161                     System.err.print(" for multisampled GLCapabilities");
162                   }
163                   System.err.println();
164                 }
165               }
166 
167               // Produce a list of GLCapabilities to give to the
168               // GLCapabilitiesChooser.
169               // Use wglGetPixelFormatAttribivARB instead of
170               // DescribePixelFormat to get higher-precision information
171               // about the pixel format (should make the GLCapabilities
172               // more precise as well...i.e., remove the
173               // "HardwareAccelerated" bit, which is basically
174               // meaningless, and put in whether it can render to a
175               // window, to a pbuffer, or to a pixmap)
176               int niattribs = 0;
177               iattributes[0] = WGLExt.WGL_NUMBER_PIXEL_FORMATS_ARB;
178               if (dummyWGLExt.wglGetPixelFormatAttribivARB(hdc, 0, 0, 1, iattributes, 0, iresults, 0)) {
179                 numFormats = iresults[0];
180 
181                 if (DEBUG) {
182                   System.err.println("wglGetPixelFormatAttribivARB reported WGL_NUMBER_PIXEL_FORMATS_ARB = " + numFormats);
183                 }
184 
185                 // Should we be filtering out the pixel formats which aren't
186                 // applicable, as we are doing here?
187                 // We don't have enough information in the GLCapabilities to
188                 // represent those that aren't...
189                 iattributes[niattribs++] = WGLExt.WGL_DRAW_TO_WINDOW_ARB;
190                 iattributes[niattribs++] = WGLExt.WGL_ACCELERATION_ARB;
191                 iattributes[niattribs++] = WGLExt.WGL_SUPPORT_OPENGL_ARB;
192                 iattributes[niattribs++] = WGLExt.WGL_DEPTH_BITS_ARB;
193                 iattributes[niattribs++] = WGLExt.WGL_STENCIL_BITS_ARB;
194                 iattributes[niattribs++] = WGLExt.WGL_DOUBLE_BUFFER_ARB;
195                 iattributes[niattribs++] = WGLExt.WGL_STEREO_ARB;
196                 iattributes[niattribs++] = WGLExt.WGL_PIXEL_TYPE_ARB;
197                 iattributes[niattribs++] = WGLExt.WGL_RED_BITS_ARB;
198                 iattributes[niattribs++] = WGLExt.WGL_GREEN_BITS_ARB;
199                 iattributes[niattribs++] = WGLExt.WGL_BLUE_BITS_ARB;
200                 iattributes[niattribs++] = WGLExt.WGL_ALPHA_BITS_ARB;
201                 iattributes[niattribs++] = WGLExt.WGL_ACCUM_RED_BITS_ARB;
202                 iattributes[niattribs++] = WGLExt.WGL_ACCUM_GREEN_BITS_ARB;
203                 iattributes[niattribs++] = WGLExt.WGL_ACCUM_BLUE_BITS_ARB;
204                 iattributes[niattribs++] = WGLExt.WGL_ACCUM_ALPHA_BITS_ARB;
205                 if (haveWGLARBMultisample) {
206                   iattributes[niattribs++] = WGLExt.WGL_SAMPLE_BUFFERS_ARB;
207                   iattributes[niattribs++] = WGLExt.WGL_SAMPLES_ARB;
208                 }
209 
210                 availableCaps = new GLCapabilities[numFormats];
211                 for (int i = 0; i < numFormats; i++) {
212                   if (!dummyWGLExt.wglGetPixelFormatAttribivARB(hdc, i+1, 0, niattribs, iattributes, 0, iresults, 0)) {
213                     throw new GLException("Error getting pixel format attributes for pixel format " + (i + 1) + " of device context");
214                   }
215                   availableCaps[i] = iattributes2GLCapabilities(iattributes, niattribs, iresults, true);
216                 }
217                 gotAvailableCaps = true;
218               } else {
219                 long lastErr = WGL.GetLastError();
220                 // Intel Extreme graphics fails with a zero error code
221                 if (lastErr != 0) {
222                   throw new GLException("Unable to enumerate pixel formats of window using wglGetPixelFormatAttribivARB: error code " + WGL.GetLastError());
223                 }
224               }
225             }
226           }
227         } finally {
228           dummyContext.release();
229           dummyContext.destroy();
230           dummyDrawable.destroy();
231         }
232       }
233 
234       // Fallback path for older cards, in particular Intel Extreme motherboard graphics
235       if (!gotAvailableCaps) {
236         if (DEBUG) {
237           if (!capabilities.getSampleBuffers()) {
238             System.err.println(getThreadName() + ": Using ChoosePixelFormat because multisampling not requested");
239           } else {
240             System.err.println(getThreadName() + ": Using ChoosePixelFormat because no wglChoosePixelFormatARB");
241           }
242         }
243         pfd = glCapabilities2PFD(capabilities, onscreen);
244         // Remove one-basing of pixel format (added on later)
245         recommendedPixelFormat = WGL.ChoosePixelFormat(hdc, pfd) - 1;
246 
247         numFormats = WGL.DescribePixelFormat(hdc, 1, 0, null);
248         if (numFormats == 0) {
249           throw new GLException("Unable to enumerate pixel formats of window for GLCapabilitiesChooser");
250         }
251         availableCaps = new GLCapabilities[numFormats];
252         for (int i = 0; i < numFormats; i++) {
253           if (WGL.DescribePixelFormat(hdc, 1 + i, pfd.size(), pfd) == 0) {
254             throw new GLException("Error describing pixel format " + (1 + i) + " of device context");
255           }
256           availableCaps[i] = pfd2GLCapabilities(pfd);
257         }
258       }
259 
260       // NOTE: officially, should make a copy of all of these
261       // GLCapabilities to avoid mutation by the end user during the
262       // chooseCapabilities call, but for the time being, assume they
263       // won't be changed
264 
265       // Supply information to chooser
266       pixelFormat = chooser.chooseCapabilities(capabilities, availableCaps, recommendedPixelFormat);
267       if ((pixelFormat < 0) || (pixelFormat >= numFormats)) {
268         throw new GLException("Invalid result " + pixelFormat +
269                               " from GLCapabilitiesChooser (should be between 0 and " +
270                               (numFormats - 1) + ")");
271       }
272       if (DEBUG) {
273         System.err.println(getThreadName() + ": Chosen pixel format (" + pixelFormat + "):");
274         System.err.println(availableCaps[pixelFormat]);
275       }
276       chosenCaps = availableCaps[pixelFormat];
277       pixelFormat += 1; // one-base the index
278       if (WGL.DescribePixelFormat(hdc, pixelFormat, pfd.size(), pfd) == 0) {
279         throw new GLException("Error re-describing the chosen pixel format: " + WGL.GetLastError());
280       }
281     } else {
282       // For now, use ChoosePixelFormat for offscreen surfaces until
283       // we figure out how to properly choose an offscreen-
284       // compatible pixel format
285       pfd = glCapabilities2PFD(capabilities, onscreen);
286       pixelFormat = WGL.ChoosePixelFormat(hdc, pfd);
287     }
288     if (!WGL.SetPixelFormat(hdc, pixelFormat, pfd)) {
289       long lastError = WGL.GetLastError();
290       if (DEBUG) {
291         System.err.println(getThreadName() + ": SetPixelFormat failed: current context = " + WGL.wglGetCurrentContext() +
292                            ", current DC = " + WGL.wglGetCurrentDC());
293         System.err.println(getThreadName() + ": GetPixelFormat(hdc " + toHexString(hdc) + ") returns " + WGL.GetPixelFormat(hdc));
294       }
295       throw new GLException("Unable to set pixel format " + pixelFormat + " for device context " + toHexString(hdc) + ": error code " + lastError);
296     }
297     // Reuse the previously-constructed GLCapabilities because it
298     // turns out that using DescribePixelFormat on some pixel formats
299     // (which, for example, support full-scene antialiasing) for some
300     // reason return that they are not OpenGL-capable
301     if (chosenCaps != null) {
302       setChosenGLCapabilities(chosenCaps);
303     } else {
304       setChosenGLCapabilities(pfd2GLCapabilities(pfd));
305     }
306     pixelFormatChosen = true;
307   }
308 
glCapabilities2PFD(GLCapabilities caps, boolean onscreen)309   protected static PIXELFORMATDESCRIPTOR glCapabilities2PFD(GLCapabilities caps, boolean onscreen) {
310     int colorDepth = (caps.getRedBits() +
311                       caps.getGreenBits() +
312                       caps.getBlueBits());
313     if (colorDepth < 15) {
314       throw new GLException("Bit depths < 15 (i.e., non-true-color) not supported");
315     }
316     PIXELFORMATDESCRIPTOR pfd = newPixelFormatDescriptor();
317     int pfdFlags = (WGL.PFD_SUPPORT_OPENGL |
318                     WGL.PFD_GENERIC_ACCELERATED);
319     if (caps.getDoubleBuffered()) {
320       pfdFlags |= WGL.PFD_DOUBLEBUFFER;
321     }
322     if (onscreen) {
323       pfdFlags |= WGL.PFD_DRAW_TO_WINDOW;
324     } else {
325       pfdFlags |= WGL.PFD_DRAW_TO_BITMAP;
326     }
327     if (caps.getStereo()) {
328       pfdFlags |= WGL.PFD_STEREO;
329     }
330     pfd.dwFlags(pfdFlags);
331     pfd.iPixelType((byte) WGL.PFD_TYPE_RGBA);
332     pfd.cColorBits((byte) colorDepth);
333     pfd.cRedBits  ((byte) caps.getRedBits());
334     pfd.cGreenBits((byte) caps.getGreenBits());
335     pfd.cBlueBits ((byte) caps.getBlueBits());
336     pfd.cAlphaBits((byte) caps.getAlphaBits());
337     int accumDepth = (caps.getAccumRedBits() +
338                       caps.getAccumGreenBits() +
339                       caps.getAccumBlueBits());
340     pfd.cAccumBits     ((byte) accumDepth);
341     pfd.cAccumRedBits  ((byte) caps.getAccumRedBits());
342     pfd.cAccumGreenBits((byte) caps.getAccumGreenBits());
343     pfd.cAccumBlueBits ((byte) caps.getAccumBlueBits());
344     pfd.cAccumAlphaBits((byte) caps.getAccumAlphaBits());
345     pfd.cDepthBits((byte) caps.getDepthBits());
346     pfd.cStencilBits((byte) caps.getStencilBits());
347     pfd.iLayerType((byte) WGL.PFD_MAIN_PLANE);
348     return pfd;
349   }
350 
newPixelFormatDescriptor()351   protected static PIXELFORMATDESCRIPTOR newPixelFormatDescriptor() {
352     PIXELFORMATDESCRIPTOR pfd = PIXELFORMATDESCRIPTOR.create();
353     pfd.nSize((short) pfd.size());
354     pfd.nVersion((short) 1);
355     return pfd;
356   }
357 
pfd2GLCapabilities(PIXELFORMATDESCRIPTOR pfd)358   protected static GLCapabilities pfd2GLCapabilities(PIXELFORMATDESCRIPTOR pfd) {
359     if ((pfd.dwFlags() & WGL.PFD_SUPPORT_OPENGL) == 0) {
360       return null;
361     }
362     GLCapabilities res = new GLCapabilities();
363     res.setRedBits       (pfd.cRedBits());
364     res.setGreenBits     (pfd.cGreenBits());
365     res.setBlueBits      (pfd.cBlueBits());
366     res.setAlphaBits     (pfd.cAlphaBits());
367     res.setAccumRedBits  (pfd.cAccumRedBits());
368     res.setAccumGreenBits(pfd.cAccumGreenBits());
369     res.setAccumBlueBits (pfd.cAccumBlueBits());
370     res.setAccumAlphaBits(pfd.cAccumAlphaBits());
371     res.setDepthBits     (pfd.cDepthBits());
372     res.setStencilBits   (pfd.cStencilBits());
373     res.setDoubleBuffered((pfd.dwFlags() & WGL.PFD_DOUBLEBUFFER) != 0);
374     res.setStereo        ((pfd.dwFlags() & WGL.PFD_STEREO) != 0);
375     res.setHardwareAccelerated(((pfd.dwFlags() & WGL.PFD_GENERIC_FORMAT) == 0) ||
376 			       ((pfd.dwFlags() & WGL.PFD_GENERIC_ACCELERATED) != 0));
377     return res;
378   }
379 
glCapabilities2iattributes(GLCapabilities capabilities, int[] iattributes, WGLExt wglExt, boolean pbuffer, int[] floatMode)380   protected static boolean glCapabilities2iattributes(GLCapabilities capabilities,
381                                                       int[] iattributes,
382                                                       WGLExt wglExt,
383                                                       boolean pbuffer,
384                                                       int[] floatMode) throws GLException {
385     if (!wglExt.isExtensionAvailable("WGL_ARB_pixel_format")) {
386       return false;
387     }
388 
389     int niattribs = 0;
390 
391     iattributes[niattribs++] = WGLExt.WGL_SUPPORT_OPENGL_ARB;
392     iattributes[niattribs++] = GL.GL_TRUE;
393     if (pbuffer) {
394       iattributes[niattribs++] = WGLExt.WGL_DRAW_TO_PBUFFER_ARB;
395       iattributes[niattribs++] = GL.GL_TRUE;
396     } else {
397       iattributes[niattribs++] = WGLExt.WGL_DRAW_TO_WINDOW_ARB;
398       iattributes[niattribs++] = GL.GL_TRUE;
399     }
400 
401     iattributes[niattribs++] = WGLExt.WGL_DOUBLE_BUFFER_ARB;
402     if (capabilities.getDoubleBuffered()) {
403       iattributes[niattribs++] = GL.GL_TRUE;
404     } else {
405       iattributes[niattribs++] = GL.GL_FALSE;
406     }
407 
408     iattributes[niattribs++] = WGLExt.WGL_STEREO_ARB;
409     if (capabilities.getStereo()) {
410       iattributes[niattribs++] = GL.GL_TRUE;
411     } else {
412       iattributes[niattribs++] = GL.GL_FALSE;
413     }
414 
415     iattributes[niattribs++] = WGLExt.WGL_DEPTH_BITS_ARB;
416     iattributes[niattribs++] = capabilities.getDepthBits();
417     iattributes[niattribs++] = WGLExt.WGL_RED_BITS_ARB;
418     iattributes[niattribs++] = capabilities.getRedBits();
419     iattributes[niattribs++] = WGLExt.WGL_GREEN_BITS_ARB;
420     iattributes[niattribs++] = capabilities.getGreenBits();
421     iattributes[niattribs++] = WGLExt.WGL_BLUE_BITS_ARB;
422     iattributes[niattribs++] = capabilities.getBlueBits();
423     iattributes[niattribs++] = WGLExt.WGL_ALPHA_BITS_ARB;
424     iattributes[niattribs++] = capabilities.getAlphaBits();
425     iattributes[niattribs++] = WGLExt.WGL_STENCIL_BITS_ARB;
426     iattributes[niattribs++] = capabilities.getStencilBits();
427     if (capabilities.getAccumRedBits()   > 0 ||
428         capabilities.getAccumGreenBits() > 0 ||
429         capabilities.getAccumBlueBits()  > 0 ||
430         capabilities.getAccumAlphaBits() > 0) {
431       iattributes[niattribs++] = WGLExt.WGL_ACCUM_BITS_ARB;
432       iattributes[niattribs++] = (capabilities.getAccumRedBits() +
433                                   capabilities.getAccumGreenBits() +
434                                   capabilities.getAccumBlueBits() +
435                                   capabilities.getAccumAlphaBits());
436       iattributes[niattribs++] = WGLExt.WGL_ACCUM_RED_BITS_ARB;
437       iattributes[niattribs++] = capabilities.getAccumRedBits();
438       iattributes[niattribs++] = WGLExt.WGL_ACCUM_GREEN_BITS_ARB;
439       iattributes[niattribs++] = capabilities.getAccumGreenBits();
440       iattributes[niattribs++] = WGLExt.WGL_ACCUM_BLUE_BITS_ARB;
441       iattributes[niattribs++] = capabilities.getAccumBlueBits();
442       iattributes[niattribs++] = WGLExt.WGL_ACCUM_ALPHA_BITS_ARB;
443       iattributes[niattribs++] = capabilities.getAccumAlphaBits();
444     }
445 
446     if (wglExt.isExtensionAvailable("WGL_ARB_multisample")) {
447       if (capabilities.getSampleBuffers()) {
448         iattributes[niattribs++] = WGLExt.WGL_SAMPLE_BUFFERS_ARB;
449         iattributes[niattribs++] = GL.GL_TRUE;
450         iattributes[niattribs++] = WGLExt.WGL_SAMPLES_ARB;
451         iattributes[niattribs++] = capabilities.getNumSamples();
452       }
453     }
454 
455     boolean rtt      = capabilities.getPbufferRenderToTexture();
456     boolean rect     = capabilities.getPbufferRenderToTextureRectangle();
457     boolean useFloat = capabilities.getPbufferFloatingPointBuffers();
458     boolean ati      = false;
459     if (pbuffer) {
460       // Check some invariants and set up some state
461       if (rect && !rtt) {
462         throw new GLException("Render-to-texture-rectangle requires render-to-texture to be specified");
463       }
464 
465       if (rect) {
466         if (!wglExt.isExtensionAvailable("GL_NV_texture_rectangle")) {
467           throw new GLException("Render-to-texture-rectangle requires GL_NV_texture_rectangle extension");
468         }
469       }
470 
471       if (useFloat) {
472         if (!wglExt.isExtensionAvailable("WGL_ATI_pixel_format_float") &&
473             !wglExt.isExtensionAvailable("WGL_NV_float_buffer")) {
474           throw new GLException("Floating-point pbuffers not supported by this hardware");
475         }
476 
477         // Prefer NVidia extension over ATI
478         if (wglExt.isExtensionAvailable("WGL_NV_float_buffer")) {
479           ati = false;
480           floatMode[0] = GLPbuffer.NV_FLOAT;
481         } else {
482           ati = true;
483           floatMode[0] = GLPbuffer.ATI_FLOAT;
484         }
485         if (DEBUG) {
486           System.err.println("Using " + (ati ? "ATI" : "NVidia") + " floating-point extension");
487         }
488       }
489 
490       // See whether we need to change the pixel type to support ATI's
491       // floating-point pbuffers
492       if (useFloat && ati) {
493         if (rtt) {
494           throw new GLException("Render-to-floating-point-texture not supported on ATI hardware");
495         } else {
496           iattributes[niattribs++] = WGLExt.WGL_PIXEL_TYPE_ARB;
497           iattributes[niattribs++] = WGLExt.WGL_TYPE_RGBA_FLOAT_ATI;
498         }
499       } else {
500         if (!rtt) {
501           // Currently we don't support non-truecolor visuals in the
502           // GLCapabilities, so we don't offer the option of making
503           // color-index pbuffers.
504           iattributes[niattribs++] = WGLExt.WGL_PIXEL_TYPE_ARB;
505           iattributes[niattribs++] = WGLExt.WGL_TYPE_RGBA_ARB;
506         }
507       }
508 
509       if (useFloat && !ati) {
510         iattributes[niattribs++] = WGLExt.WGL_FLOAT_COMPONENTS_NV;
511         iattributes[niattribs++] = GL.GL_TRUE;
512       }
513 
514       if (rtt) {
515         if (useFloat) {
516           assert(!ati);
517           if (!rect) {
518             throw new GLException("Render-to-floating-point-texture only supported on NVidia hardware with render-to-texture-rectangle");
519           }
520           iattributes[niattribs++] = WGLExt.WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV;
521           iattributes[niattribs++] = GL.GL_TRUE;
522         } else {
523           iattributes[niattribs++] = rect ? WGLExt.WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV : WGLExt.WGL_BIND_TO_TEXTURE_RGB_ARB;
524           iattributes[niattribs++] = GL.GL_TRUE;
525         }
526       }
527     } else {
528       iattributes[niattribs++] = WGLExt.WGL_PIXEL_TYPE_ARB;
529       iattributes[niattribs++] = WGLExt.WGL_TYPE_RGBA_ARB;
530     }
531 
532     return true;
533   }
534 
iattributes2GLCapabilities(int[] iattribs, int niattribs, int[] iresults, boolean requireRenderToWindow)535   protected static GLCapabilities iattributes2GLCapabilities(int[] iattribs,
536                                                              int niattribs,
537                                                              int[] iresults,
538                                                              boolean requireRenderToWindow) {
539     GLCapabilities res = new GLCapabilities();
540     for (int i = 0; i < niattribs; i++) {
541       int attr = iattribs[i];
542       switch (attr) {
543         case WGLExt.WGL_DRAW_TO_WINDOW_ARB:
544           if (requireRenderToWindow && iresults[i] != GL.GL_TRUE)
545             return null;
546           break;
547 
548         case WGLExt.WGL_DRAW_TO_PBUFFER_ARB:
549           break;
550 
551         case WGLExt.WGL_ACCELERATION_ARB:
552           res.setHardwareAccelerated(iresults[i] == WGLExt.WGL_FULL_ACCELERATION_ARB);
553           break;
554 
555         case WGLExt.WGL_SUPPORT_OPENGL_ARB:
556           if (iresults[i] != GL.GL_TRUE)
557             return null;
558           break;
559 
560         case WGLExt.WGL_DEPTH_BITS_ARB:
561           res.setDepthBits(iresults[i]);
562           break;
563 
564         case WGLExt.WGL_STENCIL_BITS_ARB:
565           res.setStencilBits(iresults[i]);
566           break;
567 
568         case WGLExt.WGL_DOUBLE_BUFFER_ARB:
569           res.setDoubleBuffered(iresults[i] == GL.GL_TRUE);
570           break;
571 
572         case WGLExt.WGL_STEREO_ARB:
573           res.setStereo(iresults[i] == GL.GL_TRUE);
574           break;
575 
576         case WGLExt.WGL_PIXEL_TYPE_ARB:
577           // Fail softly with unknown results here
578           if (iresults[i] == WGLExt.WGL_TYPE_RGBA_ARB ||
579               iresults[i] == WGLExt.WGL_TYPE_RGBA_FLOAT_ATI) {
580             res.setPbufferFloatingPointBuffers(true);
581           }
582           break;
583 
584         case WGLExt.WGL_FLOAT_COMPONENTS_NV:
585           if (iresults[i] != 0) {
586             res.setPbufferFloatingPointBuffers(true);
587           }
588           break;
589 
590         case WGLExt.WGL_RED_BITS_ARB:
591           res.setRedBits(iresults[i]);
592           break;
593 
594         case WGLExt.WGL_GREEN_BITS_ARB:
595           res.setGreenBits(iresults[i]);
596           break;
597 
598         case WGLExt.WGL_BLUE_BITS_ARB:
599           res.setBlueBits(iresults[i]);
600           break;
601 
602         case WGLExt.WGL_ALPHA_BITS_ARB:
603           res.setAlphaBits(iresults[i]);
604           break;
605 
606         case WGLExt.WGL_ACCUM_RED_BITS_ARB:
607           res.setAccumRedBits(iresults[i]);
608           break;
609 
610         case WGLExt.WGL_ACCUM_GREEN_BITS_ARB:
611           res.setAccumGreenBits(iresults[i]);
612           break;
613 
614         case WGLExt.WGL_ACCUM_BLUE_BITS_ARB:
615           res.setAccumBlueBits(iresults[i]);
616           break;
617 
618         case WGLExt.WGL_ACCUM_ALPHA_BITS_ARB:
619           res.setAccumAlphaBits(iresults[i]);
620           break;
621 
622         case WGLExt.WGL_SAMPLE_BUFFERS_ARB:
623           res.setSampleBuffers(iresults[i] != 0);
624           break;
625 
626         case WGLExt.WGL_SAMPLES_ARB:
627           res.setNumSamples(iresults[i]);
628           break;
629 
630         default:
631           throw new GLException("Unknown pixel format attribute " + iattribs[i]);
632       }
633     }
634     return res;
635   }
636 
getThreadName()637   protected static String getThreadName() {
638     return Thread.currentThread().getName();
639   }
640 }
641