CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Common/GPU/OpenGL/GLFeatures.cpp
Views: 1401
#include "ppsspp_config.h"12#include <cstring>3#include <set>45#include "Common/StringUtils.h"67#if PPSSPP_API(ANY_GL)8#include "Common/GPU/OpenGL/GLCommon.h"910#if defined(_WIN32)11#include "GL/wglew.h"12#endif13#endif1415#include "Common/GPU/OpenGL/GLFeatures.h"1617#include "Common/Log.h"1819#if defined(USING_GLES2)20#if defined(__ANDROID__)21PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC eglGetSystemTimeFrequencyNV;22PFNEGLGETSYSTEMTIMENVPROC eglGetSystemTimeNV;23PFNGLDRAWTEXTURENVPROC glDrawTextureNV;24PFNGLBLITFRAMEBUFFERNVPROC glBlitFramebufferNV;25PFNGLMAPBUFFERPROC glMapBuffer;2627PFNGLDISCARDFRAMEBUFFEREXTPROC glDiscardFramebufferEXT;28PFNGLGENVERTEXARRAYSOESPROC glGenVertexArraysOES;29PFNGLBINDVERTEXARRAYOESPROC glBindVertexArrayOES;30PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArraysOES;31PFNGLISVERTEXARRAYOESPROC glIsVertexArrayOES;32#endif33#if !PPSSPP_PLATFORM(IOS)34#include "EGL/egl.h"35#endif36#endif3738GLExtensions gl_extensions;39std::string g_all_gl_extensions;40static std::set<std::string> g_set_gl_extensions;41std::string g_all_egl_extensions;42static std::set<std::string> g_set_egl_extensions;4344static bool extensionsDone = false;45static bool useCoreContext = false;4647static void ParseExtensionsString(const std::string& str, std::set<std::string> &output) {48output.clear();4950size_t next = 0;51for (size_t pos = 0, len = str.length(); pos < len; ++pos) {52if (str[pos] == ' ') {53output.emplace(str.substr(next, pos - next));54// Skip the delimiter itself.55next = pos + 1;56}57}5859if (next == 0 && str.length() != 0) {60output.insert(str);61} else if (next < str.length()) {62output.emplace(str.substr(next));63}64}6566bool GLExtensions::VersionGEThan(int major, int minor, int sub) {67if (gl_extensions.ver[0] > major)68return true;69if (gl_extensions.ver[0] < major)70return false;71if (gl_extensions.ver[1] > minor)72return true;73if (gl_extensions.ver[1] < minor)74return false;75return gl_extensions.ver[2] >= sub;76}7778int GLExtensions::GLSLVersion() {79if (gl_extensions.IsGLES) {80if (gl_extensions.GLES3) {81// GLSL version matches ES version.82return gl_extensions.ver[0] * 100 + gl_extensions.ver[1] * 10;83} else {84return 100;85}86} else {87// Used for shader translation and core contexts (Apple drives fail without an exact match.)88if (gl_extensions.VersionGEThan(3, 3)) {89return gl_extensions.ver[0] * 100 + gl_extensions.ver[1] * 10;90} else if (gl_extensions.VersionGEThan(3, 2)) {91return 150;92} else if (gl_extensions.VersionGEThan(3, 1)) {93return 140;94} else if (gl_extensions.VersionGEThan(3, 0)) {95return 130;96} else if (gl_extensions.VersionGEThan(2, 1)) {97return 120;98} else {99return 110;100}101}102}103104void ProcessGPUFeatures() {105gl_extensions.bugs = 0;106107DEBUG_LOG(Log::G3D, "Checking for GL driver bugs... vendor=%i model='%s'", (int)gl_extensions.gpuVendor, gl_extensions.model);108109if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) {110if (!strcmp(gl_extensions.model, "PowerVR SGX 545") ||111!strcmp(gl_extensions.model, "PowerVR SGX 544") ||112!strcmp(gl_extensions.model, "PowerVR SGX 544MP2") ||113!strcmp(gl_extensions.model, "PowerVR SGX 543") ||114!strcmp(gl_extensions.model, "PowerVR SGX 540") ||115!strcmp(gl_extensions.model, "PowerVR SGX 530") ||116!strcmp(gl_extensions.model, "PowerVR SGX 520") ) {117WARN_LOG(Log::G3D, "GL DRIVER BUG: PVR with bad and terrible precision");118gl_extensions.bugs |= BUG_PVR_SHADER_PRECISION_TERRIBLE | BUG_PVR_SHADER_PRECISION_BAD;119} else {120// TODO: I'm not sure if the Rogue series is affected by this.121WARN_LOG(Log::G3D, "GL DRIVER BUG: PVR with bad precision");122gl_extensions.bugs |= BUG_PVR_SHADER_PRECISION_BAD;123}124}125}126127// http://stackoverflow.com/questions/16147700/opengl-es-using-tegra-specific-extensions-gl-ext-texture-array128129bool CheckGLExtensions() {130#if PPSSPP_API(ANY_GL)131// Make sure to only do this once. It's okay to call CheckGLExtensions from wherever,132// as long as you're on the rendering thread (the one with the GL context).133if (extensionsDone) {134return true;135}136137gl_extensions = {};138gl_extensions.IsCoreContext = useCoreContext;139140const char *renderer = (const char *)glGetString(GL_RENDERER);141const char *versionStr = (const char *)glGetString(GL_VERSION);142const char *glslVersionStr = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION);143144if (!renderer || !versionStr || !glslVersionStr) {145// Something is very wrong! Bail.146return false;147}148149extensionsDone = true;150151#ifdef USING_GLES2152gl_extensions.IsGLES = !useCoreContext;153#else154if (strstr(versionStr, "OpenGL ES") == versionStr) {155// For desktops running GLES.156gl_extensions.IsGLES = true;157}158#endif159160// Check vendor string to try and guess GPU161const char *cvendor = (char *)glGetString(GL_VENDOR);162// TODO: move this stuff to gpu_features.cpp163if (cvendor) {164const std::string vendor = StripSpaces(std::string(cvendor));165if (vendor == "NVIDIA Corporation"166|| vendor == "Nouveau"167|| vendor == "nouveau") {168gl_extensions.gpuVendor = GPU_VENDOR_NVIDIA;169} else if (vendor == "Advanced Micro Devices, Inc."170|| vendor == "ATI Technologies Inc."171|| vendor == "AMD") {172gl_extensions.gpuVendor = GPU_VENDOR_AMD;173} else if (vendor == "Intel"174|| vendor == "Intel Inc."175|| vendor == "Intel Corporation"176|| vendor == "Tungsten Graphics, Inc") { // We'll assume this last one means Intel177gl_extensions.gpuVendor = GPU_VENDOR_INTEL;178} else if (vendor == "ARM") {179gl_extensions.gpuVendor = GPU_VENDOR_ARM;180} else if (vendor == "Imagination Technologies") {181gl_extensions.gpuVendor = GPU_VENDOR_IMGTEC;182} else if (vendor == "Qualcomm") {183gl_extensions.gpuVendor = GPU_VENDOR_QUALCOMM;184if (1 != sscanf(renderer, "Adreno (TM) %d", &gl_extensions.modelNumber)) {185gl_extensions.modelNumber = 300; // or what should we default to?186}187} else if (vendor == "Broadcom") {188gl_extensions.gpuVendor = GPU_VENDOR_BROADCOM;189// Just for reference: Galaxy Y has renderer == "VideoCore IV HW"190} else if (vendor == "Vivante Corporation") {191gl_extensions.gpuVendor = GPU_VENDOR_VIVANTE;192} else if (vendor == "Apple Inc." || vendor == "Apple") {193gl_extensions.gpuVendor = GPU_VENDOR_APPLE;194} else {195WARN_LOG(Log::G3D, "Unknown GL vendor: '%s'", vendor.c_str());196gl_extensions.gpuVendor = GPU_VENDOR_UNKNOWN;197}198} else {199gl_extensions.gpuVendor = GPU_VENDOR_UNKNOWN;200}201202INFO_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");203204strncpy(gl_extensions.model, renderer, sizeof(gl_extensions.model));205gl_extensions.model[sizeof(gl_extensions.model) - 1] = 0;206207// Start by assuming we're at 2.0.208int parsed[2] = {2, 0};209{ // Grab the version and attempt to parse.210char buffer[128] = { 0 };211strncpy(buffer, versionStr, sizeof(buffer) - 1);212213int len = (int)strlen(buffer);214bool beforeDot = true;215int lastDigit = 0;216for (int i = 0; i < len; i++) {217if (buffer[i] >= '0' && buffer[i] <= '9') {218lastDigit = buffer[i] - '0';219if (!beforeDot) {220parsed[1] = lastDigit;221break;222}223}224if (beforeDot && buffer[i] == '.' && lastDigit) {225parsed[0] = lastDigit;226beforeDot = false;227}228}229if (beforeDot && lastDigit) {230parsed[0] = lastDigit;231}232}233234235if (!gl_extensions.IsGLES) { // For desktop GL236gl_extensions.ver[0] = parsed[0];237gl_extensions.ver[1] = parsed[1];238239// If the GL version >= 4.3, we know it's a true superset of OpenGL ES 3.0 and can thus enable240// all the same modern paths.241// Most of it could be enabled on lower GPUs as well, but let's start this way.242if (gl_extensions.VersionGEThan(4, 3, 0)) {243gl_extensions.GLES3 = true;244#ifdef USING_GLES2245// Try to load up the other funcs if we're not using glew.246gl3stubInit();247#endif248}249} else {250// Start by assuming we're at 2.0.251gl_extensions.ver[0] = 2;252253#ifdef GL_MAJOR_VERSION254// Before grabbing the values, reset the error.255glGetError();256glGetIntegerv(GL_MAJOR_VERSION, &gl_extensions.ver[0]);257glGetIntegerv(GL_MINOR_VERSION, &gl_extensions.ver[1]);258// We check error here to detect if these properties were supported.259if (glGetError() != GL_NO_ERROR) {260// They weren't, reset to GLES 2.0.261gl_extensions.ver[0] = 2;262gl_extensions.ver[1] = 0;263} else if (parsed[0] && (gl_extensions.ver[0] != parsed[0] || gl_extensions.ver[1] != parsed[1])) {264// Something going wrong. Possible bug in GL ES drivers. See #9688265INFO_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.",266versionStr ? versionStr : "N/A", parsed[0], parsed[1], gl_extensions.ver[0], gl_extensions.ver[1]);267268gl_extensions.ver[0] = 2;269gl_extensions.ver[1] = 0;270}271#endif272273// If the above didn't give us a version, or gave us a crazy version, fallback.274#ifdef USING_GLES2275if (versionStr && (gl_extensions.ver[0] < 3 || gl_extensions.ver[0] > 5)) {276// Try to load GLES 3.0 only if "3.0" found in version277// This simple heuristic avoids issues on older devices where you can only call eglGetProcAddress a limited278// number of times. Make sure to check for 3.0 in the shader version too to avoid false positives, see #5584.279bool gl_3_0_in_string = versionStr && strstr(versionStr, "3.0") && glslVersionStr && strstr(glslVersionStr, "3.0");280bool gl_3_1_in_string = versionStr && strstr(versionStr, "3.1") && glslVersionStr && strstr(glslVersionStr, "3.1"); // intentionally left out .1281if ((gl_3_0_in_string || gl_3_1_in_string) && gl3stubInit()) {282gl_extensions.ver[0] = 3;283if (gl_3_1_in_string) {284gl_extensions.ver[1] = 1;285}286gl_extensions.GLES3 = true;287// Though, let's ban Mali from the GLES 3 path for now, see #4078288if (strstr(renderer, "Mali") != 0) {289INFO_LOG(Log::G3D, "Forcing GLES3 off for Mali driver version: %s\n", versionStr ? versionStr : "N/A");290gl_extensions.GLES3 = false;291}292} else {293// Just to be safe.294gl_extensions.ver[0] = 2;295gl_extensions.ver[1] = 0;296}297} else {298// Otherwise, let's trust GL_MAJOR_VERSION. Note that Mali is intentionally not banned here.299if (gl_extensions.ver[0] >= 3) {300gl_extensions.GLES3 = gl3stubInit();301}302}303#else304// If we have GLEW/similar, assume GLES3 loaded.305gl_extensions.GLES3 = gl_extensions.ver[0] >= 3;306#endif307308if (gl_extensions.GLES3) {309if (gl_extensions.ver[1] >= 1) {310INFO_LOG(Log::G3D, "OpenGL ES 3.1 support detected!\n");311} else {312INFO_LOG(Log::G3D, "OpenGL ES 3.0 support detected!\n");313}314}315}316317const char *extString = nullptr;318if (gl_extensions.ver[0] >= 3) {319// Let's use the new way for OpenGL 3.x+, required in the core profile.320GLint numExtensions = 0;321glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);322g_all_gl_extensions.clear();323g_set_gl_extensions.clear();324for (GLint i = 0; i < numExtensions; ++i) {325const char *ext = (const char *)glGetStringi(GL_EXTENSIONS, i);326g_set_gl_extensions.insert(ext);327g_all_gl_extensions += ext;328g_all_gl_extensions += " ";329}330} else {331extString = (const char *)glGetString(GL_EXTENSIONS);332g_all_gl_extensions = extString ? extString : "";333ParseExtensionsString(g_all_gl_extensions, g_set_gl_extensions);334}335336#if defined(WIN32) && !defined(__LIBRETRO__)337const char *wglString = 0;338if (wglGetExtensionsStringEXT)339wglString = wglGetExtensionsStringEXT();340g_all_egl_extensions = wglString ? wglString : "";341ParseExtensionsString(g_all_egl_extensions, g_set_egl_extensions);342343gl_extensions.EXT_swap_control_tear = g_set_egl_extensions.count("WGL_EXT_swap_control_tear") != 0;344#elif !defined(USING_GLES2)345// const char *glXString = glXQueryExtensionString();346// gl_extensions.EXT_swap_control_tear = strstr(glXString, "GLX_EXT_swap_control_tear") != 0;347#endif348349// Check the desktop extension instead of the OES one. They are very similar.350// Also explicitly check those ATI devices that claims to support npot351gl_extensions.OES_texture_npot = g_set_gl_extensions.count("GL_ARB_texture_non_power_of_two") != 0352&& !(((strncmp(renderer, "ATI RADEON X", 12) == 0) || (strncmp(renderer, "ATI MOBILITY RADEON X", 21) == 0)));353354gl_extensions.ARB_conservative_depth = g_set_gl_extensions.count("GL_ARB_conservative_depth") != 0;355gl_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);356gl_extensions.ARB_shading_language_420pack = (g_set_gl_extensions.count("GL_ARB_shading_language_420pack") != 0);357gl_extensions.EXT_bgra = g_set_gl_extensions.count("GL_EXT_bgra") != 0;358gl_extensions.EXT_gpu_shader4 = g_set_gl_extensions.count("GL_EXT_gpu_shader4") != 0;359gl_extensions.NV_framebuffer_blit = g_set_gl_extensions.count("GL_NV_framebuffer_blit") != 0;360gl_extensions.NV_copy_image = g_set_gl_extensions.count("GL_NV_copy_image") != 0;361gl_extensions.OES_copy_image = g_set_gl_extensions.count("GL_OES_copy_image") != 0;362gl_extensions.EXT_copy_image = g_set_gl_extensions.count("GL_EXT_copy_image") != 0;363gl_extensions.ARB_copy_image = g_set_gl_extensions.count("GL_ARB_copy_image") != 0;364gl_extensions.ARB_buffer_storage = g_set_gl_extensions.count("GL_ARB_buffer_storage") != 0;365gl_extensions.ARB_vertex_array_object = g_set_gl_extensions.count("GL_ARB_vertex_array_object") != 0;366gl_extensions.ARB_texture_float = g_set_gl_extensions.count("GL_ARB_texture_float") != 0;367gl_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;368gl_extensions.EXT_draw_instanced = g_set_gl_extensions.count("GL_EXT_draw_instanced") != 0;369gl_extensions.ARB_draw_instanced = g_set_gl_extensions.count("GL_ARB_draw_instanced") != 0;370gl_extensions.ARB_cull_distance = g_set_gl_extensions.count("GL_ARB_cull_distance") != 0;371gl_extensions.ARB_depth_clamp = g_set_gl_extensions.count("GL_ARB_depth_clamp") != 0;372gl_extensions.ARB_uniform_buffer_object = g_set_gl_extensions.count("GL_ARB_uniform_buffer_object") != 0;373gl_extensions.ARB_explicit_attrib_location = g_set_gl_extensions.count("GL_ARB_explicit_attrib_location") != 0;374gl_extensions.ARB_texture_non_power_of_two = g_set_gl_extensions.count("GL_ARB_texture_non_power_of_two") != 0;375gl_extensions.ARB_shader_stencil_export = g_set_gl_extensions.count("GL_ARB_shader_stencil_export") != 0;376gl_extensions.ARB_texture_compression_bptc = g_set_gl_extensions.count("GL_ARB_texture_compression_bptc") != 0;377gl_extensions.ARB_texture_compression_rgtc = g_set_gl_extensions.count("GL_ARB_texture_compression_rgtc") != 0;378gl_extensions.KHR_texture_compression_astc_ldr = g_set_gl_extensions.count("GL_KHR_texture_compression_astc_ldr") != 0;379gl_extensions.EXT_texture_compression_s3tc = g_set_gl_extensions.count("GL_EXT_texture_compression_s3tc") != 0;380gl_extensions.OES_texture_compression_astc = g_set_gl_extensions.count("GL_OES_texture_compression_astc") != 0;381382if (gl_extensions.IsGLES) {383gl_extensions.EXT_blend_func_extended = g_set_gl_extensions.count("GL_EXT_blend_func_extended") != 0;384gl_extensions.OES_texture_npot = g_set_gl_extensions.count("GL_OES_texture_npot") != 0;385gl_extensions.OES_packed_depth_stencil = (g_set_gl_extensions.count("GL_OES_packed_depth_stencil") != 0) || gl_extensions.GLES3;386gl_extensions.OES_depth24 = g_set_gl_extensions.count("GL_OES_depth24") != 0;387gl_extensions.OES_depth_texture = g_set_gl_extensions.count("GL_OES_depth_texture") != 0;388gl_extensions.OES_mapbuffer = g_set_gl_extensions.count("GL_OES_mapbuffer") != 0;389gl_extensions.EXT_blend_minmax = g_set_gl_extensions.count("GL_EXT_blend_minmax") != 0;390gl_extensions.EXT_unpack_subimage = g_set_gl_extensions.count("GL_EXT_unpack_subimage") != 0;391gl_extensions.EXT_shader_framebuffer_fetch = g_set_gl_extensions.count("GL_EXT_shader_framebuffer_fetch") != 0;392gl_extensions.ARM_shader_framebuffer_fetch = g_set_gl_extensions.count("GL_ARM_shader_framebuffer_fetch") != 0;393gl_extensions.OES_texture_float = g_set_gl_extensions.count("GL_OES_texture_float") != 0;394gl_extensions.OES_texture_3D = g_set_gl_extensions.count("GL_OES_texture_3D") != 0;395gl_extensions.EXT_buffer_storage = g_set_gl_extensions.count("GL_EXT_buffer_storage") != 0;396gl_extensions.EXT_clip_cull_distance = g_set_gl_extensions.count("GL_EXT_clip_cull_distance") != 0;397gl_extensions.EXT_depth_clamp = g_set_gl_extensions.count("GL_EXT_depth_clamp") != 0;398gl_extensions.APPLE_clip_distance = g_set_gl_extensions.count("GL_APPLE_clip_distance") != 0;399400#if defined(__ANDROID__)401// On Android, incredibly, this is not consistently non-zero! It does seem to have the same value though.402// https://twitter.com/ID_AA_Carmack/status/387383037794603008403#ifdef _DEBUG404void *invalidAddress = (void *)eglGetProcAddress("InvalidGlCall1");405void *invalidAddress2 = (void *)eglGetProcAddress("AnotherInvalidGlCall2");406DEBUG_LOG(Log::G3D, "Addresses returned for invalid extensions: %p %p", invalidAddress, invalidAddress2);407#endif408409// These are all the same. Let's alias.410if (!gl_extensions.OES_copy_image) {411if (gl_extensions.NV_copy_image) {412glCopyImageSubDataOES = (decltype(glCopyImageSubDataOES))eglGetProcAddress("glCopyImageSubDataNV");413} else if (gl_extensions.EXT_copy_image) {414glCopyImageSubDataOES = (decltype(glCopyImageSubDataOES))eglGetProcAddress("glCopyImageSubDataEXT");415}416}417418if (gl_extensions.NV_framebuffer_blit) {419glBlitFramebufferNV = (PFNGLBLITFRAMEBUFFERNVPROC)eglGetProcAddress("glBlitFramebufferNV");420}421422gl_extensions.OES_vertex_array_object = g_set_gl_extensions.count("GL_OES_vertex_array_object") != 0;423if (gl_extensions.OES_vertex_array_object) {424glGenVertexArraysOES = (PFNGLGENVERTEXARRAYSOESPROC)eglGetProcAddress("glGenVertexArraysOES");425glBindVertexArrayOES = (PFNGLBINDVERTEXARRAYOESPROC)eglGetProcAddress("glBindVertexArrayOES");426glDeleteVertexArraysOES = (PFNGLDELETEVERTEXARRAYSOESPROC)eglGetProcAddress("glDeleteVertexArraysOES");427glIsVertexArrayOES = (PFNGLISVERTEXARRAYOESPROC)eglGetProcAddress("glIsVertexArrayOES");428}429430// Hm, this should be available on iOS too.431gl_extensions.EXT_discard_framebuffer = g_set_gl_extensions.count("GL_EXT_discard_framebuffer") != 0;432if (gl_extensions.EXT_discard_framebuffer) {433glDiscardFramebufferEXT = (PFNGLDISCARDFRAMEBUFFEREXTPROC)eglGetProcAddress("glDiscardFramebufferEXT");434}435#else436gl_extensions.OES_vertex_array_object = false;437gl_extensions.EXT_discard_framebuffer = false;438#endif439} else {440gl_extensions.ARB_blend_func_extended = g_set_gl_extensions.count("GL_ARB_blend_func_extended") != 0;441442// Desktops support minmax and subimage unpack (GL_UNPACK_ROW_LENGTH etc)443gl_extensions.EXT_blend_minmax = true;444gl_extensions.EXT_unpack_subimage = true;445}446447// GLES 3 subsumes many ES2 extensions.448if (gl_extensions.GLES3) {449gl_extensions.EXT_blend_minmax = true;450gl_extensions.EXT_unpack_subimage = true;451}452453#if defined(__ANDROID__)454if (gl_extensions.OES_mapbuffer) {455glMapBuffer = (PFNGLMAPBUFFERPROC)eglGetProcAddress("glMapBufferOES");456}457458// Look for EGL extensions459EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);460461const char *eglString = eglQueryString(display, EGL_EXTENSIONS);462g_all_egl_extensions = eglString ? eglString : "";463ParseExtensionsString(g_all_egl_extensions, g_set_egl_extensions);464465gl_extensions.EGL_NV_system_time = g_set_egl_extensions.count("EGL_NV_system_time") != 0;466gl_extensions.EGL_NV_coverage_sample = g_set_egl_extensions.count("EGL_NV_coverage_sample") != 0;467468if (gl_extensions.EGL_NV_system_time) {469eglGetSystemTimeNV = (PFNEGLGETSYSTEMTIMENVPROC)eglGetProcAddress("eglGetSystemTimeNV");470eglGetSystemTimeFrequencyNV = (PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC)eglGetProcAddress("eglGetSystemTimeFrequencyNV");471}472#elif defined(USING_GLES2) && defined(__linux__)473const char *eglString = eglQueryString(NULL, EGL_EXTENSIONS);474g_all_egl_extensions = eglString ? eglString : "";475if (eglString) {476eglString = eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS);477if (eglString) {478g_all_egl_extensions.append(" ");479g_all_egl_extensions.append(eglString);480}481}482ParseExtensionsString(g_all_egl_extensions, g_set_egl_extensions);483#endif484485glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &gl_extensions.maxVertexTextureUnits);486487#ifdef GL_LOW_FLOAT488// This is probably a waste of time, implementations lie.489if (gl_extensions.IsGLES || g_set_gl_extensions.count("GL_ARB_ES2_compatibility") || gl_extensions.VersionGEThan(4, 1)) {490const GLint precisions[6] = {491GL_LOW_FLOAT, GL_MEDIUM_FLOAT, GL_HIGH_FLOAT,492GL_LOW_INT, GL_MEDIUM_INT, GL_HIGH_INT493};494GLint shaderTypes[2] = {495GL_VERTEX_SHADER, GL_FRAGMENT_SHADER496};497for (int st = 0; st < 2; st++) {498for (int p = 0; p < 6; p++) {499glGetShaderPrecisionFormat(shaderTypes[st], precisions[p], gl_extensions.range[st][p], &gl_extensions.precision[st][p]);500}501}502503// Now, old Adreno lies about supporting full precision integers. So let's override it.504// The model number comparison should probably be 400 or 500. This causes us to avoid depal-in-shader.505// It seems though that this caused large perf regressions on Adreno 5xx, so I've bumped it up to 600.506if (gl_extensions.gpuVendor == GPU_VENDOR_QUALCOMM && gl_extensions.modelNumber < 600) {507WARN_LOG(Log::G3D, "Detected old Adreno - lowering reported int precision for safety");508gl_extensions.range[1][5][0] = 15;509gl_extensions.range[1][5][1] = 15;510}511}512#endif513514gl_extensions.ARB_framebuffer_object = g_set_gl_extensions.count("GL_ARB_framebuffer_object") != 0;515gl_extensions.EXT_framebuffer_object = g_set_gl_extensions.count("GL_EXT_framebuffer_object") != 0;516gl_extensions.ARB_pixel_buffer_object = g_set_gl_extensions.count("GL_ARB_pixel_buffer_object") != 0;517gl_extensions.NV_pixel_buffer_object = g_set_gl_extensions.count("GL_NV_pixel_buffer_object") != 0;518519if (!gl_extensions.IsGLES && gl_extensions.IsCoreContext) {520// These are required, and don't need to be specified by the driver (they aren't on Apple.)521gl_extensions.ARB_vertex_array_object = true;522gl_extensions.ARB_framebuffer_object = true;523}524525// Add any extensions that are included in core. May be elided.526if (!gl_extensions.IsGLES) {527if (gl_extensions.VersionGEThan(3, 0)) {528gl_extensions.ARB_texture_float = true;529}530if (gl_extensions.VersionGEThan(3, 1)) {531gl_extensions.ARB_draw_instanced = true;532gl_extensions.ARB_uniform_buffer_object = true;533}534if (gl_extensions.VersionGEThan(3, 2)) {535gl_extensions.ARB_depth_clamp = true;536}537if (gl_extensions.VersionGEThan(3, 3)) {538gl_extensions.ARB_blend_func_extended = true;539gl_extensions.ARB_explicit_attrib_location = true;540}541if (gl_extensions.VersionGEThan(4, 0)) {542// ARB_gpu_shader5 = true;543}544if (gl_extensions.VersionGEThan(4, 1)) {545// ARB_get_program_binary = true;546// ARB_separate_shader_objects = true;547// ARB_shader_precision = true;548// ARB_viewport_array = true;549}550if (gl_extensions.VersionGEThan(4, 2)) {551// ARB_texture_storage = true;552}553if (gl_extensions.VersionGEThan(4, 3)) {554gl_extensions.ARB_copy_image = true;555gl_extensions.ARB_stencil_texturing = true;556// ARB_explicit_uniform_location = true;557// ARB_texture_view = true;558// ARB_vertex_attrib_binding = true;559}560if (gl_extensions.VersionGEThan(4, 4)) {561gl_extensions.ARB_buffer_storage = true;562}563if (gl_extensions.VersionGEThan(4, 5)) {564gl_extensions.ARB_cull_distance = true;565}566if (gl_extensions.VersionGEThan(4, 6)) {567// Actually ARB, but they're basically the same.568gl_extensions.EXT_texture_filter_anisotropic = true;569}570}571572// Force off clip for a cmomon buggy Samsung version.573if (!strcmp(versionStr, "OpenGL ES 3.2 ANGLE git hash: aa8f94c52952")) {574// Maybe could use bugs, but for now let's just force it back off.575// Seeing errors that gl_ClipDistance is undefined.576gl_extensions.EXT_clip_cull_distance = false;577}578579// Check the old query API. It doesn't seem to be very reliable (can miss stuff).580GLint numCompressedFormats = 0;581glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numCompressedFormats);582GLint *compressedFormats = new GLint[numCompressedFormats];583if (numCompressedFormats > 0) {584glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, compressedFormats);585for (int i = 0; i < numCompressedFormats; i++) {586switch (compressedFormats[i]) {587case GL_COMPRESSED_RGB8_ETC2: gl_extensions.supportsETC2 = true; break;588#ifdef GL_COMPRESSED_RGBA_ASTC_4x4_KHR589case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: gl_extensions.supportsASTC = true; break;590#endif591#ifndef USING_GLES2592case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: gl_extensions.supportsBC123 = true; break;593case GL_COMPRESSED_RGBA_BPTC_UNORM: gl_extensions.supportsBC7 = true; break;594#endif595}596}597}598599// Enable additional formats based on extensions.600if (gl_extensions.EXT_texture_compression_s3tc) gl_extensions.supportsBC123 = true;601if (gl_extensions.ARB_texture_compression_bptc) gl_extensions.supportsBC7 = true;602if (gl_extensions.ARB_texture_compression_rgtc) gl_extensions.supportsBC45 = true;603if (gl_extensions.KHR_texture_compression_astc_ldr) gl_extensions.supportsASTC = true;604if (gl_extensions.OES_texture_compression_astc) gl_extensions.supportsASTC = true;605606// Now, disable known-emulated texture formats.607if (gl_extensions.gpuVendor == GPU_VENDOR_NVIDIA && !gl_extensions.IsGLES) {608gl_extensions.supportsETC2 = false;609gl_extensions.supportsASTC = false;610}611delete[] compressedFormats;612613ProcessGPUFeatures();614615int error = glGetError();616if (error)617ERROR_LOG(Log::G3D, "GL error in init: %i", error);618619#endif620return true;621}622623void SetGLCoreContext(bool flag) {624if (!extensionsDone) {625useCoreContext = flag;626// For convenience, it'll get reset later.627gl_extensions.IsCoreContext = useCoreContext;628} else {629_assert_(flag == useCoreContext);630}631}632633void ResetGLExtensions() {634extensionsDone = false;635636gl_extensions = {};637gl_extensions.IsCoreContext = useCoreContext;638g_all_gl_extensions.clear();639g_all_egl_extensions.clear();640}641642static const char * const glsl_fragment_prelude =643"#ifdef GL_ES\n"644"precision mediump float;\n"645"#endif\n";646647std::string ApplyGLSLPrelude(const std::string &source, uint32_t stage) {648#if PPSSPP_API(ANY_GL)649std::string temp;650std::string version = "";651if (!gl_extensions.IsGLES && gl_extensions.IsCoreContext) {652// We need to add a corresponding #version. Apple drivers fail without an exact match.653version = StringFromFormat("#version %d\n", gl_extensions.GLSLVersion());654} else if (gl_extensions.IsGLES && gl_extensions.GLES3) {655version = StringFromFormat("#version %d es\n", gl_extensions.GLSLVersion());656}657if (stage == GL_FRAGMENT_SHADER) {658temp = version + glsl_fragment_prelude + source;659} else if (stage == GL_VERTEX_SHADER) {660temp = version + source;661}662return temp;663#else664return source;665#endif666}667668669