| 
									
										
										
										
											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                         */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ | 
					
						
							|  |  |  | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */ | 
					
						
							|  |  |  | /*                                                                        */ | 
					
						
							|  |  |  | /* 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.                 */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-08 14:51:32 +02:00
										 |  |  | #if defined(X11_ENABLED) && 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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-12 21:46:16 +01:00
										 |  |  | #include "thirdparty/glad/glad/gl.h"
 | 
					
						
							|  |  |  | #include "thirdparty/glad/glad/glx.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-15 14:13:56 +02:00
										 |  |  | #ifdef SOWRAP_ENABLED
 | 
					
						
							| 
									
										
										
										
											2023-06-08 14:51:32 +02:00
										 |  |  | #include "x11/dynwrappers/xlib-so_wrap.h"
 | 
					
						
							| 
									
										
										
										
											2023-02-15 14:13:56 +02:00
										 |  |  | #else
 | 
					
						
							|  |  |  | #include <X11/XKBlib.h>
 | 
					
						
							|  |  |  | #include <X11/Xlib.h>
 | 
					
						
							|  |  |  | #include <X11/Xutil.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-08 14:51:32 +02:00
										 |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | #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 *); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-11 12:32:23 +02:00
										 |  |  | // To prevent shadowing warnings
 | 
					
						
							|  |  |  | #undef glGetString
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 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 | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-29 12:03:06 +01:00
										 |  |  | 	if (gladLoaderLoadGLX(x11_display, XScreenNumberOfScreen(XDefaultScreenOfDisplay(x11_display))) == 0) { | 
					
						
							|  |  |  | 		print_verbose("Unable to load GLX, GPU detection skipped."); | 
					
						
							|  |  |  | 		quick_exit(1); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 	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); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-06 12:17:14 +02:00
										 |  |  | int silent_error_handler(Display *display, XErrorEvent *error) { | 
					
						
							|  |  |  | 	static char message[1024]; | 
					
						
							|  |  |  | 	XGetErrorText(display, error->error_code, message, sizeof(message)); | 
					
						
							|  |  |  | 	print_verbose(vformat("XServer error: %s" | 
					
						
							|  |  |  | 						  "\n   Major opcode of failed request: %d" | 
					
						
							|  |  |  | 						  "\n   Serial number of failed request: %d" | 
					
						
							|  |  |  | 						  "\n   Current serial number in output stream: %d", | 
					
						
							|  |  |  | 			String::utf8(message), (uint64_t)error->request_code, (uint64_t)error->minor_code, (uint64_t)error->serial)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	quick_exit(1); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 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; | 
					
						
							| 
									
										
										
										
											2023-11-06 12:17:14 +02:00
										 |  |  | 			XSetErrorHandler(&silent_error_handler); | 
					
						
							| 
									
										
										
										
											2022-05-20 13:28:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 			char string[201]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			close(fdset[0]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-17 15:02:21 -05:00
										 |  |  | 			if (i) { | 
					
						
							| 
									
										
										
										
											2019-01-27 22:31:38 +00:00
										 |  |  | 				setenv("DRI_PRIME", "1", 1); | 
					
						
							| 
									
										
										
										
											2021-12-17 15:02:21 -05:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-11-12 21:46:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-08 14:51:32 +02:00
										 |  |  | #endif // X11_ENABLED && GLES3_ENABLED
 |