1/**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
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
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28/**
29 * @file
30 *
31 * WGL_ARB_pixel_format extension implementation.
32 *
33 * @sa http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt
34 */
35
36
37#include <windows.h>
38
39#define WGL_WGLEXT_PROTOTYPES
40
41#include <GL/gl.h>
42#include <GL/wglext.h>
43
44#include "pipe/p_compiler.h"
45#include "util/u_format.h"
46#include "util/u_memory.h"
47#include "stw_device.h"
48#include "stw_pixelformat.h"
49
50
51static boolean
52stw_query_attrib(
53   int iPixelFormat,
54   int iLayerPlane,
55   int attrib,
56   int *pvalue )
57{
58   uint count;
59   const struct stw_pixelformat_info *pfi;
60
61   count = stw_pixelformat_get_extended_count();
62
63   if (attrib == WGL_NUMBER_PIXEL_FORMATS_ARB) {
64      *pvalue = (int) count;
65      return TRUE;
66   }
67
68   pfi = stw_pixelformat_get_info( iPixelFormat );
69   if (!pfi) {
70      return FALSE;
71   }
72
73   switch (attrib) {
74   case WGL_DRAW_TO_WINDOW_ARB:
75      *pvalue = pfi->pfd.dwFlags & PFD_DRAW_TO_WINDOW ? TRUE : FALSE;
76      return TRUE;
77
78   case WGL_DRAW_TO_BITMAP_ARB:
79      *pvalue = pfi->pfd.dwFlags & PFD_DRAW_TO_BITMAP ? TRUE : FALSE;
80      return TRUE;
81
82   case WGL_NEED_PALETTE_ARB:
83      *pvalue = pfi->pfd.dwFlags & PFD_NEED_PALETTE ? TRUE : FALSE;
84      return TRUE;
85
86   case WGL_NEED_SYSTEM_PALETTE_ARB:
87      *pvalue = pfi->pfd.dwFlags & PFD_NEED_SYSTEM_PALETTE ? TRUE : FALSE;
88      return TRUE;
89
90   case WGL_SWAP_METHOD_ARB:
91      *pvalue = pfi->pfd.dwFlags & PFD_SWAP_COPY ? WGL_SWAP_COPY_ARB : WGL_SWAP_UNDEFINED_ARB;
92      return TRUE;
93
94   case WGL_SWAP_LAYER_BUFFERS_ARB:
95      *pvalue = FALSE;
96      return TRUE;
97
98   case WGL_NUMBER_OVERLAYS_ARB:
99      *pvalue = 0;
100      return TRUE;
101
102   case WGL_NUMBER_UNDERLAYS_ARB:
103      *pvalue = 0;
104      return TRUE;
105   }
106
107   if (iLayerPlane != 0)
108      return FALSE;
109
110   switch (attrib) {
111   case WGL_ACCELERATION_ARB:
112      *pvalue = WGL_FULL_ACCELERATION_ARB;
113      break;
114
115   case WGL_TRANSPARENT_ARB:
116      *pvalue = FALSE;
117      break;
118
119   case WGL_TRANSPARENT_RED_VALUE_ARB:
120   case WGL_TRANSPARENT_GREEN_VALUE_ARB:
121   case WGL_TRANSPARENT_BLUE_VALUE_ARB:
122   case WGL_TRANSPARENT_ALPHA_VALUE_ARB:
123   case WGL_TRANSPARENT_INDEX_VALUE_ARB:
124      break;
125
126   case WGL_SHARE_DEPTH_ARB:
127   case WGL_SHARE_STENCIL_ARB:
128   case WGL_SHARE_ACCUM_ARB:
129      *pvalue = TRUE;
130      break;
131
132   case WGL_SUPPORT_GDI_ARB:
133      *pvalue = pfi->pfd.dwFlags & PFD_SUPPORT_GDI ? TRUE : FALSE;
134      break;
135
136   case WGL_SUPPORT_OPENGL_ARB:
137      *pvalue = pfi->pfd.dwFlags & PFD_SUPPORT_OPENGL ? TRUE : FALSE;
138      break;
139
140   case WGL_DOUBLE_BUFFER_ARB:
141      *pvalue = pfi->pfd.dwFlags & PFD_DOUBLEBUFFER ? TRUE : FALSE;
142      break;
143
144   case WGL_STEREO_ARB:
145      *pvalue = pfi->pfd.dwFlags & PFD_STEREO ? TRUE : FALSE;
146      break;
147
148   case WGL_PIXEL_TYPE_ARB:
149      switch (pfi->pfd.iPixelType) {
150      case PFD_TYPE_RGBA:
151         if (util_format_is_float(pfi->stvis.color_format)) {
152            *pvalue = WGL_TYPE_RGBA_FLOAT_ARB;
153         }
154         else {
155            *pvalue = WGL_TYPE_RGBA_ARB;
156         }
157         break;
158      case PFD_TYPE_COLORINDEX:
159         *pvalue = WGL_TYPE_COLORINDEX_ARB;
160         break;
161      default:
162         return FALSE;
163      }
164      break;
165
166   case WGL_COLOR_BITS_ARB:
167      *pvalue = pfi->pfd.cColorBits;
168      break;
169
170   case WGL_RED_BITS_ARB:
171      *pvalue = pfi->pfd.cRedBits;
172      break;
173
174   case WGL_RED_SHIFT_ARB:
175      *pvalue = pfi->pfd.cRedShift;
176      break;
177
178   case WGL_GREEN_BITS_ARB:
179      *pvalue = pfi->pfd.cGreenBits;
180      break;
181
182   case WGL_GREEN_SHIFT_ARB:
183      *pvalue = pfi->pfd.cGreenShift;
184      break;
185
186   case WGL_BLUE_BITS_ARB:
187      *pvalue = pfi->pfd.cBlueBits;
188      break;
189
190   case WGL_BLUE_SHIFT_ARB:
191      *pvalue = pfi->pfd.cBlueShift;
192      break;
193
194   case WGL_ALPHA_BITS_ARB:
195      *pvalue = pfi->pfd.cAlphaBits;
196      break;
197
198   case WGL_ALPHA_SHIFT_ARB:
199      *pvalue = pfi->pfd.cAlphaShift;
200      break;
201
202   case WGL_ACCUM_BITS_ARB:
203      *pvalue = pfi->pfd.cAccumBits;
204      break;
205
206   case WGL_ACCUM_RED_BITS_ARB:
207      *pvalue = pfi->pfd.cAccumRedBits;
208      break;
209
210   case WGL_ACCUM_GREEN_BITS_ARB:
211      *pvalue = pfi->pfd.cAccumGreenBits;
212      break;
213
214   case WGL_ACCUM_BLUE_BITS_ARB:
215      *pvalue = pfi->pfd.cAccumBlueBits;
216      break;
217
218   case WGL_ACCUM_ALPHA_BITS_ARB:
219      *pvalue = pfi->pfd.cAccumAlphaBits;
220      break;
221
222   case WGL_DEPTH_BITS_ARB:
223      *pvalue = pfi->pfd.cDepthBits;
224      break;
225
226   case WGL_STENCIL_BITS_ARB:
227      *pvalue = pfi->pfd.cStencilBits;
228      break;
229
230   case WGL_AUX_BUFFERS_ARB:
231      *pvalue = pfi->pfd.cAuxBuffers;
232      break;
233
234   case WGL_SAMPLE_BUFFERS_ARB:
235      *pvalue = 1;
236      break;
237
238   case WGL_SAMPLES_ARB:
239      *pvalue = pfi->stvis.samples;
240      break;
241
242
243   /* WGL_ARB_pbuffer */
244
245   case WGL_MAX_PBUFFER_WIDTH_ARB:
246   case WGL_MAX_PBUFFER_HEIGHT_ARB:
247      *pvalue = stw_dev->max_2d_length;
248      break;
249
250   case WGL_MAX_PBUFFER_PIXELS_ARB:
251      *pvalue = stw_dev->max_2d_length * stw_dev->max_2d_length;
252      break;
253
254   case WGL_DRAW_TO_PBUFFER_ARB:
255      *pvalue = 1;
256      break;
257
258
259   default:
260      return FALSE;
261   }
262
263   return TRUE;
264}
265
266struct attrib_match_info
267{
268   int attribute;
269   int weight;
270   BOOL exact;
271};
272
273static const struct attrib_match_info attrib_match[] = {
274
275   /* WGL_ARB_pixel_format */
276   { WGL_DRAW_TO_WINDOW_ARB,      0, TRUE },
277   { WGL_DRAW_TO_BITMAP_ARB,      0, TRUE },
278   { WGL_ACCELERATION_ARB,        0, TRUE },
279   { WGL_NEED_PALETTE_ARB,        0, TRUE },
280   { WGL_NEED_SYSTEM_PALETTE_ARB, 0, TRUE },
281   { WGL_SWAP_LAYER_BUFFERS_ARB,  0, TRUE },
282   { WGL_SWAP_METHOD_ARB,         0, TRUE },
283   { WGL_NUMBER_OVERLAYS_ARB,     4, FALSE },
284   { WGL_NUMBER_UNDERLAYS_ARB,    4, FALSE },
285   /*{ WGL_SHARE_DEPTH_ARB,         0, TRUE },*/     /* no overlays -- ignore */
286   /*{ WGL_SHARE_STENCIL_ARB,       0, TRUE },*/   /* no overlays -- ignore */
287   /*{ WGL_SHARE_ACCUM_ARB,         0, TRUE },*/     /* no overlays -- ignore */
288   { WGL_SUPPORT_GDI_ARB,         0, TRUE },
289   { WGL_SUPPORT_OPENGL_ARB,      0, TRUE },
290   { WGL_DOUBLE_BUFFER_ARB,       0, TRUE },
291   { WGL_STEREO_ARB,              0, TRUE },
292   { WGL_PIXEL_TYPE_ARB,          0, TRUE },
293   { WGL_COLOR_BITS_ARB,          1, FALSE },
294   { WGL_RED_BITS_ARB,            1, FALSE },
295   { WGL_GREEN_BITS_ARB,          1, FALSE },
296   { WGL_BLUE_BITS_ARB,           1, FALSE },
297   { WGL_ALPHA_BITS_ARB,          1, FALSE },
298   { WGL_ACCUM_BITS_ARB,          1, FALSE },
299   { WGL_ACCUM_RED_BITS_ARB,      1, FALSE },
300   { WGL_ACCUM_GREEN_BITS_ARB,    1, FALSE },
301   { WGL_ACCUM_BLUE_BITS_ARB,     1, FALSE },
302   { WGL_ACCUM_ALPHA_BITS_ARB,    1, FALSE },
303   { WGL_DEPTH_BITS_ARB,          1, FALSE },
304   { WGL_STENCIL_BITS_ARB,        1, FALSE },
305   { WGL_AUX_BUFFERS_ARB,         2, FALSE },
306
307   /* WGL_ARB_multisample */
308   { WGL_SAMPLE_BUFFERS_ARB,      2, FALSE },
309   { WGL_SAMPLES_ARB,             2, FALSE }
310};
311
312struct stw_pixelformat_score
313{
314   int points;
315   uint index;
316};
317
318static BOOL
319score_pixelformats(
320   struct stw_pixelformat_score *scores,
321   uint count,
322   int attribute,
323   int expected_value )
324{
325   uint i;
326   const struct attrib_match_info *ami = NULL;
327   uint index;
328
329   /* Find out if a given attribute should be considered for score calculation.
330    */
331   for (i = 0; i < sizeof( attrib_match ) / sizeof( attrib_match[0] ); i++) {
332      if (attrib_match[i].attribute == attribute) {
333         ami = &attrib_match[i];
334         break;
335      }
336   }
337   if (ami == NULL)
338      return TRUE;
339
340   /* Iterate all pixelformats, query the requested attribute and calculate
341    * score points.
342    */
343   for (index = 0; index < count; index++) {
344      int actual_value;
345
346      if (!stw_query_attrib( index + 1, 0, attribute, &actual_value ))
347         return FALSE;
348
349      if (ami->exact) {
350         /* For an exact match criteria, if the actual and expected values differ,
351          * the score is set to 0 points, effectively removing the pixelformat
352          * from a list of matching pixelformats.
353          */
354         if (actual_value != expected_value)
355            scores[index].points = 0;
356      }
357      else {
358         /* For a minimum match criteria, if the actual value is smaller than the expected
359          * value, the pixelformat is rejected (score set to 0). However, if the actual
360          * value is bigger, the pixelformat is given a penalty to favour pixelformats that
361          * more closely match the expected values.
362          */
363         if (actual_value < expected_value)
364            scores[index].points = 0;
365         else if (actual_value > expected_value)
366            scores[index].points -= (actual_value - expected_value) * ami->weight;
367      }
368   }
369
370   return TRUE;
371}
372
373WINGDIAPI BOOL APIENTRY
374wglChoosePixelFormatARB(
375   HDC hdc,
376   const int *piAttribIList,
377   const FLOAT *pfAttribFList,
378   UINT nMaxFormats,
379   int *piFormats,
380   UINT *nNumFormats )
381{
382   uint count;
383   struct stw_pixelformat_score *scores;
384   uint i;
385
386   *nNumFormats = 0;
387
388   /* Allocate and initialize pixelformat score table -- better matches
389    * have higher scores. Start with a high score and take out penalty
390    * points for a mismatch when the match does not have to be exact.
391    * Set a score to 0 if there is a mismatch for an exact match criteria.
392    */
393   count = stw_pixelformat_get_extended_count();
394   scores = (struct stw_pixelformat_score *) MALLOC( count * sizeof( struct stw_pixelformat_score ) );
395   if (scores == NULL)
396      return FALSE;
397   for (i = 0; i < count; i++) {
398      scores[i].points = 0x7fffffff;
399      scores[i].index = i;
400   }
401
402   /* Given the attribute list calculate a score for each pixelformat.
403    */
404   if (piAttribIList != NULL) {
405      while (*piAttribIList != 0) {
406         if (!score_pixelformats( scores, count, piAttribIList[0], piAttribIList[1] )) {
407            FREE( scores );
408            return FALSE;
409         }
410         piAttribIList += 2;
411      }
412   }
413   if (pfAttribFList != NULL) {
414      while (*pfAttribFList != 0) {
415         if (!score_pixelformats( scores, count, (int) pfAttribFList[0], (int) pfAttribFList[1] )) {
416            FREE( scores );
417            return FALSE;
418         }
419         pfAttribFList += 2;
420      }
421   }
422
423   /* Bubble-sort the resulting scores. Pixelformats with higher scores go first.
424    * TODO: Find out if there are any patent issues with it.
425    */
426   if (count > 1) {
427      uint n = count;
428      boolean swapped;
429
430      do {
431         swapped = FALSE;
432         for (i = 1; i < n; i++) {
433            if (scores[i - 1].points < scores[i].points) {
434               struct stw_pixelformat_score score = scores[i - 1];
435
436               scores[i - 1] = scores[i];
437               scores[i] = score;
438               swapped = TRUE;
439            }
440         }
441         n--;
442      }
443      while (swapped);
444   }
445
446   /* Return a list of pixelformats that are the best match.
447    * Reject pixelformats with non-positive scores.
448    */
449   for (i = 0; i < count; i++) {
450      if (scores[i].points > 0) {
451         if (*nNumFormats < nMaxFormats)
452            piFormats[*nNumFormats] = scores[i].index + 1;
453         (*nNumFormats)++;
454      }
455   }
456
457   FREE( scores );
458   return TRUE;
459}
460
461WINGDIAPI BOOL APIENTRY
462wglGetPixelFormatAttribfvARB(
463   HDC hdc,
464   int iPixelFormat,
465   int iLayerPlane,
466   UINT nAttributes,
467   const int *piAttributes,
468   FLOAT *pfValues )
469{
470   UINT i;
471
472   (void) hdc;
473
474   for (i = 0; i < nAttributes; i++) {
475      int value;
476
477      if (!stw_query_attrib( iPixelFormat, iLayerPlane, piAttributes[i], &value ))
478         return FALSE;
479      pfValues[i] = (FLOAT) value;
480   }
481
482   return TRUE;
483}
484
485WINGDIAPI BOOL APIENTRY
486wglGetPixelFormatAttribivARB(
487   HDC hdc,
488   int iPixelFormat,
489   int iLayerPlane,
490   UINT nAttributes,
491   const int *piAttributes,
492   int *piValues )
493{
494   UINT i;
495
496   (void) hdc;
497
498   for (i = 0; i < nAttributes; i++) {
499      if (!stw_query_attrib( iPixelFormat, iLayerPlane, piAttributes[i], &piValues[i] ))
500         return FALSE;
501   }
502
503   return TRUE;
504}
505