diff --git a/src/backends/generic/vid.c b/src/backends/generic/vid.c index bcc41ffb..57a3db87 100644 --- a/src/backends/generic/vid.c +++ b/src/backends/generic/vid.c @@ -342,7 +342,6 @@ void Key_MarkAllUp(void); void VID_ShutdownRenderer(void); extern qboolean GLimp_InitGraphics(int fullscreen, int *pwidth, int *pheight); -extern void GLimp_ShutdownGraphics(void); qboolean VID_LoadRefresh(void) @@ -399,7 +398,6 @@ VID_LoadRefresh(void) ri.Vid_WriteScreenshot = VID_WriteScreenshot; ri.GLimp_InitGraphics = GLimp_InitGraphics; - ri.GLimp_ShutdownGraphics = GLimp_ShutdownGraphics; re = GetRefAPI( ri ); diff --git a/src/backends/sdl/refresh.c b/src/backends/sdl/refresh.c index c973dee0..85e9f7fb 100644 --- a/src/backends/sdl/refresh.c +++ b/src/backends/sdl/refresh.c @@ -123,6 +123,30 @@ SetSDLIcon() SDL_FreeSurface(icon); } +// FIXME: We need a header for this. +// Maybe we could put it in vid.h. +void GLimp_GrabInput(qboolean grab); + +/* + * Shuts the SDL render backend down + */ +static void +ShutdownGraphics(void) +{ + if (window) + { + /* cleanly ungrab input (needs window) */ + GLimp_GrabInput(false); + SDL_DestroyWindow(window); + + window = NULL; + } + + // make sure that after vid_restart the refreshrate will be queried from SDL2 again. + glimp_refreshRate = -1; + + initSuccessful = false; // not initialized anymore +} // -------- /* @@ -216,8 +240,8 @@ GLimp_InitGraphics(int fullscreen, int *pwidth, int *pheight) /* Is the surface used? */ if (window) { - re.ShutdownWindow(true); - SDL_DestroyWindow(window); + re.ShutdownContext(); + ShutdownGraphics(); window = NULL; } @@ -363,24 +387,3 @@ GLimp_GetRefreshRate(void) return glimp_refreshRate; } - -/* - * Shuts the SDL render backend down - */ -void -GLimp_ShutdownGraphics(void) -{ - if (window) - { - /* cleanly ungrab input (needs window) */ - GLimp_GrabInput(false); - SDL_DestroyWindow(window); - - window = NULL; - } - - // make sure that after vid_restart the refreshrate will be queried from SDL2 again. - glimp_refreshRate = -1; - - initSuccessful = false; // not initialized anymore -} diff --git a/src/client/header/ref.h b/src/client/header/ref.h index 435507ae..9bfbf1d8 100644 --- a/src/client/header/ref.h +++ b/src/client/header/ref.h @@ -145,9 +145,8 @@ typedef struct // returns true (1) on success int (EXPORT *InitContext)(void* sdl_window); - // shuts down rendering (OpenGL) context, calls - // VID_ShutdownWindow() to shut down window as well, if !contextOnly - void (EXPORT *ShutdownWindow)(qboolean contextOnly); + // shuts down rendering (OpenGL) context. + void (EXPORT *ShutdownContext)(void); // returns true if vsync is active, else false qboolean (EXPORT *IsVSyncActive)(void); @@ -233,7 +232,6 @@ typedef struct void (IMPORT *Vid_WriteScreenshot)( int width, int height, int comp, const void* data ); qboolean (IMPORT *GLimp_InitGraphics)(int fullscreen, int *pwidth, int *pheight); - void (IMPORT *GLimp_ShutdownGraphics)(void); } refimport_t; // this is the only function actually exported at the linker level diff --git a/src/client/refresh/gl1/gl1_main.c b/src/client/refresh/gl1/gl1_main.c index 5220a599..47266183 100644 --- a/src/client/refresh/gl1/gl1_main.c +++ b/src/client/refresh/gl1/gl1_main.c @@ -1882,7 +1882,7 @@ GetRefAPI(refimport_t imp) re.Shutdown = RI_Shutdown; re.PrepareForWindow = RI_PrepareForWindow; re.InitContext = RI_InitContext; - re.ShutdownWindow = RI_ShutdownWindow; + re.ShutdownContext = RI_ShutdownWindow; re.IsVSyncActive = RI_IsVSyncActive; re.BeginRegistration = RI_BeginRegistration; re.RegisterModel = RI_RegisterModel; diff --git a/src/client/refresh/gl1/gl1_sdl.c b/src/client/refresh/gl1/gl1_sdl.c index 27fc99de..26b7c360 100644 --- a/src/client/refresh/gl1/gl1_sdl.c +++ b/src/client/refresh/gl1/gl1_sdl.c @@ -222,8 +222,9 @@ RI_ShutdownWindow(qboolean contextOnly) } if (!contextOnly) - { - ri.GLimp_ShutdownGraphics(); + { + // FIXME + //ri.GLimp_ShutdownGraphics(); window = NULL; gl_state.hwgamma = false; diff --git a/src/client/refresh/gl3/gl3_main.c b/src/client/refresh/gl3/gl3_main.c index e6e4d09d..cfba3b09 100644 --- a/src/client/refresh/gl3/gl3_main.c +++ b/src/client/refresh/gl3/gl3_main.c @@ -524,15 +524,6 @@ GL3_Init(void) R_Printf(PRINT_ALL, " - OpenGL Debug Output: Not Supported\n"); } - if(gl3config.compat_profile) - { - // for some fucking reason particles (GL_POINT) don't work in compatibility profiles - // without setting this.. SDL1.2 only gives compat profiles and we might wanna support - // them for SDL2 as well, so broken screengrab software etc that uses GL1 functions still works - // (GL_POINT_SPRITE is not even part of 3.2core, it was only in GL2 and was deprecated afterwards) - glEnable(QGL_POINT_SPRITE); - } - // generate texture handles for all possible lightmaps glGenTextures(MAX_LIGHTMAPS*MAX_LIGHTMAPS_PER_SURFACE, gl3state.lightmap_textureIDs[0]); @@ -583,7 +574,7 @@ GL3_Shutdown(void) } /* shutdown OS specific OpenGL stuff like contexts, etc. */ - GL3_ShutdownWindow(false); + GL3_ShutdownContext(); } static void @@ -1575,7 +1566,7 @@ GL3_Clear(void) } /* stencilbuffer shadows */ - if (gl_shadows->value && have_stencil) + if (gl_shadows->value && gl3config.stencil) { glClearStencil(1); glClear(GL_STENCIL_BUFFER_BIT); @@ -1678,10 +1669,10 @@ GL3_BeginFrame(float camera_separation) gl_anisotropic->modified = false; } - if(r_vsync->modified) + if (r_vsync->modified) { r_vsync->modified = false; - GL3_SetSwapInterval(); + GL3_SetVsync(); } /* clear screen if desired */ @@ -1733,7 +1724,7 @@ GetRefAPI(refimport_t imp) re.Shutdown = GL3_Shutdown; re.PrepareForWindow = GL3_PrepareForWindow; re.InitContext = GL3_InitContext; - re.ShutdownWindow = GL3_ShutdownWindow; + re.ShutdownContext = GL3_ShutdownContext; re.IsVSyncActive = GL3_IsVsyncActive; re.BeginRegistration = GL3_BeginRegistration; diff --git a/src/client/refresh/gl3/gl3_mesh.c b/src/client/refresh/gl3/gl3_mesh.c index edad09bc..0fc1653a 100644 --- a/src/client/refresh/gl3/gl3_mesh.c +++ b/src/client/refresh/gl3/gl3_mesh.c @@ -44,8 +44,6 @@ static float r_avertexnormal_dots[SHADEDOT_QUANT][256] = { typedef float vec4_t[4]; static vec4_t s_lerped[MAX_VERTS]; extern vec3_t lightspot; -extern qboolean have_stencil; - typedef struct gl3_shadowinfo_s { vec3_t lightspot; @@ -920,8 +918,7 @@ GL3_DrawAliasModel(entity_t *entity) glDepthRange(gl3depthmin, gl3depthmax); } - if (gl_shadows->value && - !(entity->flags & (RF_TRANSLUCENT | RF_WEAPONMODEL | RF_NOSHADOW))) + if (gl_shadows->value && gl3config.stencil && !(entity->flags & (RF_TRANSLUCENT | RF_WEAPONMODEL | RF_NOSHADOW))) { gl3_shadowinfo_t si = {0}; VectorCopy(lightspot, si.lightspot); @@ -951,7 +948,8 @@ void GL3_DrawAliasShadows(void) glEnable(GL_BLEND); GL3_UseProgram(gl3state.si3DaliasColor.shaderProgram); - if (have_stencil) + + if (gl3config.stencil) { glEnable(GL_STENCIL_TEST); glStencilFunc(GL_EQUAL, 1, 2); @@ -974,7 +972,7 @@ void GL3_DrawAliasShadows(void) DrawAliasShadow(si); } - if (have_stencil) + if (gl3config.stencil) { glDisable(GL_STENCIL_TEST); } diff --git a/src/client/refresh/gl3/gl3_sdl.c b/src/client/refresh/gl3/gl3_sdl.c index cbadf8e7..3096dee6 100644 --- a/src/client/refresh/gl3/gl3_sdl.c +++ b/src/client/refresh/gl3/gl3_sdl.c @@ -20,14 +20,13 @@ * * ======================================================================= * - * SDL-specific refresher things, for OpenGL3 - * Also all glad (or whatever OpenGL loader I end up using) specific things - * (I'd like to keep the OpenGL loader easily exchangable if possible) + * SDL backend for the GL3 renderer. Everything that needs to be on the + * renderer side of thing. Also all glad (or whatever OpenGL loader I + * end up using) specific things. * * ======================================================================= */ - #include "header/local.h" #include @@ -36,45 +35,169 @@ static SDL_Window* window = NULL; static SDL_GLContext context = NULL; static qboolean vsyncActive = false; -qboolean have_stencil = false; +// -------- -// called by GLimp_InitGraphics() before creating window, -// returns flags for SDL window creation, -1 on error -int GL3_PrepareForWindow(void) +enum { + // Not all GL.h header know about GL_DEBUG_SEVERITY_NOTIFICATION_*. + QGL_DEBUG_SEVERITY_NOTIFICATION = 0x826B +}; + +/* + * Callback function for debug output. + */ +static void APIENTRY +DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, + const GLchar *message, const void *userParam) { - int msaa_samples = 0; + const char* sourceStr = "Source: Unknown"; + const char* typeStr = "Type: Unknown"; + const char* severityStr = "Severity: Unknown"; - if(SDL_GL_LoadLibrary(NULL) < 0) // Default OpenGL is fine. + switch (severity) { - // TODO: is there a better way? - ri.Sys_Error(ERR_FATAL, "Couldn't load libGL: %s!", SDL_GetError()); + case QGL_DEBUG_SEVERITY_NOTIFICATION: + return; - return -1; + case GL_DEBUG_SEVERITY_HIGH_ARB: severityStr = "Severity: High"; break; + case GL_DEBUG_SEVERITY_MEDIUM_ARB: severityStr = "Severity: Medium"; break; + case GL_DEBUG_SEVERITY_LOW_ARB: severityStr = "Severity: Low"; break; } + switch (source) + { +#define SRCCASE(X) case GL_DEBUG_SOURCE_ ## X ## _ARB: sourceStr = "Source: " #X; break; + SRCCASE(API); + SRCCASE(WINDOW_SYSTEM); + SRCCASE(SHADER_COMPILER); + SRCCASE(THIRD_PARTY); + SRCCASE(APPLICATION); + SRCCASE(OTHER); +#undef SRCCASE + } + + switch(type) + { +#define TYPECASE(X) case GL_DEBUG_TYPE_ ## X ## _ARB: typeStr = "Type: " #X; break; + TYPECASE(ERROR); + TYPECASE(DEPRECATED_BEHAVIOR); + TYPECASE(UNDEFINED_BEHAVIOR); + TYPECASE(PORTABILITY); + TYPECASE(PERFORMANCE); + TYPECASE(OTHER); +#undef TYPECASE + } + + // use PRINT_ALL - this is only called with gl3_debugcontext != 0 anyway. + R_Printf(PRINT_ALL, "GLDBG %s %s %s: %s\n", sourceStr, typeStr, severityStr, message); +} + +// --------- + +/* + * Swaps the buffers and shows the next frame. + */ +void GL3_EndFrame(void) +{ + SDL_GL_SwapWindow(window); +} + +/* + * Returns whether the vsync is enabled. + */ +qboolean GL3_IsVsyncActive(void) +{ + return vsyncActive; +} + +/* + * Enables or disabes the vsync. + */ +void GL3_SetVsync(void) +{ + SDL_GL_SetSwapInterval(r_vsync->value ? 1 : 0); + vsyncActive = SDL_GL_GetSwapInterval() != 0; +} + +/* + * This function returns the flags used at the SDL window + * creation by GLimp_InitGraphics(). In case of error -1 + * is returned. + */ +int GL3_PrepareForWindow(void) +{ + // Mkay, let's try to load the libGL, + const char *libgl; + cvar_t *gl3_libgl = ri.Cvar_Get("gl3_libgl", "", CVAR_ARCHIVE); + + if (strlen(gl3_libgl->string) == 0) + { + libgl = NULL; + } + else + { + libgl = gl3_libgl->string; + } + + while (1) + { + if (SDL_GL_LoadLibrary(libgl) < 0) + { + if (libgl == NULL) + { + ri.Sys_Error(ERR_FATAL, "Couldn't load libGL: %s!", SDL_GetError()); + + return -1; + } + else + { + R_Printf(PRINT_ALL, "Couldn't load libGL: %s!\n", SDL_GetError()); + R_Printf(PRINT_ALL, "Retrying with default...\n"); + + ri.Cvar_Set("gl3_libgl", ""); + libgl = NULL; + } + } + else + { + break; + } + } + + // Set GL context attributs bound to the window. 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_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); + + if (SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8) < 0) + { + gl3config.stencil = true; + } + else + { + gl3config.stencil = false; + } SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + // Set GL context flags. int contextFlags = SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG; - if(gl3_debugcontext && gl3_debugcontext->value) + if (gl3_debugcontext && gl3_debugcontext->value) { contextFlags |= SDL_GL_CONTEXT_DEBUG_FLAG; } - if(contextFlags != 0) + + if (contextFlags != 0) { SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, contextFlags); } - gl3config.compat_profile = false; + // Let's see if the driver supports MSAA. + int msaa_samples = 0; if (gl_msaa_samples->value) { @@ -108,77 +231,23 @@ int GL3_PrepareForWindow(void) return SDL_WINDOW_OPENGL; } -enum { - // for some reason my driver calls the DebugCallback with the following severity - // even though I think it shouldn't for the extension I'm using? - // anyway, my gl headers don't know GL_DEBUG_SEVERITY_NOTIFICATION_* so I define it here - QGL_DEBUG_SEVERITY_NOTIFICATION = 0x826B -}; - -static void APIENTRY -DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, - const GLchar *message, const void *userParam) -{ - const char* sourceStr = "Source: Unknown"; - const char* typeStr = "Type: Unknown"; - const char* severityStr = "Severity: Unknown"; - - switch(severity) - { - case QGL_DEBUG_SEVERITY_NOTIFICATION: - // severityStr = "Severity: Note"; break; - return; // ignore these - - case GL_DEBUG_SEVERITY_HIGH_ARB: severityStr = "Severity: High"; break; - case GL_DEBUG_SEVERITY_MEDIUM_ARB: severityStr = "Severity: Medium"; break; - case GL_DEBUG_SEVERITY_LOW_ARB: severityStr = "Severity: Low"; break; - } - - switch(source) - { -#define SRCCASE(X) case GL_DEBUG_SOURCE_ ## X ## _ARB: sourceStr = "Source: " #X; break; - - SRCCASE(API); - SRCCASE(WINDOW_SYSTEM); - SRCCASE(SHADER_COMPILER); - SRCCASE(THIRD_PARTY); - SRCCASE(APPLICATION); - SRCCASE(OTHER); - -#undef SRCCASE - } - - switch(type) - { -#define TYPECASE(X) case GL_DEBUG_TYPE_ ## X ## _ARB: typeStr = "Type: " #X; break; - - TYPECASE(ERROR); - TYPECASE(DEPRECATED_BEHAVIOR); - TYPECASE(UNDEFINED_BEHAVIOR); - TYPECASE(PORTABILITY); - TYPECASE(PERFORMANCE); - TYPECASE(OTHER); - -#undef TYPECASE - } - - // use PRINT_ALL - this is only called with gl3_debugcontext != 0 anyway. - R_Printf(PRINT_ALL, "GLDBG %s %s %s: %s\n", sourceStr, typeStr, severityStr, message); -} - +/* + * Initializes the OpenGL context. Returns true at + * success and false at failure. + */ int GL3_InitContext(void* win) { - int msaa_samples = 0, stencil_bits = 0; - char title[40] = {0}; - - if(win == NULL) + // Coders are stupid. + if (win == NULL) { ri.Sys_Error(ERR_FATAL, "R_InitContext() must not be called with NULL argument!"); return false; } - window = (SDL_Window*)win; + window = (SDL_Window *)win; + + // Initialize GL context. context = SDL_GL_CreateContext(window); if(context == NULL) @@ -190,6 +259,9 @@ int GL3_InitContext(void* win) return false; } + // Check if we've got the requested MSAA. + int msaa_samples = 0; + if (gl_msaa_samples->value) { if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &msaa_samples) == 0) @@ -198,21 +270,22 @@ int GL3_InitContext(void* win) } } - /* For SDL2, this must be done after creating the window */ - GL3_SetSwapInterval(); + // Check if we've got 8 stencil bits + int stencil_bits = 0; - /* Initialize the stencil buffer */ - if (SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &stencil_bits) == 0) + if (gl3config.stencil) { - R_Printf(PRINT_ALL, "Got %d bits of stencil.\n", stencil_bits); - - if (stencil_bits >= 1) + if (SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &stencil_bits) != 8) { - have_stencil = true; + gl3config.stencil = false; } } - if(!gladLoadGLLoader(SDL_GL_GetProcAddress)) + // Enable vsync if requested. + GL3_SetVsync(); + + // Load GL pointrs through GLAD and check context. + if( !gladLoadGLLoader(SDL_GL_GetProcAddress)) { R_Printf(PRINT_ALL, "GL3_InitContext(): ERROR: loading OpenGL function pointers failed!\n"); @@ -235,48 +308,29 @@ int GL3_InitContext(void* win) gl3config.major_version = GLVersion.major; gl3config.minor_version = GLVersion.minor; - if(gl3_debugcontext && gl3_debugcontext->value && gl3config.debug_output) + // Debug context setup. + if (gl3_debugcontext && gl3_debugcontext->value && gl3config.debug_output) { glDebugMessageCallbackARB(DebugCallback, NULL); - // call GL3_DebugCallback() synchronously, i.e. directly when and where the error happens - // (so we can get the cause in a backtrace) - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); // TODO: only do this if gl3_debugcontext->value >= 2 ? - // TODO: the following line could control verboseness (in that case we'd get all the low prio messages) - // glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, true); + // Call GL3_DebugCallback() synchronously, i.e. directly when and + // where the error happens (so we can get the cause in a backtrace) + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); } - /* Window title - set here so we can display renderer name in it */ + // Window title - set here so we can display renderer name in it. + char title[40] = {0}; + snprintf(title, sizeof(title), "Yamagi Quake II %s - OpenGL 3.2", YQ2VERSION); SDL_SetWindowTitle(window, title); return true; } -void GL3_SetSwapInterval(void) -{ - /* Set vsync - TODO: -1 could be set for "late swap tearing" */ - SDL_GL_SetSwapInterval(r_vsync->value ? 1 : 0); - vsyncActive = SDL_GL_GetSwapInterval() != 0; -} - -qboolean GL3_IsVsyncActive(void) -{ - return vsyncActive; -} - /* - * Swaps the buffers to show the new frame + * Shuts the GL context down. */ -void GL3_EndFrame(void) -{ - SDL_GL_SwapWindow(window); -} - -/* - * Shuts the SDL render backend down - */ -void GL3_ShutdownWindow(qboolean contextOnly) +void GL3_ShutdownContext() { if (window) { @@ -285,12 +339,5 @@ void GL3_ShutdownWindow(qboolean contextOnly) SDL_GL_DeleteContext(context); context = NULL; } - - if (!contextOnly) - { - ri.GLimp_ShutdownGraphics(); - - window = NULL; - } } } diff --git a/src/client/refresh/gl3/header/local.h b/src/client/refresh/gl3/header/local.h index 8bc43efa..a94e8a3d 100644 --- a/src/client/refresh/gl3/header/local.h +++ b/src/client/refresh/gl3/header/local.h @@ -96,16 +96,15 @@ typedef struct const char *vendor_string; const char *version_string; const char *glsl_version_string; - //const char *extensions_string; deprecated in GL3 int major_version; int minor_version; - qboolean compat_profile; // ---- qboolean anisotropic; // is GL_EXT_texture_filter_anisotropic supported? qboolean debug_output; // is GL_ARB_debug_output supported? + qboolean stencil; // Do we have a stencil buffer? // ---- @@ -355,14 +354,12 @@ extern qboolean GL3_CullBox(vec3_t mins, vec3_t maxs); extern void GL3_RotateForEntity(entity_t *e); // gl3_sdl.c -extern qboolean have_stencil; - -extern int GL3_PrepareForWindow(void); extern int GL3_InitContext(void* win); -extern void GL3_SetSwapInterval(void); +extern int GL3_PrepareForWindow(void); extern qboolean GL3_IsVsyncActive(void); extern void GL3_EndFrame(void); -extern void GL3_ShutdownWindow(qboolean contextOnly); +extern void GL3_SetVsync(void); +extern void GL3_ShutdownContext(void); // gl3_misc.c extern void GL3_InitParticleTexture(void);