1 #include "ppsspp_config.h"
2 
3 #include <cstring>
4 #include <set>
5 
6 #include "Common/StringUtils.h"
7 
8 #if PPSSPP_API(ANY_GL)
9 #include "Common/GPU/OpenGL/GLCommon.h"
10 
11 #if defined(_WIN32)
12 #include "GL/wglew.h"
13 #endif
14 #endif
15 
16 #include "Common/GPU/OpenGL/GLFeatures.h"
17 
18 #include "Common/Log.h"
19 
20 #if defined(USING_GLES2)
21 #if defined(__ANDROID__)
22 PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC eglGetSystemTimeFrequencyNV;
23 PFNEGLGETSYSTEMTIMENVPROC eglGetSystemTimeNV;
24 PFNGLDRAWTEXTURENVPROC glDrawTextureNV;
25 PFNGLBLITFRAMEBUFFERNVPROC glBlitFramebufferNV;
26 PFNGLMAPBUFFERPROC glMapBuffer;
27 
28 PFNGLDISCARDFRAMEBUFFEREXTPROC glDiscardFramebufferEXT;
29 PFNGLGENVERTEXARRAYSOESPROC glGenVertexArraysOES;
30 PFNGLBINDVERTEXARRAYOESPROC glBindVertexArrayOES;
31 PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArraysOES;
32 PFNGLISVERTEXARRAYOESPROC glIsVertexArrayOES;
33 #endif
34 #if !PPSSPP_PLATFORM(IOS)
35 #include "EGL/egl.h"
36 #endif
37 #endif
38 
39 GLExtensions gl_extensions;
40 std::string g_all_gl_extensions;
41 static std::set<std::string> g_set_gl_extensions;
42 std::string g_all_egl_extensions;
43 static std::set<std::string> g_set_egl_extensions;
44 
45 static bool extensionsDone = false;
46 static bool useCoreContext = false;
47 
ParseExtensionsString(const std::string & str,std::set<std::string> & output)48 static void ParseExtensionsString(const std::string& str, std::set<std::string> &output) {
49 	output.clear();
50 
51 	size_t next = 0;
52 	for (size_t pos = 0, len = str.length(); pos < len; ++pos) {
53 		if (str[pos] == ' ') {
54 			output.insert(str.substr(next, pos - next));
55 			// Skip the delimiter itself.
56 			next = pos + 1;
57 		}
58 	}
59 
60 	if (next == 0 && str.length() != 0) {
61 		output.insert(str);
62 	} else if (next < str.length()) {
63 		output.insert(str.substr(next));
64 	}
65 }
66 
VersionGEThan(int major,int minor,int sub)67 bool GLExtensions::VersionGEThan(int major, int minor, int sub) {
68 	if (gl_extensions.ver[0] > major)
69 		return true;
70 	if (gl_extensions.ver[0] < major)
71 		return false;
72 	if (gl_extensions.ver[1] > minor)
73 		return true;
74 	if (gl_extensions.ver[1] < minor)
75 		return false;
76 	return gl_extensions.ver[2] >= sub;
77 }
78 
GLSLVersion()79 int GLExtensions::GLSLVersion() {
80 	if (gl_extensions.IsGLES) {
81 		if (gl_extensions.GLES3) {
82 			// GLSL version matches ES version.
83 			return gl_extensions.ver[0] * 100 + gl_extensions.ver[1] * 10;
84 		} else {
85 			return 100;
86 		}
87 	} else {
88 		// Used for shader translation and core contexts (Apple drives fail without an exact match.)
89 		if (gl_extensions.VersionGEThan(3, 3)) {
90 			return gl_extensions.ver[0] * 100 + gl_extensions.ver[1] * 10;
91 		} else if (gl_extensions.VersionGEThan(3, 2)) {
92 			return 150;
93 		} else if (gl_extensions.VersionGEThan(3, 1)) {
94 			return 140;
95 		} else if (gl_extensions.VersionGEThan(3, 0)) {
96 			return 130;
97 		} else if (gl_extensions.VersionGEThan(2, 1)) {
98 			return 120;
99 		} else {
100 			return 110;
101 		}
102 	}
103 }
104 
ProcessGPUFeatures()105 void ProcessGPUFeatures() {
106 	gl_extensions.bugs = 0;
107 
108 	DEBUG_LOG(G3D, "Checking for GL driver bugs... vendor=%i model='%s'", (int)gl_extensions.gpuVendor, gl_extensions.model);
109 
110 	if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) {
111 		if (!strcmp(gl_extensions.model, "PowerVR SGX 545") ||
112 			  !strcmp(gl_extensions.model, "PowerVR SGX 544") ||
113 			  !strcmp(gl_extensions.model, "PowerVR SGX 544MP2") ||
114 			  !strcmp(gl_extensions.model, "PowerVR SGX 543") ||
115 			  !strcmp(gl_extensions.model, "PowerVR SGX 540") ||
116 			  !strcmp(gl_extensions.model, "PowerVR SGX 530") ||
117 				!strcmp(gl_extensions.model, "PowerVR SGX 520") ) {
118 			WARN_LOG(G3D, "GL DRIVER BUG: PVR with bad and terrible precision");
119 			gl_extensions.bugs |= BUG_PVR_SHADER_PRECISION_TERRIBLE | BUG_PVR_SHADER_PRECISION_BAD;
120 		} else {
121 			// TODO: I'm not sure if the Rogue series is affected by this.
122 			WARN_LOG(G3D, "GL DRIVER BUG: PVR with bad precision");
123 			gl_extensions.bugs |= BUG_PVR_SHADER_PRECISION_BAD;
124 		}
125 	}
126 }
127 
128 // http://stackoverflow.com/questions/16147700/opengl-es-using-tegra-specific-extensions-gl-ext-texture-array
129 
CheckGLExtensions()130 void CheckGLExtensions() {
131 
132 #if PPSSPP_API(ANY_GL)
133 
134 	// Make sure to only do this once. It's okay to call CheckGLExtensions from wherever.
135 	if (extensionsDone)
136 		return;
137 	extensionsDone = true;
138 	memset(&gl_extensions, 0, sizeof(gl_extensions));
139 	gl_extensions.IsCoreContext = useCoreContext;
140 
141 	const char *renderer = (const char *)glGetString(GL_RENDERER);
142 	const char *versionStr = (const char *)glGetString(GL_VERSION);
143 	const char *glslVersionStr = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
144 
145 
146 #ifdef USING_GLES2
147 	gl_extensions.IsGLES = !useCoreContext;
148 #else
149 	if (strstr(versionStr, "OpenGL ES") == versionStr) {
150 		// For desktops running GLES.
151 		gl_extensions.IsGLES = true;
152 	}
153 #endif
154 
155 	// Check vendor string to try and guess GPU
156 	const char *cvendor = (char *)glGetString(GL_VENDOR);
157 	// TODO: move this stuff to gpu_features.cpp
158 	if (cvendor) {
159 		const std::string vendor = StripSpaces(std::string(cvendor));
160 		if (vendor == "NVIDIA Corporation"
161 			|| vendor == "Nouveau"
162 			|| vendor == "nouveau") {
163 			gl_extensions.gpuVendor = GPU_VENDOR_NVIDIA;
164 		} else if (vendor == "Advanced Micro Devices, Inc."
165 			|| vendor == "ATI Technologies Inc."
166 			|| vendor == "AMD") {
167 			gl_extensions.gpuVendor = GPU_VENDOR_AMD;
168 		} else if (vendor == "Intel"
169 			|| vendor == "Intel Inc."
170 			|| vendor == "Intel Corporation"
171 			|| vendor == "Tungsten Graphics, Inc") { // We'll assume this last one means Intel
172 			gl_extensions.gpuVendor = GPU_VENDOR_INTEL;
173 		} else if (vendor == "ARM") {
174 			gl_extensions.gpuVendor = GPU_VENDOR_ARM;
175 		} else if (vendor == "Imagination Technologies") {
176 			gl_extensions.gpuVendor = GPU_VENDOR_IMGTEC;
177 		} else if (vendor == "Qualcomm") {
178 			gl_extensions.gpuVendor = GPU_VENDOR_QUALCOMM;
179 			sscanf(renderer, "Adreno (TM) %d", &gl_extensions.modelNumber);
180 		} else if (vendor == "Broadcom") {
181 			gl_extensions.gpuVendor = GPU_VENDOR_BROADCOM;
182 			// Just for reference: Galaxy Y has renderer == "VideoCore IV HW"
183 		} else if (vendor == "Vivante Corporation") {
184 			gl_extensions.gpuVendor = GPU_VENDOR_VIVANTE;
185 		} else if (vendor == "Apple Inc." || vendor == "Apple") {
186 			gl_extensions.gpuVendor = GPU_VENDOR_APPLE;
187 		} else {
188 			WARN_LOG(G3D, "Unknown GL vendor: '%s'", vendor.c_str());
189 			gl_extensions.gpuVendor = GPU_VENDOR_UNKNOWN;
190 		}
191 	} else {
192 		gl_extensions.gpuVendor = GPU_VENDOR_UNKNOWN;
193 	}
194 
195 	INFO_LOG(G3D, "GPU Vendor : %s ; renderer: %s version str: %s ; GLSL version str: %s", cvendor ? cvendor : "N/A", renderer ? renderer : "N/A", versionStr ? versionStr : "N/A", glslVersionStr ? glslVersionStr : "N/A");
196 
197 	if (renderer) {
198 		strncpy(gl_extensions.model, renderer, sizeof(gl_extensions.model));
199 		gl_extensions.model[sizeof(gl_extensions.model) - 1] = 0;
200 	}
201 
202 	// Start by assuming we're at 2.0.
203 	int parsed[2] = {2, 0};
204 	{ // Grab the version and attempt to parse.
205 		char buffer[128] = { 0 };
206 		if (versionStr) {
207 			strncpy(buffer, versionStr, sizeof(buffer) - 1);
208 		}
209 
210 		int len = (int)strlen(buffer);
211 		bool beforeDot = true;
212 		int lastDigit = 0;
213 		for (int i = 0; i < len; i++) {
214 			if (buffer[i] >= '0' && buffer[i] <= '9') {
215 				lastDigit = buffer[i] - '0';
216 				if (!beforeDot) {
217 					parsed[1] = lastDigit;
218 					break;
219 				}
220 			}
221 			if (beforeDot && buffer[i] == '.' && lastDigit) {
222 				parsed[0] = lastDigit;
223 				beforeDot = false;
224 			}
225 		}
226 		if (beforeDot && lastDigit) {
227 			parsed[0] = lastDigit;
228 		}
229 	}
230 
231 
232 	if (!gl_extensions.IsGLES) { // For desktop GL
233 		gl_extensions.ver[0] = parsed[0];
234 		gl_extensions.ver[1] = parsed[1];
235 
236 		// If the GL version >= 4.3, we know it's a true superset of OpenGL ES 3.0 and can thus enable
237 		// all the same modern paths.
238 		// Most of it could be enabled on lower GPUs as well, but let's start this way.
239 		if (gl_extensions.VersionGEThan(4, 3, 0)) {
240 			gl_extensions.GLES3 = true;
241 #ifdef USING_GLES2
242 			// Try to load up the other funcs if we're not using glew.
243 			gl3stubInit();
244 #endif
245 		}
246 	} else {
247 		// Start by assuming we're at 2.0.
248 		gl_extensions.ver[0] = 2;
249 
250 #ifdef GL_MAJOR_VERSION
251 		// Before grabbing the values, reset the error.
252 		glGetError();
253 		glGetIntegerv(GL_MAJOR_VERSION, &gl_extensions.ver[0]);
254 		glGetIntegerv(GL_MINOR_VERSION, &gl_extensions.ver[1]);
255 		// We check error here to detect if these properties were supported.
256 		if (glGetError() != GL_NO_ERROR) {
257 			// They weren't, reset to GLES 2.0.
258 			gl_extensions.ver[0] = 2;
259 			gl_extensions.ver[1] = 0;
260 		} else if (parsed[0] && (gl_extensions.ver[0] != parsed[0] || gl_extensions.ver[1] != parsed[1])) {
261 			// Something going wrong. Possible bug in GL ES drivers. See #9688
262 			INFO_LOG(G3D, "GL ES version mismatch. Version string '%s' parsed as %d.%d but API return %d.%d. Fallback to GL ES 2.0.",
263 				versionStr ? versionStr : "N/A", parsed[0], parsed[1], gl_extensions.ver[0], gl_extensions.ver[1]);
264 
265 			gl_extensions.ver[0] = 2;
266 			gl_extensions.ver[1] = 0;
267 		}
268 #endif
269 
270 		// If the above didn't give us a version, or gave us a crazy version, fallback.
271 #ifdef USING_GLES2
272 		if (gl_extensions.ver[0] < 3 || gl_extensions.ver[0] > 5) {
273 			// Try to load GLES 3.0 only if "3.0" found in version
274 			// This simple heuristic avoids issues on older devices where you can only call eglGetProcAddress a limited
275 			// number of times. Make sure to check for 3.0 in the shader version too to avoid false positives, see #5584.
276 			bool gl_3_0_in_string = strstr(versionStr, "3.0") && (glslVersionStr && strstr(glslVersionStr, "3.0"));
277 			bool gl_3_1_in_string = strstr(versionStr, "3.1") && (glslVersionStr && strstr(glslVersionStr, "3.1"));  // intentionally left out .1
278 			if ((gl_3_0_in_string || gl_3_1_in_string) && gl3stubInit()) {
279 				gl_extensions.ver[0] = 3;
280 				if (gl_3_1_in_string) {
281 					gl_extensions.ver[1] = 1;
282 				}
283 				gl_extensions.GLES3 = true;
284 				// Though, let's ban Mali from the GLES 3 path for now, see #4078
285 				if (strstr(renderer, "Mali") != 0) {
286 					gl_extensions.GLES3 = false;
287 				}
288 			} else {
289 				// Just to be safe.
290 				gl_extensions.ver[0] = 2;
291 				gl_extensions.ver[1] = 0;
292 			}
293 		} else {
294 			// Otherwise, let's trust GL_MAJOR_VERSION.  Note that Mali is intentionally not banned here.
295 			if (gl_extensions.ver[0] >= 3) {
296 				gl_extensions.GLES3 = gl3stubInit();
297 			}
298 		}
299 #else
300 		// If we have GLEW/similar, assume GLES3 loaded.
301 		gl_extensions.GLES3 = gl_extensions.ver[0] >= 3;
302 #endif
303 
304 		if (gl_extensions.GLES3) {
305 			if (gl_extensions.ver[1] >= 1) {
306 				INFO_LOG(G3D, "OpenGL ES 3.1 support detected!\n");
307 			} else {
308 				INFO_LOG(G3D, "OpenGL ES 3.0 support detected!\n");
309 			}
310 		}
311 	}
312 
313 	const char *extString = nullptr;
314 	if (gl_extensions.ver[0] >= 3) {
315 		// Let's use the new way for OpenGL 3.x+, required in the core profile.
316 		GLint numExtensions = 0;
317 		glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
318 		g_all_gl_extensions.clear();
319 		g_set_gl_extensions.clear();
320 		for (GLint i = 0; i < numExtensions; ++i) {
321 			const char *ext = (const char *)glGetStringi(GL_EXTENSIONS, i);
322 			g_set_gl_extensions.insert(ext);
323 			g_all_gl_extensions += ext;
324 			g_all_gl_extensions += " ";
325 		}
326 	} else {
327 		extString = (const char *)glGetString(GL_EXTENSIONS);
328 		g_all_gl_extensions = extString ? extString : "";
329 		ParseExtensionsString(g_all_gl_extensions, g_set_gl_extensions);
330 	}
331 
332 #if defined(WIN32) && !defined(__LIBRETRO__)
333 	const char *wglString = 0;
334 	if (wglGetExtensionsStringEXT)
335 		wglString = wglGetExtensionsStringEXT();
336 	g_all_egl_extensions = wglString ? wglString : "";
337 	ParseExtensionsString(g_all_egl_extensions, g_set_egl_extensions);
338 
339 	gl_extensions.EXT_swap_control_tear = g_set_egl_extensions.count("WGL_EXT_swap_control_tear") != 0;
340 #elif !defined(USING_GLES2)
341 	// const char *glXString = glXQueryExtensionString();
342 	// gl_extensions.EXT_swap_control_tear = strstr(glXString, "GLX_EXT_swap_control_tear") != 0;
343 #endif
344 
345 	// Check the desktop extension instead of the OES one. They are very similar.
346 	// Also explicitly check those ATI devices that claims to support npot
347 	if (renderer) {
348 		gl_extensions.OES_texture_npot = g_set_gl_extensions.count("GL_ARB_texture_non_power_of_two") != 0
349 			&& !(((strncmp(renderer, "ATI RADEON X", 12) == 0) || (strncmp(renderer, "ATI MOBILITY RADEON X", 21) == 0)));
350 	}
351 
352 	gl_extensions.ARB_blend_func_extended = g_set_gl_extensions.count("GL_ARB_blend_func_extended") != 0;
353 	gl_extensions.EXT_blend_func_extended = g_set_gl_extensions.count("GL_EXT_blend_func_extended") != 0;
354 	gl_extensions.ARB_conservative_depth = g_set_gl_extensions.count("GL_ARB_conservative_depth") != 0;
355 	gl_extensions.ARB_shader_image_load_store = (g_set_gl_extensions.count("GL_ARB_shader_image_load_store") != 0) || (g_set_gl_extensions.count("GL_EXT_shader_image_load_store") != 0);
356 	gl_extensions.ARB_shading_language_420pack = (g_set_gl_extensions.count("GL_ARB_shading_language_420pack") != 0);
357 	gl_extensions.EXT_bgra = g_set_gl_extensions.count("GL_EXT_bgra") != 0;
358 	gl_extensions.EXT_gpu_shader4 = g_set_gl_extensions.count("GL_EXT_gpu_shader4") != 0;
359 	gl_extensions.NV_framebuffer_blit = g_set_gl_extensions.count("GL_NV_framebuffer_blit") != 0;
360 	gl_extensions.NV_copy_image = g_set_gl_extensions.count("GL_NV_copy_image") != 0;
361 	gl_extensions.OES_copy_image = g_set_gl_extensions.count("GL_OES_copy_image") != 0;
362 	gl_extensions.EXT_copy_image = g_set_gl_extensions.count("GL_EXT_copy_image") != 0;
363 	gl_extensions.ARB_copy_image = g_set_gl_extensions.count("GL_ARB_copy_image") != 0;
364 	gl_extensions.ARB_buffer_storage = g_set_gl_extensions.count("GL_ARB_buffer_storage") != 0;
365 	gl_extensions.ARB_vertex_array_object = g_set_gl_extensions.count("GL_ARB_vertex_array_object") != 0;
366 	gl_extensions.ARB_texture_float = g_set_gl_extensions.count("GL_ARB_texture_float") != 0;
367 	gl_extensions.EXT_texture_filter_anisotropic = g_set_gl_extensions.count("GL_EXT_texture_filter_anisotropic") != 0 || g_set_gl_extensions.count("GL_ARB_texture_filter_anisotropic") != 0;
368 	gl_extensions.EXT_draw_instanced = g_set_gl_extensions.count("GL_EXT_draw_instanced") != 0;
369 	gl_extensions.ARB_draw_instanced = g_set_gl_extensions.count("GL_ARB_draw_instanced") != 0;
370 	gl_extensions.ARB_cull_distance = g_set_gl_extensions.count("GL_ARB_cull_distance") != 0;
371 	gl_extensions.ARB_depth_clamp = g_set_gl_extensions.count("GL_ARB_depth_clamp") != 0;
372 	gl_extensions.ARB_uniform_buffer_object = g_set_gl_extensions.count("GL_ARB_uniform_buffer_object") != 0;
373 	gl_extensions.ARB_explicit_attrib_location = g_set_gl_extensions.count("GL_ARB_explicit_attrib_location") != 0;
374 
375 	if (gl_extensions.IsGLES) {
376 		gl_extensions.OES_texture_npot = g_set_gl_extensions.count("GL_OES_texture_npot") != 0;
377 		gl_extensions.OES_packed_depth_stencil = (g_set_gl_extensions.count("GL_OES_packed_depth_stencil") != 0) || gl_extensions.GLES3;
378 		gl_extensions.OES_depth24 = g_set_gl_extensions.count("GL_OES_depth24") != 0;
379 		gl_extensions.OES_depth_texture = g_set_gl_extensions.count("GL_OES_depth_texture") != 0;
380 		gl_extensions.OES_mapbuffer = g_set_gl_extensions.count("GL_OES_mapbuffer") != 0;
381 		gl_extensions.EXT_blend_minmax = g_set_gl_extensions.count("GL_EXT_blend_minmax") != 0;
382 		gl_extensions.EXT_unpack_subimage = g_set_gl_extensions.count("GL_EXT_unpack_subimage") != 0;
383 		gl_extensions.EXT_shader_framebuffer_fetch = g_set_gl_extensions.count("GL_EXT_shader_framebuffer_fetch") != 0;
384 		gl_extensions.ARM_shader_framebuffer_fetch = g_set_gl_extensions.count("GL_ARM_shader_framebuffer_fetch") != 0;
385 		gl_extensions.OES_texture_float = g_set_gl_extensions.count("GL_OES_texture_float") != 0;
386 		gl_extensions.EXT_buffer_storage = g_set_gl_extensions.count("GL_EXT_buffer_storage") != 0;
387 		gl_extensions.EXT_clip_cull_distance = g_set_gl_extensions.count("GL_EXT_clip_cull_distance") != 0;
388 
389 #if defined(__ANDROID__)
390 		// On Android, incredibly, this is not consistently non-zero! It does seem to have the same value though.
391 		// https://twitter.com/ID_AA_Carmack/status/387383037794603008
392 #ifdef _DEBUG
393 		void *invalidAddress = (void *)eglGetProcAddress("InvalidGlCall1");
394 		void *invalidAddress2 = (void *)eglGetProcAddress("AnotherInvalidGlCall2");
395 		DEBUG_LOG(G3D, "Addresses returned for invalid extensions: %p %p", invalidAddress, invalidAddress2);
396 #endif
397 
398 		// These are all the same.  Let's alias.
399 		if (!gl_extensions.OES_copy_image) {
400 			if (gl_extensions.NV_copy_image) {
401 				glCopyImageSubDataOES = (decltype(glCopyImageSubDataOES))eglGetProcAddress("glCopyImageSubDataNV");
402 			} else if (gl_extensions.EXT_copy_image) {
403 				glCopyImageSubDataOES = (decltype(glCopyImageSubDataOES))eglGetProcAddress("glCopyImageSubDataEXT");
404 			}
405 		}
406 
407 		if (gl_extensions.NV_framebuffer_blit) {
408 			glBlitFramebufferNV = (PFNGLBLITFRAMEBUFFERNVPROC)eglGetProcAddress("glBlitFramebufferNV");
409 		}
410 
411 		gl_extensions.OES_vertex_array_object = g_set_gl_extensions.count("GL_OES_vertex_array_object") != 0;
412 		if (gl_extensions.OES_vertex_array_object) {
413 			glGenVertexArraysOES = (PFNGLGENVERTEXARRAYSOESPROC)eglGetProcAddress("glGenVertexArraysOES");
414 			glBindVertexArrayOES = (PFNGLBINDVERTEXARRAYOESPROC)eglGetProcAddress("glBindVertexArrayOES");
415 			glDeleteVertexArraysOES = (PFNGLDELETEVERTEXARRAYSOESPROC)eglGetProcAddress("glDeleteVertexArraysOES");
416 			glIsVertexArrayOES = (PFNGLISVERTEXARRAYOESPROC)eglGetProcAddress("glIsVertexArrayOES");
417 		}
418 
419 		// Hm, this should be available on iOS too.
420 		gl_extensions.EXT_discard_framebuffer = g_set_gl_extensions.count("GL_EXT_discard_framebuffer") != 0;
421 		if (gl_extensions.EXT_discard_framebuffer) {
422 			glDiscardFramebufferEXT = (PFNGLDISCARDFRAMEBUFFEREXTPROC)eglGetProcAddress("glDiscardFramebufferEXT");
423 		}
424 #else
425 		gl_extensions.OES_vertex_array_object = false;
426 		gl_extensions.EXT_discard_framebuffer = false;
427 #endif
428 	} else {
429 		// Desktops support minmax and subimage unpack (GL_UNPACK_ROW_LENGTH etc)
430 		gl_extensions.EXT_blend_minmax = true;
431 		gl_extensions.EXT_unpack_subimage = true;
432 	}
433 
434 	// GLES 3 subsumes many ES2 extensions.
435 	if (gl_extensions.GLES3) {
436 		gl_extensions.EXT_blend_minmax = true;
437 		gl_extensions.EXT_unpack_subimage = true;
438 	}
439 
440 #if defined(__ANDROID__)
441 	if (gl_extensions.OES_mapbuffer) {
442 		glMapBuffer = (PFNGLMAPBUFFERPROC)eglGetProcAddress("glMapBufferOES");
443 	}
444 
445 	// Look for EGL extensions
446 	EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
447 
448 	const char *eglString = eglQueryString(display, EGL_EXTENSIONS);
449 	g_all_egl_extensions = eglString ? eglString : "";
450 	ParseExtensionsString(g_all_egl_extensions, g_set_egl_extensions);
451 
452 	gl_extensions.EGL_NV_system_time = g_set_egl_extensions.count("EGL_NV_system_time") != 0;
453 	gl_extensions.EGL_NV_coverage_sample = g_set_egl_extensions.count("EGL_NV_coverage_sample") != 0;
454 
455 	if (gl_extensions.EGL_NV_system_time) {
456 		eglGetSystemTimeNV = (PFNEGLGETSYSTEMTIMENVPROC)eglGetProcAddress("eglGetSystemTimeNV");
457 		eglGetSystemTimeFrequencyNV = (PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC)eglGetProcAddress("eglGetSystemTimeFrequencyNV");
458 	}
459 #elif defined(USING_GLES2) && defined(__linux__)
460 	const char *eglString = eglQueryString(NULL, EGL_EXTENSIONS);
461 	g_all_egl_extensions = eglString ? eglString : "";
462 	if (eglString) {
463 		eglString = eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS);
464 		if (eglString) {
465 			g_all_egl_extensions.append(" ");
466 			g_all_egl_extensions.append(eglString);
467 		}
468 	}
469 	ParseExtensionsString(g_all_egl_extensions, g_set_egl_extensions);
470 #endif
471 
472 	glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &gl_extensions.maxVertexTextureUnits);
473 
474 #ifdef GL_LOW_FLOAT
475 	// This is probably a waste of time, implementations lie.
476 	if (gl_extensions.IsGLES || g_set_gl_extensions.count("GL_ARB_ES2_compatibility") || gl_extensions.VersionGEThan(4, 1)) {
477 		const GLint precisions[6] = {
478 			GL_LOW_FLOAT, GL_MEDIUM_FLOAT, GL_HIGH_FLOAT,
479 			GL_LOW_INT, GL_MEDIUM_INT, GL_HIGH_INT
480 		};
481 		GLint shaderTypes[2] = {
482 			GL_VERTEX_SHADER, GL_FRAGMENT_SHADER
483 		};
484 		for (int st = 0; st < 2; st++) {
485 			for (int p = 0; p < 6; p++) {
486 				glGetShaderPrecisionFormat(shaderTypes[st], precisions[p], gl_extensions.range[st][p], &gl_extensions.precision[st][p]);
487 			}
488 		}
489 
490 		// Now, old Adreno lies about supporting full precision integers. So let's override it.
491 		// The model number comparison should probably be 400 or 500. This causes us to avoid depal-in-shader.
492 		// It seems though that this caused large perf regressions on Adreno 5xx, so I've bumped it up to 600.
493 		if (gl_extensions.gpuVendor == GPU_VENDOR_QUALCOMM && gl_extensions.modelNumber < 600) {
494 			WARN_LOG(G3D, "Detected old Adreno - lowering reported int precision for safety");
495 			gl_extensions.range[1][5][0] = 15;
496 			gl_extensions.range[1][5][1] = 15;
497 		}
498 	}
499 #endif
500 
501 	gl_extensions.ARB_framebuffer_object = g_set_gl_extensions.count("GL_ARB_framebuffer_object") != 0;
502 	gl_extensions.EXT_framebuffer_object = g_set_gl_extensions.count("GL_EXT_framebuffer_object") != 0;
503 	gl_extensions.ARB_pixel_buffer_object = g_set_gl_extensions.count("GL_ARB_pixel_buffer_object") != 0;
504 	gl_extensions.NV_pixel_buffer_object = g_set_gl_extensions.count("GL_NV_pixel_buffer_object") != 0;
505 
506 	if (!gl_extensions.IsGLES && gl_extensions.IsCoreContext) {
507 		// These are required, and don't need to be specified by the driver (they aren't on Apple.)
508 		gl_extensions.ARB_vertex_array_object = true;
509 		gl_extensions.ARB_framebuffer_object = true;
510 	}
511 
512 	// Add any extensions that are included in core.  May be elided.
513 	if (!gl_extensions.IsGLES) {
514 		if (gl_extensions.VersionGEThan(3, 0)) {
515 			gl_extensions.ARB_texture_float = true;
516 		}
517 		if (gl_extensions.VersionGEThan(3, 1)) {
518 			gl_extensions.ARB_draw_instanced = true;
519 			gl_extensions.ARB_uniform_buffer_object = true;
520 		}
521 		if (gl_extensions.VersionGEThan(3, 2)) {
522 			gl_extensions.ARB_depth_clamp = true;
523 		}
524 		if (gl_extensions.VersionGEThan(3, 3)) {
525 			gl_extensions.ARB_blend_func_extended = true;
526 			gl_extensions.ARB_explicit_attrib_location = true;
527 		}
528 		if (gl_extensions.VersionGEThan(4, 0)) {
529 			// ARB_gpu_shader5 = true;
530 		}
531 		if (gl_extensions.VersionGEThan(4, 1)) {
532 			// ARB_get_program_binary = true;
533 			// ARB_separate_shader_objects = true;
534 			// ARB_shader_precision = true;
535 			// ARB_viewport_array = true;
536 		}
537 		if (gl_extensions.VersionGEThan(4, 2)) {
538 			// ARB_texture_storage = true;
539 		}
540 		if (gl_extensions.VersionGEThan(4, 3)) {
541 			gl_extensions.ARB_copy_image = true;
542 			// ARB_explicit_uniform_location = true;
543 			// ARB_stencil_texturing = true;
544 			// ARB_texture_view = true;
545 			// ARB_vertex_attrib_binding = true;
546 		}
547 		if (gl_extensions.VersionGEThan(4, 4)) {
548 			gl_extensions.ARB_buffer_storage = true;
549 		}
550 		if (gl_extensions.VersionGEThan(4, 5)) {
551 			gl_extensions.ARB_cull_distance = true;
552 		}
553 		if (gl_extensions.VersionGEThan(4, 6)) {
554 			// Actually ARB, but they're basically the same.
555 			gl_extensions.EXT_texture_filter_anisotropic = true;
556 		}
557 	}
558 
559 	ProcessGPUFeatures();
560 
561 	int error = glGetError();
562 	if (error)
563 		ERROR_LOG(G3D, "GL error in init: %i", error);
564 
565 #endif
566 
567 }
568 
SetGLCoreContext(bool flag)569 void SetGLCoreContext(bool flag) {
570 	_assert_msg_(!extensionsDone, "SetGLCoreContext() after CheckGLExtensions()");
571 
572 	useCoreContext = flag;
573 	// For convenience, it'll get reset later.
574 	gl_extensions.IsCoreContext = useCoreContext;
575 }
576 
ResetGLExtensions()577 void ResetGLExtensions() {
578 	extensionsDone = false;
579 
580 	gl_extensions = {};
581 	gl_extensions.IsCoreContext = useCoreContext;
582 	g_all_gl_extensions.clear();
583 	g_all_egl_extensions.clear();
584 }
585 
586 static const char *glsl_fragment_prelude =
587 "#ifdef GL_ES\n"
588 "precision mediump float;\n"
589 "#endif\n";
590 
ApplyGLSLPrelude(const std::string & source,uint32_t stage)591 std::string ApplyGLSLPrelude(const std::string &source, uint32_t stage) {
592 #if PPSSPP_API(ANY_GL)
593 	std::string temp;
594 	std::string version = "";
595 	if (!gl_extensions.IsGLES && gl_extensions.IsCoreContext) {
596 		// We need to add a corresponding #version.  Apple drivers fail without an exact match.
597 		version = StringFromFormat("#version %d\n", gl_extensions.GLSLVersion());
598 	} else if (gl_extensions.IsGLES && gl_extensions.GLES3) {
599 		version = StringFromFormat("#version %d es\n", gl_extensions.GLSLVersion());
600 	}
601 	if (stage == GL_FRAGMENT_SHADER) {
602 		temp = version + glsl_fragment_prelude + source;
603 	} else if (stage == GL_VERTEX_SHADER) {
604 		temp = version + source;
605 	}
606 	return temp;
607 #else
608 	return source;
609 #endif
610 }
611