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#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   { PIPE_FORMAT_B5G6R5_UNORM,      { 5,  6,  5,  0}, {11,  5,  0,  0} },
78   /* alpha */
79   { PIPE_FORMAT_B8G8R8A8_UNORM,    { 8,  8,  8,  8}, {16,  8,  0, 24} },
80   { PIPE_FORMAT_A8R8G8B8_UNORM,    { 8,  8,  8,  8}, { 8, 16, 24,  0} },
81#if 0
82   { PIPE_FORMAT_R10G10B10A2_UNORM, {10, 10, 10,  2}, { 0, 10, 20, 30} },
83#endif
84   { PIPE_FORMAT_B5G5R5A1_UNORM,    { 5,  5,  5,  1}, {10,  5,  0, 15} },
85   { PIPE_FORMAT_B4G4R4A4_UNORM,    { 4,  4,  4,  4}, {16,  4,  0, 12} }
86};
87
88static const struct stw_pf_color_info
89stw_pf_color_extended[] = {
90    { PIPE_FORMAT_R32G32B32A32_FLOAT, { 32,  32, 32,  32}, { 0,  32, 64, 96} }
91};
92
93static const struct stw_pf_depth_info
94stw_pf_depth_stencil[] = {
95   /* pure depth */
96   { PIPE_FORMAT_Z32_UNORM,   {32, 0} },
97   { PIPE_FORMAT_X8Z24_UNORM, {24, 0} },
98   { PIPE_FORMAT_Z24X8_UNORM, {24, 0} },
99   { PIPE_FORMAT_Z16_UNORM,   {16, 0} },
100   /* combined depth-stencil */
101   { PIPE_FORMAT_Z24_UNORM_S8_UINT, {24, 8} },
102   { PIPE_FORMAT_S8_UINT_Z24_UNORM, {24, 8} }
103};
104
105
106static const boolean
107stw_pf_doublebuffer[] = {
108   FALSE,
109   TRUE,
110};
111
112
113const unsigned
114stw_pf_multisample[] = {
115   0,
116   4
117};
118
119
120static void
121stw_pixelformat_add(
122   struct stw_device *stw_dev,
123   boolean extended,
124   const struct stw_pf_color_info *color,
125   const struct stw_pf_depth_info *depth,
126   unsigned accum,
127   boolean doublebuffer,
128   unsigned samples )
129{
130   struct stw_pixelformat_info *pfi;
131
132   assert(stw_dev->pixelformat_extended_count < STW_MAX_PIXELFORMATS);
133   if(stw_dev->pixelformat_extended_count >= STW_MAX_PIXELFORMATS)
134      return;
135
136   assert(util_format_get_component_bits(color->format, UTIL_FORMAT_COLORSPACE_RGB, 0) == color->bits.red);
137   assert(util_format_get_component_bits(color->format, UTIL_FORMAT_COLORSPACE_RGB, 1) == color->bits.green);
138   assert(util_format_get_component_bits(color->format, UTIL_FORMAT_COLORSPACE_RGB, 2) == color->bits.blue);
139   assert(util_format_get_component_bits(color->format, UTIL_FORMAT_COLORSPACE_RGB, 3) == color->bits.alpha);
140   assert(util_format_get_component_bits(depth->format, UTIL_FORMAT_COLORSPACE_ZS, 0) == depth->bits.depth);
141   assert(util_format_get_component_bits(depth->format, UTIL_FORMAT_COLORSPACE_ZS, 1) == depth->bits.stencil);
142
143   pfi = &stw_dev->pixelformats[stw_dev->pixelformat_extended_count];
144
145   memset(pfi, 0, sizeof *pfi);
146
147   pfi->pfd.nSize = sizeof pfi->pfd;
148   pfi->pfd.nVersion = 1;
149
150   pfi->pfd.dwFlags = PFD_SUPPORT_OPENGL;
151
152   /* TODO: also support non-native pixel formats */
153   if (!extended) {
154      pfi->pfd.dwFlags |= PFD_DRAW_TO_WINDOW;
155   }
156
157   /* See http://www.opengl.org/pipeline/article/vol003_7/ */
158   pfi->pfd.dwFlags |= PFD_SUPPORT_COMPOSITION;
159
160   if (doublebuffer)
161      pfi->pfd.dwFlags |= PFD_DOUBLEBUFFER | PFD_SWAP_COPY;
162
163   pfi->pfd.iPixelType = PFD_TYPE_RGBA;
164
165   pfi->pfd.cColorBits = color->bits.red + color->bits.green + color->bits.blue + color->bits.alpha;
166   pfi->pfd.cRedBits = color->bits.red;
167   pfi->pfd.cRedShift = color->shift.red;
168   pfi->pfd.cGreenBits = color->bits.green;
169   pfi->pfd.cGreenShift = color->shift.green;
170   pfi->pfd.cBlueBits = color->bits.blue;
171   pfi->pfd.cBlueShift = color->shift.blue;
172   pfi->pfd.cAlphaBits = color->bits.alpha;
173   pfi->pfd.cAlphaShift = color->shift.alpha;
174   pfi->pfd.cAccumBits = 4*accum;
175   pfi->pfd.cAccumRedBits = accum;
176   pfi->pfd.cAccumGreenBits = accum;
177   pfi->pfd.cAccumBlueBits = accum;
178   pfi->pfd.cAccumAlphaBits = accum;
179   pfi->pfd.cDepthBits = depth->bits.depth;
180   pfi->pfd.cStencilBits = depth->bits.stencil;
181   pfi->pfd.cAuxBuffers = 0;
182   pfi->pfd.iLayerType = 0;
183   pfi->pfd.bReserved = 0;
184   pfi->pfd.dwLayerMask = 0;
185   pfi->pfd.dwVisibleMask = 0;
186   pfi->pfd.dwDamageMask = 0;
187
188   /*
189    * since state trackers can allocate depth/stencil/accum buffers, we provide
190    * only color buffers here
191    */
192   pfi->stvis.buffer_mask = ST_ATTACHMENT_FRONT_LEFT_MASK;
193   if (doublebuffer)
194      pfi->stvis.buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK;
195
196   pfi->stvis.color_format = color->format;
197   pfi->stvis.depth_stencil_format = depth->format;
198
199   pfi->stvis.accum_format = (accum) ?
200      PIPE_FORMAT_R16G16B16A16_SNORM : PIPE_FORMAT_NONE;
201
202   pfi->stvis.samples = samples;
203   pfi->stvis.render_buffer = ST_ATTACHMENT_INVALID;
204
205   ++stw_dev->pixelformat_extended_count;
206
207   if(!extended) {
208      ++stw_dev->pixelformat_count;
209      assert(stw_dev->pixelformat_count == stw_dev->pixelformat_extended_count);
210   }
211}
212
213
214/**
215 * Add the depth/stencil/accum/ms variants for a particular color format.
216 */
217static void
218add_color_format_variants(const struct stw_pf_color_info *color,
219                          boolean extended)
220{
221   struct pipe_screen *screen = stw_dev->screen;
222   unsigned ms, db, ds, acc;
223   unsigned bind_flags = PIPE_BIND_RENDER_TARGET;
224
225   if (!extended) {
226      bind_flags |= PIPE_BIND_DISPLAY_TARGET;
227   }
228
229   if (!screen->is_format_supported(screen, color->format,
230                                    PIPE_TEXTURE_2D, 0, bind_flags)) {
231      return;
232   }
233
234   for (ms = 0; ms < Elements(stw_pf_multisample); ms++) {
235      unsigned samples = stw_pf_multisample[ms];
236
237      /* FIXME: re-enabled MSAA when we can query it */
238      if (samples)
239         continue;
240
241      for (db = 0; db < Elements(stw_pf_doublebuffer); db++) {
242         unsigned doublebuffer = stw_pf_doublebuffer[db];
243
244         for (ds = 0; ds < Elements(stw_pf_depth_stencil); ds++) {
245            const struct stw_pf_depth_info *depth = &stw_pf_depth_stencil[ds];
246
247            if (!screen->is_format_supported(screen, depth->format,
248                                             PIPE_TEXTURE_2D, 0,
249                                             PIPE_BIND_DEPTH_STENCIL)) {
250               continue;
251            }
252
253            for (acc = 0; acc < 2; acc++) {
254               stw_pixelformat_add(stw_dev, extended, color, depth,
255                                   acc * 16, doublebuffer, samples);
256            }
257         }
258      }
259   }
260}
261
262
263void
264stw_pixelformat_init( void )
265{
266   unsigned i;
267
268   assert( !stw_dev->pixelformat_count );
269   assert( !stw_dev->pixelformat_extended_count );
270
271   /* normal, displayable formats */
272   for (i = 0; i < Elements(stw_pf_color); i++) {
273      add_color_format_variants(&stw_pf_color[i], FALSE);
274   }
275
276   /* extended, pbuffer-only formats */
277   for (i = 0; i < Elements(stw_pf_color_extended); i++) {
278      add_color_format_variants(&stw_pf_color_extended[i], TRUE);
279   }
280
281   assert( stw_dev->pixelformat_count <= stw_dev->pixelformat_extended_count );
282   assert( stw_dev->pixelformat_extended_count <= STW_MAX_PIXELFORMATS );
283}
284
285uint
286stw_pixelformat_get_count( void )
287{
288   return stw_dev->pixelformat_count;
289}
290
291uint
292stw_pixelformat_get_extended_count( void )
293{
294   return stw_dev->pixelformat_extended_count;
295}
296
297const struct stw_pixelformat_info *
298stw_pixelformat_get_info( int iPixelFormat )
299{
300   int index;
301
302   if (iPixelFormat <= 0) {
303      return NULL;
304   }
305
306   index = iPixelFormat - 1;
307   if (index >= stw_dev->pixelformat_extended_count) {
308      return NULL;
309   }
310
311   return &stw_dev->pixelformats[index];
312}
313
314
315LONG APIENTRY
316DrvDescribePixelFormat(
317   HDC hdc,
318   INT iPixelFormat,
319   ULONG cjpfd,
320   PIXELFORMATDESCRIPTOR *ppfd )
321{
322   uint count;
323   const struct stw_pixelformat_info *pfi;
324
325   (void) hdc;
326
327   if (!stw_dev)
328      return 0;
329
330   count = stw_pixelformat_get_count();
331
332   if (ppfd == NULL)
333      return count;
334   if (cjpfd != sizeof( PIXELFORMATDESCRIPTOR ))
335      return 0;
336
337   pfi = stw_pixelformat_get_info( iPixelFormat );
338   if (!pfi) {
339      return 0;
340   }
341
342   memcpy(ppfd, &pfi->pfd, sizeof( PIXELFORMATDESCRIPTOR ));
343
344   return count;
345}
346
347BOOL APIENTRY
348DrvDescribeLayerPlane(
349   HDC hdc,
350   INT iPixelFormat,
351   INT iLayerPlane,
352   UINT nBytes,
353   LPLAYERPLANEDESCRIPTOR plpd )
354{
355   assert(0);
356   return FALSE;
357}
358
359int APIENTRY
360DrvGetLayerPaletteEntries(
361   HDC hdc,
362   INT iLayerPlane,
363   INT iStart,
364   INT cEntries,
365   COLORREF *pcr )
366{
367   assert(0);
368   return 0;
369}
370
371int APIENTRY
372DrvSetLayerPaletteEntries(
373   HDC hdc,
374   INT iLayerPlane,
375   INT iStart,
376   INT cEntries,
377   CONST COLORREF *pcr )
378{
379   assert(0);
380   return 0;
381}
382
383BOOL APIENTRY
384DrvRealizeLayerPalette(
385   HDC hdc,
386   INT iLayerPlane,
387   BOOL bRealize )
388{
389   assert(0);
390   return FALSE;
391}
392
393/* Only used by the wgl code, but have it here to avoid exporting the
394 * pixelformat.h functionality.
395 */
396int stw_pixelformat_choose( HDC hdc,
397                            CONST PIXELFORMATDESCRIPTOR *ppfd )
398{
399   uint count;
400   uint index;
401   uint bestindex;
402   uint bestdelta;
403
404   (void) hdc;
405
406   count = stw_pixelformat_get_extended_count();
407   bestindex = 0;
408   bestdelta = ~0U;
409
410   for (index = 1; index <= count; index++) {
411      uint delta = 0;
412      const struct stw_pixelformat_info *pfi = stw_pixelformat_get_info( index );
413
414      if (!(ppfd->dwFlags & PFD_DOUBLEBUFFER_DONTCARE) &&
415          !!(ppfd->dwFlags & PFD_DOUBLEBUFFER) !=
416          !!(pfi->pfd.dwFlags & PFD_DOUBLEBUFFER))
417         continue;
418
419      /* FIXME: Take in account individual channel bits */
420      if (ppfd->cColorBits != pfi->pfd.cColorBits)
421         delta += 8;
422
423      if (ppfd->cDepthBits != pfi->pfd.cDepthBits)
424         delta += 4;
425
426      if (ppfd->cStencilBits != pfi->pfd.cStencilBits)
427         delta += 2;
428
429      if (ppfd->cAlphaBits != pfi->pfd.cAlphaBits)
430         delta++;
431
432      if (delta < bestdelta) {
433         bestindex = index;
434         bestdelta = delta;
435         if (bestdelta == 0)
436            break;
437      }
438   }
439
440   return bestindex;
441}
442