1 | /*
|
---|
2 | * (C) Copyright IBM Corporation 2002, 2004
|
---|
3 | * 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 | * on the rights to use, copy, modify, merge, publish, distribute, sub
|
---|
9 | * license, and/or sell copies of the Software, and to permit persons to whom
|
---|
10 | * the Software is furnished to do so, subject to the following conditions:
|
---|
11 | *
|
---|
12 | * The above copyright notice and this permission notice (including the next
|
---|
13 | * paragraph) shall be included in all copies or substantial portions of the
|
---|
14 | * Software.
|
---|
15 | *
|
---|
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
---|
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
---|
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
---|
19 | * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
---|
20 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
---|
21 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
---|
22 | * USE OR OTHER DEALINGS IN THE SOFTWARE.
|
---|
23 | */
|
---|
24 |
|
---|
25 | /**
|
---|
26 | * \file utils.c
|
---|
27 | * Utility functions for DRI drivers.
|
---|
28 | *
|
---|
29 | * \author Ian Romanick <[email protected]>
|
---|
30 | */
|
---|
31 |
|
---|
32 | #include <string.h>
|
---|
33 | #include <stdlib.h>
|
---|
34 | #include "mtypes.h"
|
---|
35 | #include "extensions.h"
|
---|
36 | #include "utils.h"
|
---|
37 | #include "dispatch.h"
|
---|
38 |
|
---|
39 | int driDispatchRemapTable[ driDispatchRemapTable_size ];
|
---|
40 |
|
---|
41 | #if defined(USE_X86_ASM)
|
---|
42 | #include "x86/common_x86_asm.h"
|
---|
43 | #endif
|
---|
44 |
|
---|
45 | #if defined(USE_PPC_ASM)
|
---|
46 | #include "ppc/common_ppc_features.h"
|
---|
47 | #endif
|
---|
48 |
|
---|
49 | unsigned
|
---|
50 | driParseDebugString( const char * debug,
|
---|
51 | const struct dri_debug_control * control )
|
---|
52 | {
|
---|
53 | unsigned flag;
|
---|
54 |
|
---|
55 |
|
---|
56 | flag = 0;
|
---|
57 | if ( debug != NULL ) {
|
---|
58 | while( control->string != NULL ) {
|
---|
59 | if ( !strcmp( debug, "all" ) ||
|
---|
60 | strstr( debug, control->string ) != NULL ) {
|
---|
61 | flag |= control->flag;
|
---|
62 | }
|
---|
63 |
|
---|
64 | control++;
|
---|
65 | }
|
---|
66 | }
|
---|
67 |
|
---|
68 | return flag;
|
---|
69 | }
|
---|
70 |
|
---|
71 |
|
---|
72 |
|
---|
73 | /**
|
---|
74 | * Create the \c GL_RENDERER string for DRI drivers.
|
---|
75 | *
|
---|
76 | * Almost all DRI drivers use a \c GL_RENDERER string of the form:
|
---|
77 | *
|
---|
78 | * "Mesa DRI <chip> <driver date> <AGP speed) <CPU information>"
|
---|
79 | *
|
---|
80 | * Using the supplied chip name, driver data, and AGP speed, this function
|
---|
81 | * creates the string.
|
---|
82 | *
|
---|
83 | * \param buffer Buffer to hold the \c GL_RENDERER string.
|
---|
84 | * \param hardware_name Name of the hardware.
|
---|
85 | * \param driver_date Driver date.
|
---|
86 | * \param agp_mode AGP mode (speed).
|
---|
87 | *
|
---|
88 | * \returns
|
---|
89 | * The length of the string stored in \c buffer. This does \b not include
|
---|
90 | * the terminating \c NUL character.
|
---|
91 | */
|
---|
92 | unsigned
|
---|
93 | driGetRendererString( char * buffer, const char * hardware_name,
|
---|
94 | const char * driver_date, GLuint agp_mode )
|
---|
95 | {
|
---|
96 | #define MAX_INFO 4
|
---|
97 | const char * cpu[MAX_INFO];
|
---|
98 | unsigned next = 0;
|
---|
99 | unsigned i;
|
---|
100 | unsigned offset;
|
---|
101 |
|
---|
102 |
|
---|
103 | offset = sprintf( buffer, "Mesa DRI %s %s", hardware_name, driver_date );
|
---|
104 |
|
---|
105 | /* Append any AGP-specific information.
|
---|
106 | */
|
---|
107 | switch ( agp_mode ) {
|
---|
108 | case 1:
|
---|
109 | case 2:
|
---|
110 | case 4:
|
---|
111 | case 8:
|
---|
112 | offset += sprintf( & buffer[ offset ], " AGP %ux", agp_mode );
|
---|
113 | break;
|
---|
114 |
|
---|
115 | default:
|
---|
116 | break;
|
---|
117 | }
|
---|
118 |
|
---|
119 | /* Append any CPU-specific information.
|
---|
120 | */
|
---|
121 | #ifdef USE_X86_ASM
|
---|
122 | if ( _mesa_x86_cpu_features ) {
|
---|
123 | cpu[next] = " x86";
|
---|
124 | next++;
|
---|
125 | }
|
---|
126 | # ifdef USE_MMX_ASM
|
---|
127 | if ( cpu_has_mmx ) {
|
---|
128 | cpu[next] = (cpu_has_mmxext) ? "/MMX+" : "/MMX";
|
---|
129 | next++;
|
---|
130 | }
|
---|
131 | # endif
|
---|
132 | # ifdef USE_3DNOW_ASM
|
---|
133 | if ( cpu_has_3dnow ) {
|
---|
134 | cpu[next] = (cpu_has_3dnowext) ? "/3DNow!+" : "/3DNow!";
|
---|
135 | next++;
|
---|
136 | }
|
---|
137 | # endif
|
---|
138 | # ifdef USE_SSE_ASM
|
---|
139 | if ( cpu_has_xmm ) {
|
---|
140 | cpu[next] = (cpu_has_xmm2) ? "/SSE2" : "/SSE";
|
---|
141 | next++;
|
---|
142 | }
|
---|
143 | # endif
|
---|
144 |
|
---|
145 | #elif defined(USE_SPARC_ASM)
|
---|
146 |
|
---|
147 | cpu[0] = " SPARC";
|
---|
148 | next = 1;
|
---|
149 |
|
---|
150 | #elif defined(USE_PPC_ASM)
|
---|
151 | if ( _mesa_ppc_cpu_features ) {
|
---|
152 | cpu[next] = (cpu_has_64) ? " PowerPC 64" : " PowerPC";
|
---|
153 | next++;
|
---|
154 | }
|
---|
155 |
|
---|
156 | # ifdef USE_VMX_ASM
|
---|
157 | if ( cpu_has_vmx ) {
|
---|
158 | cpu[next] = "/Altivec";
|
---|
159 | next++;
|
---|
160 | }
|
---|
161 | # endif
|
---|
162 |
|
---|
163 | if ( ! cpu_has_fpu ) {
|
---|
164 | cpu[next] = "/No FPU";
|
---|
165 | next++;
|
---|
166 | }
|
---|
167 | #endif
|
---|
168 |
|
---|
169 | for ( i = 0 ; i < next ; i++ ) {
|
---|
170 | const size_t len = strlen( cpu[i] );
|
---|
171 |
|
---|
172 | strncpy( & buffer[ offset ], cpu[i], len );
|
---|
173 | offset += len;
|
---|
174 | }
|
---|
175 |
|
---|
176 | return offset;
|
---|
177 | }
|
---|
178 |
|
---|
179 |
|
---|
180 |
|
---|
181 |
|
---|
182 | #define need_GL_ARB_multisample
|
---|
183 | #define need_GL_ARB_transpose_matrix
|
---|
184 | #define need_GL_ARB_window_pos
|
---|
185 | #define need_GL_EXT_compiled_vertex_array
|
---|
186 | #define need_GL_EXT_polygon_offset
|
---|
187 | #define need_GL_EXT_texture_object
|
---|
188 | #define need_GL_EXT_vertex_array
|
---|
189 | #define need_GL_MESA_window_pos
|
---|
190 |
|
---|
191 | /* These are needed in *all* drivers because Mesa internally implements
|
---|
192 | * certain functionality in terms of functions provided by these extensions.
|
---|
193 | * For example, glBlendFunc is implemented by calling glBlendFuncSeparateEXT.
|
---|
194 | */
|
---|
195 | #define need_GL_EXT_blend_func_separate
|
---|
196 | #define need_GL_NV_vertex_program
|
---|
197 |
|
---|
198 | #include "extension_helper.h"
|
---|
199 |
|
---|
200 | static const struct dri_extension all_mesa_extensions[] = {
|
---|
201 | { "GL_ARB_multisample", GL_ARB_multisample_functions },
|
---|
202 | { "GL_ARB_transpose_matrix", GL_ARB_transpose_matrix_functions },
|
---|
203 | { "GL_ARB_window_pos", GL_ARB_window_pos_functions },
|
---|
204 | { "GL_EXT_blend_func_separate", GL_EXT_blend_func_separate_functions },
|
---|
205 | { "GL_EXT_compiled_vertex_array", GL_EXT_compiled_vertex_array_functions },
|
---|
206 | { "GL_EXT_polygon_offset", GL_EXT_polygon_offset_functions },
|
---|
207 | { "GL_EXT_texture_object", GL_EXT_texture_object_functions },
|
---|
208 | { "GL_EXT_vertex_array", GL_EXT_vertex_array_functions },
|
---|
209 | { "GL_MESA_window_pos", GL_MESA_window_pos_functions },
|
---|
210 | { "GL_NV_vertex_program", GL_NV_vertex_program_functions },
|
---|
211 | { NULL, NULL }
|
---|
212 | };
|
---|
213 |
|
---|
214 |
|
---|
215 | /**
|
---|
216 | * Enable extensions supported by the driver.
|
---|
217 | *
|
---|
218 | * \bug
|
---|
219 | * ARB_imaging isn't handled properly. In Mesa, enabling ARB_imaging also
|
---|
220 | * enables all the sub-extensions that are folded into it. This means that
|
---|
221 | * we need to add entry-points (via \c driInitSingleExtension) for those
|
---|
222 | * new functions here.
|
---|
223 | */
|
---|
224 | void driInitExtensions( GLcontext * ctx,
|
---|
225 | const struct dri_extension * extensions_to_enable,
|
---|
226 | GLboolean enable_imaging )
|
---|
227 | {
|
---|
228 | static int first_time = 1;
|
---|
229 | unsigned i;
|
---|
230 |
|
---|
231 | if ( first_time ) {
|
---|
232 | for ( i = 0 ; i < driDispatchRemapTable_size ; i++ ) {
|
---|
233 | driDispatchRemapTable[i] = -1;
|
---|
234 | }
|
---|
235 |
|
---|
236 | first_time = 0;
|
---|
237 | driInitExtensions( ctx, all_mesa_extensions, GL_FALSE );
|
---|
238 | }
|
---|
239 |
|
---|
240 | if ( (ctx != NULL) && enable_imaging ) {
|
---|
241 | _mesa_enable_imaging_extensions( ctx );
|
---|
242 | }
|
---|
243 |
|
---|
244 | for ( i = 0 ; extensions_to_enable[i].name != NULL ; i++ ) {
|
---|
245 | driInitSingleExtension( ctx, & extensions_to_enable[i] );
|
---|
246 | }
|
---|
247 | }
|
---|
248 |
|
---|
249 |
|
---|
250 |
|
---|
251 |
|
---|
252 | /**
|
---|
253 | * Enable and add dispatch functions for a single extension
|
---|
254 | *
|
---|
255 | * \param ctx Context where extension is to be enabled.
|
---|
256 | * \param ext Extension that is to be enabled.
|
---|
257 | *
|
---|
258 | * \sa driInitExtensions, _mesa_enable_extension, _glapi_add_entrypoint
|
---|
259 | *
|
---|
260 | * \todo
|
---|
261 | * Determine if it would be better to use \c strlen instead of the hardcoded
|
---|
262 | * for-loops.
|
---|
263 | */
|
---|
264 | void driInitSingleExtension( GLcontext * ctx,
|
---|
265 | const struct dri_extension * ext )
|
---|
266 | {
|
---|
267 | unsigned i;
|
---|
268 |
|
---|
269 |
|
---|
270 | if ( ext->functions != NULL ) {
|
---|
271 | for ( i = 0 ; ext->functions[i].strings != NULL ; i++ ) {
|
---|
272 | const char * functions[16];
|
---|
273 | const char * parameter_signature;
|
---|
274 | const char * str = ext->functions[i].strings;
|
---|
275 | unsigned j;
|
---|
276 | unsigned offset;
|
---|
277 |
|
---|
278 |
|
---|
279 | /* Separate the parameter signature from the rest of the string.
|
---|
280 | * If the parameter signature is empty (i.e., the string starts
|
---|
281 | * with a NUL character), then the function has a void parameter
|
---|
282 | * list.
|
---|
283 | */
|
---|
284 | parameter_signature = str;
|
---|
285 | while ( str[0] != '\0' ) {
|
---|
286 | str++;
|
---|
287 | }
|
---|
288 | str++;
|
---|
289 |
|
---|
290 |
|
---|
291 | /* Divide the string into the substrings that name each
|
---|
292 | * entry-point for the function.
|
---|
293 | */
|
---|
294 | for ( j = 0 ; j < 16 ; j++ ) {
|
---|
295 | if ( str[0] == '\0' ) {
|
---|
296 | functions[j] = NULL;
|
---|
297 | break;
|
---|
298 | }
|
---|
299 |
|
---|
300 | functions[j] = str;
|
---|
301 |
|
---|
302 | while ( str[0] != '\0' ) {
|
---|
303 | str++;
|
---|
304 | }
|
---|
305 | str++;
|
---|
306 | }
|
---|
307 |
|
---|
308 |
|
---|
309 | /* Add each entry-point to the dispatch table.
|
---|
310 | */
|
---|
311 | offset = _glapi_add_dispatch( functions, parameter_signature );
|
---|
312 | if (offset == -1) {
|
---|
313 | fprintf(stderr, "DISPATCH ERROR! _glapi_add_dispatch failed "
|
---|
314 | "to add %s!\n", functions[0]);
|
---|
315 | }
|
---|
316 | else if (ext->functions[i].remap_index != -1) {
|
---|
317 | driDispatchRemapTable[ ext->functions[i].remap_index ] =
|
---|
318 | offset;
|
---|
319 | }
|
---|
320 | else if (ext->functions[i].offset != offset) {
|
---|
321 | fprintf(stderr, "DISPATCH ERROR! %s -> %u != %u\n",
|
---|
322 | functions[0], offset, ext->functions[i].offset);
|
---|
323 | }
|
---|
324 | }
|
---|
325 | }
|
---|
326 |
|
---|
327 | if ( ctx != NULL ) {
|
---|
328 | _mesa_enable_extension( ctx, ext->name );
|
---|
329 | }
|
---|
330 | }
|
---|
331 |
|
---|
332 |
|
---|
333 | /**
|
---|
334 | * Utility function used by drivers to test the versions of other components.
|
---|
335 | *
|
---|
336 | * If one of the version requirements is not met, a message is logged using
|
---|
337 | * \c __driUtilMessage.
|
---|
338 | *
|
---|
339 | * \param driver_name Name of the driver. Used in error messages.
|
---|
340 | * \param driActual Actual DRI version supplied __driCreateNewScreen.
|
---|
341 | * \param driExpected Minimum DRI version required by the driver.
|
---|
342 | * \param ddxActual Actual DDX version supplied __driCreateNewScreen.
|
---|
343 | * \param ddxExpected Minimum DDX minor and range of DDX major version required by the driver.
|
---|
344 | * \param drmActual Actual DRM version supplied __driCreateNewScreen.
|
---|
345 | * \param drmExpected Minimum DRM version required by the driver.
|
---|
346 | *
|
---|
347 | * \returns \c GL_TRUE if all version requirements are met. Otherwise,
|
---|
348 | * \c GL_FALSE is returned.
|
---|
349 | *
|
---|
350 | * \sa __driCreateNewScreen, driCheckDriDdxDrmVersions2, __driUtilMessage
|
---|
351 | *
|
---|
352 | * \todo
|
---|
353 | * Now that the old \c driCheckDriDdxDrmVersions function is gone, this
|
---|
354 | * function and \c driCheckDriDdxDrmVersions2 should be renamed.
|
---|
355 | */
|
---|
356 | GLboolean
|
---|
357 | driCheckDriDdxDrmVersions3(const char * driver_name,
|
---|
358 | const __DRIversion * driActual,
|
---|
359 | const __DRIversion * driExpected,
|
---|
360 | const __DRIversion * ddxActual,
|
---|
361 | const __DRIutilversion2 * ddxExpected,
|
---|
362 | const __DRIversion * drmActual,
|
---|
363 | const __DRIversion * drmExpected)
|
---|
364 | {
|
---|
365 | static const char format[] = "%s DRI driver expected %s version %d.%d.x "
|
---|
366 | "but got version %d.%d.%d\n";
|
---|
367 | static const char format2[] = "%s DRI driver expected %s version %d-%d.%d.x "
|
---|
368 | "but got version %d.%d.%d\n";
|
---|
369 |
|
---|
370 |
|
---|
371 | /* Check the DRI version */
|
---|
372 | if ( (driActual->major != driExpected->major)
|
---|
373 | || (driActual->minor < driExpected->minor) ) {
|
---|
374 | fprintf(stderr, format, driver_name, "DRI",
|
---|
375 | driExpected->major, driExpected->minor,
|
---|
376 | driActual->major, driActual->minor, driActual->patch);
|
---|
377 | return GL_FALSE;
|
---|
378 | }
|
---|
379 |
|
---|
380 | /* Check that the DDX driver version is compatible */
|
---|
381 | /* for miniglx we pass in -1 so we can ignore the DDX version */
|
---|
382 | if ( (ddxActual->major != -1) && ((ddxActual->major < ddxExpected->major_min)
|
---|
383 | || (ddxActual->major > ddxExpected->major_max)
|
---|
384 | || (ddxActual->minor < ddxExpected->minor)) ) {
|
---|
385 | fprintf(stderr, format2, driver_name, "DDX",
|
---|
386 | ddxExpected->major_min, ddxExpected->major_max, ddxExpected->minor,
|
---|
387 | ddxActual->major, ddxActual->minor, ddxActual->patch);
|
---|
388 | return GL_FALSE;
|
---|
389 | }
|
---|
390 |
|
---|
391 | /* Check that the DRM driver version is compatible */
|
---|
392 | if ( (drmActual->major != drmExpected->major)
|
---|
393 | || (drmActual->minor < drmExpected->minor) ) {
|
---|
394 | fprintf(stderr, format, driver_name, "DRM",
|
---|
395 | drmExpected->major, drmExpected->minor,
|
---|
396 | drmActual->major, drmActual->minor, drmActual->patch);
|
---|
397 | return GL_FALSE;
|
---|
398 | }
|
---|
399 |
|
---|
400 | return GL_TRUE;
|
---|
401 | }
|
---|
402 |
|
---|
403 | GLboolean
|
---|
404 | driCheckDriDdxDrmVersions2(const char * driver_name,
|
---|
405 | const __DRIversion * driActual,
|
---|
406 | const __DRIversion * driExpected,
|
---|
407 | const __DRIversion * ddxActual,
|
---|
408 | const __DRIversion * ddxExpected,
|
---|
409 | const __DRIversion * drmActual,
|
---|
410 | const __DRIversion * drmExpected)
|
---|
411 | {
|
---|
412 | __DRIutilversion2 ddx_expected;
|
---|
413 | ddx_expected.major_min = ddxExpected->major;
|
---|
414 | ddx_expected.major_max = ddxExpected->major;
|
---|
415 | ddx_expected.minor = ddxExpected->minor;
|
---|
416 | ddx_expected.patch = ddxExpected->patch;
|
---|
417 | return driCheckDriDdxDrmVersions3(driver_name, driActual,
|
---|
418 | driExpected, ddxActual, & ddx_expected,
|
---|
419 | drmActual, drmExpected);
|
---|
420 | }
|
---|
421 |
|
---|
422 | GLboolean driClipRectToFramebuffer( const GLframebuffer *buffer,
|
---|
423 | GLint *x, GLint *y,
|
---|
424 | GLsizei *width, GLsizei *height )
|
---|
425 | {
|
---|
426 | /* left clipping */
|
---|
427 | if (*x < buffer->_Xmin) {
|
---|
428 | *width -= (buffer->_Xmin - *x);
|
---|
429 | *x = buffer->_Xmin;
|
---|
430 | }
|
---|
431 |
|
---|
432 | /* right clipping */
|
---|
433 | if (*x + *width > buffer->_Xmax)
|
---|
434 | *width -= (*x + *width - buffer->_Xmax - 1);
|
---|
435 |
|
---|
436 | if (*width <= 0)
|
---|
437 | return GL_FALSE;
|
---|
438 |
|
---|
439 | /* bottom clipping */
|
---|
440 | if (*y < buffer->_Ymin) {
|
---|
441 | *height -= (buffer->_Ymin - *y);
|
---|
442 | *y = buffer->_Ymin;
|
---|
443 | }
|
---|
444 |
|
---|
445 | /* top clipping */
|
---|
446 | if (*y + *height > buffer->_Ymax)
|
---|
447 | *height -= (*y + *height - buffer->_Ymax - 1);
|
---|
448 |
|
---|
449 | if (*height <= 0)
|
---|
450 | return GL_FALSE;
|
---|
451 |
|
---|
452 | return GL_TRUE;
|
---|
453 | }
|
---|
454 |
|
---|
455 | /**
|
---|
456 | * Creates a set of \c __GLcontextModes that a driver will expose.
|
---|
457 | *
|
---|
458 | * A set of \c __GLcontextModes will be created based on the supplied
|
---|
459 | * parameters. The number of modes processed will be 2 *
|
---|
460 | * \c num_depth_stencil_bits * \c num_db_modes.
|
---|
461 | *
|
---|
462 | * For the most part, data is just copied from \c depth_bits, \c stencil_bits,
|
---|
463 | * \c db_modes, and \c visType into each \c __GLcontextModes element.
|
---|
464 | * However, the meanings of \c fb_format and \c fb_type require further
|
---|
465 | * explanation. The \c fb_format specifies which color components are in
|
---|
466 | * each pixel and what the default order is. For example, \c GL_RGB specifies
|
---|
467 | * that red, green, blue are available and red is in the "most significant"
|
---|
468 | * position and blue is in the "least significant". The \c fb_type specifies
|
---|
469 | * the bit sizes of each component and the actual ordering. For example, if
|
---|
470 | * \c GL_UNSIGNED_SHORT_5_6_5_REV is specified with \c GL_RGB, bits [15:11]
|
---|
471 | * are the blue value, bits [10:5] are the green value, and bits [4:0] are
|
---|
472 | * the red value.
|
---|
473 | *
|
---|
474 | * One subtle issue is the combination of \c GL_RGB or \c GL_BGR and either
|
---|
475 | * of the \c GL_UNSIGNED_INT_8_8_8_8 modes. The resulting mask values in the
|
---|
476 | * \c __GLcontextModes structure is \b identical to the \c GL_RGBA or
|
---|
477 | * \c GL_BGRA case, except the \c alphaMask is zero. This means that, as
|
---|
478 | * far as this routine is concerned, \c GL_RGB with \c GL_UNSIGNED_INT_8_8_8_8
|
---|
479 | * still uses 32-bits.
|
---|
480 | *
|
---|
481 | * If in doubt, look at the tables used in the function.
|
---|
482 | *
|
---|
483 | * \param ptr_to_modes Pointer to a pointer to a linked list of
|
---|
484 | * \c __GLcontextModes. Upon completion, a pointer to
|
---|
485 | * the next element to be process will be stored here.
|
---|
486 | * If the function fails and returns \c GL_FALSE, this
|
---|
487 | * value will be unmodified, but some elements in the
|
---|
488 | * linked list may be modified.
|
---|
489 | * \param fb_format Format of the framebuffer. Currently only \c GL_RGB,
|
---|
490 | * \c GL_RGBA, \c GL_BGR, and \c GL_BGRA are supported.
|
---|
491 | * \param fb_type Type of the pixels in the framebuffer. Currently only
|
---|
492 | * \c GL_UNSIGNED_SHORT_5_6_5,
|
---|
493 | * \c GL_UNSIGNED_SHORT_5_6_5_REV,
|
---|
494 | * \c GL_UNSIGNED_INT_8_8_8_8, and
|
---|
495 | * \c GL_UNSIGNED_INT_8_8_8_8_REV are supported.
|
---|
496 | * \param depth_bits Array of depth buffer sizes to be exposed.
|
---|
497 | * \param stencil_bits Array of stencil buffer sizes to be exposed.
|
---|
498 | * \param num_depth_stencil_bits Number of entries in both \c depth_bits and
|
---|
499 | * \c stencil_bits.
|
---|
500 | * \param db_modes Array of buffer swap modes. If an element has a
|
---|
501 | * value of \c GLX_NONE, then it represents a
|
---|
502 | * single-buffered mode. Other valid values are
|
---|
503 | * \c GLX_SWAP_EXCHANGE_OML, \c GLX_SWAP_COPY_OML, and
|
---|
504 | * \c GLX_SWAP_UNDEFINED_OML. See the
|
---|
505 | * GLX_OML_swap_method extension spec for more details.
|
---|
506 | * \param num_db_modes Number of entries in \c db_modes.
|
---|
507 | * \param visType GLX visual type. Usually either \c GLX_TRUE_COLOR or
|
---|
508 | * \c GLX_DIRECT_COLOR.
|
---|
509 | *
|
---|
510 | * \returns
|
---|
511 | * \c GL_TRUE on success or \c GL_FALSE on failure. Currently the only
|
---|
512 | * cause of failure is a bad parameter (i.e., unsupported \c fb_format or
|
---|
513 | * \c fb_type).
|
---|
514 | *
|
---|
515 | * \todo
|
---|
516 | * There is currently no way to support packed RGB modes (i.e., modes with
|
---|
517 | * exactly 3 bytes per pixel) or floating-point modes. This could probably
|
---|
518 | * be done by creating some new, private enums with clever names likes
|
---|
519 | * \c GL_UNSIGNED_3BYTE_8_8_8, \c GL_4FLOAT_32_32_32_32,
|
---|
520 | * \c GL_4HALF_16_16_16_16, etc. We can cross that bridge when we come to it.
|
---|
521 | */
|
---|
522 | __DRIconfig **
|
---|
523 | driCreateConfigs(GLenum fb_format, GLenum fb_type,
|
---|
524 | const u_int8_t * depth_bits, const u_int8_t * stencil_bits,
|
---|
525 | unsigned num_depth_stencil_bits,
|
---|
526 | const GLenum * db_modes, unsigned num_db_modes)
|
---|
527 | {
|
---|
528 | static const u_int8_t bits_table[4][4] = {
|
---|
529 | /* R G B A */
|
---|
530 | { 3, 3, 2, 0 }, /* Any GL_UNSIGNED_BYTE_3_3_2 */
|
---|
531 | { 5, 6, 5, 0 }, /* Any GL_UNSIGNED_SHORT_5_6_5 */
|
---|
532 | { 8, 8, 8, 0 }, /* Any RGB with any GL_UNSIGNED_INT_8_8_8_8 */
|
---|
533 | { 8, 8, 8, 8 } /* Any RGBA with any GL_UNSIGNED_INT_8_8_8_8 */
|
---|
534 | };
|
---|
535 |
|
---|
536 | static const u_int32_t masks_table_rgb[6][4] = {
|
---|
537 | { 0x000000E0, 0x0000001C, 0x00000003, 0x00000000 }, /* 3_3_2 */
|
---|
538 | { 0x00000007, 0x00000038, 0x000000C0, 0x00000000 }, /* 2_3_3_REV */
|
---|
539 | { 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000 }, /* 5_6_5 */
|
---|
540 | { 0x0000001F, 0x000007E0, 0x0000F800, 0x00000000 }, /* 5_6_5_REV */
|
---|
541 | { 0xFF000000, 0x00FF0000, 0x0000FF00, 0x00000000 }, /* 8_8_8_8 */
|
---|
542 | { 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000 } /* 8_8_8_8_REV */
|
---|
543 | };
|
---|
544 |
|
---|
545 | static const u_int32_t masks_table_rgba[6][4] = {
|
---|
546 | { 0x000000E0, 0x0000001C, 0x00000003, 0x00000000 }, /* 3_3_2 */
|
---|
547 | { 0x00000007, 0x00000038, 0x000000C0, 0x00000000 }, /* 2_3_3_REV */
|
---|
548 | { 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000 }, /* 5_6_5 */
|
---|
549 | { 0x0000001F, 0x000007E0, 0x0000F800, 0x00000000 }, /* 5_6_5_REV */
|
---|
550 | { 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF }, /* 8_8_8_8 */
|
---|
551 | { 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 }, /* 8_8_8_8_REV */
|
---|
552 | };
|
---|
553 |
|
---|
554 | static const u_int32_t masks_table_bgr[6][4] = {
|
---|
555 | { 0x00000007, 0x00000038, 0x000000C0, 0x00000000 }, /* 3_3_2 */
|
---|
556 | { 0x000000E0, 0x0000001C, 0x00000003, 0x00000000 }, /* 2_3_3_REV */
|
---|
557 | { 0x0000001F, 0x000007E0, 0x0000F800, 0x00000000 }, /* 5_6_5 */
|
---|
558 | { 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000 }, /* 5_6_5_REV */
|
---|
559 | { 0x0000FF00, 0x00FF0000, 0xFF000000, 0x00000000 }, /* 8_8_8_8 */
|
---|
560 | { 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000 }, /* 8_8_8_8_REV */
|
---|
561 | };
|
---|
562 |
|
---|
563 | static const u_int32_t masks_table_bgra[6][4] = {
|
---|
564 | { 0x00000007, 0x00000038, 0x000000C0, 0x00000000 }, /* 3_3_2 */
|
---|
565 | { 0x000000E0, 0x0000001C, 0x00000003, 0x00000000 }, /* 2_3_3_REV */
|
---|
566 | { 0x0000001F, 0x000007E0, 0x0000F800, 0x00000000 }, /* 5_6_5 */
|
---|
567 | { 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000 }, /* 5_6_5_REV */
|
---|
568 | { 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF }, /* 8_8_8_8 */
|
---|
569 | { 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000 }, /* 8_8_8_8_REV */
|
---|
570 | };
|
---|
571 |
|
---|
572 | static const u_int8_t bytes_per_pixel[6] = {
|
---|
573 | 1, /* 3_3_2 */
|
---|
574 | 1, /* 2_3_3_REV */
|
---|
575 | 2, /* 5_6_5 */
|
---|
576 | 2, /* 5_6_5_REV */
|
---|
577 | 4, /* 8_8_8_8 */
|
---|
578 | 4 /* 8_8_8_8_REV */
|
---|
579 | };
|
---|
580 |
|
---|
581 | const u_int8_t * bits;
|
---|
582 | const u_int32_t * masks;
|
---|
583 | int index;
|
---|
584 | __DRIconfig **configs, **c;
|
---|
585 | __GLcontextModes *modes;
|
---|
586 | unsigned i;
|
---|
587 | unsigned j;
|
---|
588 | unsigned k;
|
---|
589 | unsigned num_modes;
|
---|
590 | unsigned num_accum_bits = 2;
|
---|
591 |
|
---|
592 | switch ( fb_type ) {
|
---|
593 | case GL_UNSIGNED_BYTE_3_3_2:
|
---|
594 | index = 0;
|
---|
595 | break;
|
---|
596 | case GL_UNSIGNED_BYTE_2_3_3_REV:
|
---|
597 | index = 1;
|
---|
598 | break;
|
---|
599 | case GL_UNSIGNED_SHORT_5_6_5:
|
---|
600 | index = 2;
|
---|
601 | break;
|
---|
602 | case GL_UNSIGNED_SHORT_5_6_5_REV:
|
---|
603 | index = 3;
|
---|
604 | break;
|
---|
605 | case GL_UNSIGNED_INT_8_8_8_8:
|
---|
606 | index = 4;
|
---|
607 | break;
|
---|
608 | case GL_UNSIGNED_INT_8_8_8_8_REV:
|
---|
609 | index = 5;
|
---|
610 | break;
|
---|
611 | default:
|
---|
612 | fprintf( stderr, "[%s:%u] Unknown framebuffer type 0x%04x.\n",
|
---|
613 | __FUNCTION__, __LINE__, fb_type );
|
---|
614 | return NULL;
|
---|
615 | }
|
---|
616 |
|
---|
617 |
|
---|
618 | /* Valid types are GL_UNSIGNED_SHORT_5_6_5 and GL_UNSIGNED_INT_8_8_8_8 and
|
---|
619 | * the _REV versions.
|
---|
620 | *
|
---|
621 | * Valid formats are GL_RGBA, GL_RGB, and GL_BGRA.
|
---|
622 | */
|
---|
623 |
|
---|
624 | switch ( fb_format ) {
|
---|
625 | case GL_RGB:
|
---|
626 | masks = masks_table_rgb[ index ];
|
---|
627 | break;
|
---|
628 |
|
---|
629 | case GL_RGBA:
|
---|
630 | masks = masks_table_rgba[ index ];
|
---|
631 | break;
|
---|
632 |
|
---|
633 | case GL_BGR:
|
---|
634 | masks = masks_table_bgr[ index ];
|
---|
635 | break;
|
---|
636 |
|
---|
637 | case GL_BGRA:
|
---|
638 | masks = masks_table_bgra[ index ];
|
---|
639 | break;
|
---|
640 |
|
---|
641 | default:
|
---|
642 | fprintf( stderr, "[%s:%u] Unknown framebuffer format 0x%04x.\n",
|
---|
643 | __FUNCTION__, __LINE__, fb_format );
|
---|
644 | return NULL;
|
---|
645 | }
|
---|
646 |
|
---|
647 | switch ( bytes_per_pixel[ index ] ) {
|
---|
648 | case 1:
|
---|
649 | bits = bits_table[0];
|
---|
650 | break;
|
---|
651 | case 2:
|
---|
652 | bits = bits_table[1];
|
---|
653 | break;
|
---|
654 | default:
|
---|
655 | bits = ((fb_format == GL_RGB) || (fb_format == GL_BGR))
|
---|
656 | ? bits_table[2]
|
---|
657 | : bits_table[3];
|
---|
658 | break;
|
---|
659 | }
|
---|
660 |
|
---|
661 | num_modes = num_depth_stencil_bits * num_db_modes * num_accum_bits;
|
---|
662 | configs = _mesa_calloc((num_modes + 1) * sizeof *configs);
|
---|
663 | if (configs == NULL)
|
---|
664 | return NULL;
|
---|
665 |
|
---|
666 | c = configs;
|
---|
667 | for ( k = 0 ; k < num_depth_stencil_bits ; k++ ) {
|
---|
668 | for ( i = 0 ; i < num_db_modes ; i++ ) {
|
---|
669 | for ( j = 0 ; j < num_accum_bits ; j++ ) {
|
---|
670 | *c = _mesa_malloc (sizeof **c);
|
---|
671 | modes = &(*c)->modes;
|
---|
672 | c++;
|
---|
673 |
|
---|
674 | memset(modes, 0, sizeof *modes);
|
---|
675 | modes->redBits = bits[0];
|
---|
676 | modes->greenBits = bits[1];
|
---|
677 | modes->blueBits = bits[2];
|
---|
678 | modes->alphaBits = bits[3];
|
---|
679 | modes->redMask = masks[0];
|
---|
680 | modes->greenMask = masks[1];
|
---|
681 | modes->blueMask = masks[2];
|
---|
682 | modes->alphaMask = masks[3];
|
---|
683 | modes->rgbBits = modes->redBits + modes->greenBits
|
---|
684 | + modes->blueBits + modes->alphaBits;
|
---|
685 |
|
---|
686 | modes->accumRedBits = 16 * j;
|
---|
687 | modes->accumGreenBits = 16 * j;
|
---|
688 | modes->accumBlueBits = 16 * j;
|
---|
689 | modes->accumAlphaBits = (masks[3] != 0) ? 16 * j : 0;
|
---|
690 | modes->visualRating = (j == 0) ? GLX_NONE : GLX_SLOW_CONFIG;
|
---|
691 |
|
---|
692 | modes->stencilBits = stencil_bits[k];
|
---|
693 | modes->depthBits = depth_bits[k];
|
---|
694 |
|
---|
695 | modes->transparentPixel = GLX_NONE;
|
---|
696 | modes->transparentRed = GLX_DONT_CARE;
|
---|
697 | modes->transparentGreen = GLX_DONT_CARE;
|
---|
698 | modes->transparentBlue = GLX_DONT_CARE;
|
---|
699 | modes->transparentAlpha = GLX_DONT_CARE;
|
---|
700 | modes->transparentIndex = GLX_DONT_CARE;
|
---|
701 | modes->visualType = GLX_DONT_CARE;
|
---|
702 | modes->renderType = GLX_RGBA_BIT;
|
---|
703 | modes->drawableType = GLX_WINDOW_BIT;
|
---|
704 | modes->rgbMode = GL_TRUE;
|
---|
705 |
|
---|
706 | if ( db_modes[i] == GLX_NONE ) {
|
---|
707 | modes->doubleBufferMode = GL_FALSE;
|
---|
708 | }
|
---|
709 | else {
|
---|
710 | modes->doubleBufferMode = GL_TRUE;
|
---|
711 | modes->swapMethod = db_modes[i];
|
---|
712 | }
|
---|
713 |
|
---|
714 | modes->haveAccumBuffer = ((modes->accumRedBits +
|
---|
715 | modes->accumGreenBits +
|
---|
716 | modes->accumBlueBits +
|
---|
717 | modes->accumAlphaBits) > 0);
|
---|
718 | modes->haveDepthBuffer = (modes->depthBits > 0);
|
---|
719 | modes->haveStencilBuffer = (modes->stencilBits > 0);
|
---|
720 |
|
---|
721 | modes->bindToTextureRgb = GL_TRUE;
|
---|
722 | modes->bindToTextureRgba = GL_TRUE;
|
---|
723 | modes->bindToMipmapTexture = GL_FALSE;
|
---|
724 | modes->bindToTextureTargets = modes->rgbMode ?
|
---|
725 | __DRI_ATTRIB_TEXTURE_1D_BIT |
|
---|
726 | __DRI_ATTRIB_TEXTURE_2D_BIT |
|
---|
727 | __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT :
|
---|
728 | 0;
|
---|
729 | }
|
---|
730 | }
|
---|
731 | }
|
---|
732 | *c = NULL;
|
---|
733 |
|
---|
734 | return configs;
|
---|
735 | }
|
---|
736 |
|
---|
737 | const __DRIconfig **driConcatConfigs(__DRIconfig **a, __DRIconfig **b)
|
---|
738 | {
|
---|
739 | const __DRIconfig **all;
|
---|
740 | int i, j, index;
|
---|
741 |
|
---|
742 | i = 0;
|
---|
743 | while (a[i] != NULL)
|
---|
744 | i++;
|
---|
745 | j = 0;
|
---|
746 | while (b[j] != NULL)
|
---|
747 | j++;
|
---|
748 |
|
---|
749 | all = _mesa_malloc((i + j + 1) * sizeof *all);
|
---|
750 | index = 0;
|
---|
751 | for (i = 0; a[i] != NULL; i++)
|
---|
752 | all[index++] = a[i];
|
---|
753 | for (j = 0; b[j] != NULL; j++)
|
---|
754 | all[index++] = b[j];
|
---|
755 | all[index++] = NULL;
|
---|
756 |
|
---|
757 | _mesa_free(a);
|
---|
758 | _mesa_free(b);
|
---|
759 |
|
---|
760 | return all;
|
---|
761 | }
|
---|
762 |
|
---|
763 | #define __ATTRIB(attrib, field) \
|
---|
764 | { attrib, offsetof(__GLcontextModes, field) }
|
---|
765 |
|
---|
766 | static const struct { unsigned int attrib, offset; } attribMap[] = {
|
---|
767 | __ATTRIB(__DRI_ATTRIB_BUFFER_SIZE, rgbBits),
|
---|
768 | __ATTRIB(__DRI_ATTRIB_LEVEL, level),
|
---|
769 | __ATTRIB(__DRI_ATTRIB_RED_SIZE, redBits),
|
---|
770 | __ATTRIB(__DRI_ATTRIB_GREEN_SIZE, greenBits),
|
---|
771 | __ATTRIB(__DRI_ATTRIB_BLUE_SIZE, blueBits),
|
---|
772 | __ATTRIB(__DRI_ATTRIB_ALPHA_SIZE, alphaBits),
|
---|
773 | __ATTRIB(__DRI_ATTRIB_DEPTH_SIZE, depthBits),
|
---|
774 | __ATTRIB(__DRI_ATTRIB_STENCIL_SIZE, stencilBits),
|
---|
775 | __ATTRIB(__DRI_ATTRIB_ACCUM_RED_SIZE, accumRedBits),
|
---|
776 | __ATTRIB(__DRI_ATTRIB_ACCUM_GREEN_SIZE, accumGreenBits),
|
---|
777 | __ATTRIB(__DRI_ATTRIB_ACCUM_BLUE_SIZE, accumBlueBits),
|
---|
778 | __ATTRIB(__DRI_ATTRIB_ACCUM_ALPHA_SIZE, accumAlphaBits),
|
---|
779 | __ATTRIB(__DRI_ATTRIB_SAMPLE_BUFFERS, sampleBuffers),
|
---|
780 | __ATTRIB(__DRI_ATTRIB_SAMPLES, samples),
|
---|
781 | __ATTRIB(__DRI_ATTRIB_DOUBLE_BUFFER, doubleBufferMode),
|
---|
782 | __ATTRIB(__DRI_ATTRIB_STEREO, stereoMode),
|
---|
783 | __ATTRIB(__DRI_ATTRIB_AUX_BUFFERS, numAuxBuffers),
|
---|
784 | __ATTRIB(__DRI_ATTRIB_TRANSPARENT_TYPE, transparentPixel),
|
---|
785 | __ATTRIB(__DRI_ATTRIB_TRANSPARENT_INDEX_VALUE, transparentPixel),
|
---|
786 | __ATTRIB(__DRI_ATTRIB_TRANSPARENT_RED_VALUE, transparentRed),
|
---|
787 | __ATTRIB(__DRI_ATTRIB_TRANSPARENT_GREEN_VALUE, transparentGreen),
|
---|
788 | __ATTRIB(__DRI_ATTRIB_TRANSPARENT_BLUE_VALUE, transparentBlue),
|
---|
789 | __ATTRIB(__DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE, transparentAlpha),
|
---|
790 | __ATTRIB(__DRI_ATTRIB_FLOAT_MODE, floatMode),
|
---|
791 | __ATTRIB(__DRI_ATTRIB_RED_MASK, redMask),
|
---|
792 | __ATTRIB(__DRI_ATTRIB_GREEN_MASK, greenMask),
|
---|
793 | __ATTRIB(__DRI_ATTRIB_BLUE_MASK, blueMask),
|
---|
794 | __ATTRIB(__DRI_ATTRIB_ALPHA_MASK, alphaMask),
|
---|
795 | __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_WIDTH, maxPbufferWidth),
|
---|
796 | __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_HEIGHT, maxPbufferHeight),
|
---|
797 | __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_PIXELS, maxPbufferPixels),
|
---|
798 | __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH, optimalPbufferWidth),
|
---|
799 | __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT, optimalPbufferHeight),
|
---|
800 | __ATTRIB(__DRI_ATTRIB_SWAP_METHOD, swapMethod),
|
---|
801 | __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGB, bindToTextureRgb),
|
---|
802 | __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGBA, bindToTextureRgba),
|
---|
803 | __ATTRIB(__DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE, bindToMipmapTexture),
|
---|
804 | __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS, bindToTextureTargets),
|
---|
805 | __ATTRIB(__DRI_ATTRIB_YINVERTED, yInverted),
|
---|
806 |
|
---|
807 | /* The struct field doesn't matter here, these are handled by the
|
---|
808 | * switch in driGetConfigAttribIndex. We need them in the array
|
---|
809 | * so the iterator includes them though.*/
|
---|
810 | __ATTRIB(__DRI_ATTRIB_RENDER_TYPE, level),
|
---|
811 | __ATTRIB(__DRI_ATTRIB_CONFIG_CAVEAT, level),
|
---|
812 | __ATTRIB(__DRI_ATTRIB_SWAP_METHOD, level)
|
---|
813 | };
|
---|
814 |
|
---|
815 | #define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
|
---|
816 |
|
---|
817 | static int
|
---|
818 | driGetConfigAttribIndex(const __DRIconfig *config,
|
---|
819 | unsigned int index, unsigned int *value)
|
---|
820 | {
|
---|
821 | switch (attribMap[index].attrib) {
|
---|
822 | case __DRI_ATTRIB_RENDER_TYPE:
|
---|
823 | if (config->modes.rgbMode)
|
---|
824 | *value = __DRI_ATTRIB_RGBA_BIT;
|
---|
825 | else
|
---|
826 | *value = __DRI_ATTRIB_COLOR_INDEX_BIT;
|
---|
827 | break;
|
---|
828 | case __DRI_ATTRIB_CONFIG_CAVEAT:
|
---|
829 | if (config->modes.visualRating == GLX_NON_CONFORMANT_CONFIG)
|
---|
830 | *value = __DRI_ATTRIB_NON_CONFORMANT_CONFIG;
|
---|
831 | else if (config->modes.visualRating == GLX_SLOW_CONFIG)
|
---|
832 | *value = __DRI_ATTRIB_SLOW_BIT;
|
---|
833 | else
|
---|
834 | *value = 0;
|
---|
835 | break;
|
---|
836 | case __DRI_ATTRIB_SWAP_METHOD:
|
---|
837 | break;
|
---|
838 |
|
---|
839 | case __DRI_ATTRIB_FLOAT_MODE:
|
---|
840 | *value = config->modes.floatMode;
|
---|
841 | break;
|
---|
842 |
|
---|
843 | default:
|
---|
844 | *value = *(unsigned int *)
|
---|
845 | ((char *) &config->modes + attribMap[index].offset);
|
---|
846 |
|
---|
847 | break;
|
---|
848 | }
|
---|
849 |
|
---|
850 | return GL_TRUE;
|
---|
851 | }
|
---|
852 |
|
---|
853 | int
|
---|
854 | driGetConfigAttrib(const __DRIconfig *config,
|
---|
855 | unsigned int attrib, unsigned int *value)
|
---|
856 | {
|
---|
857 | int i;
|
---|
858 |
|
---|
859 | for (i = 0; i < ARRAY_SIZE(attribMap); i++)
|
---|
860 | if (attribMap[i].attrib == attrib)
|
---|
861 | return driGetConfigAttribIndex(config, i, value);
|
---|
862 |
|
---|
863 | return GL_FALSE;
|
---|
864 | }
|
---|
865 |
|
---|
866 | int
|
---|
867 | driIndexConfigAttrib(const __DRIconfig *config, int index,
|
---|
868 | unsigned int *attrib, unsigned int *value)
|
---|
869 | {
|
---|
870 | if (index >= 0 && index < ARRAY_SIZE(attribMap)) {
|
---|
871 | *attrib = attribMap[index].attrib;
|
---|
872 | return driGetConfigAttribIndex(config, index, value);
|
---|
873 | }
|
---|
874 |
|
---|
875 | return GL_FALSE;
|
---|
876 | }
|
---|