1 /*
2 	vid_x11.c
3 
4 	General X11 video driver
5 
6 	Copyright (C) 1996-1997  Id Software, Inc.
7 	Copyright (C) 1999-2000  contributors of the QuakeForge project
8 	Copyright (C) 2000       Marcus Sundberg [mackan@stacken.kth.se]
9 	Copyright (C) 1999,2000  contributors of the QuakeForge project
10 	Please see the file "AUTHORS" for a list of contributors
11 
12 	This program is free software; you can redistribute it and/or
13 	modify it under the terms of the GNU General Public License
14 	as published by the Free Software Foundation; either version 2
15 	of the License, or (at your option) any later version.
16 
17 	This program is distributed in the hope that it will be useful,
18 	but WITHOUT ANY WARRANTY; without even the implied warranty of
19 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 
21 	See the GNU General Public License for more details.
22 
23 	You should have received a copy of the GNU General Public License
24 	along with this program; if not, write to:
25 
26 		Free Software Foundation, Inc.
27 		59 Temple Place - Suite 330
28 		Boston, MA  02111-1307, USA
29 
30 */
31 #define _BSD
32 
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36 
37 #ifdef HAVE_STRING_H
38 # include <string.h>
39 #endif
40 #ifdef HAVE_STRINGS_H
41 # include <strings.h>
42 #endif
43 #ifdef HAVE_UNISTD_H
44 # include <unistd.h>
45 #endif
46 
47 #include <ctype.h>
48 #include <dlfcn.h>
49 #include <errno.h>
50 #include <limits.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <sys/ipc.h>
54 #include <sys/shm.h>
55 #include <sys/time.h>
56 #include <sys/types.h>
57 #include <X11/Xatom.h>
58 #include <X11/Xlib.h>
59 #include <X11/Xutil.h>
60 #include <X11/keysym.h>
61 #include <X11/extensions/XShm.h>
62 
63 #ifdef HAVE_VIDMODE
64 # include <X11/extensions/xf86vmode.h>
65 #endif
66 
67 #include "QF/cmd.h"
68 #include "QF/console.h"
69 #include "QF/cvar.h"
70 #include "QF/qargs.h"
71 #include "QF/qendian.h"
72 #include "QF/screen.h"
73 #include "QF/sys.h"
74 #include "QF/va.h"
75 
76 #include "compat.h"
77 #include "context_x11.h"
78 #include "d_iface.h"
79 #include "dga_check.h"
80 #include "vid_internal.h"
81 
82 int XShmGetEventBase (Display *x);	// for broken X11 headers
83 
84 static GC		x_gc;
85 
86 static qboolean doShm;
87 static XShmSegmentInfo x_shminfo[2];
88 
89 static int	current_framebuffer;
90 static XImage *x_framebuffer[2] = { 0, 0 };
91 
92 int 		VID_options_items = 1;
93 
94 static byte current_palette[768];
95 
96 typedef unsigned char PIXEL8;
97 typedef unsigned short PIXEL16;
98 typedef unsigned int PIXEL24;
99 
100 static PIXEL16	st2d_8to16table[256];
101 static PIXEL24	st2d_8to24table[256];
102 static int		shiftmask_fl = 0;
103 static long 	r_shift, g_shift, b_shift;
104 static unsigned long r_mask, g_mask, b_mask;
105 
106 #define GLX_RGBA				4		// true if RGBA mode
107 #define GLX_DOUBLEBUFFER		5		// double buffering supported
108 #define GLX_RED_SIZE			8		// number of red component bits
109 #define GLX_GREEN_SIZE			9		// number of green component bits
110 #define GLX_BLUE_SIZE			10		// number of blue component bits
111 #define GLX_DEPTH_SIZE			12		// number of depth bits
112 
113 // GLXContext is a pointer to opaque data
114 typedef struct __GLXcontextRec *GLXContext;
115 typedef XID GLXDrawable;
116 
117 // Define GLAPIENTRY to a useful value
118 #ifndef GLAPIENTRY
119 # ifdef _WIN32
120 #  include <windows.h>
121 #  define GLAPIENTRY WINAPI
122 #  undef LoadImage
123 # else
124 #  ifdef APIENTRY
125 #   define GLAPIENTRY APIENTRY
126 #  else
127 #   define GLAPIENTRY
128 #  endif
129 # endif
130 #endif
131 static GLXContext ctx = NULL;
132 static void    *libgl_handle;
133 static void (*qfglXSwapBuffers) (Display *dpy, GLXDrawable drawable);
134 static XVisualInfo* (*qfglXChooseVisual) (Display *dpy, int screen,
135 										  int *attribList);
136 static GLXContext (*qfglXCreateContext) (Display *dpy, XVisualInfo *vis,
137 										 GLXContext shareList, Bool direct);
138 static Bool (*qfglXMakeCurrent) (Display *dpy, GLXDrawable drawable,
139 								 GLXContext ctx);
140 static void (GLAPIENTRY *qfglFinish) (void);
141 static void *(*glGetProcAddress) (const char *symbol) = NULL;
142 static int use_gl_procaddress = 0;
143 static cvar_t  *gl_driver;
144 
145 static void (*choose_visual) (void);
146 static void (*create_context) (void);
147 
148 static void *
QFGL_GetProcAddress(void * handle,const char * name)149 QFGL_GetProcAddress (void *handle, const char *name)
150 {
151 	void       *glfunc = NULL;
152 
153 	if (use_gl_procaddress && glGetProcAddress)
154 		glfunc = glGetProcAddress (name);
155 	if (!glfunc)
156 		glfunc = dlsym (handle, name);
157 	return glfunc;
158 }
159 
160 static void *
QFGL_ProcAddress(const char * name,qboolean crit)161 QFGL_ProcAddress (const char *name, qboolean crit)
162 {
163 	void    *glfunc = NULL;
164 
165 	Sys_MaskPrintf (SYS_VID, "DEBUG: Finding symbol %s ... ", name);
166 
167 	glfunc = QFGL_GetProcAddress (libgl_handle, name);
168 	if (glfunc) {
169 		Sys_MaskPrintf (SYS_VID, "found [%p]\n", glfunc);
170 		return glfunc;
171 	}
172 	Sys_MaskPrintf (SYS_VID, "not found\n");
173 
174 	if (crit) {
175 		if (strncmp ("fxMesa", name, 6) == 0) {
176 			Sys_Printf ("This target requires a special version of Mesa with "
177 						"support for Glide and SVGAlib.\n");
178 			Sys_Printf ("If you are in X, try using a GLX or SGL target.\n");
179 		}
180 		Sys_Error ("Couldn't load critical OpenGL function %s, exiting...",
181 				   name);
182 	}
183 	return NULL;
184 }
185 
186 static void
glx_choose_visual(void)187 glx_choose_visual (void)
188 {
189 	int         attrib[] = {
190 		GLX_RGBA,
191 		GLX_RED_SIZE, 1,
192 		GLX_GREEN_SIZE, 1,
193 		GLX_BLUE_SIZE, 1,
194 		GLX_DOUBLEBUFFER,
195 		GLX_DEPTH_SIZE, 1,
196 		None
197 	};
198 
199 	x_visinfo = qfglXChooseVisual (x_disp, x_screen, attrib);
200 	if (!x_visinfo) {
201 		Sys_Error ("Error couldn't get an RGB, Double-buffered, Depth visual");
202 	}
203 	x_vis = x_visinfo->visual;
204 }
205 
206 static void
glx_create_context(void)207 glx_create_context (void)
208 {
209 	XSync (x_disp, 0);
210 	ctx = qfglXCreateContext (x_disp, x_visinfo, NULL, True);
211 	qfglXMakeCurrent (x_disp, x_win, ctx);
212 	viddef.init_gl ();
213 }
214 
215 static void
glx_end_rendering(void)216 glx_end_rendering (void)
217 {
218 	qfglFinish ();
219 	qfglXSwapBuffers (x_disp, x_win);
220 }
221 
222 static void
glx_load_gl(void)223 glx_load_gl (void)
224 {
225 	int          flags = RTLD_NOW;
226 
227 	choose_visual = glx_choose_visual;
228 	create_context = glx_create_context;
229 
230 	viddef.get_proc_address = QFGL_ProcAddress;
231 	viddef.end_rendering = glx_end_rendering;
232 
233 #ifdef RTLD_GLOBAL
234 	flags |= RTLD_GLOBAL;
235 #endif
236 	if (!(libgl_handle = dlopen (gl_driver->string, flags))) {
237 		Sys_Error ("Couldn't load OpenGL library %s: %s", gl_driver->string,
238 				   dlerror ());
239 	}
240 	glGetProcAddress = dlsym (libgl_handle, "glXGetProcAddress");
241 	if (!glGetProcAddress)
242 		glGetProcAddress = dlsym (libgl_handle, "glXGetProcAddressARB");
243 
244 	qfglXSwapBuffers = QFGL_ProcAddress ("glXSwapBuffers", true);
245 	qfglXChooseVisual = QFGL_ProcAddress ("glXChooseVisual", true);
246 	qfglXCreateContext = QFGL_ProcAddress ("glXCreateContext", true);
247 	qfglXMakeCurrent = QFGL_ProcAddress ("glXMakeCurrent", true);
248 
249 	use_gl_procaddress = 1;
250 
251 	qfglFinish = QFGL_ProcAddress ("glFinish", true);
252 }
253 
254 static void
shiftmask_init(void)255 shiftmask_init (void)
256 {
257 	unsigned long long x;
258 
259 	r_mask = x_vis->red_mask;
260 	g_mask = x_vis->green_mask;
261 	b_mask = x_vis->blue_mask;
262 
263 	for (r_shift = -8, x = 1; x < r_mask; x <<= 1)
264 		r_shift++;
265 	for (g_shift = -8, x = 1; x < g_mask; x <<= 1)
266 		g_shift++;
267 	for (b_shift = -8, x = 1; x < b_mask; x <<= 1)
268 		b_shift++;
269 	shiftmask_fl = 1;
270 }
271 
272 static PIXEL16
xlib_rgb16(int r,int g,int b)273 xlib_rgb16 (int r, int g, int b)
274 {
275 	PIXEL16 	p = 0;
276 
277 	if (!shiftmask_fl)
278 		shiftmask_init ();
279 
280 	if (r_shift > 0) {
281 		p = (r << (r_shift)) & r_mask;
282 	} else {
283 		if (r_shift < 0) {
284 			p = (r >> (-r_shift)) & r_mask;
285 		} else {
286 			p |= (r & r_mask);
287 		}
288 	}
289 
290 	if (g_shift > 0) {
291 		p |= (g << (g_shift)) & g_mask;
292 	} else {
293 		if (g_shift < 0) {
294 			p |= (g >> (-g_shift)) & g_mask;
295 		} else {
296 			p |= (g & g_mask);
297 		}
298 	}
299 
300 	if (b_shift > 0) {
301 		p |= (b << (b_shift)) & b_mask;
302 	} else {
303 		if (b_shift < 0) {
304 			p |= (b >> (-b_shift)) & b_mask;
305 		} else {
306 			p |= (b & b_mask);
307 		}
308 	}
309 
310 	return p;
311 }
312 
313 static PIXEL24
xlib_rgb24(int r,int g,int b)314 xlib_rgb24 (int r, int g, int b)
315 {
316 	PIXEL24 	p = 0;
317 
318 	if (!shiftmask_fl)
319 		shiftmask_init ();
320 
321 	if (r_shift > 0) {
322 		p = (r << (r_shift)) & r_mask;
323 	} else {
324 		if (r_shift < 0) {
325 			p = (r >> (-r_shift)) & r_mask;
326 		} else {
327 			p |= (r & r_mask);
328 		}
329 	}
330 
331 	if (g_shift > 0) {
332 		p |= (g << (g_shift)) & g_mask;
333 	} else {
334 		if (g_shift < 0) {
335 			p |= (g >> (-g_shift)) & g_mask;
336 		} else {
337 			p |= (g & g_mask);
338 		}
339 	}
340 
341 	if (b_shift > 0) {
342 		p |= (b << (b_shift)) & b_mask;
343 	} else {
344 		if (b_shift < 0) {
345 			p |= (b >> (-b_shift)) & b_mask;
346 		} else {
347 			p |= (b & b_mask);
348 		}
349 	}
350 
351 	return p;
352 }
353 
354 static void
st2_fixup(XImage * framebuf,int x,int y,int width,int height)355 st2_fixup (XImage *framebuf, int x, int y, int width, int height)
356 {
357 	int 		xi, yi;
358 	unsigned char *src;
359 	PIXEL16 	*dest;
360 
361 	if (x < 0 || y < 0)
362 		return;
363 
364 	for (yi = y; yi < (y + height); yi++) {
365 		src = &((byte *)viddef.buffer)[yi * viddef.width];
366 		dest = (PIXEL16 *) &framebuf->data[yi * framebuf->bytes_per_line];
367 		for (xi = x; xi < x + width; xi++) {
368 			dest[xi] = st2d_8to16table[src[xi]];
369 		}
370 	}
371 }
372 
373 static void
st3_fixup(XImage * framebuf,int x,int y,int width,int height)374 st3_fixup (XImage * framebuf, int x, int y, int width, int height)
375 {
376 	int 		yi;
377 	unsigned char *src;
378 	PIXEL24 	*dest;
379 	register int count, n;
380 
381 	if (x < 0 || y < 0)
382 		return;
383 
384 	for (yi = y; yi < (y + height); yi++) {
385 		src = &((byte *)viddef.buffer)[yi * viddef.width + x];
386 		dest = (PIXEL24 *) &framebuf->data[yi * framebuf->bytes_per_line + x];
387 
388 		// Duff's Device
389 		count = width;
390 		n = (count + 7) / 8;
391 
392 		switch (count % 8) {
393 			case 0:
394 				do {
395 					*dest++ = st2d_8to24table[*src++];
396 			case 7:
397 					*dest++ = st2d_8to24table[*src++];
398 			case 6:
399 					*dest++ = st2d_8to24table[*src++];
400 			case 5:
401 					*dest++ = st2d_8to24table[*src++];
402 			case 4:
403 					*dest++ = st2d_8to24table[*src++];
404 			case 3:
405 					*dest++ = st2d_8to24table[*src++];
406 			case 2:
407 					*dest++ = st2d_8to24table[*src++];
408 			case 1:
409 					*dest++ = st2d_8to24table[*src++];
410 				} while (--n > 0);
411 		}
412 	}
413 }
414 
415 void
D_BeginDirectRect(int x,int y,byte * pbitmap,int width,int height)416 D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
417 {
418 // direct drawing of the "accessing disk" icon isn't supported
419 }
420 
421 void
D_EndDirectRect(int x,int y,int width,int height)422 D_EndDirectRect (int x, int y, int width, int height)
423 {
424 // direct drawing of the "accessing disk" icon isn't supported
425 }
426 
427 static void
ResetFrameBuffer(void)428 ResetFrameBuffer (void)
429 {
430 	int         mem, pwidth;
431 	char       *buf;
432 
433 	if (x_framebuffer[0]) {
434 		XDestroyImage (x_framebuffer[0]);
435 	}
436 
437 	pwidth = x_visinfo->depth / 8;
438 
439 	if (pwidth == 3)
440 		pwidth = 4;
441 	mem = ((viddef.width * pwidth + 7) & ~7) * viddef.height;
442 	buf = malloc (mem);
443 	SYS_CHECKMEM (buf);
444 
445 	// allocate new screen buffer
446 	x_framebuffer[0] = XCreateImage (x_disp, x_vis, x_visinfo->depth,
447 									 ZPixmap, 0, buf, viddef.width,
448 									 viddef.height, 32, 0);
449 
450 	if (!x_framebuffer[0]) {
451 		Sys_Error ("VID: XCreateImage failed");
452 	}
453 }
454 
455 static void
ResetSharedFrameBuffers(void)456 ResetSharedFrameBuffers (void)
457 {
458 	int 	size;
459 	int 	key;
460 	int 	minsize = getpagesize ();
461 	int 	frm;
462 
463 	for (frm = 0; frm < 2; frm++) {
464 
465 		// free up old frame buffer memory
466 		if (x_framebuffer[frm]) {
467 			XShmDetach (x_disp, &x_shminfo[frm]);
468 			free (x_framebuffer[frm]);
469 			shmdt (x_shminfo[frm].shmaddr);
470 		}
471 		// create the image
472 		x_framebuffer[frm] = XShmCreateImage (x_disp, x_vis, x_visinfo->depth,
473 											  ZPixmap, 0, &x_shminfo[frm],
474 											  viddef.width, viddef.height);
475 
476 		// grab shared memory
477 		size = x_framebuffer[frm]->bytes_per_line * x_framebuffer[frm]->height;
478 
479 		if (size < minsize)
480 			Sys_Error ("VID: Window must use at least %d bytes", minsize);
481 
482 		key = random ();
483 		x_shminfo[frm].shmid = shmget ((key_t) key, size, IPC_CREAT | 0777);
484 		if (x_shminfo[frm].shmid == -1)
485 			Sys_Error ("VID: Could not get any shared memory (%s)",
486 					   strerror (errno));
487 
488 		// attach to the shared memory segment
489 		x_shminfo[frm].shmaddr = (void *) shmat (x_shminfo[frm].shmid, 0, 0);
490 
491 		Sys_MaskPrintf (SYS_VID, "VID: shared memory id=%d, addr=0x%lx\n",
492 						x_shminfo[frm].shmid, (long) x_shminfo[frm].shmaddr);
493 
494 		x_framebuffer[frm]->data = x_shminfo[frm].shmaddr;
495 
496 		// get the X server to attach to it
497 		if (!XShmAttach (x_disp, &x_shminfo[frm]))
498 			Sys_Error ("VID: XShmAttach() failed");
499 		XSync (x_disp, 0);
500 		shmctl (x_shminfo[frm].shmid, IPC_RMID, 0);
501 
502 	}
503 }
504 
505 static void
x11_init_buffers(void)506 x11_init_buffers (void)
507 {
508 	if (doShm)
509 		ResetSharedFrameBuffers ();
510 	else
511 		ResetFrameBuffer ();
512 
513 	current_framebuffer = 0;
514 
515 	viddef.direct = 0;
516 	viddef.rowbytes = viddef.width;
517 	if (x_visinfo->depth != 8) {
518 		if (viddef.buffer)
519 			free (viddef.buffer);
520 		viddef.buffer = calloc (viddef.width, viddef.height);
521 		if (!viddef.buffer)
522 			Sys_Error ("Not enough memory for video mode");
523 	} else {
524 		viddef.buffer = x_framebuffer[current_framebuffer]->data;
525 	}
526 	viddef.conbuffer = viddef.buffer;
527 
528 	viddef.conrowbytes = viddef.rowbytes;
529 }
530 
531 static void
x11_choose_visual(void)532 x11_choose_visual (void)
533 {
534 	int         pnum, i;
535 	XVisualInfo template;
536 	int         num_visuals;
537 	int         template_mask;
538 
539 	template_mask = 0;
540 
541 	// specify a visual id
542 	if ((pnum = COM_CheckParm ("-visualid"))) {
543 		if (pnum >= com_argc - 1)
544 			Sys_Error ("VID: -visualid <id#>");
545 		template.visualid = atoi (com_argv[pnum + 1]);
546 		template_mask = VisualIDMask;
547 	} else {							// If not specified, use default
548 										// visual
549 		template.visualid =
550 			XVisualIDFromVisual (XDefaultVisual (x_disp, x_screen));
551 		template_mask = VisualIDMask;
552 	}
553 
554 	// pick a visual -- warn if more than one was available
555 	x_visinfo = XGetVisualInfo (x_disp, template_mask, &template,
556 								&num_visuals);
557 
558 	if (x_visinfo->depth == 8 && x_visinfo->class == PseudoColor)
559 		x_cmap = XCreateColormap (x_disp, x_win, x_vis, AllocAll);
560 	x_vis = x_visinfo->visual;
561 
562 	if (num_visuals > 1) {
563 		Sys_MaskPrintf (SYS_VID,
564 						"Found more than one visual id at depth %d:\n",
565 						template.depth);
566 		for (i = 0; i < num_visuals; i++)
567 			Sys_MaskPrintf (SYS_VID, "    -visualid %d\n",
568 							(int) x_visinfo[i].visualid);
569 	} else {
570 		if (num_visuals == 0) {
571 			if (template_mask == VisualIDMask) {
572 				Sys_Error ("VID: Bad visual ID %ld", template.visualid);
573 			} else {
574 				Sys_Error ("VID: No visuals at depth %d", template.depth);
575 			}
576 		}
577 	}
578 
579 	Sys_MaskPrintf (SYS_VID, "Using visualid %d:\n",
580 					(int) x_visinfo->visualid);
581 	Sys_MaskPrintf (SYS_VID, "    class %d\n", x_visinfo->class);
582 	Sys_MaskPrintf (SYS_VID, "    screen %d\n", x_visinfo->screen);
583 	Sys_MaskPrintf (SYS_VID, "    depth %d\n", x_visinfo->depth);
584 	Sys_MaskPrintf (SYS_VID, "    red_mask 0x%x\n",
585 					(int) x_visinfo->red_mask);
586 	Sys_MaskPrintf (SYS_VID, "    green_mask 0x%x\n",
587 					(int) x_visinfo->green_mask);
588 	Sys_MaskPrintf (SYS_VID, "    blue_mask 0x%x\n",
589 					(int) x_visinfo->blue_mask);
590 	Sys_MaskPrintf (SYS_VID, "    colormap_size %d\n",
591 					x_visinfo->colormap_size);
592 	Sys_MaskPrintf (SYS_VID, "    bits_per_rgb %d\n",
593 					x_visinfo->bits_per_rgb);
594 }
595 
596 static void
x11_create_context(void)597 x11_create_context (void)
598 {
599 	// create the GC
600 	{
601 		XGCValues   xgcvalues;
602 		int         valuemask = GCGraphicsExposures;
603 
604 		xgcvalues.graphics_exposures = False;
605 		x_gc = XCreateGC (x_disp, x_win, valuemask, &xgcvalues);
606 	}
607 
608 	// even if MITSHM is available, make sure it's a local connection
609 	if (XShmQueryExtension (x_disp)) {
610 		char       *displayname;
611 		char       *d;
612 
613 		doShm = true;
614 
615 		if ((displayname = XDisplayName (NULL))) {
616 			if ((d = strchr (displayname, ':')))
617 				*d = '\0';
618 
619 			if (!(!strcasecmp (displayname, "unix") || !*displayname))
620 				doShm = false;
621 		}
622 	}
623 
624 	if (doShm) {
625 		x_shmeventtype = XShmGetEventBase (x_disp) + ShmCompletion;
626 	}
627 
628 	viddef.do_screen_buffer = x11_init_buffers;
629 	VID_InitBuffers ();
630 
631 //  XSynchronize (x_disp, False);
632 //	X11_AddEvent (x_shmeventtype, event_shm);
633 }
634 
635 static void
VID_SetPalette(const byte * palette)636 VID_SetPalette (const byte *palette)
637 {
638 	int         i;
639 	XColor      colors[256];
640 
641 	for (i = 0; i < 256; i++) {
642 		st2d_8to16table[i] = xlib_rgb16 (palette[i * 3], palette[i * 3 + 1],
643 										 palette[i * 3 + 2]);
644 		st2d_8to24table[i] = xlib_rgb24 (palette[i * 3], palette[i * 3 + 1],
645 										 palette[i * 3 + 2]);
646 	}
647 
648 	if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8) {
649 		if (palette != current_palette) {
650 			memcpy (current_palette, palette, 768);
651 		}
652 		for (i = 0; i < 256; i++) {
653 			colors[i].pixel = i;
654 			colors[i].flags = DoRed | DoGreen | DoBlue;
655 			colors[i].red = palette[(i * 3)] << 8;
656 			colors[i].green = palette[(i * 3) + 1] << 8;
657 			colors[i].blue = palette[(i * 3) + 2] << 8;
658 		}
659 		XStoreColors (x_disp, x_cmap, colors, 256);
660 	}
661 }
662 
663 /*
664 	Set up color translation tables and the window.  Takes a 256-color 8-bit
665 	palette.  Palette data will go away after the call, so copy it if you'll
666 	need it later.
667 */
668 void
VID_Init(byte * palette,byte * colormap)669 VID_Init (byte *palette, byte *colormap)
670 {
671 	choose_visual = x11_choose_visual;
672 	create_context = x11_create_context;
673 
674 	R_LoadModule (glx_load_gl, VID_SetPalette);
675 
676 	viddef.numpages = 2;
677 	viddef.colormap8 = colormap;
678 	viddef.fullbright = 256 - viddef.colormap8[256 * VID_GRADES];
679 
680 	srandom (getpid ());
681 
682 	VID_GetWindowSize (320, 200);
683 	X11_OpenDisplay ();
684 	choose_visual ();
685 	X11_SetVidMode (viddef.width, viddef.height);
686 	X11_CreateWindow (viddef.width, viddef.height);
687 	X11_CreateNullCursor ();	// hide mouse pointer
688 	create_context ();
689 
690 	VID_InitGamma (palette);
691 	viddef.set_palette (viddef.palette);
692 
693 	Sys_MaskPrintf (SYS_VID, "Video mode %dx%d initialized.\n",
694 					viddef.width, viddef.height);
695 
696 	viddef.initialized = true;
697 	viddef.recalc_refdef = 1;			// force a surface cache flush
698 }
699 
700 void
VID_Init_Cvars()701 VID_Init_Cvars ()
702 {
703 	X11_Init_Cvars ();
704 	gl_driver = Cvar_Get ("gl_driver", GL_DRIVER, CVAR_ROM, NULL,
705 						  "The OpenGL library to use. (path optional)");
706 }
707 
708 /*
709 	VID_Shutdown
710 
711 	Restore video mode
712 */
713 void
VID_Shutdown(void)714 VID_Shutdown (void)
715 {
716 	Sys_MaskPrintf (SYS_VID, "VID_Shutdown\n");
717 	X11_CloseDisplay ();
718 }
719 
720 static int  config_notify = 0;
721 static int  config_notify_width;
722 static int  config_notify_height;
723 
724 /*
725 	VID_Update
726 
727 	Flush the given rectangles from the view buffer to the screen.
728 */
729 void
VID_Update(vrect_t * rects)730 VID_Update (vrect_t *rects)
731 {
732 	/* If the window changes dimension, skip this frame. */
733 	if (config_notify) {
734 		fprintf (stderr, "config notify\n");
735 		config_notify = 0;
736 		viddef.width = config_notify_width & ~7;
737 		viddef.height = config_notify_height;
738 
739 		VID_InitBuffers ();
740 
741 		viddef.recalc_refdef = 1;			/* force a surface cache flush */
742 		Con_CheckResize ();
743 		return;
744 	}
745 
746 	while (rects) {
747 		switch (x_visinfo->depth) {
748 			case 16:
749 				st2_fixup (x_framebuffer[current_framebuffer],
750 						   rects->x, rects->y, rects->width, rects->height);
751 				break;
752 			case 24:
753 				st3_fixup (x_framebuffer[current_framebuffer],
754 						   rects->x, rects->y, rects->width, rects->height);
755 				break;
756 		}
757 		if (doShm) {
758 			if (!XShmPutImage (x_disp, x_win, x_gc,
759 							   x_framebuffer[current_framebuffer],
760 							   rects->x, rects->y, rects->x, rects->y,
761 							   rects->width, rects->height, True)) {
762 				Sys_Error ("VID_Update: XShmPutImage failed");
763 			}
764 			oktodraw = false;
765 			while (!oktodraw)
766 				X11_ProcessEvent ();
767 			rects = rects->next;
768 
769 			current_framebuffer = !current_framebuffer;
770 		} else {
771 			if (XPutImage (x_disp, x_win, x_gc, x_framebuffer[0],
772 							rects->x, rects->y, rects->x, rects->y,
773 							rects->width, rects->height)) {
774 				Sys_Error ("VID_Update: XPutImage failed");
775 			}
776 			rects = rects->next;
777 		}
778 	}
779 	XSync (x_disp, False);
780 	r_data->scr_fullupdate = 0;
781 }
782 
783 void
VID_LockBuffer(void)784 VID_LockBuffer (void)
785 {
786 }
787 
788 void
VID_UnlockBuffer(void)789 VID_UnlockBuffer (void)
790 {
791 }
792 
793 void
VID_SetCaption(const char * text)794 VID_SetCaption (const char *text)
795 {
796 	if (text && *text) {
797 		char       *temp = strdup (text);
798 
799 		X11_SetCaption (va ("%s: %s", PACKAGE_STRING, temp));
800 		free (temp);
801 	} else {
802 		X11_SetCaption (va ("%s", PACKAGE_STRING));
803 	}
804 }
805 
806 qboolean
VID_SetGamma(double gamma)807 VID_SetGamma (double gamma)
808 {
809 	return X11_SetGamma (gamma);
810 }
811