From 94f88c82cf79a14aa0c79a79d2b0cb37112d3aab Mon Sep 17 00:00:00 2001 From: Zachary Lund Date: Fri, 3 Jan 2014 23:14:35 -0600 Subject: [PATCH 1/7] Added OpenGL debug callback support and context changes. 1. We no longer hardcode a 3.2 profile. It chooses the latest profile that fits out description. 2. I added three tables and macros to help with the offsets compared to the variables to help reading. Read comments for more info. 3. I added glewExperimental being set. What a dumb "feature". It doesn't help anything... --- libobs-opengl/gl-subsystem.c | 78 +++++++++++++++++++++++++++++++++--- libobs-opengl/gl-x11.c | 15 +++---- 2 files changed, 80 insertions(+), 13 deletions(-) diff --git a/libobs-opengl/gl-subsystem.c b/libobs-opengl/gl-subsystem.c index d72cb229d..7457e15eb 100644 --- a/libobs-opengl/gl-subsystem.c +++ b/libobs-opengl/gl-subsystem.c @@ -18,6 +18,74 @@ #include #include "gl-subsystem.h" +/* Tables for OpenGL debug */ +static const char* debug_source_table[] = { + "API", + "Window System", + "Shader Compiler", + "Third Party" + "Application", + "Other" +}; + +static const char* debug_type_table[] = { + "Error", + "Deprecated Behavior", + "Undefined Behavior", + "Portability", + "Performance", + "Other" +}; + +static const char* debug_severity_table[] = { + "High", + "Medium", + "Low" +}; + +/* ARB and core values are the same. They'll always be linear so no hardcoding. */ +/* The values subtracted are the lowest value in the list of valid values. */ +#define GL_DEBUG_SOURCE_OFFSET(x) (x - GL_DEBUG_SOURCE_API_ARB) +#define GL_DEBUG_TYPE_OFFSET(x) (x - GL_DEBUG_TYPE_ERROR_ARB) +#define GL_DEBUG_SEVERITY_OFFSET(x) (x - GL_DEBUG_SEVERITY_HIGH_ARB) + +#ifdef _DEBUG +static void gl_debug_proc( + GLenum source, GLenum type, GLuint id, GLenum severity, + GLsizei length, const GLchar *message, GLvoid *data ) +{ + blog( LOG_DEBUG, + "[%s][%s]{%}: %.*s", + debug_source_table[GL_DEBUG_SOURCE_OFFSET(source)], + debug_type_table[GL_DEBUG_TYPE_OFFSET(type)], + debug_severity_table[GL_DEBUG_SEVERITY_OFFSET(severity)], + length, message + ); +} + +static void gl_enable_debug() +{ + /* Perhaps we should create GLEW contexts? */ + + if (GLEW_VERSION_4_0) + glDebugMessageCallback(gl_debug_proc, NULL); + else if (GLEW_ARB_debug_output) { + glDebugMessageCallbackARB(gl_debug_proc, NULL); + } else { + blog(LOG_DEBUG, "Failed to set GL debug callback as it is not supported."); + return; + } + + glEnable(GL_DEBUG_OUTPUT); + if (glGetError() == GL_INVALID_ENUM) + blog(LOG_DEBUG, "OpenGL debug information not available"); /* Debug callback simply won't be called. */ + else + blog(LOG_DEBUG, "Successfully hooked into OpenGL debug message callback."); +} +#else +static void gl_enable_debug() {} +#endif + static void clear_textures(struct gs_device *device) { GLenum i; @@ -69,6 +137,9 @@ device_t device_create(struct gs_init_data *info) if (!device->plat) goto fail; + /* We expect platform specific code to initialize GLEW as they might use it themselves anyways. */ + /* Also, that code needs to set glewExperimental to true (since it fails to set core functionality like a dum dum) */ + glGenProgramPipelines(1, &device->pipeline); if (!gl_success("glGenProgramPipelines")) goto fail; @@ -77,12 +148,7 @@ device_t device_create(struct gs_init_data *info) if (!gl_success("glBindProgramPipeline")) goto fail; -#ifdef _DEBUG - glEnable(GL_DEBUG_OUTPUT); - if (glGetError() == GL_INVALID_ENUM) - blog(LOG_DEBUG, "OpenGL debug information not available"); -#endif - + gl_enable_debug(); gl_enable(GL_CULL_FACE); device_leavecontext(device); diff --git a/libobs-opengl/gl-x11.c b/libobs-opengl/gl-x11.c index 223641ae1..55acc0119 100644 --- a/libobs-opengl/gl-x11.c +++ b/libobs-opengl/gl-x11.c @@ -19,12 +19,11 @@ static const GLenum fb_attribs[] = { }; static const GLenum ctx_attribs[] = { - GLX_CONTEXT_MAJOR_VERSION_ARB, 3, - GLX_CONTEXT_MINOR_VERSION_ARB, 2, - GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB | - GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, +#ifdef _DEBUG + GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, +#endif GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - 0, 0 + None, }; static const char* __GLX_error_table[] = { @@ -169,17 +168,19 @@ struct gl_platform *gl_platform_create(device_t device, goto fail2; } - blog(LOG_INFO, "OpenGL version: %s\n", glGetString(GL_VERSION)); - /* Initialize GLEW */ { GLenum err = glewInit(); + glewExperimental = true; + if (GLEW_OK != err) { blog(LOG_ERROR, glewGetErrorString(err)); goto fail2; } } + blog(LOG_INFO, "OpenGL version: %s\n", glGetString(GL_VERSION)); + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); glEnable(GL_DEBUG_OUTPUT); glEnable(GL_CULL_FACE); From 3dc2024c8f183dda9fd0759457521cd0ff2e196f Mon Sep 17 00:00:00 2001 From: Zachary Lund Date: Sat, 4 Jan 2014 00:42:23 -0600 Subject: [PATCH 2/7] Remove enable statements. This should be done in platform-independent code using GLEW. --- libobs-opengl/gl-x11.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libobs-opengl/gl-x11.c b/libobs-opengl/gl-x11.c index 55acc0119..d6d3395ba 100644 --- a/libobs-opengl/gl-x11.c +++ b/libobs-opengl/gl-x11.c @@ -181,10 +181,6 @@ struct gl_platform *gl_platform_create(device_t device, blog(LOG_INFO, "OpenGL version: %s\n", glGetString(GL_VERSION)); - glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); - glEnable(GL_DEBUG_OUTPUT); - glEnable(GL_CULL_FACE); - plat->swap.device = device; plat->swap.info = *info; plat->swap.wi = gl_windowinfo_create(info); From ffd80449d392e3b44f88d747381b64bb1aa190e6 Mon Sep 17 00:00:00 2001 From: Zachary Lund Date: Sat, 4 Jan 2014 00:48:41 -0600 Subject: [PATCH 3/7] Added gl_update (does nothing for now). Fix previous commit.. --- libobs-opengl/gl-x11.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libobs-opengl/gl-x11.c b/libobs-opengl/gl-x11.c index d6d3395ba..d94310775 100644 --- a/libobs-opengl/gl-x11.c +++ b/libobs-opengl/gl-x11.c @@ -233,6 +233,12 @@ void device_leavecontext(device_t device) blog(LOG_ERROR, "Failed to reset current context."); } } + +void gl_update(device_t device) +{ + /* I don't know of anything we can do here. */ +} + void device_load_swapchain(device_t device, swapchain_t swap) { if(!swap) From 8df5293be11ccac13697c4d3fa75e950456c07e5 Mon Sep 17 00:00:00 2001 From: Zachary Lund Date: Sat, 4 Jan 2014 01:08:49 -0600 Subject: [PATCH 4/7] Added GLX version check and assures context is set to none on failure. Fixed the location glewExperimental was being set to just before glewInit() (where it should be). --- libobs-opengl/gl-x11.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/libobs-opengl/gl-x11.c b/libobs-opengl/gl-x11.c index d94310775..f5bc2aca6 100644 --- a/libobs-opengl/gl-x11.c +++ b/libobs-opengl/gl-x11.c @@ -138,6 +138,17 @@ struct gl_platform *gl_platform_create(device_t device, XSetErrorHandler(GLXErrorHandler); + /* We require glX version 1.4 */ + { + int major = 0, minor = 0; + + glXQueryVersion(display, &major, &minor); + if (major < 1 || minor < 4) { + blog(LOG_ERROR, "GLX version isn't high enough."); + goto fail0; + } + } + glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress("glXCreateContextAttribsARB"); if (!glXCreateContextAttribsARB) { blog(LOG_ERROR, "ARB_GLX_create_context not supported!"); @@ -169,9 +180,9 @@ struct gl_platform *gl_platform_create(device_t device, } /* Initialize GLEW */ - { - GLenum err = glewInit(); + { glewExperimental = true; + GLenum err = glewInit(); if (GLEW_OK != err) { blog(LOG_ERROR, glewGetErrorString(err)); @@ -192,6 +203,7 @@ struct gl_platform *gl_platform_create(device_t device, return plat; fail2: + glXMakeCurrent(display, None, NULL); glXDestroyContext(display, plat->context); fail1: XFree(configs); From fee0d9a8f37104cd3837a3ff21d9fbe2e91e1f3f Mon Sep 17 00:00:00 2001 From: Zachary Lund Date: Sat, 4 Jan 2014 01:37:00 -0600 Subject: [PATCH 5/7] Minor style fixup --- libobs-opengl/gl-subsystem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libobs-opengl/gl-subsystem.c b/libobs-opengl/gl-subsystem.c index 7457e15eb..6c97f9088 100644 --- a/libobs-opengl/gl-subsystem.c +++ b/libobs-opengl/gl-subsystem.c @@ -69,9 +69,9 @@ static void gl_enable_debug() if (GLEW_VERSION_4_0) glDebugMessageCallback(gl_debug_proc, NULL); - else if (GLEW_ARB_debug_output) { + else if (GLEW_ARB_debug_output) glDebugMessageCallbackARB(gl_debug_proc, NULL); - } else { + else { blog(LOG_DEBUG, "Failed to set GL debug callback as it is not supported."); return; } From 4aef1d00d1cd0adbfb8cc88b6e22b74e83b0cef2 Mon Sep 17 00:00:00 2001 From: Zachary Lund Date: Sun, 5 Jan 2014 19:55:19 -0600 Subject: [PATCH 6/7] Change _DEBUG coverage a bit --- libobs-opengl/gl-subsystem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libobs-opengl/gl-subsystem.c b/libobs-opengl/gl-subsystem.c index 6c97f9088..dfc2baf10 100644 --- a/libobs-opengl/gl-subsystem.c +++ b/libobs-opengl/gl-subsystem.c @@ -18,6 +18,7 @@ #include #include "gl-subsystem.h" +#ifdef _DEBUG /* Tables for OpenGL debug */ static const char* debug_source_table[] = { "API", @@ -49,7 +50,6 @@ static const char* debug_severity_table[] = { #define GL_DEBUG_TYPE_OFFSET(x) (x - GL_DEBUG_TYPE_ERROR_ARB) #define GL_DEBUG_SEVERITY_OFFSET(x) (x - GL_DEBUG_SEVERITY_HIGH_ARB) -#ifdef _DEBUG static void gl_debug_proc( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *data ) From 840c1cfd65d043c16e59b1f1316f52d95d6555a0 Mon Sep 17 00:00:00 2001 From: Zachary Lund Date: Sun, 5 Jan 2014 21:05:17 -0600 Subject: [PATCH 7/7] I removed GL-specific extension checking to a platform independent file. I also fixed autoconf to find wxWidgets 2.9 without user intervention Removed unused code and added more organization --- configure.ac | 2 +- libobs-opengl/gl-cocoa.m | 26 ---------------- libobs-opengl/gl-subsystem.c | 58 ++++++++++++++++++++++++++++-------- libobs-opengl/gl-windows.c | 51 ++----------------------------- libobs-opengl/gl-x11.c | 12 +------- 5 files changed, 50 insertions(+), 99 deletions(-) diff --git a/configure.ac b/configure.ac index e7f110bad..8146f1c31 100644 --- a/configure.ac +++ b/configure.ac @@ -91,7 +91,7 @@ WX_CONFIG_CHECK( is in LD_LIBRARY_PATH or equivalent variable and wxWidgets version is $wxVersion or above. ]) ], - [core], ) + [core], [--version=2.9]) CPPFLAGS="$CPPFLAGS $WX_CPPFLAGS" CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS_ONLY" diff --git a/libobs-opengl/gl-cocoa.m b/libobs-opengl/gl-cocoa.m index 143fb2b02..03ec771e1 100644 --- a/libobs-opengl/gl-cocoa.m +++ b/libobs-opengl/gl-cocoa.m @@ -97,11 +97,6 @@ static NSOpenGLContext *gl_context_create(struct gs_init_data *info) return context; } -static inline void required_extension_error(const char *extension) -{ - blog(LOG_ERROR, "OpenGL extension %s is required", extension); -} - static bool gl_init_extensions(device_t device) { glewExperimental=true; @@ -112,27 +107,6 @@ static bool gl_init_extensions(device_t device) return false; } - if(!GLEW_VERSION_2_1) { - blog(LOG_ERROR, "OpenGL 2.1 minimum required by the graphics " - "adapter"); - return false; - } - - if(!GLEW_ARB_framebuffer_object) { - required_extension_error("GL_ARB_framebuffer_object"); - return false; - } - - if(!GLEW_ARB_separate_shader_objects) { - required_extension_error("GL_ARB_separate_shader_objects"); - return false; - } - - //something inside glew produces error code 1280 (invalid enum) - glGetError(); - - device->copy_type = COPY_TYPE_FBO_BLIT; - return true; } diff --git a/libobs-opengl/gl-subsystem.c b/libobs-opengl/gl-subsystem.c index dfc2baf10..d3ce4c0ab 100644 --- a/libobs-opengl/gl-subsystem.c +++ b/libobs-opengl/gl-subsystem.c @@ -50,12 +50,12 @@ static const char* debug_severity_table[] = { #define GL_DEBUG_TYPE_OFFSET(x) (x - GL_DEBUG_TYPE_ERROR_ARB) #define GL_DEBUG_SEVERITY_OFFSET(x) (x - GL_DEBUG_SEVERITY_HIGH_ARB) -static void gl_debug_proc( +static APIENTRY void gl_debug_proc( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *data ) { blog( LOG_DEBUG, - "[%s][%s]{%}: %.*s", + "[%s][%s]{%s}: %.*s", debug_source_table[GL_DEBUG_SOURCE_OFFSET(source)], debug_type_table[GL_DEBUG_TYPE_OFFSET(type)], debug_severity_table[GL_DEBUG_SEVERITY_OFFSET(severity)], @@ -76,16 +76,49 @@ static void gl_enable_debug() return; } - glEnable(GL_DEBUG_OUTPUT); - if (glGetError() == GL_INVALID_ENUM) - blog(LOG_DEBUG, "OpenGL debug information not available"); /* Debug callback simply won't be called. */ - else - blog(LOG_DEBUG, "Successfully hooked into OpenGL debug message callback."); + gl_enable(GL_DEBUG_OUTPUT); } #else static void gl_enable_debug() {} #endif +static inline void required_extension_error(const char *extension) +{ +} + +static bool gl_init_extensions(struct gs_device* device) +{ + if (!GLEW_VERSION_2_1) { + blog(LOG_ERROR, "obs-studio requires OpenGL version 2.1 or higher."); + return false; + } + + gl_enable_debug(); + + if (!GLEW_VERSION_3_0 && !GLEW_ARB_framebuffer_object) { + blog(LOG_ERROR, "OpenGL extension ARB_framebuffer_object is required."); + return false; + } + + if (GLEW_VERSION_3_1 || GLEW_ARB_seamless_cube_map) { + gl_enable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + } + + if (!GLEW_VERSION_4_1 && !GLEW_ARB_separate_shader_objects) { + blog(LOG_ERROR, "OpenGL extension ARB_separate_shader_objects is required."); + return false; + } + + if (GLEW_ARB_copy_image || GLEW_VERSION_4_2) + device->copy_type = COPY_TYPE_ARB; + else if (GLEW_NV_copy_image) + device->copy_type = COPY_TYPE_NV; + else + device->copy_type = COPY_TYPE_FBO_BLIT; /* ?? */ + + return true; +} + static void clear_textures(struct gs_device *device) { GLenum i; @@ -137,8 +170,10 @@ device_t device_create(struct gs_init_data *info) if (!device->plat) goto fail; - /* We expect platform specific code to initialize GLEW as they might use it themselves anyways. */ - /* Also, that code needs to set glewExperimental to true (since it fails to set core functionality like a dum dum) */ + if (!gl_init_extensions(device)) + goto fail; + + gl_enable(GL_CULL_FACE); glGenProgramPipelines(1, &device->pipeline); if (!gl_success("glGenProgramPipelines")) @@ -148,9 +183,6 @@ device_t device_create(struct gs_init_data *info) if (!gl_success("glBindProgramPipeline")) goto fail; - gl_enable_debug(); - gl_enable(GL_CULL_FACE); - device_leavecontext(device); device->cur_swap = gl_platform_getswap(device->plat); @@ -1111,7 +1143,7 @@ void device_frustum(device_t device, float left, float right, dst->x.x = nearx2 / rml; dst->z.x = (left+right) / rml; - + dst->y.y = nearx2 / tmb; dst->z.y = (bottom+top) / tmb; diff --git a/libobs-opengl/gl-windows.c b/libobs-opengl/gl-windows.c index dc92b524b..bd2e285f3 100644 --- a/libobs-opengl/gl-windows.c +++ b/libobs-opengl/gl-windows.c @@ -155,10 +155,9 @@ static inline HGLRC gl_init_basic_context(HDC hdc) static const int attribs[] = { - WGL_CONTEXT_MAJOR_VERSION_ARB, 3, - WGL_CONTEXT_MINOR_VERSION_ARB, 2, - WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB | - WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, +#ifdef _DEBUG + WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB, +#endif WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 0, 0 }; @@ -244,29 +243,11 @@ static bool gl_init_extensions(device_t device) return false; } - if (!GLEW_VERSION_2_1) { - blog(LOG_ERROR, "OpenGL 2.1 minimum required by the graphics " - "adapter"); - return false; - } - - if (!GLEW_ARB_framebuffer_object) { - required_extension_error("GL_ARB_framebuffer_object"); - return false; - } - if (!WGLEW_ARB_pixel_format) { required_extension_error("WGL_ARB_pixel_format"); return false; } - if (GLEW_ARB_copy_image) - device->copy_type = COPY_TYPE_ARB; - else if (GLEW_NV_copy_image) - device->copy_type = COPY_TYPE_NV; - else - device->copy_type = COPY_TYPE_FBO_BLIT; - return true; } @@ -377,19 +358,6 @@ static bool init_default_swap(struct gl_platform *plat, device_t device, return true; } -#ifdef _DEBUG -static void APIENTRY gl_debug_message_amd(GLuint id, - GLenum category, - GLenum severity, - GLsizei length, - const GLchar *msg, - void *param) -{ - OutputDebugStringA(msg); - OutputDebugStringA("\n"); -} -#endif - void gl_update(device_t device) { /* does nothing on windows */ @@ -425,19 +393,6 @@ struct gl_platform *gl_platform_create(device_t device, if (!plat->hrc) goto fail; - if (GLEW_ARB_seamless_cube_map) { - glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); - gl_success("GL_TEXTURE_CUBE_MAP_SEAMLESS"); - } - -#ifdef _DEBUG - if (GLEW_AMD_debug_output) { - glDebugMessageEnableAMD(0, 0, 0, NULL, true); - glDebugMessageCallbackAMD(gl_debug_message_amd, device); - gl_success("glDebugMessageCallback"); - } -#endif - return plat; fail: diff --git a/libobs-opengl/gl-x11.c b/libobs-opengl/gl-x11.c index f5bc2aca6..d1eebd6c0 100644 --- a/libobs-opengl/gl-x11.c +++ b/libobs-opengl/gl-x11.c @@ -105,24 +105,14 @@ static void print_info_stuff(struct gs_init_data *info) struct gl_platform *gl_platform_create(device_t device, struct gs_init_data *info) { - /* X11 */ int num_configs = 0; int error_base = 0, event_base = 0; Display *display = XOpenDisplay(NULL); /* Open default screen */ - - /* OBS */ struct gl_platform *plat = bmalloc(sizeof(struct gl_platform)); - - /* GLX */ GLXFBConfig* configs; print_info_stuff(info); - if (!plat) { - blog(LOG_ERROR, "Out of memory"); - return NULL; - } - memset(plat, 0, sizeof(struct gl_platform)); if (!display) { @@ -144,7 +134,7 @@ struct gl_platform *gl_platform_create(device_t device, glXQueryVersion(display, &major, &minor); if (major < 1 || minor < 4) { - blog(LOG_ERROR, "GLX version isn't high enough."); + blog(LOG_ERROR, "GLX version found: %i.%i\nRequired: 1.4", major, minor); goto fail0; } }