1 /* bzflag
2 * Copyright (c) 1993-2021 Tim Riker
3 *
4 * This package is free software; you can redistribute it and/or
5 * modify it under the terms of the license found in the file
6 * named COPYING that should have accompanied this file.
7 *
8 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
9 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11 */
12
13 #include "XVisual.h"
14 #include <assert.h>
15 #include <string.h>
16 #include <GL/glx.h>
17
XVisual(const XDisplay * _display)18 XVisual::XVisual(const XDisplay* _display) :
19 display(_display->getRep()),
20 attributeCount(0),
21 visual(NULL)
22 {
23 display->ref();
24 attributes[attributeCount] = None;
25 }
26
~XVisual()27 XVisual::~XVisual()
28 {
29 if (visual) XFree(visual);
30 display->unref();
31 }
32
33 // NOTE: to keep searching simple I cheat. All bool attributes
34 // are followed by GLX_USE_GL (which is a bool and ignored)
35 // so that interesting attributes always fall on even indices.
36
setLevel(int level)37 void XVisual::setLevel(int level)
38 {
39 int index = findAttribute(GLX_LEVEL);
40 if (index == -1) appendAttribute(GLX_LEVEL, level);
41 else editAttribute(index, level);
42 }
43
setDoubleBuffer(bool on)44 void XVisual::setDoubleBuffer(bool on)
45 {
46 int index = findAttribute(GLX_DOUBLEBUFFER);
47 if (!on)
48 {
49 if (index != -1) removeAttribute(index);
50 }
51 else
52 {
53 if (index == -1) appendAttribute(GLX_DOUBLEBUFFER, GLX_USE_GL);
54 }
55 }
56
setIndex(int minDepth)57 void XVisual::setIndex(int minDepth)
58 {
59 int index = findAttribute(GLX_RGBA);
60 if (index != -1) removeAttribute(index);
61 index = findAttribute(GLX_BUFFER_SIZE);
62 if (index == -1) appendAttribute(GLX_BUFFER_SIZE, minDepth);
63 else editAttribute(index, minDepth);
64 }
65
setRGBA(int minRed,int minGreen,int minBlue,int minAlpha)66 void XVisual::setRGBA(int minRed, int minGreen,
67 int minBlue, int minAlpha)
68 {
69 int index = findAttribute(GLX_RGBA);
70 if (index == -1) appendAttribute(GLX_RGBA, GLX_USE_GL);
71 index = findAttribute(GLX_RED_SIZE);
72 if (index == -1) appendAttribute(GLX_RED_SIZE, minRed);
73 else editAttribute(index, minRed);
74 index = findAttribute(GLX_GREEN_SIZE);
75 if (index == -1) appendAttribute(GLX_GREEN_SIZE, minGreen);
76 else editAttribute(index, minGreen);
77 index = findAttribute(GLX_BLUE_SIZE);
78 if (index == -1) appendAttribute(GLX_BLUE_SIZE, minBlue);
79 else editAttribute(index, minBlue);
80 index = findAttribute(GLX_ALPHA_SIZE);
81 if (minAlpha == 0)
82 {
83 if (index != -1) removeAttribute(index);
84 }
85 else if (index == -1) appendAttribute(GLX_ALPHA_SIZE, minAlpha);
86 else editAttribute(index, minAlpha);
87 }
88
setDepth(int minDepth)89 void XVisual::setDepth(int minDepth)
90 {
91 int index = findAttribute(GLX_DEPTH_SIZE);
92 if (minDepth == 0)
93 {
94 if (index != -1) removeAttribute(index);
95 }
96 else if (index == -1) appendAttribute(GLX_DEPTH_SIZE, minDepth);
97 else editAttribute(index, minDepth);
98 }
99
setStencil(int minDepth)100 void XVisual::setStencil(int minDepth)
101
102 {
103 int index = findAttribute(GLX_STENCIL_SIZE);
104 if (minDepth == 0)
105 {
106 if (index != -1) removeAttribute(index);
107 }
108 else if (index == -1) appendAttribute(GLX_STENCIL_SIZE, minDepth);
109 else editAttribute(index, minDepth);
110 }
111
setAccum(int minRed,int minGreen,int minBlue,int minAlpha)112 void XVisual::setAccum(int minRed, int minGreen,
113 int minBlue, int minAlpha)
114 {
115 int index = findAttribute(GLX_ACCUM_RED_SIZE);
116 if (index == -1) appendAttribute(GLX_ACCUM_RED_SIZE, minRed);
117 else editAttribute(index, minRed);
118 index = findAttribute(GLX_ACCUM_GREEN_SIZE);
119 if (index == -1) appendAttribute(GLX_ACCUM_GREEN_SIZE, minGreen);
120 else editAttribute(index, minGreen);
121 index = findAttribute(GLX_ACCUM_BLUE_SIZE);
122 if (index == -1) appendAttribute(GLX_ACCUM_BLUE_SIZE, minBlue);
123 else editAttribute(index, minBlue);
124 index = findAttribute(GLX_ACCUM_ALPHA_SIZE);
125 if (index == -1) appendAttribute(GLX_ACCUM_ALPHA_SIZE, minAlpha);
126 else editAttribute(index, minAlpha);
127 }
128
setStereo(bool on)129 void XVisual::setStereo(bool on)
130 {
131 int index = findAttribute(GLX_STEREO);
132 if (!on)
133 {
134 if (index != -1) removeAttribute(index);
135 }
136 else
137 {
138 if (index == -1) appendAttribute(GLX_STEREO, GLX_USE_GL);
139 }
140 }
141
setMultisample(int minSamples)142 void XVisual::setMultisample(int minSamples)
143 {
144 (void)minSamples; // quiet compiler if ifdef'd code not used
145 #if defined(GLX_SAMPLES_SGIS) && defined(GLX_SGIS_multisample)
146 int index = findAttribute(GLX_SAMPLES_SGIS);
147 if (index == -1) appendAttribute(GLX_SAMPLES_SGIS, minSamples);
148 else editAttribute(index, minSamples);
149 #endif
150 }
151
findAttribute(int attribute) const152 int XVisual::findAttribute(int attribute) const
153 {
154 for (int i = 0; i < attributeCount; i += 2)
155 if (attributes[i] == attribute)
156 return i;
157 return -1;
158 }
159
appendAttribute(int attribute,int value)160 void XVisual::appendAttribute(int attribute, int value)
161 {
162 attributes[attributeCount] = attribute;
163 attributes[attributeCount+1] = value;
164 attributeCount += 2;
165 attributes[attributeCount] = None;
166 }
167
removeAttribute(int index)168 void XVisual::removeAttribute(int index)
169 {
170 attributeCount -= 2;
171 attributes[index] = attributes[attributeCount];
172 attributes[index+1] = attributes[attributeCount+1];
173 attributes[attributeCount] = None;
174 }
175
editAttribute(int index,int value)176 void XVisual::editAttribute(int index, int value)
177 {
178 attributes[index+1] = value;
179 }
180
build()181 bool XVisual::build()
182 {
183 if (!visual && getenv("MESA_RGB_VISUAL") == NULL)
184 {
185 // check each available visual looking for the best match.
186 // we prefer deeper and dynamic (rather than static) visuals.
187
188 // first get the list of all visuals by making a template to
189 // match any visual on the screen and matching it.
190 const long visualMask = VisualScreenMask;
191 XVisualInfo visualTemplate;
192 visualTemplate.screen = display->getScreen();
193 int numVisuals;
194 XVisualInfo* visualList = XGetVisualInfo(display->getDisplay(),
195 visualMask,
196 &visualTemplate,
197 &numVisuals);
198 if (numVisuals > 0 && visualList != NULL)
199 {
200 // no best visual so far
201 int bestVisual = -1;
202 int attrib;
203
204 // now check each visual
205 for (int i = 0; i < numVisuals; i++)
206 {
207 // ignore visuals that aren't deep enough
208 if (visualList[i].depth < 8)
209 continue;
210
211 // ignore visuals that glX can't use
212 if (glXGetConfig(display->getDisplay(), visualList + i,
213 GLX_USE_GL, &attrib) != 0 ||
214 attrib == GL_FALSE)
215 continue;
216
217 // ignore visuals that don't satisfy our requirements
218 if (!matchRequirements(visualList + i))
219 continue;
220
221 // use visual if it's better than the existing one. some visual
222 // is always better than none at all.
223 if (bestVisual == -1)
224 {
225 bestVisual = i;
226 continue;
227 }
228
229 // DirectColor is better than other visual classes, then
230 // PseudoColor, then TrueColor, then StaticColor, then GreyScale.
231 if (visualClassIsBetter(visualList[i].c_class,
232 visualList[bestVisual].c_class))
233 {
234 bestVisual = i;
235 continue;
236 }
237
238 // if visual class wasn't better and isn't the same then it
239 // must be worse.
240 if (visualList[i].c_class != visualList[bestVisual].c_class)
241 continue;
242
243 // deeper is better
244 if (visualList[i].depth > visualList[bestVisual].depth)
245 {
246 bestVisual = i;
247 continue;
248 }
249
250 // not better
251 }
252
253 // save best visual, if one was found
254 if (bestVisual != -1)
255 {
256 visual = XGetVisualInfo(display->getDisplay(),
257 VisualAllMask,
258 visualList + bestVisual,
259 &numVisuals);
260 if (numVisuals == 0)
261 visual = NULL;
262 }
263
264 // done with visuals
265 XFree(visualList);
266 }
267 }
268
269 // emergency backup plan -- let glXChooseVisual choose for us
270 if (!visual)
271 {
272 visual = glXChooseVisual(display->getDisplay(),
273 display->getScreen(), attributes);
274 }
275
276 return visual != NULL;
277 }
278
matchRequirements(XVisualInfo * v) const279 bool XVisual::matchRequirements(XVisualInfo* v) const
280 {
281 // check RGBA, DOUBLEBUFFER, and STEREO
282 int value;
283 if (glXGetConfig(display->getDisplay(), v, GLX_RGBA, &value) != 0 ||
284 (findAttribute(GLX_RGBA) != -1) != value)
285 return false;
286 if (glXGetConfig(display->getDisplay(), v, GLX_DOUBLEBUFFER, &value) != 0 ||
287 (findAttribute(GLX_DOUBLEBUFFER) != -1) != value)
288 return false;
289 if (glXGetConfig(display->getDisplay(), v, GLX_STEREO, &value) != 0 ||
290 (findAttribute(GLX_STEREO) != -1) != value)
291 return false;
292
293 // check the rest
294 for (int i = 0; i < attributeCount; i += 2)
295 {
296 // get value of desired attribute from visual
297 if (glXGetConfig(display->getDisplay(), v, attributes[i], &value) != 0)
298 return false;
299
300 // compare to desired value
301 switch (attributes[i])
302 {
303 case GLX_RGBA:
304 case GLX_DOUBLEBUFFER:
305 case GLX_STEREO:
306 // skip these
307 break;
308
309 case GLX_LEVEL:
310 if (value != attributes[i + 1])
311 return false;
312 break;
313
314 case GLX_BUFFER_SIZE:
315 case GLX_RED_SIZE:
316 case GLX_GREEN_SIZE:
317 case GLX_BLUE_SIZE:
318 case GLX_ALPHA_SIZE:
319 case GLX_DEPTH_SIZE:
320 case GLX_STENCIL_SIZE:
321 case GLX_ACCUM_RED_SIZE:
322 case GLX_ACCUM_GREEN_SIZE:
323 case GLX_ACCUM_BLUE_SIZE:
324 case GLX_ACCUM_ALPHA_SIZE:
325 #if defined(GLX_SAMPLES_SGIS) && defined(GLX_SGIS_multisample)
326 case GLX_SAMPLES_SGIS:
327 #endif
328 if (value < attributes[i + 1])
329 return false;
330 break;
331
332 default:
333 assert(0 && "unexpected GLX attribute");
334 }
335 }
336
337 return true;
338 }
339
visualClassIsBetter(int a,int b)340 bool XVisual::visualClassIsBetter(int a, int b)
341 {
342 // not better if the same
343 if (a == b)
344 return false;
345
346 // direct color is best
347 if (a == DirectColor)
348 return true;
349 if (b == DirectColor)
350 return false;
351
352 // then pseudo color (because we can adjust it)
353 if (a == PseudoColor)
354 return true;
355 if (b == PseudoColor)
356 return false;
357
358 // then true color
359 if (a == TrueColor)
360 return true;
361 if (b == TrueColor)
362 return false;
363
364 // then static color
365 if (a == StaticColor)
366 return true;
367 if (b == StaticColor)
368 return false;
369
370 // then gray scale
371 if (a == GrayScale)
372 return true;
373
374 return false;
375 }
376
get()377 XVisualInfo* XVisual::get()
378 {
379 if (!build()) return NULL;
380 return visual;
381 }
382
383 // Local Variables: ***
384 // mode: C++ ***
385 // tab-width: 4 ***
386 // c-basic-offset: 4 ***
387 // indent-tabs-mode: nil ***
388 // End: ***
389 // ex: shiftwidth=4 tabstop=4
390