749 lines
20 KiB
C
749 lines
20 KiB
C
/*
|
|
* This software is licensed under the terms of the MIT License.
|
|
* See COPYING for further information.
|
|
* ---
|
|
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
|
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
|
*/
|
|
|
|
#include "taisei.h"
|
|
|
|
#include "util.h"
|
|
#include "rwops/rwops_autobuf.h"
|
|
#include "opengl.h"
|
|
#include "debug.h"
|
|
#include "shaders.h"
|
|
|
|
// undef extension abstraction macros
|
|
#undef glDebugMessageControl
|
|
#undef glDebugMessageCallback
|
|
#undef glObjectLabel
|
|
#undef glDrawArraysInstanced
|
|
#undef glDrawElementsInstanced
|
|
#undef glVertexAttribDivisor
|
|
#undef glDrawArraysInstancedBaseInstance
|
|
#undef glDrawElementsInstancedBaseInstance
|
|
#undef glDrawBuffers
|
|
#undef glClearTexImage
|
|
// #undef glClearTexSubImage
|
|
#undef glBindVertexArray
|
|
#undef glDeleteVertexArrays
|
|
#undef glGenVertexArrays
|
|
#undef glIsVertexArray
|
|
#undef glGetFloati_v
|
|
#undef glViewportIndexedfv
|
|
|
|
struct glext_s glext;
|
|
|
|
typedef void (*glad_glproc_ptr)(void);
|
|
|
|
static const char *const ext_vendor_table[] = {
|
|
#define TSGL_EXT_VENDOR(v) [_TSGL_EXTVNUM_##v] = #v,
|
|
TSGL_EXT_VENDORS
|
|
#undef TSGL_EXT_VENDOR
|
|
|
|
NULL,
|
|
};
|
|
|
|
static ext_flag_t glcommon_ext_flag(const char *ext) {
|
|
assert(ext != NULL);
|
|
ext = strchr(ext, '_');
|
|
|
|
if(ext == NULL) {
|
|
log_fatal("Bad extension string: %s", ext);
|
|
}
|
|
|
|
const char *sep = strchr(++ext, '_');
|
|
|
|
if(sep == NULL) {
|
|
log_fatal("Bad extension string: %s", ext);
|
|
}
|
|
|
|
char vendor[sep - ext + 1];
|
|
strlcpy(vendor, ext, sizeof(vendor));
|
|
|
|
for(const char *const *p = ext_vendor_table; *p; ++p) {
|
|
if(!strcmp(*p, vendor)) {
|
|
return 1 << (p - ext_vendor_table);
|
|
}
|
|
}
|
|
|
|
log_fatal("Unknown vendor '%s' in extension string %s", vendor, ext);
|
|
}
|
|
|
|
ext_flag_t glcommon_check_extension(const char *ext) {
|
|
const char *overrides = env_get("TAISEI_GL_EXT_OVERRIDES", "");
|
|
ext_flag_t flag = glcommon_ext_flag(ext);
|
|
|
|
if(*overrides) {
|
|
char buf[strlen(overrides)+1], *save, *arg, *e;
|
|
strcpy(buf, overrides);
|
|
arg = buf;
|
|
|
|
while((e = strtok_r(arg, " ", &save))) {
|
|
bool r = true;
|
|
|
|
if(*e == '-') {
|
|
++e;
|
|
r = false;
|
|
}
|
|
|
|
if(!strcmp(e, ext)) {
|
|
return r ? flag : 0;
|
|
}
|
|
|
|
arg = NULL;
|
|
}
|
|
}
|
|
|
|
return SDL_GL_ExtensionSupported(ext) ? flag : 0;
|
|
}
|
|
|
|
ext_flag_t glcommon_require_extension(const char *ext) {
|
|
ext_flag_t val = glcommon_check_extension(ext);
|
|
|
|
if(!val) {
|
|
if(env_get("TAISEI_GL_REQUIRE_EXTENSION_FATAL", 0)) {
|
|
log_fatal("Required extension %s is not available", ext);
|
|
}
|
|
|
|
log_error("Required extension %s is not available, expect crashes or rendering errors", ext);
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
static void glcommon_ext_debug_output(void) {
|
|
#ifndef STATIC_GLES3
|
|
if(
|
|
GL_ATLEAST(4, 3)
|
|
&& (glext.DebugMessageCallback = GL_FUNC(DebugMessageCallback))
|
|
&& (glext.DebugMessageControl = GL_FUNC(DebugMessageControl))
|
|
&& (glext.ObjectLabel = GL_FUNC(ObjectLabel))
|
|
) {
|
|
glext.debug_output = TSGL_EXTFLAG_NATIVE;
|
|
log_info("Using core functionality");
|
|
return;
|
|
}
|
|
|
|
if(glext.version.is_es) {
|
|
if((glext.debug_output = glcommon_check_extension("GL_KHR_debug"))
|
|
&& (glext.DebugMessageCallback = GL_FUNC(DebugMessageCallbackKHR))
|
|
&& (glext.DebugMessageControl = GL_FUNC(DebugMessageControlKHR))
|
|
&& (glext.ObjectLabel = GL_FUNC(ObjectLabelKHR))
|
|
) {
|
|
log_info("Using GL_KHR_debug");
|
|
return;
|
|
}
|
|
} else {
|
|
if((glext.debug_output = glcommon_check_extension("GL_KHR_debug"))
|
|
&& (glext.DebugMessageCallback = GL_FUNC(DebugMessageCallback))
|
|
&& (glext.DebugMessageControl = GL_FUNC(DebugMessageControl))
|
|
&& (glext.ObjectLabel = GL_FUNC(ObjectLabel))
|
|
) {
|
|
log_info("Using GL_KHR_debug");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if((glext.debug_output = glcommon_check_extension("GL_ARB_debug_output"))
|
|
&& (glext.DebugMessageCallback = GL_FUNC(DebugMessageCallbackARB))
|
|
&& (glext.DebugMessageControl = GL_FUNC(DebugMessageControlARB))
|
|
) {
|
|
log_info("Using GL_ARB_debug_output");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
glext.debug_output = 0;
|
|
log_warn("Extension not supported");
|
|
}
|
|
|
|
static void glcommon_ext_base_instance(void) {
|
|
#ifndef STATIC_GLES3
|
|
if(
|
|
GL_ATLEAST(4, 2)
|
|
&& (glext.DrawArraysInstancedBaseInstance = GL_FUNC(DrawArraysInstancedBaseInstance))
|
|
&& (glext.DrawElementsInstancedBaseInstance = GL_FUNC(DrawElementsInstancedBaseInstance))
|
|
) {
|
|
glext.base_instance = TSGL_EXTFLAG_NATIVE;
|
|
log_info("Using core functionality");
|
|
return;
|
|
}
|
|
|
|
if((glext.base_instance = glcommon_check_extension("GL_ARB_base_instance"))
|
|
&& (glext.DrawArraysInstancedBaseInstance = GL_FUNC(DrawArraysInstancedBaseInstance))
|
|
&& (glext.DrawElementsInstancedBaseInstance = GL_FUNC(DrawElementsInstancedBaseInstance))
|
|
) {
|
|
log_info("Using GL_ARB_base_instance");
|
|
return;
|
|
}
|
|
|
|
if((glext.base_instance = glcommon_check_extension("GL_EXT_base_instance"))
|
|
&& (glext.DrawArraysInstancedBaseInstance = GL_FUNC(DrawArraysInstancedBaseInstanceEXT))
|
|
&& (glext.DrawElementsInstancedBaseInstance = GL_FUNC(DrawElementsInstancedBaseInstanceEXT))
|
|
) {
|
|
log_info("Using GL_EXT_base_instance");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
glext.base_instance = 0;
|
|
log_warn("Extension not supported");
|
|
}
|
|
|
|
static void glcommon_ext_pixel_buffer_object(void) {
|
|
#ifdef STATIC_GLES3
|
|
glext.pixel_buffer_object = TSGL_EXTFLAG_NATIVE;
|
|
log_info("Using core functionality");
|
|
return;
|
|
#else
|
|
// TODO: verify that these requirements are correct
|
|
if(GL_ATLEAST(2, 0) || GLES_ATLEAST(3, 0)) {
|
|
glext.pixel_buffer_object = TSGL_EXTFLAG_NATIVE;
|
|
log_info("Using core functionality");
|
|
return;
|
|
}
|
|
|
|
const char *exts[] = {
|
|
"GL_ARB_pixel_buffer_object",
|
|
"GL_EXT_pixel_buffer_object",
|
|
"GL_NV_pixel_buffer_object",
|
|
NULL
|
|
};
|
|
|
|
for(const char **p = exts; *p; ++p) {
|
|
if((glext.pixel_buffer_object = glcommon_check_extension(*p))) {
|
|
log_info("Using %s", *p);
|
|
return;
|
|
}
|
|
}
|
|
|
|
glext.pixel_buffer_object = 0;
|
|
log_warn("Extension not supported");
|
|
#endif
|
|
}
|
|
|
|
static void glcommon_ext_depth_texture(void) {
|
|
#ifdef STATIC_GLES3
|
|
glext.depth_texture = TSGL_EXTFLAG_NATIVE;
|
|
log_info("Using core functionality");
|
|
return;
|
|
#else
|
|
// TODO: detect this for core OpenGL properly
|
|
if(!glext.version.is_es || GLES_ATLEAST(3, 0)) {
|
|
glext.depth_texture = TSGL_EXTFLAG_NATIVE;
|
|
log_info("Using core functionality");
|
|
return;
|
|
}
|
|
|
|
const char *exts[] = {
|
|
"GL_OES_depth_texture",
|
|
"GL_ANGLE_depth_texture",
|
|
NULL
|
|
};
|
|
|
|
for(const char **p = exts; *p; ++p) {
|
|
if((glext.pixel_buffer_object = glcommon_check_extension(*p))) {
|
|
log_info("Using %s", *p);
|
|
return;
|
|
}
|
|
}
|
|
|
|
glext.depth_texture = 0;
|
|
log_warn("Extension not supported");
|
|
#endif
|
|
}
|
|
|
|
static void glcommon_ext_instanced_arrays(void) {
|
|
#ifdef STATIC_GLES3
|
|
glext.instanced_arrays = TSGL_EXTFLAG_NATIVE;
|
|
log_info("Using core functionality");
|
|
return;
|
|
#else
|
|
if(
|
|
(GL_ATLEAST(3, 3) || GLES_ATLEAST(3, 0))
|
|
&& (glext.DrawArraysInstanced = GL_FUNC(DrawArraysInstanced))
|
|
&& (glext.DrawElementsInstanced = GL_FUNC(DrawElementsInstanced))
|
|
&& (glext.VertexAttribDivisor = GL_FUNC(VertexAttribDivisor))
|
|
) {
|
|
glext.instanced_arrays = TSGL_EXTFLAG_NATIVE;
|
|
log_info("Using core functionality");
|
|
return;
|
|
}
|
|
|
|
if((glext.instanced_arrays = glcommon_check_extension("GL_ARB_instanced_arrays"))
|
|
&& (glext.DrawArraysInstanced = GL_FUNC(DrawArraysInstancedARB))
|
|
&& (glext.DrawElementsInstanced = GL_FUNC(DrawElementsInstancedARB))
|
|
&& (glext.VertexAttribDivisor = GL_FUNC(VertexAttribDivisorARB))
|
|
) {
|
|
log_info("Using GL_ARB_instanced_arrays (GL_ARB_draw_instanced assumed)");
|
|
return;
|
|
}
|
|
|
|
if((glext.instanced_arrays = glcommon_check_extension("GL_EXT_instanced_arrays"))
|
|
&& (glext.DrawArraysInstanced = GL_FUNC(DrawArraysInstancedEXT))
|
|
&& (glext.DrawElementsInstanced = GL_FUNC(DrawElementsInstancedEXT))
|
|
&& (glext.VertexAttribDivisor = GL_FUNC(VertexAttribDivisorEXT))
|
|
) {
|
|
log_info("Using GL_EXT_instanced_arrays");
|
|
return;
|
|
}
|
|
|
|
if((glext.instanced_arrays = glcommon_check_extension("GL_ANGLE_instanced_arrays"))
|
|
&& (glext.DrawArraysInstanced = GL_FUNC(DrawArraysInstancedANGLE))
|
|
&& (glext.DrawElementsInstanced = GL_FUNC(DrawElementsInstancedANGLE))
|
|
&& (glext.VertexAttribDivisor = GL_FUNC(VertexAttribDivisorANGLE))
|
|
) {
|
|
log_info("Using GL_ANGLE_instanced_arrays");
|
|
return;
|
|
}
|
|
|
|
if((glext.instanced_arrays = glcommon_check_extension("GL_NV_instanced_arrays"))
|
|
&& (glext.DrawArraysInstanced = GL_FUNC(DrawArraysInstancedNV))
|
|
&& (glext.DrawElementsInstanced = GL_FUNC(DrawElementsInstancedNV))
|
|
&& (glext.VertexAttribDivisor = GL_FUNC(VertexAttribDivisorNV))
|
|
) {
|
|
log_info("Using GL_NV_instanced_arrays (GL_NV_draw_instanced assumed)");
|
|
return;
|
|
}
|
|
|
|
glext.instanced_arrays = 0;
|
|
log_warn("Extension not supported");
|
|
#endif
|
|
}
|
|
|
|
static void glcommon_ext_draw_buffers(void) {
|
|
#ifdef STATIC_GLES3
|
|
glext.draw_buffers = TSGL_EXTFLAG_NATIVE;
|
|
log_info("Using core functionality");
|
|
return;
|
|
#else
|
|
if(
|
|
(GL_ATLEAST(2, 0) || GLES_ATLEAST(3, 0))
|
|
&& (glext.DrawBuffers = GL_FUNC(DrawBuffers))
|
|
) {
|
|
glext.draw_buffers = TSGL_EXTFLAG_NATIVE;
|
|
log_info("Using core functionality");
|
|
return;
|
|
}
|
|
|
|
if((glext.instanced_arrays = glcommon_check_extension("GL_ARB_draw_buffers"))
|
|
&& (glext.DrawBuffers = GL_FUNC(DrawBuffersARB))
|
|
) {
|
|
log_info("Using GL_ARB_draw_buffers");
|
|
return;
|
|
}
|
|
|
|
if((glext.instanced_arrays = glcommon_check_extension("GL_EXT_draw_buffers"))
|
|
&& (glext.DrawBuffers = GL_FUNC(DrawBuffersEXT))
|
|
) {
|
|
log_info("Using GL_EXT_draw_buffers");
|
|
return;
|
|
}
|
|
|
|
glext.draw_buffers = 0;
|
|
log_warn("Extension not supported");
|
|
#endif
|
|
}
|
|
|
|
static void glcommon_ext_texture_filter_anisotropic(void) {
|
|
if(GL_ATLEAST(4, 6)) {
|
|
glext.texture_filter_anisotropic = TSGL_EXTFLAG_NATIVE;
|
|
log_info("Using core functionality");
|
|
return;
|
|
}
|
|
|
|
if((glext.texture_filter_anisotropic = glcommon_check_extension("GL_ARB_texture_filter_anisotropic"))) {
|
|
log_info("Using ARB_texture_filter_anisotropic");
|
|
return;
|
|
}
|
|
|
|
if((glext.texture_filter_anisotropic = glcommon_check_extension("GL_EXT_texture_filter_anisotropic"))) {
|
|
log_info("Using EXT_texture_filter_anisotropic");
|
|
return;
|
|
}
|
|
|
|
glext.texture_filter_anisotropic = 0;
|
|
log_warn("Extension not supported");
|
|
}
|
|
|
|
static void glcommon_ext_clear_texture(void) {
|
|
#ifdef STATIC_GLES3
|
|
if((glext.clear_texture = glcommon_check_extension("GL_EXT_clear_texture"))) {
|
|
log_info("Using GL_EXT_clear_texture");
|
|
return;
|
|
}
|
|
#else
|
|
if(
|
|
GL_ATLEAST(4, 4)
|
|
&& (glext.ClearTexImage = GL_FUNC(ClearTexImage))
|
|
) {
|
|
glext.clear_texture = TSGL_EXTFLAG_NATIVE;
|
|
log_info("Using core functionality");
|
|
return;
|
|
}
|
|
|
|
if((glext.clear_texture = glcommon_check_extension("GL_ARB_clear_texture"))
|
|
&& (glext.ClearTexImage = GL_FUNC(ClearTexImage))
|
|
) {
|
|
log_info("Using GL_ARB_clear_texture");
|
|
return;
|
|
}
|
|
|
|
if((glext.clear_texture = glcommon_check_extension("GL_EXT_clear_texture"))
|
|
&& (glext.ClearTexImage = GL_FUNC(ClearTexImageEXT))
|
|
) {
|
|
log_info("Using GL_EXT_clear_texture");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
glext.clear_texture = 0;
|
|
log_warn("Extension not supported");
|
|
}
|
|
|
|
static void glcommon_ext_texture_norm16(void) {
|
|
if(!glext.version.is_es) {
|
|
glext.texture_norm16 = TSGL_EXTFLAG_NATIVE;
|
|
log_info("Using core functionality");
|
|
return;
|
|
}
|
|
|
|
if((glext.texture_norm16 = glcommon_check_extension("GL_EXT_texture_norm16"))) {
|
|
log_info("Using GL_EXT_texture_norm16");
|
|
return;
|
|
}
|
|
|
|
glext.texture_norm16 = 0;
|
|
log_warn("Extension not supported");
|
|
}
|
|
|
|
static void glcommon_ext_texture_rg(void) {
|
|
if(!glext.version.is_es) {
|
|
glext.texture_rg = TSGL_EXTFLAG_NATIVE;
|
|
log_info("Using core functionality");
|
|
return;
|
|
}
|
|
|
|
if((glext.texture_rg = glcommon_check_extension("GL_EXT_texture_rg"))) {
|
|
log_info("Using GL_EXT_texture_rg");
|
|
return;
|
|
}
|
|
|
|
glext.texture_rg = 0;
|
|
log_warn("Extension not supported");
|
|
}
|
|
|
|
static void glcommon_ext_texture_float_linear(void) {
|
|
if(!glext.version.is_es) {
|
|
glext.texture_float_linear = TSGL_EXTFLAG_NATIVE;
|
|
log_info("Using core functionality");
|
|
return;
|
|
}
|
|
|
|
if((glext.texture_float_linear = glcommon_check_extension("GL_OES_texture_float_linear"))) {
|
|
log_info("Using GL_OES_texture_float_linear");
|
|
return;
|
|
}
|
|
|
|
glext.texture_float_linear = 0;
|
|
log_warn("Extension not supported");
|
|
}
|
|
|
|
static void glcommon_ext_texture_half_float_linear(void) {
|
|
if(!glext.version.is_es) {
|
|
glext.texture_half_float_linear = TSGL_EXTFLAG_NATIVE;
|
|
log_info("Using core functionality");
|
|
return;
|
|
}
|
|
|
|
if((glext.texture_half_float_linear = glcommon_check_extension("GL_OES_texture_half_float_linear"))) {
|
|
log_info("Using GL_OES_texture_half_float_linear");
|
|
return;
|
|
}
|
|
|
|
glext.texture_half_float_linear = 0;
|
|
log_warn("Extension not supported");
|
|
}
|
|
|
|
static void glcommon_ext_color_buffer_float(void) {
|
|
if(!glext.version.is_es) {
|
|
glext.color_buffer_float = TSGL_EXTFLAG_NATIVE;
|
|
log_info("Using core functionality");
|
|
return;
|
|
}
|
|
|
|
if((glext.color_buffer_float = glcommon_check_extension("GL_EXT_color_buffer_float"))) {
|
|
log_info("Using GL_EXT_color_buffer_float");
|
|
return;
|
|
}
|
|
|
|
glext.color_buffer_float = 0;
|
|
log_warn("Extension not supported");
|
|
}
|
|
|
|
static void glcommon_ext_float_blend(void) {
|
|
if(!glext.version.is_es) {
|
|
glext.float_blend = TSGL_EXTFLAG_NATIVE;
|
|
log_info("Using core functionality");
|
|
return;
|
|
}
|
|
|
|
if((glext.float_blend = glcommon_check_extension("GL_EXT_float_blend"))) {
|
|
log_info("Using GL_EXT_float_blend");
|
|
return;
|
|
}
|
|
|
|
glext.float_blend = 0;
|
|
log_warn("Extension not supported");
|
|
}
|
|
|
|
static void glcommon_ext_vertex_array_object(void) {
|
|
#ifdef STATIC_GLES3
|
|
glext.vertex_array_object = TSGL_EXTFLAG_NATIVE;
|
|
log_info("Using core functionality");
|
|
return;
|
|
#else
|
|
if((GL_ATLEAST(3, 0) || GLES_ATLEAST(3, 0))
|
|
&& (glext.BindVertexArray = GL_FUNC(BindVertexArray))
|
|
&& (glext.DeleteVertexArrays = GL_FUNC(DeleteVertexArrays))
|
|
&& (glext.GenVertexArrays = GL_FUNC(GenVertexArrays))
|
|
&& (glext.IsVertexArray = GL_FUNC(IsVertexArray))
|
|
) {
|
|
glext.vertex_array_object = TSGL_EXTFLAG_NATIVE;
|
|
log_info("Using core functionality");
|
|
return;
|
|
}
|
|
|
|
if((glext.vertex_array_object = glcommon_check_extension("GL_ARB_vertex_array_object"))
|
|
&& (glext.BindVertexArray = GL_FUNC(BindVertexArray))
|
|
&& (glext.DeleteVertexArrays = GL_FUNC(DeleteVertexArrays))
|
|
&& (glext.GenVertexArrays = GL_FUNC(GenVertexArrays))
|
|
&& (glext.IsVertexArray = GL_FUNC(IsVertexArray))
|
|
) {
|
|
log_info("Using GL_ARB_vertex_array_object");
|
|
return;
|
|
}
|
|
|
|
if((glext.vertex_array_object = glcommon_check_extension("GL_OES_vertex_array_object"))
|
|
&& (glext.BindVertexArray = GL_FUNC(BindVertexArrayOES))
|
|
&& (glext.DeleteVertexArrays = GL_FUNC(DeleteVertexArraysOES))
|
|
&& (glext.GenVertexArrays = GL_FUNC(GenVertexArraysOES))
|
|
&& (glext.IsVertexArray = GL_FUNC(IsVertexArrayOES))
|
|
) {
|
|
log_info("Using GL_OES_vertex_array_object");
|
|
return;
|
|
}
|
|
|
|
if((glext.vertex_array_object = glcommon_check_extension("GL_APPLE_vertex_array_object"))
|
|
&& (glext.BindVertexArray = GL_FUNC(BindVertexArrayAPPLE))
|
|
&& (glext.DeleteVertexArrays = GL_FUNC(DeleteVertexArraysAPPLE))
|
|
&& (glext.GenVertexArrays = GL_FUNC(GenVertexArraysAPPLE))
|
|
&& (glext.IsVertexArray = GL_FUNC(IsVertexArrayAPPLE))
|
|
) {
|
|
log_info("Using GL_APPLE_vertex_array_object");
|
|
return;
|
|
}
|
|
|
|
glext.vertex_array_object = 0;
|
|
log_warn("Extension not supported");
|
|
#endif
|
|
}
|
|
|
|
static void glcommon_ext_viewport_array(void) {
|
|
#ifndef STATIC_GLES3
|
|
if((GL_ATLEAST(4, 1))
|
|
&& (glext.GetFloati_v = GL_FUNC(GetFloati_v))
|
|
&& (glext.ViewportIndexedfv = GL_FUNC(ViewportIndexedfv))
|
|
) {
|
|
glext.viewport_array = TSGL_EXTFLAG_NATIVE;
|
|
log_info("Using core functionality");
|
|
return;
|
|
}
|
|
|
|
if((glext.viewport_array = glcommon_check_extension("GL_ARB_viewport_array"))
|
|
&& (glext.GetFloati_v = GL_FUNC(GetFloati_v))
|
|
&& (glext.ViewportIndexedfv = GL_FUNC(ViewportIndexedfv))
|
|
) {
|
|
log_info("Using GL_ARB_viewport_array");
|
|
return;
|
|
}
|
|
|
|
if((glext.viewport_array = glcommon_check_extension("GL_OES_viewport_array"))
|
|
&& (glext.GetFloati_v = GL_FUNC(GetFloati_vOES))
|
|
&& (glext.ViewportIndexedfv = GL_FUNC(ViewportIndexedfvOES))
|
|
) {
|
|
log_info("Using GL_OES_viewport_array");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
glext.viewport_array = 0;
|
|
log_warn("Extension not supported");
|
|
}
|
|
|
|
#ifndef STATIC_GLES3
|
|
static APIENTRY GLvoid shim_glClearDepth(GLdouble depthval) {
|
|
glClearDepthf(depthval);
|
|
}
|
|
|
|
static APIENTRY GLvoid shim_glClearDepthf(GLfloat depthval) {
|
|
glClearDepth(depthval);
|
|
}
|
|
#endif
|
|
|
|
void glcommon_check_capabilities(void) {
|
|
memset(&glext, 0, sizeof(glext));
|
|
|
|
const char *glslv = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
|
|
const char *glv = (const char*)glGetString(GL_VERSION);
|
|
|
|
#ifdef STATIC_GLES3
|
|
GLint major, minor;
|
|
glGetIntegerv(GL_MAJOR_VERSION, &major);
|
|
glGetIntegerv(GL_MINOR_VERSION, &minor);
|
|
glext.version.major = major;
|
|
glext.version.minor = minor;
|
|
#else
|
|
glext.version.major = GLVersion.major;
|
|
glext.version.minor = GLVersion.minor;
|
|
#endif
|
|
|
|
if(!glslv) {
|
|
glslv = "None";
|
|
}
|
|
|
|
glext.version.is_es = strstartswith(glv, "OpenGL ES");
|
|
|
|
#ifdef STATIC_GLES3
|
|
if(!GLES_ATLEAST(3, 0)) {
|
|
log_fatal("Compiled with STATIC_GLES3, but got a non-GLES3 context. Can't work with this");
|
|
}
|
|
#endif
|
|
|
|
if(glext.version.is_es) {
|
|
glext.version.is_ANGLE = strstr(glv, "(ANGLE ");
|
|
glext.version.is_webgl = strstr(glv, "(WebGL ");
|
|
}
|
|
|
|
log_info("OpenGL version: %s", glv);
|
|
log_info("OpenGL vendor: %s", (const char*)glGetString(GL_VENDOR));
|
|
log_info("OpenGL renderer: %s", (const char*)glGetString(GL_RENDERER));
|
|
log_info("GLSL version: %s", glslv);
|
|
|
|
// XXX: this is the legacy way, maybe we shouldn't try this first
|
|
const char *exts = (const char*)glGetString(GL_EXTENSIONS);
|
|
|
|
if(exts) {
|
|
log_info("Supported extensions: %s", exts);
|
|
} else {
|
|
void *buf;
|
|
SDL_RWops *writer = SDL_RWAutoBuffer(&buf, 1024);
|
|
GLint num_extensions;
|
|
|
|
SDL_RWprintf(writer, "Supported extensions:");
|
|
glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
|
|
|
|
for(int i = 0; i < num_extensions; ++i) {
|
|
SDL_RWprintf(writer, " %s", (const char*)glGetStringi(GL_EXTENSIONS, i));
|
|
}
|
|
|
|
SDL_WriteU8(writer, 0);
|
|
log_info("%s", (char*)buf);
|
|
SDL_RWclose(writer);
|
|
}
|
|
|
|
glcommon_ext_base_instance();
|
|
glcommon_ext_clear_texture();
|
|
glcommon_ext_color_buffer_float();
|
|
glcommon_ext_debug_output();
|
|
glcommon_ext_depth_texture();
|
|
glcommon_ext_draw_buffers();
|
|
glcommon_ext_float_blend();
|
|
glcommon_ext_instanced_arrays();
|
|
glcommon_ext_pixel_buffer_object();
|
|
glcommon_ext_texture_filter_anisotropic();
|
|
glcommon_ext_texture_float_linear();
|
|
glcommon_ext_texture_half_float_linear();
|
|
glcommon_ext_texture_norm16();
|
|
glcommon_ext_texture_rg();
|
|
glcommon_ext_vertex_array_object();
|
|
glcommon_ext_viewport_array();
|
|
|
|
// GLES has only glClearDepthf
|
|
// Core has only glClearDepth until GL 4.1
|
|
#ifndef STATIC_GLES3
|
|
assert(glClearDepth || glClearDepthf);
|
|
|
|
if(!glClearDepth) {
|
|
glClearDepth = shim_glClearDepth;
|
|
}
|
|
|
|
if(!glClearDepthf) {
|
|
glClearDepthf = shim_glClearDepthf;
|
|
}
|
|
#endif
|
|
|
|
glcommon_build_shader_lang_table();
|
|
}
|
|
|
|
void glcommon_load_library(void) {
|
|
#ifndef STATIC_GLES3
|
|
const char *lib = env_get("TAISEI_LIBGL", "");
|
|
|
|
if(!*lib) {
|
|
lib = NULL;
|
|
}
|
|
|
|
if(SDL_GL_LoadLibrary(lib) < 0) {
|
|
log_fatal("SDL_GL_LoadLibrary() failed: %s", SDL_GetError());
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void glcommon_unload_library(void) {
|
|
#ifndef STATIC_GLES3
|
|
SDL_GL_UnloadLibrary();
|
|
#endif
|
|
glcommon_free_shader_lang_table();
|
|
}
|
|
|
|
void glcommon_load_functions(void) {
|
|
#ifndef STATIC_GLES3
|
|
int profile;
|
|
|
|
if(SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile) < 0) {
|
|
log_fatal("SDL_GL_GetAttribute() failed: %s", SDL_GetError());
|
|
}
|
|
|
|
if(profile == SDL_GL_CONTEXT_PROFILE_ES) {
|
|
if(!gladLoadGLES2Loader(SDL_GL_GetProcAddress)) {
|
|
log_fatal("Failed to load OpenGL ES functions");
|
|
}
|
|
} else {
|
|
if(!gladLoadGLLoader(SDL_GL_GetProcAddress)) {
|
|
log_fatal("Failed to load OpenGL functions");
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void glcommon_setup_attributes(SDL_GLprofile profile, uint major, uint minor, SDL_GLcontextFlag ctxflags) {
|
|
if(glcommon_debug_requested()) {
|
|
ctxflags |= SDL_GL_CONTEXT_DEBUG_FLAG;
|
|
}
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile);
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
|
|
|
|
#ifndef __EMSCRIPTEN__
|
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
|
|
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
|
|
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
|
|
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, ctxflags);
|
|
#endif
|
|
}
|