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