Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/GPU/OpenGL/GLFeatures.cpp
5663 views
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
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.emplace(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.emplace(str.substr(next));
64
}
65
}
66
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
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
105
void ProcessGPUFeatures() {
106
gl_extensions.bugs = 0;
107
108
DEBUG_LOG(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(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(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
130
bool CheckGLExtensions() {
131
#if PPSSPP_API(ANY_GL)
132
// Make sure to only do this once. It's okay to call CheckGLExtensions from wherever,
133
// as long as you're on the rendering thread (the one with the GL context).
134
if (extensionsDone) {
135
return true;
136
}
137
138
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
if (!renderer || !versionStr || !glslVersionStr) {
146
// Something is very wrong! Bail.
147
return false;
148
}
149
150
extensionsDone = true;
151
152
#ifdef USING_GLES2
153
gl_extensions.IsGLES = !useCoreContext;
154
#else
155
if (strstr(versionStr, "OpenGL ES") == versionStr) {
156
// For desktops running GLES.
157
gl_extensions.IsGLES = true;
158
}
159
#endif
160
161
// Check vendor string to try and guess GPU
162
const char *cvendor = (char *)glGetString(GL_VENDOR);
163
// TODO: move this stuff to gpu_features.cpp
164
if (cvendor) {
165
const std::string vendor(StripSpaces(cvendor));
166
if (vendor == "NVIDIA Corporation"
167
|| vendor == "Nouveau"
168
|| vendor == "nouveau") {
169
gl_extensions.gpuVendor = GPU_VENDOR_NVIDIA;
170
} else if (vendor == "Advanced Micro Devices, Inc."
171
|| vendor == "ATI Technologies Inc."
172
|| vendor == "AMD") {
173
gl_extensions.gpuVendor = GPU_VENDOR_AMD;
174
} else if (vendor == "Intel"
175
|| vendor == "Intel Inc."
176
|| vendor == "Intel Corporation"
177
|| vendor == "Tungsten Graphics, Inc") { // We'll assume this last one means Intel
178
gl_extensions.gpuVendor = GPU_VENDOR_INTEL;
179
} else if (vendor == "ARM") {
180
gl_extensions.gpuVendor = GPU_VENDOR_ARM;
181
} else if (vendor == "Imagination Technologies") {
182
gl_extensions.gpuVendor = GPU_VENDOR_IMGTEC;
183
} else if (vendor == "Qualcomm") {
184
gl_extensions.gpuVendor = GPU_VENDOR_QUALCOMM;
185
if (1 != sscanf(renderer, "Adreno (TM) %d", &gl_extensions.modelNumber)) {
186
gl_extensions.modelNumber = 300; // or what should we default to?
187
}
188
} else if (vendor == "Broadcom") {
189
gl_extensions.gpuVendor = GPU_VENDOR_BROADCOM;
190
// Just for reference: Galaxy Y has renderer == "VideoCore IV HW"
191
} else if (vendor == "Vivante Corporation") {
192
gl_extensions.gpuVendor = GPU_VENDOR_VIVANTE;
193
} else if (vendor == "Apple Inc." || vendor == "Apple") {
194
gl_extensions.gpuVendor = GPU_VENDOR_APPLE;
195
} else {
196
WARN_LOG(Log::G3D, "Unknown GL vendor: '%s'", vendor.c_str());
197
gl_extensions.gpuVendor = GPU_VENDOR_UNKNOWN;
198
}
199
} else {
200
gl_extensions.gpuVendor = GPU_VENDOR_UNKNOWN;
201
}
202
203
INFO_LOG(Log::G3D, "GPU Vendor : %s ; renderer: %s version str: %s ; GLSL version str: %s", cvendor ? cvendor : "N/A", renderer, versionStr ? versionStr : "N/A", glslVersionStr ? glslVersionStr : "N/A");
204
205
strncpy(gl_extensions.model, renderer, sizeof(gl_extensions.model));
206
gl_extensions.model[sizeof(gl_extensions.model) - 1] = 0;
207
208
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl_extensions.maxTextureSize);
209
#ifndef USING_GLES2
210
glGetIntegerv(GL_MAX_CLIP_PLANES, &gl_extensions.maxClipPlanes);
211
#endif
212
213
// Start by assuming we're at 2.0.
214
int parsed[2] = {2, 0};
215
{ // Grab the version and attempt to parse.
216
char buffer[128]{};
217
truncate_cpy(buffer, versionStr);
218
219
const int len = (int)strlen(buffer);
220
bool beforeDot = true;
221
int lastDigit = 0;
222
for (int i = 0; i < len; i++) {
223
if (buffer[i] >= '0' && buffer[i] <= '9') {
224
lastDigit = buffer[i] - '0';
225
if (!beforeDot) {
226
parsed[1] = lastDigit;
227
break;
228
}
229
}
230
if (beforeDot && buffer[i] == '.' && lastDigit) {
231
parsed[0] = lastDigit;
232
beforeDot = false;
233
}
234
}
235
if (beforeDot && lastDigit) {
236
parsed[0] = lastDigit;
237
}
238
}
239
240
241
if (!gl_extensions.IsGLES) { // For desktop GL
242
gl_extensions.ver[0] = parsed[0];
243
gl_extensions.ver[1] = parsed[1];
244
245
// If the GL version >= 4.3, we know it's a true superset of OpenGL ES 3.0 and can thus enable
246
// all the same modern paths.
247
// Most of it could be enabled on lower GPUs as well, but let's start this way.
248
if (gl_extensions.VersionGEThan(4, 3, 0)) {
249
gl_extensions.GLES3 = true;
250
#ifdef USING_GLES2
251
// Try to load up the other funcs if we're not using glew.
252
gl3stubInit();
253
#endif
254
}
255
} else {
256
// Start by assuming we're at 2.0.
257
gl_extensions.ver[0] = 2;
258
259
#ifdef GL_MAJOR_VERSION
260
// Before grabbing the values, reset the error.
261
glGetError();
262
glGetIntegerv(GL_MAJOR_VERSION, &gl_extensions.ver[0]);
263
glGetIntegerv(GL_MINOR_VERSION, &gl_extensions.ver[1]);
264
// We check error here to detect if these properties were supported.
265
if (glGetError() != GL_NO_ERROR) {
266
// They weren't, reset to GLES 2.0.
267
gl_extensions.ver[0] = 2;
268
gl_extensions.ver[1] = 0;
269
} else if (parsed[0] && (gl_extensions.ver[0] != parsed[0] || gl_extensions.ver[1] != parsed[1])) {
270
// Something going wrong. Possible bug in GL ES drivers. See #9688
271
INFO_LOG(Log::G3D, "GL ES version mismatch. Version string '%s' parsed as %d.%d but API return %d.%d. Fallback to GL ES 2.0.",
272
versionStr ? versionStr : "N/A", parsed[0], parsed[1], gl_extensions.ver[0], gl_extensions.ver[1]);
273
274
gl_extensions.ver[0] = 2;
275
gl_extensions.ver[1] = 0;
276
}
277
#endif
278
279
// If the above didn't give us a version, or gave us a crazy version, fallback.
280
#ifdef USING_GLES2
281
if (versionStr && (gl_extensions.ver[0] < 3 || gl_extensions.ver[0] > 5)) {
282
// Try to load GLES 3.0 only if "3.0" found in version
283
// This simple heuristic avoids issues on older devices where you can only call eglGetProcAddress a limited
284
// number of times. Make sure to check for 3.0 in the shader version too to avoid false positives, see #5584.
285
bool gl_3_0_in_string = versionStr && strstr(versionStr, "3.0") && glslVersionStr && strstr(glslVersionStr, "3.0");
286
bool gl_3_1_in_string = versionStr && strstr(versionStr, "3.1") && glslVersionStr && strstr(glslVersionStr, "3.1"); // intentionally left out .1
287
if ((gl_3_0_in_string || gl_3_1_in_string) && gl3stubInit()) {
288
gl_extensions.ver[0] = 3;
289
if (gl_3_1_in_string) {
290
gl_extensions.ver[1] = 1;
291
}
292
gl_extensions.GLES3 = true;
293
// Though, let's ban Mali from the GLES 3 path for now, see #4078
294
if (strstr(renderer, "Mali") != 0) {
295
INFO_LOG(Log::G3D, "Forcing GLES3 off for Mali driver version: %s\n", versionStr ? versionStr : "N/A");
296
gl_extensions.GLES3 = false;
297
}
298
} else {
299
// Just to be safe.
300
gl_extensions.ver[0] = 2;
301
gl_extensions.ver[1] = 0;
302
}
303
} else {
304
// Otherwise, let's trust GL_MAJOR_VERSION. Note that Mali is intentionally not banned here.
305
if (gl_extensions.ver[0] >= 3) {
306
gl_extensions.GLES3 = gl3stubInit();
307
}
308
}
309
#else
310
// If we have GLEW/similar, assume GLES3 loaded.
311
gl_extensions.GLES3 = gl_extensions.ver[0] >= 3;
312
#endif
313
314
if (gl_extensions.GLES3) {
315
if (gl_extensions.ver[1] >= 1) {
316
INFO_LOG(Log::G3D, "OpenGL ES 3.1 support detected!\n");
317
} else {
318
INFO_LOG(Log::G3D, "OpenGL ES 3.0 support detected!\n");
319
}
320
}
321
}
322
323
const char *extString = nullptr;
324
if (gl_extensions.ver[0] >= 3) {
325
// Let's use the new way for OpenGL 3.x+, required in the core profile.
326
GLint numExtensions = 0;
327
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
328
g_all_gl_extensions.clear();
329
g_set_gl_extensions.clear();
330
for (GLint i = 0; i < numExtensions; ++i) {
331
const char *ext = (const char *)glGetStringi(GL_EXTENSIONS, i);
332
g_set_gl_extensions.insert(ext);
333
g_all_gl_extensions += ext;
334
g_all_gl_extensions += " ";
335
}
336
} else {
337
extString = (const char *)glGetString(GL_EXTENSIONS);
338
g_all_gl_extensions = extString ? extString : "";
339
ParseExtensionsString(g_all_gl_extensions, g_set_gl_extensions);
340
}
341
342
#if defined(WIN32) && !defined(__LIBRETRO__)
343
const char *wglString = 0;
344
if (wglGetExtensionsStringEXT)
345
wglString = wglGetExtensionsStringEXT();
346
g_all_egl_extensions = wglString ? wglString : "";
347
ParseExtensionsString(g_all_egl_extensions, g_set_egl_extensions);
348
349
gl_extensions.EXT_swap_control_tear = g_set_egl_extensions.count("WGL_EXT_swap_control_tear") != 0;
350
#elif !defined(USING_GLES2)
351
// const char *glXString = glXQueryExtensionString();
352
// gl_extensions.EXT_swap_control_tear = strstr(glXString, "GLX_EXT_swap_control_tear") != 0;
353
#endif
354
355
// Check the desktop extension instead of the OES one. They are very similar.
356
// Also explicitly check those ATI devices that claims to support npot
357
gl_extensions.OES_texture_npot = g_set_gl_extensions.count("GL_ARB_texture_non_power_of_two") != 0
358
&& !(((strncmp(renderer, "ATI RADEON X", 12) == 0) || (strncmp(renderer, "ATI MOBILITY RADEON X", 21) == 0)));
359
360
gl_extensions.ARB_conservative_depth = g_set_gl_extensions.count("GL_ARB_conservative_depth") != 0;
361
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);
362
gl_extensions.ARB_shading_language_420pack = (g_set_gl_extensions.count("GL_ARB_shading_language_420pack") != 0);
363
gl_extensions.EXT_bgra = g_set_gl_extensions.count("GL_EXT_bgra") != 0;
364
gl_extensions.EXT_gpu_shader4 = g_set_gl_extensions.count("GL_EXT_gpu_shader4") != 0;
365
gl_extensions.NV_framebuffer_blit = g_set_gl_extensions.count("GL_NV_framebuffer_blit") != 0;
366
gl_extensions.NV_copy_image = g_set_gl_extensions.count("GL_NV_copy_image") != 0;
367
gl_extensions.OES_copy_image = g_set_gl_extensions.count("GL_OES_copy_image") != 0;
368
gl_extensions.EXT_copy_image = g_set_gl_extensions.count("GL_EXT_copy_image") != 0;
369
gl_extensions.ARB_copy_image = g_set_gl_extensions.count("GL_ARB_copy_image") != 0;
370
gl_extensions.ARB_buffer_storage = g_set_gl_extensions.count("GL_ARB_buffer_storage") != 0;
371
gl_extensions.ARB_vertex_array_object = g_set_gl_extensions.count("GL_ARB_vertex_array_object") != 0;
372
gl_extensions.ARB_texture_float = g_set_gl_extensions.count("GL_ARB_texture_float") != 0;
373
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;
374
gl_extensions.EXT_draw_instanced = g_set_gl_extensions.count("GL_EXT_draw_instanced") != 0;
375
gl_extensions.ARB_draw_instanced = g_set_gl_extensions.count("GL_ARB_draw_instanced") != 0;
376
gl_extensions.ARB_cull_distance = g_set_gl_extensions.count("GL_ARB_cull_distance") != 0;
377
gl_extensions.ARB_depth_clamp = g_set_gl_extensions.count("GL_ARB_depth_clamp") != 0;
378
gl_extensions.ARB_uniform_buffer_object = g_set_gl_extensions.count("GL_ARB_uniform_buffer_object") != 0;
379
gl_extensions.ARB_explicit_attrib_location = g_set_gl_extensions.count("GL_ARB_explicit_attrib_location") != 0;
380
gl_extensions.ARB_texture_non_power_of_two = g_set_gl_extensions.count("GL_ARB_texture_non_power_of_two") != 0;
381
gl_extensions.ARB_shader_stencil_export = g_set_gl_extensions.count("GL_ARB_shader_stencil_export") != 0;
382
gl_extensions.ARB_texture_compression_bptc = g_set_gl_extensions.count("GL_ARB_texture_compression_bptc") != 0;
383
gl_extensions.ARB_texture_compression_rgtc = g_set_gl_extensions.count("GL_ARB_texture_compression_rgtc") != 0;
384
gl_extensions.KHR_texture_compression_astc_ldr = g_set_gl_extensions.count("GL_KHR_texture_compression_astc_ldr") != 0;
385
gl_extensions.EXT_texture_compression_s3tc = g_set_gl_extensions.count("GL_EXT_texture_compression_s3tc") != 0;
386
gl_extensions.OES_texture_compression_astc = g_set_gl_extensions.count("GL_OES_texture_compression_astc") != 0;
387
388
if (gl_extensions.IsGLES) {
389
gl_extensions.EXT_blend_func_extended = g_set_gl_extensions.count("GL_EXT_blend_func_extended") != 0;
390
gl_extensions.OES_texture_npot = g_set_gl_extensions.count("GL_OES_texture_npot") != 0;
391
gl_extensions.OES_packed_depth_stencil = (g_set_gl_extensions.count("GL_OES_packed_depth_stencil") != 0) || gl_extensions.GLES3;
392
gl_extensions.OES_depth24 = g_set_gl_extensions.count("GL_OES_depth24") != 0;
393
gl_extensions.OES_depth_texture = g_set_gl_extensions.count("GL_OES_depth_texture") != 0;
394
gl_extensions.OES_mapbuffer = g_set_gl_extensions.count("GL_OES_mapbuffer") != 0;
395
gl_extensions.EXT_blend_minmax = g_set_gl_extensions.count("GL_EXT_blend_minmax") != 0;
396
gl_extensions.EXT_unpack_subimage = g_set_gl_extensions.count("GL_EXT_unpack_subimage") != 0;
397
gl_extensions.EXT_shader_framebuffer_fetch = g_set_gl_extensions.count("GL_EXT_shader_framebuffer_fetch") != 0;
398
gl_extensions.ARM_shader_framebuffer_fetch = g_set_gl_extensions.count("GL_ARM_shader_framebuffer_fetch") != 0;
399
gl_extensions.OES_texture_float = g_set_gl_extensions.count("GL_OES_texture_float") != 0;
400
gl_extensions.OES_texture_3D = g_set_gl_extensions.count("GL_OES_texture_3D") != 0;
401
gl_extensions.EXT_buffer_storage = g_set_gl_extensions.count("GL_EXT_buffer_storage") != 0;
402
gl_extensions.EXT_clip_cull_distance = g_set_gl_extensions.count("GL_EXT_clip_cull_distance") != 0;
403
gl_extensions.EXT_depth_clamp = g_set_gl_extensions.count("GL_EXT_depth_clamp") != 0;
404
gl_extensions.APPLE_clip_distance = g_set_gl_extensions.count("GL_APPLE_clip_distance") != 0;
405
406
#if defined(__ANDROID__)
407
// On Android, incredibly, this is not consistently non-zero! It does seem to have the same value though.
408
// https://twitter.com/ID_AA_Carmack/status/387383037794603008
409
#ifdef _DEBUG
410
void *invalidAddress = (void *)eglGetProcAddress("InvalidGlCall1");
411
void *invalidAddress2 = (void *)eglGetProcAddress("AnotherInvalidGlCall2");
412
DEBUG_LOG(Log::G3D, "Addresses returned for invalid extensions: %p %p", invalidAddress, invalidAddress2);
413
#endif
414
415
// These are all the same. Let's alias.
416
if (!gl_extensions.OES_copy_image) {
417
if (gl_extensions.NV_copy_image) {
418
glCopyImageSubDataOES = (decltype(glCopyImageSubDataOES))eglGetProcAddress("glCopyImageSubDataNV");
419
} else if (gl_extensions.EXT_copy_image) {
420
glCopyImageSubDataOES = (decltype(glCopyImageSubDataOES))eglGetProcAddress("glCopyImageSubDataEXT");
421
}
422
}
423
424
if (gl_extensions.NV_framebuffer_blit) {
425
glBlitFramebufferNV = (PFNGLBLITFRAMEBUFFERNVPROC)eglGetProcAddress("glBlitFramebufferNV");
426
}
427
428
gl_extensions.OES_vertex_array_object = g_set_gl_extensions.count("GL_OES_vertex_array_object") != 0;
429
if (gl_extensions.OES_vertex_array_object) {
430
glGenVertexArraysOES = (PFNGLGENVERTEXARRAYSOESPROC)eglGetProcAddress("glGenVertexArraysOES");
431
glBindVertexArrayOES = (PFNGLBINDVERTEXARRAYOESPROC)eglGetProcAddress("glBindVertexArrayOES");
432
glDeleteVertexArraysOES = (PFNGLDELETEVERTEXARRAYSOESPROC)eglGetProcAddress("glDeleteVertexArraysOES");
433
glIsVertexArrayOES = (PFNGLISVERTEXARRAYOESPROC)eglGetProcAddress("glIsVertexArrayOES");
434
}
435
436
// Hm, this should be available on iOS too.
437
gl_extensions.EXT_discard_framebuffer = g_set_gl_extensions.count("GL_EXT_discard_framebuffer") != 0;
438
if (gl_extensions.EXT_discard_framebuffer) {
439
glDiscardFramebufferEXT = (PFNGLDISCARDFRAMEBUFFEREXTPROC)eglGetProcAddress("glDiscardFramebufferEXT");
440
}
441
#else
442
gl_extensions.OES_vertex_array_object = false;
443
gl_extensions.EXT_discard_framebuffer = false;
444
#endif
445
} else {
446
gl_extensions.ARB_blend_func_extended = g_set_gl_extensions.count("GL_ARB_blend_func_extended") != 0;
447
448
// Desktops support minmax and subimage unpack (GL_UNPACK_ROW_LENGTH etc)
449
gl_extensions.EXT_blend_minmax = true;
450
gl_extensions.EXT_unpack_subimage = true;
451
}
452
453
// GLES 3 subsumes many ES2 extensions.
454
if (gl_extensions.GLES3) {
455
gl_extensions.EXT_blend_minmax = true;
456
gl_extensions.EXT_unpack_subimage = true;
457
}
458
459
#if defined(__ANDROID__)
460
if (gl_extensions.OES_mapbuffer) {
461
glMapBuffer = (PFNGLMAPBUFFERPROC)eglGetProcAddress("glMapBufferOES");
462
}
463
464
// Look for EGL extensions
465
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
466
467
const char *eglString = eglQueryString(display, EGL_EXTENSIONS);
468
g_all_egl_extensions = eglString ? eglString : "";
469
ParseExtensionsString(g_all_egl_extensions, g_set_egl_extensions);
470
471
gl_extensions.EGL_NV_system_time = g_set_egl_extensions.count("EGL_NV_system_time") != 0;
472
gl_extensions.EGL_NV_coverage_sample = g_set_egl_extensions.count("EGL_NV_coverage_sample") != 0;
473
474
if (gl_extensions.EGL_NV_system_time) {
475
eglGetSystemTimeNV = (PFNEGLGETSYSTEMTIMENVPROC)eglGetProcAddress("eglGetSystemTimeNV");
476
eglGetSystemTimeFrequencyNV = (PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC)eglGetProcAddress("eglGetSystemTimeFrequencyNV");
477
}
478
#elif defined(USING_GLES2) && defined(__linux__)
479
const char *eglString = eglQueryString(NULL, EGL_EXTENSIONS);
480
g_all_egl_extensions = eglString ? eglString : "";
481
if (eglString) {
482
eglString = eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS);
483
if (eglString) {
484
g_all_egl_extensions.append(" ");
485
g_all_egl_extensions.append(eglString);
486
}
487
}
488
ParseExtensionsString(g_all_egl_extensions, g_set_egl_extensions);
489
#endif
490
491
glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &gl_extensions.maxVertexTextureUnits);
492
493
#ifdef GL_LOW_FLOAT
494
// This is probably a waste of time, implementations lie.
495
if (gl_extensions.IsGLES || g_set_gl_extensions.count("GL_ARB_ES2_compatibility") || gl_extensions.VersionGEThan(4, 1)) {
496
const GLint precisions[6] = {
497
GL_LOW_FLOAT, GL_MEDIUM_FLOAT, GL_HIGH_FLOAT,
498
GL_LOW_INT, GL_MEDIUM_INT, GL_HIGH_INT
499
};
500
GLint shaderTypes[2] = {
501
GL_VERTEX_SHADER, GL_FRAGMENT_SHADER
502
};
503
for (int st = 0; st < 2; st++) {
504
for (int p = 0; p < 6; p++) {
505
glGetShaderPrecisionFormat(shaderTypes[st], precisions[p], gl_extensions.range[st][p], &gl_extensions.precision[st][p]);
506
}
507
}
508
509
// Now, old Adreno lies about supporting full precision integers. So let's override it.
510
// The model number comparison should probably be 400 or 500. This causes us to avoid depal-in-shader.
511
// It seems though that this caused large perf regressions on Adreno 5xx, so I've bumped it up to 600.
512
if (gl_extensions.gpuVendor == GPU_VENDOR_QUALCOMM && gl_extensions.modelNumber < 600) {
513
WARN_LOG(Log::G3D, "Detected old Adreno - lowering reported int precision for safety");
514
gl_extensions.range[1][5][0] = 15;
515
gl_extensions.range[1][5][1] = 15;
516
}
517
}
518
#endif
519
520
gl_extensions.ARB_framebuffer_object = g_set_gl_extensions.count("GL_ARB_framebuffer_object") != 0;
521
gl_extensions.EXT_framebuffer_object = g_set_gl_extensions.count("GL_EXT_framebuffer_object") != 0;
522
gl_extensions.ARB_pixel_buffer_object = g_set_gl_extensions.count("GL_ARB_pixel_buffer_object") != 0;
523
gl_extensions.NV_pixel_buffer_object = g_set_gl_extensions.count("GL_NV_pixel_buffer_object") != 0;
524
525
if (!gl_extensions.IsGLES && gl_extensions.IsCoreContext) {
526
// These are required, and don't need to be specified by the driver (they aren't on Apple.)
527
gl_extensions.ARB_vertex_array_object = true;
528
gl_extensions.ARB_framebuffer_object = true;
529
}
530
531
// Add any extensions that are included in core. May be elided.
532
if (!gl_extensions.IsGLES) {
533
if (gl_extensions.VersionGEThan(3, 0)) {
534
gl_extensions.ARB_texture_float = true;
535
}
536
if (gl_extensions.VersionGEThan(3, 1)) {
537
gl_extensions.ARB_draw_instanced = true;
538
gl_extensions.ARB_uniform_buffer_object = true;
539
}
540
if (gl_extensions.VersionGEThan(3, 2)) {
541
gl_extensions.ARB_depth_clamp = true;
542
}
543
if (gl_extensions.VersionGEThan(3, 3)) {
544
gl_extensions.ARB_blend_func_extended = true;
545
gl_extensions.ARB_explicit_attrib_location = true;
546
}
547
if (gl_extensions.VersionGEThan(4, 0)) {
548
// ARB_gpu_shader5 = true;
549
}
550
if (gl_extensions.VersionGEThan(4, 1)) {
551
// ARB_get_program_binary = true;
552
// ARB_separate_shader_objects = true;
553
// ARB_shader_precision = true;
554
// ARB_viewport_array = true;
555
}
556
if (gl_extensions.VersionGEThan(4, 2)) {
557
// ARB_texture_storage = true;
558
}
559
if (gl_extensions.VersionGEThan(4, 3)) {
560
gl_extensions.ARB_copy_image = true;
561
gl_extensions.ARB_stencil_texturing = true;
562
// ARB_explicit_uniform_location = true;
563
// ARB_texture_view = true;
564
// ARB_vertex_attrib_binding = true;
565
}
566
if (gl_extensions.VersionGEThan(4, 4)) {
567
gl_extensions.ARB_buffer_storage = true;
568
}
569
if (gl_extensions.VersionGEThan(4, 5)) {
570
gl_extensions.ARB_cull_distance = true;
571
}
572
if (gl_extensions.VersionGEThan(4, 6)) {
573
// Actually ARB, but they're basically the same.
574
gl_extensions.EXT_texture_filter_anisotropic = true;
575
}
576
}
577
578
// Force off clip for a cmomon buggy Samsung version.
579
if (!strcmp(versionStr, "OpenGL ES 3.2 ANGLE git hash: aa8f94c52952")) {
580
// Maybe could use bugs, but for now let's just force it back off.
581
// Seeing errors that gl_ClipDistance is undefined.
582
gl_extensions.EXT_clip_cull_distance = false;
583
}
584
585
// Check the old query API. It doesn't seem to be very reliable (can miss stuff).
586
GLint numCompressedFormats = 0;
587
glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numCompressedFormats);
588
GLint *compressedFormats = new GLint[numCompressedFormats];
589
if (numCompressedFormats > 0) {
590
glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, compressedFormats);
591
for (int i = 0; i < numCompressedFormats; i++) {
592
switch (compressedFormats[i]) {
593
case GL_COMPRESSED_RGB8_ETC2: gl_extensions.supportsETC2 = true; break;
594
#ifdef GL_COMPRESSED_RGBA_ASTC_4x4_KHR
595
case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: gl_extensions.supportsASTC = true; break;
596
#endif
597
#ifndef USING_GLES2
598
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: gl_extensions.supportsBC123 = true; break;
599
case GL_COMPRESSED_RGBA_BPTC_UNORM: gl_extensions.supportsBC7 = true; break;
600
#endif
601
}
602
}
603
}
604
605
// Enable additional formats based on extensions.
606
if (gl_extensions.EXT_texture_compression_s3tc) gl_extensions.supportsBC123 = true;
607
if (gl_extensions.ARB_texture_compression_bptc) gl_extensions.supportsBC7 = true;
608
if (gl_extensions.ARB_texture_compression_rgtc) gl_extensions.supportsBC45 = true;
609
if (gl_extensions.KHR_texture_compression_astc_ldr) gl_extensions.supportsASTC = true;
610
if (gl_extensions.OES_texture_compression_astc) gl_extensions.supportsASTC = true;
611
612
// Now, disable known-emulated texture formats.
613
if (gl_extensions.gpuVendor == GPU_VENDOR_NVIDIA && !gl_extensions.IsGLES) {
614
gl_extensions.supportsETC2 = false;
615
gl_extensions.supportsASTC = false;
616
}
617
delete[] compressedFormats;
618
619
ProcessGPUFeatures();
620
621
int error = glGetError();
622
if (error)
623
ERROR_LOG(Log::G3D, "GL error in init: %i", error);
624
625
#endif
626
return true;
627
}
628
629
void SetGLCoreContext(bool flag) {
630
if (!extensionsDone) {
631
useCoreContext = flag;
632
// For convenience, it'll get reset later.
633
gl_extensions.IsCoreContext = useCoreContext;
634
} else {
635
_assert_(flag == useCoreContext);
636
}
637
}
638
639
void ResetGLExtensions() {
640
extensionsDone = false;
641
642
gl_extensions = {};
643
gl_extensions.IsCoreContext = useCoreContext;
644
g_all_gl_extensions.clear();
645
g_all_egl_extensions.clear();
646
}
647
648
static const char * const glsl_fragment_prelude =
649
"#ifdef GL_ES\n"
650
"precision mediump float;\n"
651
"#endif\n";
652
653
std::string ApplyGLSLPrelude(const std::string &source, uint32_t stage) {
654
#if PPSSPP_API(ANY_GL)
655
std::string temp;
656
std::string version = "";
657
if (!gl_extensions.IsGLES && gl_extensions.IsCoreContext) {
658
// We need to add a corresponding #version. Apple drivers fail without an exact match.
659
version = StringFromFormat("#version %d\n", gl_extensions.GLSLVersion());
660
} else if (gl_extensions.IsGLES && gl_extensions.GLES3) {
661
version = StringFromFormat("#version %d es\n", gl_extensions.GLSLVersion());
662
}
663
if (stage == GL_FRAGMENT_SHADER) {
664
temp = version + glsl_fragment_prelude + source;
665
} else if (stage == GL_VERTEX_SHADER) {
666
temp = version + source;
667
}
668
return temp;
669
#else
670
return source;
671
#endif
672
}
673
674