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