1 // Copyright (C)2019-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 "vglwrap.h"
14 #ifdef EGLBACKEND
15 #include "EGLContextHash.h"
16 #include "VGLPbufferHash.h"
17 #include "EGLError.h"
18 #include "BufferState.h"
19 #endif
20 #include "PixmapHash.h"
21 #include "glxvisual.h"
22 #include "threadlocal.h"
23 #include <X11/Xmd.h>
24 #include <GL/glxproto.h>
25
26 #ifndef X_GLXCreateContextAttribsARB
27 #define X_GLXCreateContextAttribsARB 34
28 #endif
29
30 #ifdef EGLBACKEND
31
32 #define CATCH_EGL(minorCode) \
33 catch(vglfaker::EGLError &e) \
34 { \
35 int glxError = e.getGLXError(); \
36 bool isX11Error = e.isX11Error(); \
37 if(glxError >= 0) \
38 { \
39 if(fconfig.verbose) \
40 vglout.print("[VGL] ERROR: in %s--\n[VGL] %s\n", GET_METHOD(e), \
41 e.what()); \
42 vglfaker::sendGLXError(dpy, minorCode, glxError, isX11Error); \
43 } \
44 else throw; \
45 } \
46
47
VGL_THREAD_LOCAL(CurrentDrawable,GLXDrawable,None)48 VGL_THREAD_LOCAL(CurrentDrawable, GLXDrawable, None)
49 VGL_THREAD_LOCAL(CurrentReadDrawable, GLXDrawable, None)
50
51
52 static vglfaker::VGLPbuffer *getCurrentVGLPbuffer(EGLint readdraw)
53 {
54 vglfaker::VGLPbuffer *pb = vpbhash.find(readdraw == EGL_READ ?
55 getCurrentReadDrawable() : getCurrentDrawable());
56 if(pb)
57 {
58 GLint fbo = -1;
59 _glGetIntegerv(readdraw == EGL_READ ?
60 GL_READ_FRAMEBUFFER_BINDING : GL_DRAW_FRAMEBUFFER_BINDING, &fbo);
61 if(fbo == (GLint)pb->getFBO())
62 return pb;
63 }
64 return NULL;
65 }
66
67 #endif
68
69
VGLBindFramebuffer(GLenum target,GLuint framebuffer,bool ext)70 void VGLBindFramebuffer(GLenum target, GLuint framebuffer, bool ext)
71 {
72 #ifdef EGLBACKEND
73 if(fconfig.egl)
74 {
75 if(framebuffer == 0)
76 {
77 if(target == GL_DRAW_FRAMEBUFFER || target == GL_FRAMEBUFFER)
78 {
79 vglfaker::VGLPbuffer *pb = vpbhash.find(getCurrentDrawable());
80 if(pb)
81 {
82 framebuffer = pb->getFBO();
83 ectxhash.setDrawFBO(_eglGetCurrentContext(), 0);
84 }
85 }
86 if(target == GL_READ_FRAMEBUFFER || target == GL_FRAMEBUFFER)
87 {
88 vglfaker::VGLPbuffer *pb = vpbhash.find(getCurrentReadDrawable());
89 if(pb)
90 {
91 framebuffer = pb->getFBO();
92 ectxhash.setReadFBO(_eglGetCurrentContext(), 0);
93 }
94 }
95 }
96 else
97 {
98 if(target == GL_DRAW_FRAMEBUFFER || target == GL_FRAMEBUFFER)
99 ectxhash.setDrawFBO(_eglGetCurrentContext(), framebuffer);
100 if(target == GL_READ_FRAMEBUFFER || target == GL_FRAMEBUFFER)
101 ectxhash.setReadFBO(_eglGetCurrentContext(), framebuffer);
102 }
103 }
104 #endif
105 if(ext) _glBindFramebufferEXT(target, framebuffer);
106 else _glBindFramebuffer(target, framebuffer);
107 }
108
109
VGLDeleteFramebuffers(GLsizei n,const GLuint * framebuffers)110 void VGLDeleteFramebuffers(GLsizei n, const GLuint *framebuffers)
111 {
112 #ifdef EGLBACKEND
113 if(fconfig.egl)
114 {
115 if(n > 0 && framebuffers)
116 {
117 GLint drawFBO = -1, readFBO = -1;
118 _glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &drawFBO);
119 _glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &readFBO);
120 for(GLsizei i = 0; i < n; i++)
121 {
122 if((GLint)framebuffers[i] == drawFBO)
123 VGLBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
124 if((GLint)framebuffers[i] == readFBO)
125 VGLBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
126 }
127 }
128 }
129 #endif
130 _glDeleteFramebuffers(n, framebuffers);
131 }
132
133
VGLCreateContext(Display * dpy,VGLFBConfig config,GLXContext share,Bool direct,const int * glxAttribs)134 GLXContext VGLCreateContext(Display *dpy, VGLFBConfig config, GLXContext share,
135 Bool direct, const int *glxAttribs)
136 {
137 #ifdef EGLBACKEND
138 if(fconfig.egl)
139 {
140 if(!direct) return NULL;
141
142 int eglAttribs[256], egli = 0;
143 for(int i = 0; i < 256; i++) eglAttribs[i] = EGL_NONE;
144 bool majorVerSpecified = false, forwardCompatSpecified = false;
145 int majorVer = -1;
146
147 if(glxAttribs && glxAttribs[0] != None)
148 {
149 for(int glxi = 0; glxAttribs[glxi] && egli < 256; glxi += 2)
150 {
151 switch(glxAttribs[glxi])
152 {
153 case GLX_CONTEXT_MAJOR_VERSION_ARB:
154 eglAttribs[egli++] = EGL_CONTEXT_MAJOR_VERSION;
155 eglAttribs[egli++] = majorVer = glxAttribs[glxi + 1];
156 majorVerSpecified = true;
157 break;
158 case GLX_CONTEXT_MINOR_VERSION_ARB:
159 eglAttribs[egli++] = EGL_CONTEXT_MINOR_VERSION;
160 eglAttribs[egli++] = glxAttribs[glxi + 1];
161 break;
162 case GLX_CONTEXT_FLAGS_ARB:
163 {
164 int flags = glxAttribs[glxi + 1];
165 if(flags & GLX_CONTEXT_DEBUG_BIT_ARB)
166 {
167 eglAttribs[egli++] = EGL_CONTEXT_OPENGL_DEBUG;
168 eglAttribs[egli++] = EGL_TRUE;
169 }
170 if(flags & GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB)
171 {
172 eglAttribs[egli++] = EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE;
173 eglAttribs[egli++] = EGL_TRUE;
174 forwardCompatSpecified = true;
175 }
176 if(flags & GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB)
177 {
178 // For future expansion
179 eglAttribs[egli++] = EGL_CONTEXT_OPENGL_ROBUST_ACCESS;
180 eglAttribs[egli++] = EGL_TRUE;
181 }
182 if(flags & ~(GLX_CONTEXT_DEBUG_BIT_ARB |
183 GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB))
184 {
185 vglfaker::sendGLXError(dpy, X_GLXCreateContextAttribsARB,
186 BadValue, true);
187 return NULL;
188 }
189 break;
190 }
191 case GLX_CONTEXT_PROFILE_MASK_ARB:
192 // The mask bits are the same for GLX_ARB_create_context and EGL.
193 eglAttribs[egli++] = EGL_CONTEXT_OPENGL_PROFILE_MASK;
194 eglAttribs[egli++] = glxAttribs[glxi + 1];
195 if(glxAttribs[glxi + 1] != GLX_CONTEXT_CORE_PROFILE_BIT_ARB
196 && glxAttribs[glxi + 1]
197 != GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB)
198 {
199 vglfaker::sendGLXError(dpy, X_GLXCreateContextAttribsARB,
200 GLXBadProfileARB, false);
201 return NULL;
202 }
203 break;
204 case GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB:
205 switch(glxAttribs[glxi + 1])
206 {
207 case GLX_NO_RESET_NOTIFICATION_ARB:
208 eglAttribs[egli++] =
209 EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY;
210 eglAttribs[egli++] = EGL_NO_RESET_NOTIFICATION;
211 break;
212 case GLX_LOSE_CONTEXT_ON_RESET_ARB:
213 eglAttribs[egli++] =
214 EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY;
215 eglAttribs[egli++] = EGL_LOSE_CONTEXT_ON_RESET;
216 break;
217 }
218 break;
219 default:
220 if(glxAttribs[glxi] == GLX_RENDER_TYPE
221 && glxAttribs[glxi + 1] == GLX_COLOR_INDEX_TYPE)
222 {
223 vglfaker::sendGLXError(dpy, X_GLXCreateContextAttribsARB,
224 BadMatch, true);
225 return NULL;
226 }
227 else
228 {
229 vglfaker::sendGLXError(dpy, X_GLXCreateContextAttribsARB,
230 BadValue, true);
231 }
232 return NULL;
233 }
234 }
235 }
236
237 CARD16 minorCode = egli ? X_GLXCreateContextAttribsARB :
238 X_GLXCreateNewContext;
239 if(majorVerSpecified && forwardCompatSpecified && majorVer < 3)
240 {
241 vglfaker::sendGLXError(dpy, minorCode, BadMatch, true);
242 return NULL;
243 }
244 try
245 {
246 if(!VALID_CONFIG(config))
247 {
248 vglfaker::sendGLXError(dpy, minorCode, GLXBadFBConfig, false);
249 return NULL;
250 }
251 if(!share)
252 {
253 vglfaker::getRBOContext(dpy).createContext();
254 share = (GLXContext)vglfaker::getRBOContext(dpy).getContext();
255 }
256 if(!_eglBindAPI(EGL_OPENGL_API))
257 THROW("Could not enable OpenGL API");
258 GLXContext ctx = (GLXContext)_eglCreateContext(EDPY, (EGLConfig)0,
259 (EGLContext)share, egli ? eglAttribs : NULL);
260 EGLint eglError = _eglGetError();
261 // Some implementations of eglCreateContext() return NULL but do not set
262 // the EGL error if certain invalid OpenGL versions are passed to the
263 // function. This is why we can't have nice things.
264 if(!ctx && eglError == EGL_SUCCESS && majorVerSpecified)
265 eglError = EGL_BAD_MATCH;
266 if(!ctx && eglError != EGL_SUCCESS)
267 throw(vglfaker::EGLError("eglCreateContext()", __LINE__, eglError));
268 if(ctx) ectxhash.add(ctx, config);
269 return ctx;
270 }
271 CATCH_EGL(minorCode)
272 return 0;
273 }
274 else
275 #endif
276 {
277 if(glxAttribs && glxAttribs[0] != None)
278 return _glXCreateContextAttribsARB(DPY3D, GLXFBC(config), share, direct,
279 glxAttribs);
280 else
281 return _glXCreateNewContext(DPY3D, GLXFBC(config), GLX_RGBA_TYPE, share,
282 direct);
283 }
284 }
285
286
VGLCreatePbuffer(Display * dpy,VGLFBConfig config,const int * glxAttribs)287 GLXPbuffer VGLCreatePbuffer(Display *dpy, VGLFBConfig config,
288 const int *glxAttribs)
289 {
290 #ifdef EGLBACKEND
291 if(fconfig.egl)
292 {
293 try
294 {
295 vglfaker::VGLPbuffer *pb =
296 new vglfaker::VGLPbuffer(dpy, config, glxAttribs);
297 GLXDrawable id = pb->getID();
298 if(id) vpbhash.add(id, pb);
299 return id;
300 }
301 CATCH_EGL(X_GLXCreatePbuffer)
302 return 0;
303 }
304 else
305 #endif
306 return _glXCreatePbuffer(DPY3D, GLXFBC(config), glxAttribs);
307 }
308
309
VGLDestroyContext(Display * dpy,GLXContext ctx)310 void VGLDestroyContext(Display *dpy, GLXContext ctx)
311 {
312 #ifdef EGLBACKEND
313 if(fconfig.egl)
314 {
315 try
316 {
317 if(!ctx) return;
318 VGLFBConfig config = ectxhash.findConfig(ctx);
319 ectxhash.remove(ctx);
320 if(!_eglBindAPI(EGL_OPENGL_API))
321 THROW("Could not enable OpenGL API");
322 if(!_eglDestroyContext(EDPY, (EGLContext)ctx))
323 THROW_EGL("eglDestroyContext()");
324 if(!config)
325 vglfaker::sendGLXError(dpy, X_GLXDestroyContext, GLXBadContext, false);
326 }
327 CATCH_EGL(X_GLXDestroyContext)
328 }
329 else
330 #endif
331 _glXDestroyContext(DPY3D, ctx);
332 }
333
334
VGLDestroyPbuffer(Display * dpy,GLXPbuffer pbuf)335 void VGLDestroyPbuffer(Display *dpy, GLXPbuffer pbuf)
336 {
337 #ifdef EGLBACKEND
338 if(fconfig.egl)
339 {
340 try
341 {
342 vpbhash.remove(pbuf);
343 }
344 CATCH_EGL(X_GLXDestroyPbuffer)
345 }
346 else
347 #endif
348 _glXDestroyPbuffer(DPY3D, pbuf);
349 }
350
351
VGLDrawBuffer(GLenum mode)352 void VGLDrawBuffer(GLenum mode)
353 {
354 #ifdef EGLBACKEND
355 if(fconfig.egl)
356 {
357 vglfaker::VGLPbuffer *pb = getCurrentVGLPbuffer(EGL_DRAW);
358 if(pb)
359 {
360 pb->setDrawBuffer(mode, false);
361 return;
362 }
363 }
364 #endif
365 _glDrawBuffer(mode);
366 }
367
368
VGLDrawBuffers(GLsizei n,const GLenum * bufs)369 void VGLDrawBuffers(GLsizei n, const GLenum *bufs)
370 {
371 #ifdef EGLBACKEND
372 if(fconfig.egl)
373 {
374 vglfaker::VGLPbuffer *pb = getCurrentVGLPbuffer(EGL_DRAW);
375 if(pb)
376 {
377 pb->setDrawBuffers(n, bufs, false);
378 return;
379 }
380 }
381 #endif
382 _glDrawBuffers(n, bufs);
383 }
384
385
VGLGetCurrentContext(void)386 GLXContext VGLGetCurrentContext(void)
387 {
388 #ifdef EGLBACKEND
389 if(fconfig.egl)
390 {
391 if(!_eglBindAPI(EGL_OPENGL_API))
392 THROW("Could not enable OpenGL API");
393 return (GLXContext)_eglGetCurrentContext();
394 }
395 else
396 #endif
397 return _glXGetCurrentContext();
398 }
399
400
VGLGetCurrentDisplay(void)401 Display *VGLGetCurrentDisplay(void)
402 {
403 #ifdef EGLBACKEND
404 if(fconfig.egl)
405 {
406 vglfaker::VGLPbuffer *pb = vpbhash.find(getCurrentDrawable());
407 return pb ? pb->getDisplay() : NULL;
408 }
409 else
410 #endif
411 return _glXGetCurrentDisplay();
412 }
413
414
VGLGetCurrentDrawable(void)415 GLXDrawable VGLGetCurrentDrawable(void)
416 {
417 #ifdef EGLBACKEND
418 if(fconfig.egl)
419 return getCurrentDrawable();
420 else
421 #endif
422 return _glXGetCurrentDrawable();
423 }
424
425
VGLGetCurrentReadDrawable(void)426 GLXDrawable VGLGetCurrentReadDrawable(void)
427 {
428 #ifdef EGLBACKEND
429 if(fconfig.egl)
430 return getCurrentReadDrawable();
431 else
432 #endif
433 return _glXGetCurrentReadDrawable();
434 }
435
436
VGLGetFBConfigAttrib(Display * dpy,VGLFBConfig config,int attribute,int * value)437 int VGLGetFBConfigAttrib(Display *dpy, VGLFBConfig config, int attribute,
438 int *value)
439 {
440 #ifdef EGLBACKEND
441 if(fconfig.egl)
442 {
443 if(!value) return GLX_BAD_VALUE;
444
445 switch(attribute)
446 {
447 case GLX_FBCONFIG_ID:
448 *value = config->id;
449 return Success;
450 case GLX_BUFFER_SIZE:
451 *value = config->attr.redSize + config->attr.greenSize +
452 config->attr.blueSize + config->attr.alphaSize;
453 return Success;
454 case GLX_LEVEL:
455 *value = 0;
456 return Success;
457 case GLX_DOUBLEBUFFER:
458 *value = config->attr.doubleBuffer;
459 return Success;
460 case GLX_STEREO:
461 *value = config->attr.stereo;
462 return Success;
463 case GLX_AUX_BUFFERS:
464 *value = 0;
465 return Success;
466 case GLX_RED_SIZE:
467 *value = config->attr.redSize;
468 return Success;
469 case GLX_GREEN_SIZE:
470 *value = config->attr.greenSize;
471 return Success;
472 case GLX_BLUE_SIZE:
473 *value = config->attr.blueSize;
474 return Success;
475 case GLX_ALPHA_SIZE:
476 *value = config->attr.alphaSize;
477 return Success;
478 case GLX_DEPTH_SIZE:
479 *value = config->attr.depthSize;
480 return Success;
481 case GLX_STENCIL_SIZE:
482 *value = config->attr.stencilSize;
483 return Success;
484 case GLX_ACCUM_RED_SIZE:
485 case GLX_ACCUM_GREEN_SIZE:
486 case GLX_ACCUM_BLUE_SIZE:
487 case GLX_ACCUM_ALPHA_SIZE:
488 *value = 0;
489 return Success;
490 case GLX_RENDER_TYPE:
491 *value = GLX_RGBA_BIT;
492 return Success;
493 case GLX_DRAWABLE_TYPE:
494 *value = GLX_PBUFFER_BIT |
495 (config->visualID ? GLX_WINDOW_BIT | GLX_PIXMAP_BIT : 0);
496 return Success;
497 case GLX_X_RENDERABLE:
498 *value = !!config->visualID;
499 return Success;
500 case GLX_VISUAL_ID:
501 *value = config->visualID;
502 return Success;
503 case GLX_X_VISUAL_TYPE:
504 *value = config->c_class == TrueColor ?
505 GLX_TRUE_COLOR : GLX_DIRECT_COLOR;
506 return Success;
507 case GLX_CONFIG_CAVEAT:
508 case GLX_TRANSPARENT_TYPE:
509 *value = GLX_NONE;
510 return Success;
511 case GLX_TRANSPARENT_INDEX_VALUE:
512 case GLX_TRANSPARENT_RED_VALUE:
513 case GLX_TRANSPARENT_GREEN_VALUE:
514 case GLX_TRANSPARENT_BLUE_VALUE:
515 case GLX_TRANSPARENT_ALPHA_VALUE:
516 *value = 0;
517 return Success;
518 case GLX_MAX_PBUFFER_WIDTH:
519 {
520 *value = config->maxPBWidth;
521 return EGL_TRUE;
522 }
523 case GLX_MAX_PBUFFER_HEIGHT:
524 {
525 *value = config->maxPBHeight;
526 return EGL_TRUE;
527 }
528 case GLX_MAX_PBUFFER_PIXELS:
529 {
530 *value = config->maxPBWidth * config->maxPBHeight;
531 return EGL_TRUE;
532 }
533 case GLX_SAMPLE_BUFFERS:
534 *value = !!config->attr.samples;
535 return Success;
536 case GLX_SAMPLES:
537 *value = config->attr.samples;
538 return Success;
539 default:
540 return GLX_BAD_ATTRIBUTE;
541 }
542 } // fconfig.egl
543 else
544 #endif
545 return _glXGetFBConfigAttrib(DPY3D, GLXFBC(config), attribute, value);
546 }
547
548
VGLGetFramebufferAttachmentParameteriv(GLenum target,GLenum attachment,GLenum pname,GLint * params)549 void VGLGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment,
550 GLenum pname, GLint *params)
551 {
552 #ifdef EGLBACKEND
553 bool isDefault = false;
554
555 if(fconfig.egl)
556 {
557 if(!params)
558 {
559 _glGetFramebufferAttachmentParameteriv(target, attachment, pname,
560 params);
561 return;
562 }
563 else if((attachment >= GL_FRONT_LEFT && attachment <= GL_BACK_RIGHT)
564 || (attachment >= GL_DEPTH && attachment <= GL_STENCIL))
565 {
566 vglfaker::VGLPbuffer *pb;
567 if(((target == GL_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER)
568 && (pb = getCurrentVGLPbuffer(EGL_DRAW)) != NULL)
569 || (target == GL_READ_FRAMEBUFFER
570 && (pb = getCurrentVGLPbuffer(EGL_READ)) != NULL))
571 {
572 switch(attachment)
573 {
574 case GL_FRONT_LEFT:
575 attachment = GL_COLOR_ATTACHMENT0; isDefault = true; break;
576 case GL_FRONT_RIGHT:
577 attachment = GL_COLOR_ATTACHMENT2; isDefault = true; break;
578 case GL_BACK_LEFT:
579 attachment = GL_COLOR_ATTACHMENT1; isDefault = true; break;
580 case GL_BACK_RIGHT:
581 attachment = GL_COLOR_ATTACHMENT3; isDefault = true; break;
582 case GL_DEPTH:
583 {
584 VGLFBConfig config = pb->getFBConfig();
585 if(config->attr.stencilSize && config->attr.depthSize)
586 attachment = GL_DEPTH_STENCIL_ATTACHMENT;
587 else
588 attachment = GL_DEPTH_ATTACHMENT;
589 isDefault = true; break;
590 }
591 case GL_STENCIL:
592 {
593 VGLFBConfig config = pb->getFBConfig();
594 if(config->attr.stencilSize && config->attr.depthSize)
595 attachment = GL_DEPTH_STENCIL_ATTACHMENT;
596 else
597 attachment = GL_STENCIL_ATTACHMENT;
598 isDefault = true; break;
599 }
600 }
601 }
602 }
603 }
604 #endif
605 _glGetFramebufferAttachmentParameteriv(target, attachment, pname, params);
606 #ifdef EGLBACKEND
607 if(fconfig.egl)
608 {
609 if(isDefault && *params == GL_RENDERBUFFER)
610 *params = GL_FRAMEBUFFER_DEFAULT;
611 }
612 #endif
613 }
614
615
VGLGetFramebufferParameteriv(GLenum target,GLenum pname,GLint * params)616 void VGLGetFramebufferParameteriv(GLenum target, GLenum pname, GLint *params)
617 {
618 #ifdef EGLBACKEND
619 if(fconfig.egl)
620 {
621 if(!params)
622 {
623 _glGetFramebufferParameteriv(target, pname, params);
624 return;
625 }
626 vglfaker::VGLPbuffer *pb;
627 if(((target == GL_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER)
628 && (pb = getCurrentVGLPbuffer(EGL_DRAW)) != NULL)
629 || (target == GL_READ_FRAMEBUFFER
630 && (pb = getCurrentVGLPbuffer(EGL_READ)) != NULL))
631 {
632 if(pname == GL_DOUBLEBUFFER)
633 {
634 *params = pb->getFBConfig()->attr.doubleBuffer;
635 return;
636 }
637 else if(pname == GL_STEREO)
638 {
639 *params = pb->getFBConfig()->attr.stereo;
640 return;
641 }
642 }
643 }
644 #endif
645 _glGetFramebufferParameteriv(target, pname, params);
646 }
647
648
VGLGetIntegerv(GLenum pname,GLint * params)649 void VGLGetIntegerv(GLenum pname, GLint *params)
650 {
651 #ifdef EGLBACKEND
652 if(fconfig.egl)
653 {
654 if(!_eglBindAPI(EGL_OPENGL_API))
655 THROW("Could not enable OpenGL API");
656 EGLContext ctx = _eglGetCurrentContext();
657 VGLFBConfig config = ectxhash.findConfig(ctx);
658
659 if(!params || !config)
660 {
661 _glGetIntegerv(pname, params);
662 return;
663 }
664 else if(pname == GL_DOUBLEBUFFER)
665 {
666 vglfaker::VGLPbuffer *pb = getCurrentVGLPbuffer(EGL_DRAW);
667 if(pb)
668 {
669 *params = config->attr.doubleBuffer;
670 return;
671 }
672 }
673 else if(pname == GL_DRAW_BUFFER)
674 {
675 vglfaker::VGLPbuffer *pb = getCurrentVGLPbuffer(EGL_DRAW);
676 GLenum drawBuf = ectxhash.getDrawBuffer(ctx, 0);
677 if(pb)
678 {
679 *params = drawBuf;
680 return;
681 }
682 }
683 else if(pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
684 {
685 vglfaker::VGLPbuffer *pb = getCurrentVGLPbuffer(EGL_DRAW);
686 int index = pname - GL_DRAW_BUFFER0;
687 GLenum drawBuf = ectxhash.getDrawBuffer(ctx, index);
688 if(pb)
689 {
690 *params = drawBuf;
691 return;
692 }
693 }
694 else if(pname == GL_DRAW_FRAMEBUFFER_BINDING)
695 {
696 *params = ectxhash.getDrawFBO(ctx);
697 return;
698 }
699 else if(pname == GL_MAX_DRAW_BUFFERS)
700 {
701 _glGetIntegerv(GL_MAX_DRAW_BUFFERS, params);
702 if(*params > 16) *params = 16;
703 return;
704 }
705 else if(pname == GL_READ_BUFFER)
706 {
707 vglfaker::VGLPbuffer *pb = getCurrentVGLPbuffer(EGL_READ);
708 GLenum readBuf = ectxhash.getReadBuffer(ctx);
709 if(pb)
710 {
711 *params = readBuf;
712 return;
713 }
714 }
715 else if(pname == GL_READ_FRAMEBUFFER_BINDING)
716 {
717 *params = ectxhash.getReadFBO(ctx);
718 return;
719 }
720 else if(pname == GL_STEREO)
721 {
722 vglfaker::VGLPbuffer *pb = getCurrentVGLPbuffer(EGL_DRAW);
723 if(pb)
724 {
725 *params = config->attr.stereo;
726 return;
727 }
728 }
729 }
730 #endif
731 _glGetIntegerv(pname, params);
732 }
733
734
VGLGetNamedFramebufferParameteriv(GLuint framebuffer,GLenum pname,GLint * param)735 void VGLGetNamedFramebufferParameteriv(GLuint framebuffer, GLenum pname,
736 GLint *param)
737 {
738 #ifdef EGLBACKEND
739 if(fconfig.egl)
740 {
741 if(!param)
742 {
743 _glGetNamedFramebufferParameteriv(framebuffer, pname, param);
744 return;
745 }
746 vglfaker::VGLPbuffer *pb;
747 if(framebuffer == 0 && (pb = vpbhash.find(getCurrentDrawable())) != NULL)
748 {
749 if(pname == GL_DOUBLEBUFFER)
750 {
751 *param = pb->getFBConfig()->attr.doubleBuffer;
752 return;
753 }
754 else if(pname == GL_STEREO)
755 {
756 *param = pb->getFBConfig()->attr.stereo;
757 return;
758 }
759 else framebuffer = pb->getFBO();
760 }
761 }
762 #endif
763 _glGetNamedFramebufferParameteriv(framebuffer, pname, param);
764 }
765
766
VGLIsDirect(GLXContext ctx)767 Bool VGLIsDirect(GLXContext ctx)
768 {
769 #ifdef EGLBACKEND
770 if(fconfig.egl)
771 return True;
772 else
773 #endif
774 return _glXIsDirect(DPY3D, ctx);
775 }
776
777
VGLMakeCurrent(Display * dpy,GLXDrawable draw,GLXDrawable read,GLXContext ctx)778 Bool VGLMakeCurrent(Display *dpy, GLXDrawable draw, GLXDrawable read,
779 GLXContext ctx)
780 {
781 #ifdef EGLBACKEND
782 if(fconfig.egl)
783 {
784 try
785 {
786 if(!_eglBindAPI(EGL_OPENGL_API))
787 THROW("Could not enable OpenGL API");
788 EGLBoolean ret = (Bool)_eglMakeCurrent(EDPY, EGL_NO_SURFACE,
789 EGL_NO_SURFACE, (EGLContext)ctx);
790 if(!ret) THROW_EGL("eglMakeCurrent()");
791 setCurrentDrawable(draw);
792 setCurrentReadDrawable(read);
793 if(!ctx) return True;
794
795 vglfaker::VGLPbuffer *drawpb = NULL, *readpb = NULL;
796 drawpb = vpbhash.find(draw);
797 readpb = (read == draw ? drawpb : vpbhash.find(read));
798 GLint drawFBO = -1, readFBO = -1;
799 _glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &drawFBO);
800 _glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &readFBO);
801
802 if(drawpb) drawpb->createBuffer(false, true);
803 if(readpb && readpb != drawpb) readpb->createBuffer(false, true);
804
805 bool boundNewDrawFBO = false, boundNewReadFBO = false;
806 if(drawpb && (ectxhash.getDrawFBO(ctx) == 0 || drawFBO == 0))
807 {
808 _glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawpb->getFBO());
809 boundNewDrawFBO = true;
810 }
811 if(readpb && (ectxhash.getReadFBO(ctx) == 0 || readFBO == 0))
812 {
813 _glBindFramebuffer(GL_READ_FRAMEBUFFER, readpb->getFBO());
814 boundNewReadFBO = true;
815 }
816
817 VGLFBConfig config = ectxhash.findConfig(ctx);
818 if(drawpb)
819 {
820 if(drawFBO == 0 && config)
821 {
822 drawpb->setDrawBuffer(config->attr.doubleBuffer ?
823 GL_BACK : GL_FRONT, false);
824 _glViewport(0, 0, drawpb->getWidth(), drawpb->getHeight());
825 }
826 else if(boundNewDrawFBO)
827 {
828 const GLenum *oldDrawBufs; GLsizei nDrawBufs = 0;
829 oldDrawBufs = ectxhash.getDrawBuffers(ctx, nDrawBufs);
830 if(oldDrawBufs && nDrawBufs > 0)
831 {
832 drawpb->setDrawBuffers(nDrawBufs, oldDrawBufs, false);
833 delete [] oldDrawBufs;
834 }
835 }
836 }
837 if(readpb)
838 {
839 if(readFBO == 0 && config)
840 readpb->setReadBuffer(config->attr.doubleBuffer ?
841 GL_BACK : GL_FRONT, false);
842 else if(boundNewReadFBO)
843 {
844 GLenum oldReadBuf = ectxhash.getReadBuffer(ctx);
845 if(oldReadBuf) readpb->setReadBuffer(oldReadBuf, false);
846 }
847 }
848
849 return ret;
850 }
851 CATCH_EGL(X_GLXMakeContextCurrent)
852 return 0;
853 }
854 else
855 #endif
856 return _glXMakeContextCurrent(DPY3D, draw, read, ctx);
857 }
858
859
VGLNamedFramebufferDrawBuffer(GLuint framebuffer,GLenum buf,bool ext)860 void VGLNamedFramebufferDrawBuffer(GLuint framebuffer, GLenum buf, bool ext)
861 {
862 #ifdef EGLBACKEND
863 if(fconfig.egl)
864 {
865 vglfaker::VGLPbuffer *pb;
866 if(framebuffer == 0 && (pb = vpbhash.find(getCurrentDrawable())) != NULL)
867 {
868 pb->setDrawBuffer(buf, true);
869 return;
870 }
871 }
872 #endif
873 if(ext) _glFramebufferDrawBufferEXT(framebuffer, buf);
874 else _glNamedFramebufferDrawBuffer(framebuffer, buf);
875 }
876
877
VGLNamedFramebufferDrawBuffers(GLuint framebuffer,GLsizei n,const GLenum * bufs,bool ext)878 void VGLNamedFramebufferDrawBuffers(GLuint framebuffer, GLsizei n,
879 const GLenum *bufs, bool ext)
880 {
881 #ifdef EGLBACKEND
882 if(fconfig.egl)
883 {
884 vglfaker::VGLPbuffer *pb;
885 if(framebuffer == 0 && (pb = vpbhash.find(getCurrentDrawable())) != NULL)
886 {
887 pb->setDrawBuffers(n, bufs, true);
888 return;
889 }
890 }
891 #endif
892 if(ext) _glFramebufferDrawBuffersEXT(framebuffer, n, bufs);
893 else _glNamedFramebufferDrawBuffers(framebuffer, n, bufs);
894 }
895
896
VGLNamedFramebufferReadBuffer(GLuint framebuffer,GLenum mode,bool ext)897 void VGLNamedFramebufferReadBuffer(GLuint framebuffer, GLenum mode, bool ext)
898 {
899 #ifdef EGLBACKEND
900 if(fconfig.egl)
901 {
902 vglfaker::VGLPbuffer *pb;
903 if(framebuffer == 0
904 && (pb = vpbhash.find(getCurrentReadDrawable())) != NULL)
905 {
906 pb->setReadBuffer(mode, true);
907 return;
908 }
909 }
910 #endif
911 if(ext) _glFramebufferReadBufferEXT(framebuffer, mode);
912 else _glNamedFramebufferReadBuffer(framebuffer, mode);
913 }
914
915
VGLQueryContext(Display * dpy,GLXContext ctx,int attribute,int * value)916 int VGLQueryContext(Display *dpy, GLXContext ctx, int attribute, int *value)
917 {
918 #ifdef EGLBACKEND
919 if(fconfig.egl)
920 {
921 int retval = Success;
922 VGLFBConfig config;
923
924 if(!ctx || !(config = ectxhash.findConfig(ctx)))
925 {
926 vglfaker::sendGLXError(dpy, X_GLXQueryContext, GLXBadContext, false);
927 return GLX_BAD_CONTEXT;
928 }
929 switch(attribute)
930 {
931 case GLX_FBCONFIG_ID:
932 *value = config->id;
933 retval = Success;
934 break;
935 case GLX_RENDER_TYPE:
936 *value = GLX_RGBA_TYPE;
937 retval = Success;
938 break;
939 case GLX_SCREEN:
940 *value = config->screen;
941 retval = Success;
942 break;
943 default:
944 retval = GLX_BAD_ATTRIBUTE;
945 }
946
947 return retval;
948 }
949 else
950 #endif
951 {
952 int retval = _glXQueryContext(DPY3D, ctx, attribute, value);
953 if(fconfig.amdgpuHack && ctx && attribute == GLX_RENDER_TYPE && value
954 && *value == 0)
955 *value = GLX_RGBA_TYPE;
956 return retval;
957 }
958 }
959
960
VGLQueryDrawable(Display * dpy,GLXDrawable draw,int attribute,unsigned int * value)961 void VGLQueryDrawable(Display *dpy, GLXDrawable draw, int attribute,
962 unsigned int *value)
963 {
964 #ifdef EGLBACKEND
965 if(fconfig.egl)
966 {
967 vglfaker::VGLPbuffer *pb = NULL;
968
969 if(!value) return;
970
971 if(!draw || (pb = vpbhash.find(draw)) == NULL)
972 {
973 vglfaker::sendGLXError(dpy, X_GLXGetDrawableAttributes, GLXBadDrawable,
974 false);
975 return;
976 }
977
978 switch(attribute)
979 {
980 case GLX_WIDTH:
981 *value = pb->getWidth();
982 return;
983 case GLX_HEIGHT:
984 *value = pb->getHeight();
985 return;
986 case GLX_PRESERVED_CONTENTS:
987 *value = 1;
988 return;
989 case GLX_LARGEST_PBUFFER:
990 *value = 0;
991 return;
992 case GLX_FBCONFIG_ID:
993 *value = pb->getFBConfig() ? pb->getFBConfig()->id : 0;
994 return;
995 default:
996 return;
997 }
998 }
999 else
1000 #endif
1001 _glXQueryDrawable(DPY3D, draw, attribute, value);
1002 }
1003
1004
VGLQueryExtension(Display * dpy,int * majorOpcode,int * eventBase,int * errorBase)1005 Bool VGLQueryExtension(Display *dpy, int *majorOpcode, int *eventBase,
1006 int *errorBase)
1007 {
1008 #ifdef EGLBACKEND
1009 if(fconfig.egl)
1010 {
1011 // If the 2D X server has a GLX extension, then we hijack its major opcode
1012 // and error base.
1013 Bool retval = _XQueryExtension(dpy, "GLX", majorOpcode, eventBase,
1014 errorBase);
1015 // Otherwise, there is no sane way for the EGL back end to operate, mostly
1016 // because of XCB.
1017 if(!retval)
1018 THROW("The EGL back end requires a 2D X server with a GLX extension.");
1019 return retval;
1020 }
1021 // When using the GLX back end, all GLX errors will come from the 3D X
1022 // server.
1023 else
1024 #endif
1025 return _XQueryExtension(DPY3D, "GLX", majorOpcode, eventBase, errorBase);
1026 }
1027
1028
VGLReadBuffer(GLenum mode)1029 void VGLReadBuffer(GLenum mode)
1030 {
1031 #ifdef EGLBACKEND
1032 if(fconfig.egl)
1033 {
1034 vglfaker::VGLPbuffer *pb = getCurrentVGLPbuffer(EGL_READ);
1035 if(pb)
1036 {
1037 pb->setReadBuffer(mode, false);
1038 return;
1039 }
1040 }
1041 #endif
1042 _glReadBuffer(mode);
1043 }
1044
1045
VGLReadPixels(GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,void * data)1046 void VGLReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
1047 GLenum format, GLenum type, void *data)
1048 {
1049 #ifdef EGLBACKEND
1050 if(fconfig.egl)
1051 {
1052 bool fallthrough = true;
1053 VGLFBConfig config = ectxhash.findConfig(_eglGetCurrentContext());
1054 vglfaker::VGLPbuffer *readpb = getCurrentVGLPbuffer(EGL_READ);
1055
1056 if(config && config->attr.samples > 1 && readpb)
1057 {
1058 GLuint fbo = 0, rbo = 0;
1059 _glGenFramebuffers(1, &fbo);
1060 if(fbo)
1061 {
1062 vglfaker::BufferState
1063 bs(BS_DRAWFBO | BS_READFBO | BS_DRAWBUFS | BS_READBUF);
1064 _glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
1065
1066 _glGenRenderbuffers(1, &rbo);
1067 if(rbo)
1068 {
1069 vglfaker::BufferState bsRBO(BS_RBO);
1070 _glBindRenderbuffer(GL_RENDERBUFFER, rbo);
1071
1072 GLenum internalFormat = GL_RGB8;
1073 if(config->attr.redSize > 8) internalFormat = GL_RGB10_A2;
1074 else if(config->attr.alphaSize) internalFormat = GL_RGBA8;
1075 _glRenderbufferStorage(GL_RENDERBUFFER, internalFormat,
1076 readpb->getWidth(), readpb->getHeight());
1077 _glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1078 GL_RENDERBUFFER, rbo);
1079
1080 GLenum status = _glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
1081 if(status == GL_FRAMEBUFFER_COMPLETE)
1082 {
1083 _glBlitFramebuffer(0, 0, readpb->getWidth(), readpb->getHeight(),
1084 0, 0, readpb->getWidth(), readpb->getHeight(),
1085 GL_COLOR_BUFFER_BIT, GL_NEAREST);
1086 _glBindFramebuffer(GL_DRAW_FRAMEBUFFER, bs.getOldReadFBO());
1087 _glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
1088 _glReadPixels(x, y, width, height, format, type, data);
1089 fallthrough = false;
1090 }
1091 _glDeleteRenderbuffers(1, &rbo);
1092 }
1093 _glDeleteFramebuffers(1, &fbo);
1094 }
1095 }
1096 if(!fallthrough) return;
1097 }
1098 #endif
1099 _glReadPixels(x, y, width, height, format, type, data);
1100 }
1101
1102
VGLSwapBuffers(Display * dpy,GLXDrawable drawable)1103 void VGLSwapBuffers(Display *dpy, GLXDrawable drawable)
1104 {
1105 #ifdef EGLBACKEND
1106 if(fconfig.egl)
1107 {
1108 try
1109 {
1110 if(pmhash.find(dpy, drawable)) return;
1111
1112 vglfaker::VGLPbuffer *pb = NULL;
1113
1114 if(drawable && (pb = vpbhash.find(drawable)) != NULL)
1115 pb->swap();
1116 else
1117 vglfaker::sendGLXError(dpy, X_GLXSwapBuffers, GLXBadDrawable, false);
1118 }
1119 CATCH_EGL(X_GLXSwapBuffers)
1120 }
1121 else
1122 #endif
1123 _glXSwapBuffers(DPY3D, drawable);
1124 }
1125