1/*
2 * Copyright (C) 2009  VMware, Inc.
3 * Copyright (C) 1999-2006  Brian Paul
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24
25/*
26 * This program is a work-alike of the GLX glxinfo program.
27 * Command line options:
28 *  -t                     print wide table
29 *  -v                     print verbose information
30 *  -b                     only print ID of "best" visual on screen 0
31 *  -l                     print interesting OpenGL limits (added 5 Sep 2002)
32 */
33
34
35#include <windows.h>
36#include <stdbool.h>
37#include <GL/glew.h>
38#include <GL/wglew.h>
39#include <assert.h>
40#include <stdio.h>
41#include <string.h>
42#include <stdlib.h>
43#include "glinfo_common.h"
44
45
46static GLboolean have_WGL_ARB_create_context;
47static GLboolean have_WGL_ARB_pbuffer;
48static GLboolean have_WGL_ARB_pixel_format;
49static GLboolean have_WGL_ARB_multisample;
50static GLboolean have_WGL_ARB_framebuffer_sRGB; /* or EXT version */
51
52static PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB_func;
53static PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB_func;
54
55
56/**
57 * An extension of PIXELFORMATDESCRIPTOR to handle multisample, etc.
58 */
59struct format_info {
60   PIXELFORMATDESCRIPTOR pfd;
61   int sampleBuffers, numSamples;
62   int transparency;
63   bool floatComponents;
64   bool srgb;
65   bool draw_to_bitmap;
66   bool draw_to_pbuffer;
67   bool gdi_drawing;
68};
69
70
71static LRESULT CALLBACK
72WndProc(HWND hWnd,
73        UINT uMsg,
74        WPARAM wParam,
75        LPARAM lParam )
76{
77   switch (uMsg) {
78   case WM_DESTROY:
79      PostQuitMessage(0);
80      break;
81   default:
82      return DefWindowProc(hWnd, uMsg, wParam, lParam);
83   }
84
85   return 0;
86}
87
88
89static void
90print_screen_info(HDC _hdc, const struct options *opts, GLboolean coreProfile)
91{
92   WNDCLASS wc;
93   HWND win;
94   HGLRC ctx;
95   int visinfo;
96   HDC hdc;
97   PIXELFORMATDESCRIPTOR pfd;
98   int version;
99   const char *oglString = "OpenGL";
100
101   memset(&wc, 0, sizeof wc);
102   wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
103   wc.hCursor = LoadCursor(NULL, IDC_ARROW);
104   wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
105   wc.lpfnWndProc = WndProc;
106   wc.lpszClassName = "wglinfo";
107   wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
108   RegisterClass(&wc);
109
110   win = CreateWindowEx(0,
111                        wc.lpszClassName,
112                        "wglinfo",
113                        WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
114                        CW_USEDEFAULT,
115                        CW_USEDEFAULT,
116                        CW_USEDEFAULT,
117                        CW_USEDEFAULT,
118                        NULL,
119                        NULL,
120                        wc.hInstance,
121                        NULL);
122   if (!win) {
123      fprintf(stderr, "Couldn't create window\n");
124      return;
125   }
126
127   hdc = GetDC(win);
128   if (!hdc) {
129      fprintf(stderr, "Couldn't obtain HDC\n");
130      return;
131   }
132
133   memset(&pfd, 0, sizeof(pfd));
134   pfd.cColorBits = 3;
135   pfd.cRedBits = 1;
136   pfd.cGreenBits = 1;
137   pfd.cBlueBits = 1;
138   pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
139   pfd.iLayerType = PFD_MAIN_PLANE;
140   pfd.iPixelType = PFD_TYPE_RGBA;
141   pfd.nSize = sizeof(pfd);
142   pfd.nVersion = 1;
143
144   visinfo = ChoosePixelFormat(hdc, &pfd);
145   if (!visinfo) {
146      pfd.dwFlags |= PFD_DOUBLEBUFFER;
147      visinfo = ChoosePixelFormat(hdc, &pfd);
148   }
149
150   if (!visinfo) {
151      fprintf(stderr, "Error: couldn't find RGB WGL visual\n");
152      return;
153   }
154
155   SetPixelFormat(hdc, visinfo, &pfd);
156   ctx = wglCreateContext(hdc);
157   if (!ctx) {
158      fprintf(stderr, "Error: wglCreateContext failed\n");
159      return;
160   }
161
162   if (wglMakeCurrent(hdc, ctx)) {
163#if defined(WGL_ARB_extensions_string)
164      PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB_func =
165         (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
166#endif
167      const char *glVendor, *glRenderer, *glVersion, *glExtensions;
168      const char *wglExtensions = NULL;
169      struct ext_functions extfuncs;
170
171#if defined(WGL_ARB_extensions_string)
172      if (wglGetExtensionsStringARB_func) {
173         wglExtensions = wglGetExtensionsStringARB_func(hdc);
174         if (extension_supported("WGL_ARB_pbuffer", wglExtensions)) {
175            have_WGL_ARB_pbuffer = GL_TRUE;
176         }
177         if (extension_supported("WGL_ARB_pixel_format", wglExtensions)) {
178            have_WGL_ARB_pixel_format = GL_TRUE;
179         }
180         if (extension_supported("WGL_ARB_multisample", wglExtensions)) {
181            have_WGL_ARB_multisample = GL_TRUE;
182         }
183         if (extension_supported("WGL_ARB_create_context", wglExtensions)) {
184            have_WGL_ARB_create_context = GL_TRUE;
185         }
186         if (extension_supported("WGL_ARB_framebuffer_sRGB", wglExtensions) ||
187             extension_supported("WGL_EXT_framebuffer_sRGB", wglExtensions)) {
188            have_WGL_ARB_framebuffer_sRGB = GL_TRUE;
189         }
190      }
191#endif
192
193      if (coreProfile && have_WGL_ARB_create_context) {
194         /* Try to create a new, core context */
195         HGLRC core_ctx = 0;
196         int i;
197
198         wglCreateContextAttribsARB_func =
199            (PFNWGLCREATECONTEXTATTRIBSARBPROC)
200            wglGetProcAddress("wglCreateContextAttribsARB");
201         assert(wglCreateContextAttribsARB_func);
202         if (!wglCreateContextAttribsARB_func) {
203            printf("Failed to get wglCreateContextAttribsARB pointer.");
204            return;
205         }
206
207         for (i = 0; gl_versions[i].major > 0; i++) {
208            int attribs[10], n;
209
210            /* don't bother below GL 3.1 */
211            if (gl_versions[i].major == 3 && gl_versions[i].minor == 0) {
212               break;
213            }
214
215            n = 0;
216            attribs[n++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
217            attribs[n++] = gl_versions[i].major;
218            attribs[n++] = WGL_CONTEXT_MINOR_VERSION_ARB;
219            attribs[n++] = gl_versions[i].minor;
220            if (gl_versions[i].major * 10 + gl_versions[i].minor > 31) {
221               attribs[n++] = WGL_CONTEXT_PROFILE_MASK_ARB;
222               attribs[n++] = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
223            }
224            attribs[n++] = 0;
225
226            core_ctx = wglCreateContextAttribsARB_func(hdc, 0, attribs);
227            if (core_ctx) {
228               break;
229            }
230         }
231
232         if (!core_ctx) {
233            printf("Failed to create core profile context.\n");
234            return;
235         }
236
237         ctx = core_ctx;
238         if (!wglMakeCurrent(hdc, ctx)) {
239            printf("Failed to bind core profile context.\n");
240            return;
241         }
242         oglString = "OpenGL core profile";
243      }
244      else {
245         coreProfile = GL_FALSE;
246      }
247
248      extfuncs.GetProgramivARB = (PFNGLGETPROGRAMIVARBPROC)
249         wglGetProcAddress("glGetProgramivARB");
250      extfuncs.GetStringi = (PFNGLGETSTRINGIPROC)
251         wglGetProcAddress("glGetStringi");
252      extfuncs.GetConvolutionParameteriv = (GETCONVOLUTIONPARAMETERIVPROC)
253         wglGetProcAddress("glGetConvolutionParameteriv");
254
255      glVendor = (const char *) glGetString(GL_VENDOR);
256      glRenderer = (const char *) glGetString(GL_RENDERER);
257      glVersion = (const char *) glGetString(GL_VERSION);
258      if (coreProfile) {
259         glExtensions = build_core_profile_extension_list(&extfuncs);
260      }
261      else {
262         glExtensions = (const char *) glGetString(GL_EXTENSIONS);
263      }
264
265      /*
266       * Print all the vendor, version, extension strings.
267       */
268
269      if (!coreProfile) {
270         if (wglExtensions && opts->mode != Brief) {
271            printf("WGL extensions:\n");
272            print_extension_list(wglExtensions, opts->singleLine);
273         }
274         printf("OpenGL vendor string: %s\n", glVendor);
275         printf("OpenGL renderer string: %s\n", glRenderer);
276      }
277
278      printf("%s version string: %s\n", oglString, glVersion);
279
280      version = (glVersion[0] - '0') * 10 + (glVersion[2] - '0');
281
282#ifdef GL_VERSION_2_0
283      if (version >= 20) {
284         char *v = (char *) glGetString(GL_SHADING_LANGUAGE_VERSION);
285         printf("%s shading language version string: %s\n", oglString, v);
286      }
287#endif
288#ifdef GL_VERSION_3_0
289      if (version >= 30) {
290         GLint flags;
291         glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
292         printf("%s context flags: %s\n", oglString, context_flags_string(flags));
293      }
294#endif
295#ifdef GL_VERSION_3_2
296      if (version >= 32) {
297         GLint mask;
298         glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
299         printf("%s profile mask: %s\n", oglString, profile_mask_string(mask));
300      }
301#endif
302
303      if (opts->mode != Brief) {
304         printf("%s extensions:\n", oglString);
305         print_extension_list(glExtensions, opts->singleLine);
306      }
307
308      if (opts->limits) {
309         print_limits(glExtensions, oglString, version, &extfuncs);
310      }
311   }
312   else {
313      fprintf(stderr, "Error: wglMakeCurrent failed\n");
314   }
315
316   DestroyWindow(win);
317}
318
319
320static const char *
321visual_render_type_name(BYTE iPixelType)
322{
323   switch (iPixelType) {
324      case PFD_TYPE_RGBA:
325         return "rgba";
326      case PFD_TYPE_COLORINDEX:
327         return "ci";
328      default:
329         return "";
330   }
331}
332
333static void
334print_visual_attribs_verbose(int iPixelFormat, const struct format_info *info)
335{
336   printf("Visual ID: %x generic=%d drawToWindow=%d drawToBitmap=%d drawToPBuffer=%d GDI=%d\n",
337          iPixelFormat,
338          info->pfd.dwFlags & PFD_GENERIC_FORMAT ? 1 : 0,
339          info->pfd.dwFlags & PFD_DRAW_TO_WINDOW ? 1 : 0,
340          info->draw_to_bitmap,
341          info->draw_to_pbuffer,
342          info->gdi_drawing);
343   printf("    bufferSize=%d level=%d renderType=%s doubleBuffer=%d stereo=%d\n",
344          0 /* info->pfd.bufferSize */, 0 /* info->pfd.level */,
345	  visual_render_type_name(info->pfd.iPixelType),
346          info->pfd.dwFlags & PFD_DOUBLEBUFFER ? 1 : 0,
347          info->pfd.dwFlags & PFD_STEREO ? 1 : 0);
348   printf("    rgba: cRedBits=%d cGreenBits=%d cBlueBits=%d cAlphaBits=%d float=%c sRGB=%c\n",
349          info->pfd.cRedBits, info->pfd.cGreenBits,
350          info->pfd.cBlueBits, info->pfd.cAlphaBits,
351          info->floatComponents ? 'Y' : 'N',
352          info->srgb ? 'Y' : 'N');
353   printf("    cAuxBuffers=%d cDepthBits=%d cStencilBits=%d\n",
354          info->pfd.cAuxBuffers, info->pfd.cDepthBits, info->pfd.cStencilBits);
355   printf("    accum: cRedBits=%d cGreenBits=%d cBlueBits=%d cAlphaBits=%d\n",
356          info->pfd.cAccumRedBits, info->pfd.cAccumGreenBits,
357          info->pfd.cAccumBlueBits, info->pfd.cAccumAlphaBits);
358   printf("    multiSample=%d  multiSampleBuffers=%d\n",
359          info->numSamples, info->sampleBuffers);
360   if (info->pfd.dwFlags & PFD_SWAP_EXCHANGE)
361      printf("    swapMethod = Exchange\n");
362   else if (info->pfd.dwFlags & PFD_SWAP_COPY)
363      printf("    swapMethod = Copy\n");
364   else
365      printf("    swapMethod = Undefined\n");
366}
367
368
369static void
370print_visual_attribs_short_header(void)
371{
372   printf("    visual   x   bf lv rg d st colorbuffer   sr ax dp st accumbuffer  ms \n");
373   printf("  id gen win sp  sz l  ci b ro  r  g  b  a F gb bf th cl  r  g  b  a ns b\n");
374   printf("-------------------------------------------------------------------------\n");
375}
376
377
378static void
379print_visual_attribs_short(int iPixelFormat, const struct format_info *info)
380{
381   printf("0x%03x %2d  %2d %2d %3d %2d %c%c %c  %c %2d %2d %2d %2d %c  %c %2d %2d %2d",
382          iPixelFormat,
383          info->pfd.dwFlags & PFD_GENERIC_FORMAT ? 1 : 0,
384          info->pfd.dwFlags & PFD_DRAW_TO_WINDOW ? 1 : 0,
385          info->transparency,
386          info->pfd.cColorBits,
387          0 /* info->pfd.level */,
388          info->pfd.iPixelType == PFD_TYPE_RGBA ? 'r' : ' ',
389          info->pfd.iPixelType == PFD_TYPE_COLORINDEX ? 'c' : ' ',
390          info->pfd.dwFlags & PFD_DOUBLEBUFFER ? 'y' : '.',
391          info->pfd.dwFlags & PFD_STEREO ? 'y' : '.',
392          info->pfd.cRedBits, info->pfd.cGreenBits,
393          info->pfd.cBlueBits, info->pfd.cAlphaBits,
394          info->floatComponents ? 'f' : '.',
395          info->srgb ? 's' : '.',
396          info->pfd.cAuxBuffers,
397          info->pfd.cDepthBits,
398          info->pfd.cStencilBits
399          );
400
401   printf(" %2d %2d %2d %2d %2d %1d\n",
402          info->pfd.cAccumRedBits, info->pfd.cAccumGreenBits,
403          info->pfd.cAccumBlueBits, info->pfd.cAccumAlphaBits,
404          info->numSamples, info->sampleBuffers);
405}
406
407
408static void
409print_visual_attribs_long_header(void)
410{
411 printf("Vis   Vis   Visual Trans  buff lev render DB ste  r   g   b   a      s  aux dep ste  accum buffers  MS   MS \n");
412 printf(" ID  Depth   Type  parent size el   type     reo sz  sz  sz  sz flt rgb buf th  ncl  r   g   b   a  num bufs\n");
413 printf("------------------------------------------------------------------------------------------------------------\n");
414}
415
416
417static void
418print_visual_attribs_long(int iPixelFormat, const struct format_info *info)
419{
420   printf("0x%3x %2d %11d %2d     %2d %2d  %4s %3d %3d %3d %3d %3d %3d",
421          iPixelFormat,
422          info->pfd.dwFlags & PFD_GENERIC_FORMAT ? 1 : 0,
423          info->pfd.dwFlags & PFD_DRAW_TO_WINDOW ? 1 : 0,
424          0,
425          0 /* info->pfd.bufferSize */,
426          0 /* info->pfd.level */,
427          visual_render_type_name(info->pfd.iPixelType),
428          info->pfd.dwFlags & PFD_DOUBLEBUFFER ? 1 : 0,
429          info->pfd.dwFlags & PFD_STEREO ? 1 : 0,
430          info->pfd.cRedBits, info->pfd.cGreenBits,
431          info->pfd.cBlueBits, info->pfd.cAlphaBits
432          );
433
434   printf("  %c   %c %3d %4d %2d %3d %3d %3d %3d  %2d  %2d\n",
435          info->floatComponents ? 'f' : '.',
436          info->srgb ? 's' : '.',
437          info->pfd.cAuxBuffers,
438          info->pfd.cDepthBits,
439          info->pfd.cStencilBits,
440          info->pfd.cAccumRedBits, info->pfd.cAccumGreenBits,
441          info->pfd.cAccumBlueBits, info->pfd.cAccumAlphaBits,
442          info->sampleBuffers, info->numSamples
443          );
444}
445
446
447/**
448 * Wrapper for wglGetPixelFormatAttribivARB()
449 * \param attrib  the WGL_* attribute to query
450 * \return value of the attribute, or 0 if failure
451 */
452static int
453get_pf_attrib(HDC hdc, int pf, int attrib)
454{
455   int layer = 0, value;
456   assert(have_WGL_ARB_pixel_format);
457   if (wglGetPixelFormatAttribivARB_func(hdc, pf, layer, 1, &attrib, &value)) {
458      return value;
459   }
460   else {
461      return 0;
462   }
463}
464
465
466/**
467 * Fill in the format_info fields for the pixel format given by pf.
468 */
469static GLboolean
470get_format_info(HDC hdc, int pf, struct format_info *info)
471{
472   memset(info, 0, sizeof(*info));
473
474   if (have_WGL_ARB_pixel_format) {
475      int swapMethod;
476
477      info->pfd.dwFlags = 0;
478      if (get_pf_attrib(hdc, pf, WGL_DRAW_TO_WINDOW_ARB))
479         info->pfd.dwFlags |= PFD_DRAW_TO_WINDOW;
480      if (!get_pf_attrib(hdc, pf, WGL_ACCELERATION_ARB))
481         info->pfd.dwFlags |= PFD_GENERIC_FORMAT;
482      if (get_pf_attrib(hdc, pf, WGL_SUPPORT_OPENGL_ARB))
483         info->pfd.dwFlags |= PFD_SUPPORT_OPENGL;
484      if (get_pf_attrib(hdc, pf, WGL_DOUBLE_BUFFER_ARB))
485         info->pfd.dwFlags |= PFD_DOUBLEBUFFER;
486      if (get_pf_attrib(hdc, pf, WGL_STEREO_ARB))
487         info->pfd.dwFlags |= PFD_STEREO;
488
489      if (get_pf_attrib(hdc, pf, WGL_DRAW_TO_BITMAP_ARB))
490         info->draw_to_bitmap = true;
491      if (have_WGL_ARB_pbuffer && get_pf_attrib(hdc, pf, WGL_DRAW_TO_PBUFFER_ARB))
492         info->draw_to_pbuffer = true;
493      if (get_pf_attrib(hdc, pf, WGL_SUPPORT_GDI_ARB))
494         info->gdi_drawing = true;
495
496      swapMethod = get_pf_attrib(hdc, pf, WGL_SWAP_METHOD_ARB);
497      if (swapMethod == WGL_SWAP_EXCHANGE_ARB)
498         info->pfd.dwFlags |= PFD_SWAP_EXCHANGE;
499      else if (swapMethod == WGL_SWAP_COPY_ARB)
500         info->pfd.dwFlags |= PFD_SWAP_COPY;
501
502      int pixel_type = get_pf_attrib(hdc, pf, WGL_PIXEL_TYPE_ARB);
503      if (pixel_type == WGL_TYPE_RGBA_ARB)
504         info->pfd.iPixelType = PFD_TYPE_RGBA;
505      else if (pixel_type == WGL_TYPE_COLORINDEX_ARB)
506         info->pfd.iPixelType = PFD_TYPE_COLORINDEX;
507      else if (pixel_type == WGL_TYPE_RGBA_FLOAT_ARB) {
508         info->pfd.iPixelType = PFD_TYPE_RGBA;
509         info->floatComponents = true;
510      }
511
512      info->pfd.cColorBits = get_pf_attrib(hdc, pf, WGL_COLOR_BITS_ARB);
513      info->pfd.cRedBits = get_pf_attrib(hdc, pf, WGL_RED_BITS_ARB);
514      info->pfd.cGreenBits = get_pf_attrib(hdc, pf, WGL_GREEN_BITS_ARB);
515      info->pfd.cBlueBits = get_pf_attrib(hdc, pf, WGL_BLUE_BITS_ARB);
516      info->pfd.cAlphaBits = get_pf_attrib(hdc, pf, WGL_ALPHA_BITS_ARB);
517
518      info->pfd.cDepthBits = get_pf_attrib(hdc, pf, WGL_DEPTH_BITS_ARB);
519      info->pfd.cStencilBits = get_pf_attrib(hdc, pf, WGL_STENCIL_BITS_ARB);
520      info->pfd.cAuxBuffers = get_pf_attrib(hdc, pf, WGL_AUX_BUFFERS_ARB);
521
522      info->pfd.cAccumRedBits = get_pf_attrib(hdc, pf,
523                                              WGL_ACCUM_RED_BITS_ARB);
524      info->pfd.cAccumGreenBits = get_pf_attrib(hdc, pf,
525                                                WGL_ACCUM_GREEN_BITS_ARB);
526      info->pfd.cAccumBlueBits = get_pf_attrib(hdc, pf,
527                                               WGL_ACCUM_BLUE_BITS_ARB);
528      info->pfd.cAccumAlphaBits = get_pf_attrib(hdc, pf,
529                                                WGL_ACCUM_ALPHA_BITS_ARB);
530
531      info->sampleBuffers = get_pf_attrib(hdc, pf, WGL_SAMPLE_BUFFERS_ARB);
532      info->numSamples = get_pf_attrib(hdc, pf, WGL_SAMPLES_ARB);
533
534      info->transparency = get_pf_attrib(hdc, pf, WGL_TRANSPARENT_ARB);
535
536      if (have_WGL_ARB_framebuffer_sRGB) {
537         info->srgb = get_pf_attrib(hdc, pf, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB);
538      }
539   }
540   else {
541      if (!DescribePixelFormat(hdc, pf,
542                               sizeof(PIXELFORMATDESCRIPTOR), &info->pfd))
543         return GL_FALSE;
544   }
545   return GL_TRUE;
546}
547
548
549
550static void
551print_visual_info(HDC hdc, InfoMode mode)
552{
553   struct format_info info;
554   int numVisuals, numWglVisuals;
555   int i;
556
557   wglGetPixelFormatAttribivARB_func =
558      (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)
559      wglGetProcAddress("wglGetPixelFormatAttribivARB");
560
561   /* Get number of visuals / pixel formats */
562   numVisuals = DescribePixelFormat(hdc, 1,
563                                    sizeof(PIXELFORMATDESCRIPTOR), NULL);
564   printf("%d Regular pixel formats\n", numVisuals);
565
566   if (have_WGL_ARB_pixel_format) {
567      int numExtVisuals = get_pf_attrib(hdc, 0, WGL_NUMBER_PIXEL_FORMATS_ARB);
568      printf("%d Regular + Extended pixel formats\n", numExtVisuals);
569      numVisuals = numExtVisuals;
570   }
571
572   if (numVisuals == 0)
573      return;
574
575   numWglVisuals = 0;
576   for (i = 0; i < numVisuals; i++) {
577      if(!DescribePixelFormat(hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &info.pfd))
578	 continue;
579
580      //if(!(info.pfd.dwFlags & PFD_SUPPORT_OPENGL))
581      //   continue;
582
583      ++numWglVisuals;
584   }
585
586   printf("%d WGL Visuals\n", numWglVisuals);
587
588   if (mode == Normal)
589      print_visual_attribs_short_header();
590   else if (mode == Wide)
591      print_visual_attribs_long_header();
592
593   for (i = 0; i < numVisuals; i++) {
594      get_format_info(hdc, i, &info);
595
596      if (mode == Verbose)
597	 print_visual_attribs_verbose(i, &info);
598      else if (mode == Normal)
599         print_visual_attribs_short(i, &info);
600      else if (mode == Wide)
601         print_visual_attribs_long(i, &info);
602   }
603   printf("\n");
604}
605
606
607/*
608 * Examine all visuals to find the so-called best one.
609 * We prefer deepest RGBA buffer with depth, stencil and accum
610 * that has no caveats.
611 */
612static int
613find_best_visual(HDC hdc)
614{
615#if 0
616   XVisualInfo theTemplate;
617   XVisualInfo *visuals;
618   int numVisuals;
619   long mask;
620   int i;
621   struct visual_attribs bestVis;
622
623   /* get list of all visuals on this screen */
624   theTemplate.screen = scrnum;
625   mask = VisualScreenMask;
626   visuals = XGetVisualInfo(hdc, mask, &theTemplate, &numVisuals);
627
628   /* init bestVis with first visual info */
629   get_visual_attribs(hdc, &visuals[0], &bestVis);
630
631   /* try to find a "better" visual */
632   for (i = 1; i < numVisuals; i++) {
633      struct visual_attribs vis;
634
635      get_visual_attribs(hdc, &visuals[i], &vis);
636
637      /* always skip visuals with caveats */
638      if (vis.visualCaveat != GLX_NONE_EXT)
639         continue;
640
641      /* see if this vis is better than bestVis */
642      if ((!bestVis.supportsGL && vis.supportsGL) ||
643          (bestVis.visualCaveat != GLX_NONE_EXT) ||
644          (bestVis.iPixelType != vis.iPixelType) ||
645          (!bestVis.doubleBuffer && vis.doubleBuffer) ||
646          (bestVis.cRedBits < vis.cRedBits) ||
647          (bestVis.cGreenBits < vis.cGreenBits) ||
648          (bestVis.cBlueBits < vis.cBlueBits) ||
649          (bestVis.cAlphaBits < vis.cAlphaBits) ||
650          (bestVis.cDepthBits < vis.cDepthBits) ||
651          (bestVis.cStencilBits < vis.cStencilBits) ||
652          (bestVis.cAccumRedBits < vis.cAccumRedBits)) {
653         /* found a better visual */
654         bestVis = vis;
655      }
656   }
657
658   return bestVis.id;
659#else
660   return 0;
661#endif
662}
663
664
665
666int
667main(int argc, char *argv[])
668{
669   HDC hdc;
670   struct options opts;
671
672   parse_args(argc, argv, &opts);
673
674   hdc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
675
676   if (opts.findBest) {
677      int b;
678      b = find_best_visual(hdc);
679      printf("%d\n", b);
680   }
681   else {
682      print_screen_info(hdc, &opts, GL_FALSE);
683      printf("\n");
684      print_screen_info(hdc, &opts, GL_TRUE);
685      printf("\n");
686      if (opts.mode != Brief) {
687         print_visual_info(hdc, opts.mode);
688      }
689   }
690
691   return 0;
692}
693