1/**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
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 VMWARE 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#include "pipe/p_format.h"
29#include "pipe/p_defines.h"
30#include "pipe/p_screen.h"
31
32#include "util/u_format.h"
33#include "util/u_debug.h"
34#include "util/u_memory.h"
35
36#include "stw_icd.h"
37#include "stw_device.h"
38#include "stw_pixelformat.h"
39#include "stw_tls.h"
40
41
42struct stw_pf_color_info
43{
44   enum pipe_format format;
45   struct {
46      unsigned char red;
47      unsigned char green;
48      unsigned char blue;
49      unsigned char alpha;
50   } bits;
51   struct {
52      unsigned char red;
53      unsigned char green;
54      unsigned char blue;
55      unsigned char alpha;
56   } shift;
57};
58
59struct stw_pf_depth_info
60{
61   enum pipe_format format;
62   struct {
63      unsigned char depth;
64      unsigned char stencil;
65   } bits;
66};
67
68
69/* NOTE: order matters, since in otherwise equal circumstances the first
70 * format listed will get chosen */
71
72static const struct stw_pf_color_info
73stw_pf_color[] = {
74   /* no-alpha */
75   { PIPE_FORMAT_B8G8R8X8_UNORM,    { 8,  8,  8,  0}, {16,  8,  0,  0} },
76   { PIPE_FORMAT_X8R8G8B8_UNORM,    { 8,  8,  8,  0}, { 8, 16, 24,  0} },
77   /* alpha */
78   { PIPE_FORMAT_B8G8R8A8_UNORM,    { 8,  8,  8,  8}, {16,  8,  0, 24} },
79   { PIPE_FORMAT_A8R8G8B8_UNORM,    { 8,  8,  8,  8}, { 8, 16, 24,  0} },
80   /* shallow bit depths */
81   { PIPE_FORMAT_B5G6R5_UNORM,      { 5,  6,  5,  0}, {11,  5,  0,  0} },
82#if 0
83   { PIPE_FORMAT_R10G10B10A2_UNORM, {10, 10, 10,  2}, { 0, 10, 20, 30} },
84#endif
85   { PIPE_FORMAT_B5G5R5A1_UNORM,    { 5,  5,  5,  1}, {10,  5,  0, 15} },
86   { PIPE_FORMAT_B4G4R4A4_UNORM,    { 4,  4,  4,  4}, {16,  4,  0, 12} }
87};
88
89static const struct stw_pf_color_info
90stw_pf_color_extended[] = {
91   { PIPE_FORMAT_R32G32B32A32_FLOAT, {32, 32, 32, 32}, {0, 32, 64, 96} }
92};
93
94static const struct stw_pf_depth_info
95stw_pf_depth_stencil[] = {
96   /* pure depth */
97   { PIPE_FORMAT_Z32_UNORM,   {32, 0} },
98   { PIPE_FORMAT_X8Z24_UNORM, {24, 0} },
99   { PIPE_FORMAT_Z24X8_UNORM, {24, 0} },
100   { PIPE_FORMAT_Z16_UNORM,   {16, 0} },
101   /* combined depth-stencil */
102   { PIPE_FORMAT_Z24_UNORM_S8_UINT, {24, 8} },
103   { PIPE_FORMAT_S8_UINT_Z24_UNORM, {24, 8} }
104};
105
106
107static const boolean
108stw_pf_doublebuffer[] = {
109   FALSE,
110   TRUE,
111};
112
113
114const unsigned
115stw_pf_multisample[] = {
116   0,
117   4,
118   8,
119   16
120};
121
122
123static void
124stw_pixelformat_add(struct stw_device *stw_dev,
125                    boolean extended,
126                    const struct stw_pf_color_info *color,
127                    const struct stw_pf_depth_info *depth,
128                    unsigned accum,
129                    boolean doublebuffer,
130                    unsigned samples)
131{
132   struct stw_pixelformat_info *pfi;
133
134   assert(stw_dev->pixelformat_extended_count < STW_MAX_PIXELFORMATS);
135   if (stw_dev->pixelformat_extended_count >= STW_MAX_PIXELFORMATS)
136      return;
137
138   assert(util_format_get_component_bits(color->format, UTIL_FORMAT_COLORSPACE_RGB, 0) == color->bits.red);
139   assert(util_format_get_component_bits(color->format, UTIL_FORMAT_COLORSPACE_RGB, 1) == color->bits.green);
140   assert(util_format_get_component_bits(color->format, UTIL_FORMAT_COLORSPACE_RGB, 2) == color->bits.blue);
141   assert(util_format_get_component_bits(color->format, UTIL_FORMAT_COLORSPACE_RGB, 3) == color->bits.alpha);
142   assert(util_format_get_component_bits(depth->format, UTIL_FORMAT_COLORSPACE_ZS, 0) == depth->bits.depth);
143   assert(util_format_get_component_bits(depth->format, UTIL_FORMAT_COLORSPACE_ZS, 1) == depth->bits.stencil);
144
145   pfi = &stw_dev->pixelformats[stw_dev->pixelformat_extended_count];
146
147   memset(pfi, 0, sizeof *pfi);
148
149   pfi->pfd.nSize = sizeof pfi->pfd;
150   pfi->pfd.nVersion = 1;
151
152   pfi->pfd.dwFlags = PFD_SUPPORT_OPENGL;
153
154   /* TODO: also support non-native pixel formats */
155   if (!extended) {
156      pfi->pfd.dwFlags |= PFD_DRAW_TO_WINDOW;
157   }
158
159   /* See http://www.opengl.org/pipeline/article/vol003_7/ */
160   pfi->pfd.dwFlags |= PFD_SUPPORT_COMPOSITION;
161
162   if (doublebuffer)
163      pfi->pfd.dwFlags |= PFD_DOUBLEBUFFER | PFD_SWAP_EXCHANGE;
164
165   pfi->pfd.iPixelType = PFD_TYPE_RGBA;
166
167   pfi->pfd.cColorBits =
168      color->bits.red + color->bits.green + color->bits.blue + color->bits.alpha;
169   pfi->pfd.cRedBits = color->bits.red;
170   pfi->pfd.cRedShift = color->shift.red;
171   pfi->pfd.cGreenBits = color->bits.green;
172   pfi->pfd.cGreenShift = color->shift.green;
173   pfi->pfd.cBlueBits = color->bits.blue;
174   pfi->pfd.cBlueShift = color->shift.blue;
175   pfi->pfd.cAlphaBits = color->bits.alpha;
176   pfi->pfd.cAlphaShift = color->shift.alpha;
177   pfi->pfd.cAccumBits = 4*accum;
178   pfi->pfd.cAccumRedBits = accum;
179   pfi->pfd.cAccumGreenBits = accum;
180   pfi->pfd.cAccumBlueBits = accum;
181   pfi->pfd.cAccumAlphaBits = accum;
182   pfi->pfd.cDepthBits = depth->bits.depth;
183   pfi->pfd.cStencilBits = depth->bits.stencil;
184   pfi->pfd.cAuxBuffers = 0;
185   pfi->pfd.iLayerType = 0;
186   pfi->pfd.bReserved = 0;
187   pfi->pfd.dwLayerMask = 0;
188   pfi->pfd.dwVisibleMask = 0;
189   pfi->pfd.dwDamageMask = 0;
190
191   /*
192    * since state trackers can allocate depth/stencil/accum buffers, we provide
193    * only color buffers here
194    */
195   pfi->stvis.buffer_mask = ST_ATTACHMENT_FRONT_LEFT_MASK;
196   if (doublebuffer)
197      pfi->stvis.buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK;
198
199   pfi->stvis.color_format = color->format;
200   pfi->stvis.depth_stencil_format = depth->format;
201
202   pfi->stvis.accum_format = (accum) ?
203      PIPE_FORMAT_R16G16B16A16_SNORM : PIPE_FORMAT_NONE;
204
205   pfi->stvis.samples = samples;
206   pfi->stvis.render_buffer = ST_ATTACHMENT_INVALID;
207
208   /* WGL_ARB_render_texture */
209   if (color->bits.alpha)
210      pfi->bindToTextureRGBA = TRUE;
211
212   pfi->bindToTextureRGB = TRUE;
213
214   ++stw_dev->pixelformat_extended_count;
215
216   if (!extended) {
217      ++stw_dev->pixelformat_count;
218      assert(stw_dev->pixelformat_count == stw_dev->pixelformat_extended_count);
219   }
220}
221
222
223/**
224 * Add the depth/stencil/accum/ms variants for a list of color formats.
225 */
226static unsigned
227add_color_format_variants(const struct stw_pf_color_info *color_formats,
228                          unsigned num_color_formats, boolean extended)
229{
230   struct pipe_screen *screen = stw_dev->screen;
231   unsigned cfmt, ms, db, ds, acc;
232   unsigned bind_flags = PIPE_BIND_RENDER_TARGET;
233   unsigned num_added = 0;
234   int force_samples = 0;
235
236   /* Since GLUT for Windows doesn't support MSAA we have an env var
237    * to force all pixel formats to have a particular number of samples.
238    */
239   {
240      const char *samples= getenv("SVGA_FORCE_MSAA");
241      if (samples)
242         force_samples = atoi(samples);
243   }
244
245   if (!extended) {
246      bind_flags |= PIPE_BIND_DISPLAY_TARGET;
247   }
248
249   for (ms = 0; ms < ARRAY_SIZE(stw_pf_multisample); ms++) {
250      unsigned samples = stw_pf_multisample[ms];
251
252      if (force_samples && samples != force_samples)
253         continue;
254
255      for (cfmt = 0; cfmt < num_color_formats; cfmt++) {
256         if (!screen->is_format_supported(screen, color_formats[cfmt].format,
257                                          PIPE_TEXTURE_2D, samples, samples,
258                                          bind_flags)) {
259            continue;
260         }
261
262         for (db = 0; db < ARRAY_SIZE(stw_pf_doublebuffer); db++) {
263            unsigned doublebuffer = stw_pf_doublebuffer[db];
264
265            for (ds = 0; ds < ARRAY_SIZE(stw_pf_depth_stencil); ds++) {
266               const struct stw_pf_depth_info *depth = &stw_pf_depth_stencil[ds];
267
268               if (!screen->is_format_supported(screen, depth->format,
269                                                PIPE_TEXTURE_2D, samples,
270                                                samples,
271                                                PIPE_BIND_DEPTH_STENCIL)) {
272                  continue;
273               }
274
275               for (acc = 0; acc < 2; acc++) {
276                  stw_pixelformat_add(stw_dev, extended, &color_formats[cfmt],
277                                      depth,
278                                      acc * 16, doublebuffer, samples);
279                  num_added++;
280               }
281            }
282         }
283      }
284   }
285
286   return num_added;
287}
288
289
290void
291stw_pixelformat_init(void)
292{
293   unsigned num_formats;
294
295   assert(!stw_dev->pixelformat_count);
296   assert(!stw_dev->pixelformat_extended_count);
297
298   /* normal, displayable formats */
299   num_formats = add_color_format_variants(stw_pf_color,
300                                           ARRAY_SIZE(stw_pf_color), FALSE);
301   assert(num_formats > 0);
302
303   /* extended, pbuffer-only formats */
304   add_color_format_variants(stw_pf_color_extended,
305                             ARRAY_SIZE(stw_pf_color_extended), TRUE);
306
307   assert(stw_dev->pixelformat_count <= stw_dev->pixelformat_extended_count);
308   assert(stw_dev->pixelformat_extended_count <= STW_MAX_PIXELFORMATS);
309}
310
311
312uint
313stw_pixelformat_get_count(void)
314{
315   return stw_dev->pixelformat_count;
316}
317
318
319uint
320stw_pixelformat_get_extended_count(void)
321{
322   return stw_dev->pixelformat_extended_count;
323}
324
325
326const struct stw_pixelformat_info *
327stw_pixelformat_get_info(int iPixelFormat)
328{
329   unsigned index;
330
331   if (iPixelFormat <= 0) {
332      return NULL;
333   }
334
335   index = iPixelFormat - 1;
336   if (index >= stw_dev->pixelformat_extended_count) {
337      return NULL;
338   }
339
340   return &stw_dev->pixelformats[index];
341}
342
343
344LONG APIENTRY
345DrvDescribePixelFormat(HDC hdc, INT iPixelFormat, ULONG cjpfd,
346                       PIXELFORMATDESCRIPTOR *ppfd)
347{
348   uint count;
349   const struct stw_pixelformat_info *pfi;
350
351   (void) hdc;
352
353   if (!stw_dev)
354      return 0;
355
356   count = stw_pixelformat_get_count();
357
358   if (ppfd == NULL)
359      return count;
360
361   if (cjpfd != sizeof(PIXELFORMATDESCRIPTOR))
362      return 0;
363
364   pfi = stw_pixelformat_get_info(iPixelFormat);
365   if (!pfi) {
366      return 0;
367   }
368
369   memcpy(ppfd, &pfi->pfd, sizeof(PIXELFORMATDESCRIPTOR));
370
371   return count;
372}
373
374
375BOOL APIENTRY
376DrvDescribeLayerPlane(HDC hdc, INT iPixelFormat, INT iLayerPlane,
377                      UINT nBytes, LPLAYERPLANEDESCRIPTOR plpd)
378{
379   assert(0);
380   return FALSE;
381}
382
383
384int APIENTRY
385DrvGetLayerPaletteEntries(HDC hdc, INT iLayerPlane, INT iStart,
386                          INT cEntries, COLORREF *pcr)
387{
388   assert(0);
389   return 0;
390}
391
392
393int APIENTRY
394DrvSetLayerPaletteEntries(HDC hdc, INT iLayerPlane, INT iStart,
395                          INT cEntries, CONST COLORREF *pcr)
396{
397   assert(0);
398   return 0;
399}
400
401
402BOOL APIENTRY
403DrvRealizeLayerPalette(HDC hdc, INT iLayerPlane, BOOL bRealize)
404{
405   assert(0);
406   return FALSE;
407}
408
409
410/* Only used by the wgl code, but have it here to avoid exporting the
411 * pixelformat.h functionality.
412 */
413int
414stw_pixelformat_choose(HDC hdc, CONST PIXELFORMATDESCRIPTOR *ppfd)
415{
416   uint count;
417   uint index;
418   uint bestindex;
419   uint bestdelta;
420
421   (void) hdc;
422
423   count = stw_pixelformat_get_extended_count();
424   bestindex = 0;
425   bestdelta = ~0U;
426
427   for (index = 1; index <= count; index++) {
428      uint delta = 0;
429      const struct stw_pixelformat_info *pfi = stw_pixelformat_get_info(index);
430
431      if (!(ppfd->dwFlags & PFD_DOUBLEBUFFER_DONTCARE) &&
432          !!(ppfd->dwFlags & PFD_DOUBLEBUFFER) !=
433          !!(pfi->pfd.dwFlags & PFD_DOUBLEBUFFER))
434         continue;
435
436      /* Selection logic:
437      * - Enabling a feature (depth, stencil...) is given highest priority.
438      * - Giving as many bits as requested is given medium priority.
439      * - Giving no more bits than requested is given lowest priority.
440      */
441
442      /* FIXME: Take in account individual channel bits */
443      if (ppfd->cColorBits && !pfi->pfd.cColorBits)
444         delta += 10000;
445      else if (ppfd->cColorBits > pfi->pfd.cColorBits)
446         delta += 100;
447      else if (ppfd->cColorBits < pfi->pfd.cColorBits)
448         delta++;
449
450      if (ppfd->cDepthBits && !pfi->pfd.cDepthBits)
451         delta += 10000;
452      else if (ppfd->cDepthBits > pfi->pfd.cDepthBits)
453         delta += 200;
454      else if (ppfd->cDepthBits < pfi->pfd.cDepthBits)
455         delta += 2;
456
457      if (ppfd->cStencilBits && !pfi->pfd.cStencilBits)
458         delta += 10000;
459      else if (ppfd->cStencilBits > pfi->pfd.cStencilBits)
460         delta += 400;
461      else if (ppfd->cStencilBits < pfi->pfd.cStencilBits)
462         delta++;
463
464      if (ppfd->cAlphaBits && !pfi->pfd.cAlphaBits)
465         delta += 10000;
466      else if (ppfd->cAlphaBits > pfi->pfd.cAlphaBits)
467         delta += 100;
468      else if (ppfd->cAlphaBits < pfi->pfd.cAlphaBits)
469         delta++;
470
471      if (delta < bestdelta) {
472         bestindex = index;
473         bestdelta = delta;
474         if (bestdelta == 0)
475            break;
476      }
477   }
478
479   return bestindex;
480}
481