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

:: 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.

Request the best configuration possible
so engine gfxinfo command tells the user
what is supported by his hardware and driver
even if the engine needs less.

:: 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: do not test all OpenGL versions unless r_glExtendedValidation is set
  • Loading branch information
illwieckz committed Dec 30, 2021
1 parent a1d7a45 commit 0c067a3
Show file tree
Hide file tree
Showing 6 changed files with 1,154 additions and 264 deletions.
2 changes: 1 addition & 1 deletion src/engine/client/cl_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2666,7 +2666,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
125 changes: 83 additions & 42 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 @@ -905,108 +906,148 @@ 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::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("PIXELFORMAT: color(%d-bits) Z(%d-bit) stencil(%d-bits)", glConfig.colorBits, glConfig.depthBits, glConfig.stencilBits );

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

Log::Notice("MODE: %d, %d x %d %s hz: %s",
r_mode->integer,
glConfig.vidWidth, glConfig.vidHeight,
fsstrings[ r_fullscreen->integer == 1 ],
out
);
}

if ( !!r_glExtendedValidation->integer )
{
Log::Notice("Using OpenGL version %d.%d, requested: %d.%d, best: %d.%d", glConfig2.glMajor, glConfig2.glMinor, glConfig2.glRequestedMajor, glConfig2.glRequestedMinor, glConfig2.glBestMajor, glConfig2.glBestMinor );
}
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("%sOpenGL 3.x context is forward compatible.", Color::ToString( Color::Green ) );
}
else
{
Log::Debug("%sContext is NOT forward compatible", Color::ToString( Color::Red ));
Log::Notice("%sOpenGL 3.x context is not forward compatible.", Color::ToString( Color::Red ));
}
}
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 +1073,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 @@ -1428,7 +1470,6 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p

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

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

Expand Down
1 change: 1 addition & 0 deletions 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 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 glBestMajor;
int glBestMinor;

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
2 changes: 2 additions & 0 deletions src/engine/renderer/tr_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@ struct glconfig_t
char renderer_string[ MAX_STRING_CHARS ];
char vendor_string[ MAX_STRING_CHARS ];
char version_string[ MAX_STRING_CHARS ];

// DELETEME: delete when breaking ABI (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
Expand Down
Loading

0 comments on commit 0c067a3

Please sign in to comment.