| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2020-03-03 10:36:29 -03:00
										 |  |  | /*  detect_prime_x11.cpp                                                 */ | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*                       This file is part of:                           */ | 
					
						
							|  |  |  | /*                           GODOT ENGINE                                */ | 
					
						
							|  |  |  | /*                      https://godotengine.org                          */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2022-01-03 21:27:34 +01:00
										 |  |  | /* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ | 
					
						
							|  |  |  | /* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */ | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* Permission is hereby granted, free of charge, to any person obtaining */ | 
					
						
							|  |  |  | /* a copy of this software and associated documentation files (the       */ | 
					
						
							|  |  |  | /* "Software"), to deal in the Software without restriction, including   */ | 
					
						
							|  |  |  | /* without limitation the rights to use, copy, modify, merge, publish,   */ | 
					
						
							|  |  |  | /* distribute, sublicense, and/or sell copies of the Software, and to    */ | 
					
						
							|  |  |  | /* permit persons to whom the Software is furnished to do so, subject to */ | 
					
						
							|  |  |  | /* the following conditions:                                             */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* The above copyright notice and this permission notice shall be        */ | 
					
						
							|  |  |  | /* included in all copies or substantial portions of the Software.       */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ | 
					
						
							|  |  |  | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ | 
					
						
							|  |  |  | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ | 
					
						
							|  |  |  | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ | 
					
						
							|  |  |  | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ | 
					
						
							|  |  |  | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ | 
					
						
							|  |  |  | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef X11_ENABLED
 | 
					
						
							| 
									
										
										
										
											2021-10-26 08:18:39 -07:00
										 |  |  | #if defined(GLES3_ENABLED)
 | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-18 18:11:30 +00:00
										 |  |  | #include "detect_prime_x11.h"
 | 
					
						
							| 
									
										
										
										
											2020-03-24 09:50:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-07 19:33:38 -03:00
										 |  |  | #include "core/string/print_string.h"
 | 
					
						
							|  |  |  | #include "core/string/ustring.h"
 | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-12 21:46:16 +01:00
										 |  |  | #include "thirdparty/glad/glad/gl.h"
 | 
					
						
							|  |  |  | #include "thirdparty/glad/glad/glx.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | #include <X11/Xlib.h>
 | 
					
						
							|  |  |  | #include <X11/Xutil.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <cstring>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <sys/types.h>
 | 
					
						
							|  |  |  | #include <sys/wait.h>
 | 
					
						
							|  |  |  | #include <unistd.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
 | 
					
						
							|  |  |  | #define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLXContext, Bool, const int *); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct vendor { | 
					
						
							| 
									
										
										
										
											2022-05-02 16:28:25 +02:00
										 |  |  | 	const char *glxvendor = nullptr; | 
					
						
							| 
									
										
										
										
											2020-11-24 10:12:55 +01:00
										 |  |  | 	int priority = 0; | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | vendor vendormap[] = { | 
					
						
							|  |  |  | 	{ "Advanced Micro Devices, Inc.", 30 }, | 
					
						
							| 
									
										
										
										
											2021-02-20 16:49:06 +01:00
										 |  |  | 	{ "AMD", 30 }, | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 	{ "NVIDIA Corporation", 30 }, | 
					
						
							|  |  |  | 	{ "X.Org", 30 }, | 
					
						
							|  |  |  | 	{ "Intel Open Source Technology Center", 20 }, | 
					
						
							| 
									
										
										
										
											2020-03-11 08:35:57 +01:00
										 |  |  | 	{ "Intel", 20 }, | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 	{ "nouveau", 10 }, | 
					
						
							|  |  |  | 	{ "Mesa Project", 0 }, | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 	{ nullptr, 0 } | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Runs inside a child. Exiting will not quit the engine.
 | 
					
						
							|  |  |  | void create_context() { | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 	Display *x11_display = XOpenDisplay(nullptr); | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 	Window x11_window; | 
					
						
							|  |  |  | 	GLXContext glx_context; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	static int visual_attribs[] = { | 
					
						
							|  |  |  | 		GLX_RENDER_TYPE, GLX_RGBA_BIT, | 
					
						
							|  |  |  | 		GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, | 
					
						
							|  |  |  | 		GLX_DOUBLEBUFFER, true, | 
					
						
							|  |  |  | 		GLX_RED_SIZE, 1, | 
					
						
							|  |  |  | 		GLX_GREEN_SIZE, 1, | 
					
						
							|  |  |  | 		GLX_BLUE_SIZE, 1, | 
					
						
							|  |  |  | 		GLX_DEPTH_SIZE, 24, | 
					
						
							|  |  |  | 		None | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int fbcount; | 
					
						
							| 
									
										
										
										
											2021-12-17 15:02:21 -05:00
										 |  |  | 	GLXFBConfig fbconfig = nullptr; | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 	XVisualInfo *vi = nullptr; | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	XSetWindowAttributes swa; | 
					
						
							|  |  |  | 	swa.event_mask = StructureNotifyMask; | 
					
						
							|  |  |  | 	swa.border_pixel = 0; | 
					
						
							|  |  |  | 	unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount); | 
					
						
							| 
									
										
										
										
											2021-12-17 15:02:21 -05:00
										 |  |  | 	if (!fbc) { | 
					
						
							| 
									
										
										
										
											2022-11-12 21:46:16 +01:00
										 |  |  | 		quick_exit(1); | 
					
						
							| 
									
										
										
										
											2021-12-17 15:02:21 -05:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	vi = glXGetVisualFromFBConfig(x11_display, fbc[0]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	fbconfig = fbc[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	static int context_attribs[] = { | 
					
						
							|  |  |  | 		GLX_CONTEXT_MAJOR_VERSION_ARB, 3, | 
					
						
							|  |  |  | 		GLX_CONTEXT_MINOR_VERSION_ARB, 3, | 
					
						
							|  |  |  | 		GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, | 
					
						
							|  |  |  | 		GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, | 
					
						
							|  |  |  | 		None | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 	glx_context = glXCreateContextAttribsARB(x11_display, fbconfig, nullptr, true, context_attribs); | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone); | 
					
						
							|  |  |  | 	x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, 10, 10, 0, vi->depth, InputOutput, vi->visual, valuemask, &swa); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-17 15:02:21 -05:00
										 |  |  | 	if (!x11_window) { | 
					
						
							| 
									
										
										
										
											2022-11-12 21:46:16 +01:00
										 |  |  | 		quick_exit(1); | 
					
						
							| 
									
										
										
										
											2021-12-17 15:02:21 -05:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	glXMakeCurrent(x11_display, x11_window, glx_context); | 
					
						
							|  |  |  | 	XFree(vi); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int detect_prime() { | 
					
						
							|  |  |  | 	pid_t p; | 
					
						
							| 
									
										
										
										
											2021-02-20 16:49:06 +01:00
										 |  |  | 	int priorities[2] = {}; | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 	String vendors[2]; | 
					
						
							|  |  |  | 	String renderers[2]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vendors[0] = "Unknown"; | 
					
						
							|  |  |  | 	vendors[1] = "Unknown"; | 
					
						
							|  |  |  | 	renderers[0] = "Unknown"; | 
					
						
							|  |  |  | 	renderers[1] = "Unknown"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (int i = 0; i < 2; ++i) { | 
					
						
							|  |  |  | 		int fdset[2]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (pipe(fdset) == -1) { | 
					
						
							|  |  |  | 			print_verbose("Failed to pipe(), using default GPU"); | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Fork so the driver initialization can crash without taking down the engine.
 | 
					
						
							|  |  |  | 		p = fork(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (p > 0) { | 
					
						
							|  |  |  | 			// Main thread
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			int stat_loc = 0; | 
					
						
							|  |  |  | 			char string[201]; | 
					
						
							|  |  |  | 			string[200] = '\0'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			close(fdset[1]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			waitpid(p, &stat_loc, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (!stat_loc) { | 
					
						
							|  |  |  | 				// No need to do anything complicated here. Anything less than
 | 
					
						
							|  |  |  | 				// PIPE_BUF will be delivered in one read() call.
 | 
					
						
							| 
									
										
										
										
											2019-06-19 10:41:07 +02:00
										 |  |  | 				// Leave it 'Unknown' otherwise.
 | 
					
						
							|  |  |  | 				if (read(fdset[0], string, sizeof(string) - 1) > 0) { | 
					
						
							|  |  |  | 					vendors[i] = string; | 
					
						
							|  |  |  | 					renderers[i] = string + strlen(string) + 1; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			close(fdset[0]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			// In child, exit() here will not quit the engine.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-20 13:28:44 +01:00
										 |  |  | 			// Prevent false leak reports as we will not be properly
 | 
					
						
							|  |  |  | 			// cleaning up these processes, and fork() makes a copy
 | 
					
						
							|  |  |  | 			// of all globals.
 | 
					
						
							|  |  |  | 			CoreGlobals::leak_reporting_enabled = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 			char string[201]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			close(fdset[0]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-17 15:02:21 -05:00
										 |  |  | 			if (i) { | 
					
						
							| 
									
										
										
										
											2020-05-10 12:56:01 +02:00
										 |  |  | 				setenv("DRI_PRIME", "1", 1); | 
					
						
							| 
									
										
										
										
											2021-12-17 15:02:21 -05:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-11-12 21:46:16 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if (gladLoaderLoadGLX(NULL, 0) == 0) { | 
					
						
							|  |  |  | 				print_verbose("Unable to load GLX, GPU detection skipped."); | 
					
						
							|  |  |  | 				quick_exit(1); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 			create_context(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-12 21:46:16 +01:00
										 |  |  | 			PFNGLGETSTRINGPROC glGetString = (PFNGLGETSTRINGPROC)glXGetProcAddressARB((GLubyte *)"glGetString"); | 
					
						
							|  |  |  | 			if (!glGetString) { | 
					
						
							|  |  |  | 				print_verbose("Unable to get glGetString, GPU detection skipped."); | 
					
						
							|  |  |  | 				quick_exit(1); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 			const char *vendor = (const char *)glGetString(GL_VENDOR); | 
					
						
							|  |  |  | 			const char *renderer = (const char *)glGetString(GL_RENDERER); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-21 20:57:39 +01:00
										 |  |  | 			unsigned int vendor_len = strlen(vendor) + 1; | 
					
						
							|  |  |  | 			unsigned int renderer_len = strlen(renderer) + 1; | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if (vendor_len + renderer_len >= sizeof(string)) { | 
					
						
							|  |  |  | 				renderer_len = 200 - vendor_len; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			memcpy(&string, vendor, vendor_len); | 
					
						
							|  |  |  | 			memcpy(&string[vendor_len], renderer, renderer_len); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-19 10:41:07 +02:00
										 |  |  | 			if (write(fdset[1], string, vendor_len + renderer_len) == -1) { | 
					
						
							|  |  |  | 				print_verbose("Couldn't write vendor/renderer string."); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 			close(fdset[1]); | 
					
						
							| 
									
										
										
										
											2022-11-07 09:27:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// The function quick_exit() is used because exit() will call destructors on static objects copied by fork().
 | 
					
						
							|  |  |  | 			// These objects will be freed anyway when the process finishes execution.
 | 
					
						
							|  |  |  | 			quick_exit(0); | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int preferred = 0; | 
					
						
							|  |  |  | 	int priority = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (vendors[0] == vendors[1]) { | 
					
						
							|  |  |  | 		print_verbose("Only one GPU found, using default."); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (int i = 1; i >= 0; --i) { | 
					
						
							|  |  |  | 		vendor *v = vendormap; | 
					
						
							|  |  |  | 		while (v->glxvendor) { | 
					
						
							|  |  |  | 			if (v->glxvendor == vendors[i]) { | 
					
						
							|  |  |  | 				priorities[i] = v->priority; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (v->priority >= priority) { | 
					
						
							|  |  |  | 					priority = v->priority; | 
					
						
							|  |  |  | 					preferred = i; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			++v; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	print_verbose("Found renderers:"); | 
					
						
							|  |  |  | 	for (int i = 0; i < 2; ++i) { | 
					
						
							|  |  |  | 		print_verbose("Renderer " + itos(i) + ": " + renderers[i] + " with priority: " + itos(priorities[i])); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	print_verbose("Using renderer: " + renderers[preferred]); | 
					
						
							|  |  |  | 	return preferred; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #endif
 |