1/*
2 * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
3 * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice including the dates of first publication and
13 * either this permission notice or a reference to
14 * http://oss.sgi.com/projects/FreeB/
15 * shall be included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
22 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 * Except as contained in this notice, the name of Silicon Graphics, Inc.
26 * shall not be used in advertising or otherwise to promote the sale, use or
27 * other dealings in this Software without prior written authorization from
28 * Silicon Graphics, Inc.
29 */
30
31#ifdef HAVE_DIX_CONFIG_H
32#include <dix-config.h>
33#endif
34
35#include <GL/glxtokens.h>
36#include <string.h>
37#include <windowstr.h>
38#include <os.h>
39#include <colormapst.h>
40
41#include "extinit.h"
42#include "privates.h"
43#include "glxserver.h"
44#include "glxutil.h"
45#include "glxext.h"
46#include "protocol-versions.h"
47
48#ifdef COMPOSITE
49#include "compositeext.h"
50#endif
51
52static DevPrivateKeyRec glxScreenPrivateKeyRec;
53
54#define glxScreenPrivateKey (&glxScreenPrivateKeyRec)
55
56const char GLServerVersion[] = "1.4";
57static const char GLServerExtensions[] =
58    "GL_ARB_depth_texture "
59    "GL_ARB_draw_buffers "
60    "GL_ARB_fragment_program "
61    "GL_ARB_fragment_program_shadow "
62    "GL_ARB_imaging "
63    "GL_ARB_multisample "
64    "GL_ARB_multitexture "
65    "GL_ARB_occlusion_query "
66    "GL_ARB_point_parameters "
67    "GL_ARB_point_sprite "
68    "GL_ARB_shadow "
69    "GL_ARB_shadow_ambient "
70    "GL_ARB_texture_border_clamp "
71    "GL_ARB_texture_compression "
72    "GL_ARB_texture_cube_map "
73    "GL_ARB_texture_env_add "
74    "GL_ARB_texture_env_combine "
75    "GL_ARB_texture_env_crossbar "
76    "GL_ARB_texture_env_dot3 "
77    "GL_ARB_texture_mirrored_repeat "
78    "GL_ARB_texture_non_power_of_two "
79    "GL_ARB_transpose_matrix "
80    "GL_ARB_vertex_program "
81    "GL_ARB_window_pos "
82    "GL_EXT_abgr "
83    "GL_EXT_bgra "
84    "GL_EXT_blend_color "
85    "GL_EXT_blend_equation_separate "
86    "GL_EXT_blend_func_separate "
87    "GL_EXT_blend_logic_op "
88    "GL_EXT_blend_minmax "
89    "GL_EXT_blend_subtract "
90    "GL_EXT_clip_volume_hint "
91    "GL_EXT_copy_texture "
92    "GL_EXT_draw_range_elements "
93    "GL_EXT_fog_coord "
94    "GL_EXT_framebuffer_object "
95    "GL_EXT_multi_draw_arrays "
96    "GL_EXT_packed_pixels "
97    "GL_EXT_paletted_texture "
98    "GL_EXT_point_parameters "
99    "GL_EXT_polygon_offset "
100    "GL_EXT_rescale_normal "
101    "GL_EXT_secondary_color "
102    "GL_EXT_separate_specular_color "
103    "GL_EXT_shadow_funcs "
104    "GL_EXT_shared_texture_palette "
105    "GL_EXT_stencil_two_side "
106    "GL_EXT_stencil_wrap "
107    "GL_EXT_subtexture "
108    "GL_EXT_texture "
109    "GL_EXT_texture3D "
110    "GL_EXT_texture_compression_dxt1 "
111    "GL_EXT_texture_compression_s3tc "
112    "GL_EXT_texture_edge_clamp "
113    "GL_EXT_texture_env_add "
114    "GL_EXT_texture_env_combine "
115    "GL_EXT_texture_env_dot3 "
116    "GL_EXT_texture_filter_anisotropic "
117    "GL_EXT_texture_lod "
118    "GL_EXT_texture_lod_bias "
119    "GL_EXT_texture_mirror_clamp "
120    "GL_EXT_texture_object "
121    "GL_EXT_texture_rectangle "
122    "GL_EXT_vertex_array "
123    "GL_3DFX_texture_compression_FXT1 "
124    "GL_APPLE_packed_pixels "
125    "GL_ATI_draw_buffers "
126    "GL_ATI_texture_env_combine3 "
127    "GL_ATI_texture_mirror_once "
128    "GL_HP_occlusion_test "
129    "GL_IBM_texture_mirrored_repeat "
130    "GL_INGR_blend_func_separate "
131    "GL_MESA_pack_invert "
132    "GL_MESA_ycbcr_texture "
133    "GL_NV_blend_square "
134    "GL_NV_depth_clamp "
135    "GL_NV_fog_distance "
136    "GL_NV_fragment_program_option "
137    "GL_NV_fragment_program2 "
138    "GL_NV_light_max_exponent "
139    "GL_NV_multisample_filter_hint "
140    "GL_NV_point_sprite "
141    "GL_NV_texgen_reflection "
142    "GL_NV_texture_compression_vtc "
143    "GL_NV_texture_env_combine4 "
144    "GL_NV_texture_expand_normal "
145    "GL_NV_texture_rectangle "
146    "GL_NV_vertex_program2_option "
147    "GL_NV_vertex_program3 "
148    "GL_OES_compressed_paletted_texture "
149    "GL_SGI_color_matrix "
150    "GL_SGI_color_table "
151    "GL_SGIS_generate_mipmap "
152    "GL_SGIS_multisample "
153    "GL_SGIS_point_parameters "
154    "GL_SGIS_texture_border_clamp "
155    "GL_SGIS_texture_edge_clamp "
156    "GL_SGIS_texture_lod "
157    "GL_SGIX_depth_texture "
158    "GL_SGIX_shadow "
159    "GL_SGIX_shadow_ambient "
160    "GL_SUN_slice_accum ";
161
162static Bool
163glxCloseScreen(ScreenPtr pScreen)
164{
165    __GLXscreen *pGlxScreen = glxGetScreen(pScreen);
166
167    pScreen->CloseScreen = pGlxScreen->CloseScreen;
168
169    pGlxScreen->destroy(pGlxScreen);
170
171    return pScreen->CloseScreen(pScreen);
172}
173
174__GLXscreen *
175glxGetScreen(ScreenPtr pScreen)
176{
177    return dixLookupPrivate(&pScreen->devPrivates, glxScreenPrivateKey);
178}
179
180GLint
181glxConvertToXVisualType(int visualType)
182{
183    static const int x_visual_types[] = {
184        TrueColor, DirectColor,
185        PseudoColor, StaticColor,
186        GrayScale, StaticGray
187    };
188
189    return ((unsigned) (visualType - GLX_TRUE_COLOR) < 6)
190        ? x_visual_types[visualType - GLX_TRUE_COLOR] : -1;
191}
192
193/* This code inspired by composite/compinit.c.  We could move this to
194 * mi/ and share it with composite.*/
195
196static VisualPtr
197AddScreenVisuals(ScreenPtr pScreen, int count, int d)
198{
199    int i;
200    DepthPtr depth;
201
202    depth = NULL;
203    for (i = 0; i < pScreen->numDepths; i++) {
204        if (pScreen->allowedDepths[i].depth == d) {
205            depth = &pScreen->allowedDepths[i];
206            break;
207        }
208    }
209    if (depth == NULL)
210        return NULL;
211
212    if (ResizeVisualArray(pScreen, count, depth) == FALSE)
213        return NULL;
214
215    /* Return a pointer to the first of the added visuals. */
216    return pScreen->visuals + pScreen->numVisuals - count;
217}
218
219static int
220findFirstSet(unsigned int v)
221{
222    int i;
223
224    for (i = 0; i < 32; i++)
225        if (v & (1 << i))
226            return i;
227
228    return -1;
229}
230
231static void
232initGlxVisual(VisualPtr visual, __GLXconfig * config)
233{
234    int maxBits;
235
236    maxBits = max(config->redBits, max(config->greenBits, config->blueBits));
237
238    config->visualID = visual->vid;
239    visual->class = glxConvertToXVisualType(config->visualType);
240    visual->bitsPerRGBValue = maxBits;
241    visual->ColormapEntries = 1 << maxBits;
242    visual->nplanes = config->redBits + config->greenBits + config->blueBits;
243
244    visual->redMask = config->redMask;
245    visual->greenMask = config->greenMask;
246    visual->blueMask = config->blueMask;
247    visual->offsetRed = findFirstSet(config->redMask);
248    visual->offsetGreen = findFirstSet(config->greenMask);
249    visual->offsetBlue = findFirstSet(config->blueMask);
250}
251
252static __GLXconfig *
253pickFBConfig(__GLXscreen * pGlxScreen, VisualPtr visual)
254{
255    __GLXconfig *best = NULL, *config;
256    int best_score = 0;
257
258    for (config = pGlxScreen->fbconfigs; config != NULL; config = config->next) {
259        int score = 0;
260
261        if (config->redMask != visual->redMask ||
262            config->greenMask != visual->greenMask ||
263            config->blueMask != visual->blueMask)
264            continue;
265        if (config->visualRating != GLX_NONE)
266            continue;
267        /* Ignore multisampled configs */
268        if (config->sampleBuffers)
269            continue;
270        if (glxConvertToXVisualType(config->visualType) != visual->class)
271            continue;
272        /* If it's the 32-bit RGBA visual, demand a 32-bit fbconfig. */
273        if (visual->nplanes == 32 && config->rgbBits != 32)
274            continue;
275        /* If it's the 32-bit RGBA visual, do not pick sRGB capable config.
276         * This can cause issues with compositors that are not sRGB aware.
277         */
278        if (visual->nplanes == 32 && config->sRGBCapable == GL_TRUE)
279            continue;
280        /* Can't use the same FBconfig for multiple X visuals.  I think. */
281        if (config->visualID != 0)
282            continue;
283#ifdef COMPOSITE
284        if (!noCompositeExtension) {
285            /* Use only duplicated configs for compIsAlternateVisuals */
286            if (!!compIsAlternateVisual(pGlxScreen->pScreen, visual->vid) !=
287                !!config->duplicatedForComp)
288                continue;
289        }
290#endif
291        /*
292         * If possible, use the same swapmethod for all built-in visual
293         * fbconfigs, to avoid getting the 32-bit composite visual when
294         * requesting, for example, a SWAP_COPY fbconfig.
295         */
296        if (config->swapMethod == GLX_SWAP_UNDEFINED_OML)
297            score += 32;
298        if (config->swapMethod == GLX_SWAP_EXCHANGE_OML)
299            score += 16;
300        if (config->doubleBufferMode > 0)
301            score += 8;
302        if (config->depthBits > 0)
303            score += 4;
304        if (config->stencilBits > 0)
305            score += 2;
306        if (config->alphaBits > 0)
307            score++;
308
309        if (score > best_score) {
310            best = config;
311            best_score = score;
312        }
313    }
314
315    return best;
316}
317
318void
319__glXScreenInit(__GLXscreen * pGlxScreen, ScreenPtr pScreen)
320{
321    __GLXconfig *m;
322    __GLXconfig *config;
323    int i;
324
325    if (!dixRegisterPrivateKey(&glxScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
326        return;
327
328    pGlxScreen->pScreen = pScreen;
329    pGlxScreen->GLextensions = strdup(GLServerExtensions);
330    pGlxScreen->GLXextensions = NULL;
331
332    pGlxScreen->CloseScreen = pScreen->CloseScreen;
333    pScreen->CloseScreen = glxCloseScreen;
334
335    i = 0;
336    for (m = pGlxScreen->fbconfigs; m != NULL; m = m->next) {
337        m->fbconfigID = FakeClientID(0);
338        m->visualID = 0;
339        i++;
340    }
341    pGlxScreen->numFBConfigs = i;
342
343    pGlxScreen->visuals =
344        calloc(pGlxScreen->numFBConfigs, sizeof(__GLXconfig *));
345
346    /* First, try to choose featureful FBconfigs for the existing X visuals.
347     * Note that if multiple X visuals end up with the same FBconfig being
348     * chosen, the later X visuals don't get GLX visuals (because we want to
349     * prioritize the root visual being GLX).
350     */
351    for (i = 0; i < pScreen->numVisuals; i++) {
352        VisualPtr visual = &pScreen->visuals[i];
353
354        config = pickFBConfig(pGlxScreen, visual);
355        if (config) {
356            pGlxScreen->visuals[pGlxScreen->numVisuals++] = config;
357            config->visualID = visual->vid;
358#ifdef COMPOSITE
359            if (!noCompositeExtension) {
360                if (compIsAlternateVisual(pScreen, visual->vid))
361                    config->visualSelectGroup++;
362            }
363#endif
364        }
365    }
366
367    /* Then, add new visuals corresponding to all FBconfigs that didn't have
368     * an existing, appropriate visual.
369     */
370    for (config = pGlxScreen->fbconfigs; config != NULL; config = config->next) {
371        int depth;
372
373        VisualPtr visual;
374
375        if (config->visualID != 0)
376            continue;
377
378        /* Only count RGB bits and not alpha, as we're not trying to create
379         * visuals for compositing (that's what the 32-bit composite visual
380         * set up above is for.
381         */
382        depth = config->redBits + config->greenBits + config->blueBits;
383#ifdef COMPOSITE
384        if (!noCompositeExtension) {
385            if (config->duplicatedForComp) {
386                    depth += config->alphaBits;
387                    config->visualSelectGroup++;
388            }
389        }
390#endif
391        /* Make sure that our FBconfig's depth can actually be displayed
392         * (corresponds to an existing visual).
393         */
394        for (i = 0; i < pScreen->numVisuals; i++) {
395            if (depth == pScreen->visuals[i].nplanes)
396                break;
397        }
398        /* if it can't, fix up the fbconfig to not advertise window support */
399        if (i == pScreen->numVisuals)
400            config->drawableType &= ~(GLX_WINDOW_BIT);
401
402        /* fbconfig must support window drawables */
403        if (!(config->drawableType & GLX_WINDOW_BIT)) {
404            config->visualID = 0;
405            continue;
406        }
407
408        /* Create a new X visual for our FBconfig. */
409        visual = AddScreenVisuals(pScreen, 1, depth);
410        if (visual == NULL)
411            continue;
412
413#ifdef COMPOSITE
414        if (!noCompositeExtension) {
415            if (config->duplicatedForComp)
416                (void) CompositeRegisterAlternateVisuals(pScreen, &visual->vid, 1);
417        }
418#endif
419        pGlxScreen->visuals[pGlxScreen->numVisuals++] = config;
420        initGlxVisual(visual, config);
421    }
422
423    dixSetPrivate(&pScreen->devPrivates, glxScreenPrivateKey, pGlxScreen);
424
425    if (pGlxScreen->glvnd)
426        __glXEnableExtension(pGlxScreen->glx_enable_bits, "GLX_EXT_libglvnd");
427
428    i = __glXGetExtensionString(pGlxScreen->glx_enable_bits, NULL);
429    if (i > 0) {
430        pGlxScreen->GLXextensions = xnfalloc(i);
431        (void) __glXGetExtensionString(pGlxScreen->glx_enable_bits,
432                                       pGlxScreen->GLXextensions);
433    }
434
435}
436
437void
438__glXScreenDestroy(__GLXscreen * screen)
439{
440    __GLXconfig *config, *next;
441
442    free(screen->glvnd);
443    free(screen->GLXextensions);
444    free(screen->GLextensions);
445    free(screen->visuals);
446
447    for (config = screen->fbconfigs; config != NULL; config = next) {
448        next = config->next;
449        free(config);
450    }
451}
452