diff --git a/CMakeLists.txt b/CMakeLists.txt index f11b79862d..b962301baf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,6 +83,7 @@ if(NOT DAEMON_EXTERNAL_APP) endif() option(BUILD_TTY_CLIENT "Build Daemon headless client" 1) option(BUILD_DUMMY_APP "Build the dummy app for daemon" 0) + option(BUILD_TEST_COMPILE_GLSL "Build OSMesa-based GLSL compilation tester (Linux only)" 0) set(NACL_RUNTIME_PATH "" CACHE STRING "Directory containing the NaCl binaries") @@ -501,7 +502,6 @@ set(LIBS_BASE ${LIBS_BASE} srclibs-minizip) # Look for OpenGL here before we potentially switch to looking for static libs. if (BUILD_CLIENT) find_package(OpenGL REQUIRED) - include_directories(${OPENGL_INCLUDE_DIR}) set(LIBS_CLIENT ${LIBS_CLIENT} OpenGL::GL) endif() @@ -739,6 +739,8 @@ if (NOT NACL) endif() endif() +set(EMBED_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/embed_data) + if (BUILD_CLIENT) set(Definitions BUILD_ENGINE BUILD_GRAPHICAL_CLIENT @@ -754,12 +756,25 @@ if (BUILD_CLIENT) Files WIN32 ${WIN_RC} ${QCOMMONLIST} ${SERVERLIST} ${CLIENTBASELIST} ${CLIENTLIST} Libs ${LIBS_CLIENT} ${LIBS_CLIENTBASE} ${LIBS_ENGINE} ) + target_include_directories(client PRIVATE ${OPENGL_INCLUDE_DIR} ${EMBED_INCLUDE_DIR}) +endif() +if (BUILD_TEST_COMPILE_GLSL) + AddApplication( + Target test-compile-glsl + ExecutableName test-compile-glsl + Definitions BUILD_ENGINE USE_OSMESA + Flags ${WARNINGS} + Files ${TESTCOMPILEGLSLLIST} + Libs ${LIBS_ENGINE} OSMesa # TODO "FindOSMesa" etc. + ) + target_include_directories(test-compile-glsl PRIVATE ${EMBED_INCLUDE_DIR}) +endif() + +if (BUILD_CLIENT OR BUILD_TEST_COMPILE_GLSL) # generate glsl include files set(GLSL_SOURCE_DIR ${ENGINE_DIR}/renderer/glsl_source) - set(EMBED_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/embed_data) file(MAKE_DIRECTORY ${EMBED_INCLUDE_DIR}) - set_property(TARGET client APPEND PROPERTY INCLUDE_DIRECTORIES ${EMBED_INCLUDE_DIR}) foreach(res ${GLSLSOURCELIST}) get_filename_component(filename_no_ext ${res} NAME_WE) @@ -770,7 +785,12 @@ if (BUILD_CLIENT) "-DVARIABLE_NAME=${filename_no_ext}_glsl" -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/EmbedText.cmake MAIN_DEPENDENCY ${res} ) - set_property(TARGET client APPEND PROPERTY SOURCES ${outpath}) + if (BUILD_CLIENT) + set_property(TARGET client APPEND PROPERTY SOURCES ${outpath}) + endif() + if (BUILD_TEST_COMPILE_GLSL) + set_property(TARGET test-compile-glsl APPEND PROPERTY SOURCES ${outpath}) + endif() endforeach() endif() diff --git a/src.cmake b/src.cmake index 7f6d6a10e9..ce28d6235c 100644 --- a/src.cmake +++ b/src.cmake @@ -83,6 +83,7 @@ if (DAEMON_PARENT_SCOPE_DIR) endif() set(RENDERERLIST + ${ENGINE_DIR}/renderer/gl_config.cpp ${ENGINE_DIR}/renderer/gl_shader.cpp ${ENGINE_DIR}/renderer/gl_shader.h ${ENGINE_DIR}/renderer/iqm.h @@ -350,4 +351,13 @@ set(DEDSERVERLIST ${ENGINE_DIR}/server/ServerApplication.cpp ) +set(TESTCOMPILEGLSLLIST + ${ENGINE_DIR}/qcommon/cvar.cpp + ${ENGINE_DIR}/qcommon/files.cpp + ${ENGINE_DIR}/renderer/gl_config.cpp + ${ENGINE_DIR}/renderer/gl_shader.cpp + ${ENGINE_DIR}/renderer/shader_test_app.cpp + ${ENGINE_DIR}/renderer/shaders.cpp +) + set(WIN_RC ${ENGINE_DIR}/sys/daemon.rc) diff --git a/src/engine/renderer/gl_config.cpp b/src/engine/renderer/gl_config.cpp new file mode 100644 index 0000000000..a3199f50f6 --- /dev/null +++ b/src/engine/renderer/gl_config.cpp @@ -0,0 +1,902 @@ +#include "common/Common.h" +#include "tr_local.h" + +Log::Logger glConfigLogger("glconfig", "", Log::Level::NOTICE); +#define logger glConfigLogger + +glconfig_t glConfig; +glconfig2_t glConfig2; + +glstate_t glState; + +cvar_t *r_glMajorVersion; +cvar_t *r_glMinorVersion; +cvar_t *r_glProfile; +cvar_t *r_glDebugProfile; +cvar_t *r_glDebugMode; +cvar_t *r_glAllowSoftware; + +cvar_t *r_verbose; +cvar_t *r_ignore; + +cvar_t *r_znear; +cvar_t *r_zfar; + +cvar_t *r_smp; +cvar_t *r_showSmp; +cvar_t *r_skipBackEnd; +cvar_t *r_skipLightBuffer; + +cvar_t *r_measureOverdraw; + +cvar_t *r_fastsky; +cvar_t *r_drawSun; + +cvar_t *r_lodBias; +cvar_t *r_lodScale; +cvar_t *r_lodTest; + +cvar_t *r_norefresh; +cvar_t *r_drawentities; +cvar_t *r_drawworld; +cvar_t *r_drawpolies; +cvar_t *r_speeds; +cvar_t *r_novis; +cvar_t *r_nocull; +cvar_t *r_facePlaneCull; +cvar_t *r_showcluster; +cvar_t *r_nocurves; +cvar_t *r_lightScissors; +cvar_t *r_noLightVisCull; +cvar_t *r_noInteractionSort; +cvar_t *r_dynamicLight; +cvar_t *r_staticLight; +cvar_t *r_dynamicLightCastShadows; +cvar_t *r_precomputedLighting; +cvar_t *r_vertexLighting; +cvar_t *r_exportTextures; +cvar_t *r_heatHaze; +cvar_t *r_noMarksOnTrisurfs; +cvar_t *r_lazyShaders; + +cvar_t *r_ext_occlusion_query; +cvar_t *r_ext_draw_buffers; +cvar_t *r_ext_vertex_array_object; +cvar_t *r_ext_half_float_pixel; +cvar_t *r_ext_texture_float; +cvar_t *r_ext_texture_integer; +cvar_t *r_ext_texture_rg; +cvar_t *r_ext_texture_filter_anisotropic; +cvar_t *r_ext_gpu_shader4; +cvar_t *r_arb_buffer_storage; +cvar_t *r_arb_map_buffer_range; +cvar_t *r_arb_sync; +cvar_t *r_arb_uniform_buffer_object; +cvar_t *r_arb_texture_gather; +cvar_t *r_arb_gpu_shader5; + +cvar_t *r_checkGLErrors; +cvar_t *r_logFile; + +cvar_t *r_stencilbits; +cvar_t *r_depthbits; +cvar_t *r_colorbits; +cvar_t *r_alphabits; +cvar_t *r_ext_multisample; + +cvar_t *r_drawBuffer; +cvar_t *r_shadows; +cvar_t *r_softShadows; +cvar_t *r_softShadowsPP; +cvar_t *r_shadowBlur; + +cvar_t *r_shadowMapQuality; +cvar_t *r_shadowMapSizeUltra; +cvar_t *r_shadowMapSizeVeryHigh; +cvar_t *r_shadowMapSizeHigh; +cvar_t *r_shadowMapSizeMedium; +cvar_t *r_shadowMapSizeLow; + +cvar_t *r_shadowMapSizeSunUltra; +cvar_t *r_shadowMapSizeSunVeryHigh; +cvar_t *r_shadowMapSizeSunHigh; +cvar_t *r_shadowMapSizeSunMedium; +cvar_t *r_shadowMapSizeSunLow; + +cvar_t *r_shadowOffsetFactor; +cvar_t *r_shadowOffsetUnits; +cvar_t *r_shadowLodBias; +cvar_t *r_shadowLodScale; +cvar_t *r_noShadowPyramids; +cvar_t *r_cullShadowPyramidFaces; +cvar_t *r_cullShadowPyramidCurves; +cvar_t *r_cullShadowPyramidTriangles; +cvar_t *r_debugShadowMaps; +cvar_t *r_noShadowFrustums; +cvar_t *r_noLightFrustums; +cvar_t *r_shadowMapLinearFilter; +cvar_t *r_lightBleedReduction; +cvar_t *r_overDarkeningFactor; +cvar_t *r_shadowMapDepthScale; +cvar_t *r_parallelShadowSplits; +cvar_t *r_parallelShadowSplitWeight; + +cvar_t *r_mode; +cvar_t *r_nobind; +cvar_t *r_singleShader; +cvar_t *r_colorMipLevels; +cvar_t *r_picMip; +cvar_t *r_imageMaxDimension; +cvar_t *r_ignoreMaterialMinDimension; +cvar_t *r_ignoreMaterialMaxDimension; +cvar_t *r_replaceMaterialMinDimensionIfPresentWithMaxDimension; +cvar_t *r_finish; +cvar_t *r_clear; +cvar_t *r_swapInterval; +cvar_t *r_textureMode; +cvar_t *r_offsetFactor; +cvar_t *r_offsetUnits; + +cvar_t *r_physicalMapping; +cvar_t *r_specularExponentMin; +cvar_t *r_specularExponentMax; +cvar_t *r_specularScale; +cvar_t *r_specularMapping; +cvar_t *r_deluxeMapping; +cvar_t *r_normalScale; +cvar_t *r_normalMapping; +cvar_t *r_liquidMapping; +cvar_t *r_highQualityNormalMapping; +cvar_t *r_reliefDepthScale; +cvar_t *r_reliefMapping; +cvar_t *r_glowMapping; +cvar_t *r_reflectionMapping; + +cvar_t *r_wrapAroundLighting; +cvar_t *r_halfLambertLighting; +cvar_t *r_rimLighting; +cvar_t *r_rimExponent; +cvar_t *r_gamma; +cvar_t *r_lockpvs; +cvar_t *r_noportals; +cvar_t *r_portalOnly; +cvar_t *r_portalSky; +cvar_t *r_max_portal_levels; + +cvar_t *r_subdivisions; +cvar_t *r_stitchCurves; + +cvar_t *r_noBorder; +cvar_t *r_fullscreen; + +cvar_t *r_customwidth; +cvar_t *r_customheight; + +cvar_t *r_debugSurface; +cvar_t *r_simpleMipMaps; + +cvar_t *r_showImages; + +cvar_t *r_forceFog; +cvar_t *r_wolfFog; +cvar_t *r_noFog; + +cvar_t *r_forceAmbient; +cvar_t *r_ambientScale; +cvar_t *r_lightScale; +cvar_t *r_debugSort; +cvar_t *r_printShaders; + +cvar_t *r_maxPolys; +cvar_t *r_maxPolyVerts; + +cvar_t *r_showTris; +cvar_t *r_showSky; +cvar_t *r_showShadowVolumes; +cvar_t *r_showShadowLod; +cvar_t *r_showShadowMaps; +cvar_t *r_showSkeleton; +cvar_t *r_showEntityTransforms; +cvar_t *r_showLightTransforms; +cvar_t *r_showLightInteractions; +cvar_t *r_showLightScissors; +cvar_t *r_showLightBatches; +cvar_t *r_showLightGrid; +cvar_t *r_showLightTiles; +cvar_t *r_showBatches; +cvar_t *r_showLightMaps; +cvar_t *r_showDeluxeMaps; +cvar_t *r_showNormalMaps; +cvar_t *r_showMaterialMaps; +cvar_t *r_showAreaPortals; +cvar_t *r_showCubeProbes; +cvar_t *r_showBspNodes; +cvar_t *r_showParallelShadowSplits; +cvar_t *r_showDecalProjectors; + +cvar_t *r_vboFaces; +cvar_t *r_vboCurves; +cvar_t *r_vboTriangles; +cvar_t *r_vboShadows; +cvar_t *r_vboLighting; +cvar_t *r_vboModels; +cvar_t *r_vboVertexSkinning; +cvar_t *r_vboDeformVertexes; + +cvar_t *r_mergeLeafSurfaces; + +cvar_t *r_bloom; +cvar_t *r_bloomBlur; +cvar_t *r_bloomPasses; +cvar_t *r_FXAA; +cvar_t *r_ssao; + +cvar_t *r_evsmPostProcess; + +cvar_t *r_fontScale; + +void AssertCvarRange( cvar_t *cv, float minVal, float maxVal, bool shouldBeIntegral ) +{ + if ( shouldBeIntegral ) + { + if ( cv->value != static_cast(cv->integer) ) + { + Log::Warn("cvar '%s' must be integral (%f)", cv->name, cv->value ); + Cvar_Set( cv->name, va( "%d", cv->integer ) ); + } + } + + if ( cv->value < minVal ) + { + Log::Warn("cvar '%s' out of range (%g < %g)", cv->name, cv->value, minVal ); + Cvar_Set( cv->name, va( "%f", minVal ) ); + } + else if ( cv->value > maxVal ) + { + Log::Warn("cvar '%s' out of range (%g > %g)", cv->name, cv->value, maxVal ); + Cvar_Set( cv->name, va( "%f", maxVal ) ); + } +} + +/* +=============== +GLimp_InitExtensions +=============== +*/ + +/* ExtFlag_CORE means the extension is known to be an OpenGL 3 core extension. +The code considers the extension is available even if the extension is not listed +if the driver pretends to support OpenGL Core 3 and we know this extension is part +of OpenGL Core 3. */ + +enum { + ExtFlag_NONE, + ExtFlag_REQUIRED = BIT( 1 ), + ExtFlag_CORE = BIT( 2 ), +}; + +static bool LoadExt( int flags, bool hasExt, const char* name, bool test = true ) +{ + if ( hasExt || ( flags & ExtFlag_CORE && glConfig2.glCoreProfile) ) + { + if ( test ) + { + logger.WithoutSuppression().Notice( "...using GL_%s", name ); + return true; + } + else + { + // Required extension can't be made optional + ASSERT( !( flags & ExtFlag_REQUIRED ) ); + + logger.WithoutSuppression().Notice( "...ignoring GL_%s", name ); + } + } + else + { + if ( flags & ExtFlag_REQUIRED ) + { + Sys::Error( "Required extension GL_%s is missing", name ); + } + else + { + logger.WithoutSuppression().Notice( "...GL_%s not found", name ); + } + } + return false; +} + +#define LOAD_EXTENSION(flags, ext) LoadExt(flags, GLEW_##ext, #ext) + +#define LOAD_EXTENSION_WITH_TEST(flags, ext, test) LoadExt(flags, GLEW_##ext, #ext, test) + +static GLenum debugTypes[] = +{ + 0, + GL_DEBUG_TYPE_ERROR_ARB, + GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, + GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB, + GL_DEBUG_TYPE_PORTABILITY_ARB, + GL_DEBUG_TYPE_PERFORMANCE_ARB, + GL_DEBUG_TYPE_OTHER_ARB +}; + +#ifdef _WIN32 +#define DEBUG_CALLBACK_CALL APIENTRY +#else +#define DEBUG_CALLBACK_CALL +#endif +static void DEBUG_CALLBACK_CALL GLimp_DebugCallback( GLenum, GLenum type, GLuint, + GLenum severity, GLsizei, const GLchar *message, const void* ) +{ + const char *debugTypeName; + const char *debugSeverity; + + if ( r_glDebugMode->integer <= Util::ordinal(glDebugModes_t::GLDEBUG_NONE)) + { + return; + } + + if ( r_glDebugMode->integer < Util::ordinal(glDebugModes_t::GLDEBUG_ALL)) + { + if ( debugTypes[ r_glDebugMode->integer ] != type ) + { + return; + } + } + + switch ( type ) + { + case GL_DEBUG_TYPE_ERROR_ARB: + debugTypeName = "DEBUG_TYPE_ERROR"; + break; + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: + debugTypeName = "DEBUG_TYPE_DEPRECATED_BEHAVIOR"; + break; + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: + debugTypeName = "DEBUG_TYPE_UNDEFINED_BEHAVIOR"; + break; + case GL_DEBUG_TYPE_PORTABILITY_ARB: + debugTypeName = "DEBUG_TYPE_PORTABILITY"; + break; + case GL_DEBUG_TYPE_PERFORMANCE_ARB: + debugTypeName = "DEBUG_TYPE_PERFORMANCE"; + break; + case GL_DEBUG_TYPE_OTHER_ARB: + debugTypeName = "DEBUG_TYPE_OTHER"; + break; + default: + debugTypeName = "DEBUG_TYPE_UNKNOWN"; + break; + } + + switch ( severity ) + { + case GL_DEBUG_SEVERITY_HIGH_ARB: + debugSeverity = "high"; + break; + case GL_DEBUG_SEVERITY_MEDIUM_ARB: + debugSeverity = "med"; + break; + case GL_DEBUG_SEVERITY_LOW_ARB: + debugSeverity = "low"; + break; + default: + debugSeverity = "none"; + break; + } + + logger.Warn("%s: severity: %s msg: %s", debugTypeName, debugSeverity, message ); +} + +#ifdef USE_OSMESA +#define LOAD_EXTENSION_WITH_TEST(...) false +#define LOAD_EXTENSION(...) false +#endif + +void GLimp_InitExtensions() +{ + logger.Notice("Initializing OpenGL extensions" ); + + if ( LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_debug_output, r_glDebugProfile->value ) ) + { + glDebugMessageCallbackARB( (GLDEBUGPROCARB)GLimp_DebugCallback, nullptr ); + glEnable( GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB ); + } + + // Shader limits + glGetIntegerv( GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &glConfig2.maxVertexUniforms ); + glGetIntegerv( GL_MAX_VERTEX_ATTRIBS_ARB, &glConfig2.maxVertexAttribs ); + + int reservedComponents = 36 * 10; // approximation how many uniforms we have besides the bone matrices + glConfig2.maxVertexSkinningBones = Math::Clamp( ( glConfig2.maxVertexUniforms - reservedComponents ) / 16, 0, MAX_BONES ); + glConfig2.vboVertexSkinningAvailable = r_vboVertexSkinning->integer && ( ( glConfig2.maxVertexSkinningBones >= 12 ) ? true : false ); + + // GLSL + + Q_strncpyz( glConfig2.shadingLanguageVersionString, ( char * ) glGetString( GL_SHADING_LANGUAGE_VERSION_ARB ), + sizeof( glConfig2.shadingLanguageVersionString ) ); + int majorVersion, minorVersion; + if ( sscanf( glConfig2.shadingLanguageVersionString, "%i.%i", &majorVersion, &minorVersion ) != 2 ) + { + logger.Warn("unrecognized shading language version string format" ); + } + glConfig2.shadingLanguageVersion = majorVersion * 100 + minorVersion; + + logger.Notice("...found shading language version %i", glConfig2.shadingLanguageVersion ); + + // Texture formats and compression + glGetIntegerv( GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, &glConfig2.maxCubeMapTextureSize ); + + // made required in OpenGL 3.0 + glConfig2.textureHalfFloatAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_CORE, ARB_half_float_pixel, r_ext_half_float_pixel->value ); + + // made required in OpenGL 3.0 + glConfig2.textureFloatAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_CORE, ARB_texture_float, r_ext_texture_float->value ); + + // made required in OpenGL 3.0 + glConfig2.gpuShader4Available = LOAD_EXTENSION_WITH_TEST( ExtFlag_CORE, EXT_gpu_shader4, r_ext_gpu_shader4->value ); + + // made required in OpenGL 3.0 + // GL_EXT_texture_integer can be used in shaders only if GL_EXT_gpu_shader4 is also available + glConfig2.textureIntegerAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_CORE, EXT_texture_integer, r_ext_texture_integer->value ) + && glConfig2.gpuShader4Available; + + // made required in OpenGL 3.0 + glConfig2.textureRGAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_CORE, ARB_texture_rg, r_ext_texture_rg->value ); + + { + /* GT218-based GPU with Nvidia 340.108 driver advertising + ARB_texture_gather extension is know to fail to compile + the depthtile1 GLSL shader. + + See https://github.com/DaemonEngine/Daemon/issues/368 + + Unfortunately this workaround may also disable the feature for + all GPUs using this driver even if we don't know if some of them + are not affected by the bug while advertising this extension, but + there is no known easy way to detect GT218-based cards. Not all cards + using 340 driver supports this extension anyway, like the G92 one. + + We can assume cards not using the 340 driver are not GT218 ones and + are not affected. + + Usually, those GT218 cards are not powerful enough for dynamic + lighting so it is likely this feature would be disabled to + get acceptable framerate on this hardware anyway, making the + need for such extension and the related shader code useless. */ + bool foundNvidia340 = ( Q_stristr( glConfig.vendor_string, "NVIDIA Corporation" ) && Q_stristr( glConfig.version_string, "NVIDIA 340." ) ); + + if ( foundNvidia340 ) + { + // No need for WithoutSuppression for something which can only be printed once per renderer restart. + logger.Notice("...found buggy Nvidia 340 driver"); + } + + // made required in OpenGL 4.0 + glConfig2.textureGatherAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_texture_gather, r_arb_texture_gather->value && !foundNvidia340 ); + } + + // made required in OpenGL 1.3 + glConfig.textureCompression = textureCompression_t::TC_NONE; + if( LOAD_EXTENSION( ExtFlag_NONE, EXT_texture_compression_s3tc ) ) + { + glConfig.textureCompression = textureCompression_t::TC_S3TC; + } + + // made required in OpenGL 3.0 + glConfig2.textureCompressionRGTCAvailable = LOAD_EXTENSION( ExtFlag_CORE, ARB_texture_compression_rgtc ); + + // Texture - others + glConfig2.textureAnisotropyAvailable = false; + if ( LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, EXT_texture_filter_anisotropic, r_ext_texture_filter_anisotropic->value ) ) + { + glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glConfig2.maxTextureAnisotropy ); + glConfig2.textureAnisotropyAvailable = true; + } + + // VAO and VBO + // made required in OpenGL 3.0 + + LOAD_EXTENSION( ExtFlag_REQUIRED | ExtFlag_CORE, ARB_half_float_vertex ); + + // made required in OpenGL 3.0 + LOAD_EXTENSION( ExtFlag_REQUIRED | ExtFlag_CORE, ARB_framebuffer_object ); + + // FBO + glGetIntegerv( GL_MAX_RENDERBUFFER_SIZE, &glConfig2.maxRenderbufferSize ); + glGetIntegerv( GL_MAX_COLOR_ATTACHMENTS, &glConfig2.maxColorAttachments ); + + // made required in OpenGL 1.5 + glConfig2.occlusionQueryAvailable = false; + glConfig2.occlusionQueryBits = 0; + if ( r_ext_occlusion_query->integer != 0 ) + { + glConfig2.occlusionQueryAvailable = true; + glGetQueryiv( GL_SAMPLES_PASSED, GL_QUERY_COUNTER_BITS, &glConfig2.occlusionQueryBits ); + } + + // made required in OpenGL 2.0 + glConfig2.drawBuffersAvailable = false; + if ( r_ext_draw_buffers->integer != 0 ) + { + glGetIntegerv( GL_MAX_DRAW_BUFFERS, &glConfig2.maxDrawBuffers ); + glConfig2.drawBuffersAvailable = true; + } + + { + int formats = 0; + + glGetIntegerv( GL_NUM_PROGRAM_BINARY_FORMATS, &formats ); + + if ( formats == 0 ) + { + // No need for WithoutSuppression for something which can only be printed once per renderer restart. + logger.Notice("...no program binary formats"); + } + + glConfig2.getProgramBinaryAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_get_program_binary, formats > 0 ); + } + + glConfig2.bufferStorageAvailable = false; + glConfig2.bufferStorageAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_buffer_storage, r_arb_buffer_storage->integer > 0 ); + + // made required since OpenGL 3.1 + glConfig2.uniformBufferObjectAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_CORE, ARB_uniform_buffer_object, r_arb_uniform_buffer_object->value ); + + // made required in OpenGL 3.0 + glConfig2.mapBufferRangeAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_CORE, ARB_map_buffer_range, r_arb_map_buffer_range->value ); + + // made required in OpenGL 3.2 + glConfig2.syncAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_CORE, ARB_sync, r_arb_sync->value ); + + GL_CheckErrors(); +} + +void GLimp_LogComment( const char *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 ) ); + + glDebugMessageInsertARB( GL_DEBUG_SOURCE_APPLICATION_ARB, + GL_DEBUG_TYPE_OTHER_ARB, + 0, + GL_DEBUG_SEVERITY_MEDIUM_ARB, + strlen( buf ), buf ); + } +} + +/* +================== +GL_CheckErrors + +Must not be called while the backend rendering thread is running +================== +*/ +void GL_CheckErrors_( const char *fileName, int line ) +{ + int err; + char s[ 128 ]; + + if ( r_checkGLErrors->integer ) + { + return; + } + + while ( ( err = glGetError() ) != GL_NO_ERROR ) + { + switch ( err ) + { + case GL_INVALID_ENUM: + strcpy( s, "GL_INVALID_ENUM" ); + break; + + case GL_INVALID_VALUE: + strcpy( s, "GL_INVALID_VALUE" ); + break; + + case GL_INVALID_OPERATION: + strcpy( s, "GL_INVALID_OPERATION" ); + break; + + case GL_STACK_OVERFLOW: + strcpy( s, "GL_STACK_OVERFLOW" ); + break; + + case GL_STACK_UNDERFLOW: + strcpy( s, "GL_STACK_UNDERFLOW" ); + break; + + case GL_OUT_OF_MEMORY: + strcpy( s, "GL_OUT_OF_MEMORY" ); + break; + + case GL_TABLE_TOO_LARGE: + strcpy( s, "GL_TABLE_TOO_LARGE" ); + break; + + case GL_INVALID_FRAMEBUFFER_OPERATION: + strcpy( s, "GL_INVALID_FRAMEBUFFER_OPERATION" ); + break; + + default: + Com_sprintf( s, sizeof( s ), "0x%X", err ); + break; + } + // Pre-format the string so that each callsite counts separately for log suppression + std::string error = Str::Format("OpenGL error %s detected at %s:%d", s, fileName, line); + Log::Warn(error); + } +} + +void R_RegisterCvars() +{ + // OpenGL context selection + r_glMajorVersion = Cvar_Get( "r_glMajorVersion", "", CVAR_LATCH ); + r_glMinorVersion = Cvar_Get( "r_glMinorVersion", "", CVAR_LATCH ); + r_glProfile = Cvar_Get( "r_glProfile", "", CVAR_LATCH ); + r_glDebugProfile = Cvar_Get( "r_glDebugProfile", "", CVAR_LATCH ); + r_glDebugMode = Cvar_Get( "r_glDebugMode", "0", CVAR_CHEAT ); + r_glAllowSoftware = Cvar_Get( "r_glAllowSoftware", "0", CVAR_LATCH ); + + // latched and archived variables + r_ext_occlusion_query = Cvar_Get( "r_ext_occlusion_query", "1", CVAR_CHEAT | CVAR_LATCH ); + r_ext_draw_buffers = Cvar_Get( "r_ext_draw_buffers", "1", CVAR_CHEAT | CVAR_LATCH ); + r_ext_vertex_array_object = Cvar_Get( "r_ext_vertex_array_object", "1", CVAR_CHEAT | CVAR_LATCH ); + r_ext_half_float_pixel = Cvar_Get( "r_ext_half_float_pixel", "1", CVAR_CHEAT | CVAR_LATCH ); + r_ext_texture_float = Cvar_Get( "r_ext_texture_float", "1", CVAR_CHEAT | CVAR_LATCH ); + r_ext_texture_integer = Cvar_Get( "r_ext_texture_integer", "1", CVAR_CHEAT | CVAR_LATCH ); + r_ext_texture_rg = Cvar_Get( "r_ext_texture_rg", "1", CVAR_CHEAT | CVAR_LATCH ); + r_ext_texture_filter_anisotropic = Cvar_Get( "r_ext_texture_filter_anisotropic", "4", CVAR_LATCH | CVAR_ARCHIVE ); + r_ext_gpu_shader4 = Cvar_Get( "r_ext_gpu_shader4", "1", CVAR_CHEAT | CVAR_LATCH ); + r_arb_buffer_storage = Cvar_Get( "r_arb_buffer_storage", "1", CVAR_CHEAT | CVAR_LATCH ); + r_arb_map_buffer_range = Cvar_Get( "r_arb_map_buffer_range", "1", CVAR_CHEAT | CVAR_LATCH ); + r_arb_sync = Cvar_Get( "r_arb_sync", "1", CVAR_CHEAT | CVAR_LATCH ); + r_arb_uniform_buffer_object = Cvar_Get( "r_arb_uniform_buffer_object", "1", CVAR_CHEAT | CVAR_LATCH ); + r_arb_texture_gather = Cvar_Get( "r_arb_texture_gather", "1", CVAR_CHEAT | CVAR_LATCH ); + r_arb_gpu_shader5 = Cvar_Get( "r_arb_gpu_shader5", "1", CVAR_CHEAT | CVAR_LATCH ); + + r_picMip = Cvar_Get( "r_picMip", "0", CVAR_LATCH | CVAR_ARCHIVE ); + r_imageMaxDimension = Cvar_Get( "r_imageMaxDimension", "0", CVAR_LATCH | CVAR_ARCHIVE ); + r_ignoreMaterialMinDimension = Cvar_Get( "r_ignoreMaterialMinDimension", "0", CVAR_LATCH | CVAR_ARCHIVE ); + r_ignoreMaterialMaxDimension = Cvar_Get( "r_ignoreMaterialMaxDimension", "0", CVAR_LATCH | CVAR_ARCHIVE ); + r_replaceMaterialMinDimensionIfPresentWithMaxDimension + = Cvar_Get( "r_replaceMaterialMinDimensionIfPresentWithMaxDimension", "0", CVAR_LATCH | CVAR_ARCHIVE ); + r_colorMipLevels = Cvar_Get( "r_colorMipLevels", "0", CVAR_LATCH ); + r_colorbits = Cvar_Get( "r_colorbits", "0", CVAR_LATCH ); + r_alphabits = Cvar_Get( "r_alphabits", "0", CVAR_LATCH ); + r_stencilbits = Cvar_Get( "r_stencilbits", "8", CVAR_LATCH ); + r_depthbits = Cvar_Get( "r_depthbits", "0", CVAR_LATCH ); + r_ext_multisample = Cvar_Get( "r_ext_multisample", "0", CVAR_LATCH | CVAR_ARCHIVE ); + r_mode = Cvar_Get( "r_mode", "-2", CVAR_LATCH | CVAR_ARCHIVE ); + r_noBorder = Cvar_Get( "r_noBorder", "0", CVAR_ARCHIVE ); + r_fullscreen = Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE ); + r_customwidth = Cvar_Get( "r_customwidth", "1600", CVAR_LATCH | CVAR_ARCHIVE ); + r_customheight = Cvar_Get( "r_customheight", "1024", CVAR_LATCH | CVAR_ARCHIVE ); + r_simpleMipMaps = Cvar_Get( "r_simpleMipMaps", "0", CVAR_LATCH ); + r_subdivisions = Cvar_Get( "r_subdivisions", "4", CVAR_LATCH ); + r_dynamicLightCastShadows = Cvar_Get( "r_dynamicLightCastShadows", "1", 0 ); + r_precomputedLighting = Cvar_Get( "r_precomputedLighting", "1", CVAR_LATCH ); + r_vertexLighting = Cvar_Get( "r_vertexLighting", "0", CVAR_LATCH | CVAR_ARCHIVE ); + r_exportTextures = Cvar_Get( "r_exportTextures", "0", 0 ); + r_heatHaze = Cvar_Get( "r_heatHaze", "1", CVAR_LATCH | CVAR_ARCHIVE ); + r_noMarksOnTrisurfs = Cvar_Get( "r_noMarksOnTrisurfs", "1", CVAR_CHEAT ); + r_lazyShaders = Cvar_Get( "r_lazyShaders", "0", 0 ); + + r_forceFog = Cvar_Get( "r_forceFog", "0", CVAR_CHEAT /* | CVAR_LATCH */ ); + AssertCvarRange( r_forceFog, 0.0f, 1.0f, false ); + r_wolfFog = Cvar_Get( "r_wolfFog", "1", CVAR_CHEAT ); + r_noFog = Cvar_Get( "r_noFog", "0", CVAR_CHEAT ); + + r_forceAmbient = Cvar_Get( "r_forceAmbient", "0.125", CVAR_LATCH ); + AssertCvarRange( r_forceAmbient, 0.0f, 0.3f, false ); + + r_smp = Cvar_Get( "r_smp", "0", CVAR_LATCH ); + + // temporary latched variables that can only change over a restart + r_singleShader = Cvar_Get( "r_singleShader", "0", CVAR_CHEAT | CVAR_LATCH ); + r_stitchCurves = Cvar_Get( "r_stitchCurves", "1", CVAR_CHEAT | CVAR_LATCH ); + r_debugShadowMaps = Cvar_Get( "r_debugShadowMaps", "0", CVAR_CHEAT | CVAR_LATCH ); + r_shadowMapLinearFilter = Cvar_Get( "r_shadowMapLinearFilter", "1", CVAR_CHEAT | CVAR_LATCH ); + r_lightBleedReduction = Cvar_Get( "r_lightBleedReduction", "0", CVAR_CHEAT | CVAR_LATCH ); + r_overDarkeningFactor = Cvar_Get( "r_overDarkeningFactor", "30.0", CVAR_CHEAT | CVAR_LATCH ); + r_shadowMapDepthScale = Cvar_Get( "r_shadowMapDepthScale", "1.41", CVAR_CHEAT | CVAR_LATCH ); + + r_parallelShadowSplitWeight = Cvar_Get( "r_parallelShadowSplitWeight", "0.9", CVAR_CHEAT ); + r_parallelShadowSplits = Cvar_Get( "r_parallelShadowSplits", "2", CVAR_CHEAT | CVAR_LATCH ); + AssertCvarRange( r_parallelShadowSplits, 0, MAX_SHADOWMAPS - 1, true ); + + // archived variables that can change at any time + r_lodBias = Cvar_Get( "r_lodBias", "0", 0 ); + r_znear = Cvar_Get( "r_znear", "3", CVAR_CHEAT ); + r_zfar = Cvar_Get( "r_zfar", "0", CVAR_CHEAT ); + r_checkGLErrors = Cvar_Get( "r_ignoreGLErrors", "0", 0 ); + r_fastsky = Cvar_Get( "r_fastsky", "0", CVAR_ARCHIVE ); + r_drawSun = Cvar_Get( "r_drawSun", "0", 0 ); + r_finish = Cvar_Get( "r_finish", "0", CVAR_CHEAT ); + r_textureMode = Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE ); + r_swapInterval = Cvar_Get( "r_swapInterval", "0", CVAR_ARCHIVE ); + r_gamma = Cvar_Get( "r_gamma", "1.0", CVAR_ARCHIVE ); + r_facePlaneCull = Cvar_Get( "r_facePlaneCull", "1", 0 ); + + r_ambientScale = Cvar_Get( "r_ambientScale", "1.0", CVAR_CHEAT | CVAR_LATCH ); + r_lightScale = Cvar_Get( "r_lightScale", "2", CVAR_CHEAT ); + + r_vboFaces = Cvar_Get( "r_vboFaces", "1", CVAR_CHEAT ); + r_vboCurves = Cvar_Get( "r_vboCurves", "1", CVAR_CHEAT ); + r_vboTriangles = Cvar_Get( "r_vboTriangles", "1", CVAR_CHEAT ); + r_vboShadows = Cvar_Get( "r_vboShadows", "1", CVAR_CHEAT ); + r_vboLighting = Cvar_Get( "r_vboLighting", "1", CVAR_CHEAT ); + r_vboModels = Cvar_Get( "r_vboModels", "1", 0 ); + r_vboVertexSkinning = Cvar_Get( "r_vboVertexSkinning", "1", CVAR_LATCH ); + r_vboDeformVertexes = Cvar_Get( "r_vboDeformVertexes", "1", CVAR_LATCH ); + + r_mergeLeafSurfaces = Cvar_Get( "r_mergeLeafSurfaces", "1", CVAR_LATCH ); + + r_evsmPostProcess = Cvar_Get( "r_evsmPostProcess", "0", CVAR_LATCH ); + + r_printShaders = Cvar_Get( "r_printShaders", "0", 0 ); + + r_bloom = Cvar_Get( "r_bloom", "0", CVAR_LATCH | CVAR_ARCHIVE ); + r_bloomBlur = Cvar_Get( "r_bloomBlur", "1.0", CVAR_CHEAT ); + r_bloomPasses = Cvar_Get( "r_bloomPasses", "2", CVAR_CHEAT ); + r_FXAA = Cvar_Get( "r_FXAA", "0", CVAR_LATCH | CVAR_ARCHIVE ); + r_ssao = Cvar_Get( "r_ssao", "0", CVAR_LATCH | CVAR_ARCHIVE ); + + // temporary variables that can change at any time + r_showImages = Cvar_Get( "r_showImages", "0", CVAR_TEMP ); + + r_debugSort = Cvar_Get( "r_debugSort", "0", CVAR_CHEAT ); + + r_nocurves = Cvar_Get( "r_nocurves", "0", CVAR_CHEAT ); + r_lightScissors = Cvar_Get( "r_lightScissors", "1", CVAR_ARCHIVE ); + AssertCvarRange( r_lightScissors, 0, 2, true ); + + r_noLightVisCull = Cvar_Get( "r_noLightVisCull", "0", CVAR_CHEAT ); + r_noInteractionSort = Cvar_Get( "r_noInteractionSort", "0", CVAR_CHEAT ); + r_dynamicLight = Cvar_Get( "r_dynamicLight", "2", CVAR_LATCH | CVAR_ARCHIVE ); + + r_staticLight = Cvar_Get( "r_staticLight", "2", CVAR_ARCHIVE ); + r_drawworld = Cvar_Get( "r_drawworld", "1", CVAR_CHEAT ); + r_portalOnly = Cvar_Get( "r_portalOnly", "0", CVAR_CHEAT ); + r_portalSky = Cvar_Get( "cg_skybox", "1", 0 ); + r_max_portal_levels = Cvar_Get( "r_max_portal_levels", "5", 0 ); + + r_showSmp = Cvar_Get( "r_showSmp", "0", CVAR_CHEAT ); + r_skipBackEnd = Cvar_Get( "r_skipBackEnd", "0", CVAR_CHEAT ); + r_skipLightBuffer = Cvar_Get( "r_skipLightBuffer", "0", CVAR_CHEAT ); + + r_measureOverdraw = Cvar_Get( "r_measureOverdraw", "0", CVAR_CHEAT ); + r_lodScale = Cvar_Get( "r_lodScale", "5", CVAR_CHEAT ); + r_lodTest = Cvar_Get( "r_lodTest", "0.5", CVAR_CHEAT ); + r_norefresh = Cvar_Get( "r_norefresh", "0", CVAR_CHEAT ); + r_drawentities = Cvar_Get( "r_drawentities", "1", CVAR_CHEAT ); + r_drawpolies = Cvar_Get( "r_drawpolies", "1", CVAR_CHEAT ); + r_ignore = Cvar_Get( "r_ignore", "1", CVAR_CHEAT ); + r_nocull = Cvar_Get( "r_nocull", "0", CVAR_CHEAT ); + r_novis = Cvar_Get( "r_novis", "0", CVAR_CHEAT ); + r_showcluster = Cvar_Get( "r_showcluster", "0", CVAR_CHEAT ); + r_speeds = Cvar_Get( "r_speeds", "0", 0 ); + r_verbose = Cvar_Get( "r_verbose", "0", CVAR_CHEAT ); + 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_clear = Cvar_Get( "r_clear", "1", 0 ); + r_offsetFactor = Cvar_Get( "r_offsetFactor", "-1", CVAR_CHEAT ); + r_offsetUnits = Cvar_Get( "r_offsetUnits", "-2", CVAR_CHEAT ); + + r_physicalMapping = Cvar_Get( "r_physicalMapping", "1", CVAR_LATCH | CVAR_ARCHIVE ); + r_specularExponentMin = Cvar_Get( "r_specularExponentMin", "0", CVAR_CHEAT ); + r_specularExponentMax = Cvar_Get( "r_specularExponentMax", "16", CVAR_CHEAT ); + r_specularScale = Cvar_Get( "r_specularScale", "1.0", CVAR_CHEAT | CVAR_LATCH ); + r_specularMapping = Cvar_Get( "r_specularMapping", "1", CVAR_LATCH | CVAR_ARCHIVE ); + r_deluxeMapping = Cvar_Get( "r_deluxeMapping", "1", CVAR_LATCH | CVAR_ARCHIVE ); + r_normalScale = Cvar_Get( "r_normalScale", "1.0", CVAR_ARCHIVE ); + r_normalMapping = Cvar_Get( "r_normalMapping", "1", CVAR_LATCH | CVAR_ARCHIVE ); + r_highQualityNormalMapping = Cvar_Get( "r_highQualityNormalMapping", "0", CVAR_LATCH ); + r_liquidMapping = Cvar_Get( "r_liquidMapping", "0", CVAR_LATCH | CVAR_ARCHIVE ); + r_reliefDepthScale = Cvar_Get( "r_reliefDepthScale", "0.03", CVAR_CHEAT ); + r_reliefMapping = Cvar_Get( "r_reliefMapping", "0", CVAR_LATCH | CVAR_ARCHIVE ); + r_glowMapping = Cvar_Get( "r_glowMapping", "1", CVAR_LATCH ); + r_reflectionMapping = Cvar_Get( "r_reflectionMapping", "0", CVAR_LATCH | CVAR_ARCHIVE ); + + r_wrapAroundLighting = Cvar_Get( "r_wrapAroundLighting", "0.7", CVAR_CHEAT | CVAR_LATCH ); + r_halfLambertLighting = Cvar_Get( "r_halfLambertLighting", "1", CVAR_LATCH | CVAR_ARCHIVE ); + r_rimLighting = Cvar_Get( "r_rimLighting", "0", CVAR_LATCH | CVAR_ARCHIVE ); + r_rimExponent = Cvar_Get( "r_rimExponent", "3", CVAR_CHEAT | CVAR_LATCH ); + AssertCvarRange( r_rimExponent, 0.5, 8.0, false ); + + r_drawBuffer = Cvar_Get( "r_drawBuffer", "GL_BACK", CVAR_CHEAT ); + r_lockpvs = Cvar_Get( "r_lockpvs", "0", CVAR_CHEAT ); + r_noportals = Cvar_Get( "r_noportals", "0", CVAR_CHEAT ); + + r_shadows = Cvar_Get( "cg_shadows", "1", CVAR_LATCH ); + AssertCvarRange( r_shadows, 0, Util::ordinal(shadowingMode_t::SHADOWING_EVSM32), true ); + + r_softShadows = Cvar_Get( "r_softShadows", "0", CVAR_LATCH ); + AssertCvarRange( r_softShadows, 0, 6, true ); + + r_softShadowsPP = Cvar_Get( "r_softShadowsPP", "0", CVAR_LATCH ); + + r_shadowBlur = Cvar_Get( "r_shadowBlur", "2", CVAR_LATCH ); + + r_shadowMapQuality = Cvar_Get( "r_shadowMapQuality", "3", CVAR_LATCH ); + AssertCvarRange( r_shadowMapQuality, 0, 4, true ); + + r_shadowMapSizeUltra = Cvar_Get( "r_shadowMapSizeUltra", "1024", CVAR_LATCH ); + AssertCvarRange( r_shadowMapSizeUltra, 32, 2048, true ); + + r_shadowMapSizeVeryHigh = Cvar_Get( "r_shadowMapSizeVeryHigh", "512", CVAR_LATCH ); + AssertCvarRange( r_shadowMapSizeVeryHigh, 32, 2048, true ); + + r_shadowMapSizeHigh = Cvar_Get( "r_shadowMapSizeHigh", "256", CVAR_LATCH ); + AssertCvarRange( r_shadowMapSizeHigh, 32, 2048, true ); + + r_shadowMapSizeMedium = Cvar_Get( "r_shadowMapSizeMedium", "128", CVAR_LATCH ); + AssertCvarRange( r_shadowMapSizeMedium, 32, 2048, true ); + + r_shadowMapSizeLow = Cvar_Get( "r_shadowMapSizeLow", "64", CVAR_LATCH ); + AssertCvarRange( r_shadowMapSizeLow, 32, 2048, true ); + + r_shadowMapSizeSunUltra = Cvar_Get( "r_shadowMapSizeSunUltra", "1024", CVAR_LATCH ); + AssertCvarRange( r_shadowMapSizeSunUltra, 32, 2048, true ); + + r_shadowMapSizeSunVeryHigh = Cvar_Get( "r_shadowMapSizeSunVeryHigh", "1024", CVAR_LATCH ); + AssertCvarRange( r_shadowMapSizeSunVeryHigh, 512, 2048, true ); + + r_shadowMapSizeSunHigh = Cvar_Get( "r_shadowMapSizeSunHigh", "1024", CVAR_LATCH ); + AssertCvarRange( r_shadowMapSizeSunHigh, 512, 2048, true ); + + r_shadowMapSizeSunMedium = Cvar_Get( "r_shadowMapSizeSunMedium", "1024", CVAR_LATCH ); + AssertCvarRange( r_shadowMapSizeSunMedium, 512, 2048, true ); + + r_shadowMapSizeSunLow = Cvar_Get( "r_shadowMapSizeSunLow", "1024", CVAR_LATCH ); + AssertCvarRange( r_shadowMapSizeSunLow, 512, 2048, true ); + + r_shadowOffsetFactor = Cvar_Get( "r_shadowOffsetFactor", "0", CVAR_CHEAT ); + r_shadowOffsetUnits = Cvar_Get( "r_shadowOffsetUnits", "0", CVAR_CHEAT ); + r_shadowLodBias = Cvar_Get( "r_shadowLodBias", "0", CVAR_CHEAT ); + r_shadowLodScale = Cvar_Get( "r_shadowLodScale", "0.8", CVAR_CHEAT ); + r_noShadowPyramids = Cvar_Get( "r_noShadowPyramids", "0", CVAR_CHEAT ); + r_cullShadowPyramidFaces = Cvar_Get( "r_cullShadowPyramidFaces", "0", CVAR_CHEAT ); + r_cullShadowPyramidCurves = Cvar_Get( "r_cullShadowPyramidCurves", "1", CVAR_CHEAT ); + r_cullShadowPyramidTriangles = Cvar_Get( "r_cullShadowPyramidTriangles", "1", CVAR_CHEAT ); + r_noShadowFrustums = Cvar_Get( "r_noShadowFrustums", "0", CVAR_CHEAT ); + r_noLightFrustums = Cvar_Get( "r_noLightFrustums", "1", CVAR_CHEAT ); + + r_maxPolys = Cvar_Get( "r_maxpolys", "10000", CVAR_LATCH ); // 600 in vanilla Q3A + AssertCvarRange( r_maxPolys, 600, 30000, true ); + + r_maxPolyVerts = Cvar_Get( "r_maxpolyverts", "100000", CVAR_LATCH ); // 3000 in vanilla Q3A + AssertCvarRange( r_maxPolyVerts, 3000, 200000, true ); + + r_showTris = Cvar_Get( "r_showTris", "0", CVAR_CHEAT ); + r_showSky = Cvar_Get( "r_showSky", "0", CVAR_CHEAT ); + r_showShadowVolumes = Cvar_Get( "r_showShadowVolumes", "0", CVAR_CHEAT ); + r_showShadowLod = Cvar_Get( "r_showShadowLod", "0", CVAR_CHEAT ); + r_showShadowMaps = Cvar_Get( "r_showShadowMaps", "0", CVAR_CHEAT ); + r_showSkeleton = Cvar_Get( "r_showSkeleton", "0", CVAR_CHEAT ); + r_showEntityTransforms = Cvar_Get( "r_showEntityTransforms", "0", CVAR_CHEAT ); + r_showLightTransforms = Cvar_Get( "r_showLightTransforms", "0", CVAR_CHEAT ); + r_showLightInteractions = Cvar_Get( "r_showLightInteractions", "0", CVAR_CHEAT ); + r_showLightScissors = Cvar_Get( "r_showLightScissors", "0", CVAR_CHEAT ); + r_showLightBatches = Cvar_Get( "r_showLightBatches", "0", CVAR_CHEAT ); + r_showLightGrid = Cvar_Get( "r_showLightGrid", "0", CVAR_CHEAT ); + r_showLightTiles = Cvar_Get("r_showLightTiles", "0", CVAR_CHEAT | CVAR_LATCH ); + r_showBatches = Cvar_Get( "r_showBatches", "0", CVAR_CHEAT ); + r_showLightMaps = Cvar_Get( "r_showLightMaps", "0", CVAR_CHEAT | CVAR_LATCH ); + r_showDeluxeMaps = Cvar_Get( "r_showDeluxeMaps", "0", CVAR_CHEAT | CVAR_LATCH ); + r_showNormalMaps = Cvar_Get( "r_showNormalMaps", "0", CVAR_CHEAT | CVAR_LATCH ); + r_showMaterialMaps = Cvar_Get( "r_showMaterialMaps", "0", CVAR_CHEAT | CVAR_LATCH ); + r_showAreaPortals = Cvar_Get( "r_showAreaPortals", "0", CVAR_CHEAT ); + r_showCubeProbes = Cvar_Get( "r_showCubeProbes", "0", CVAR_CHEAT ); + r_showBspNodes = Cvar_Get( "r_showBspNodes", "0", CVAR_CHEAT ); + r_showParallelShadowSplits = Cvar_Get( "r_showParallelShadowSplits", "0", CVAR_CHEAT | CVAR_LATCH ); + r_showDecalProjectors = Cvar_Get( "r_showDecalProjectors", "0", CVAR_CHEAT ); + + r_fontScale = Cvar_Get( "r_fontScale", "36", CVAR_LATCH ); +} diff --git a/src/engine/renderer/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp index cc2fda0465..5150cf3d5c 100644 --- a/src/engine/renderer/gl_shader.cpp +++ b/src/engine/renderer/gl_shader.cpp @@ -245,10 +245,10 @@ void GLShaderManager::UpdateShaderProgramUniformLocations( GLShader *shader, sha size_t numUniformBlocks = shader->_uniformBlocks.size(); // create buffer for storing uniform locations - shaderProgram->uniformLocations = ( GLint * ) ri.Z_Malloc( sizeof( GLint ) * numUniforms ); + shaderProgram->uniformLocations = new GLint[numUniforms]{}; // create buffer for uniform firewall - shaderProgram->uniformFirewall = ( byte * ) ri.Z_Malloc( uniformSize ); + shaderProgram->uniformFirewall = new byte[uniformSize]{}; // update uniforms for (GLUniform *uniform : shader->_uniforms) @@ -258,7 +258,7 @@ void GLShaderManager::UpdateShaderProgramUniformLocations( GLShader *shader, sha if( glConfig2.uniformBufferObjectAvailable ) { // create buffer for storing uniform block indexes - shaderProgram->uniformBlockIndexes = ( GLuint * ) ri.Z_Malloc( sizeof( GLuint ) * numUniformBlocks ); + shaderProgram->uniformBlockIndexes = new GLuint[numUniformBlocks]{}; // update uniform blocks for (GLUniformBlock *uniformBlock : shader->_uniformBlocks) @@ -755,7 +755,7 @@ std::string GLShaderManager::BuildGPUShaderText( Str::StringRef mainShaderNa bool GLShaderManager::buildPermutation( GLShader *shader, int macroIndex, int deformIndex ) { std::string compileMacros; - int startTime = ri.Milliseconds(); + int startTime = Sys::Milliseconds(); int endTime; size_t i = macroIndex + ( deformIndex << shader->_compileMacros.size() ); @@ -815,7 +815,7 @@ bool GLShaderManager::buildPermutation( GLShader *shader, int macroIndex, int de GL_CheckErrors(); - endTime = ri.Milliseconds(); + endTime = Sys::Milliseconds(); _totalBuildTime += ( endTime - startTime ); return true; } @@ -960,9 +960,6 @@ void GLShaderManager::SaveShaderBinary( GLShader *shader, size_t programNum ) { #ifdef GL_ARB_get_program_binary GLint binaryLength; - GLuint binarySize = 0; - byte *binary; - byte *binaryptr; GLBinaryHeader shaderHeader{}; // Zero init. shaderProgram_t *shaderProgram; @@ -977,8 +974,6 @@ void GLShaderManager::SaveShaderBinary( GLShader *shader, size_t programNum ) shaderProgram = &shader->_shaderPrograms[ programNum ]; - // find output size - binarySize += sizeof( shaderHeader ); glGetProgramiv( shaderProgram->program, GL_PROGRAM_BINARY_LENGTH, &binaryLength ); // The binary length may be 0 if there is an error. @@ -987,15 +982,10 @@ void GLShaderManager::SaveShaderBinary( GLShader *shader, size_t programNum ) return; } - binarySize += binaryLength; - - binaryptr = binary = ( byte* )ri.Hunk_AllocateTempMemory( binarySize ); - - // reserve space for the header - binaryptr += sizeof( shaderHeader ); + std::unique_ptr binary( new byte[binaryLength] ); // get the program binary and write it to the buffer - glGetProgramBinary( shaderProgram->program, binaryLength, nullptr, &shaderHeader.binaryFormat, binaryptr ); + glGetProgramBinary( shaderProgram->program, binaryLength, nullptr, &shaderHeader.binaryFormat, binary.get() ); // set the header shaderHeader.version = GL_SHADER_VERSION; @@ -1010,13 +1000,14 @@ void GLShaderManager::SaveShaderBinary( GLShader *shader, size_t programNum ) shaderHeader.checkSum = shader->_checkSum; shaderHeader.driverVersionHash = _driverVersionHash; - // write the header to the buffer - memcpy(binary, &shaderHeader, sizeof( shaderHeader ) ); - auto fileName = Str::Format("glsl/%s/%s_%u.bin", shader->GetName(), shader->GetName(), (unsigned int)programNum); - ri.FS_WriteFile(fileName.c_str(), binary, binarySize); - - ri.Hunk_FreeTempMemory( binary ); + try { + FS::File file = FS::HomePath::OpenWrite(fileName); + file.Write(&shaderHeader, sizeof(shaderHeader)); + file.Write(binary.get(), binaryLength); + } catch (const std::system_error& err) { + Log::Notice("Failed to cache shader binary %s: %s", fileName, err.what()); + } #endif } @@ -1178,20 +1169,17 @@ GLuint GLShaderManager::CompileShader( Str::StringRef programName, void GLShaderManager::PrintShaderSource( Str::StringRef programName, GLuint object ) const { - char *dump; int maxLength = 0; glGetShaderiv( object, GL_SHADER_SOURCE_LENGTH, &maxLength ); - dump = ( char * ) ri.Hunk_AllocateTempMemory( maxLength ); - - glGetShaderSource( object, maxLength, &maxLength, dump ); + std::string src; + src.resize(maxLength); + glGetShaderSource( object, maxLength, &maxLength, &src[0] ); + src.resize(maxLength); std::string buffer; std::string delim("\n"); - std::string src(dump); - - ri.Hunk_FreeTempMemory( dump ); int i = 0; size_t pos = 0; @@ -1224,7 +1212,6 @@ void GLShaderManager::PrintShaderSource( Str::StringRef programName, GLuint obje void GLShaderManager::PrintInfoLog( GLuint object) const { - char *msg; int maxLength = 0; std::string msgText; @@ -1242,24 +1229,24 @@ void GLShaderManager::PrintInfoLog( GLuint object) const return; } - msg = ( char * ) ri.Hunk_AllocateTempMemory( maxLength ); + std::string msg; + msg.resize(maxLength); if ( glIsShader( object ) ) { - glGetShaderInfoLog( object, maxLength, &maxLength, msg ); + glGetShaderInfoLog( object, maxLength, &maxLength, &msg[0] ); msgText = "Compile log:"; } else if ( glIsProgram( object ) ) { - glGetProgramInfoLog( object, maxLength, &maxLength, msg ); + glGetProgramInfoLog( object, maxLength, &maxLength, &msg[0] ); msgText = "Link log:"; } + msg.resize(maxLength); if (maxLength > 0) msgText += '\n'; msgText += msg; Log::Warn(msgText); - - ri.Hunk_FreeTempMemory( msg ); } void GLShaderManager::LinkProgram( GLuint program ) const @@ -2197,3 +2184,224 @@ void GLShader_fxaa::BuildShaderFragmentLibNames( std::string& fragmentInlines ) { fragmentInlines += "fxaa3_11"; } + +void GL_BindProgram( shaderProgram_t *program ) +{ + if ( !program ) + { + GL_BindNullProgram(); + return; + } + + if ( glState.currentProgram != program ) + { + glUseProgram( program->program ); + glState.currentProgram = program; + } +} + +void GL_BindNullProgram() +{ + if ( r_logFile->integer ) + { + GLimp_LogComment( "--- GL_BindNullProgram ---\n" ); + } + + if ( glState.currentProgram ) + { + glUseProgram( 0 ); + glState.currentProgram = nullptr; + } +} + +static void GLSL_InitGPUShadersOrError() +{ + // make sure the render thread is stopped + R_SyncRenderThread(); + + GL_CheckErrors(); + + gl_shaderManager.InitDriverInfo(); + + // single texture rendering + gl_shaderManager.GenerateBuiltinHeaders(); + // single texture rendering + gl_shaderManager.load( gl_genericShader ); + + // standard light mapping + gl_shaderManager.load( gl_lightMappingShader ); + + // Deprecated forward renderer uses r_dynamicLight -1 + if ( r_dynamicLight->integer < 0 ) + { + // omni-directional specular bump mapping ( Doom3 style ) + gl_shaderManager.load( gl_forwardLightingShader_omniXYZ ); + + // projective lighting ( Doom3 style ) + gl_shaderManager.load( gl_forwardLightingShader_projXYZ ); + + // directional sun lighting ( Doom3 style ) + gl_shaderManager.load( gl_forwardLightingShader_directionalSun ); + } + else if ( r_dynamicLight->integer > 0 ) + { + gl_shaderManager.load( gl_depthtile1Shader ); + gl_shaderManager.load( gl_depthtile2Shader ); + gl_shaderManager.load( gl_lighttileShader ); + } + +#if !defined( GLSL_COMPILE_STARTUP_ONLY ) + + gl_shaderManager.load( gl_depthToColorShader ); + +#endif // #if !defined(GLSL_COMPILE_STARTUP_ONLY) + + // shadowmap distance compression + gl_shaderManager.load( gl_shadowFillShader ); + + if ( r_reflectionMapping->integer != 0 ) + { + // bumped cubemap reflection for abitrary polygons ( EMBM ) + gl_shaderManager.load( gl_reflectionShader ); + } + + // skybox drawing for abitrary polygons + gl_shaderManager.load( gl_skyboxShader ); + + // Q3A volumetric fog + gl_shaderManager.load( gl_fogQuake3Shader ); + + // global fog post process effect + gl_shaderManager.load( gl_fogGlobalShader ); + + // heatHaze post process effect + gl_shaderManager.load( gl_heatHazeShader ); + + // NOTE: screen shader seems to be only used by bloom post process effect. + if ( r_bloom->integer != 0 ) + { + // screen post process effect + gl_shaderManager.load( gl_screenShader ); + } + + // portal process effect + gl_shaderManager.load( gl_portalShader ); + + // LDR bright pass filter + gl_shaderManager.load( gl_contrastShader ); + + // camera post process effect + gl_shaderManager.load( gl_cameraEffectsShader ); + + // gaussian blur + gl_shaderManager.load( gl_blurXShader ); + + gl_shaderManager.load( gl_blurYShader ); + + // debug utils + gl_shaderManager.load( gl_debugShadowMapShader ); + + if ( r_liquidMapping->integer != 0 ) + { + gl_shaderManager.load( gl_liquidShader ); + } + +#if !defined( GLSL_COMPILE_STARTUP_ONLY ) + + gl_shaderManager.load( gl_volumetricFogShader ); + +#endif // #if !defined(GLSL_COMPILE_STARTUP_ONLY) + + /* NOTE: motionblur is enabled by cg_motionblur which is a client cvar + so we have to build it in all cases. */ + gl_shaderManager.load( gl_motionblurShader ); + + if (GLEW_ARB_texture_gather) + { + if (r_ssao->integer) + { + gl_shaderManager.load(gl_ssaoShader); + } + } + else + { + Log::Warn("SSAO not used because GL_ARB_texture_gather is not available."); + } + + if ( r_FXAA->integer != 0 ) + { + gl_shaderManager.load( gl_fxaaShader ); + } + + if ( !r_lazyShaders->integer ) + { + gl_shaderManager.buildAll(); + } +} + +void GLSL_InitGPUShaders() +{ + /* + Without a shaderpath option, the shader debugging cycle is like this: + 1. Change shader file(s). + 2. Run script to convert shader files into c++, storing them in shaders.cpp + 3. Recompile app to pickup the new shaders.cpp changes. + 4. Run the app and get to the point required to check work. + 5. If the change failed or succeeded but you want to make more changes restart at step 1. + + Alternatively, if set shaderpath "c:/unvanquished/main" is used, the cycle is: + 1. Change shader file(s) - don't run the buildshaders script unless samples.cpp is missing. + 2. Start the app, the app will load the shader files directly. + If there is a problem the app will revert to the last working changes + in samples.cpp, so need to restart the app. + 3. Fix the problem shader files + 4. Do /glsl_restart at the app console to reload them. Repeat from step 3 as needed. + + Note that unv will respond by listing the files it thinks are different. + If this matches your expectations then it's not an error. + Note foward slashes (like those used in windows pathnames are processed + as escape characters by the Unvanquished command processor, + so use two forward slashes in that case. + */ + + auto shaderPath = GetShaderPath(); + if (shaderPath.empty()) + shaderKind = ShaderKind::BuiltIn; + else + shaderKind = ShaderKind::External; + + bool externalFailed = false; + if (shaderKind == ShaderKind::External) + { + try + { + Log::Warn("Loading external shaders."); + GLSL_InitGPUShadersOrError(); + Log::Warn("External shaders in use."); + } + catch (const ShaderException& e) + { + Log::Warn("External shaders failed: %s", e.what()); + Log::Warn("Attempting to use built in shaders instead."); + shaderKind = ShaderKind::BuiltIn; + externalFailed = true; + } + } + + if (shaderKind == ShaderKind::BuiltIn) + { + // Let the user know if we are transitioning from external to + // built-in shaders. We won't alert them if we were already using + // built-in shaders as this is the normal case. + try + { + GLSL_InitGPUShadersOrError(); + } + catch (const ShaderException&e) + { + Sys::Error("Built-in shaders failed: %s", e.what()); // Fatal. + }; + if (externalFailed) + Log::Warn("Now using built-in shaders because external shaders failed."); + } +} diff --git a/src/engine/renderer/gl_shader.h b/src/engine/renderer/gl_shader.h index 5dea410a93..415c9f9732 100644 --- a/src/engine/renderer/gl_shader.h +++ b/src/engine/renderer/gl_shader.h @@ -168,20 +168,9 @@ class GLShader glDeleteShader( p->FS ); } - if ( p->uniformFirewall ) - { - ri.Free( p->uniformFirewall ); - } - - if ( p->uniformLocations ) - { - ri.Free( p->uniformLocations ); - } - - if ( p->uniformBlockIndexes ) - { - ri.Free( p->uniformBlockIndexes ); - } + delete[] p->uniformFirewall; + delete[] p->uniformLocations; + delete[] p->uniformBlockIndexes; } } diff --git a/src/engine/renderer/shader_test_app.cpp b/src/engine/renderer/shader_test_app.cpp new file mode 100644 index 0000000000..05bf1e1a76 --- /dev/null +++ b/src/engine/renderer/shader_test_app.cpp @@ -0,0 +1,70 @@ +/* +=========================================================================== +Daemon BSD Source Code +Copyright (c) 2021, Daemon Developers +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Daemon developers nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +=========================================================================== +*/ + +#include + +#include "framework/System.h" +#include "framework/Application.h" +#include "framework/CommandSystem.h" +#include "tr_local.h" + + + + +void GL_VertexAttribsState(uint32_t) {} +bool CL_WWWBadChecksum(const char*) { return false; } +void R_SyncRenderThread() {} +void GLSL_InitGPUShaders(); +void GLimp_InitExtensions(); + +namespace Application { + +using BufferType = char[4]; +static ALIGNED(4, BufferType) buffer; // 1x1, 4 bytes per pixel + +class ShaderTestApplication : public Application { + public: + void Frame() override { + OSMesaContext context; + if (!(context = OSMesaCreateContext(OSMESA_RGBA, nullptr)) || + !OSMesaMakeCurrent(context, buffer, GL_UNSIGNED_BYTE, 1, 1)) { + Sys::Error("Can't initialize OSMesa"); + } + R_RegisterCvars(); + GLimp_InitExtensions(); + glConfig2.shadingLanguageVersion = 120; // TODO make a cvar + GLSL_InitGPUShaders(); + Sys::Quit("GLSL shaders compiled successfully"); + } +}; + +INSTANTIATE_APPLICATION(ShaderTestApplication) + +} diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index 420b71a4c9..83f335bc25 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -98,35 +98,6 @@ void BindAnimatedImage( textureBundle_t *bundle ) GL_Bind( bundle->image[ index ] ); } -void GL_BindProgram( shaderProgram_t *program ) -{ - if ( !program ) - { - GL_BindNullProgram(); - return; - } - - if ( glState.currentProgram != program ) - { - glUseProgram( program->program ); - glState.currentProgram = program; - } -} - -void GL_BindNullProgram() -{ - if ( r_logFile->integer ) - { - GLimp_LogComment( "--- GL_BindNullProgram ---\n" ); - } - - if ( glState.currentProgram ) - { - glUseProgram( 0 ); - glState.currentProgram = nullptr; - } -} - void GL_SelectTexture( int unit ) { if ( glState.currenttmu == unit ) diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index e833c8f4ff..3534c6cd37 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -23,264 +23,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // tr_init.c -- functions that are not called every frame #include "tr_local.h" - glconfig_t glConfig; - glconfig2_t glConfig2; - - glstate_t glState; - float displayAspect = 0.0f; static void GfxInfo_f(); - cvar_t *r_glMajorVersion; - cvar_t *r_glMinorVersion; - cvar_t *r_glProfile; - cvar_t *r_glDebugProfile; - cvar_t *r_glDebugMode; - cvar_t *r_glAllowSoftware; - - cvar_t *r_verbose; - cvar_t *r_ignore; - - cvar_t *r_znear; - cvar_t *r_zfar; - - cvar_t *r_smp; - cvar_t *r_showSmp; - cvar_t *r_skipBackEnd; - cvar_t *r_skipLightBuffer; - - cvar_t *r_measureOverdraw; - - cvar_t *r_fastsky; - cvar_t *r_drawSun; - - cvar_t *r_lodBias; - cvar_t *r_lodScale; - cvar_t *r_lodTest; - - cvar_t *r_norefresh; - cvar_t *r_drawentities; - cvar_t *r_drawworld; - cvar_t *r_drawpolies; - cvar_t *r_speeds; - cvar_t *r_novis; - cvar_t *r_nocull; - cvar_t *r_facePlaneCull; - cvar_t *r_showcluster; - cvar_t *r_nocurves; - cvar_t *r_lightScissors; - cvar_t *r_noLightVisCull; - cvar_t *r_noInteractionSort; - cvar_t *r_dynamicLight; - cvar_t *r_staticLight; - cvar_t *r_dynamicLightCastShadows; - cvar_t *r_precomputedLighting; - cvar_t *r_vertexLighting; - cvar_t *r_exportTextures; - cvar_t *r_heatHaze; - cvar_t *r_noMarksOnTrisurfs; - cvar_t *r_lazyShaders; - - cvar_t *r_ext_occlusion_query; - cvar_t *r_ext_draw_buffers; - cvar_t *r_ext_vertex_array_object; - cvar_t *r_ext_half_float_pixel; - cvar_t *r_ext_texture_float; - cvar_t *r_ext_texture_integer; - cvar_t *r_ext_texture_rg; - cvar_t *r_ext_texture_filter_anisotropic; - cvar_t *r_ext_gpu_shader4; - cvar_t *r_arb_buffer_storage; - cvar_t *r_arb_map_buffer_range; - cvar_t *r_arb_sync; - cvar_t *r_arb_uniform_buffer_object; - cvar_t *r_arb_texture_gather; - cvar_t *r_arb_gpu_shader5; - - cvar_t *r_checkGLErrors; - cvar_t *r_logFile; - - cvar_t *r_stencilbits; - cvar_t *r_depthbits; - cvar_t *r_colorbits; - cvar_t *r_alphabits; - cvar_t *r_ext_multisample; - - cvar_t *r_drawBuffer; - cvar_t *r_shadows; - cvar_t *r_softShadows; - cvar_t *r_softShadowsPP; - cvar_t *r_shadowBlur; - - cvar_t *r_shadowMapQuality; - cvar_t *r_shadowMapSizeUltra; - cvar_t *r_shadowMapSizeVeryHigh; - cvar_t *r_shadowMapSizeHigh; - cvar_t *r_shadowMapSizeMedium; - cvar_t *r_shadowMapSizeLow; - - cvar_t *r_shadowMapSizeSunUltra; - cvar_t *r_shadowMapSizeSunVeryHigh; - cvar_t *r_shadowMapSizeSunHigh; - cvar_t *r_shadowMapSizeSunMedium; - cvar_t *r_shadowMapSizeSunLow; - - cvar_t *r_shadowOffsetFactor; - cvar_t *r_shadowOffsetUnits; - cvar_t *r_shadowLodBias; - cvar_t *r_shadowLodScale; - cvar_t *r_noShadowPyramids; - cvar_t *r_cullShadowPyramidFaces; - cvar_t *r_cullShadowPyramidCurves; - cvar_t *r_cullShadowPyramidTriangles; - cvar_t *r_debugShadowMaps; - cvar_t *r_noShadowFrustums; - cvar_t *r_noLightFrustums; - cvar_t *r_shadowMapLinearFilter; - cvar_t *r_lightBleedReduction; - cvar_t *r_overDarkeningFactor; - cvar_t *r_shadowMapDepthScale; - cvar_t *r_parallelShadowSplits; - cvar_t *r_parallelShadowSplitWeight; - - cvar_t *r_mode; - cvar_t *r_nobind; - cvar_t *r_singleShader; - cvar_t *r_colorMipLevels; - cvar_t *r_picMip; - cvar_t *r_imageMaxDimension; - cvar_t *r_ignoreMaterialMinDimension; - cvar_t *r_ignoreMaterialMaxDimension; - cvar_t *r_replaceMaterialMinDimensionIfPresentWithMaxDimension; - cvar_t *r_finish; - cvar_t *r_clear; - cvar_t *r_swapInterval; - cvar_t *r_textureMode; - cvar_t *r_offsetFactor; - cvar_t *r_offsetUnits; - - cvar_t *r_physicalMapping; - cvar_t *r_specularExponentMin; - cvar_t *r_specularExponentMax; - cvar_t *r_specularScale; - cvar_t *r_specularMapping; - cvar_t *r_deluxeMapping; - cvar_t *r_normalScale; - cvar_t *r_normalMapping; - cvar_t *r_liquidMapping; - cvar_t *r_highQualityNormalMapping; - cvar_t *r_reliefDepthScale; - cvar_t *r_reliefMapping; - cvar_t *r_glowMapping; - cvar_t *r_reflectionMapping; - - cvar_t *r_wrapAroundLighting; - cvar_t *r_halfLambertLighting; - cvar_t *r_rimLighting; - cvar_t *r_rimExponent; - cvar_t *r_gamma; - cvar_t *r_lockpvs; - cvar_t *r_noportals; - cvar_t *r_portalOnly; - cvar_t *r_portalSky; - cvar_t *r_max_portal_levels; - - cvar_t *r_subdivisions; - cvar_t *r_stitchCurves; - - cvar_t *r_noBorder; - cvar_t *r_fullscreen; - - cvar_t *r_customwidth; - cvar_t *r_customheight; - - cvar_t *r_debugSurface; - cvar_t *r_simpleMipMaps; - - cvar_t *r_showImages; - - cvar_t *r_forceFog; - cvar_t *r_wolfFog; - cvar_t *r_noFog; - - cvar_t *r_forceAmbient; - cvar_t *r_ambientScale; - cvar_t *r_lightScale; - cvar_t *r_debugSort; - cvar_t *r_printShaders; - - cvar_t *r_maxPolys; - cvar_t *r_maxPolyVerts; - - cvar_t *r_showTris; - cvar_t *r_showSky; - cvar_t *r_showShadowVolumes; - cvar_t *r_showShadowLod; - cvar_t *r_showShadowMaps; - cvar_t *r_showSkeleton; - cvar_t *r_showEntityTransforms; - cvar_t *r_showLightTransforms; - cvar_t *r_showLightInteractions; - cvar_t *r_showLightScissors; - cvar_t *r_showLightBatches; - cvar_t *r_showLightGrid; - cvar_t *r_showLightTiles; - cvar_t *r_showBatches; - cvar_t *r_showLightMaps; - cvar_t *r_showDeluxeMaps; - cvar_t *r_showNormalMaps; - cvar_t *r_showMaterialMaps; - cvar_t *r_showAreaPortals; - cvar_t *r_showCubeProbes; - cvar_t *r_showBspNodes; - cvar_t *r_showParallelShadowSplits; - cvar_t *r_showDecalProjectors; - - cvar_t *r_vboFaces; - cvar_t *r_vboCurves; - cvar_t *r_vboTriangles; - cvar_t *r_vboShadows; - cvar_t *r_vboLighting; - cvar_t *r_vboModels; - cvar_t *r_vboVertexSkinning; - cvar_t *r_vboDeformVertexes; - - cvar_t *r_mergeLeafSurfaces; - - cvar_t *r_bloom; - cvar_t *r_bloomBlur; - cvar_t *r_bloomPasses; - cvar_t *r_FXAA; - cvar_t *r_ssao; - - cvar_t *r_evsmPostProcess; - - cvar_t *r_fontScale; - - void AssertCvarRange( cvar_t *cv, float minVal, float maxVal, bool shouldBeIntegral ) - { - if ( shouldBeIntegral ) - { - if ( cv->value != static_cast(cv->integer) ) - { - Log::Warn("cvar '%s' must be integral (%f)", cv->name, cv->value ); - ri.Cvar_Set( cv->name, va( "%d", cv->integer ) ); - } - } - - if ( cv->value < minVal ) - { - Log::Warn("cvar '%s' out of range (%g < %g)", cv->name, cv->value, minVal ); - ri.Cvar_Set( cv->name, va( "%f", minVal ) ); - } - else if ( cv->value > maxVal ) - { - Log::Warn("cvar '%s' out of range (%g > %g)", cv->name, cv->value, maxVal ); - ri.Cvar_Set( cv->name, va( "%f", maxVal ) ); - } - } - /* ** InitOpenGL ** @@ -367,69 +113,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA return true; } - /* - ================== - GL_CheckErrors - - Must not be called while the backend rendering thread is running - ================== - */ - void GL_CheckErrors_( const char *fileName, int line ) - { - int err; - char s[ 128 ]; - - if ( !checkGLErrors() ) - { - return; - } - - while ( ( err = glGetError() ) != GL_NO_ERROR ) - { - switch ( err ) - { - case GL_INVALID_ENUM: - strcpy( s, "GL_INVALID_ENUM" ); - break; - - case GL_INVALID_VALUE: - strcpy( s, "GL_INVALID_VALUE" ); - break; - - case GL_INVALID_OPERATION: - strcpy( s, "GL_INVALID_OPERATION" ); - break; - - case GL_STACK_OVERFLOW: - strcpy( s, "GL_STACK_OVERFLOW" ); - break; - - case GL_STACK_UNDERFLOW: - strcpy( s, "GL_STACK_UNDERFLOW" ); - break; - - case GL_OUT_OF_MEMORY: - strcpy( s, "GL_OUT_OF_MEMORY" ); - break; - - case GL_TABLE_TOO_LARGE: - strcpy( s, "GL_TABLE_TOO_LARGE" ); - break; - - case GL_INVALID_FRAMEBUFFER_OPERATION: - strcpy( s, "GL_INVALID_FRAMEBUFFER_OPERATION" ); - break; - - default: - Com_sprintf( s, sizeof( s ), "0x%X", err ); - break; - } - // Pre-format the string so that each callsite counts separately for log suppression - std::string error = Str::Format("OpenGL error %s detected at %s:%d", s, fileName, line); - Log::Warn(error); - } - } - /* ** R_GetModeInfo */ @@ -1027,283 +710,18 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p */ void R_Register() { - // OpenGL context selection - r_glMajorVersion = ri.Cvar_Get( "r_glMajorVersion", "", CVAR_LATCH ); - r_glMinorVersion = ri.Cvar_Get( "r_glMinorVersion", "", CVAR_LATCH ); - r_glProfile = ri.Cvar_Get( "r_glProfile", "", CVAR_LATCH ); - 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 ); - - // latched and archived variables - r_ext_occlusion_query = ri.Cvar_Get( "r_ext_occlusion_query", "1", CVAR_CHEAT | CVAR_LATCH ); - r_ext_draw_buffers = ri.Cvar_Get( "r_ext_draw_buffers", "1", CVAR_CHEAT | CVAR_LATCH ); - r_ext_vertex_array_object = ri.Cvar_Get( "r_ext_vertex_array_object", "1", CVAR_CHEAT | CVAR_LATCH ); - r_ext_half_float_pixel = ri.Cvar_Get( "r_ext_half_float_pixel", "1", CVAR_CHEAT | CVAR_LATCH ); - r_ext_texture_float = ri.Cvar_Get( "r_ext_texture_float", "1", CVAR_CHEAT | CVAR_LATCH ); - r_ext_texture_integer = ri.Cvar_Get( "r_ext_texture_integer", "1", CVAR_CHEAT | CVAR_LATCH ); - r_ext_texture_rg = ri.Cvar_Get( "r_ext_texture_rg", "1", CVAR_CHEAT | CVAR_LATCH ); - r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic", "4", CVAR_LATCH | CVAR_ARCHIVE ); - r_ext_gpu_shader4 = ri.Cvar_Get( "r_ext_gpu_shader4", "1", CVAR_CHEAT | CVAR_LATCH ); - r_arb_buffer_storage = ri.Cvar_Get( "r_arb_buffer_storage", "1", CVAR_CHEAT | CVAR_LATCH ); - r_arb_map_buffer_range = ri.Cvar_Get( "r_arb_map_buffer_range", "1", CVAR_CHEAT | CVAR_LATCH ); - r_arb_sync = ri.Cvar_Get( "r_arb_sync", "1", CVAR_CHEAT | CVAR_LATCH ); - r_arb_uniform_buffer_object = ri.Cvar_Get( "r_arb_uniform_buffer_object", "1", CVAR_CHEAT | CVAR_LATCH ); - r_arb_texture_gather = ri.Cvar_Get( "r_arb_texture_gather", "1", CVAR_CHEAT | CVAR_LATCH ); - r_arb_gpu_shader5 = ri.Cvar_Get( "r_arb_gpu_shader5", "1", CVAR_CHEAT | CVAR_LATCH ); - - r_picMip = ri.Cvar_Get( "r_picMip", "0", CVAR_LATCH | CVAR_ARCHIVE ); - r_imageMaxDimension = ri.Cvar_Get( "r_imageMaxDimension", "0", CVAR_LATCH | CVAR_ARCHIVE ); - r_ignoreMaterialMinDimension = ri.Cvar_Get( "r_ignoreMaterialMinDimension", "0", CVAR_LATCH | CVAR_ARCHIVE ); - r_ignoreMaterialMaxDimension = ri.Cvar_Get( "r_ignoreMaterialMaxDimension", "0", CVAR_LATCH | CVAR_ARCHIVE ); - r_replaceMaterialMinDimensionIfPresentWithMaxDimension - = ri.Cvar_Get( "r_replaceMaterialMinDimensionIfPresentWithMaxDimension", "0", CVAR_LATCH | CVAR_ARCHIVE ); - 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 ); - r_noBorder = ri.Cvar_Get( "r_noBorder", "0", CVAR_ARCHIVE ); - r_fullscreen = ri.Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE ); - r_customwidth = ri.Cvar_Get( "r_customwidth", "1600", CVAR_LATCH | CVAR_ARCHIVE ); - r_customheight = ri.Cvar_Get( "r_customheight", "1024", CVAR_LATCH | CVAR_ARCHIVE ); - r_simpleMipMaps = ri.Cvar_Get( "r_simpleMipMaps", "0", CVAR_LATCH ); - r_subdivisions = ri.Cvar_Get( "r_subdivisions", "4", CVAR_LATCH ); - r_dynamicLightCastShadows = ri.Cvar_Get( "r_dynamicLightCastShadows", "1", 0 ); - r_precomputedLighting = ri.Cvar_Get( "r_precomputedLighting", "1", CVAR_LATCH ); - r_vertexLighting = ri.Cvar_Get( "r_vertexLighting", "0", CVAR_LATCH | CVAR_ARCHIVE ); - r_exportTextures = ri.Cvar_Get( "r_exportTextures", "0", 0 ); - r_heatHaze = ri.Cvar_Get( "r_heatHaze", "1", CVAR_LATCH | CVAR_ARCHIVE ); - r_noMarksOnTrisurfs = ri.Cvar_Get( "r_noMarksOnTrisurfs", "1", CVAR_CHEAT ); - r_lazyShaders = ri.Cvar_Get( "r_lazyShaders", "0", 0 ); - - r_forceFog = ri.Cvar_Get( "r_forceFog", "0", CVAR_CHEAT /* | CVAR_LATCH */ ); - AssertCvarRange( r_forceFog, 0.0f, 1.0f, false ); - r_wolfFog = ri.Cvar_Get( "r_wolfFog", "1", CVAR_CHEAT ); - r_noFog = ri.Cvar_Get( "r_noFog", "0", CVAR_CHEAT ); - - r_forceAmbient = ri.Cvar_Get( "r_forceAmbient", "0.125", CVAR_LATCH ); - AssertCvarRange( r_forceAmbient, 0.0f, 0.3f, false ); - - r_smp = ri.Cvar_Get( "r_smp", "0", CVAR_LATCH ); - - // temporary latched variables that can only change over a restart - r_singleShader = ri.Cvar_Get( "r_singleShader", "0", CVAR_CHEAT | CVAR_LATCH ); - r_stitchCurves = ri.Cvar_Get( "r_stitchCurves", "1", CVAR_CHEAT | CVAR_LATCH ); - r_debugShadowMaps = ri.Cvar_Get( "r_debugShadowMaps", "0", CVAR_CHEAT | CVAR_LATCH ); - r_shadowMapLinearFilter = ri.Cvar_Get( "r_shadowMapLinearFilter", "1", CVAR_CHEAT | CVAR_LATCH ); - r_lightBleedReduction = ri.Cvar_Get( "r_lightBleedReduction", "0", CVAR_CHEAT | CVAR_LATCH ); - r_overDarkeningFactor = ri.Cvar_Get( "r_overDarkeningFactor", "30.0", CVAR_CHEAT | CVAR_LATCH ); - r_shadowMapDepthScale = ri.Cvar_Get( "r_shadowMapDepthScale", "1.41", CVAR_CHEAT | CVAR_LATCH ); - - r_parallelShadowSplitWeight = ri.Cvar_Get( "r_parallelShadowSplitWeight", "0.9", CVAR_CHEAT ); - r_parallelShadowSplits = ri.Cvar_Get( "r_parallelShadowSplits", "2", CVAR_CHEAT | CVAR_LATCH ); - AssertCvarRange( r_parallelShadowSplits, 0, MAX_SHADOWMAPS - 1, true ); - - // archived variables that can change at any time - r_lodBias = ri.Cvar_Get( "r_lodBias", "0", 0 ); - r_znear = ri.Cvar_Get( "r_znear", "3", CVAR_CHEAT ); - r_zfar = ri.Cvar_Get( "r_zfar", "0", CVAR_CHEAT ); - r_checkGLErrors = ri.Cvar_Get( "r_checkGLErrors", "-1", 0 ); - r_fastsky = ri.Cvar_Get( "r_fastsky", "0", CVAR_ARCHIVE ); - r_drawSun = ri.Cvar_Get( "r_drawSun", "0", 0 ); - r_finish = ri.Cvar_Get( "r_finish", "0", CVAR_CHEAT ); - r_textureMode = ri.Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE ); - r_swapInterval = ri.Cvar_Get( "r_swapInterval", "0", CVAR_ARCHIVE ); - r_gamma = ri.Cvar_Get( "r_gamma", "1.0", CVAR_ARCHIVE ); - r_facePlaneCull = ri.Cvar_Get( "r_facePlaneCull", "1", 0 ); - - r_ambientScale = ri.Cvar_Get( "r_ambientScale", "1.0", CVAR_CHEAT | CVAR_LATCH ); - r_lightScale = ri.Cvar_Get( "r_lightScale", "2", CVAR_CHEAT ); - - r_vboFaces = ri.Cvar_Get( "r_vboFaces", "1", CVAR_CHEAT ); - r_vboCurves = ri.Cvar_Get( "r_vboCurves", "1", CVAR_CHEAT ); - r_vboTriangles = ri.Cvar_Get( "r_vboTriangles", "1", CVAR_CHEAT ); - r_vboShadows = ri.Cvar_Get( "r_vboShadows", "1", CVAR_CHEAT ); - r_vboLighting = ri.Cvar_Get( "r_vboLighting", "1", CVAR_CHEAT ); - r_vboModels = ri.Cvar_Get( "r_vboModels", "1", CVAR_LATCH ); - r_vboVertexSkinning = ri.Cvar_Get( "r_vboVertexSkinning", "1", CVAR_LATCH ); - r_vboDeformVertexes = ri.Cvar_Get( "r_vboDeformVertexes", "1", CVAR_LATCH ); - - r_mergeLeafSurfaces = ri.Cvar_Get( "r_mergeLeafSurfaces", "1", CVAR_LATCH ); - - r_evsmPostProcess = ri.Cvar_Get( "r_evsmPostProcess", "0", CVAR_LATCH ); - - r_printShaders = ri.Cvar_Get( "r_printShaders", "0", 0 ); - - r_bloom = ri.Cvar_Get( "r_bloom", "0", CVAR_LATCH | CVAR_ARCHIVE ); - r_bloomBlur = ri.Cvar_Get( "r_bloomBlur", "1.0", CVAR_CHEAT ); - r_bloomPasses = ri.Cvar_Get( "r_bloomPasses", "2", CVAR_CHEAT ); - r_FXAA = ri.Cvar_Get( "r_FXAA", "0", CVAR_LATCH | CVAR_ARCHIVE ); - r_ssao = ri.Cvar_Get( "r_ssao", "0", CVAR_LATCH | CVAR_ARCHIVE ); - - // temporary variables that can change at any time - r_showImages = ri.Cvar_Get( "r_showImages", "0", CVAR_TEMP ); - - r_debugSort = ri.Cvar_Get( "r_debugSort", "0", CVAR_CHEAT ); - - r_nocurves = ri.Cvar_Get( "r_nocurves", "0", CVAR_CHEAT ); - r_lightScissors = ri.Cvar_Get( "r_lightScissors", "1", CVAR_ARCHIVE ); - AssertCvarRange( r_lightScissors, 0, 2, true ); - - r_noLightVisCull = ri.Cvar_Get( "r_noLightVisCull", "0", CVAR_CHEAT ); - r_noInteractionSort = ri.Cvar_Get( "r_noInteractionSort", "0", CVAR_CHEAT ); - r_dynamicLight = ri.Cvar_Get( "r_dynamicLight", "2", CVAR_LATCH | CVAR_ARCHIVE ); - - r_staticLight = ri.Cvar_Get( "r_staticLight", "2", CVAR_ARCHIVE ); - r_drawworld = ri.Cvar_Get( "r_drawworld", "1", CVAR_CHEAT ); - r_portalOnly = ri.Cvar_Get( "r_portalOnly", "0", CVAR_CHEAT ); - r_portalSky = ri.Cvar_Get( "cg_skybox", "1", 0 ); - r_max_portal_levels = ri.Cvar_Get( "r_max_portal_levels", "5", 0 ); - - r_showSmp = ri.Cvar_Get( "r_showSmp", "0", CVAR_CHEAT ); - r_skipBackEnd = ri.Cvar_Get( "r_skipBackEnd", "0", CVAR_CHEAT ); - r_skipLightBuffer = ri.Cvar_Get( "r_skipLightBuffer", "0", CVAR_CHEAT ); - - r_measureOverdraw = ri.Cvar_Get( "r_measureOverdraw", "0", CVAR_CHEAT ); - r_lodScale = ri.Cvar_Get( "r_lodScale", "5", CVAR_CHEAT ); - r_lodTest = ri.Cvar_Get( "r_lodTest", "0.5", CVAR_CHEAT ); - r_norefresh = ri.Cvar_Get( "r_norefresh", "0", CVAR_CHEAT ); - r_drawentities = ri.Cvar_Get( "r_drawentities", "1", CVAR_CHEAT ); - r_drawpolies = ri.Cvar_Get( "r_drawpolies", "1", CVAR_CHEAT ); - r_ignore = ri.Cvar_Get( "r_ignore", "1", CVAR_CHEAT ); - r_nocull = ri.Cvar_Get( "r_nocull", "0", CVAR_CHEAT ); - r_novis = ri.Cvar_Get( "r_novis", "0", CVAR_CHEAT ); - r_showcluster = ri.Cvar_Get( "r_showcluster", "0", CVAR_CHEAT ); - r_speeds = ri.Cvar_Get( "r_speeds", "0", 0 ); - r_verbose = ri.Cvar_Get( "r_verbose", "0", CVAR_CHEAT ); - r_logFile = ri.Cvar_Get( "r_logFile", "0", CVAR_CHEAT ); - r_debugSurface = ri.Cvar_Get( "r_debugSurface", "0", CVAR_CHEAT ); - r_nobind = ri.Cvar_Get( "r_nobind", "0", CVAR_CHEAT ); - r_clear = ri.Cvar_Get( "r_clear", "1", 0 ); - r_offsetFactor = ri.Cvar_Get( "r_offsetFactor", "-1", CVAR_CHEAT ); - r_offsetUnits = ri.Cvar_Get( "r_offsetUnits", "-2", CVAR_CHEAT ); - - r_physicalMapping = ri.Cvar_Get( "r_physicalMapping", "1", CVAR_LATCH | CVAR_ARCHIVE ); - r_specularExponentMin = ri.Cvar_Get( "r_specularExponentMin", "0", CVAR_CHEAT ); - r_specularExponentMax = ri.Cvar_Get( "r_specularExponentMax", "16", CVAR_CHEAT ); - r_specularScale = ri.Cvar_Get( "r_specularScale", "1.0", CVAR_CHEAT | CVAR_LATCH ); - r_specularMapping = ri.Cvar_Get( "r_specularMapping", "1", CVAR_LATCH | CVAR_ARCHIVE ); - r_deluxeMapping = ri.Cvar_Get( "r_deluxeMapping", "1", CVAR_LATCH | CVAR_ARCHIVE ); - r_normalScale = ri.Cvar_Get( "r_normalScale", "1.0", CVAR_ARCHIVE ); - r_normalMapping = ri.Cvar_Get( "r_normalMapping", "1", CVAR_LATCH | CVAR_ARCHIVE ); - r_highQualityNormalMapping = ri.Cvar_Get( "r_highQualityNormalMapping", "0", CVAR_LATCH ); - r_liquidMapping = ri.Cvar_Get( "r_liquidMapping", "0", CVAR_LATCH | CVAR_ARCHIVE ); - r_reliefDepthScale = ri.Cvar_Get( "r_reliefDepthScale", "0.03", CVAR_CHEAT ); - r_reliefMapping = ri.Cvar_Get( "r_reliefMapping", "0", CVAR_LATCH | CVAR_ARCHIVE ); - r_glowMapping = ri.Cvar_Get( "r_glowMapping", "1", CVAR_LATCH ); - r_reflectionMapping = ri.Cvar_Get( "r_reflectionMapping", "0", CVAR_LATCH | CVAR_ARCHIVE ); - - r_wrapAroundLighting = ri.Cvar_Get( "r_wrapAroundLighting", "0.7", CVAR_CHEAT | CVAR_LATCH ); - r_halfLambertLighting = ri.Cvar_Get( "r_halfLambertLighting", "1", CVAR_LATCH | CVAR_ARCHIVE ); - r_rimLighting = ri.Cvar_Get( "r_rimLighting", "0", CVAR_LATCH | CVAR_ARCHIVE ); - r_rimExponent = ri.Cvar_Get( "r_rimExponent", "3", CVAR_CHEAT | CVAR_LATCH ); - AssertCvarRange( r_rimExponent, 0.5, 8.0, false ); - - r_drawBuffer = ri.Cvar_Get( "r_drawBuffer", "GL_BACK", CVAR_CHEAT ); - r_lockpvs = ri.Cvar_Get( "r_lockpvs", "0", CVAR_CHEAT ); - r_noportals = ri.Cvar_Get( "r_noportals", "0", CVAR_CHEAT ); - - r_shadows = ri.Cvar_Get( "cg_shadows", "1", CVAR_LATCH ); - AssertCvarRange( r_shadows, 0, Util::ordinal(shadowingMode_t::SHADOWING_EVSM32), true ); - - r_softShadows = ri.Cvar_Get( "r_softShadows", "0", CVAR_LATCH ); - AssertCvarRange( r_softShadows, 0, 6, true ); - - r_softShadowsPP = ri.Cvar_Get( "r_softShadowsPP", "0", CVAR_LATCH ); - - r_shadowBlur = ri.Cvar_Get( "r_shadowBlur", "2", CVAR_LATCH ); - - r_shadowMapQuality = ri.Cvar_Get( "r_shadowMapQuality", "3", CVAR_LATCH ); - AssertCvarRange( r_shadowMapQuality, 0, 4, true ); - - r_shadowMapSizeUltra = ri.Cvar_Get( "r_shadowMapSizeUltra", "1024", CVAR_LATCH ); - AssertCvarRange( r_shadowMapSizeUltra, 32, 2048, true ); - - r_shadowMapSizeVeryHigh = ri.Cvar_Get( "r_shadowMapSizeVeryHigh", "512", CVAR_LATCH ); - AssertCvarRange( r_shadowMapSizeVeryHigh, 32, 2048, true ); - - r_shadowMapSizeHigh = ri.Cvar_Get( "r_shadowMapSizeHigh", "256", CVAR_LATCH ); - AssertCvarRange( r_shadowMapSizeHigh, 32, 2048, true ); - - r_shadowMapSizeMedium = ri.Cvar_Get( "r_shadowMapSizeMedium", "128", CVAR_LATCH ); - AssertCvarRange( r_shadowMapSizeMedium, 32, 2048, true ); - - r_shadowMapSizeLow = ri.Cvar_Get( "r_shadowMapSizeLow", "64", CVAR_LATCH ); - AssertCvarRange( r_shadowMapSizeLow, 32, 2048, true ); - shadowMapResolutions[ 0 ] = r_shadowMapSizeUltra->integer; shadowMapResolutions[ 1 ] = r_shadowMapSizeVeryHigh->integer; shadowMapResolutions[ 2 ] = r_shadowMapSizeHigh->integer; shadowMapResolutions[ 3 ] = r_shadowMapSizeMedium->integer; shadowMapResolutions[ 4 ] = r_shadowMapSizeLow->integer; - r_shadowMapSizeSunUltra = ri.Cvar_Get( "r_shadowMapSizeSunUltra", "1024", CVAR_LATCH ); - AssertCvarRange( r_shadowMapSizeSunUltra, 32, 2048, true ); - - r_shadowMapSizeSunVeryHigh = ri.Cvar_Get( "r_shadowMapSizeSunVeryHigh", "1024", CVAR_LATCH ); - AssertCvarRange( r_shadowMapSizeSunVeryHigh, 512, 2048, true ); - - r_shadowMapSizeSunHigh = ri.Cvar_Get( "r_shadowMapSizeSunHigh", "1024", CVAR_LATCH ); - AssertCvarRange( r_shadowMapSizeSunHigh, 512, 2048, true ); - - r_shadowMapSizeSunMedium = ri.Cvar_Get( "r_shadowMapSizeSunMedium", "1024", CVAR_LATCH ); - AssertCvarRange( r_shadowMapSizeSunMedium, 512, 2048, true ); - - r_shadowMapSizeSunLow = ri.Cvar_Get( "r_shadowMapSizeSunLow", "1024", CVAR_LATCH ); - AssertCvarRange( r_shadowMapSizeSunLow, 512, 2048, true ); - sunShadowMapResolutions[ 0 ] = r_shadowMapSizeSunUltra->integer; sunShadowMapResolutions[ 1 ] = r_shadowMapSizeSunVeryHigh->integer; sunShadowMapResolutions[ 2 ] = r_shadowMapSizeSunHigh->integer; sunShadowMapResolutions[ 3 ] = r_shadowMapSizeSunMedium->integer; sunShadowMapResolutions[ 4 ] = r_shadowMapSizeSunLow->integer; - r_shadowOffsetFactor = ri.Cvar_Get( "r_shadowOffsetFactor", "0", CVAR_CHEAT ); - r_shadowOffsetUnits = ri.Cvar_Get( "r_shadowOffsetUnits", "0", CVAR_CHEAT ); - r_shadowLodBias = ri.Cvar_Get( "r_shadowLodBias", "0", CVAR_CHEAT ); - r_shadowLodScale = ri.Cvar_Get( "r_shadowLodScale", "0.8", CVAR_CHEAT ); - r_noShadowPyramids = ri.Cvar_Get( "r_noShadowPyramids", "0", CVAR_CHEAT ); - r_cullShadowPyramidFaces = ri.Cvar_Get( "r_cullShadowPyramidFaces", "0", CVAR_CHEAT ); - r_cullShadowPyramidCurves = ri.Cvar_Get( "r_cullShadowPyramidCurves", "1", CVAR_CHEAT ); - r_cullShadowPyramidTriangles = ri.Cvar_Get( "r_cullShadowPyramidTriangles", "1", CVAR_CHEAT ); - r_noShadowFrustums = ri.Cvar_Get( "r_noShadowFrustums", "0", CVAR_CHEAT ); - r_noLightFrustums = ri.Cvar_Get( "r_noLightFrustums", "1", CVAR_CHEAT ); - - r_maxPolys = ri.Cvar_Get( "r_maxpolys", "10000", CVAR_LATCH ); // 600 in vanilla Q3A - AssertCvarRange( r_maxPolys, 600, 30000, true ); - - r_maxPolyVerts = ri.Cvar_Get( "r_maxpolyverts", "100000", CVAR_LATCH ); // 3000 in vanilla Q3A - AssertCvarRange( r_maxPolyVerts, 3000, 200000, true ); - - r_showTris = ri.Cvar_Get( "r_showTris", "0", CVAR_CHEAT ); - r_showSky = ri.Cvar_Get( "r_showSky", "0", CVAR_CHEAT ); - r_showShadowVolumes = ri.Cvar_Get( "r_showShadowVolumes", "0", CVAR_CHEAT ); - r_showShadowLod = ri.Cvar_Get( "r_showShadowLod", "0", CVAR_CHEAT ); - r_showShadowMaps = ri.Cvar_Get( "r_showShadowMaps", "0", CVAR_CHEAT ); - r_showSkeleton = ri.Cvar_Get( "r_showSkeleton", "0", CVAR_CHEAT ); - r_showEntityTransforms = ri.Cvar_Get( "r_showEntityTransforms", "0", CVAR_CHEAT ); - r_showLightTransforms = ri.Cvar_Get( "r_showLightTransforms", "0", CVAR_CHEAT ); - r_showLightInteractions = ri.Cvar_Get( "r_showLightInteractions", "0", CVAR_CHEAT ); - r_showLightScissors = ri.Cvar_Get( "r_showLightScissors", "0", CVAR_CHEAT ); - r_showLightBatches = ri.Cvar_Get( "r_showLightBatches", "0", CVAR_CHEAT ); - r_showLightGrid = ri.Cvar_Get( "r_showLightGrid", "0", CVAR_CHEAT ); - r_showLightTiles = ri.Cvar_Get("r_showLightTiles", "0", CVAR_CHEAT | CVAR_LATCH ); - r_showBatches = ri.Cvar_Get( "r_showBatches", "0", CVAR_CHEAT ); - r_showLightMaps = ri.Cvar_Get( "r_showLightMaps", "0", CVAR_CHEAT | CVAR_LATCH ); - r_showDeluxeMaps = ri.Cvar_Get( "r_showDeluxeMaps", "0", CVAR_CHEAT | CVAR_LATCH ); - r_showNormalMaps = ri.Cvar_Get( "r_showNormalMaps", "0", CVAR_CHEAT | CVAR_LATCH ); - r_showMaterialMaps = ri.Cvar_Get( "r_showMaterialMaps", "0", CVAR_CHEAT | CVAR_LATCH ); - r_showAreaPortals = ri.Cvar_Get( "r_showAreaPortals", "0", CVAR_CHEAT ); - r_showCubeProbes = ri.Cvar_Get( "r_showCubeProbes", "0", CVAR_CHEAT ); - r_showBspNodes = ri.Cvar_Get( "r_showBspNodes", "0", CVAR_CHEAT ); - r_showParallelShadowSplits = ri.Cvar_Get( "r_showParallelShadowSplits", "0", CVAR_CHEAT | CVAR_LATCH ); - r_showDecalProjectors = ri.Cvar_Get( "r_showDecalProjectors", "0", CVAR_CHEAT ); - - r_fontScale = ri.Cvar_Get( "r_fontScale", "36", CVAR_LATCH ); - // make sure all the commands added here are also removed in R_Shutdown ri.Cmd_AddCommand( "imagelist", R_ImageList_f ); ri.Cmd_AddCommand( "shaderlist", R_ShaderList_f ); diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 454739217e..05db005d1c 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -31,8 +31,20 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "tr_public.h" #include "iqm.h" +#ifdef USE_OSMESA +#define GL_GLEXT_PROTOTYPES +#include +#include +// TODO get rid of GLEW_xxx references outside of glimp_loadextensions? +#define GLEW_ARB_texture_gather 1 +#define GLEW_ARB_gpu_shader5 0 // must be 0 +#define GLEW_EXT_gpu_shader4 0 // 0 to disable bitwise operations +#define GLEW_ARB_uniform_buffer_object 1 +#define GLEW_ARB_debug_output 1 +#else //USE_OS_MESA #define GLEW_NO_GLU #include +#endif //USE_OS_MESA #define DYN_BUFFER_SIZE ( 4 * 1024 * 1024 ) #define DYN_BUFFER_SEGMENTS 4 @@ -2868,6 +2880,8 @@ static inline void halfToFloat( const f16vec4_t in, vec4_t out ) extern cvar_t *r_showcluster; extern cvar_t *r_mode; // video mode + extern cvar_t *r_customwidth; + extern cvar_t *r_customheight; extern cvar_t *r_noBorder; extern cvar_t *r_fullscreen; extern cvar_t *r_gamma; @@ -3206,6 +3220,7 @@ inline bool checkGLErrors() model_t *R_AllocModel(); bool R_Init(); + void R_RegisterCvars(); void AssertCvarRange( cvar_t *cv, float minVal, float maxVal, bool shouldBeIntegral ); @@ -3281,6 +3296,7 @@ inline bool checkGLErrors() */ bool GLimp_Init(); + void GLimp_InitExtensions(); void GLimp_Shutdown(); void GLimp_EndFrame(); void GLimp_HandleCvars(); diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index f39a3cfca9..b5f78c8d77 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -32,193 +32,6 @@ This file deals with applying shaders to surface data in the tess struct. ================================================================================= */ -static void GLSL_InitGPUShadersOrError() -{ - // make sure the render thread is stopped - R_SyncRenderThread(); - - GL_CheckErrors(); - - gl_shaderManager.InitDriverInfo(); - - // single texture rendering - gl_shaderManager.GenerateBuiltinHeaders(); - - // single texture rendering - gl_shaderManager.load( gl_genericShader ); - - // standard light mapping - gl_shaderManager.load( gl_lightMappingShader ); - - // Deprecated forward renderer uses r_dynamicLight -1 - if ( r_dynamicLight->integer < 0 ) - { - // omni-directional specular bump mapping ( Doom3 style ) - gl_shaderManager.load( gl_forwardLightingShader_omniXYZ ); - - // projective lighting ( Doom3 style ) - gl_shaderManager.load( gl_forwardLightingShader_projXYZ ); - - // directional sun lighting ( Doom3 style ) - gl_shaderManager.load( gl_forwardLightingShader_directionalSun ); - } - else if ( r_dynamicLight->integer > 0 ) - { - gl_shaderManager.load( gl_depthtile1Shader ); - gl_shaderManager.load( gl_depthtile2Shader ); - gl_shaderManager.load( gl_lighttileShader ); - } - - // shadowmap distance compression - gl_shaderManager.load( gl_shadowFillShader ); - - if ( r_reflectionMapping->integer != 0 ) - { - // bumped cubemap reflection for abitrary polygons ( EMBM ) - gl_shaderManager.load( gl_reflectionShader ); - } - - // skybox drawing for abitrary polygons - gl_shaderManager.load( gl_skyboxShader ); - - // Q3A volumetric fog - gl_shaderManager.load( gl_fogQuake3Shader ); - - // global fog post process effect - gl_shaderManager.load( gl_fogGlobalShader ); - - // heatHaze post process effect - gl_shaderManager.load( gl_heatHazeShader ); - - // NOTE: screen shader seems to be only used by bloom post process effect. - if ( r_bloom->integer != 0 ) - { - // screen post process effect - gl_shaderManager.load( gl_screenShader ); - } - - // portal process effect - gl_shaderManager.load( gl_portalShader ); - - // LDR bright pass filter - gl_shaderManager.load( gl_contrastShader ); - - // camera post process effect - gl_shaderManager.load( gl_cameraEffectsShader ); - - // gaussian blur - gl_shaderManager.load( gl_blurXShader ); - - gl_shaderManager.load( gl_blurYShader ); - - // debug utils - gl_shaderManager.load( gl_debugShadowMapShader ); - - if ( r_liquidMapping->integer != 0 ) - { - gl_shaderManager.load( gl_liquidShader ); - } - -#if !defined( GLSL_COMPILE_STARTUP_ONLY ) - - gl_shaderManager.load( gl_volumetricFogShader ); - -#endif // #if !defined(GLSL_COMPILE_STARTUP_ONLY) - - /* NOTE: motionblur is enabled by cg_motionblur which is a client cvar - so we have to build it in all cases. */ - gl_shaderManager.load( gl_motionblurShader ); - - if (GLEW_ARB_texture_gather) - { - if (r_ssao->integer) - { - gl_shaderManager.load(gl_ssaoShader); - } - } - else - { - Log::Warn("SSAO not used because GL_ARB_texture_gather is not available."); - } - - if ( r_FXAA->integer != 0 ) - { - gl_shaderManager.load( gl_fxaaShader ); - } - - if ( !r_lazyShaders->integer ) - { - gl_shaderManager.buildAll(); - } -} - -void GLSL_InitGPUShaders() -{ - /* - Without a shaderpath option, the shader debugging cycle is like this: - 1. Change shader file(s). - 2. Run script to convert shader files into c++, storing them in shaders.cpp - 3. Recompile app to pickup the new shaders.cpp changes. - 4. Run the app and get to the point required to check work. - 5. If the change failed or succeeded but you want to make more changes restart at step 1. - - Alternatively, if set shaderpath "c:/unvanquished/main" is used, the cycle is: - 1. Change shader file(s) - don't run the buildshaders script unless samples.cpp is missing. - 2. Start the app, the app will load the shader files directly. - If there is a problem the app will revert to the last working changes - in samples.cpp, so need to restart the app. - 3. Fix the problem shader files - 4. Do /glsl_restart at the app console to reload them. Repeat from step 3 as needed. - - Note that unv will respond by listing the files it thinks are different. - If this matches your expectations then it's not an error. - Note foward slashes (like those used in windows pathnames are processed - as escape characters by the Unvanquished command processor, - so use two forward slashes in that case. - */ - - auto shaderPath = GetShaderPath(); - if (shaderPath.empty()) - shaderKind = ShaderKind::BuiltIn; - else - shaderKind = ShaderKind::External; - - bool externalFailed = false; - if (shaderKind == ShaderKind::External) - { - try - { - Log::Warn("Loading external shaders."); - GLSL_InitGPUShadersOrError(); - Log::Warn("External shaders in use."); - } - catch (const ShaderException& e) - { - Log::Warn("External shaders failed: %s", e.what()); - Log::Warn("Attempting to use built in shaders instead."); - shaderKind = ShaderKind::BuiltIn; - externalFailed = true; - } - } - - if (shaderKind == ShaderKind::BuiltIn) - { - // Let the user know if we are transitioning from external to - // built-in shaders. We won't alert them if we were already using - // built-in shaders as this is the normal case. - try - { - GLSL_InitGPUShadersOrError(); - } - catch (const ShaderException&e) - { - Sys::Error("Built-in shaders failed: %s", e.what()); // Fatal. - }; - if (externalFailed) - Log::Warn("Now using built-in shaders because external shaders failed."); - } -} - void GLSL_ShutdownGPUShaders() { R_SyncRenderThread(); diff --git a/src/engine/sys/sdl_glimp.cpp b/src/engine/sys/sdl_glimp.cpp index 511aa9573a..614634a809 100644 --- a/src/engine/sys/sdl_glimp.cpp +++ b/src/engine/sys/sdl_glimp.cpp @@ -33,7 +33,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "framework/CommandSystem.h" #include "framework/CvarSystem.h" -static Log::Logger logger("glconfig", "", Log::Level::NOTICE); +extern Log::Logger glConfigLogger; +#define logger glConfigLogger SDL_Window *window = nullptr; static SDL_GLContext glContext = nullptr; @@ -862,296 +863,6 @@ static bool GLimp_StartDriverAndSetMode( int mode, bool fullscreen, bool noborde return true; } -static GLenum debugTypes[] = -{ - 0, - GL_DEBUG_TYPE_ERROR_ARB, - GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, - GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB, - GL_DEBUG_TYPE_PORTABILITY_ARB, - GL_DEBUG_TYPE_PERFORMANCE_ARB, - GL_DEBUG_TYPE_OTHER_ARB -}; - -#ifdef _WIN32 -#define DEBUG_CALLBACK_CALL APIENTRY -#else -#define DEBUG_CALLBACK_CALL -#endif -static void DEBUG_CALLBACK_CALL GLimp_DebugCallback( GLenum, GLenum type, GLuint, - GLenum severity, GLsizei, const GLchar *message, const void* ) -{ - const char *debugTypeName; - const char *debugSeverity; - - if ( r_glDebugMode->integer <= Util::ordinal(glDebugModes_t::GLDEBUG_NONE)) - { - return; - } - - if ( r_glDebugMode->integer < Util::ordinal(glDebugModes_t::GLDEBUG_ALL)) - { - if ( debugTypes[ r_glDebugMode->integer ] != type ) - { - return; - } - } - - switch ( type ) - { - case GL_DEBUG_TYPE_ERROR_ARB: - debugTypeName = "DEBUG_TYPE_ERROR"; - break; - case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: - debugTypeName = "DEBUG_TYPE_DEPRECATED_BEHAVIOR"; - break; - case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: - debugTypeName = "DEBUG_TYPE_UNDEFINED_BEHAVIOR"; - break; - case GL_DEBUG_TYPE_PORTABILITY_ARB: - debugTypeName = "DEBUG_TYPE_PORTABILITY"; - break; - case GL_DEBUG_TYPE_PERFORMANCE_ARB: - debugTypeName = "DEBUG_TYPE_PERFORMANCE"; - break; - case GL_DEBUG_TYPE_OTHER_ARB: - debugTypeName = "DEBUG_TYPE_OTHER"; - break; - default: - debugTypeName = "DEBUG_TYPE_UNKNOWN"; - break; - } - - switch ( severity ) - { - case GL_DEBUG_SEVERITY_HIGH_ARB: - debugSeverity = "high"; - break; - case GL_DEBUG_SEVERITY_MEDIUM_ARB: - debugSeverity = "med"; - break; - case GL_DEBUG_SEVERITY_LOW_ARB: - debugSeverity = "low"; - break; - default: - debugSeverity = "none"; - break; - } - - logger.Warn("%s: severity: %s msg: %s", debugTypeName, debugSeverity, message ); -} - -/* -=============== -GLimp_InitExtensions -=============== -*/ - -/* ExtFlag_CORE means the extension is known to be an OpenGL 3 core extension. -The code considers the extension is available even if the extension is not listed -if the driver pretends to support OpenGL Core 3 and we know this extension is part -of OpenGL Core 3. */ - -enum { - ExtFlag_NONE, - ExtFlag_REQUIRED = BIT( 1 ), - ExtFlag_CORE = BIT( 2 ), -}; - -static bool LoadExt( int flags, bool hasExt, const char* name, bool test = true ) -{ - if ( hasExt || ( flags & ExtFlag_CORE && glConfig2.glCoreProfile) ) - { - if ( test ) - { - logger.WithoutSuppression().Notice( "...using GL_%s", name ); - return true; - } - else - { - // Required extension can't be made optional - ASSERT( !( flags & ExtFlag_REQUIRED ) ); - - logger.WithoutSuppression().Notice( "...ignoring GL_%s", name ); - } - } - else - { - if ( flags & ExtFlag_REQUIRED ) - { - Sys::Error( "Required extension GL_%s is missing", name ); - } - else - { - logger.WithoutSuppression().Notice( "...GL_%s not found", name ); - } - } - return false; -} - -#define LOAD_EXTENSION(flags, ext) LoadExt(flags, GLEW_##ext, #ext) - -#define LOAD_EXTENSION_WITH_TEST(flags, ext, test) LoadExt(flags, GLEW_##ext, #ext, test) - -static void GLimp_InitExtensions() -{ - logger.Notice("Initializing OpenGL extensions" ); - - if ( LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_debug_output, r_glDebugProfile->value ) ) - { - glDebugMessageCallbackARB( (GLDEBUGPROCARB)GLimp_DebugCallback, nullptr ); - glEnable( GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB ); - } - - // Shader limits - glGetIntegerv( GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &glConfig2.maxVertexUniforms ); - glGetIntegerv( GL_MAX_VERTEX_ATTRIBS_ARB, &glConfig2.maxVertexAttribs ); - - int reservedComponents = 36 * 10; // approximation how many uniforms we have besides the bone matrices - glConfig2.maxVertexSkinningBones = Math::Clamp( ( glConfig2.maxVertexUniforms - reservedComponents ) / 16, 0, MAX_BONES ); - glConfig2.vboVertexSkinningAvailable = r_vboVertexSkinning->integer && ( ( glConfig2.maxVertexSkinningBones >= 12 ) ? true : false ); - - // GLSL - - Q_strncpyz( glConfig2.shadingLanguageVersionString, ( char * ) glGetString( GL_SHADING_LANGUAGE_VERSION_ARB ), - sizeof( glConfig2.shadingLanguageVersionString ) ); - int majorVersion, minorVersion; - if ( sscanf( glConfig2.shadingLanguageVersionString, "%i.%i", &majorVersion, &minorVersion ) != 2 ) - { - logger.Warn("unrecognized shading language version string format" ); - } - glConfig2.shadingLanguageVersion = majorVersion * 100 + minorVersion; - - logger.Notice("...found shading language version %i", glConfig2.shadingLanguageVersion ); - - // Texture formats and compression - glGetIntegerv( GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, &glConfig2.maxCubeMapTextureSize ); - - // made required in OpenGL 3.0 - glConfig2.textureHalfFloatAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_CORE, ARB_half_float_pixel, r_ext_half_float_pixel->value ); - - // made required in OpenGL 3.0 - glConfig2.textureFloatAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_CORE, ARB_texture_float, r_ext_texture_float->value ); - - // made required in OpenGL 3.0 - glConfig2.gpuShader4Available = LOAD_EXTENSION_WITH_TEST( ExtFlag_CORE, EXT_gpu_shader4, r_ext_gpu_shader4->value ); - - // made required in OpenGL 3.0 - // GL_EXT_texture_integer can be used in shaders only if GL_EXT_gpu_shader4 is also available - glConfig2.textureIntegerAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_CORE, EXT_texture_integer, r_ext_texture_integer->value ) - && glConfig2.gpuShader4Available; - - // made required in OpenGL 3.0 - glConfig2.textureRGAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_CORE, ARB_texture_rg, r_ext_texture_rg->value ); - - { - /* GT218-based GPU with Nvidia 340.108 driver advertising - ARB_texture_gather extension is know to fail to compile - the depthtile1 GLSL shader. - - See https://github.com/DaemonEngine/Daemon/issues/368 - - Unfortunately this workaround may also disable the feature for - all GPUs using this driver even if we don't know if some of them - are not affected by the bug while advertising this extension, but - there is no known easy way to detect GT218-based cards. Not all cards - using 340 driver supports this extension anyway, like the G92 one. - - We can assume cards not using the 340 driver are not GT218 ones and - are not affected. - - Usually, those GT218 cards are not powerful enough for dynamic - lighting so it is likely this feature would be disabled to - get acceptable framerate on this hardware anyway, making the - need for such extension and the related shader code useless. */ - bool foundNvidia340 = ( Q_stristr( glConfig.vendor_string, "NVIDIA Corporation" ) && Q_stristr( glConfig.version_string, "NVIDIA 340." ) ); - - if ( foundNvidia340 ) - { - // No need for WithoutSuppression for something which can only be printed once per renderer restart. - logger.Notice("...found buggy Nvidia 340 driver"); - } - - // made required in OpenGL 4.0 - glConfig2.textureGatherAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_texture_gather, r_arb_texture_gather->value && !foundNvidia340 ); - } - - // made required in OpenGL 1.3 - glConfig.textureCompression = textureCompression_t::TC_NONE; - if( LOAD_EXTENSION( ExtFlag_NONE, EXT_texture_compression_s3tc ) ) - { - glConfig.textureCompression = textureCompression_t::TC_S3TC; - } - - // made required in OpenGL 3.0 - glConfig2.textureCompressionRGTCAvailable = LOAD_EXTENSION( ExtFlag_CORE, ARB_texture_compression_rgtc ); - - // Texture - others - glConfig2.textureAnisotropyAvailable = false; - if ( LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, EXT_texture_filter_anisotropic, r_ext_texture_filter_anisotropic->value ) ) - { - glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glConfig2.maxTextureAnisotropy ); - glConfig2.textureAnisotropyAvailable = true; - } - - // VAO and VBO - // made required in OpenGL 3.0 - - LOAD_EXTENSION( ExtFlag_REQUIRED | ExtFlag_CORE, ARB_half_float_vertex ); - - // made required in OpenGL 3.0 - LOAD_EXTENSION( ExtFlag_REQUIRED | ExtFlag_CORE, ARB_framebuffer_object ); - - // FBO - glGetIntegerv( GL_MAX_RENDERBUFFER_SIZE, &glConfig2.maxRenderbufferSize ); - glGetIntegerv( GL_MAX_COLOR_ATTACHMENTS, &glConfig2.maxColorAttachments ); - - // made required in OpenGL 1.5 - glConfig2.occlusionQueryAvailable = false; - glConfig2.occlusionQueryBits = 0; - if ( r_ext_occlusion_query->integer != 0 ) - { - glConfig2.occlusionQueryAvailable = true; - glGetQueryiv( GL_SAMPLES_PASSED, GL_QUERY_COUNTER_BITS, &glConfig2.occlusionQueryBits ); - } - - // made required in OpenGL 2.0 - glConfig2.drawBuffersAvailable = false; - if ( r_ext_draw_buffers->integer != 0 ) - { - glGetIntegerv( GL_MAX_DRAW_BUFFERS, &glConfig2.maxDrawBuffers ); - glConfig2.drawBuffersAvailable = true; - } - - { - int formats = 0; - - glGetIntegerv( GL_NUM_PROGRAM_BINARY_FORMATS, &formats ); - - if ( formats == 0 ) - { - // No need for WithoutSuppression for something which can only be printed once per renderer restart. - logger.Notice("...no program binary formats"); - } - - glConfig2.getProgramBinaryAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_get_program_binary, formats > 0 ); - } - - glConfig2.bufferStorageAvailable = false; - glConfig2.bufferStorageAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_buffer_storage, r_arb_buffer_storage->integer > 0 ); - - // made required since OpenGL 3.1 - glConfig2.uniformBufferObjectAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_CORE, ARB_uniform_buffer_object, r_arb_uniform_buffer_object->value ); - - // made required in OpenGL 3.0 - glConfig2.mapBufferRangeAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_CORE, ARB_map_buffer_range, r_arb_map_buffer_range->value ); - - // made required in OpenGL 3.2 - glConfig2.syncAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_CORE, ARB_sync, r_arb_sync->value ); - - GL_CheckErrors(); -} - static const int R_MODE_FALLBACK = 3; // 640 * 480 /* Support code for GLimp_Init */ @@ -1508,20 +1219,3 @@ void GLimp_HandleCvars() // TODO: Update r_allowResize using SDL_SetWindowResizable when we have SDL 2.0.5 } - -void GLimp_LogComment( const char *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 ) ); - - glDebugMessageInsertARB( GL_DEBUG_SOURCE_APPLICATION_ARB, - GL_DEBUG_TYPE_OTHER_ARB, - 0, - GL_DEBUG_SEVERITY_MEDIUM_ARB, - strlen( buf ), buf ); - } -}