1 // Copyright (C)2009-2021 D. R. Commander
2 //
3 // This library is free software and may be redistributed and/or modified under
4 // the terms of the wxWindows Library License, Version 3.1 or (at your option)
5 // any later version.  The full license is in the LICENSE.txt file included
6 // with this distribution.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // wxWindows Library License for more details.
12 
13 #include <ctype.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include <math.h>
17 #include "Error.h"
18 #include "Log.h"
19 #include "Mutex.h"
20 #include "fakerconfig.h"
21 #include <stdio.h>
22 #include <X11/keysym.h>
23 #if FCONFIG_USESHM == 1
24 	#include <sys/shm.h>
25 	#include <sys/ipc.h>
26 	#include <sys/types.h>
27 #endif
28 #include "vglutil.h"
29 #include <X11/Xatom.h>
30 #ifdef USEXV
31 	#include <X11/extensions/Xv.h>
32 	#include <X11/extensions/Xvlib.h>
33 #endif
34 #ifdef USEHELGRIND
35 	#include <valgrind/helgrind.h>
36 #endif
37 
38 using namespace vglutil;
39 
40 
41 #define DEFQUAL  95
42 
43 static FakerConfig fconfig_env;
44 static bool fconfig_envset = false;
45 
46 #if FCONFIG_USESHM == 1
47 static int fconfig_shmid = -1;
fconfig_getshmid(void)48 int fconfig_getshmid(void) { return fconfig_shmid; }
49 #endif
50 static FakerConfig *fconfig_instance = NULL;
51 
52 
53 // This is a hack necessary to defer the initialization of the recursive mutex
54 // so MainWin will not interfere with it
55 
56 class DeferredCS : CriticalSection
57 {
58 	public:
DeferredCS()59 		DeferredCS() : isInit(false) {}
60 
init(void)61 		DeferredCS *init(void)
62 		{
63 			if(!isInit)
64 			{
65 				isInit = true;
66 				pthread_mutexattr_t ma;
67 				pthread_mutexattr_init(&ma);
68 				pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE);
69 				pthread_mutex_init(&mutex, &ma);
70 				pthread_mutexattr_destroy(&ma);
71 			}
72 			return this;
73 		}
74 
75 	private:
76 
77 		bool isInit;
78 };
79 
80 static DeferredCS fconfig_mutex;
81 #define fcmutex  ((CriticalSection &)(*fconfig_mutex.init()))
82 
83 
84 static void fconfig_init(void);
85 
86 
fconfig_getinstance(void)87 FakerConfig *fconfig_getinstance(void)
88 {
89 	if(fconfig_instance == NULL)
90 	{
91 		CriticalSection::SafeLock l(fcmutex);
92 		if(fconfig_instance == NULL)
93 		{
94 			#if FCONFIG_USESHM == 1
95 
96 			void *addr = NULL;
97 			if((fconfig_shmid = shmget(IPC_PRIVATE, sizeof(FakerConfig),
98 				IPC_CREAT | 0600)) == -1)
99 				THROW_UNIX();
100 			if((addr = shmat(fconfig_shmid, 0, 0)) == (void *)-1) THROW_UNIX();
101 			if(!addr)
102 				THROW("Could not attach to config structure in shared memory");
103 			#ifndef sun
104 			shmctl(fconfig_shmid, IPC_RMID, 0);
105 			#endif
106 			char *env = NULL;
107 			if((env = getenv("VGL_VERBOSE")) != NULL && strlen(env) > 0
108 				&& !strncmp(env, "1", 1))
109 				vglout.println("[VGL] Shared memory segment ID for vglconfig: %d",
110 					fconfig_shmid);
111 			fconfig_instance = (FakerConfig *)addr;
112 
113 			#else
114 
115 			fconfig_instance = new FakerConfig;
116 			if(!fconfig_instance) THROW("Could not allocate config structure");
117 
118 			#endif
119 
120 			fconfig_init();
121 		}
122 	}
123 	return fconfig_instance;
124 }
125 
126 
fconfig_deleteinstance(CriticalSection * mutex)127 void fconfig_deleteinstance(CriticalSection *mutex)
128 {
129 	if(fconfig_instance != NULL)
130 	{
131 		CriticalSection::SafeLock l(mutex ? *mutex : fcmutex, false);
132 		if(fconfig_instance != NULL)
133 		{
134 			#if FCONFIG_USESHM == 1
135 
136 			shmdt((char *)fconfig_instance);
137 			if(fconfig_shmid != -1)
138 			{
139 				int ret = shmctl(fconfig_shmid, IPC_RMID, 0);
140 				char *env = NULL;
141 				if((env = getenv("VGL_VERBOSE")) != NULL && strlen(env) > 0
142 					&& !strncmp(env, "1", 1) && ret != -1)
143 					vglout.println("[VGL] Removed shared memory segment %d",
144 						fconfig_shmid);
145 			}
146 
147 			#else
148 
149 			delete fconfig_instance;
150 
151 			#endif
152 
153 			fconfig_instance = NULL;
154 		}
155 	}
156 }
157 
158 
fconfig_init(void)159 static void fconfig_init(void)
160 {
161 	CriticalSection::SafeLock l(fcmutex);
162 	memset(&fconfig, 0, sizeof(FakerConfig));
163 	memset(&fconfig_env, 0, sizeof(FakerConfig));
164 	fconfig.compress = -1;
165 	strncpy(fconfig.config, VGLCONFIG_PATH, MAXSTR);
166 	#ifdef sun
167 	fconfig.dlsymloader = true;
168 	#endif
169 	#ifdef FAKEXCB
170 	fconfig.fakeXCB = 1;
171 	#endif
172 	fconfig.forcealpha = 0;
173 	fconfig_setgamma(fconfig, 1.0);
174 	fconfig.glflushtrigger = 1;
175 	fconfig.gui = 1;
176 	fconfig.guikey = XK_F9;
177 	fconfig.guimod = ShiftMask | ControlMask;
178 	fconfig.interframe = 1;
179 	strncpy(fconfig.localdpystring, ":0", MAXSTR);
180 	fconfig.np = 1;
181 	fconfig.port = -1;
182 	fconfig.probeglx = 1;
183 	fconfig.qual = DEFQUAL;
184 	fconfig.readback = RRREAD_PBO;
185 	fconfig.refreshrate = 60.0;
186 	fconfig.samples = -1;
187 	fconfig.spoil = 1;
188 	fconfig.spoillast = 1;
189 	fconfig.stereo = RRSTEREO_QUADBUF;
190 	fconfig.subsamp = -1;
191 	fconfig.tilesize = RR_DEFAULTTILESIZE;
192 	fconfig.transpixel = -1;
193 	fconfig_reloadenv();
194 	#ifdef USEHELGRIND
195 	ANNOTATE_BENIGN_RACE_SIZED(&fconfig.egl, sizeof(bool), );
196 	ANNOTATE_BENIGN_RACE_SIZED(&fconfig.flushdelay, sizeof(double), );
197 	#endif
198 }
199 
200 
fconfig_buildlut(FakerConfig & fc)201 static void fconfig_buildlut(FakerConfig &fc)
202 {
203 	if(fc.gamma != 0.0 && fc.gamma != 1.0 && fc.gamma != -1.0)
204 	{
205 		double g = fc.gamma > 0.0 ? 1.0 / fc.gamma : -fc.gamma;
206 		for(int i = 0; i < 256; i++)
207 			fc.gamma_lut[i] = (unsigned char)(255. * pow((double)i / 255., g) + 0.5);
208 		for(int i = 0; i < 1024; i++)
209 			fc.gamma_lut10[i] =
210 				(unsigned short)(1023. * pow((double)i / 1023., g) + 0.5);
211 		for(int i = 0; i < 65536; i++)
212 		{
213 			fc.gamma_lut16[i] =
214 				(unsigned short)(255. * pow((double)(i / 256) / 255., g) + 0.5) << 8;
215 			fc.gamma_lut16[i] |=
216 				(unsigned short)(255. * pow((double)(i % 256) / 255., g) + 0.5);
217 		}
218 	}
219 }
220 
221 
222 #define FETCHENV_STR(envvar, s) \
223 { \
224 	if((env = getenv(envvar)) != NULL && strlen(env) > 0 \
225 		&& (!fconfig_envset || strncmp(env, fconfig_env.s, MAXSTR - 1))) \
226 	{ \
227 		strncpy(fconfig.s, env, MAXSTR - 1); \
228 		strncpy(fconfig_env.s, env, MAXSTR - 1); \
229 	} \
230 }
231 
232 #define FETCHENV_BOOL(envvar, b) \
233 { \
234 	if((env = getenv(envvar)) != NULL && strlen(env) > 0) \
235 	{ \
236 		if(!strncmp(env, "1", 1) && (!fconfig_envset || fconfig_env.b != 1)) \
237 			fconfig.b = fconfig_env.b = 1; \
238 		else if(!strncmp(env, "0", 1) && (!fconfig_envset || fconfig_env.b != 0)) \
239 			fconfig.b = fconfig_env.b = 0; \
240 	} \
241 }
242 
243 #define FETCHENV_INT(envvar, i, min, max) \
244 { \
245 	if((env = getenv(envvar)) != NULL && strlen(env) > 0) \
246 	{ \
247 		char *t = NULL;  int itemp = strtol(env, &t, 10); \
248 		if(t && t != env && itemp >= min && itemp <= max \
249 			&& (!fconfig_envset || itemp != fconfig_env.i)) \
250 			fconfig.i = fconfig_env.i = itemp; \
251 	} \
252 }
253 
254 #define FETCHENV_DBL(envvar, d, min, max) \
255 { \
256 	char *temp = NULL; \
257 	if((temp = getenv(envvar)) != NULL && strlen(temp) > 0) \
258 	{ \
259 		char *t = NULL;  double dtemp = strtod(temp, &t); \
260 		if(t && t != temp && dtemp >= min && dtemp <= max \
261 			&& (!fconfig_envset || dtemp != fconfig_env.d)) \
262 			fconfig.d = fconfig_env.d = dtemp; \
263 	} \
264 }
265 
266 
fconfig_setgamma(FakerConfig & fc,double gamma)267 void fconfig_setgamma(FakerConfig &fc, double gamma)
268 {
269 	fc.gamma = gamma;
270 	fconfig_buildlut(fc);
271 }
272 
273 
fconfig_reloadenv(void)274 void fconfig_reloadenv(void)
275 {
276 	char *env;
277 
278 	CriticalSection::SafeLock l(fcmutex);
279 
280 	FETCHENV_BOOL("VGL_ALLOWINDIRECT", allowindirect);
281 	FETCHENV_BOOL("VGL_AMDGPUHACK", amdgpuHack);
282 	FETCHENV_BOOL("VGL_AUTOTEST", autotest);
283 	FETCHENV_STR("VGL_CLIENT", client);
284 	if((env = getenv("VGL_SUBSAMP")) != NULL && strlen(env) > 0)
285 	{
286 		int subsamp = -1;
287 		if(!strnicmp(env, "G", 1)) subsamp = 0;
288 		else
289 		{
290 			char *t = NULL;  int itemp = strtol(env, &t, 10);
291 			if(t && t != env)
292 			{
293 				switch(itemp)
294 				{
295 					case 0:                              subsamp = 0;  break;
296 					case 444: case 11: case 1:           subsamp = 1;  break;
297 					case 422: case 21: case 2:           subsamp = 2;  break;
298 					case 411: case 420: case 22: case 4: subsamp = 4;  break;
299 					case 410: case 42: case 8:           subsamp = 8;  break;
300 					case 44:  case 16:                   subsamp = 16;  break;
301 				}
302 			}
303 		}
304 		if(subsamp >= 0 && (!fconfig_envset || fconfig_env.subsamp != subsamp))
305 			fconfig.subsamp = fconfig_env.subsamp = subsamp;
306 	}
307 	FETCHENV_STR("VGL_TRANSPORT", transport);
308 	if((env = getenv("VGL_COMPRESS")) != NULL && strlen(env) > 0)
309 	{
310 		char *t = NULL;  int itemp = strtol(env, &t, 10);
311 		int compress = -1;
312 		if(t && t != env && itemp >= 0
313 			&& (itemp < RR_COMPRESSOPT || strlen(fconfig.transport) > 0))
314 			compress = itemp;
315 		else if(!strnicmp(env, "p", 1)) compress = RRCOMP_PROXY;
316 		else if(!strnicmp(env, "j", 1)) compress = RRCOMP_JPEG;
317 		else if(!strnicmp(env, "r", 1)) compress = RRCOMP_RGB;
318 		else if(!strnicmp(env, "x", 1)) compress = RRCOMP_XV;
319 		else if(!strnicmp(env, "y", 1)) compress = RRCOMP_YUV;
320 		if(compress >= 0 && (!fconfig_envset || fconfig_env.compress != compress))
321 		{
322 			fconfig_setcompress(fconfig, compress);
323 			fconfig_env.compress = compress;
324 		}
325 	}
326 	FETCHENV_STR("VGL_CONFIG", config);
327 	FETCHENV_STR("VGL_DEFAULTFBCONFIG", defaultfbconfig);
328 	if((env = getenv("VGL_DISPLAY")) != NULL && strlen(env) > 0)
329 	{
330 		if(!fconfig_envset || strncmp(env, fconfig_env.localdpystring, MAXSTR - 1))
331 		{
332 			strncpy(fconfig.localdpystring, env, MAXSTR - 1);
333 			strncpy(fconfig_env.localdpystring, env, MAXSTR - 1);
334 		}
335 		if((env[0] == '/' || !strnicmp(env, "EGL", 3)))
336 			fconfig.egl = true;
337 	}
338 	FETCHENV_BOOL("VGL_DLSYM", dlsymloader);
339 	#ifdef EGLBACKEND
340 	FETCHENV_STR("VGL_EGLLIB", egllib);
341 	#endif
342 	FETCHENV_STR("VGL_EXCLUDE", excludeddpys);
343 	#ifdef FAKEXCB
344 	FETCHENV_BOOL("VGL_FAKEXCB", fakeXCB);
345 	#endif
346 	FETCHENV_BOOL("VGL_FORCEALPHA", forcealpha);
347 	FETCHENV_DBL("VGL_FPS", fps, 0.0, 1000000.0);
348 	if((env = getenv("VGL_GAMMA")) != NULL && strlen(env) > 0)
349 	{
350 		if(!strcmp(env, "1"))
351 		{
352 			if(!fconfig_envset || fconfig_env.gamma != 2.22)
353 			{
354 				fconfig_env.gamma = 2.22;
355 				fconfig_setgamma(fconfig, 2.22);
356 			}
357 		}
358 		else if(!strcmp(env, "0"))
359 		{
360 			if(!fconfig_envset || fconfig_env.gamma != 1.0)
361 			{
362 				fconfig_env.gamma = 1.0;
363 				fconfig_setgamma(fconfig, 1.0);
364 			}
365 		}
366 		else
367 		{
368 			char *t = NULL;  double dtemp = strtod(env, &t);
369 			if(t && t != env
370 				&& (!fconfig_envset || fconfig_env.gamma != dtemp))
371 			{
372 				fconfig_env.gamma = dtemp;
373 				fconfig_setgamma(fconfig, dtemp);
374 			}
375 		}
376 	}
377 	FETCHENV_BOOL("VGL_GLFLUSHTRIGGER", glflushtrigger);
378 	FETCHENV_STR("VGL_GLLIB", gllib);
379 	FETCHENV_STR("VGL_GLXVENDOR", glxvendor);
380 	FETCHENV_STR("VGL_GUI", guikeyseq);
381 	if(strlen(fconfig.guikeyseq) > 0)
382 	{
383 		if(!stricmp(fconfig.guikeyseq, "none")) fconfig.gui = false;
384 		else
385 		{
386 			unsigned int mod = 0, key = 0;
387 			for(unsigned int i = 0; i < strlen(fconfig.guikeyseq); i++)
388 				fconfig.guikeyseq[i] = tolower(fconfig.guikeyseq[i]);
389 			if(strstr(fconfig.guikeyseq, "ctrl")) mod |= ControlMask;
390 			if(strstr(fconfig.guikeyseq, "alt")) mod |= Mod1Mask;
391 			if(strstr(fconfig.guikeyseq, "shift")) mod |= ShiftMask;
392 			if(strstr(fconfig.guikeyseq, "f10")) key = XK_F10;
393 			else if(strstr(fconfig.guikeyseq, "f11")) key = XK_F11;
394 			else if(strstr(fconfig.guikeyseq, "f12")) key = XK_F12;
395 			else if(strstr(fconfig.guikeyseq, "f1")) key = XK_F1;
396 			else if(strstr(fconfig.guikeyseq, "f2")) key = XK_F2;
397 			else if(strstr(fconfig.guikeyseq, "f3")) key = XK_F3;
398 			else if(strstr(fconfig.guikeyseq, "f4")) key = XK_F4;
399 			else if(strstr(fconfig.guikeyseq, "f5")) key = XK_F5;
400 			else if(strstr(fconfig.guikeyseq, "f6")) key = XK_F6;
401 			else if(strstr(fconfig.guikeyseq, "f7")) key = XK_F7;
402 			else if(strstr(fconfig.guikeyseq, "f8")) key = XK_F8;
403 			else if(strstr(fconfig.guikeyseq, "f9")) key = XK_F9;
404 			if(key) fconfig.guikey = key;  fconfig.guimod = mod;
405 			fconfig.gui = true;
406 		}
407 	}
408 	FETCHENV_BOOL("VGL_INTERFRAME", interframe);
409 	FETCHENV_STR("VGL_LOG", log);
410 	FETCHENV_BOOL("VGL_LOGO", logo);
411 	FETCHENV_INT("VGL_NPROCS", np, 1, min(NumProcs(), MAXPROCS));
412 	#ifdef FAKEOPENCL
413 	FETCHENV_STR("VGL_OCLLIB", ocllib);
414 	#endif
415 	FETCHENV_INT("VGL_PORT", port, 0, 65535);
416 	FETCHENV_BOOL("VGL_PROBEGLX", probeglx);
417 	FETCHENV_INT("VGL_QUAL", qual, 1, 100);
418 	if((env = getenv("VGL_READBACK")) != NULL && strlen(env) > 0)
419 	{
420 		int readback = -1;
421 		if(!strnicmp(env, "N", 1)) readback = RRREAD_NONE;
422 		else if(!strnicmp(env, "P", 1)) readback = RRREAD_PBO;
423 		else if(!strnicmp(env, "S", 1)) readback = RRREAD_SYNC;
424 		else
425 		{
426 			char *t = NULL;  int itemp = strtol(env, &t, 10);
427 			if(t && t != env && itemp >= 0 && itemp < RR_READBACKOPT)
428 				readback = itemp;
429 		}
430 		if(readback >= 0 && (!fconfig_envset || fconfig_env.readback != readback))
431 			fconfig.readback = fconfig_env.readback = readback;
432 	}
433 	FETCHENV_DBL("VGL_REFRESHRATE", refreshrate, 0.0, 1000000.0);
434 	FETCHENV_INT("VGL_SAMPLES", samples, 0, 64);
435 	FETCHENV_BOOL("VGL_SPOIL", spoil);
436 	FETCHENV_BOOL("VGL_SPOILLAST", spoillast);
437 	FETCHENV_BOOL("VGL_SSL", ssl);
438 	{
439 		if((env = getenv("VGL_STEREO")) != NULL && strlen(env) > 0)
440 		{
441 			int stereo = -1;
442 			if(!strnicmp(env, "L", 1)) stereo = RRSTEREO_LEYE;
443 			else if(!strnicmp(env, "RC", 2)) stereo = RRSTEREO_REDCYAN;
444 			else if(!strnicmp(env, "R", 1)) stereo = RRSTEREO_REYE;
445 			else if(!strnicmp(env, "Q", 1)) stereo = RRSTEREO_QUADBUF;
446 			else if(!strnicmp(env, "GM", 2)) stereo = RRSTEREO_GREENMAGENTA;
447 			else if(!strnicmp(env, "BY", 2)) stereo = RRSTEREO_BLUEYELLOW;
448 			else if(!strnicmp(env, "I", 2)) stereo = RRSTEREO_INTERLEAVED;
449 			else if(!strnicmp(env, "TB", 2)) stereo = RRSTEREO_TOPBOTTOM;
450 			else if(!strnicmp(env, "SS", 2)) stereo = RRSTEREO_SIDEBYSIDE;
451 			else
452 			{
453 				char *t = NULL;  int itemp = strtol(env, &t, 10);
454 				if(t && t != env && itemp >= 0 && itemp < RR_STEREOOPT) stereo = itemp;
455 			}
456 			if(stereo >= 0 && (!fconfig_envset || fconfig_env.stereo != stereo))
457 				fconfig.stereo = fconfig_env.stereo = stereo;
458 		}
459 	}
460 	FETCHENV_BOOL("VGL_SYNC", sync);
461 	FETCHENV_INT("VGL_TILESIZE", tilesize, 8, 1024);
462 	FETCHENV_BOOL("VGL_TRACE", trace);
463 	FETCHENV_INT("VGL_TRANSPIXEL", transpixel, 0, 255);
464 	FETCHENV_BOOL("VGL_TRAPX11", trapx11);
465 	FETCHENV_STR("VGL_XVENDOR", vendor);
466 	FETCHENV_BOOL("VGL_VERBOSE", verbose);
467 	FETCHENV_BOOL("VGL_WM", wm);
468 	FETCHENV_STR("VGL_X11LIB", x11lib);
469 	#ifdef FAKEXCB
470 	FETCHENV_STR("VGL_XCBLIB", xcblib);
471 	FETCHENV_STR("VGL_XCBGLXLIB", xcbglxlib);
472 	FETCHENV_STR("VGL_XCBKEYSYMSLIB", xcbkeysymslib);
473 	FETCHENV_STR("VGL_XCBX11LIB", xcbkeysymslib);
474 	#endif
475 
476 	if(strlen(fconfig.transport) > 0)
477 	{
478 		if(fconfig.compress < 0) fconfig.compress = 0;
479 		if(fconfig.subsamp < 0) fconfig.subsamp = 1;
480 	}
481 
482 	fconfig_envset = true;
483 }
484 
485 
fconfig_setdefaultsfromdpy(Display * dpy)486 void fconfig_setdefaultsfromdpy(Display *dpy)
487 {
488 	CriticalSection::SafeLock l(fcmutex);
489 
490 	if(fconfig.compress < 0)
491 	{
492 		bool useSunRay = false;
493 		Atom atom = None;
494 		if((atom = XInternAtom(dpy, "_SUN_SUNRAY_SESSION", True)) != None)
495 			useSunRay = true;
496 		const char *dstr = DisplayString(dpy);
497 		if((strlen(dstr) && dstr[0] == ':') || (strlen(dstr) > 5
498 			&& !strnicmp(dstr, "unix", 4)))
499 		{
500 			if(useSunRay) fconfig_setcompress(fconfig, RRCOMP_XV);
501 			else fconfig_setcompress(fconfig, RRCOMP_PROXY);
502 		}
503 		else
504 		{
505 			if(useSunRay) fconfig_setcompress(fconfig, RRCOMP_YUV);
506 			else fconfig_setcompress(fconfig, RRCOMP_JPEG);
507 		}
508 	}
509 
510 	if(fconfig.port < 0)
511 	{
512 		#ifdef USESSL
513 		fconfig.port = fconfig.ssl ? RR_DEFAULTSSLPORT : RR_DEFAULTPORT;
514 		#else
515 		fconfig.port = RR_DEFAULTPORT;
516 		#endif
517 		Atom atom = None;  unsigned long n = 0, bytesLeft = 0;
518 		int actualFormat = 0;  Atom actualType = None;
519 		unsigned char *prop = NULL;
520 		if((atom = XInternAtom(dpy,
521 			fconfig.ssl ? "_VGLCLIENT_SSLPORT" : "_VGLCLIENT_PORT", True)) != None)
522 		{
523 			if(XGetWindowProperty(dpy, RootWindow(dpy, DefaultScreen(dpy)), atom, 0,
524 				1, False, XA_INTEGER, &actualType, &actualFormat, &n, &bytesLeft,
525 				&prop) == Success && n >= 1 && actualFormat == 16
526 				&& actualType == XA_INTEGER && prop)
527 				fconfig.port = *(unsigned short *)prop;
528 			if(prop) XFree(prop);
529 		}
530 	}
531 
532 	#ifdef USEXV
533 
534 	int k, port, nformats, dummy1, dummy2, dummy3;
535 	unsigned int i, j, nadaptors = 0;
536 	XvAdaptorInfo *ai = NULL;
537 	XvImageFormatValues *ifv = NULL;
538 
539 	if(XQueryExtension(dpy, "XVideo", &dummy1, &dummy2, &dummy3)
540 		&& XvQueryAdaptors(dpy, DefaultRootWindow(dpy), &nadaptors,
541 		&ai) == Success && nadaptors >= 1 && ai)
542 	{
543 		port = -1;
544 		for(i = 0; i < nadaptors; i++)
545 		{
546 			for(j = ai[i].base_id; j < ai[i].base_id + ai[i].num_ports; j++)
547 			{
548 				nformats = 0;
549 				ifv = XvListImageFormats(dpy, j, &nformats);
550 				if(ifv && nformats > 0)
551 				{
552 					for(k = 0; k < nformats; k++)
553 					{
554 						if(ifv[k].id == 0x30323449)
555 						{
556 							XFree(ifv);  port = j;
557 							goto found;
558 						}
559 					}
560 				}
561 				XFree(ifv);
562 			}
563 		}
564 		found:
565 		XvFreeAdaptorInfo(ai);  ai = NULL;
566 		if(port != -1) fconfig.transvalid[RRTRANS_XV] = 1;
567 	}
568 
569 	#endif
570 }
571 
572 
fconfig_setcompress(FakerConfig & fc,int i)573 void fconfig_setcompress(FakerConfig &fc, int i)
574 {
575 	if(i < 0 || (i >= RR_COMPRESSOPT && strlen(fc.transport) == 0)) return;
576 	CriticalSection::SafeLock l(fcmutex);
577 
578 	bool is = (fc.compress >= 0);
579 	fc.compress = i;
580 	if(strlen(fc.transport) > 0) return;
581 	if(!is) fc.transvalid[_Trans[fc.compress]] = fc.transvalid[RRTRANS_X11] = 1;
582 	if(fc.subsamp < 0) fc.subsamp = _Defsubsamp[fc.compress];
583 	if(strlen(fc.transport) == 0 && _Minsubsamp[fc.compress] >= 0
584 		&& _Maxsubsamp[fc.compress] >= 0)
585 	{
586 		if(fc.subsamp < _Minsubsamp[fc.compress]
587 			|| fc.subsamp > _Maxsubsamp[fc.compress])
588 			fc.subsamp = _Defsubsamp[fc.compress];
589 	}
590 }
591 
592 
593 #define PRCONF_INT(i)  vglout.println(#i "  =  %d", fc.i)
594 #define PRCONF_STR(s) \
595 	vglout.println(#s "  =  \"%s\"", strlen(fc.s) > 0 ? fc.s : "{Empty}")
596 #define PRCONF_DBL(d)  vglout.println(#d "  =  %f", fc.d)
597 
fconfig_print(FakerConfig & fc)598 void fconfig_print(FakerConfig &fc)
599 {
600 	PRCONF_INT(allowindirect);
601 	PRCONF_INT(amdgpuHack);
602 	PRCONF_STR(client);
603 	PRCONF_INT(compress);
604 	PRCONF_STR(config);
605 	PRCONF_STR(defaultfbconfig);
606 	PRCONF_INT(dlsymloader);
607 	#ifdef EGLBACKEND
608 	PRCONF_INT(egl);
609 	PRCONF_STR(egllib);
610 	#endif
611 	PRCONF_STR(excludeddpys);
612 	PRCONF_DBL(fps);
613 	PRCONF_DBL(flushdelay);
614 	PRCONF_INT(forcealpha);
615 	PRCONF_DBL(gamma);
616 	PRCONF_INT(glflushtrigger);
617 	PRCONF_STR(gllib);
618 	PRCONF_STR(glxvendor);
619 	PRCONF_INT(gui);
620 	PRCONF_INT(guikey);
621 	PRCONF_STR(guikeyseq);
622 	PRCONF_INT(guimod);
623 	PRCONF_INT(interframe);
624 	PRCONF_STR(localdpystring);
625 	PRCONF_STR(log);
626 	PRCONF_INT(logo);
627 	PRCONF_INT(np);
628 	#ifdef FAKEOPENCL
629 	PRCONF_STR(ocllib);
630 	#endif
631 	PRCONF_INT(port);
632 	PRCONF_INT(qual);
633 	PRCONF_INT(readback);
634 	PRCONF_INT(samples);
635 	PRCONF_INT(spoil);
636 	PRCONF_INT(spoillast);
637 	PRCONF_INT(ssl);
638 	PRCONF_INT(stereo);
639 	PRCONF_INT(subsamp);
640 	PRCONF_INT(sync);
641 	PRCONF_INT(tilesize);
642 	PRCONF_INT(trace);
643 	PRCONF_INT(transpixel);
644 	PRCONF_INT(transvalid[RRTRANS_X11]);
645 	PRCONF_INT(transvalid[RRTRANS_VGL]);
646 	PRCONF_INT(transvalid[RRTRANS_XV]);
647 	PRCONF_INT(trapx11);
648 	PRCONF_STR(vendor);
649 	PRCONF_INT(verbose);
650 	PRCONF_INT(wm);
651 	PRCONF_STR(x11lib);
652 	#ifdef FAKEXCB
653 	PRCONF_STR(xcblib);
654 	PRCONF_STR(xcbglxlib);
655 	PRCONF_STR(xcbkeysymslib);
656 	PRCONF_STR(xcbx11lib);
657 	#endif
658 }
659