Skip to content

Commit

Permalink
sdl_glimp,tr_init: rewrite the original GL selection code, improve gf…
Browse files Browse the repository at this point in the history
…xinfo

This commit squashes multiple commits by illwieckz and slipher.

See #478

Co-authored-by: Thomas “illwieckz” Debesse <[email protected]>
Co-authored-by: slipher <[email protected]>

== squashed commits by illwieckz

:: sdl_glimp: rewrite the original GL selection code

- Detect best configuration possible.
- Try custom configuration if exists.
- If no custom configuration or if it fails,
  load the recommended configuration if
  possible (OpenGL 3.2 core) or the best
  one available.
- Reuse window and context when possible.
- Display meaningful popup telling user
  OpenGL version is too low or required
  extensions are missing when that happens.
- Rely on more return codes for GLimp_SetMode().
- Test for negative SDL_Init return value,
  not just -1.

:: sdl_glimp,tr_init: do not test all OpenGL versions unless r_glExtendedValidation is set

When r_glExtendedValidation is enabled, the engine
tests if OpenGL versions higher than 3.2 core
are supported for logging and diagnostic purpose,
but still requestes 3.2 core anyway. Some drivers
may provide more than 3.2 when requesting 3.2, this
is not our fault.

:: sdl_glimp,tr_init: rewrite logging, improve gfxinfo

- Move GL query for logging purpose from tr_init to sdl_glimp.
- Do not split MODE log message.
- Unify some log.
- Add more debug log when building GL extension list.
- Also increase the extensions_string length to not
  truncate the string, 4096 is not enough, there can
  be more than 6000 characters on an OpenGL 4.6 driver.
- Also log missing extensions to make gfxinfo more useful.
- Rewrite gfxinfo in more useful way.
- List enabled and missing GL extensions.

:: sdl_glimp: silence the GL error when querying if context
is core on non-core implementation

- Silence the error that may happen when querying if the
  OpenGL context uses core profile when core profile is not
  supported by the OpenGL implementation to begin with.

For example this may happen on implementations not supporting
higher than OpenGL 2.1, while forcing OpenGL 2.1 on
implementations supporting higher versions including
core profiles may not raise an error.

:: sdl_glimp: make GLimp_StartDriverAndSetMode only return true on RSERR_OK

- Only return true on OK, don't return true on unknown errors.

:: sdl_glimp: catch errors from GLimp_DetectAvailableModes to prevent further segfault

It may be possible to create a valid context that is unusable.

For example the 3840×2160 resolution is too large for the
Radeon 9700 and the Mesa r300 driver may print this error
when the requested resolution is higher than what is supported
by hardware:

> r300: Implementation error: Render targets are too big in r300_set_framebuffer_state, refusing to bind framebuffer state!

It will unfortunately return a valid but unusable context that will
make the engine segfault when calling GL_SetDefaultState().

:: sdl_glimp: flag fullscreen window as borderless when borderless is enabled

Flag fullscreen window as borderless when borderless is enabled
otherwise the window will be bordered when leaving fullscreen
while the borderless option would be enabled.

:: sdl_glimp,tr_init: remove unused depthBits

:: sdl_glimp: remove SDL_INIT_NOPARACHUTE

In GLimp_StartDriverAndSetMod() the SDL_INIT_NOPARACHUTE flag was
removed from SDL_Init( SDL_INIT_VIDEO ) as this flag is now
ignored, see https://wiki.libsdl.org/SDL_Init

== squashed commits by slipher

:: Better type safety in GL detection code

:: Simplify GL_ValidateBestContext duplicate loop

:: GLimp_SetMode - simplify error handling

:: Rework GL initialization

Have GLimp_ValidateBestContext() validate both the highest-numbered
available context (if r_glExtendedValidation is enabled), and the
highest context that we actually want to use (at most 3.2). This means
most of the code in GLimp_ApplyPreferredOptions can be removed because
it was duplicating the knowledge about version preferences and the code
for instantiating them in GLimp_ValidateBestContext.

:: Also cut down on other code duplication.

:: Remove dead cvar r_stencilBits

:: Fix glConfig.colorBits logging

- show actual not requested
- don't log it twice at notice level
  • Loading branch information
illwieckz committed Jun 4, 2021
1 parent b15aa4e commit d242de2
Show file tree
Hide file tree
Showing 7 changed files with 1,026 additions and 301 deletions.
6 changes: 4 additions & 2 deletions src/engine/client/cl_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2662,7 +2662,7 @@ void CL_StartHunkUsers()
if ( !cls.rendererStarted )
{
CL_ShutdownRef();
Sys::Error( "Couldn't load a renderer" );
Sys::Error( "Couldn't load a renderer." );
}

if ( !Audio::Init() ) {
Expand Down Expand Up @@ -3023,7 +3023,9 @@ void CL_Shutdown()

recursive = false;

memset( &cls, 0, sizeof( cls ) );
// do not leak.
cls.~clientStatic_t();
new(&cls) clientStatic_t{};

Log::Debug( "-----------------------" );

Expand Down
21 changes: 6 additions & 15 deletions src/engine/renderer/tr_cmds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -773,21 +773,12 @@ void RE_BeginFrame()
// do overdraw measurement
if ( r_measureOverdraw->integer )
{
if ( glConfig.stencilBits < 4 )
{
Log::Warn("not enough stencil bits to measure overdraw: %d", glConfig.stencilBits );
ri.Cvar_Set( "r_measureOverdraw", "0" );
}
else
{
R_SyncRenderThread();
glEnable( GL_STENCIL_TEST );
glStencilMask( ~0U );
GL_ClearStencil( 0U );
glStencilFunc( GL_ALWAYS, 0U, ~0U );
glStencilOp( GL_KEEP, GL_INCR, GL_INCR );
}

R_SyncRenderThread();
glEnable( GL_STENCIL_TEST );
glStencilMask( ~0U );
GL_ClearStencil( 0U );
glStencilFunc( GL_ALWAYS, 0U, ~0U );
glStencilOp( GL_KEEP, GL_INCR, GL_INCR );
r_measureOverdraw->modified = false;
}
else
Expand Down
135 changes: 86 additions & 49 deletions src/engine/renderer/tr_init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
cvar_t *r_glDebugProfile;
cvar_t *r_glDebugMode;
cvar_t *r_glAllowSoftware;
cvar_t *r_glExtendedValidation;

cvar_t *r_verbose;
cvar_t *r_ignore;
Expand Down Expand Up @@ -101,7 +102,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
cvar_t *r_checkGLErrors;
cvar_t *r_logFile;

cvar_t *r_stencilbits;
cvar_t *r_depthbits;
cvar_t *r_colorbits;
cvar_t *r_alphabits;
Expand Down Expand Up @@ -801,11 +801,7 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p
GLimp_LogComment( "--- GL_SetDefaultState ---\n" );

GL_ClearDepth( 1.0f );

if ( glConfig.stencilBits >= 4 )
{
GL_ClearStencil( 0 );
}
GL_ClearStencil( 0 );

GL_FrontFace( GL_CCW );
GL_CullFace( GL_FRONT );
Expand Down Expand Up @@ -905,108 +901,150 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p
Log::Notice("GL_VENDOR: %s", glConfig.vendor_string );
Log::Notice("GL_RENDERER: %s", glConfig.renderer_string );
Log::Notice("GL_VERSION: %s", glConfig.version_string );
Log::Debug("GL_EXTENSIONS: %s", glConfig.extensions_string );
Log::Debug("GL_MAX_TEXTURE_SIZE: %d", glConfig.maxTextureSize );
Log::Debug("GL_EXTENSIONS: %s", glConfig2.glExtensionsString );
Log::Notice("GL_MAX_TEXTURE_SIZE: %d", glConfig.maxTextureSize );

Log::Notice("GL_SHADING_LANGUAGE_VERSION: %s", glConfig2.shadingLanguageVersionString );

Log::Notice("GL_MAX_VERTEX_UNIFORM_COMPONENTS %d", glConfig2.maxVertexUniforms );
Log::Debug("GL_MAX_VERTEX_ATTRIBS %d", glConfig2.maxVertexAttribs );
Log::Notice("GL_MAX_VERTEX_ATTRIBS %d", glConfig2.maxVertexAttribs );

if ( glConfig2.occlusionQueryAvailable )
{
Log::Debug("%d occlusion query bits", glConfig2.occlusionQueryBits );
Log::Notice("Occlusion query bits: %d", glConfig2.occlusionQueryBits );
}

if ( glConfig2.drawBuffersAvailable )
{
Log::Debug("GL_MAX_DRAW_BUFFERS: %d", glConfig2.maxDrawBuffers );
Log::Notice("GL_MAX_DRAW_BUFFERS: %d", glConfig2.maxDrawBuffers );
}

if ( glConfig2.textureAnisotropyAvailable )
{
Log::Debug("GL_TEXTURE_MAX_ANISOTROPY_EXT: %f", glConfig2.maxTextureAnisotropy );
Log::Notice("GL_TEXTURE_MAX_ANISOTROPY_EXT: %f", glConfig2.maxTextureAnisotropy );
}

Log::Debug("GL_MAX_RENDERBUFFER_SIZE: %d", glConfig2.maxRenderbufferSize );
Log::Debug("GL_MAX_COLOR_ATTACHMENTS: %d", glConfig2.maxColorAttachments );
Log::Notice("GL_MAX_RENDERBUFFER_SIZE: %d", glConfig2.maxRenderbufferSize );
Log::Notice("GL_MAX_COLOR_ATTACHMENTS: %d", glConfig2.maxColorAttachments );

Log::Notice("PIXELFORMAT: color(%d-bits)", glConfig.colorBits );

{
std::string out;
if ( glConfig.displayFrequency )
{
out = Str::Format("%d", glConfig.displayFrequency );
}
else
{
out = "N/A";
}

Log::Debug("\nPIXELFORMAT: color(%d-bits) Z(%d-bit) stencil(%d-bits)", glConfig.colorBits,
glConfig.depthBits, glConfig.stencilBits );
Log::Debug("MODE: %d, %d x %d %s hz:", r_mode->integer, glConfig.vidWidth, glConfig.vidHeight,
fsstrings[ r_fullscreen->integer == 1 ] );
Log::Notice("MODE: %d, %d x %d %s hz: %s",
r_mode->integer,
glConfig.vidWidth, glConfig.vidHeight,
fsstrings[ r_fullscreen->integer == 1 ],
out
);
}

if ( glConfig.displayFrequency )
if ( !!r_glExtendedValidation->integer )
{
Log::Debug("%d", glConfig.displayFrequency );
Log::Notice("Using OpenGL version %d.%d, requested: %d.%d, highest: %d.%d",
glConfig2.glMajor, glConfig2.glMinor, glConfig2.glRequestedMajor, glConfig2.glRequestedMinor,
glConfig2.glHighestMajor, glConfig2.glHighestMinor );
}
else
{
Log::Debug("N/A" );
Log::Notice("Using OpenGL version %d.%d, requested: %d.%d", glConfig2.glMajor, glConfig2.glMinor, glConfig2.glRequestedMajor, glConfig2.glRequestedMinor );
}

Log::Debug("texturemode: %s", r_textureMode->string );
Log::Debug("picmip: %d", r_picMip->integer );
Log::Debug("imageMaxDimension: %d", r_imageMaxDimension->integer );
Log::Debug("ignoreMaterialMinDimension: %d", r_ignoreMaterialMinDimension->integer );
Log::Debug("ignoreMaterialMaxDimension: %d", r_ignoreMaterialMaxDimension->integer );
Log::Debug("replaceMaterialMinDimensionIfPresentWithMaxDimension: %d", r_replaceMaterialMinDimensionIfPresentWithMaxDimension->integer );

if ( glConfig.driverType == glDriverType_t::GLDRV_OPENGL3 )
{
int contextFlags, profile;

Log::Notice("%sUsing OpenGL 3.x context", Color::ToString( Color::Green ) );
Log::Notice("%sUsing OpenGL 3.x context.", Color::ToString( Color::Green ) );

// check if we have a core-profile
glGetIntegerv( GL_CONTEXT_PROFILE_MASK, &profile );
/* See https://www.khronos.org/opengl/wiki/OpenGL_Context
for information about core, compatibility and forward context. */

if ( profile == GL_CONTEXT_CORE_PROFILE_BIT )
if ( glConfig2.glCoreProfile )
{
Log::Debug("%sHaving a core profile", Color::ToString( Color::Green ) );
Log::Notice("%sUsing an OpenGL core profile.", Color::ToString( Color::Green ) );
}
else
{
Log::Debug("%sHaving a compatibility profile", Color::ToString( Color::Red ) );
Log::Notice("%sUsing an OpenGL compatibility profile.", Color::ToString( Color::Red ) );
}

// check if context is forward compatible
glGetIntegerv( GL_CONTEXT_FLAGS, &contextFlags );

if ( contextFlags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT )
if ( glConfig2.glForwardCompatibleContext )
{
Log::Debug("%sContext is forward compatible", Color::ToString( Color::Green ) );
Log::Notice("OpenGL 3.x context is forward compatible.");
}
else
{
Log::Debug("%sContext is NOT forward compatible", Color::ToString( Color::Red ));
Log::Notice("OpenGL 3.x context is not forward compatible.");
}
}
else
{
Log::Notice("%sUsing OpenGL 2.x context.", Color::ToString( Color::Red ) );
}

if ( glConfig2.glEnabledExtensionsString.length() != 0 )
{
Log::Notice("%sUsing OpenGL extensions: %s", Color::ToString( Color::Green ), glConfig2.glEnabledExtensionsString );
}

if ( glConfig2.glMissingExtensionsString.length() != 0 )
{
Log::Notice("%sMissing OpenGL extensions: %s", Color::ToString( Color::Red ), glConfig2.glMissingExtensionsString );
}

if ( glConfig.hardwareType == glHardwareType_t::GLHW_R300 )
{
Log::Debug("HACK: ATI R300 approximations" );
Log::Notice("%sUsing ATI R300 approximations.", Color::ToString( Color::Red ));
}

if ( glConfig.textureCompression != textureCompression_t::TC_NONE )
{
Log::Debug("Using S3TC (DXTC) texture compression" );
Log::Notice("%sUsing S3TC (DXTC) texture compression.", Color::ToString( Color::Green ) );
}

if ( glConfig2.vboVertexSkinningAvailable )
{
Log::Notice("Using GPU vertex skinning with max %i bones in a single pass", glConfig2.maxVertexSkinningBones );
/* Mesa drivers usually support 256 bones, Nvidia proprietary drivers
usually support 233 bones, OpenGL 2.1 hardware usually supports no more
than 41 bones which may not be enough to use hardware acceleration on
models from games like Unvanquished. */
if ( glConfig2.maxVertexSkinningBones < 233 )
{
Log::Notice("%sUsing GPU vertex skinning with max %i bones in a single pass, some models may not be hardware accelerated.", Color::ToString( Color::Red ), glConfig2.maxVertexSkinningBones );
}
else
{
Log::Notice("%sUsing GPU vertex skinning with max %i bones in a single pass, models are hardware accelerated.", Color::ToString( Color::Green ), glConfig2.maxVertexSkinningBones );
}
}
else
{
Log::Notice("%sMissing GPU vertex skinning, models are not hardware-accelerated.", Color::ToString( Color::Red ) );
}

if ( glConfig.smpActive )
{
Log::Debug("Using dual processor acceleration" );
Log::Notice("Using dual processor acceleration." );
}

if ( r_finish->integer )
{
Log::Debug("Forcing glFinish" );
Log::Notice("Forcing glFinish." );
}

Log::Debug("texturemode: %s", r_textureMode->string );
Log::Debug("picmip: %d", r_picMip->integer );
Log::Debug("imageMaxDimension: %d", r_imageMaxDimension->integer );
Log::Debug("ignoreMaterialMinDimension: %d", r_ignoreMaterialMinDimension->integer );
Log::Debug("ignoreMaterialMaxDimension: %d", r_ignoreMaterialMaxDimension->integer );
Log::Debug("replaceMaterialMinDimensionIfPresentWithMaxDimension: %d", r_replaceMaterialMinDimensionIfPresentWithMaxDimension->integer );
}

static void GLSL_restart_f()
Expand All @@ -1032,6 +1070,7 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p
r_glDebugProfile = ri.Cvar_Get( "r_glDebugProfile", "", CVAR_LATCH );
r_glDebugMode = ri.Cvar_Get( "r_glDebugMode", "0", CVAR_CHEAT );
r_glAllowSoftware = ri.Cvar_Get( "r_glAllowSoftware", "0", CVAR_LATCH );
r_glExtendedValidation = ri.Cvar_Get( "r_glExtendedValidation", "0", CVAR_LATCH );

// latched and archived variables
r_ext_occlusion_query = ri.Cvar_Get( "r_ext_occlusion_query", "1", CVAR_CHEAT | CVAR_LATCH );
Expand Down Expand Up @@ -1059,7 +1098,6 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p
r_colorMipLevels = ri.Cvar_Get( "r_colorMipLevels", "0", CVAR_LATCH );
r_colorbits = ri.Cvar_Get( "r_colorbits", "0", CVAR_LATCH );
r_alphabits = ri.Cvar_Get( "r_alphabits", "0", CVAR_LATCH );
r_stencilbits = ri.Cvar_Get( "r_stencilbits", "8", CVAR_LATCH );
r_depthbits = ri.Cvar_Get( "r_depthbits", "0", CVAR_LATCH );
r_ext_multisample = ri.Cvar_Get( "r_ext_multisample", "0", CVAR_LATCH | CVAR_ARCHIVE );
r_mode = ri.Cvar_Get( "r_mode", "-2", CVAR_LATCH | CVAR_ARCHIVE );
Expand Down Expand Up @@ -1428,7 +1466,6 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p

// print info
GfxInfo_f();
GL_CheckErrors();

Log::Debug("----- finished R_Init -----" );

Expand Down
2 changes: 1 addition & 1 deletion src/engine/renderer/tr_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -2811,6 +2811,7 @@ static inline void halfToFloat( const f16vec4_t in, vec4_t out )
extern cvar_t *r_glDebugProfile;
extern cvar_t *r_glDebugMode;
extern cvar_t *r_glAllowSoftware;
extern cvar_t *r_glExtendedValidation;

extern cvar_t *r_ignore; // used for debugging anything
extern cvar_t *r_verbose; // used for verbose debug spew
Expand All @@ -2820,7 +2821,6 @@ static inline void halfToFloat( const f16vec4_t in, vec4_t out )
extern cvar_t *r_znear; // near Z clip plane
extern cvar_t *r_zfar;

extern cvar_t *r_stencilbits; // number of desired stencil bits
extern cvar_t *r_depthbits; // number of desired depth bits
extern cvar_t *r_colorbits; // number of desired color bits, only relevant for fullscreen
extern cvar_t *r_alphabits; // number of desired depth bits
Expand Down
15 changes: 15 additions & 0 deletions src/engine/renderer/tr_public.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,29 @@ Maryland 20850 USA.
#define __TR_PUBLIC_H

#include "tr_types.h"
#include <string>

#define REF_API_VERSION 10

struct glconfig2_t
{
bool textureCompressionRGTCAvailable;

int glHighestMajor;
int glHighestMinor;

int glRequestedMajor;
int glRequestedMinor;

int glMajor;
int glMinor;

bool glCoreProfile;
bool glForwardCompatibleContext;

std::string glExtensionsString;
std::string glEnabledExtensionsString;
std::string glMissingExtensionsString;

int maxCubeMapTextureSize;

Expand Down
16 changes: 13 additions & 3 deletions src/engine/renderer/tr_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -335,12 +335,22 @@ struct glconfig_t
char renderer_string[ MAX_STRING_CHARS ];
char vendor_string[ MAX_STRING_CHARS ];
char version_string[ MAX_STRING_CHARS ];
char extensions_string[ MAX_STRING_CHARS * 4 ]; // TTimo - bumping, some cards have a big extension string

// TODO(0.53): Delete, moved to glconfig2_t.
char extensions_string[ MAX_STRING_CHARS * 4 ]; // TTimo - bumping, some cards have a big extension string

int maxTextureSize; // queried from GL
int unused;

int colorBits, depthBits, stencilBits;
// TODO(0.53): Delete, unused.
int unused;

int colorBits;

// TODO(0.53): Delete, unused.
int stencilBits;

// TODO(0.53): Delete, unused.
int depthBits;

glDriverType_t driverType;
glHardwareType_t hardwareType;
Expand Down
Loading

0 comments on commit d242de2

Please sign in to comment.