1 // Copyright (C)2004 Landmark Graphics Corporation
2 // Copyright (C)2005, 2006 Sun Microsystems, Inc.
3 // Copyright (C)2009, 2011-2012, 2015, 2018-2021 D. R. Commander
4 //
5 // This library is free software and may be redistributed and/or modified under
6 // the terms of the wxWindows Library License, Version 3.1 or (at your option)
7 // any later version.  The full license is in the LICENSE.txt file included
8 // with this distribution.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // wxWindows Library License for more details.
14 
15 // Interposed OpenGL functions
16 
17 #include <math.h>
18 #include "ContextHash.h"
19 #include "WindowHash.h"
20 #include "faker.h"
21 
22 
doGLReadback(bool spoilLast,bool sync)23 static void doGLReadback(bool spoilLast, bool sync)
24 {
25 	GLXDrawable drawable = VGLGetCurrentDrawable();
26 	if(!drawable) return;
27 
28 	vglfaker::VirtualWin *vw;
29 	if((vw = winhash.find(NULL, drawable)) != NULL)
30 	{
31 		if(DrawingToFront() || vw->dirty)
32 		{
33 				OPENTRACE(doGLReadback);  PRARGX(vw->getGLXDrawable());
34 				PRARGI(sync);  PRARGI(spoilLast);  STARTTRACE();
35 
36 			vw->readback(GL_FRONT, spoilLast, sync);
37 
38 				STOPTRACE();  CLOSETRACE();
39 		}
40 	}
41 }
42 
43 
44 extern "C" {
45 
46 // VirtualGL reads back and transports the contents of the front buffer if
47 // something has been rendered to it since the last readback and one of the
48 // following functions is called to signal the end of a frame.
49 
glFinish(void)50 void glFinish(void)
51 {
52 	if(vglfaker::getExcludeCurrent()) { _glFinish();  return; }
53 
54 	TRY();
55 
56 		if(fconfig.trace) vglout.print("[VGL] glFinish()\n");
57 
58 	DISABLE_FAKER();
59 
60 	_glFinish();
61 	fconfig.flushdelay = 0.;
62 	doGLReadback(false, fconfig.sync);
63 
64 	CATCH();
65 	ENABLE_FAKER();
66 }
67 
68 
glFlush(void)69 void glFlush(void)
70 {
71 	static double lastTime = -1.;  double thisTime;
72 
73 	if(vglfaker::getExcludeCurrent()) { _glFlush();  return; }
74 
75 	TRY();
76 
77 		if(fconfig.trace) vglout.print("[VGL] glFlush()\n");
78 
79 	DISABLE_FAKER();
80 
81 	_glFlush();
82 	if(lastTime < 0.) lastTime = GetTime();
83 	else
84 	{
85 		thisTime = GetTime() - lastTime;
86 		if(thisTime - lastTime < 0.01) fconfig.flushdelay = 0.01;
87 		else fconfig.flushdelay = 0.;
88 	}
89 
90 	// See the notes regarding VGL_SPOILLAST and VGL_GLFLUSHTRIGGER in the
91 	// VirtualGL User's Guide.
92 	if(fconfig.glflushtrigger) doGLReadback(fconfig.spoillast, fconfig.sync);
93 
94 	CATCH();
95 	ENABLE_FAKER();
96 }
97 
98 
glXWaitGL(void)99 void glXWaitGL(void)
100 {
101 	if(vglfaker::getExcludeCurrent()) { _glXWaitGL();  return; }
102 
103 	TRY();
104 
105 		if(fconfig.trace) vglout.print("[VGL] glXWaitGL()\n");
106 
107 	DISABLE_FAKER();
108 
109 	_glFinish();  // glXWaitGL() on some systems calls glFinish(), so we do this
110 	              // to avoid 2 readbacks
111 	fconfig.flushdelay = 0.;
112 	doGLReadback(false, fconfig.sync);
113 
114 	CATCH();
115 	ENABLE_FAKER();
116 }
117 
118 
glBindFramebuffer(GLenum target,GLuint framebuffer)119 void glBindFramebuffer(GLenum target, GLuint framebuffer)
120 {
121 	if(vglfaker::getExcludeCurrent())
122 	{
123 		_glBindFramebuffer(target, framebuffer);
124 		return;
125 	}
126 
127 	TRY();
128 
129 	VGLBindFramebuffer(target, framebuffer);
130 
131 	CATCH();
132 }
133 
glBindFramebufferEXT(GLenum target,GLuint framebuffer)134 void glBindFramebufferEXT(GLenum target, GLuint framebuffer)
135 {
136 	if(vglfaker::getExcludeCurrent())
137 	{
138 		_glBindFramebufferEXT(target, framebuffer);
139 		return;
140 	}
141 
142 	TRY();
143 
144 	VGLBindFramebuffer(target, framebuffer, true);
145 
146 	CATCH();
147 }
148 
149 
glDeleteFramebuffers(GLsizei n,const GLuint * framebuffers)150 void glDeleteFramebuffers(GLsizei n, const GLuint *framebuffers)
151 {
152 	if(vglfaker::getExcludeCurrent())
153 	{
154 		_glDeleteFramebuffers(n, framebuffers);
155 		return;
156 	}
157 
158 	TRY();
159 
160 	VGLDeleteFramebuffers(n, framebuffers);
161 
162 	CATCH();
163 }
164 
glDeleteFramebuffersEXT(GLsizei n,const GLuint * framebuffers)165 void glDeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
166 {
167 	glDeleteFramebuffers(n, framebuffers);
168 }
169 
170 
171 // If the application is rendering to the front buffer and switches the draw
172 // buffer before calling glFlush()/glFinish()/glXWaitGL(), we set a lazy
173 // readback trigger to indicate that the front buffer needs to be read back
174 // upon the next call to glFlush()/glFinish()/glXWaitGL().
175 
glDrawBuffer(GLenum mode)176 void glDrawBuffer(GLenum mode)
177 {
178 	if(vglfaker::getExcludeCurrent()) { _glDrawBuffer(mode);  return; }
179 
180 	TRY();
181 
182 		OPENTRACE(glDrawBuffer);  PRARGX(mode);  STARTTRACE();
183 
184 	vglfaker::VirtualWin *vw;
185 	int before = -1, after = -1, rbefore = -1, rafter = -1;
186 	GLXDrawable drawable = VGLGetCurrentDrawable();
187 
188 	if(drawable && (vw = winhash.find(NULL, drawable)) != NULL)
189 	{
190 		before = DrawingToFront();
191 		rbefore = DrawingToRight();
192 		VGLDrawBuffer(mode);
193 		after = DrawingToFront();
194 		rafter = DrawingToRight();
195 		if(before && !after) vw->dirty = true;
196 		if(rbefore && !rafter && vw->isStereo()) vw->rdirty = true;
197 	}
198 	else VGLDrawBuffer(mode);
199 
200 		STOPTRACE();
201 		if(drawable && vw)
202 		{
203 			PRARGI(vw->dirty);  PRARGI(vw->rdirty);  PRARGX(vw->getGLXDrawable());
204 		}
205 		CLOSETRACE();
206 
207 	CATCH();
208 }
209 
210 
glDrawBuffers(GLsizei n,const GLenum * bufs)211 void glDrawBuffers(GLsizei n, const GLenum *bufs)
212 {
213 	if(vglfaker::getExcludeCurrent()) { _glDrawBuffers(n, bufs);  return; }
214 
215 	TRY();
216 
217 		OPENTRACE(glDrawBuffers);  PRARGI(n);
218 		if(n && bufs)
219 		{
220 			for(GLsizei i = 0; i < n; i++) PRARGX(bufs[i]);
221 		}
222 		STARTTRACE();
223 
224 	vglfaker::VirtualWin *vw = NULL;
225 	int before = -1, after = -1, rbefore = -1, rafter = -1;
226 	GLXDrawable drawable = VGLGetCurrentDrawable();
227 
228 	if(drawable && (vw = winhash.find(NULL, drawable)) != NULL)
229 	{
230 		before = DrawingToFront();
231 		rbefore = DrawingToRight();
232 		VGLDrawBuffers(n, bufs);
233 		after = DrawingToFront();
234 		rafter = DrawingToRight();
235 		if(before && !after) vw->dirty = true;
236 		if(rbefore && !rafter && vw->isStereo()) vw->rdirty = true;
237 	}
238 	else VGLDrawBuffers(n, bufs);
239 
240 		STOPTRACE();
241 		if(drawable && vw)
242 		{
243 			PRARGI(vw->dirty);  PRARGI(vw->rdirty);  PRARGX(vw->getGLXDrawable());
244 		}
245 		CLOSETRACE();
246 
247 	CATCH();
248 }
249 
glDrawBuffersARB(GLsizei n,const GLenum * bufs)250 void glDrawBuffersARB(GLsizei n, const GLenum *bufs)
251 {
252 	glDrawBuffers(n, bufs);
253 }
254 
glDrawBuffersATI(GLsizei n,const GLenum * bufs)255 void glDrawBuffersATI(GLsizei n, const GLenum *bufs)
256 {
257 	glDrawBuffers(n, bufs);
258 }
259 
260 
glFramebufferDrawBufferEXT(GLuint framebuffer,GLenum mode)261 void glFramebufferDrawBufferEXT(GLuint framebuffer, GLenum mode)
262 {
263 	if(vglfaker::getExcludeCurrent())
264 	{
265 		_glFramebufferDrawBufferEXT(framebuffer, mode);
266 		return;
267 	}
268 
269 	TRY();
270 
271 		OPENTRACE(glFramebufferDrawBufferEXT);  PRARGI(framebuffer);  PRARGX(mode);
272 		STARTTRACE();
273 
274 	vglfaker::VirtualWin *vw = NULL;
275 	int before = -1, after = -1, rbefore = -1, rafter = -1;
276 	GLXDrawable drawable = 0;
277 
278 	if(framebuffer == 0 && (drawable = VGLGetCurrentDrawable()) != 0
279 		&& (vw = winhash.find(NULL, drawable)) != NULL)
280 	{
281 		before = DrawingToFront();
282 		rbefore = DrawingToRight();
283 		VGLNamedFramebufferDrawBuffer(framebuffer, mode, true);
284 		after = DrawingToFront();
285 		rafter = DrawingToRight();
286 		if(before && !after) vw->dirty = true;
287 		if(rbefore && !rafter && vw->isStereo()) vw->rdirty = true;
288 	}
289 	else VGLNamedFramebufferDrawBuffer(framebuffer, mode, true);
290 
291 		STOPTRACE();
292 		if(drawable && vw)
293 		{
294 			PRARGI(vw->dirty);  PRARGI(vw->rdirty);  PRARGX(vw->getGLXDrawable());
295 		}
296 		CLOSETRACE();
297 
298 	CATCH();
299 }
300 
301 
glFramebufferDrawBuffersEXT(GLuint framebuffer,GLsizei n,const GLenum * bufs)302 void glFramebufferDrawBuffersEXT(GLuint framebuffer, GLsizei n,
303 	const GLenum *bufs)
304 {
305 	if(vglfaker::getExcludeCurrent())
306 	{
307 		_glFramebufferDrawBuffersEXT(framebuffer, n, bufs);
308 		return;
309 	}
310 
311 	TRY();
312 
313 		OPENTRACE(glFramebufferDrawBuffersEXT);  PRARGI(framebuffer);  PRARGI(n);
314 		if(n && bufs)
315 		{
316 			for(GLsizei i = 0; i < n; i++) PRARGX(bufs[i]);
317 		}
318 		STARTTRACE();
319 
320 	vglfaker::VirtualWin *vw = NULL;
321 	int before = -1, after = -1, rbefore = -1, rafter = -1;
322 	GLXDrawable drawable = 0;
323 
324 	if(framebuffer == 0 && (drawable = VGLGetCurrentDrawable()) != 0
325 		&& (vw = winhash.find(NULL, drawable)) != NULL)
326 	{
327 		before = DrawingToFront();
328 		rbefore = DrawingToRight();
329 		VGLNamedFramebufferDrawBuffers(framebuffer, n, bufs, true);
330 		after = DrawingToFront();
331 		rafter = DrawingToRight();
332 		if(before && !after) vw->dirty = true;
333 		if(rbefore && !rafter && vw->isStereo()) vw->rdirty = true;
334 	}
335 	else VGLNamedFramebufferDrawBuffers(framebuffer, n, bufs, true);
336 
337 		STOPTRACE();
338 		if(drawable && vw)
339 		{
340 			PRARGI(vw->dirty);  PRARGI(vw->rdirty);  PRARGX(vw->getGLXDrawable());
341 		}
342 		CLOSETRACE();
343 
344 	CATCH();
345 }
346 
347 
glFramebufferReadBufferEXT(GLuint framebuffer,GLenum mode)348 void glFramebufferReadBufferEXT(GLuint framebuffer, GLenum mode)
349 {
350 	if(vglfaker::getExcludeCurrent())
351 	{
352 		_glFramebufferReadBufferEXT(framebuffer, mode);
353 		return;
354 	}
355 
356 	TRY();
357 
358 	VGLNamedFramebufferReadBuffer(framebuffer, mode, true);
359 
360 	CATCH();
361 }
362 
363 
glGetBooleanv(GLenum pname,GLboolean * data)364 void glGetBooleanv(GLenum pname, GLboolean *data)
365 {
366 	if(vglfaker::getExcludeCurrent() || !data || !fconfig.egl)
367 	{
368 		_glGetBooleanv(pname, data);  return;
369 	}
370 
371 	TRY();
372 
373 	switch(pname)
374 	{
375 		case GL_DOUBLEBUFFER:
376 		case GL_DRAW_BUFFER:
377 		case GL_DRAW_BUFFER0:
378 		case GL_DRAW_FRAMEBUFFER_BINDING:
379 		case GL_MAX_DRAW_BUFFERS:
380 		case GL_READ_BUFFER:
381 		case GL_READ_FRAMEBUFFER_BINDING:
382 		case GL_STEREO:
383 		{
384 			GLint val = -1;
385 			VGLGetIntegerv(pname, &val);
386 			*data = (val == 0 ? GL_FALSE : GL_TRUE);
387 			break;
388 		}
389 		default:
390 			_glGetBooleanv(pname, data);
391 	}
392 
393 	CATCH();
394 }
395 
396 
glGetDoublev(GLenum pname,GLdouble * data)397 void glGetDoublev(GLenum pname, GLdouble *data)
398 {
399 	if(vglfaker::getExcludeCurrent() || !data || !fconfig.egl)
400 	{
401 		_glGetDoublev(pname, data);  return;
402 	}
403 
404 	TRY();
405 
406 	switch(pname)
407 	{
408 		case GL_DOUBLEBUFFER:
409 		case GL_DRAW_BUFFER:
410 		case GL_DRAW_BUFFER0:
411 		case GL_DRAW_FRAMEBUFFER_BINDING:
412 		case GL_MAX_DRAW_BUFFERS:
413 		case GL_READ_BUFFER:
414 		case GL_READ_FRAMEBUFFER_BINDING:
415 		case GL_STEREO:
416 		{
417 			GLint val = -1;
418 			VGLGetIntegerv(pname, &val);
419 			*data = (GLdouble)val;
420 			break;
421 		}
422 		default:
423 			_glGetDoublev(pname, data);
424 	}
425 
426 	CATCH();
427 }
428 
429 
glGetFloatv(GLenum pname,GLfloat * data)430 void glGetFloatv(GLenum pname, GLfloat *data)
431 {
432 	if(vglfaker::getExcludeCurrent() || !data || !fconfig.egl)
433 	{
434 		_glGetFloatv(pname, data);  return;
435 	}
436 
437 	TRY();
438 
439 	switch(pname)
440 	{
441 		case GL_DOUBLEBUFFER:
442 		case GL_DRAW_BUFFER:
443 		case GL_DRAW_BUFFER0:
444 		case GL_DRAW_FRAMEBUFFER_BINDING:
445 		case GL_MAX_DRAW_BUFFERS:
446 		case GL_READ_BUFFER:
447 		case GL_READ_FRAMEBUFFER_BINDING:
448 		case GL_STEREO:
449 		{
450 			GLint val = -1;
451 			VGLGetIntegerv(pname, &val);
452 			*data = (GLfloat)val;
453 			break;
454 		}
455 		default:
456 			_glGetFloatv(pname, data);
457 	}
458 
459 	CATCH();
460 }
461 
462 
glGetFramebufferAttachmentParameteriv(GLenum target,GLenum attachment,GLenum pname,GLint * params)463 void glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment,
464 	GLenum pname, GLint *params)
465 {
466 	if(vglfaker::getExcludeCurrent())
467 	{
468 		_glGetFramebufferAttachmentParameteriv(target, attachment, pname, params);
469 		return;
470 	}
471 
472 	TRY();
473 
474 	VGLGetFramebufferAttachmentParameteriv(target, attachment, pname, params);
475 
476 	CATCH();
477 }
478 
479 
glGetFramebufferParameteriv(GLenum target,GLenum pname,GLint * params)480 void glGetFramebufferParameteriv(GLenum target, GLenum pname, GLint *params)
481 {
482 	if(vglfaker::getExcludeCurrent())
483 	{
484 		_glGetFramebufferParameteriv(target, pname, params);  return;
485 	}
486 
487 	TRY();
488 
489 	VGLGetFramebufferParameteriv(target, pname, params);
490 
491 	CATCH();
492 }
493 
494 
glGetIntegerv(GLenum pname,GLint * params)495 void glGetIntegerv(GLenum pname, GLint *params)
496 {
497 	if(vglfaker::getExcludeCurrent()) { _glGetIntegerv(pname, params);  return; }
498 
499 	TRY();
500 
501 	VGLGetIntegerv(pname, params);
502 
503 	CATCH();
504 }
505 
506 
glGetInteger64v(GLenum pname,GLint64 * data)507 void glGetInteger64v(GLenum pname, GLint64 *data)
508 {
509 	if(vglfaker::getExcludeCurrent() || !data || !fconfig.egl)
510 	{
511 		_glGetInteger64v(pname, data);  return;
512 	}
513 
514 	TRY();
515 
516 	switch(pname)
517 	{
518 		case GL_DOUBLEBUFFER:
519 		case GL_DRAW_BUFFER:
520 		case GL_DRAW_BUFFER0:
521 		case GL_DRAW_FRAMEBUFFER_BINDING:
522 		case GL_MAX_DRAW_BUFFERS:
523 		case GL_READ_BUFFER:
524 		case GL_READ_FRAMEBUFFER_BINDING:
525 		case GL_STEREO:
526 		{
527 			GLint val = -1;
528 			VGLGetIntegerv(pname, &val);
529 			*data = (GLint64)val;
530 			break;
531 		}
532 		default:
533 			_glGetInteger64v(pname, data);
534 	}
535 
536 	CATCH();
537 }
538 
539 
glGetNamedFramebufferParameteriv(GLuint framebuffer,GLenum pname,GLint * param)540 void glGetNamedFramebufferParameteriv(GLuint framebuffer, GLenum pname,
541 	GLint *param)
542 {
543 	if(vglfaker::getExcludeCurrent())
544 	{
545 		_glGetNamedFramebufferParameteriv(framebuffer, pname, param);  return;
546 	}
547 
548 	TRY()
549 
550 	VGLGetNamedFramebufferParameteriv(framebuffer, pname, param);
551 
552 	CATCH();
553 }
554 
555 
glGetString(GLenum name)556 const GLubyte *glGetString(GLenum name)
557 {
558 	char *string = NULL;
559 
560 	if(vglfaker::getExcludeCurrent()) { return _glGetString(name); }
561 
562 	TRY();
563 
564 	string = (char *)_glGetString(name);
565 	if(name == GL_EXTENSIONS && string
566 		&& strstr(string, "GL_EXT_x11_sync_object") != NULL)
567 	{
568 		if(!vglfaker::glExtensions)
569 		{
570 			vglfaker::GlobalCriticalSection::SafeLock l(globalMutex);
571 			if(!vglfaker::glExtensions)
572 			{
573 				vglfaker::glExtensions = strdup(string);
574 				if(!vglfaker::glExtensions) THROW("strdup() failed");
575 				char *ptr =
576 					strstr((char *)vglfaker::glExtensions, "GL_EXT_x11_sync_object");
577 				if(ptr)
578 				{
579 					if(ptr[22] == ' ') memmove(ptr, &ptr[23], strlen(&ptr[23]) + 1);
580 					else *ptr = 0;
581 				}
582 			}
583 		}
584 		string = vglfaker::glExtensions;
585 	}
586 
587 	CATCH();
588 
589 	return (GLubyte *)string;
590 }
591 
592 
glGetStringi(GLenum name,GLuint index)593 const GLubyte *glGetStringi(GLenum name, GLuint index)
594 {
595 	const GLubyte *string = NULL;
596 
597 	if(vglfaker::getExcludeCurrent()) { return _glGetStringi(name, index); }
598 
599 	TRY();
600 
601 	string = _glGetStringi(name, index);
602 	if(name == GL_EXTENSIONS && string
603 		&& !strcmp((char *)string, "GL_EXT_x11_sync_object"))
604 	{
605 		// This is a hack to avoid interposing the various flavors of
606 		// glGetInteger*() and modifying the value returned for GL_NUM_EXTENSIONS.
607 		string = (const GLubyte *)"";
608 	}
609 
610 	CATCH();
611 
612 	return string;
613 }
614 
615 
glNamedFramebufferDrawBuffer(GLuint framebuffer,GLenum buf)616 void glNamedFramebufferDrawBuffer(GLuint framebuffer, GLenum buf)
617 {
618 	if(vglfaker::getExcludeCurrent())
619 	{
620 		_glNamedFramebufferDrawBuffer(framebuffer, buf);
621 		return;
622 	}
623 
624 	TRY();
625 
626 		OPENTRACE(glNamedFramebufferDrawBuffer);  PRARGI(framebuffer);
627 		PRARGX(buf);  STARTTRACE();
628 
629 	vglfaker::VirtualWin *vw = NULL;
630 	int before = -1, after = -1, rbefore = -1, rafter = -1;
631 	GLXDrawable drawable = 0;
632 
633 	if(framebuffer == 0 && (drawable = VGLGetCurrentDrawable()) != 0
634 		&& (vw = winhash.find(NULL, drawable)) != NULL)
635 	{
636 		before = DrawingToFront();
637 		rbefore = DrawingToRight();
638 		VGLNamedFramebufferDrawBuffer(framebuffer, buf);
639 		after = DrawingToFront();
640 		rafter = DrawingToRight();
641 		if(before && !after) vw->dirty = true;
642 		if(rbefore && !rafter && vw->isStereo()) vw->rdirty = true;
643 	}
644 	else VGLNamedFramebufferDrawBuffer(framebuffer, buf);
645 
646 		STOPTRACE();
647 		if(drawable && vw)
648 		{
649 			PRARGI(vw->dirty);  PRARGI(vw->rdirty);  PRARGX(vw->getGLXDrawable());
650 		}
651 		CLOSETRACE();
652 
653 	CATCH();
654 }
655 
656 
glNamedFramebufferDrawBuffers(GLuint framebuffer,GLsizei n,const GLenum * bufs)657 void glNamedFramebufferDrawBuffers(GLuint framebuffer, GLsizei n,
658 	const GLenum *bufs)
659 {
660 	if(vglfaker::getExcludeCurrent())
661 	{
662 		_glNamedFramebufferDrawBuffers(framebuffer, n, bufs);
663 		return;
664 	}
665 
666 	TRY();
667 
668 		OPENTRACE(glNamedFramebufferDrawBuffers);  PRARGI(framebuffer);  PRARGI(n);
669 		if(n && bufs)
670 		{
671 			for(GLsizei i = 0; i < n; i++) PRARGX(bufs[i]);
672 		}
673 		STARTTRACE();
674 
675 	vglfaker::VirtualWin *vw = NULL;
676 	int before = -1, after = -1, rbefore = -1, rafter = -1;
677 	GLXDrawable drawable = 0;
678 
679 	if(framebuffer == 0 && (drawable = VGLGetCurrentDrawable()) != 0
680 		&& (vw = winhash.find(NULL, drawable)) != NULL)
681 	{
682 		before = DrawingToFront();
683 		rbefore = DrawingToRight();
684 		VGLNamedFramebufferDrawBuffers(framebuffer, n, bufs);
685 		after = DrawingToFront();
686 		rafter = DrawingToRight();
687 		if(before && !after) vw->dirty = true;
688 		if(rbefore && !rafter && vw->isStereo()) vw->rdirty = true;
689 	}
690 	else VGLNamedFramebufferDrawBuffers(framebuffer, n, bufs);
691 
692 		STOPTRACE();
693 		if(drawable && vw)
694 		{
695 			PRARGI(vw->dirty);  PRARGI(vw->rdirty);  PRARGX(vw->getGLXDrawable());
696 		}
697 		CLOSETRACE();
698 
699 	CATCH();
700 }
701 
702 
glNamedFramebufferReadBuffer(GLuint framebuffer,GLenum mode)703 void glNamedFramebufferReadBuffer(GLuint framebuffer, GLenum mode)
704 {
705 	if(vglfaker::getExcludeCurrent())
706 	{
707 		_glNamedFramebufferReadBuffer(framebuffer, mode);
708 		return;
709 	}
710 
711 	TRY();
712 
713 	VGLNamedFramebufferReadBuffer(framebuffer, mode);
714 
715 	CATCH();
716 }
717 
718 
719 // glPopAttrib() can change the draw buffer state as well :|
720 
glPopAttrib(void)721 void glPopAttrib(void)
722 {
723 	if(vglfaker::getExcludeCurrent()) { _glPopAttrib();  return; }
724 
725 	TRY();
726 
727 		OPENTRACE(glPopAttrib);  STARTTRACE();
728 
729 	vglfaker::VirtualWin *vw;
730 	int before = -1, after = -1, rbefore = -1, rafter = -1;
731 	GLXDrawable drawable = VGLGetCurrentDrawable();
732 
733 	if(drawable && (vw = winhash.find(NULL, drawable)) != NULL)
734 	{
735 		before = DrawingToFront();
736 		rbefore = DrawingToRight();
737 		_glPopAttrib();
738 		after = DrawingToFront();
739 		rafter = DrawingToRight();
740 		if(before && !after) vw->dirty = true;
741 		if(rbefore && !rafter && vw->isStereo()) vw->rdirty = true;
742 	}
743 	else _glPopAttrib();
744 
745 		STOPTRACE();
746 		if(drawable && vw)
747 		{
748 			PRARGI(vw->dirty);  PRARGI(vw->rdirty);  PRARGX(vw->getGLXDrawable());
749 		}
750 		CLOSETRACE();
751 
752 	CATCH();
753 }
754 
755 
glReadBuffer(GLenum mode)756 void glReadBuffer(GLenum mode)
757 {
758 	if(vglfaker::getExcludeCurrent()) { _glReadBuffer(mode);  return; }
759 
760 	TRY();
761 
762 	VGLReadBuffer(mode);
763 
764 	CATCH();
765 }
766 
767 
glReadPixels(GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,GLvoid * pixels)768 void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
769 	GLenum format, GLenum type, GLvoid *pixels)
770 {
771 	if(vglfaker::getExcludeCurrent())
772 	{
773 		_glReadPixels(x, y, width, height, format, type, pixels);
774 		return;
775 	}
776 
777 	TRY();
778 
779 	VGLReadPixels(x, y, width, height, format, type, pixels);
780 
781 	CATCH();
782 }
783 
784 
785 // Sometimes XNextEvent() is called from a thread other than the
786 // rendering thread, so we wait until glViewport() is called and
787 // take that opportunity to resize the off-screen drawable.
788 
glViewport(GLint x,GLint y,GLsizei width,GLsizei height)789 void glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
790 {
791 	if(vglfaker::getExcludeCurrent())
792 	{
793 		_glViewport(x, y, width, height);  return;
794 	}
795 
796 	TRY();
797 
798 		OPENTRACE(glViewport);  PRARGI(x);  PRARGI(y);  PRARGI(width);
799 		PRARGI(height);  STARTTRACE();
800 
801 	GLXContext ctx = VGLGetCurrentContext();
802 	GLXDrawable draw = VGLGetCurrentDrawable();
803 	GLXDrawable read = VGLGetCurrentReadDrawable();
804 	Display *dpy = VGLGetCurrentDisplay();
805 	GLXDrawable newRead = 0, newDraw = 0;
806 
807 	if(dpy && (draw || read) && ctx && ctxhash.findConfig(ctx))
808 	{
809 		newRead = read, newDraw = draw;
810 		vglfaker::VirtualWin *drawVW = winhash.find(NULL, draw);
811 		vglfaker::VirtualWin *readVW = winhash.find(NULL, read);
812 		if(drawVW) drawVW->checkResize();
813 		if(readVW && readVW != drawVW) readVW->checkResize();
814 		if(drawVW) newDraw = drawVW->updateGLXDrawable();
815 		if(readVW) newRead = readVW->updateGLXDrawable();
816 		if(newRead != read || newDraw != draw)
817 		{
818 			VGLMakeCurrent(dpy, newDraw, newRead, ctx);
819 			if(drawVW) { drawVW->clear();  drawVW->cleanup(); }
820 			if(readVW) readVW->cleanup();
821 		}
822 	}
823 	_glViewport(x, y, width, height);
824 
825 		STOPTRACE();
826 		if(draw != newDraw) { PRARGX(draw);  PRARGX(newDraw); }
827 		if(read != newRead) { PRARGX(read);  PRARGX(newRead); }
828 		CLOSETRACE();
829 
830 	CATCH();
831 }
832 
833 
834 }  // extern "C"
835