OpenGL debug tweaks, allow disabling texture LOD functionality

This commit is contained in:
rdb 2015-12-15 12:45:50 +01:00
parent f8837999ed
commit 49d69a6b36
4 changed files with 113 additions and 53 deletions

View File

@ -610,17 +610,21 @@ reset() {
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
} }
GLCAT.debug() << "gl-debug enabled.\n"; GLCAT.info() << "gl-debug enabled.\n";
} else { } else {
GLCAT.debug() << "gl-debug enabled, but NOT supported.\n"; GLCAT.warning() << "gl-debug enabled, but NOT supported.\n";
} }
} else { } else {
GLCAT.debug() << "gl-debug NOT enabled.\n";
// However, still check if it is supported. // However, still check if it is supported.
_supports_debug = is_at_least_gl_version(4, 3) _supports_debug = is_at_least_gl_version(4, 3)
|| has_extension("GL_KHR_debug") || has_extension("GL_KHR_debug")
|| has_extension("GL_ARB_debug_output"); || has_extension("GL_ARB_debug_output");
if (_supports_debug) {
GLCAT.debug() << "gl-debug supported, but NOT enabled.\n";
} else {
GLCAT.debug() << "gl-debug disabled and unsupported.\n";
}
} }
#endif // OPENGLES_1 #endif // OPENGLES_1
@ -665,7 +669,8 @@ reset() {
#elif defined(OPENGLES_1) #elif defined(OPENGLES_1)
_supports_point_sprite = has_extension("GL_OES_point_sprite"); _supports_point_sprite = has_extension("GL_OES_point_sprite");
#else #else
_supports_point_sprite = has_extension("GL_ARB_point_sprite"); _supports_point_sprite = is_at_least_gl_version(2, 0) ||
has_extension("GL_ARB_point_sprite");
#endif #endif
if (_supports_point_sprite) { if (_supports_point_sprite) {
@ -873,7 +878,8 @@ reset() {
_supports_cube_map = true; _supports_cube_map = true;
#else #else
_supports_cube_map = _supports_cube_map =
has_extension("GL_ARB_texture_cube_map") || is_at_least_gl_version(1, 3) || is_at_least_gl_version(1, 3) ||
has_extension("GL_ARB_texture_cube_map") ||
has_extension("GL_OES_texture_cube_map"); has_extension("GL_OES_texture_cube_map");
#endif #endif
@ -909,8 +915,6 @@ reset() {
_supports_texture_srgb = true; _supports_texture_srgb = true;
} }
_supports_compressed_texture = false;
#ifdef OPENGLES #ifdef OPENGLES
_supports_compressed_texture = true; _supports_compressed_texture = true;
@ -968,6 +972,9 @@ reset() {
get_extension_func("glCompressedTexSubImage3DARB"); get_extension_func("glCompressedTexSubImage3DARB");
_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC) _glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)
get_extension_func("glGetCompressedTexImageARB"); get_extension_func("glGetCompressedTexImageARB");
} else {
_supports_compressed_texture = false;
} }
if (_supports_compressed_texture) { if (_supports_compressed_texture) {
@ -992,7 +999,7 @@ reset() {
GLint num_compressed_formats = 0; GLint num_compressed_formats = 0;
glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_formats); glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_formats);
GLint *formats = (GLint *)PANDA_MALLOC_ARRAY(num_compressed_formats * sizeof(GLint)); GLint *formats = (GLint *)alloca(num_compressed_formats * sizeof(GLint));
glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats); glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats);
for (int i = 0; i < num_compressed_formats; ++i) { for (int i = 0; i < num_compressed_formats; ++i) {
switch (formats[i]) { switch (formats[i]) {
@ -1028,20 +1035,19 @@ reset() {
break; break;
} }
} }
PANDA_FREE_ARRAY(formats);
} }
#ifdef OPENGLES_2 #ifdef OPENGLES_2
_supports_bgr = false; _supports_bgr = false;
#else #else
_supports_bgr = _supports_bgr =
has_extension("GL_EXT_bgra") || is_at_least_gl_version(1, 2); is_at_least_gl_version(1, 2) || has_extension("GL_EXT_bgra");
#endif #endif
#ifdef SUPPORT_FIXED_FUNCTION #ifdef SUPPORT_FIXED_FUNCTION
_supports_rescale_normal = _supports_rescale_normal =
!core_profile && gl_support_rescale_normal && !core_profile && gl_support_rescale_normal &&
(has_extension("GL_EXT_rescale_normal") || is_at_least_gl_version(1, 2)); (is_at_least_gl_version(1, 2) || has_extension("GL_EXT_rescale_normal"));
#ifndef OPENGLES #ifndef OPENGLES
_use_separate_specular_color = gl_separate_specular_color && _use_separate_specular_color = gl_separate_specular_color &&
@ -1063,18 +1069,20 @@ reset() {
_supports_multisample = _supports_multisample =
has_extension("GL_ARB_multisample") || is_at_least_gl_version(1, 3); has_extension("GL_ARB_multisample") || is_at_least_gl_version(1, 3);
#ifdef OPENGLES_2 #ifdef OPENGLES_1
_supports_generate_mipmap = is_at_least_gles_version(1, 1);
#elif defined(OPENGLES)
_supports_generate_mipmap = true; _supports_generate_mipmap = true;
#else #else
_supports_generate_mipmap = _supports_generate_mipmap = is_at_least_gl_version(1, 4) ||
has_extension("GL_SGIS_generate_mipmap") || is_at_least_gl_version(1, 4) || is_at_least_gles_version(1, 1); has_extension("GL_SGIS_generate_mipmap");
#endif #endif
#ifdef OPENGLES #ifdef OPENGLES
_supports_tex_non_pow2 = _supports_tex_non_pow2 =
has_extension("GL_OES_texture_npot"); has_extension("GL_OES_texture_npot");
#else #else
_supports_tex_non_pow2 = _supports_tex_non_pow2 = is_at_least_gl_version(2, 0) ||
has_extension("GL_ARB_texture_non_power_of_two"); has_extension("GL_ARB_texture_non_power_of_two");
#endif #endif
@ -1202,7 +1210,7 @@ reset() {
#else #else
if (gl_support_shadow_filter && if (gl_support_shadow_filter &&
_supports_depth_texture && _supports_depth_texture &&
has_extension("GL_ARB_shadow") && (is_at_least_gl_version(1, 4) || has_extension("GL_ARB_shadow")) &&
has_extension("GL_ARB_fragment_program_shadow")) { has_extension("GL_ARB_fragment_program_shadow")) {
_supports_shadow_filter = true; _supports_shadow_filter = true;
} }
@ -1222,11 +1230,19 @@ reset() {
#else #else
if (!core_profile) { if (!core_profile) {
_supports_texture_combine = _supports_texture_combine =
has_extension("GL_ARB_texture_env_combine") || is_at_least_gl_version(1, 3) || is_at_least_gles_version(1, 1); is_at_least_gl_version(1, 3) ||
is_at_least_gles_version(1, 1) ||
has_extension("GL_ARB_texture_env_combine");
_supports_texture_saved_result = _supports_texture_saved_result =
has_extension("GL_ARB_texture_env_crossbar") || has_extension("GL_OES_texture_env_crossbar") || is_at_least_gl_version(1, 4); is_at_least_gl_version(1, 4) ||
has_extension("GL_ARB_texture_env_crossbar") ||
has_extension("GL_OES_texture_env_crossbar");
_supports_texture_dot3 = _supports_texture_dot3 =
has_extension("GL_ARB_texture_env_dot3") || is_at_least_gl_version(1, 3) || is_at_least_gles_version(1, 1); is_at_least_gl_version(1, 3) ||
is_at_least_gles_version(1, 1) ||
has_extension("GL_ARB_texture_env_dot3");
} }
#endif #endif
@ -1556,7 +1572,8 @@ reset() {
} else { } else {
_glVertexAttribIPointer = NULL; _glVertexAttribIPointer = NULL;
} }
if (has_extension("GL_ARB_vertex_attrib_64bit")) { if (is_at_least_gl_version(4, 1) ||
has_extension("GL_ARB_vertex_attrib_64bit")) {
_glVertexAttribLPointer = (PFNGLVERTEXATTRIBLPOINTERPROC) _glVertexAttribLPointer = (PFNGLVERTEXATTRIBLPOINTERPROC)
get_extension_func("glVertexAttribLPointer"); get_extension_func("glVertexAttribLPointer");
} else { } else {
@ -1911,7 +1928,7 @@ reset() {
#endif #endif
_supports_framebuffer_multisample = false; _supports_framebuffer_multisample = false;
if ( has_extension("GL_EXT_framebuffer_multisample") ) { if (has_extension("GL_EXT_framebuffer_multisample")) {
_supports_framebuffer_multisample = true; _supports_framebuffer_multisample = true;
_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) _glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)
get_extension_func("glRenderbufferStorageMultisampleEXT"); get_extension_func("glRenderbufferStorageMultisampleEXT");
@ -1919,7 +1936,7 @@ reset() {
#ifndef OPENGLES #ifndef OPENGLES
_supports_framebuffer_multisample_coverage_nv = false; _supports_framebuffer_multisample_coverage_nv = false;
if ( has_extension("GL_NV_framebuffer_multisample_coverage") ) { if (has_extension("GL_NV_framebuffer_multisample_coverage")) {
_supports_framebuffer_multisample_coverage_nv = true; _supports_framebuffer_multisample_coverage_nv = true;
_glRenderbufferStorageMultisampleCoverage = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC) _glRenderbufferStorageMultisampleCoverage = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC)
get_extension_func("glRenderbufferStorageMultisampleCoverageNV"); get_extension_func("glRenderbufferStorageMultisampleCoverageNV");
@ -1928,7 +1945,7 @@ reset() {
#ifndef OPENGLES_1 #ifndef OPENGLES_1
_supports_framebuffer_blit = false; _supports_framebuffer_blit = false;
if ( has_extension("GL_EXT_framebuffer_blit") ) { if (has_extension("GL_EXT_framebuffer_blit")) {
_supports_framebuffer_blit = true; _supports_framebuffer_blit = true;
_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFEREXTPROC) _glBlitFramebuffer = (PFNGLBLITFRAMEBUFFEREXTPROC)
get_extension_func("glBlitFramebufferEXT"); get_extension_func("glBlitFramebufferEXT");
@ -2142,8 +2159,8 @@ reset() {
_edge_clamp = GL_CLAMP_TO_EDGE; _edge_clamp = GL_CLAMP_TO_EDGE;
#else #else
_edge_clamp = GL_CLAMP; _edge_clamp = GL_CLAMP;
if (has_extension("GL_SGIS_texture_edge_clamp") || if (is_at_least_gl_version(1, 2) || is_at_least_gles_version(1, 1) ||
is_at_least_gl_version(1, 2) || is_at_least_gles_version(1, 1)) { has_extension("GL_SGIS_texture_edge_clamp")) {
_edge_clamp = GL_CLAMP_TO_EDGE; _edge_clamp = GL_CLAMP_TO_EDGE;
} }
#endif #endif
@ -2179,6 +2196,20 @@ reset() {
} }
#endif #endif
#ifndef OPENGLES
_supports_texture_lod = false;
_supports_texture_lod_bias = false;
if (gl_support_texture_lod &&
(is_at_least_gl_version(1, 2) || has_extension("GL_SGIS_texture_lod"))) {
_supports_texture_lod = true;
if (is_at_least_gl_version(1, 4) || has_extension("GL_EXT_texture_lod_bias")) {
_supports_texture_lod_bias = true;
}
}
#endif
if (_supports_multisample) { if (_supports_multisample) {
GLint sample_buffers = 0; GLint sample_buffers = 0;
glGetIntegerv(GL_SAMPLE_BUFFERS, &sample_buffers); glGetIntegerv(GL_SAMPLE_BUFFERS, &sample_buffers);
@ -3398,12 +3429,18 @@ end_frame(Thread *current_thread) {
GLenum error_code = glGetError(); GLenum error_code = glGetError();
if (error_code != GL_NO_ERROR) { if (error_code != GL_NO_ERROR) {
int error_count = 0; int error_count = 0;
bool deactivate = !report_errors_loop(__LINE__, __FILE__, error_code, error_count);
do {
++error_count;
GLCAT.error()
<< "GL error 0x" << hex << error_code << dec << " : "
<< get_error_string(error_code) << "\n";
error_code = glGetError();
} while (error_code != GL_NO_ERROR);
if (error_count == 1) { if (error_count == 1) {
GLCAT.error() GLCAT.error()
<< "An OpenGL error (" << get_error_string(error_code) << "An OpenGL error has occurred.";
<< ") has occurred.";
} else { } else {
GLCAT.error() GLCAT.error()
<< error_count << " OpenGL errors have occurred."; << error_count << " OpenGL errors have occurred.";
@ -3417,7 +3454,8 @@ end_frame(Thread *current_thread) {
<< "in your PRC file to display more information.\n"; << "in your PRC file to display more information.\n";
} }
if (deactivate) { _error_count += error_count;
if (_error_count >= gl_max_errors) {
panic_deactivate(); panic_deactivate();
} }
} }
@ -4855,9 +4893,14 @@ prepare_sampler(const SamplerState &sampler) {
} }
} }
_glSamplerParameterf(index, GL_TEXTURE_MIN_LOD, sampler.get_min_lod()); if (_supports_texture_lod) {
_glSamplerParameterf(index, GL_TEXTURE_MAX_LOD, sampler.get_max_lod()); _glSamplerParameterf(index, GL_TEXTURE_MIN_LOD, sampler.get_min_lod());
_glSamplerParameterf(index, GL_TEXTURE_LOD_BIAS, sampler.get_lod_bias()); _glSamplerParameterf(index, GL_TEXTURE_MAX_LOD, sampler.get_max_lod());
}
if (_supports_texture_lod_bias) {
_glSamplerParameterf(index, GL_TEXTURE_LOD_BIAS, sampler.get_lod_bias());
}
gsc->enqueue_lru(&_prepared_objects->_sampler_object_lru); gsc->enqueue_lru(&_prepared_objects->_sampler_object_lru);
@ -7011,13 +7054,15 @@ get_error_string(GLenum error_code) {
// We used to use gluErrorString here, but I (rdb) took it out // We used to use gluErrorString here, but I (rdb) took it out
// because that was really the only function we used from GLU. // because that was really the only function we used from GLU.
// The idea with the error table was taken from SGI's sample implementation. // The idea with the error table was taken from SGI's sample implementation.
static const char *error_strings[GL_OUT_OF_MEMORY - GL_INVALID_ENUM + 1] = { static const char *error_strings[] = {
"invalid enumerant", "invalid enumerant",
"invalid value", "invalid value",
"invalid operation", "invalid operation",
"stack overflow", "stack overflow",
"stack underflow", "stack underflow",
"out of memory", "out of memory",
"invalid framebuffer operation",
"context lost",
}; };
if (error_code == GL_NO_ERROR) { if (error_code == GL_NO_ERROR) {
@ -7026,8 +7071,8 @@ get_error_string(GLenum error_code) {
} else if (error_code == GL_TABLE_TOO_LARGE) { } else if (error_code == GL_TABLE_TOO_LARGE) {
return "table too large"; return "table too large";
#endif #endif
} else if (error_code >= GL_INVALID_ENUM && error_code <= GL_OUT_OF_MEMORY) { } else if (error_code >= 0x0500 && error_code <= 0x0507) {
return error_strings[error_code - GL_INVALID_ENUM]; return error_strings[error_code - 0x0500];
} }
// Other error, somehow? Just display the error code then. // Other error, somehow? Just display the error code then.
@ -7174,6 +7219,7 @@ void CLP(GraphicsStateGuardian)::
query_glsl_version() { query_glsl_version() {
_gl_shadlang_ver_major = 0; _gl_shadlang_ver_major = 0;
_gl_shadlang_ver_minor = 0; _gl_shadlang_ver_minor = 0;
#ifndef OPENGLES_1
#ifndef OPENGLES #ifndef OPENGLES
// OpenGL 2.0 introduces GLSL in the core. In 1.x, it is an extension. // OpenGL 2.0 introduces GLSL in the core. In 1.x, it is an extension.
@ -7187,25 +7233,28 @@ query_glsl_version() {
GLCAT.warning() << "Invalid GL_SHADING_LANGUAGE_VERSION format.\n"; GLCAT.warning() << "Invalid GL_SHADING_LANGUAGE_VERSION format.\n";
} }
} }
#elif !defined(OPENGLES_1) #else
// OpenGL ES 2.0 and above has shader support built-in. // OpenGL ES 2.0 and above has shader support built-in.
string ver = show_gl_string("GL_SHADING_LANGUAGE_VERSION", GL_SHADING_LANGUAGE_VERSION); string ver = show_gl_string("GL_SHADING_LANGUAGE_VERSION", GL_SHADING_LANGUAGE_VERSION);
_gl_shadlang_ver_major = 1; _gl_shadlang_ver_major = 1;
_gl_shadlang_ver_minor = 0; _gl_shadlang_ver_minor = 0;
if (ver.empty() || if (ver.empty() ||
sscanf(ver.c_str(), "OpenGL ES GLSL %d.%d", &_gl_shadlang_ver_major, sscanf(ver.c_str(), "OpenGL ES GLSL ES %d.%d", &_gl_shadlang_ver_major,
&_gl_shadlang_ver_minor) != 2) { &_gl_shadlang_ver_minor) != 2) {
GLCAT.warning() << "Invalid GL_SHADING_LANGUAGE_VERSION format.\n"; GLCAT.warning() << "Invalid GL_SHADING_LANGUAGE_VERSION format.\n";
} }
#endif #endif
#ifndef OPENGLES_1
if (GLCAT.is_debug()) { if (GLCAT.is_debug()) {
GLCAT.debug() GLCAT.debug()
<< "Detected GLSL version: " << "Detected GLSL "
#ifdef OPENGLES
"ES "
#endif
"version: "
<< _gl_shadlang_ver_major << "." << _gl_shadlang_ver_minor << "\n"; << _gl_shadlang_ver_major << "." << _gl_shadlang_ver_minor << "\n";
} }
#endif #endif // !OPENGLES_1
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -10732,13 +10781,13 @@ specify_texture(CLP(TextureContext) *gtc, const SamplerState &sampler) {
#endif #endif
#ifndef OPENGLES #ifndef OPENGLES
if (is_at_least_gl_version(1, 2)) { if (_supports_texture_lod) {
glTexParameterf(target, GL_TEXTURE_MIN_LOD, sampler.get_min_lod()); glTexParameterf(target, GL_TEXTURE_MIN_LOD, sampler.get_min_lod());
glTexParameterf(target, GL_TEXTURE_MAX_LOD, sampler.get_max_lod()); glTexParameterf(target, GL_TEXTURE_MAX_LOD, sampler.get_max_lod());
}
if (is_at_least_gl_version(1, 4)) { if (_supports_texture_lod_bias) {
glTexParameterf(target, GL_TEXTURE_LOD_BIAS, sampler.get_lod_bias()); glTexParameterf(target, GL_TEXTURE_LOD_BIAS, sampler.get_lod_bias());
}
} }
#endif #endif
@ -11151,7 +11200,7 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) {
} }
#ifndef OPENGLES // OpenGL ES doesn't have GL_TEXTURE_MAX_LEVEL. #ifndef OPENGLES // OpenGL ES doesn't have GL_TEXTURE_MAX_LEVEL.
if (is_at_least_gl_version(1, 2)) { if (_supports_texture_lod) {
// By the time we get here, we have a pretty good prediction for // By the time we get here, we have a pretty good prediction for
// the number of mipmaps we're going to have, so tell the GL that's // the number of mipmaps we're going to have, so tell the GL that's
// all it's going to get. // all it's going to get.
@ -11666,7 +11715,7 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
<< "No mipmap level " << n << " defined for " << tex->get_name() << "No mipmap level " << n << " defined for " << tex->get_name()
<< "\n"; << "\n";
#ifndef OPENGLES #ifndef OPENGLES
if (is_at_least_gl_version(1, 2)) { if (_supports_texture_lod) {
// Tell the GL we have no more mipmaps for it to use. // Tell the GL we have no more mipmaps for it to use.
glTexParameteri(texture_target, GL_TEXTURE_MAX_LEVEL, n - mipmap_bias); glTexParameteri(texture_target, GL_TEXTURE_MAX_LEVEL, n - mipmap_bias);
} }
@ -11886,10 +11935,8 @@ upload_simple_texture(CLP(TextureContext) *gtc) {
#ifndef OPENGLES #ifndef OPENGLES
// Turn off mipmaps for the simple texture. // Turn off mipmaps for the simple texture.
if (tex->uses_mipmaps()) { if (tex->uses_mipmaps() && _supports_texture_lod) {
if (is_at_least_gl_version(1, 2)) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
}
} }
#endif #endif
@ -12554,7 +12601,7 @@ do_extract_texture_data(CLP(TextureContext) *gtc) {
GLint num_expected_levels = tex->get_expected_num_mipmap_levels(); GLint num_expected_levels = tex->get_expected_num_mipmap_levels();
GLint highest_level = num_expected_levels; GLint highest_level = num_expected_levels;
#ifndef OPENGLES #ifndef OPENGLES
if (is_at_least_gl_version(1, 2)) { if (_supports_texture_lod) {
glGetTexParameteriv(target, GL_TEXTURE_MAX_LEVEL, &highest_level); glGetTexParameteriv(target, GL_TEXTURE_MAX_LEVEL, &highest_level);
highest_level = min(highest_level, num_expected_levels); highest_level = min(highest_level, num_expected_levels);
} }

View File

@ -918,6 +918,12 @@ public:
GLenum _mirror_clamp; GLenum _mirror_clamp;
GLenum _mirror_edge_clamp; GLenum _mirror_edge_clamp;
GLenum _mirror_border_clamp; GLenum _mirror_border_clamp;
#ifndef OPENGLES
bool _supports_texture_lod;
bool _supports_texture_lod_bias;
#endif
#ifndef OPENGLES_1 #ifndef OPENGLES_1
GLsizei _instance_count; GLsizei _instance_count;
#endif #endif

View File

@ -48,6 +48,12 @@ ConfigVariableBool gl_support_rescale_normal
"it even if it appears to be available. (This appears to be " "it even if it appears to be available. (This appears to be "
"buggy on some drivers.)")); "buggy on some drivers.)"));
ConfigVariableBool gl_support_texture_lod
("gl-support-texture-lod", true,
PRC_DESC("Configure this true to enable the use of minmax LOD settings "
"and texture LOD bias settings. Set this to false if you "
"suspect a driver bug."));
ConfigVariableBool gl_ignore_filters ConfigVariableBool gl_ignore_filters
("gl-ignore-filters", false, ("gl-ignore-filters", false,
PRC_DESC("Configure this true to disable any texture filters at all (forcing " PRC_DESC("Configure this true to disable any texture filters at all (forcing "

View File

@ -46,6 +46,7 @@ extern EXPCL_PANDAGL ConfigVariableBool gl_support_fbo;
extern ConfigVariableBool gl_cheap_textures; extern ConfigVariableBool gl_cheap_textures;
extern ConfigVariableBool gl_ignore_clamp; extern ConfigVariableBool gl_ignore_clamp;
extern ConfigVariableBool gl_support_clamp_to_border; extern ConfigVariableBool gl_support_clamp_to_border;
extern ConfigVariableBool gl_support_texture_lod;
extern ConfigVariableBool gl_ignore_filters; extern ConfigVariableBool gl_ignore_filters;
extern ConfigVariableBool gl_ignore_mipmaps; extern ConfigVariableBool gl_ignore_mipmaps;
extern ConfigVariableBool gl_force_mipmaps; extern ConfigVariableBool gl_force_mipmaps;