2014-09-07 15:27:49 +00:00
|
|
|
/* * Copyright (C) 2011-2014 Gregory hainaut
|
2013-01-14 09:15:39 +00:00
|
|
|
* Copyright (C) 2007-2009 Gabest
|
|
|
|
*
|
|
|
|
* This Program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This Program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with GNU Make; see the file COPYING. If not, write to
|
|
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
|
|
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "GLLoader.h"
|
2013-05-27 16:53:38 +00:00
|
|
|
#include "GSdx.h"
|
2016-10-22 12:44:40 +00:00
|
|
|
#include "GS.h"
|
2013-01-14 09:15:39 +00:00
|
|
|
|
2019-02-01 10:34:59 +00:00
|
|
|
#ifdef __unix__
|
2015-10-17 15:05:15 +00:00
|
|
|
PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate = NULL;
|
2019-02-01 10:34:59 +00:00
|
|
|
#endif
|
2015-10-17 15:05:15 +00:00
|
|
|
|
2019-01-29 15:38:37 +00:00
|
|
|
#include "PFN_GLLOADER_CPP.h"
|
2015-10-17 15:05:15 +00:00
|
|
|
|
2019-02-04 11:36:02 +00:00
|
|
|
namespace GLExtension {
|
|
|
|
|
|
|
|
static std::unordered_set<std::string> s_extensions;
|
|
|
|
|
|
|
|
bool Has(const std::string& ext)
|
|
|
|
{
|
|
|
|
return !!s_extensions.count(ext);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Set(const std::string& ext, bool v)
|
|
|
|
{
|
|
|
|
if (v)
|
|
|
|
s_extensions.insert(ext);
|
|
|
|
else
|
|
|
|
s_extensions.erase(ext);
|
|
|
|
}
|
|
|
|
}
|
2017-02-17 16:44:26 +00:00
|
|
|
|
2016-05-14 15:15:30 +00:00
|
|
|
namespace ReplaceGL {
|
|
|
|
void APIENTRY ScissorIndexed(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height)
|
|
|
|
{
|
|
|
|
glScissor(left, bottom, width, height);
|
|
|
|
}
|
|
|
|
|
|
|
|
void APIENTRY ViewportIndexedf(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h)
|
|
|
|
{
|
2016-06-29 17:42:05 +00:00
|
|
|
glViewport(GLint(x), GLint(y), GLsizei(w), GLsizei(h));
|
2016-05-14 15:15:30 +00:00
|
|
|
}
|
2017-02-03 16:33:07 +00:00
|
|
|
|
|
|
|
void APIENTRY TextureBarrier()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-05-14 15:15:30 +00:00
|
|
|
}
|
|
|
|
|
2017-02-17 16:44:26 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
namespace Emulate_DSA {
|
|
|
|
// Texture entry point
|
|
|
|
void APIENTRY BindTextureUnit(GLuint unit, GLuint texture) {
|
2019-02-01 10:34:59 +00:00
|
|
|
glActiveTexture(GL_TEXTURE0 + unit);
|
2017-02-17 16:44:26 +00:00
|
|
|
glBindTexture(GL_TEXTURE_2D, texture);
|
|
|
|
}
|
|
|
|
|
|
|
|
void APIENTRY CreateTexture(GLenum target, GLsizei n, GLuint *textures) {
|
|
|
|
glGenTextures(1, textures);
|
|
|
|
}
|
|
|
|
|
|
|
|
void APIENTRY TextureStorage(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) {
|
|
|
|
BindTextureUnit(7, texture);
|
|
|
|
glTexStorage2D(GL_TEXTURE_2D, levels, internalformat, width, height);
|
|
|
|
}
|
|
|
|
|
|
|
|
void APIENTRY TextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) {
|
|
|
|
BindTextureUnit(7, texture);
|
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, level, xoffset, yoffset, width, height, format, type, pixels);
|
|
|
|
}
|
|
|
|
|
|
|
|
void APIENTRY CopyTextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {
|
|
|
|
BindTextureUnit(7, texture);
|
|
|
|
glCopyTexSubImage2D(GL_TEXTURE_2D, level, xoffset, yoffset, x, y, width, height);
|
|
|
|
}
|
|
|
|
|
|
|
|
void APIENTRY GetTexureImage(GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels) {
|
|
|
|
BindTextureUnit(7, texture);
|
|
|
|
glGetTexImage(GL_TEXTURE_2D, level, format, type, pixels);
|
|
|
|
}
|
|
|
|
|
|
|
|
void APIENTRY TextureParameteri (GLuint texture, GLenum pname, GLint param) {
|
|
|
|
BindTextureUnit(7, texture);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, pname, param);
|
|
|
|
}
|
|
|
|
|
|
|
|
void APIENTRY GenerateTextureMipmap(GLuint texture) {
|
|
|
|
BindTextureUnit(7, texture);
|
|
|
|
glGenerateMipmap(GL_TEXTURE_2D);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Misc entry point
|
|
|
|
// (only purpose is to have a consistent API otherwise it is useless)
|
|
|
|
void APIENTRY CreateProgramPipelines(GLsizei n, GLuint *pipelines) {
|
|
|
|
glGenProgramPipelines(n, pipelines);
|
|
|
|
}
|
|
|
|
|
|
|
|
void APIENTRY CreateSamplers(GLsizei n, GLuint *samplers) {
|
|
|
|
glGenSamplers(n, samplers);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Replace function pointer to emulate DSA behavior
|
|
|
|
void Init() {
|
|
|
|
fprintf(stderr, "DSA is not supported. Expect slower performance\n");
|
|
|
|
glBindTextureUnit = BindTextureUnit;
|
|
|
|
glCreateTextures = CreateTexture;
|
|
|
|
glTextureStorage2D = TextureStorage;
|
|
|
|
glTextureSubImage2D = TextureSubImage;
|
|
|
|
glCopyTextureSubImage2D = CopyTextureSubImage;
|
|
|
|
glGetTextureImage = GetTexureImage;
|
|
|
|
glTextureParameteri = TextureParameteri;
|
|
|
|
|
|
|
|
glCreateProgramPipelines = CreateProgramPipelines;
|
|
|
|
glCreateSamplers = CreateSamplers;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-01-14 09:15:39 +00:00
|
|
|
namespace GLLoader {
|
|
|
|
|
2017-05-11 20:35:31 +00:00
|
|
|
bool s_first_load = true;
|
|
|
|
|
2017-08-02 17:52:15 +00:00
|
|
|
bool amd_legacy_buggy_driver = false;
|
|
|
|
bool vendor_id_amd = false;
|
|
|
|
bool vendor_id_nvidia = false;
|
|
|
|
bool vendor_id_intel = false;
|
|
|
|
bool mesa_driver = false;
|
|
|
|
bool in_replayer = false;
|
|
|
|
bool buggy_sso_dual_src = false;
|
2013-07-11 17:08:42 +00:00
|
|
|
|
2015-08-07 12:46:57 +00:00
|
|
|
|
2014-09-30 20:04:42 +00:00
|
|
|
bool found_geometry_shader = true; // we require GL3.3 so geometry must be supported by default
|
2015-05-02 08:53:19 +00:00
|
|
|
bool found_GL_EXT_texture_filter_anisotropic = false;
|
2017-02-03 17:30:27 +00:00
|
|
|
bool found_GL_ARB_clear_texture = false;
|
2016-05-16 16:45:47 +00:00
|
|
|
bool found_GL_ARB_get_texture_sub_image = false; // Not yet used
|
2016-03-10 20:56:36 +00:00
|
|
|
// DX11 GPU
|
|
|
|
bool found_GL_ARB_gpu_shader5 = false; // Require IvyBridge
|
|
|
|
bool found_GL_ARB_shader_image_load_store = false; // Intel IB. Nvidia/AMD miss Mesa implementation.
|
2016-03-10 21:14:41 +00:00
|
|
|
bool found_GL_ARB_viewport_array = false; // Intel IB. AMD/NVIDIA DX10
|
2016-07-07 20:02:10 +00:00
|
|
|
// Bonus to monitor the VRAM
|
|
|
|
bool found_GL_NVX_gpu_memory_info = false;
|
2014-09-07 15:27:49 +00:00
|
|
|
|
2013-08-03 08:29:01 +00:00
|
|
|
// Mandatory
|
2016-04-07 20:29:35 +00:00
|
|
|
bool found_GL_ARB_direct_state_access = false;
|
|
|
|
bool found_GL_ARB_texture_barrier = false;
|
2013-08-03 08:29:01 +00:00
|
|
|
|
2019-02-04 11:36:02 +00:00
|
|
|
static bool mandatory(const std::string& ext)
|
2013-08-03 08:29:01 +00:00
|
|
|
{
|
2019-02-04 11:36:02 +00:00
|
|
|
bool found = GLExtension::Has(ext);
|
|
|
|
if (!found)
|
|
|
|
fprintf(stderr, "ERROR: %s is NOT SUPPORTED\n", ext.c_str());
|
|
|
|
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool optional(bool& found, const std::string& name)
|
|
|
|
{
|
|
|
|
found = GLExtension::Has(name);
|
2015-05-01 12:18:05 +00:00
|
|
|
|
2017-05-11 20:35:31 +00:00
|
|
|
if (s_first_load) {
|
|
|
|
if (!found) {
|
|
|
|
fprintf(stdout, "INFO: %s is NOT SUPPORTED\n", name.c_str());
|
|
|
|
} else {
|
|
|
|
fprintf(stdout, "INFO: %s is available\n", name.c_str());
|
|
|
|
}
|
2013-08-03 08:29:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string opt("override_");
|
|
|
|
opt += name;
|
|
|
|
|
2016-05-24 19:52:06 +00:00
|
|
|
if (theApp.GetConfigI(opt.c_str()) != -1) {
|
|
|
|
found = theApp.GetConfigB(opt.c_str());
|
2013-08-03 08:29:01 +00:00
|
|
|
fprintf(stderr, "Override %s detection (%s)\n", name.c_str(), found ? "Enabled" : "Disabled");
|
2019-02-04 11:36:02 +00:00
|
|
|
GLExtension::Set(name);
|
2013-08-03 08:29:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2013-05-19 12:42:55 +00:00
|
|
|
|
2019-02-04 11:36:02 +00:00
|
|
|
bool check_gl_version(int major, int minor)
|
|
|
|
{
|
2013-05-19 12:42:55 +00:00
|
|
|
const GLubyte* s = glGetString(GL_VERSION);
|
2013-07-28 14:40:43 +00:00
|
|
|
if (s == NULL) {
|
|
|
|
fprintf(stderr, "Error: GLLoader failed to get GL version\n");
|
|
|
|
return false;
|
|
|
|
}
|
2015-07-13 10:35:55 +00:00
|
|
|
GLuint v = 1;
|
|
|
|
while (s[v] != '\0' && s[v-1] != ' ') v++;
|
2013-05-19 12:42:55 +00:00
|
|
|
|
2013-06-11 11:14:26 +00:00
|
|
|
const char* vendor = (const char*)glGetString(GL_VENDOR);
|
2017-05-11 20:35:31 +00:00
|
|
|
if (s_first_load)
|
|
|
|
fprintf(stdout, "OpenGL information. GPU: %s. Vendor: %s. Driver: %s\n", glGetString(GL_RENDERER), vendor, &s[v]);
|
2013-06-11 11:14:26 +00:00
|
|
|
|
2015-08-07 12:46:57 +00:00
|
|
|
// Name changed but driver is still bad!
|
2017-03-28 21:02:19 +00:00
|
|
|
if (strstr(vendor, "Advanced Micro Devices") || strstr(vendor, "ATI Technologies Inc.") || strstr(vendor, "ATI"))
|
2017-08-02 17:52:15 +00:00
|
|
|
vendor_id_amd = true;
|
|
|
|
/*if (vendor_id_amd && (
|
|
|
|
strstr((const char*)&s[v], " 10.") || // Blacklist all 2010 AMD drivers.
|
|
|
|
strstr((const char*)&s[v], " 11.") || // Blacklist all 2011 AMD drivers.
|
|
|
|
strstr((const char*)&s[v], " 12.") || // Blacklist all 2012 AMD drivers.
|
|
|
|
strstr((const char*)&s[v], " 13.") || // Blacklist all 2013 AMD drivers.
|
|
|
|
strstr((const char*)&s[v], " 14.") || // Blacklist all 2014 AMD drivers.
|
|
|
|
strstr((const char*)&s[v], " 15.") || // Blacklist all 2015 AMD drivers.
|
|
|
|
strstr((const char*)&s[v], " 16.") || // Blacklist all 2016 AMD drivers.
|
|
|
|
strstr((const char*)&s[v], " 17.") // Blacklist all 2017 AMD drivers for now.
|
|
|
|
))
|
|
|
|
amd_legacy_buggy_driver = true;
|
|
|
|
*/
|
2013-07-11 17:08:42 +00:00
|
|
|
if (strstr(vendor, "NVIDIA Corporation"))
|
2017-08-02 17:52:15 +00:00
|
|
|
vendor_id_nvidia = true;
|
2013-01-14 09:15:39 +00:00
|
|
|
|
2016-06-01 18:58:10 +00:00
|
|
|
#ifdef _WIN32
|
2016-10-23 10:42:54 +00:00
|
|
|
if (strstr(vendor, "Intel"))
|
2017-08-02 17:52:15 +00:00
|
|
|
vendor_id_intel = true;
|
2016-06-01 18:58:10 +00:00
|
|
|
#else
|
2016-10-23 10:42:54 +00:00
|
|
|
// On linux assumes the free driver if it isn't nvidia or amd pro driver
|
2017-08-02 17:52:15 +00:00
|
|
|
mesa_driver = !vendor_id_nvidia && !vendor_id_amd;
|
2016-06-01 18:58:10 +00:00
|
|
|
#endif
|
2019-01-26 23:12:08 +00:00
|
|
|
// As of 2019 SSO is still broken on intel (Kaby Lake confirmed).
|
2017-08-02 17:52:15 +00:00
|
|
|
buggy_sso_dual_src = vendor_id_intel || vendor_id_amd /*|| amd_legacy_buggy_driver*/;
|
2016-10-23 10:42:54 +00:00
|
|
|
|
2016-05-24 19:52:06 +00:00
|
|
|
if (theApp.GetConfigI("override_geometry_shader") != -1) {
|
|
|
|
found_geometry_shader = theApp.GetConfigB("override_geometry_shader");
|
2019-02-04 11:36:02 +00:00
|
|
|
GLExtension::Set("GL_ARB_geometry_shader4", found_geometry_shader);
|
2015-06-06 19:28:59 +00:00
|
|
|
fprintf(stderr, "Overriding geometry shaders detection\n");
|
2013-05-27 16:53:38 +00:00
|
|
|
}
|
2015-07-13 10:35:55 +00:00
|
|
|
|
|
|
|
GLint major_gl = 0;
|
|
|
|
GLint minor_gl = 0;
|
|
|
|
glGetIntegerv(GL_MAJOR_VERSION, &major_gl);
|
|
|
|
glGetIntegerv(GL_MINOR_VERSION, &minor_gl);
|
2013-01-14 09:15:39 +00:00
|
|
|
if ( (major_gl < major) || ( major_gl == major && minor_gl < minor ) ) {
|
2015-06-30 21:04:54 +00:00
|
|
|
fprintf(stderr, "OpenGL %d.%d is not supported. Only OpenGL %d.%d\n was found", major, minor, major_gl, minor_gl);
|
2013-01-14 09:15:39 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-02-04 11:36:02 +00:00
|
|
|
bool check_gl_supported_extension()
|
|
|
|
{
|
2013-01-14 09:15:39 +00:00
|
|
|
int max_ext = 0;
|
|
|
|
glGetIntegerv(GL_NUM_EXTENSIONS, &max_ext);
|
|
|
|
|
2015-10-17 15:05:15 +00:00
|
|
|
if (glGetStringi && max_ext) {
|
2013-01-14 09:15:39 +00:00
|
|
|
for (GLint i = 0; i < max_ext; i++) {
|
2017-05-26 15:26:46 +00:00
|
|
|
std::string ext{(const char*)glGetStringi(GL_EXTENSIONS, i)};
|
2019-02-04 11:36:02 +00:00
|
|
|
GLExtension::Set(ext);
|
2014-09-30 19:56:36 +00:00
|
|
|
//fprintf(stderr, "DEBUG ext: %s\n", ext.c_str());
|
2013-01-14 09:15:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-03 08:29:01 +00:00
|
|
|
bool status = true;
|
2019-02-04 11:36:02 +00:00
|
|
|
|
|
|
|
// Mandatory for both renderer
|
|
|
|
{
|
|
|
|
// GL4.1
|
|
|
|
status &= mandatory("GL_ARB_separate_shader_objects");
|
|
|
|
// GL4.2
|
|
|
|
status &= mandatory("GL_ARB_shading_language_420pack");
|
|
|
|
status &= mandatory("GL_ARB_texture_storage");
|
|
|
|
// GL4.3
|
|
|
|
status &= mandatory("GL_KHR_debug");
|
|
|
|
// GL4.4
|
|
|
|
status &= mandatory("GL_ARB_buffer_storage");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only for HW renderer
|
|
|
|
if (theApp.GetCurrentRendererType() == GSRendererType::OGL_HW) {
|
|
|
|
status &= mandatory("GL_ARB_copy_image");
|
|
|
|
status &= mandatory("GL_ARB_clip_control");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Extra
|
|
|
|
{
|
|
|
|
// Bonus
|
|
|
|
status &= optional(found_GL_EXT_texture_filter_anisotropic, "GL_EXT_texture_filter_anisotropic"); // ARB extension in 4.6
|
|
|
|
// GL4.0
|
|
|
|
status &= optional(found_GL_ARB_gpu_shader5, "GL_ARB_gpu_shader5");
|
|
|
|
// GL4.1
|
|
|
|
status &= optional(found_GL_ARB_viewport_array, "GL_ARB_viewport_array");
|
|
|
|
// GL4.2
|
|
|
|
status &= optional(found_GL_ARB_shader_image_load_store, "GL_ARB_shader_image_load_store");
|
|
|
|
// GL4.3
|
|
|
|
// GL4.4
|
|
|
|
status &= optional(found_GL_ARB_clear_texture,"GL_ARB_clear_texture");
|
|
|
|
// GL4.5
|
|
|
|
status &= optional(found_GL_ARB_direct_state_access, "GL_ARB_direct_state_access");
|
|
|
|
// Mandatory for the advance HW renderer effect. Unfortunately Mesa LLVMPIPE/SWR renderers doesn't support this extension.
|
|
|
|
// Rendering might be corrupted but it could be good enough for test/virtual machine.
|
|
|
|
status &= optional(found_GL_ARB_texture_barrier, "GL_ARB_texture_barrier");
|
|
|
|
status &= optional(found_GL_ARB_get_texture_sub_image, "GL_ARB_get_texture_sub_image");
|
|
|
|
}
|
2015-05-01 17:16:18 +00:00
|
|
|
|
2017-07-02 11:56:45 +00:00
|
|
|
if (s_first_load) {
|
2017-08-02 17:52:15 +00:00
|
|
|
if (vendor_id_amd) {
|
2017-07-02 11:56:45 +00:00
|
|
|
fprintf(stderr, "The OpenGL hardware renderer is slow on AMD GPUs due to an inefficient driver.\n"
|
|
|
|
"Check out the link below for further information.\n"
|
|
|
|
"https://github.com/PCSX2/pcsx2/wiki/OpenGL-and-AMD-GPUs---All-you-need-to-know\n");
|
|
|
|
}
|
2015-12-20 13:01:01 +00:00
|
|
|
|
2019-01-26 23:12:08 +00:00
|
|
|
if (vendor_id_intel && !found_GL_ARB_texture_barrier && !found_GL_ARB_direct_state_access) {
|
|
|
|
// Assume that driver support is good when texture barrier and DSA is supported, disable the log then.
|
2017-07-02 11:56:45 +00:00
|
|
|
fprintf(stderr, "The OpenGL renderer is inefficient on Intel GPUs due to an inefficient driver.\n"
|
|
|
|
"Check out the link below for further information.\n"
|
|
|
|
"https://github.com/PCSX2/pcsx2/wiki/OpenGL-and-Intel-GPUs-All-you-need-to-know\n");
|
|
|
|
}
|
2017-09-05 19:16:28 +00:00
|
|
|
}
|
2017-07-02 11:56:45 +00:00
|
|
|
|
2017-09-05 19:16:28 +00:00
|
|
|
if (!found_GL_ARB_viewport_array) {
|
|
|
|
glScissorIndexed = ReplaceGL::ScissorIndexed;
|
|
|
|
glViewportIndexedf = ReplaceGL::ViewportIndexedf;
|
|
|
|
if (s_first_load)
|
2017-07-02 11:56:45 +00:00
|
|
|
fprintf(stderr, "GL_ARB_viewport_array is not supported! Function pointer will be replaced\n");
|
2017-09-05 19:16:28 +00:00
|
|
|
}
|
2016-05-14 15:15:30 +00:00
|
|
|
|
2017-09-05 19:16:28 +00:00
|
|
|
if (!found_GL_ARB_texture_barrier) {
|
|
|
|
glTextureBarrier = ReplaceGL::TextureBarrier;
|
|
|
|
if (s_first_load)
|
2017-07-02 11:56:45 +00:00
|
|
|
fprintf(stderr, "GL_ARB_texture_barrier is not supported! Blending emulation will not be supported\n");
|
2017-02-03 16:33:07 +00:00
|
|
|
}
|
|
|
|
|
2017-02-17 16:44:26 +00:00
|
|
|
#ifdef _WIN32
|
2017-07-02 11:56:45 +00:00
|
|
|
// Thank you Intel for not providing support of basic features on your IGPUs.
|
2017-02-17 16:44:26 +00:00
|
|
|
if (!found_GL_ARB_direct_state_access) {
|
|
|
|
Emulate_DSA::Init();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-05-11 20:35:31 +00:00
|
|
|
if (s_first_load)
|
|
|
|
fprintf(stdout, "\n");
|
2013-05-26 13:05:03 +00:00
|
|
|
|
2013-08-03 08:29:01 +00:00
|
|
|
return status;
|
2013-01-14 09:15:39 +00:00
|
|
|
}
|
2017-05-11 20:35:31 +00:00
|
|
|
|
|
|
|
void check_gl_requirements()
|
|
|
|
{
|
|
|
|
if (!GLLoader::check_gl_version(3, 3))
|
|
|
|
throw GSDXRecoverableError();
|
|
|
|
|
|
|
|
if (!GLLoader::check_gl_supported_extension())
|
|
|
|
throw GSDXRecoverableError();
|
|
|
|
|
|
|
|
s_first_load = false;
|
|
|
|
}
|
2013-01-14 09:15:39 +00:00
|
|
|
}
|