Repository: DaemonEngine/Daemon
Pull request #1608: renderer: rewrite `GLimp_LogComment()` calls
Author: login: illwieckz
Labels: name: T-Improvement
description: Improvement for an existing feature
name: A-Renderer
name: T-Cleanup
name: A-UI
Created: 2025-03-17T23:30:44Z | Merged: 2025-03-24T14:50:56Z

Rewrite `GLimp_LogComment()` calls.

Also don't require an ending `\n` on every call.

Also only call `GLimp_LogComment()` when the function doesn't return early.

No more noisy:

```c++
if ( r_logFile->integer )
{
	GLimp_LogComment( va( "bla: %d\n", bla ) );
}

if ( condition )
{
	return;
}
```

Just this:

```c++
if ( condition )
{
	return;
}

GLIMP_LOGCOMMENT( "bla: %d", bla );
```

_Edit:_ `GLIMP_LOGCOMMENT()` is a macro wrapping both the `if ( r_logFile->integer )` test and a `Str::Format()` call.


Diff:
diff --git a/src/engine/renderer/Material.cpp b/src/engine/renderer/Material.cpp
index 89202ca0c0..1a7bfb3799 100644
--- a/src/engine/renderer/Material.cpp
+++ b/src/engine/renderer/Material.cpp
@@ -908,10 +908,8 @@ void BindShaderLightMapping( Material* material ) {
 
 		const float interpolation = 1.0 - trilerp[0];
 
-		if ( r_logFile->integer ) {
-			GLimp_LogComment( va( "Probe 0 distance = %f, probe 1 distance = %f, interpolation = %f\n",
-				Distance( position, probes[0]->origin ), Distance( position, probes[1]->origin ), interpolation ) );
-		}
+		GLIMP_LOGCOMMENT( "Probe 0 distance = %f, probe 1 distance = %f, interpolation = %f",
+			Distance( position, probes[0]->origin ), Distance( position, probes[1]->origin ), interpolation );
 
 		// bind u_EnvironmentMap0
 		gl_lightMappingShaderMaterial->SetUniform_EnvironmentMap0Bindless(
diff --git a/src/engine/renderer/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp
index 57d36c0d7b..91de1bfee2 100644
--- a/src/engine/renderer/gl_shader.cpp
+++ b/src/engine/renderer/gl_shader.cpp
@@ -2351,13 +2351,14 @@ void GLShader::BindProgram( int deformIndex ) {
 
 	currentProgram = &shaderPrograms[index];
 
-	if ( r_logFile->integer ) {
+	if ( GLimp_isLogging() )
+	{
 		std::string macros;
 
 		GetCompileMacrosString( index, macros, GLCompileMacro::VERTEX | GLCompileMacro::FRAGMENT );
 
-		auto msg = Str::Format( "--- GL_BindProgram( name = '%s', macros = '%s' ) ---\n", this->GetName(), macros );
-		GLimp_LogComment( msg.c_str() );
+		GLIMP_LOGCOMMENT( "--- GL_BindProgram( name = '%s', macros = '%s' ) ---",
+			this->GetName(), macros );
 	}
 
 	GL_BindProgram( &shaderPrograms[index] );
diff --git a/src/engine/renderer/gl_shader.h b/src/engine/renderer/gl_shader.h
index 69f40115cf..8243f09df0 100644
--- a/src/engine/renderer/gl_shader.h
+++ b/src/engine/renderer/gl_shader.h
@@ -26,7 +26,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include "tr_local.h"
 #include <stdexcept>
 
-#define LOG_GLSL_UNIFORMS 1
 #define USE_UNIFORM_FIREWALL 1
 
 // *INDENT-OFF*
@@ -684,14 +683,6 @@ class GLUniform1i : protected GLUniform
 			ASSERT_EQ( p, glState.currentProgram );
 		}
 
-#if defined( LOG_GLSL_UNIFORMS )
-		if ( r_logFile->integer )
-		{
-			GLimp_LogComment( va( "GLSL_SetUniform1i( %s, shader: %s, value: %d ) ---\n",
-				this->GetName(), _shader->GetName().c_str(), value ) );
-		}
-#endif
-
 		if ( _shader->UseMaterialSystem() && !_global ) {
 			currentValue = value;
 			return;
@@ -737,13 +728,6 @@ class GLUniform1ui : protected GLUniform {
 			ASSERT_EQ( p, glState.currentProgram );
 		}
 
-#if defined( LOG_GLSL_UNIFORMS )
-		if ( r_logFile->integer ) {
-			GLimp_LogComment( va( "GLSL_SetUniform1i( %s, shader: %s, value: %d ) ---\n",
-				this->GetName(), _shader->GetName().c_str(), value ) );
-		}
-#endif
-
 		if ( _shader->UseMaterialSystem() && !_global ) {
 			currentValue = value;
 			return;
@@ -788,13 +772,6 @@ class GLUniform1Bool : protected GLUniform {
 			ASSERT_EQ( p, glState.currentProgram );
 		}
 
-#if defined( LOG_GLSL_UNIFORMS )
-		if ( r_logFile->integer ) {
-			GLimp_LogComment( va( "GLSL_SetUniform1i( %s, shader: %s, value: %d ) ---\n",
-				this->GetName(), _shader->GetName().c_str(), value ) );
-		}
-#endif
-
 		if ( _shader->UseMaterialSystem() && !_global ) {
 			currentValue = value;
 			return;
@@ -842,14 +819,6 @@ class GLUniform1f : protected GLUniform
 			ASSERT_EQ( p, glState.currentProgram );
 		}
 
-#if defined( LOG_GLSL_UNIFORMS )
-		if ( r_logFile->integer )
-		{
-			GLimp_LogComment( va( "GLSL_SetUniform1f( %s, shader: %s, value: %f ) ---\n",
-				this->GetName(), _shader->GetName().c_str(), value ) );
-		}
-#endif
-
 		if ( _shader->UseMaterialSystem() && !_global ) {
 			currentValue = value;
 			return;
@@ -899,14 +868,6 @@ class GLUniform1fv : protected GLUniform
 			ASSERT_EQ( p, glState.currentProgram );
 		}
 
-#if defined( LOG_GLSL_UNIFORMS )
-		if ( r_logFile->integer )
-		{
-			GLimp_LogComment( va( "GLSL_SetUniform1fv( %s, shader: %s, numFloats: %d ) ---\n",
-				this->GetName(), _shader->GetName().c_str(), numFloats ) );
-		}
-#endif
-
 		if ( _shader->UseMaterialSystem() && !_global ) {
 			memcpy( currentValue.data(), f, numFloats * sizeof( float ) );
 			return;
@@ -942,14 +903,6 @@ class GLUniform2f : protected GLUniform
 			ASSERT_EQ( p, glState.currentProgram );
 		}
 
-#if defined( LOG_GLSL_UNIFORMS )
-		if ( r_logFile->integer )
-		{
-			GLimp_LogComment( va( "GLSL_SetUniform2f( %s, shader: %s, value: [ %f, %f ] ) ---\n",
-				this->GetName(), _shader->GetName().c_str(), v[ 0 ], v[ 1 ] ) );
-		}
-#endif
-
 		if ( _shader->UseMaterialSystem() && !_global ) {
 			Vector2Copy( v, currentValue );
 			return;
@@ -1002,14 +955,6 @@ class GLUniform3f : protected GLUniform
 			ASSERT_EQ( p, glState.currentProgram );
 		}
 
-#if defined( LOG_GLSL_UNIFORMS )
-		if ( r_logFile->integer )
-		{
-			GLimp_LogComment( va( "GLSL_SetUniform3f( %s, shader: %s, value: [ %f, %f, %f ] ) ---\n",
-				this->GetName(), _shader->GetName().c_str(), v[ 0 ], v[ 1 ], v[ 2 ] ) );
-		}
-#endif
-
 		if ( _shader->UseMaterialSystem() && !_global ) {
 			VectorCopy( v, currentValue );
 			return;
@@ -1062,14 +1007,6 @@ class GLUniform4f : protected GLUniform
 			ASSERT_EQ( p, glState.currentProgram );
 		}
 
-#if defined( LOG_GLSL_UNIFORMS )
-		if ( r_logFile->integer )
-		{
-			GLimp_LogComment( va( "GLSL_SetUniform4f( %s, shader: %s, value: [ %f, %f, %f, %f ] ) ---\n",
-				this->GetName(), _shader->GetName().c_str(), v[ 0 ], v[ 1 ], v[ 2 ], v[ 3 ] ) );
-		}
-#endif
-
 		if ( _shader->UseMaterialSystem() && !_global ) {
 			Vector4Copy( v, currentValue );
 			return;
@@ -1119,14 +1056,6 @@ class GLUniform4fv : protected GLUniform
 			ASSERT_EQ( p, glState.currentProgram );
 		}
 
-#if defined( LOG_GLSL_UNIFORMS )
-		if ( r_logFile->integer )
-		{
-			GLimp_LogComment( va( "GLSL_SetUniform4fv( %s, shader: %s, numV: %d ) ---\n",
-				this->GetName(), _shader->GetName().c_str(), numV ) );
-		}
-#endif
-
 		if ( _shader->UseMaterialSystem() && !_global ) {
 			memcpy( currentValue.data(), v, numV * sizeof( vec4_t ) );
 			return;
@@ -1162,16 +1091,6 @@ class GLUniformMatrix4f : protected GLUniform
 			ASSERT_EQ( p, glState.currentProgram );
 		}
 
-#if defined( LOG_GLSL_UNIFORMS )
-		if ( r_logFile->integer )
-		{
-			GLimp_LogComment( va( "GLSL_SetUniformMatrix4f( %s, shader: %s, transpose: %d, [ %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f ] ) ---\n",
-				this->GetName(), _shader->GetName().c_str(), transpose,
-				m[ 0 ], m[ 1 ], m[ 2 ], m[ 3 ], m[ 4 ], m[ 5 ], m[ 6 ], m[ 7 ], m[ 8 ], m[ 9 ], m[ 10 ], m[ 11 ], m[ 12 ],
-				m[ 13 ], m[ 14 ], m[ 15 ] ) );
-		}
-#endif
-
 		if ( _shader->UseMaterialSystem() && !_global ) {
 			MatrixCopy( m, currentValue );
 			return;
@@ -1217,14 +1136,6 @@ class GLUniformMatrix32f : protected GLUniform {
 			ASSERT_EQ( p, glState.currentProgram );
 		}
 
-#if defined( LOG_GLSL_UNIFORMS )
-		if ( r_logFile->integer ) {
-			GLimp_LogComment( va( "GLSL_SetUniformMatrix32f( %s, shader: %s, transpose: %d, [ %f, %f, %f, %f, %f, %f ] ) ---\n",
-				this->GetName(), _shader->GetName().c_str(), transpose,
-				m[0], m[1], m[2], m[3], m[4], m[5] ) );
-		}
-#endif
-
 		if ( _shader->UseMaterialSystem() && !_global ) {
 			memcpy( currentValue, m, 6 * sizeof( float ) );
 			return;
@@ -1263,14 +1174,6 @@ class GLUniformMatrix4fv : protected GLUniform
 			ASSERT_EQ( p, glState.currentProgram );
 		}
 
-#if defined( LOG_GLSL_UNIFORMS )
-		if ( r_logFile->integer )
-		{
-			GLimp_LogComment( va( "GLSL_SetUniformMatrix4fv( %s, shader: %s, numMatrices: %d, transpose: %d ) ---\n",
-				this->GetName(), _shader->GetName().c_str(), numMatrices, transpose ) );
-		}
-#endif
-
 		if ( _shader->UseMaterialSystem() && !_global ) {
 			memcpy( currentValue.data(), m, numMatrices * sizeof( matrix_t ) );
 			return;
@@ -1305,14 +1208,6 @@ class GLUniformMatrix34fv : protected GLUniform
 			ASSERT_EQ( p, glState.currentProgram );
 		}
 
-#if defined( LOG_GLSL_UNIFORMS )
-		if ( r_logFile->integer )
-		{
-			GLimp_LogComment( va( "GLSL_SetUniformMatrix34fv( %s, shader: %s, numMatrices: %d, transpose: %d ) ---\n",
-				this->GetName(), _shader->GetName().c_str(), numMatrices, transpose ) );
-		}
-#endif
-
 		if ( _shader->UseMaterialSystem() && !_global ) {
 			memcpy( currentValue.data(), m, numMatrices * sizeof( matrix_t ) );
 			return;
@@ -3786,13 +3681,9 @@ class u_ColorModulateColorGen_Float :
 		const bool vertexOverbright = false,
 		const bool useMapLightFactor = false )
 	{
-		if ( r_logFile->integer ) {
-			GLimp_LogComment(
-				va( "--- u_ColorModulate::SetUniform_ColorModulateColorGen_Float( "
-					"program = %s, colorGen = %s, alphaGen = %s ) ---\n",
-					_shader->GetName().c_str(), Util::enum_str( colorGen ), Util::enum_str( alphaGen ) )
-			);
-		}
+		GLIMP_LOGCOMMENT( "--- u_ColorModulate::SetUniform_ColorModulateColorGen_Float( "
+			"program = %s, colorGen = %s, alphaGen = %s ) ---",
+			_shader->GetName().c_str(), Util::enum_str( colorGen ), Util::enum_str( alphaGen ) );
 
 		colorModulation_t colorModulation = ColorModulateColorGen(
 			colorGen, alphaGen, vertexOverbright, useMapLightFactor );
@@ -3821,13 +3712,9 @@ class u_ColorModulateColorGen_Uint :
 		const bool vertexOverbright = false,
 		const bool useMapLightFactor = false )
 	{
-		if ( r_logFile->integer ) {
-			GLimp_LogComment(
-				va( "--- u_ColorModulate::SetUniform_ColorModulateColorGen_Uint( "
-					"program = %s, colorGen = %s, alphaGen = %s ) ---\n",
-					_shader->GetName().c_str(), Util::enum_str( colorGen ), Util::enum_str( alphaGen ) )
-			);
-		}
+		GLIMP_LOGCOMMENT( "--- u_ColorModulate::SetUniform_ColorModulateColorGen_Uint( "
+			"program = %s, colorGen = %s, alphaGen = %s ) ---",
+			_shader->GetName().c_str(), Util::enum_str( colorGen ), Util::enum_str( alphaGen ) );
 
 		colorModulation_t colorModulation = ColorModulateColorGen(
 			colorGen, alphaGen, vertexOverbright, useMapLightFactor );
diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp
index e30e76be71..d7c091bac5 100644
--- a/src/engine/renderer/tr_backend.cpp
+++ b/src/engine/renderer/tr_backend.cpp
@@ -46,11 +46,7 @@ void GL_Bind( image_t *image )
 	}
 	else
 	{
-		if ( r_logFile->integer )
-		{
-			// don't just call LogComment, or we will get a call to va() every frame!
-			GLimp_LogComment( va( "--- GL_Bind( %s ) ---\n", image->name ) );
-		}
+		GLIMP_LOGCOMMENT( "--- GL_Bind( %s ) ---", image->name );
 	}
 
 	texnum = image->texnum;
@@ -76,7 +72,7 @@ void GL_Bind( image_t *image )
 
 void GL_Unbind( image_t *image )
 {
-	GLimp_LogComment( "--- GL_Unbind() ---\n" );
+	GLIMP_LOGCOMMENT( "--- GL_Unbind() ---" );
 
 	tr.currenttextures[ glState.currenttmu ] = 0;
 	glBindTexture( image->type, 0 );
@@ -137,10 +133,7 @@ void GL_BindProgram( ShaderProgramDescriptor* program )
 
 void GL_BindNullProgram()
 {
-	if ( r_logFile->integer )
-	{
-		GLimp_LogComment( "--- GL_BindNullProgram ---\n" );
-	}
+	GLIMP_LOGCOMMENT( "--- GL_BindNullProgram ---" );
 
 	if ( glState.currentProgram )
 	{
@@ -159,11 +152,6 @@ void GL_SelectTexture( int unit )
 	if ( unit >= 0 && unit < glConfig2.maxTextureUnits )
 	{
 		glActiveTexture( GL_TEXTURE0 + unit );
-
-		if ( r_logFile->integer )
-		{
-			GLimp_LogComment( va( "glActiveTexture( GL_TEXTURE%i )\n", unit ) );
-		}
 	}
 	else
 	{
@@ -650,25 +638,13 @@ void GL_VertexAttribsState( uint32_t stateBits )
 		{
 			if ( ( stateBits & bit ) )
 			{
-				if ( r_logFile->integer )
-				{
-					static char buf[ MAX_STRING_CHARS ];
-					Q_snprintf( buf, sizeof( buf ), "glEnableVertexAttribArray( %s )\n", attributeNames[ i ] );
-
-					GLimp_LogComment( buf );
-				}
+				GLIMP_LOGCOMMENT( "glEnableVertexAttribArray( %s )", attributeNames[ i ] );
 
 				glEnableVertexAttribArray( i );
 			}
 			else
 			{
-				if ( r_logFile->integer )
-				{
-					static char buf[ MAX_STRING_CHARS ];
-					Q_snprintf( buf, sizeof( buf ), "glDisableVertexAttribArray( %s )\n", attributeNames[ i ] );
-
-					GLimp_LogComment( buf );
-				}
+				GLIMP_LOGCOMMENT( "glDisableVertexAttribArray( %s )", attributeNames[ i ] );
 
 				glDisableVertexAttribArray( i );
 			}
@@ -687,11 +663,7 @@ void GL_VertexAttribPointers( uint32_t attribBits )
 		Sys::Error( "GL_VertexAttribPointers: no VBO bound" );
 	}
 
-	if ( r_logFile->integer )
-	{
-		// don't just call LogComment, or we will get a call to va() every frame!
-		GLimp_LogComment( va( "--- GL_VertexAttribPointers( %s ) ---\n", glState.currentVBO->name ) );
-	}
+	GLIMP_LOGCOMMENT( "--- GL_VertexAttribPointers( %s ) ---", glState.currentVBO->name );
 
 	if ( glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning )
 	{
@@ -715,13 +687,7 @@ void GL_VertexAttribPointers( uint32_t attribBits )
 		{
 			const vboAttributeLayout_t *layout = &glState.currentVBO->attribs[ i ];
 
-			if ( r_logFile->integer )
-			{
-				static char buf[ MAX_STRING_CHARS ];
-				Q_snprintf( buf, sizeof( buf ), "glVertexAttribPointer( %s )\n", attributeNames[ i ] );
-
-				GLimp_LogComment( buf );
-			}
+			GLIMP_LOGCOMMENT( "glVertexAttribPointer( %s )", attributeNames[ i ] );
 
 			if ( ( ATTR_INTERP_BITS & bit ) && glState.vertexAttribsInterpolation > 0 )
 			{
@@ -811,7 +777,7 @@ static void RB_SetGL2D()
 {
 	matrix_t proj;
 
-	GLimp_LogComment( "--- RB_SetGL2D ---\n" );
+	GLIMP_LOGCOMMENT( "--- RB_SetGL2D ---" );
 
 	// disable offscreen rendering
 	R_BindNullFBO();
@@ -877,7 +843,7 @@ static void RB_RenderDrawSurfaces( shaderSort_t fromSort, shaderSort_t toSort,
 	drawSurf_t    *drawSurf;
 	int           lastSurf;
 
-	GLimp_LogComment( "--- RB_RenderDrawSurfaces ---\n" );
+	GLIMP_LOGCOMMENT( "--- RB_RenderDrawSurfaces ---" );
 
 	// draw everything
 	oldEntity = nullptr;
@@ -1236,7 +1202,7 @@ static void RB_RenderInteractions()
 	surfaceType_t *surface;
 	int           startTime = 0, endTime = 0;
 
-	GLimp_LogComment( "--- RB_RenderInteractions ---\n" );
+	GLIMP_LOGCOMMENT( "--- RB_RenderInteractions ---" );
 
 	if ( r_speeds->integer == Util::ordinal(renderSpeeds_t::RSPEEDS_SHADING_TIMES))
 	{
@@ -1278,7 +1244,7 @@ static void RB_RenderInteractions()
 				continue;
 			}
 
-			GLimp_LogComment( "----- Rendering new light -----\n" );
+			GLIMP_LOGCOMMENT( "----- Rendering new light -----" );
 
 			// Tr3B: this should never happen in the first iteration
 			if ( entity == oldEntity && shader == oldShader )
@@ -1396,12 +1362,7 @@ static void RB_SetupLightForShadowing( trRefLight_t *light, int index,
 				vec3_t   angles;
 				matrix_t rotationMatrix, transformMatrix, viewMatrix;
 
-				if ( r_logFile->integer )
-				{
-					// don't just call LogComment, or we will get
-					// a call to va() every frame!
-					GLimp_LogComment( va( "----- Rendering shadowCube side: %i -----\n", cubeSide ) );
-				}
+				GLIMP_LOGCOMMENT( "----- Rendering shadowCube side: %i -----", cubeSide );
 
 				R_BindFBO( tr.shadowMapFBO[ light->shadowLOD ] );
 				if( shadowClip )
@@ -1523,7 +1484,7 @@ static void RB_SetupLightForShadowing( trRefLight_t *light, int index,
 
 		case refLightType_t::RL_PROJ:
 			{
-				GLimp_LogComment( "--- Rendering projective shadowMap ---\n" );
+				GLIMP_LOGCOMMENT( "--- Rendering projective shadowMap ---" );
 
 				R_BindFBO( tr.shadowMapFBO[ light->shadowLOD ] );
 				if( shadowClip )
@@ -1570,7 +1531,7 @@ static void RB_SetupLightForShadowing( trRefLight_t *light, int index,
 				vec4_t   point;
 				vec4_t   transf;
 
-				GLimp_LogComment( "--- Rendering directional shadowMap ---\n" );
+				GLIMP_LOGCOMMENT( "--- Rendering directional shadowMap ---" );
 
 				R_BindFBO( tr.sunShadowMapFBO[ splitFrustumIndex ] );
 
@@ -1633,7 +1594,7 @@ static void RB_SetupLightForShadowing( trRefLight_t *light, int index,
 					R_CalcFrustumNearCorners( splitFrustum, splitFrustumNearCorners );
 					R_CalcFrustumFarCorners( splitFrustum, splitFrustumFarCorners );
 
-					if ( r_logFile->integer )
+					if ( GLimp_isLogging() )
 					{
 						vec3_t rayIntersectionNear, rayIntersectionFar;
 						float  zNear, zFar;
@@ -1648,19 +1609,23 @@ static void RB_SetupLightForShadowing( trRefLight_t *light, int index,
 
 						VectorInverse( viewDirection );
 
-						GLimp_LogComment( va( "split frustum %i: near = %5.3f, far = %5.3f\n", splitFrustumIndex, zNear, zFar ) );
-						GLimp_LogComment( va( "pyramid nearCorners\n" ) );
+						GLIMP_LOGCOMMENT( "split frustum %i: near = %5.3f, far = %5.3f",
+							splitFrustumIndex, zNear, zFar );
+
+						GLIMP_LOGCOMMENT( "pyramid nearCorners" );
 
 						for ( auto nearCorner : splitFrustumNearCorners )
 						{
-							GLimp_LogComment( va( "(%5.3f, %5.3f, %5.3f)\n", nearCorner[ 0 ], nearCorner[ 1 ], nearCorner[ 2 ] ) );
+							GLIMP_LOGCOMMENT( "(%5.3f, %5.3f, %5.3f)",
+								nearCorner[ 0 ], nearCorner[ 1 ], nearCorner[ 2 ] );
 						}
 
-						GLimp_LogComment( va( "pyramid farCorners\n" ) );
+						GLIMP_LOGCOMMENT( "pyramid farCorners" );
 
 						for ( auto farCorner : splitFrustumFarCorners )
 						{
-							GLimp_LogComment( va( "(%5.3f, %5.3f, %5.3f)\n", farCorner[ 0 ], farCorner[ 1 ], farCorner[ 2 ] ) );
+							GLIMP_LOGCOMMENT( "(%5.3f, %5.3f, %5.3f)",
+								farCorner[ 0 ], farCorner[ 1 ], farCorner[ 2 ] );
 						}
 					}
 
@@ -1736,21 +1701,21 @@ static void RB_SetupLightForShadowing( trRefLight_t *light, int index,
 						pointsToViewProjectionBounds( farCorner );
 					}
 
-					if ( r_logFile->integer )
+					if ( GLimp_isLogging() )
 					{
-						GLimp_LogComment( va( "shadow casters = %i\n", numCasters ) );
+						GLIMP_LOGCOMMENT( "shadow casters = %i", numCasters );
 
-						GLimp_LogComment( va( "split frustum light space clip bounds (%5.3f, %5.3f, %5.3f) (%5.3f, %5.3f, %5.3f)\n",
-										        splitFrustumClipBounds[ 0 ][ 0 ], splitFrustumClipBounds[ 0 ][ 1 ], splitFrustumClipBounds[ 0 ][ 2 ],
-										        splitFrustumClipBounds[ 1 ][ 0 ], splitFrustumClipBounds[ 1 ][ 1 ], splitFrustumClipBounds[ 1 ][ 2 ] ) );
+						GLIMP_LOGCOMMENT( "split frustum light space clip bounds (%5.3f, %5.3f, %5.3f) (%5.3f, %5.3f, %5.3f)",
+							splitFrustumClipBounds[ 0 ][ 0 ], splitFrustumClipBounds[ 0 ][ 1 ], splitFrustumClipBounds[ 0 ][ 2 ],
+							splitFrustumClipBounds[ 1 ][ 0 ], splitFrustumClipBounds[ 1 ][ 1 ], splitFrustumClipBounds[ 1 ][ 2 ] );
 
-						GLimp_LogComment( va( "shadow caster light space clip bounds (%5.3f, %5.3f, %5.3f) (%5.3f, %5.3f, %5.3f)\n",
-										        casterBounds[ 0 ][ 0 ], casterBounds[ 0 ][ 1 ], casterBounds[ 0 ][ 2 ],
-										        casterBounds[ 1 ][ 0 ], casterBounds[ 1 ][ 1 ], casterBounds[ 1 ][ 2 ] ) );
+						GLIMP_LOGCOMMENT( "shadow caster light space clip bounds (%5.3f, %5.3f, %5.3f) (%5.3f, %5.3f, %5.3f)",
+							casterBounds[ 0 ][ 0 ], casterBounds[ 0 ][ 1 ], casterBounds[ 0 ][ 2 ],
+							casterBounds[ 1 ][ 0 ], casterBounds[ 1 ][ 1 ], casterBounds[ 1 ][ 2 ] );
 
-						GLimp_LogComment( va( "light receiver light space clip bounds (%5.3f, %5.3f, %5.3f) (%5.3f, %5.3f, %5.3f)\n",
-										        receiverBounds[ 0 ][ 0 ], receiverBounds[ 0 ][ 1 ], receiverBounds[ 0 ][ 2 ],
-										        receiverBounds[ 1 ][ 0 ], receiverBounds[ 1 ][ 1 ], receiverBounds[ 1 ][ 2 ] ) );
+						GLIMP_LOGCOMMENT( "light receiver light space clip bounds (%5.3f, %5.3f, %5.3f) (%5.3f, %5.3f, %5.3f)",
+							receiverBounds[ 0 ][ 0 ], receiverBounds[ 0 ][ 1 ], receiverBounds[ 0 ][ 2 ],
+							receiverBounds[ 1 ][ 0 ], receiverBounds[ 1 ][ 1 ], receiverBounds[ 1 ][ 2 ] );
 					}
 
 					// scene-dependent bounding volume
@@ -1819,24 +1784,16 @@ static void RB_SetupLightForShadowing( trRefLight_t *light, int index,
 			break;
 	}
 
-	if ( r_logFile->integer )
-	{
-		// don't just call LogComment, or we will get
-		// a call to va() every frame!
-		GLimp_LogComment( va( "----- First Shadow Interaction: %i -----\n", (int)( light->firstInteraction - backEnd.viewParms.interactions ) ) );
-	}
+	GLIMP_LOGCOMMENT( "----- First Shadow Interaction: %i -----",
+		(int)( light->firstInteraction - backEnd.viewParms.interactions ) );
 }
 
 static void RB_SetupLightForLighting( trRefLight_t *light )
 {
-	GLimp_LogComment( "--- Rendering lighting ---\n" );
+	GLIMP_LOGCOMMENT( "--- Rendering lighting ---" );
 
-	if ( r_logFile->integer )
-	{
-		// don't just call LogComment, or we will get
-		// a call to va() every frame!
-		GLimp_LogComment( va( "----- First Light Interaction: %i -----\n", (int)( light->firstInteraction - backEnd.viewParms.interactions ) ) );
-	}
+	GLIMP_LOGCOMMENT( "----- First Light Interaction: %i -----",
+		(int)( light->firstInteraction - backEnd.viewParms.interactions ) );
 
 	R_BindFBO( tr.mainFBO[ backEnd.currentMainFBO ] );
 
@@ -2104,7 +2061,7 @@ static void RB_RenderInteractionsShadowMapped()
 
 	DAEMON_ASSERT( glConfig2.shadowMapping );
 
-	GLimp_LogComment( "--- RB_RenderInteractionsShadowMapped ---\n" );
+	GLIMP_LOGCOMMENT( "--- RB_RenderInteractionsShadowMapped ---" );
 
 	if ( r_speeds->integer == Util::ordinal(renderSpeeds_t::RSPEEDS_SHADING_TIMES) )
 	{
@@ -2153,12 +2110,8 @@ static void RB_RenderInteractionsShadowMapped()
 
 			if ( light->l.noShadows || light->shadowLOD < 0 )
 			{
-				if ( r_logFile->integer )
-				{
-					// don't just call LogComment, or we will get
-					// a call to va() every frame!
-					GLimp_LogComment( va( "----- Skipping shadowCube side: %i -----\n", i ) );
-				}
+				GLIMP_LOGCOMMENT( "----- Skipping shadowCube side: %i -----", i );
+
 				continue;
 			}
 
@@ -2215,12 +2168,8 @@ static void RB_RenderInteractionsShadowMapped()
 						{
 							if ( entity == oldEntity && ( alphaTest ? shader == oldShader : alphaTest == oldAlphaTest ) )
 							{
-								if ( r_logFile->integer )
-								{
-									// don't just call LogComment, or we will get
-									// a call to va() every frame!
-									GLimp_LogComment( va( "----- Batching Shadow Interaction: %i -----\n", (int)( ia - backEnd.viewParms.interactions ) ) );
-								}
+								GLIMP_LOGCOMMENT( "----- Batching Shadow Interaction: %i -----",
+									(int)( ia - backEnd.viewParms.interactions ) );
 
 								// fast path, same as previous
 								rb_surfaceTable[ Util::ordinal(*surface) ]( surface );
@@ -2231,12 +2180,8 @@ static void RB_RenderInteractionsShadowMapped()
 								// draw the contents of the last shader batch
 								Tess_End();
 
-								if ( r_logFile->integer )
-								{
-									// don't just call LogComment, or we will get
-									// a call to va() every frame!
-									GLimp_LogComment( va( "----- Beginning Shadow Interaction: %i -----\n", (int)( ia - backEnd.viewParms.interactions ) ) );
-								}
+								GLIMP_LOGCOMMENT( "----- Beginning Shadow Interaction: %i -----",
+									(int)( ia - backEnd.viewParms.interactions ) );
 
 								// we don't need tangent space calculations here
 								Tess_Begin( Tess_StageIteratorShadowFill, shader, light->shader, true, -1, 0 );
@@ -2319,12 +2264,8 @@ static void RB_RenderInteractionsShadowMapped()
 				oldAlphaTest = alphaTest;
 			}
 
-			if ( r_logFile->integer )
-			{
-				// don't just call LogComment, or we will get
-				// a call to va() every frame!
-				GLimp_LogComment( va( "----- Last Interaction: %i -----\n", (int)( iaLast - backEnd.viewParms.interactions ) ) );
-			}
+			GLIMP_LOGCOMMENT( "----- Last Interaction: %i -----",
+				(int)( iaLast - backEnd.viewParms.interactions ) );
 
 			Tess_End();
 
@@ -2337,12 +2278,7 @@ static void RB_RenderInteractionsShadowMapped()
 
 				if ( light->l.noShadows || light->shadowLOD < 0 )
 				{
-					if ( r_logFile->integer )
-					{
-						// don't just call LogComment, or we will get
-						// a call to va() every frame!
-						GLimp_LogComment( va( "----- Skipping shadowCube side: %i -----\n", i ) );
-					}
+					GLIMP_LOGCOMMENT( "----- Skipping shadowCube side: %i -----", i );
 					continue;
 				}
 
@@ -2394,12 +2330,8 @@ static void RB_RenderInteractionsShadowMapped()
 							{
 								if ( entity == oldEntity && ( alphaTest ? shader == oldShader : alphaTest == oldAlphaTest ) )
 								{
-									if ( r_logFile->integer )
-									{
-										// don't just call LogComment, or we will get
-										// a call to va() every frame!
-										GLimp_LogComment( va( "----- Batching Shadow Interaction: %i -----\n", (int)( ia - backEnd.viewParms.interactions ) ) );
-									}
+									GLIMP_LOGCOMMENT( "----- Batching Shadow Interaction: %i -----",
+										(int)( ia - backEnd.viewParms.interactions ) );
 
 									// fast path, same as previous
 									rb_surfaceTable[ Util::ordinal(*surface) ]( surface );
@@ -2410,12 +2342,8 @@ static void RB_RenderInteractionsShadowMapped()
 									// draw the contents of the last shader batch
 									Tess_End();
 
-									if ( r_logFile->integer )
-									{
-										// don't just call LogComment, or we will get
-										// a call to va() every frame!
-										GLimp_LogComment( va( "----- Beginning Shadow Interaction: %i -----\n", (int)( ia - backEnd.viewParms.interactions ) ) );
-									}
+									GLIMP_LOGCOMMENT( "----- Beginning Shadow Interaction: %i -----",
+										(int)( ia - backEnd.viewParms.interactions ) );
 
 									// we don't need tangent space calculations here
 									Tess_Begin( Tess_StageIteratorShadowFill, shader, light->shader, true, -1, 0 );
@@ -2498,12 +2426,8 @@ static void RB_RenderInteractionsShadowMapped()
 					oldAlphaTest = alphaTest;
 				}
 
-				if ( r_logFile->integer )
-				{
-					// don't just call LogComment, or we will get
-					// a call to va() every frame!
-					GLimp_LogComment( va( "----- Last Interaction: %i -----\n", (int)( iaLast - backEnd.viewParms.interactions ) ) );
-				}
+				GLIMP_LOGCOMMENT( "----- Last Interaction: %i -----",
+					(int)( iaLast - backEnd.viewParms.interactions ) );
 
 				Tess_End();
 			}
@@ -2547,12 +2471,8 @@ static void RB_RenderInteractionsShadowMapped()
 
 			if ( entity == oldEntity && shader == oldShader )
 			{
-				if ( r_logFile->integer )
-				{
-					// don't just call LogComment, or we will get
-					// a call to va() every frame!
-					GLimp_LogComment( va( "----- Batching Light Interaction: %i -----\n", (int)( ia - backEnd.viewParms.interactions ) ) );
-				}
+				GLIMP_LOGCOMMENT( "----- Batching Light Interaction: %i -----",
+					(int)( ia - backEnd.viewParms.interactions ) );
 
 				// fast path, same as previous
 				rb_surfaceTable[ Util::ordinal(*surface) ]( surface );
@@ -2563,12 +2483,8 @@ static void RB_RenderInteractionsShadowMapped()
 				// draw the contents of the last shader batch
 				Tess_End();
 
-				if ( r_logFile->integer )
-				{
-					// don't just call LogComment, or we will get
-					// a call to va() every frame!
-					GLimp_LogComment( va( "----- Beginning Light Interaction: %i -----\n", (int)( ia - backEnd.viewParms.interactions ) ) );
-				}
+				GLIMP_LOGCOMMENT( "----- Beginning Light Interaction: %i -----",
+					(int)( ia - backEnd.viewParms.interactions ) );
 
 				// begin a new batch
 				Tess_Begin( Tess_StageIteratorLighting, shader, light->shader, light->l.inverseShadows, -1, 0 );
@@ -2624,12 +2540,8 @@ static void RB_RenderInteractionsShadowMapped()
 			oldAlphaTest = alphaTest;
 		}
 
-		if ( r_logFile->integer )
-		{
-			// don't just call LogComment, or we will get
-			// a call to va() every frame!
-			GLimp_LogComment( va( "----- Last Interaction: %i -----\n", (int)( iaLast - backEnd.viewParms.interactions ) ) );
-		}
+		GLIMP_LOGCOMMENT( "----- Last Interaction: %i -----",
+			(int)( iaLast - backEnd.viewParms.interactions ) );
 
 		Tess_End();
 	}
@@ -2828,13 +2740,13 @@ void RB_RenderPostDepthLightTile()
 	vec3_t zParams;
 	int w, h;
 
-	GLimp_LogComment( "--- RB_RenderPostDepthLightTile ---\n" );
-
 	if ( ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) )
 	{
 		return;
 	}
 
+	GLIMP_LOGCOMMENT( "--- RB_RenderPostDepthLightTile ---" );
+
 	// 1st step
 	GL_State( GLS_DEPTHTEST_DISABLE );
 	GL_Cull( CT_TWO_SIDED );
@@ -2939,8 +2851,6 @@ void RB_RenderPostDepthLightTile()
 
 void RB_RenderGlobalFog()
 {
-	GLimp_LogComment( "--- RB_RenderGlobalFog ---\n" );
-
 	if ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL )
 	{
 		return;
@@ -2956,6 +2866,8 @@ void RB_RenderGlobalFog()
 		return;
 	}
 
+	GLIMP_LOGCOMMENT( "--- RB_RenderGlobalFog ---" );
+
 	GL_Cull( cullType_t::CT_TWO_SIDED );
 
 	gl_fogGlobalShader->BindProgram( 0 );
@@ -2966,10 +2878,7 @@ void RB_RenderGlobalFog()
 	{
 		fog_t* fog = &tr.world->fogs[ tr.world->globalFog ];
 
-		if ( r_logFile->integer )
-		{
-			GLimp_LogComment( va( "--- RB_RenderGlobalFog( fogNum = %i, originalBrushNumber = %i ) ---\n", tr.world->globalFog, fog->originalBrushNumber ) );
-		}
+		GLIMP_LOGCOMMENT( "--- RB_RenderGlobalFog( fogNum = %i ) ---", tr.world->globalFog );
 
 		GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
 
@@ -3009,13 +2918,13 @@ void RB_RenderGlobalFog()
 
 void RB_RenderBloom()
 {
-	GLimp_LogComment( "--- RB_RenderBloom ---\n" );
-
 	if ( ( backEnd.refdef.rdflags & ( RDF_NOWORLDMODEL | RDF_NOBLOOM ) )
 		|| !glConfig2.bloom || backEnd.viewParms.portalLevel > 0 ) {
 		return;
 	}
 
+	GLIMP_LOGCOMMENT( "--- RB_RenderBloom ---" );
+
 	{
 		GL_State( GLS_DEPTHTEST_DISABLE );
 		GL_Cull( cullType_t::CT_TWO_SIDED );
@@ -3096,15 +3005,14 @@ void RB_RenderBloom()
 
 void RB_RenderMotionBlur()
 {
-
-	GLimp_LogComment( "--- RB_RenderMotionBlur ---\n" );
-
 	if ( !glConfig2.motionBlur || ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL )
 		|| backEnd.viewParms.portalLevel > 0 )
 	{
 		return;
 	}
 
+	GLIMP_LOGCOMMENT( "--- RB_RenderMotionBlur ---" );
+
 	GL_State( GLS_DEPTHTEST_DISABLE );
 	GL_Cull( cullType_t::CT_TWO_SIDED );
 
@@ -3130,8 +3038,6 @@ void RB_RenderMotionBlur()
 
 void RB_RenderSSAO()
 {
-	GLimp_LogComment( "--- RB_RenderSSAO ---\n" );
-
 	if ( !glConfig2.ssao )
 	{
 		return;
@@ -3143,6 +3049,8 @@ void RB_RenderSSAO()
 		return;
 	}
 
+	GLIMP_LOGCOMMENT( "--- RB_RenderSSAO ---" );
+
 	GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO );
 	GL_Cull( cullType_t::CT_TWO_SIDED );
 
@@ -3179,20 +3087,18 @@ void RB_RenderSSAO()
 
 void RB_FXAA()
 {
-
-	GLimp_LogComment( "--- RB_FXAA ---\n" );
-
-	if ( ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ||
-	     backEnd.viewParms.portalLevel )
+	if ( !r_FXAA->integer || !gl_fxaaShader )
 	{
 		return;
 	}
 
-	if ( !r_FXAA->integer || !gl_fxaaShader )
+	if ( ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) || backEnd.viewParms.portalLevel )
 	{
 		return;
 	}
 
+	GLIMP_LOGCOMMENT( "--- RB_FXAA ---" );
+
 	GL_State( GLS_DEPTHTEST_DISABLE );
 	GL_Cull( cullType_t::CT_TWO_SIDED );
 
@@ -3241,13 +3147,13 @@ static void ComputeTonemapParams( const float contrast, const float highlightsCo
 }
 
 void RB_CameraPostFX() {
-	GLimp_LogComment( "--- RB_CameraPostFX ---\n" );
-
 	if ( ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ||
 	     backEnd.viewParms.portalLevel > 0 ) {
 		return;
 	}
 
+	GLIMP_LOGCOMMENT( "--- RB_CameraPostFX ---" );
+
 	GL_State( GLS_DEPTHTEST_DISABLE );
 	GL_Cull( cullType_t::CT_TWO_SIDED );
 
@@ -3287,7 +3193,7 @@ void RB_CameraPostFX() {
 
 static void RB_RenderDebugUtils()
 {
-	GLimp_LogComment( "--- RB_RenderDebugUtils ---\n" );
+	GLIMP_LOGCOMMENT( "--- RB_RenderDebugUtils ---" );
 
 	if ( r_showLightTransforms->integer || r_showShadowLod->integer )
 	{
@@ -4049,7 +3955,7 @@ static void RB_RenderDebugUtils()
 		vec_t           length;
 		vec4_t          tetraVerts[ 4 ];
 
-		GLimp_LogComment( "--- r_showLightGrid > 0: Rendering light grid\n" );
+		GLIMP_LOGCOMMENT( "--- r_showLightGrid > 0: Rendering light grid" );
 
 		gl_genericShader->SetVertexSkinning( false );
 		gl_genericShader->SetVertexAnimation( false );
@@ -4539,13 +4445,8 @@ static void RB_RenderView( bool depthPass )
 {
 	int startTime = 0, endTime = 0;
 
-	if ( r_logFile->integer )
-	{
-		// don't just call LogComment, or we will get a call to va() every frame!
-		GLimp_LogComment( va
-		                  ( "--- RB_RenderView( %i surfaces, %i interactions ) ---\n", backEnd.viewParms.numDrawSurfs,
-		                    backEnd.viewParms.numInteractions ) );
-	}
+	GLIMP_LOGCOMMENT( "--- RB_RenderView( %i surfaces, %i interactions ) ---",
+		backEnd.viewParms.numDrawSurfs, backEnd.viewParms.numInteractions );
 
 	GL_CheckErrors();
 
@@ -4766,7 +4667,7 @@ RB_SetColor
 */
 const RenderCommand *SetColorCommand::ExecuteSelf() const
 {
-	GLimp_LogComment( "--- SetColorCommand::ExecuteSelf ---\n" );
+	GLIMP_LOGCOMMENT( "--- SetColorCommand::ExecuteSelf ---" );
 
 	backEnd.color2D = color;
 
@@ -4780,7 +4681,7 @@ RB_SetColorGrading
 */
 const RenderCommand *SetColorGradingCommand::ExecuteSelf( ) const
 {
-	GLimp_LogComment( "--- SetColorGradingCommand::ExecuteSelf ---\n" );
+	GLIMP_LOGCOMMENT( "--- SetColorGradingCommand::ExecuteSelf ---" );
 
 	if( slot < 0 || slot >= REF_COLORGRADE_SLOTS ) {
 		return this + 1;
@@ -4839,7 +4740,7 @@ const RenderCommand *StretchPicCommand::ExecuteSelf( ) const
 {
 	int                       numVerts, numIndexes;
 
-	GLimp_LogComment( "--- StretchPicCommand::ExecuteSelf ---\n" );
+	GLIMP_LOGCOMMENT( "--- StretchPicCommand::ExecuteSelf ---" );
 
 	if ( !backEnd.projection2D )
 	{
@@ -5240,7 +5141,7 @@ const RenderCommand *SetupLightsCommand::ExecuteSelf( ) const
 	int numLights;
 	GLenum bufferTarget = glConfig2.uniformBufferObjectAvailable ? GL_UNIFORM_BUFFER : GL_PIXEL_UNPACK_BUFFER;
 
-	GLimp_LogComment( "--- SetupLightsCommand::ExecuteSelf ---\n" );
+	GLIMP_LOGCOMMENT( "--- SetupLightsCommand::ExecuteSelf ---" );
 
 	if( (numLights = refdef.numLights) > 0 ) {
 		shaderLight_t *buffer;
@@ -5292,7 +5193,7 @@ const RenderCommand *ClearBufferCommand::ExecuteSelf( ) const
 {
 	int clearBits = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
 
-	GLimp_LogComment( "--- ClearBufferCommand::ExecuteSelf ---\n" );
+	GLIMP_LOGCOMMENT( "--- ClearBufferCommand::ExecuteSelf ---" );
 
 	// finish any 2D drawing if needed
 	Tess_End();
@@ -5345,7 +5246,7 @@ RB_PreparePortal
 */
 const RenderCommand *PreparePortalCommand::ExecuteSelf( ) const
 {
-	GLimp_LogComment( "--- PreparePortalCommand::ExecuteSelf ---\n" );
+	GLIMP_LOGCOMMENT( "--- PreparePortalCommand::ExecuteSelf ---" );
 
 	backEnd.refdef = refdef;
 	backEnd.viewParms = viewParms;
@@ -5415,7 +5316,7 @@ RB_FinalisePortal
 */
 const RenderCommand *FinalisePortalCommand::ExecuteSelf( ) const
 {
-	GLimp_LogComment( "--- FinalisePortalCommand::ExecuteSelf ---\n" );
+	GLIMP_LOGCOMMENT( "--- FinalisePortalCommand::ExecuteSelf ---" );
 
 	backEnd.refdef = refdef;
 	backEnd.viewParms = viewParms;
@@ -5478,7 +5379,7 @@ RB_DrawView
 */
 const RenderCommand *DrawViewCommand::ExecuteSelf( ) const
 {
-	GLimp_LogComment( "--- DrawViewCommand::ExecuteSelf ---\n" );
+	GLIMP_LOGCOMMENT( "--- DrawViewCommand::ExecuteSelf ---" );
 
 	// finish any 2D drawing if needed
 	Tess_End();
@@ -5498,7 +5399,7 @@ RB_DrawPostProcess
 */
 const RenderCommand *RenderPostProcessCommand::ExecuteSelf( ) const
 {
-	GLimp_LogComment("--- RenderPostProcessCommand::ExecuteSelf ---\n");
+	GLIMP_LOGCOMMENT( "--- RenderPostProcessCommand::ExecuteSelf ---" );
 
 	// finish any 3D drawing if needed
 	if (tess.numIndexes)
@@ -5521,7 +5422,7 @@ RB_DrawBuffer
 */
 const RenderCommand *DrawBufferCommand::ExecuteSelf( ) const
 {
-	GLimp_LogComment( "--- DrawBufferCommand::ExecuteSelf ---\n" );
+	GLIMP_LOGCOMMENT( "--- DrawBufferCommand::ExecuteSelf ---" );
 
 	GL_DrawBuffer( buffer );
 
@@ -5545,7 +5446,7 @@ void RB_ShowImages()
 	float   x, y, w, h;
 	int     start, end;
 
-	GLimp_LogComment( "--- RB_ShowImages ---\n" );
+	GLIMP_LOGCOMMENT( "--- RB_ShowImages ---" );
 
 	if ( !backEnd.projection2D )
 	{
@@ -5640,8 +5541,6 @@ const RenderCommand *SwapBuffersCommand::ExecuteSelf( ) const
 		RB_ShowImages();
 	}
 
-	GLimp_LogComment( "***************** RB_SwapBuffers *****************\n\n\n" );
-
 	GLimp_EndFrame();
 
 	backEnd.projection2D = false;
@@ -5683,7 +5582,7 @@ void RB_ExecuteRenderCommands( const void *data )
 	const RenderCommand *cmd = (const RenderCommand *)data;
 	int t1, t2;
 
-	GLimp_LogComment( "--- RB_ExecuteRenderCommands ---\n" );
+	GLIMP_LOGCOMMENT( "--- RB_ExecuteRenderCommands ---" );
 
 	t1 = ri.Milliseconds();
 
diff --git a/src/engine/renderer/tr_cmds.cpp b/src/engine/renderer/tr_cmds.cpp
index af042c4002..6701d16acc 100644
--- a/src/engine/renderer/tr_cmds.cpp
+++ b/src/engine/renderer/tr_cmds.cpp
@@ -799,7 +799,7 @@ void RE_BeginFrame()
 		return;
 	}
 
-	GLimp_LogComment( "--- RE_BeginFrame ---\n" );
+	GLIMP_LOGCOMMENT( "--- RE_BeginFrame ---" );
 
 	tr.frameCount++;
 	tr.frameSceneNum = 0;
diff --git a/src/engine/renderer/tr_fbo.cpp b/src/engine/renderer/tr_fbo.cpp
index 45d006e871..28b116c3c4 100644
--- a/src/engine/renderer/tr_fbo.cpp
+++ b/src/engine/renderer/tr_fbo.cpp
@@ -368,11 +368,7 @@ void R_BindFBO( FBO_t *fbo )
 		return;
 	}
 
-	if ( r_logFile->integer )
-	{
-		// don't just call LogComment, or we will get a call to va() every frame!
-		GLimp_LogComment( va( "--- R_BindFBO( %s ) ---\n", fbo->name ) );
-	}
+	GLIMP_LOGCOMMENT( "--- R_BindFBO( %s ) ---", fbo->name );
 
 	if ( glState.currentFBO != fbo )
 	{
@@ -389,10 +385,7 @@ R_BindNullFBO
 */
 void R_BindNullFBO()
 {
-	if ( r_logFile->integer )
-	{
-		GLimp_LogComment( "--- R_BindNullFBO ---\n" );
-	}
+	GLIMP_LOGCOMMENT( "--- R_BindNullFBO ---" );
 
 	if ( glState.currentFBO )
 	{
diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp
index e3c5b7c5a2..4e3cec438c 100644
--- a/src/engine/renderer/tr_init.cpp
+++ b/src/engine/renderer/tr_init.cpp
@@ -123,7 +123,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 		Cvar::NONE, 1, 0, 2);
 
 	cvar_t      *r_checkGLErrors;
-	cvar_t      *r_logFile;
+	Cvar::Cvar<bool> r_logFile( "r_logFile", "Emit GL logs", Cvar::NONE, false );
 
 	cvar_t      *r_colorbits;
 
@@ -865,7 +865,7 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p
 	*/
 	void GL_SetDefaultState()
 	{
-		GLimp_LogComment( "--- GL_SetDefaultState ---\n" );
+		GLIMP_LOGCOMMENT( "--- GL_SetDefaultState ---" );
 
 		glCullFace( GL_FRONT );
 		GL_Cull( CT_TWO_SIDED );
@@ -1290,7 +1290,6 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p
 		r_nocull = Cvar_Get( "r_nocull", "0", CVAR_CHEAT );
 		r_novis = Cvar_Get( "r_novis", "0", CVAR_CHEAT );
 		r_speeds = Cvar_Get( "r_speeds", "0", 0 );
-		r_logFile = Cvar_Get( "r_logFile", "0", CVAR_CHEAT );
 		r_debugSurface = Cvar_Get( "r_debugSurface", "0", CVAR_CHEAT );
 		r_nobind = Cvar_Get( "r_nobind", "0", CVAR_CHEAT );
 		r_offsetFactor = Cvar_Get( "r_offsetFactor", "-1", CVAR_CHEAT );
diff --git a/src/engine/renderer/tr_light.cpp b/src/engine/renderer/tr_light.cpp
index c6fbaf27db..468c8ca7ab 100644
--- a/src/engine/renderer/tr_light.cpp
+++ b/src/engine/renderer/tr_light.cpp
@@ -1465,7 +1465,7 @@ void R_ComputeFinalAttenuation( shaderStage_t *pStage, trRefLight_t *light )
 {
 	matrix_t matrix;
 
-	GLimp_LogComment( "--- R_ComputeFinalAttenuation ---\n" );
+	GLIMP_LOGCOMMENT( "--- R_ComputeFinalAttenuation ---" );
 
 	RB_CalcTexMatrix( &pStage->bundle[ TB_COLORMAP ], matrix );
 
diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h
index 1cebe2e0ff..86ab6954c1 100644
--- a/src/engine/renderer/tr_local.h
+++ b/src/engine/renderer/tr_local.h
@@ -3020,8 +3020,6 @@ enum class ssaoMode {
 
 	extern Cvar::Cvar<bool> r_highPrecisionRendering;
 
-	extern cvar_t *r_logFile; // number of frames to emit GL logs
-
 	extern Cvar::Range<Cvar::Cvar<int>> r_shadows;
 	extern cvar_t *r_softShadows;
 	extern cvar_t *r_softShadowsPP;
@@ -3064,6 +3062,7 @@ enum class ssaoMode {
 	extern cvar_t *r_skipBackEnd;
 
 	extern cvar_t *r_checkGLErrors;
+	extern Cvar::Cvar<bool> r_logFile;
 
 	extern cvar_t *r_debugSurface;
 
@@ -3383,7 +3382,19 @@ inline bool checkGLErrors()
 	void     GLimp_SyncRenderThread();
 	void     GLimp_WakeRenderer( void *data );
 
-	void     GLimp_LogComment( const char *comment );
+inline bool GLimp_isLogging() {
+	return r_logFile.Get() && GLEW_ARB_debug_output;
+}
+
+// Never use GLimp_LogComment_() directly, use the GLIMP_LOGCOMMENT() wrapper instead.
+void GLimp_LogComment_( std::string comment );
+
+#define GLIMP_LOGCOMMENT( ... ) { \
+	if ( GLimp_isLogging() ) \
+	{ \
+		GLimp_LogComment_( Str::Format( __VA_ARGS__ ) ); \
+	} \
+}
 
 	/*
 	====================================================================
diff --git a/src/engine/renderer/tr_scene.cpp b/src/engine/renderer/tr_scene.cpp
index aa02565b4a..207b7b93b1 100644
--- a/src/engine/renderer/tr_scene.cpp
+++ b/src/engine/renderer/tr_scene.cpp
@@ -507,7 +507,7 @@ void RE_RenderScene( const refdef_t *fd )
 		return;
 	}
 
-	GLimp_LogComment( "====== RE_RenderScene =====\n" );
+	GLIMP_LOGCOMMENT( "====== RE_RenderScene =====" );
 
 	if ( r_norefresh->integer )
 	{
diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp
index 5097224612..9ceaef65c6 100644
--- a/src/engine/renderer/tr_shade.cpp
+++ b/src/engine/renderer/tr_shade.cpp
@@ -658,7 +658,7 @@ static void DrawTris()
 {
 	int deform = 0;
 
-	GLimp_LogComment( "--- DrawTris ---\n" );
+	GLIMP_LOGCOMMENT( "--- DrawTris ---" );
 
 	gl_genericShader->SetVertexSkinning( glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning );
 	gl_genericShader->SetVertexAnimation( tess.vboVertexAnimation );
@@ -786,12 +786,10 @@ void Tess_Begin( void ( *stageIteratorFunc )(),
 		Sys::Error( "tess.stageIteratorFunc == NULL" );
 	}
 
-	if ( r_logFile->integer )
-	{
-		// don't just call LogComment, or we will get
-		// a call to va() every frame!
-		GLimp_LogComment( va( "--- Tess_Begin( surfaceShader = %s, lightShader = %s, skipTangents = %i, lightmapNum = %i, fogNum = %i) ---\n", tess.surfaceShader->name, tess.lightShader ? tess.lightShader->name : nullptr, tess.skipTangents, tess.lightmapNum, tess.fogNum ) );
-	}
+	GLIMP_LOGCOMMENT( "--- Tess_Begin( surfaceShader = %s, lightShader = %s, "
+		"skipTangents = %i, lightmapNum = %i, fogNum = %i) ---",
+		tess.surfaceShader->name, tess.lightShader ? tess.lightShader->name : nullptr,
+		tess.skipTangents, tess.lightmapNum, tess.fogNum );
 }
 
 void SetNormalScale( const shaderStage_t *pStage, vec3_t normalScale )
@@ -823,7 +821,7 @@ void Render_NOP( shaderStage_t * )
 
 void Render_generic3D( shaderStage_t *pStage )
 {
-	GLimp_LogComment( "--- Render_generic3D ---\n" );
+	GLIMP_LOGCOMMENT( "--- Render_generic3D ---" );
 
 	GL_State( pStage->stateBits );
 
@@ -946,7 +944,7 @@ void Render_generic( shaderStage_t *pStage )
 
 void Render_lightMapping( shaderStage_t *pStage )
 {
-	GLimp_LogComment( "--- Render_lightMapping ---\n" );
+	GLIMP_LOGCOMMENT( "--- Render_lightMapping ---" );
 
 	lightMode_t lightMode;
 	deluxeMode_t deluxeMode;
@@ -1150,11 +1148,8 @@ void Render_lightMapping( shaderStage_t *pStage )
 
 		const float interpolation = 1.0 - trilerp[0];
 
-		if ( r_logFile->integer )
-		{
-			GLimp_LogComment( va( "Probe 0 distance = %f, probe 1 distance = %f, interpolation = %f\n",
-					Distance( position, probes[0]->origin ), Distance( position, probes[1]->origin ), interpolation ) );
-		}
+		GLIMP_LOGCOMMENT( "Probe 0 distance = %f, probe 1 distance = %f, interpolation = %f",
+			Distance( position, probes[0]->origin ), Distance( position, probes[1]->origin ), interpolation );
 
 		// bind u_EnvironmentMap0
 		gl_lightMappingShader->SetUniform_EnvironmentMap0Bindless(
@@ -1230,7 +1225,7 @@ static void Render_shadowFill( shaderStage_t *pStage )
 {
 	uint32_t      stateBits;
 
-	GLimp_LogComment( "--- Render_shadowFill ---\n" );
+	GLIMP_LOGCOMMENT( "--- Render_shadowFill ---" );
 
 	// remove blend modes
 	stateBits = pStage->stateBits;
@@ -1307,7 +1302,7 @@ static void Render_forwardLighting_DBS_omni( shaderStage_t *pStage,
 	vec3_t     lightOrigin;
 	float      shadowTexelSize;
 
-	GLimp_LogComment( "--- Render_forwardLighting_DBS_omni ---\n" );
+	GLIMP_LOGCOMMENT( "--- Render_forwardLighting_DBS_omni ---" );
 
 	bool shadowCompare = ( glConfig2.shadowMapping && !light->l.noShadows && light->shadowLOD >= 0 );
 
@@ -1482,7 +1477,7 @@ static void Render_forwardLighting_DBS_proj( shaderStage_t *pStage,
 	vec3_t     lightOrigin;
 	float      shadowTexelSize;
 
-	GLimp_LogComment( "--- Render_forwardLighting_DBS_proj ---\n" );
+	GLIMP_LOGCOMMENT( "--- Render_forwardLighting_DBS_proj ---" );
 
 	bool shadowCompare = ( glConfig2.shadowMapping && !light->l.noShadows && light->shadowLOD >= 0 );
 
@@ -1658,7 +1653,7 @@ static void Render_forwardLighting_DBS_directional( shaderStage_t *pStage, trRef
 	vec3_t     lightDirection;
 	float      shadowTexelSize;
 
-	GLimp_LogComment( "--- Render_forwardLighting_DBS_directional ---\n" );
+	GLIMP_LOGCOMMENT( "--- Render_forwardLighting_DBS_directional ---" );
 
 	bool shadowCompare = ( glConfig2.shadowMapping && !light->l.noShadows && light->shadowLOD >= 0 );
 
@@ -1860,7 +1855,7 @@ static void Render_forwardLighting_DBS_directional( shaderStage_t *pStage, trRef
 
 void Render_reflection_CB( shaderStage_t *pStage )
 {
-	GLimp_LogComment( "--- Render_reflection_CB ---\n" );
+	GLIMP_LOGCOMMENT( "--- Render_reflection_CB ---" );
 
 	GL_State( pStage->stateBits );
 
@@ -1951,7 +1946,7 @@ void Render_reflection_CB( shaderStage_t *pStage )
 
 void Render_skybox( shaderStage_t *pStage )
 {
-	GLimp_LogComment( "--- Render_skybox ---\n" );
+	GLIMP_LOGCOMMENT( "--- Render_skybox ---" );
 
 	GL_State( pStage->stateBits );
 
@@ -1976,7 +1971,7 @@ void Render_skybox( shaderStage_t *pStage )
 
 void Render_screen( shaderStage_t *pStage )
 {
-	GLimp_LogComment( "--- Render_screen ---\n" );
+	GLIMP_LOGCOMMENT( "--- Render_screen ---" );
 
 	GL_State( pStage->stateBits );
 
@@ -2001,7 +1996,7 @@ void Render_screen( shaderStage_t *pStage )
 blended to it to fade it with distance. */
 void Render_portal( shaderStage_t *pStage )
 {
-	GLimp_LogComment( "--- Render_portal ---\n" );
+	GLIMP_LOGCOMMENT( "--- Render_portal ---" );
 
 	GL_State( pStage->stateBits );
 
@@ -2031,7 +2026,7 @@ void Render_heatHaze( shaderStage_t *pStage )
 	uint32_t      stateBits;
 	float         deformMagnitude;
 
-	GLimp_LogComment( "--- Render_heatHaze ---\n" );
+	GLIMP_LOGCOMMENT( "--- Render_heatHaze ---" );
 
 	// remove alpha test
 	stateBits = pStage->stateBits;
@@ -2119,7 +2114,7 @@ void Render_liquid( shaderStage_t *pStage )
 	float         fogDensity;
 	vec3_t        fogColor;
 
-	GLimp_LogComment( "--- Render_liquid ---\n" );
+	GLIMP_LOGCOMMENT( "--- Render_liquid ---" );
 
 	// Tr3B: don't allow blend effects
 	GL_State( pStage->stateBits & ~( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS | GLS_DEPTHMASK_TRUE ) );
@@ -2222,10 +2217,8 @@ void Render_fog( shaderStage_t* pStage )
 
 	const fog_t* fog = tr.world->fogs + tess.fogNum;
 
-	if ( r_logFile->integer )
-	{
-		GLimp_LogComment( va( "--- Render_fog( fogNum = %i, originalBrushNumber = %i ) ---\n", tess.fogNum, fog->originalBrushNumber ) );
-	}
+	GLIMP_LOGCOMMENT( "--- Render_fog( fogNum = %i, originalBrushNumber = %i ) ---",
+		tess.fogNum, fog->originalBrushNumber );
 
 	// all fogging distance is based on world Z units
 	vec4_t fogDistanceVector;
@@ -2321,8 +2314,6 @@ void Tess_ComputeColor( shaderStage_t *pStage )
 	float blue;
 	float alpha;
 
-	GLimp_LogComment( "--- Tess_ComputeColor ---\n" );
-
 	// rgbGen
 	switch ( pStage->rgbGen )
 	{
@@ -2554,8 +2545,6 @@ Tess_ComputeTexMatrices
 */
 void Tess_ComputeTexMatrices( shaderStage_t *pStage )
 {
-	GLimp_LogComment( "--- Tess_ComputeTexMatrices ---\n" );
-
 	matrix_t *matrix = tess.svars.texMatrices;
 	matrix_t *lastMatrix = matrix + MAX_TEXTURE_BUNDLES;
 
@@ -2576,13 +2565,8 @@ void Tess_StageIteratorDummy()
 
 void Tess_StageIteratorDebug()
 {
-	// log this call
-	if ( r_logFile->integer )
-	{
-		// don't just call LogComment, or we will get
-		// a call to va() every frame!
-		GLimp_LogComment( va( "--- Tess_StageIteratorDebug( %i vertices, %i triangles ) ---\n", tess.numVertexes, tess.numIndexes / 3 ) );
-	}
+	GLIMP_LOGCOMMENT( "--- Tess_StageIteratorDebug( %i vertices, %i triangles ) ---",
+		tess.numVertexes, tess.numIndexes / 3 );
 
 	GL_CheckErrors();
 
@@ -2603,15 +2587,8 @@ void Tess_StageIteratorDebug()
 
 void Tess_StageIteratorColor()
 {
-	// log this call
-	if ( r_logFile->integer )
-	{
-		// don't just call LogComment, or we will get
-		// a call to va() every frame!
-		GLimp_LogComment( va
-		                  ( "--- Tess_StageIteratorColor( %s, %i vertices, %i triangles ) ---\n", tess.surfaceShader->name,
-		                    tess.numVertexes, tess.numIndexes / 3 ) );
-	}
+	GLIMP_LOGCOMMENT( "--- Tess_StageIteratorColor( %s, %i vertices, %i triangles ) ---",
+		tess.surfaceShader->name, tess.numVertexes, tess.numIndexes / 3 );
 
 	GL_CheckErrors();
 
@@ -2677,14 +2654,8 @@ void Tess_StageIteratorColor()
 }
 
 void Tess_StageIteratorPortal() {
-	// log this call
-	if ( r_logFile->integer ) {
-		// don't just call LogComment, or we will get
-		// a call to va() every frame!
-		GLimp_LogComment( va
-		( "--- Tess_StageIteratorPortal( %s, %i vertices, %i triangles ) ---\n", tess.surfaceShader->name,
-			tess.numVertexes, tess.numIndexes / 3 ) );
-	}
+	GLIMP_LOGCOMMENT( "--- Tess_StageIteratorPortal( %s, %i vertices, %i triangles ) ---",
+		tess.surfaceShader->name, tess.numVertexes, tess.numIndexes / 3 );
 
 	GL_CheckErrors();
 
@@ -2716,15 +2687,8 @@ void Tess_StageIteratorPortal() {
 
 void Tess_StageIteratorShadowFill()
 {
-	// log this call
-	if ( r_logFile->integer )
-	{
-		// don't just call LogComment, or we will get
-		// a call to va() every frame!
-		GLimp_LogComment( va
-		                  ( "--- Tess_StageIteratorShadowFill( %s, %i vertices, %i triangles ) ---\n", tess.surfaceShader->name,
-		                    tess.numVertexes, tess.numIndexes / 3 ) );
-	}
+	GLIMP_LOGCOMMENT( "--- Tess_StageIteratorShadowFill( %s, %i vertices, %i triangles ) ---",
+		tess.surfaceShader->name, tess.numVertexes, tess.numIndexes / 3 );
 
 	GL_CheckErrors();
 
@@ -2775,15 +2739,8 @@ void Tess_StageIteratorLighting()
 {
 	trRefLight_t  *light;
 
-	// log this call
-	if ( r_logFile->integer )
-	{
-		// don't just call LogComment, or we will get
-		// a call to va() every frame!
-		GLimp_LogComment( va
-		                  ( "--- Tess_StageIteratorLighting( %s, %s, %i vertices, %i triangles ) ---\n", tess.surfaceShader->name,
-		                    tess.lightShader->name, tess.numVertexes, tess.numIndexes / 3 ) );
-	}
+	GLIMP_LOGCOMMENT( "--- Tess_StageIteratorLighting( %s, %s, %i vertices, %i triangles ) ---",
+		tess.surfaceShader->name, tess.lightShader->name, tess.numVertexes, tess.numIndexes / 3 );
 
 	GL_CheckErrors();
 
@@ -2958,7 +2915,7 @@ void Tess_End()
 
 	Tess_Clear();
 
-	GLimp_LogComment( "--- Tess_End ---\n" );
+	GLIMP_LOGCOMMENT( "--- Tess_End ---" );
 
 	GL_CheckErrors();
 }
diff --git a/src/engine/renderer/tr_sky.cpp b/src/engine/renderer/tr_sky.cpp
index de1c39eb4f..5a4a42176c 100644
--- a/src/engine/renderer/tr_sky.cpp
+++ b/src/engine/renderer/tr_sky.cpp
@@ -37,15 +37,8 @@ Other things could be stuck in here, like birds in the sky, etc
 */
 void Tess_StageIteratorSky()
 {
-	// log this call
-	if ( r_logFile->integer )
-	{
-		// don't just call LogComment, or we will get
-		// a call to va() every frame!
-		GLimp_LogComment( va
-		                  ( "--- Tess_StageIteratorSky( %s, %i vertices, %i triangles ) ---\n", tess.surfaceShader->name,
-		                    tess.numVertexes, tess.numIndexes / 3 ) );
-	}
+	GLIMP_LOGCOMMENT( "--- Tess_StageIteratorSky( %s, %i vertices, %i triangles ) ---",
+		tess.surfaceShader->name, tess.numVertexes, tess.numIndexes / 3 );
 
 	tr.drawingSky = false;
 
diff --git a/src/engine/renderer/tr_surface.cpp b/src/engine/renderer/tr_surface.cpp
index f8e5f1812c..6f8249ae4f 100644
--- a/src/engine/renderer/tr_surface.cpp
+++ b/src/engine/renderer/tr_surface.cpp
@@ -98,14 +98,8 @@ void Tess_CheckOverflow( int verts, int indexes )
 		return;
 	}
 
-	if ( r_logFile->integer )
-	{
-		// don't just call LogComment, or we will get
-		// a call to va() every frame!
-		GLimp_LogComment( va
-		                  ( "--- Tess_CheckOverflow(%i + %i vertices, %i + %i triangles ) ---\n", tess.numVertexes, verts,
-		                    ( tess.numIndexes / 3 ), indexes ) );
-	}
+	GLIMP_LOGCOMMENT( "--- Tess_CheckOverflow(%i + %i vertices, %i + %i triangles ) ---",
+		tess.numVertexes, verts,( tess.numIndexes / 3 ), indexes );
 
 	Tess_End();
 
@@ -231,7 +225,7 @@ void Tess_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, const Color::C
 	vec3_t normal;
 	int    ndx;
 
-	GLimp_LogComment( "--- Tess_AddQuadStampExt ---\n" );
+	GLIMP_LOGCOMMENT( "--- Tess_AddQuadStampExt ---" );
 
 	Tess_CheckOverflow( 4, 6 );
 
@@ -323,7 +317,7 @@ void Tess_AddQuadStampExt2( vec4_t quadVerts[ 4 ], const Color::Color& color, fl
 	vec3_t normal, tangent, binormal;
 	int    ndx;
 
-	GLimp_LogComment( "--- Tess_AddQuadStampExt2 ---\n" );
+	GLIMP_LOGCOMMENT( "--- Tess_AddQuadStampExt2 ---" );
 
 	Tess_CheckOverflow( 4, 6 );
 
@@ -535,7 +529,7 @@ void Tess_AddCubeWithNormals( const vec3_t position, const vec3_t minSize, const
 }
 
 void Tess_InstantScreenSpaceQuad() {
-	GLimp_LogComment( "--- Tess_InstantScreenSpaceQuad ---\n" );
+	GLIMP_LOGCOMMENT( "--- Tess_InstantScreenSpaceQuad ---" );
 
 	tr.skipVBO = true;
 
@@ -552,7 +546,7 @@ void Tess_InstantScreenSpaceQuad() {
 
 void Tess_InstantQuad( u_ModelViewProjectionMatrix &shader, const float x, const float y, const float width, const float height )
 {
-	GLimp_LogComment( "--- Tess_InstantQuad ---\n" );
+	GLIMP_LOGCOMMENT( "--- Tess_InstantQuad ---" );
 
 	Tess_Begin( Tess_StageIteratorDummy, nullptr, nullptr, true, -1, 0 );
 
@@ -588,7 +582,7 @@ static void Tess_SurfaceSprite()
 	vec3_t delta, left, up;
 	float  radius;
 
-	GLimp_LogComment( "--- Tess_SurfaceSprite ---\n" );
+	GLIMP_LOGCOMMENT( "--- Tess_SurfaceSprite ---" );
 
 	radius = backEnd.currentEntity->e.radius;
 
@@ -651,7 +645,7 @@ static void Tess_SurfacePolychain( srfPoly_t *p )
 {
 	int i;
 
-	GLimp_LogComment( "--- Tess_SurfacePolychain ---\n" );
+	GLIMP_LOGCOMMENT( "--- Tess_SurfacePolychain ---" );
 
 	int numVertexes = p->numVerts;
 	int numIndexes = 3 * (p->numVerts - 2);
@@ -756,7 +750,7 @@ Tess_SurfaceFace
 */
 static void Tess_SurfaceFace( srfSurfaceFace_t *srf )
 {
-	GLimp_LogComment( "--- Tess_SurfaceFace ---\n" );
+	GLIMP_LOGCOMMENT( "--- Tess_SurfaceFace ---" );
 
 	if ( !r_vboFaces->integer || !Tess_SurfaceVBO( srf->vbo, srf->ibo, srf->numTriangles * 3, srf->firstIndex ) )
 	{
@@ -771,7 +765,7 @@ Tess_SurfaceGrid
 */
 static void Tess_SurfaceGrid( srfGridMesh_t *srf )
 {
-	GLimp_LogComment( "--- Tess_SurfaceGrid ---\n" );
+	GLIMP_LOGCOMMENT( "--- Tess_SurfaceGrid ---" );
 
 	if ( !r_vboCurves->integer || !Tess_SurfaceVBO( srf->vbo, srf->ibo, srf->numTriangles * 3, srf->firstIndex ) )
 	{
@@ -786,7 +780,7 @@ Tess_SurfaceTriangles
 */
 static void Tess_SurfaceTriangles( srfTriangles_t *srf )
 {
-	GLimp_LogComment( "--- Tess_SurfaceTriangles ---\n" );
+	GLIMP_LOGCOMMENT( "--- Tess_SurfaceTriangles ---" );
 
 	if ( !r_vboTriangles->integer || !Tess_SurfaceVBO( srf->vbo, srf->ibo, srf->numTriangles * 3, srf->firstIndex ) )
 	{
@@ -815,7 +809,7 @@ static void Tess_SurfaceMDV( mdvSurface_t *srf )
 	float         backlerp;
 	float         oldXyzScale, newXyzScale;
 
-	GLimp_LogComment( "--- Tess_SurfaceMDV ---\n" );
+	GLIMP_LOGCOMMENT( "--- Tess_SurfaceMDV ---" );
 
 	if ( backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame )
 	{
@@ -979,7 +973,7 @@ static void Tess_SurfaceMD5( md5Surface_t *srf )
 {
 	md5Model_t *model = srf->model;
 
-	GLimp_LogComment( "--- Tess_SurfaceMD5 ---\n" );
+	GLIMP_LOGCOMMENT( "--- Tess_SurfaceMD5 ---" );
 
 	int numIndexes = srf->numTriangles * 3;
 
@@ -1128,7 +1122,7 @@ void Tess_SurfaceIQM( srfIQModel_t *surf ) {
 	IQModel_t *model = surf->data;
 	int offset = tess.numVertexes - surf->first_vertex;
 
-	GLimp_LogComment( "--- Tess_SurfaceIQM ---\n" );
+	GLIMP_LOGCOMMENT( "--- Tess_SurfaceIQM ---" );
 
 	int numIndexes = surf->num_triangles * 3;
 
@@ -1349,7 +1343,7 @@ Entities that have a single procedurally generated surface
 */
 static void Tess_SurfaceEntity( surfaceType_t* )
 {
-	GLimp_LogComment( "--- Tess_SurfaceEntity ---\n" );
+	GLIMP_LOGCOMMENT( "--- Tess_SurfaceEntity ---" );
 
 	switch ( backEnd.currentEntity->e.reType )
 	{
@@ -1363,7 +1357,7 @@ static void Tess_SurfaceEntity( surfaceType_t* )
 
 static void Tess_SurfaceBad( surfaceType_t* )
 {
-	GLimp_LogComment( "--- Tess_SurfaceBad ---\n" );
+	GLIMP_LOGCOMMENT( "--- Tess_SurfaceBad ---" );
 
 	Log::Notice("Bad surface tesselated." );
 }
@@ -1375,7 +1369,7 @@ Tess_SurfaceVBOMesh
 */
 static void Tess_SurfaceVBOMesh( srfVBOMesh_t *srf )
 {
-	GLimp_LogComment( "--- Tess_SurfaceVBOMesh ---\n" );
+	GLIMP_LOGCOMMENT( "--- Tess_SurfaceVBOMesh ---" );
 
 	Tess_SurfaceVBO( srf->vbo, srf->ibo, srf->numIndexes, srf->firstIndex );
 }
@@ -1389,7 +1383,7 @@ void Tess_SurfaceVBOMDVMesh( srfVBOMDVMesh_t *surface )
 {
 	refEntity_t *refEnt;
 
-	GLimp_LogComment( "--- Tess_SurfaceVBOMDVMesh ---\n" );
+	GLIMP_LOGCOMMENT( "--- Tess_SurfaceVBOMDVMesh ---" );
 
 	if ( !surface->vbo || !surface->ibo )
 	{
@@ -1431,7 +1425,7 @@ static void Tess_SurfaceVBOMD5Mesh( srfVBOMD5Mesh_t *srf )
 {
 	md5Model_t *model = srf->md5Model;
 
-	GLimp_LogComment( "--- Tess_SurfaceVBOMD5Mesh ---\n" );
+	GLIMP_LOGCOMMENT( "--- Tess_SurfaceVBOMD5Mesh ---" );
 
 	if ( !srf->vbo || !srf->ibo )
 	{
diff --git a/src/engine/renderer/tr_vbo.cpp b/src/engine/renderer/tr_vbo.cpp
index f627e6d119..aee5499170 100644
--- a/src/engine/renderer/tr_vbo.cpp
+++ b/src/engine/renderer/tr_vbo.cpp
@@ -493,11 +493,7 @@ void R_BindVBO( VBO_t *vbo )
 		}
 	}
 
-	if ( r_logFile->integer )
-	{
-		// don't just call LogComment, or we will get a call to va() every frame!
-		GLimp_LogComment( va( "--- R_BindVBO( %s ) ---\n", vbo->name ) );
-	}
+	GLIMP_LOGCOMMENT( "--- R_BindVBO( %s ) ---", vbo->name );
 
 	if ( glState.currentVBO != vbo )
 	{
@@ -521,7 +517,7 @@ R_BindNullVBO
 */
 void R_BindNullVBO()
 {
-	GLimp_LogComment( "--- R_BindNullVBO ---\n" );
+	GLIMP_LOGCOMMENT( "--- R_BindNullVBO ---" );
 
 	if ( glState.currentVBO )
 	{
@@ -544,11 +540,7 @@ void R_BindIBO( IBO_t *ibo )
 		Sys::Drop( "R_BindIBO: NULL ibo" );
 	}
 
-	if ( r_logFile->integer )
-	{
-		// don't just call LogComment, or we will get a call to va() every frame!
-		GLimp_LogComment( va( "--- R_BindIBO( %s ) ---\n", ibo->name ) );
-	}
+	GLIMP_LOGCOMMENT( "--- R_BindIBO( %s ) ---", ibo->name );
 
 	if ( glState.currentIBO != ibo )
 	{
@@ -567,7 +559,7 @@ R_BindNullIBO
 */
 void R_BindNullIBO()
 {
-	GLimp_LogComment( "--- R_BindNullIBO ---\n" );
+	GLIMP_LOGCOMMENT( "--- R_BindNullIBO ---" );
 
 	if ( glState.currentIBO )
 	{
@@ -932,7 +924,7 @@ Tr3B: update the default VBO to replace the client side vertex arrays
 */
 void Tess_UpdateVBOs()
 {
-	GLimp_LogComment( "--- Tess_UpdateVBOs( ) ---\n" );
+	GLIMP_LOGCOMMENT( "--- Tess_UpdateVBOs( ) ---" );
 
 	GL_CheckErrors();
 
@@ -943,10 +935,8 @@ void Tess_UpdateVBOs()
 
 		GL_CheckErrors();
 
-		if ( r_logFile->integer )
-		{
-			GLimp_LogComment( va( "glBufferSubData( vbo = '%s', numVertexes = %i )\n", tess.vbo->name, tess.numVertexes ) );
-		}
+		GLIMP_LOGCOMMENT( "glBufferSubData( vbo = '%s', numVertexes = %i )",
+			tess.vbo->name, tess.numVertexes );
 
 		if( !glConfig2.mapBufferRangeAvailable ) {
 			R_BindVBO( tess.vbo );
diff --git a/src/engine/sys/sdl_glimp.cpp b/src/engine/sys/sdl_glimp.cpp
index 6e024159a9..19d4087ac0 100644
--- a/src/engine/sys/sdl_glimp.cpp
+++ b/src/engine/sys/sdl_glimp.cpp
@@ -3002,21 +3002,19 @@ void GLimp_HandleCvars()
 	// TODO: Update r_allowResize using SDL_SetWindowResizable when we have SDL 2.0.5
 }
 
-void GLimp_LogComment( const char *comment )
+// Never use GLimp_LogComment_() directly, use the GLIMP_LOGCOMMENT() wrapper instead.
+void GLimp_LogComment_( std::string comment )
 {
 	static char buf[ 4096 ];
 
-	if ( r_logFile->integer && GLEW_ARB_debug_output )
-	{
-		// copy string and ensure it has a trailing '\0'
-		Q_strncpyz( buf, comment, sizeof( buf ) );
+	Q_snprintf( buf, sizeof( buf ), "%s\n", comment.c_str() );
 
-		glDebugMessageInsertARB( GL_DEBUG_SOURCE_APPLICATION_ARB,
-					 GL_DEBUG_TYPE_OTHER_ARB,
-					 0,
-					 GL_DEBUG_SEVERITY_MEDIUM_ARB,
-					 strlen( buf ), buf );
-	}
+	glDebugMessageInsertARB(
+		GL_DEBUG_SOURCE_APPLICATION_ARB,
+		GL_DEBUG_TYPE_OTHER_ARB,
+		0,
+		GL_DEBUG_SEVERITY_MEDIUM_ARB,
+		strlen( buf ), buf );
 }
 
 class SetWindowOriginCmd : public Cmd::StaticCmd


Reviews:
user: login: VReaperV
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T00:04:40Z
user: login: illwieckz
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-18T00:14:05Z
user: login: illwieckz
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-18T00:14:18Z
user: login: illwieckz
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-18T00:14:25Z
user: login: illwieckz
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-18T00:14:34Z
user: login: illwieckz
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-18T00:15:02Z
user: login: illwieckz
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-18T01:54:36Z
user: login: illwieckz
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-18T02:12:33Z
user: login: DolceTriade
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T03:38:47Z
user: login: slipher
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-18T22:42:02Z
user: login: illwieckz
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-18T23:29:05Z
user: login: VReaperV
body: LGTM
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-22T09:06:51Z

Review comments:
diff_hunk: @@ -685,11 +685,8 @@ class GLUniform1i : protected GLUniform
 		}
 
 #if defined( LOG_GLSL_UNIFORMS )
-		if ( r_logFile->integer )
-		{
-			GLimp_LogComment( va( "GLSL_SetUniform1i( %s, shader: %s, value: %d ) ---\n",
-				this->GetName(), _shader->GetName().c_str(), value ) );
-		}
+		GLimp_LogComment( "GLSL_SetUniform1i( %s, shader: %s, value: %d )",
path: src/engine/renderer/gl_shader.h
user: login: VReaperV
body: The whole `LOG_GLSL_UNIFORMS` thing should just be removed. You already get a much better view of uniform names/types/values for each draw/dispatch, so this just creates noise (and you get the actual `glUniform*()` calls there too, so it just duplicates them in a worse way).
created_at: 2025-03-17T23:39:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -123,7 +123,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 		Cvar::NONE, 1, 0, 2);
 
 	cvar_t      *r_checkGLErrors;
-	cvar_t      *r_logFile;
+	Cvar::Cvar<bool> r_logFile( "r_logFile", "Emit GL logs", Cvar::CHEAT, false );
path: src/engine/renderer/tr_init.cpp
user: login: VReaperV
body: The cheat flag can be removed from this.
created_at: 2025-03-17T23:43:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2321,7 +2314,7 @@ void Tess_ComputeColor( shaderStage_t *pStage )
 	float blue;
 	float alpha;
 
-	GLimp_LogComment( "--- Tess_ComputeColor ---\n" );
+	GLimp_LogComment( "--- Tess_ComputeColor ---" );
path: src/engine/renderer/tr_shade.cpp
user: login: VReaperV
body: This and `Tess_ComputeTexMatrices()` have no GL calls in them, so I don't think these 2 logs even make sense.
created_at: 2025-03-17T23:47:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -160,10 +153,7 @@ void GL_SelectTexture( int unit )
 	{
 		glActiveTexture( GL_TEXTURE0 + unit );
 
-		if ( r_logFile->integer )
-		{
-			GLimp_LogComment( va( "glActiveTexture( GL_TEXTURE%i )\n", unit ) );
-		}
+		GLimp_LogComment( "glActiveTexture( GL_TEXTURE%i )", unit );
path: src/engine/renderer/tr_backend.cpp
user: login: VReaperV
body: This should be removed too.
created_at: 2025-03-17T23:53:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2966,10 +2880,8 @@ void RB_RenderGlobalFog()
 	{
 		fog_t* fog = &tr.world->fogs[ tr.world->globalFog ];
 
-		if ( r_logFile->integer )
-		{
-			GLimp_LogComment( va( "--- RB_RenderGlobalFog( fogNum = %i, originalBrushNumber = %i ) ---\n", tr.world->globalFog, fog->originalBrushNumber ) );
-		}
+		GLimp_LogComment( "--- RB_RenderGlobalFog( fogNum = %i, originalBrushNumber = %i ) ---",
path: src/engine/renderer/tr_backend.cpp
user: login: VReaperV
body: `originalBrushNumber` can be removed here, as it's always -1.
created_at: 2025-03-18T00:02:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5640,7 +5544,7 @@ const RenderCommand *SwapBuffersCommand::ExecuteSelf( ) const
 		RB_ShowImages();
 	}
 
-	GLimp_LogComment( "***************** RB_SwapBuffers *****************\n\n\n" );
+	GLimp_LogComment( "***************** RB_SwapBuffers *****************" );
path: src/engine/renderer/tr_backend.cpp
user: login: VReaperV
body: This should also be removed.
created_at: 2025-03-18T00:04:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -123,7 +123,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 		Cvar::NONE, 1, 0, 2);
 
 	cvar_t      *r_checkGLErrors;
-	cvar_t      *r_logFile;
+	Cvar::Cvar<bool> r_logFile( "r_logFile", "Emit GL logs", Cvar::CHEAT, false );
path: src/engine/renderer/tr_init.cpp
user: login: illwieckz
body: Done.
created_at: 2025-03-18T00:14:05Z
author_association: MEMBER
diff_hunk: @@ -2321,7 +2314,7 @@ void Tess_ComputeColor( shaderStage_t *pStage )
 	float blue;
 	float alpha;
 
-	GLimp_LogComment( "--- Tess_ComputeColor ---\n" );
+	GLimp_LogComment( "--- Tess_ComputeColor ---" );
path: src/engine/renderer/tr_shade.cpp
user: login: illwieckz
body: Done (both).
created_at: 2025-03-18T00:14:18Z
author_association: MEMBER
diff_hunk: @@ -160,10 +153,7 @@ void GL_SelectTexture( int unit )
 	{
 		glActiveTexture( GL_TEXTURE0 + unit );
 
-		if ( r_logFile->integer )
-		{
-			GLimp_LogComment( va( "glActiveTexture( GL_TEXTURE%i )\n", unit ) );
-		}
+		GLimp_LogComment( "glActiveTexture( GL_TEXTURE%i )", unit );
path: src/engine/renderer/tr_backend.cpp
user: login: illwieckz
body: Done.
created_at: 2025-03-18T00:14:25Z
author_association: MEMBER
diff_hunk: @@ -2966,10 +2880,8 @@ void RB_RenderGlobalFog()
 	{
 		fog_t* fog = &tr.world->fogs[ tr.world->globalFog ];
 
-		if ( r_logFile->integer )
-		{
-			GLimp_LogComment( va( "--- RB_RenderGlobalFog( fogNum = %i, originalBrushNumber = %i ) ---\n", tr.world->globalFog, fog->originalBrushNumber ) );
-		}
+		GLimp_LogComment( "--- RB_RenderGlobalFog( fogNum = %i, originalBrushNumber = %i ) ---",
path: src/engine/renderer/tr_backend.cpp
user: login: illwieckz
body: Done.
created_at: 2025-03-18T00:14:34Z
author_association: MEMBER
diff_hunk: @@ -5640,7 +5544,7 @@ const RenderCommand *SwapBuffersCommand::ExecuteSelf( ) const
 		RB_ShowImages();
 	}
 
-	GLimp_LogComment( "***************** RB_SwapBuffers *****************\n\n\n" );
+	GLimp_LogComment( "***************** RB_SwapBuffers *****************" );
path: src/engine/renderer/tr_backend.cpp
user: login: illwieckz
body: Done
created_at: 2025-03-18T00:15:02Z
author_association: MEMBER
diff_hunk: @@ -685,11 +685,8 @@ class GLUniform1i : protected GLUniform
 		}
 
 #if defined( LOG_GLSL_UNIFORMS )
-		if ( r_logFile->integer )
-		{
-			GLimp_LogComment( va( "GLSL_SetUniform1i( %s, shader: %s, value: %d ) ---\n",
-				this->GetName(), _shader->GetName().c_str(), value ) );
-		}
+		GLimp_LogComment( "GLSL_SetUniform1i( %s, shader: %s, value: %d )",
path: src/engine/renderer/gl_shader.h
user: login: illwieckz
body: Removed too.
created_at: 2025-03-18T01:54:35Z
author_association: MEMBER
diff_hunk: @@ -3383,7 +3382,19 @@ inline bool checkGLErrors()
 	void     GLimp_SyncRenderThread();
 	void     GLimp_WakeRenderer( void *data );
 
-	void     GLimp_LogComment( const char *comment );
+	inline bool GLimp_isLogging() {
+		return r_logFile.Get() && GLEW_ARB_debug_output;
+	}
+
+	#define GLimp_LogComment( ... ) { \
+		if ( GLimp_isLogging() ) \
+		{ \
+			GLimp_LogComment_( Str::Format( __VA_ARGS__ ) ); \
+		} \
+	}
path: src/engine/renderer/tr_local.h
user: login: illwieckz
body: @DolceTriade here
created_at: 2025-03-18T02:12:33Z
author_association: MEMBER
diff_hunk: @@ -3383,7 +3382,19 @@ inline bool checkGLErrors()
 	void     GLimp_SyncRenderThread();
 	void     GLimp_WakeRenderer( void *data );
 
-	void     GLimp_LogComment( const char *comment );
+	inline bool GLimp_isLogging() {
+		return r_logFile.Get() && GLEW_ARB_debug_output;
+	}
+
+	#define GLimp_LogComment( ... ) { \
+		if ( GLimp_isLogging() ) \
+		{ \
+			GLimp_LogComment_( Str::Format( __VA_ARGS__ ) ); \
+		} \
+	}
path: src/engine/renderer/tr_local.h
user: login: DolceTriade
body: I see
created_at: 2025-03-18T03:38:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -3383,7 +3382,19 @@ inline bool checkGLErrors()
 	void     GLimp_SyncRenderThread();
 	void     GLimp_WakeRenderer( void *data );
 
-	void     GLimp_LogComment( const char *comment );
+inline bool GLimp_isLogging() {
+	return r_logFile.Get() && GLEW_ARB_debug_output;
+}
+
+// Never use GLimp_LogComment() directly, use the GLIMP_LOGCOMMENT() wrapper instead.
+void GLimp_LogComment( std::string comment, bool wrapped = false );
path: src/engine/renderer/tr_local.h
user: login: slipher
body: `bool wrapped` seems like overkill. Just give the function a name hinting it is not intending to be used normally, like with the trailing underscore on `GL_CheckErrors_`
created_at: 2025-03-18T22:42:02Z
author_association: MEMBER
diff_hunk: @@ -3383,7 +3382,19 @@ inline bool checkGLErrors()
 	void     GLimp_SyncRenderThread();
 	void     GLimp_WakeRenderer( void *data );
 
-	void     GLimp_LogComment( const char *comment );
+inline bool GLimp_isLogging() {
+	return r_logFile.Get() && GLEW_ARB_debug_output;
+}
+
+// Never use GLimp_LogComment() directly, use the GLIMP_LOGCOMMENT() wrapper instead.
+void GLimp_LogComment( std::string comment, bool wrapped = false );
path: src/engine/renderer/tr_local.h
user: login: illwieckz
body: Done.
created_at: 2025-03-18T23:29:05Z
author_association: MEMBER

PR comments:
user: login: DolceTriade
created_at: 2025-03-18T02:07:54Z
body: Hm, maybe reaper and slipher can disagree, but I'm not sure I agree with the premise of the PR.

Keep in mind that your change isn't 1:1 with the old behavior.

```
GLimp_LogComment("%d", SomeVeryExpensiveCall())
```

`SomeVeryExpensiveCall` will now be run unconditionally. We do have `DoDebugCode` for this reason, but in that case, I'd like to see all calls to GLimp_LogComment wrapped in that function (which from a noisy-ness perspective, does not really get us much).
author_association: CONTRIBUTOR
user: login: illwieckz
created_at: 2025-03-18T02:12:14Z
body: @DolceTriade this is the part you look for:

```c++
inline bool GLimp_isLogging() {
	return r_logFile.Get() && GLEW_ARB_debug_output;
}

#define GLimp_LogComment( ... ) { \
	if ( GLimp_isLogging() ) \
	{ \
		GLimp_LogComment_( Str::Format( __VA_ARGS__ ) ); \
	} \
}
```
author_association: MEMBER
user: login: illwieckz
created_at: 2025-03-18T02:24:41Z
body: Well, I can rename `GLimp_LogComment` as upper case `GLIMP_LOGCOMMENT` to hint this is now a macro.
author_association: MEMBER
user: login: illwieckz
created_at: 2025-03-18T02:31:23Z
body: > Well, I can rename `GLimp_LogComment` as upper case `GLIMP_LOGCOMMENT` to hint this is now a macro.

Now done.
author_association: MEMBER
user: login: illwieckz
created_at: 2025-03-18T02:46:55Z
body: I also added a commit asserting that the `GLimp_LogComment()` function is never called directly and not wrapped by `GLIMP_LOGCOMMENT()`.

There is actually one place where we can call it directly, but the extra calls of `GLimp_isLogging()` will be optimized out by the compiler anyway.

So we better make sure `GLIMP_LOGCOMMENT()` is always used instead.
author_association: MEMBER
user: login: DolceTriade
created_at: 2025-03-18T03:39:36Z
body: I see. I missed that it was converted into a macro
author_association: CONTRIBUTOR
user: login: illwieckz
created_at: 2025-03-18T11:32:39Z
body: > I see. I missed that it was converted into a macro

My fault, I forgot to mention it in the first post. 😊️
author_association: MEMBER