From 966c415327802378043b43e7956febade9eef77c Mon Sep 17 00:00:00 2001 From: VReaperV Date: Fri, 16 Feb 2024 21:38:56 +0300 Subject: [PATCH] Renderer: Implement material system Implement material system, set world BSP surfaces to use it. Material system works by generating enough materials (a distinct GL state that has to be set for the whole draw call) for each stage of every drawSurf_t. All of the per-surface data that was previously set through uniforms for each drawSurf_t is now sourced from a buffer. The remaining (global) uniforms like u_ViewUp and u_ViewOrigin are still set as usual. Updates for surfaces whose parameters change with time are done by mapping the corresponding part of the memory and copying all of the data into it, then flushing it all at once. Implement bindless texture support. --- src.cmake | 6 + src/engine/renderer/Material.cpp | 1897 +++++++++++++++++ src/engine/renderer/Material.h | 201 ++ src/engine/renderer/TextureManager.cpp | 121 ++ src/engine/renderer/TextureManager.h | 76 + src/engine/renderer/gl_shader.cpp | 682 +++++- src/engine/renderer/gl_shader.h | 1777 +++++++++++++-- .../glsl_source/cameraEffects_fp.glsl | 11 +- .../renderer/glsl_source/computeLight_fp.glsl | 54 +- .../renderer/glsl_source/fogQuake3_fp.glsl | 4 + .../renderer/glsl_source/fogQuake3_vp.glsl | 2 + .../renderer/glsl_source/generic_fp.glsl | 4 + .../renderer/glsl_source/generic_vp.glsl | 7 +- .../renderer/glsl_source/heatHaze_fp.glsl | 10 +- .../renderer/glsl_source/heatHaze_vp.glsl | 2 + .../renderer/glsl_source/lightMapping_fp.glsl | 44 +- .../renderer/glsl_source/lightMapping_vp.glsl | 2 + .../renderer/glsl_source/liquid_fp.glsl | 19 +- .../renderer/glsl_source/liquid_vp.glsl | 2 + .../renderer/glsl_source/material_fp.glsl | 132 ++ .../renderer/glsl_source/material_vp.glsl | 44 + .../glsl_source/reflection_CB_fp.glsl | 12 +- .../glsl_source/reflection_CB_vp.glsl | 2 + .../glsl_source/reliefMapping_fp.glsl | 22 +- .../renderer/glsl_source/screen_fp.glsl | 4 + .../renderer/glsl_source/screen_vp.glsl | 2 + .../renderer/glsl_source/skybox_fp.glsl | 8 +- .../renderer/glsl_source/skybox_vp.glsl | 2 + .../renderer/glsl_source/vertexSprite_vp.glsl | 4 +- src/engine/renderer/shaders.cpp | 4 + src/engine/renderer/tr_backend.cpp | 209 +- src/engine/renderer/tr_bsp.cpp | 4 +- src/engine/renderer/tr_image.cpp | 17 + src/engine/renderer/tr_init.cpp | 5 + src/engine/renderer/tr_local.h | 37 +- src/engine/renderer/tr_main.cpp | 37 +- src/engine/renderer/tr_public.h | 5 + src/engine/renderer/tr_scene.cpp | 4 + src/engine/renderer/tr_shade.cpp | 367 +++- src/engine/renderer/tr_sky.cpp | 23 +- src/engine/renderer/tr_surface.cpp | 3 + src/engine/renderer/tr_vbo.cpp | 15 + src/engine/renderer/tr_world.cpp | 3 +- src/engine/sys/sdl_glimp.cpp | 70 + 44 files changed, 5574 insertions(+), 382 deletions(-) create mode 100644 src/engine/renderer/Material.cpp create mode 100644 src/engine/renderer/Material.h create mode 100644 src/engine/renderer/TextureManager.cpp create mode 100644 src/engine/renderer/TextureManager.h create mode 100644 src/engine/renderer/glsl_source/material_fp.glsl create mode 100644 src/engine/renderer/glsl_source/material_vp.glsl diff --git a/src.cmake b/src.cmake index daf96a588f..7fc6d7c758 100644 --- a/src.cmake +++ b/src.cmake @@ -102,6 +102,10 @@ set(RENDERERLIST ${ENGINE_DIR}/renderer/tr_font.cpp ${ENGINE_DIR}/renderer/InternalImage.cpp ${ENGINE_DIR}/renderer/InternalImage.h + ${ENGINE_DIR}/renderer/Material.cpp + ${ENGINE_DIR}/renderer/Material.h + ${ENGINE_DIR}/renderer/TextureManager.cpp + ${ENGINE_DIR}/renderer/TextureManager.h ${ENGINE_DIR}/renderer/tr_image.cpp ${ENGINE_DIR}/renderer/tr_image.h ${ENGINE_DIR}/renderer/tr_image_crn.cpp @@ -141,6 +145,8 @@ set(RENDERERLIST ) set(GLSLSOURCELIST + ${ENGINE_DIR}/renderer/glsl_source/material_vp.glsl + ${ENGINE_DIR}/renderer/glsl_source/material_fp.glsl ${ENGINE_DIR}/renderer/glsl_source/skybox_vp.glsl ${ENGINE_DIR}/renderer/glsl_source/ssao_fp.glsl ${ENGINE_DIR}/renderer/glsl_source/ssao_vp.glsl diff --git a/src/engine/renderer/Material.cpp b/src/engine/renderer/Material.cpp new file mode 100644 index 0000000000..2c199f6a89 --- /dev/null +++ b/src/engine/renderer/Material.cpp @@ -0,0 +1,1897 @@ +/* +=========================================================================== + +Daemon BSD Source Code +Copyright (c) 2024 Daemon Developers +All rights reserved. + +This file is part of the Daemon BSD Source Code (Daemon Source Code). + +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. + +=========================================================================== +*/ +// Material.cpp + +#include "Material.h" + +#include "tr_local.h" + +GLSSBO materialsSSBO( "materials", 0 ); +GLIndirectBuffer commandBuffer( "drawCommands" ); +MaterialSystem materialSystem; + +static void ComputeDynamics( shaderStage_t* pStage ) { + // TODO: Move color and texMatrices stuff to a compute shader + switch ( pStage->rgbGen ) { + case colorGen_t::CGEN_IDENTITY: + case colorGen_t::CGEN_ONE_MINUS_VERTEX: + default: + case colorGen_t::CGEN_IDENTITY_LIGHTING: + /* Historically CGEN_IDENTITY_LIGHTING was done this way: + + tess.svars.color = Color::White * tr.identityLight; + + But tr.identityLight is always 1.0f in Dæmon engine + as the as the overbright bit implementation is fully + software. */ + case colorGen_t::CGEN_VERTEX: + case colorGen_t::CGEN_CONST: + case colorGen_t::CGEN_ENTITY: + case colorGen_t::CGEN_ONE_MINUS_ENTITY: + { + // TODO: Move this to some entity buffer once this is extended past BSP surfaces + if ( backEnd.currentEntity ) { + // + } else { + // + } + pStage->colorDynamic = false; + + break; + } + + case colorGen_t::CGEN_WAVEFORM: + case colorGen_t::CGEN_CUSTOM_RGB: + case colorGen_t::CGEN_CUSTOM_RGBs: + { + pStage->colorDynamic = true; + break; + } + } + + switch ( pStage->alphaGen ) { + default: + case alphaGen_t::AGEN_IDENTITY: + case alphaGen_t::AGEN_ONE_MINUS_VERTEX: + case alphaGen_t::AGEN_VERTEX: + case alphaGen_t::AGEN_CONST: { + case alphaGen_t::AGEN_ENTITY: + case alphaGen_t::AGEN_ONE_MINUS_ENTITY: + // TODO: Move this to some entity buffer once this is extended past BSP surfaces + /* if ( backEnd.currentEntity ) { + } else { + } */ + pStage->colorDynamic = false; + break; + } + + case alphaGen_t::AGEN_WAVEFORM: + case alphaGen_t::AGEN_CUSTOM: + { + pStage->colorDynamic = true; + break; + } + } + + for ( textureBundle_t& bundle : pStage->bundle ) { + for ( size_t i = 0; i < bundle.numTexMods; i++ ) { + switch ( bundle.texMods[i].type ) { + case texMod_t::TMOD_NONE: + case texMod_t::TMOD_SCALE: + case texMod_t::TMOD_TRANSFORM: + break; + + case texMod_t::TMOD_TURBULENT: + case texMod_t::TMOD_ENTITY_TRANSLATE: + case texMod_t::TMOD_SCROLL: + { + pStage->texMatricesDynamic = true; + break; + } + + case texMod_t::TMOD_STRETCH: + { + if( bundle.texMods->wave.func != genFunc_t::GF_NONE ) { + pStage->texMatricesDynamic = true; + } + break; + } + + case texMod_t::TMOD_ROTATE: + { + pStage->texMatricesDynamic = true; + break; + } + + case texMod_t::TMOD_SCROLL2: + case texMod_t::TMOD_SCALE2: + case texMod_t::TMOD_CENTERSCALE: + case texMod_t::TMOD_SHEAR: + { + if ( bundle.texMods[i].sExp.active || bundle.texMods[i].tExp.active ) { + pStage->texMatricesDynamic = true; + } + break; + } + + case texMod_t::TMOD_ROTATE2: + { + if( bundle.texMods[i].rExp.active ) { + pStage->texMatricesDynamic = true; + } + break; + } + + default: + break; + } + } + } + + // TODO: Move this to a different buffer? + for ( const textureBundle_t& bundle : pStage->bundle ) { + if ( bundle.isVideoMap || bundle.numImages > 1 ) { + pStage->texturesDynamic = true; + break; + } + } + + // Can we move this to a compute shader too? + // Doesn't seem to be used much if at all, so probably not worth the effort to do that + pStage->dynamic = pStage->dynamic || pStage->ifExp.active; + pStage->dynamic = pStage->dynamic || pStage->alphaExp.active || pStage->alphaTestExp.active; + pStage->dynamic = pStage->dynamic || pStage->rgbExp.active || pStage->redExp.active || pStage->greenExp.active || pStage->blueExp.active; + pStage->dynamic = pStage->dynamic || pStage->deformMagnitudeExp.active; + pStage->dynamic = pStage->dynamic || pStage->depthScaleExp.active || pStage->etaExp.active || pStage->etaDeltaExp.active + || pStage->fogDensityExp.active || pStage->fresnelBiasExp.active || pStage->fresnelPowerExp.active + || pStage->fresnelScaleExp.active || pStage->normalIntensityExp.active || pStage->refractionIndexExp.active; + + pStage->dynamic = pStage->dynamic || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->texturesDynamic; +} + +static image_t* GetLightMap( drawSurf_t* drawSurf ) { + if ( static_cast( drawSurf->lightmapNum() ) < tr.lightmaps.size() ) { + return tr.lightmaps[drawSurf->lightmapNum()]; + } else { + return tr.whiteImage; + } +} + +static image_t* GetDeluxeMap( drawSurf_t* drawSurf ) { + if ( static_cast( drawSurf->lightmapNum() ) < tr.deluxemaps.size() ) { + return tr.deluxemaps[drawSurf->lightmapNum()]; + } else { + return tr.blackImage; + } +} + +// UpdateSurface*() functions will actually write the uniform values to the SSBO +// Mirrors parts of the Render_*() functions in tr_shade.cpp + +static void UpdateSurfaceDataGeneric( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { + shader_t* shader = drawSurf->shader; + shaderStage_t* pStage = &shader->stages[stage]; + + const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); + materials += paddedOffset; + + bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; + if ( !updated ) { + return; + } + drawSurf->initialized[stage] = true; + + gl_genericShaderMaterial->BindProgram( material.deformIndex ); + + gl_genericShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); + gl_genericShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); + + // u_AlphaThreshold + gl_genericShaderMaterial->SetUniform_AlphaTest( pStage->stateBits ); + + // u_InverseLightFactor + // We should cancel overbrightBits if there is no light, + // and it's not using blendFunc dst_color. + bool blendFunc_dstColor = ( pStage->stateBits & GLS_SRCBLEND_BITS ) == GLS_SRCBLEND_DST_COLOR; + float inverseLightFactor = ( pStage->shaderHasNoLight && !blendFunc_dstColor ) ? tr.mapInverseLightFactor : 1.0f; + gl_genericShaderMaterial->SetUniform_InverseLightFactor( inverseLightFactor ); + + // u_ColorModulate + colorGen_t rgbGen; + alphaGen_t alphaGen; + SetRgbaGen( pStage, &rgbGen, &alphaGen ); + gl_genericShaderMaterial->SetUniform_ColorModulate( rgbGen, alphaGen ); + + Tess_ComputeColor( pStage ); + gl_genericShaderMaterial->SetUniform_Color( tess.svars.color ); + + Tess_ComputeTexMatrices( pStage ); + gl_genericShaderMaterial->SetUniform_TextureMatrix( tess.svars.texMatrices[TB_COLORMAP] ); + + // u_DeformGen + gl_genericShaderMaterial->SetUniform_Time( backEnd.refdef.floatTime - backEnd.currentEntity->e.shaderTime ); + + // bind u_ColorMap= + if ( pStage->type == stageType_t::ST_STYLELIGHTMAP ) { + gl_genericShaderMaterial->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, GetLightMap( drawSurf ) ) + ); + } else { + gl_genericShaderMaterial->SetUniform_ColorMapBindless( BindAnimatedImage( 0, &pStage->bundle[TB_COLORMAP] ) ); + } + + bool needDepthMap = pStage->hasDepthFade || shader->autoSpriteMode; + if ( needDepthMap ) { + gl_genericShaderMaterial->SetUniform_DepthMapBindless( GL_BindToTMU( 1, tr.currentDepthImage ) ); + } + + bool hasDepthFade = pStage->hasDepthFade && !shader->autoSpriteMode; + if ( hasDepthFade ) { + gl_genericShaderMaterial->SetUniform_DepthScale( pStage->depthFadeValue ); + } + + gl_genericShaderMaterial->SetUniform_VertexInterpolation( false ); + + gl_genericShaderMaterial->WriteUniformsToBuffer( materials ); +} + +static void UpdateSurfaceDataLightMapping( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { + shader_t* shader = drawSurf->shader; + shaderStage_t* pStage = &shader->stages[stage]; + + const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); + materials += paddedOffset; + + bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; + if ( !updated ) { + return; + } + drawSurf->initialized[stage] = true; + + gl_lightMappingShaderMaterial->BindProgram( material.deformIndex ); + + gl_lightMappingShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); + + lightMode_t lightMode = lightMode_t::FULLBRIGHT; + deluxeMode_t deluxeMode = deluxeMode_t::NONE; + + /* TODO: investigate what this is. It's probably a hack to detect some + specific use case. Without knowing which use case this takes care about, + any change in the following code may break it. Or it may be a hack we + should drop if it is for a bug we don't have anymore. */ + bool hack = shader->lastStage != shader->stages + && shader->stages[0].rgbGen == colorGen_t::CGEN_VERTEX; + + if ( ( shader->surfaceFlags & SURF_NOLIGHTMAP ) && !hack ) { + // Use fullbright on “surfaceparm nolightmap” materials. + } else if ( pStage->type == stageType_t::ST_COLLAPSE_COLORMAP ) { + /* Use fullbright for collapsed stages without lightmaps, + for example: + + { + map textures/texture_d + heightMap textures/texture_h + } + + This is doable for some complex multi-stage materials. */ + } else if ( drawSurf->bspSurface ) { + lightMode = tr.worldLight; + deluxeMode = tr.worldDeluxe; + + if ( lightMode == lightMode_t::MAP ) { + bool hasLightMap = static_cast( drawSurf->lightmapNum() ) < tr.lightmaps.size(); + + if ( !hasLightMap ) { + lightMode = lightMode_t::VERTEX; + deluxeMode = deluxeMode_t::NONE; + } + } + } else { + lightMode = tr.modelLight; + deluxeMode = tr.modelDeluxe; + } + + // u_Map, u_DeluxeMap + image_t* lightmap = tr.whiteImage; + image_t* deluxemap = tr.whiteImage; + + // u_ColorModulate + colorGen_t rgbGen; + alphaGen_t alphaGen; + SetRgbaGen( pStage, &rgbGen, &alphaGen ); + + switch ( lightMode ) { + case lightMode_t::VERTEX: + // Do not rewrite pStage->rgbGen. + rgbGen = colorGen_t::CGEN_VERTEX; + tess.svars.color.SetRed( 0.0f ); + tess.svars.color.SetGreen( 0.0f ); + tess.svars.color.SetBlue( 0.0f ); + break; + + case lightMode_t::GRID: + // Store lightGrid1 as lightmap, + // the GLSL code will know how to deal with it. + lightmap = tr.lightGrid1Image; + break; + + case lightMode_t::MAP: + lightmap = GetLightMap( drawSurf ); + + break; + + default: + break; + } + + switch ( deluxeMode ) { + case deluxeMode_t::MAP: + // Deluxe mapping for world surface. + deluxemap = GetDeluxeMap( drawSurf ); + break; + + case deluxeMode_t::GRID: + // Deluxe mapping emulation from grid light for game models. + // Store lightGrid2 as deluxemap, + // the GLSL code will know how to deal with it. + deluxemap = tr.lightGrid2Image; + break; + + default: + break; + } + + bool enableGridLighting = ( lightMode == lightMode_t::GRID ); + bool enableGridDeluxeMapping = ( deluxeMode == deluxeMode_t::GRID ); + + // TODO: Update this when this is extended to MDV support + gl_lightMappingShaderMaterial->SetUniform_VertexInterpolation( false ); + + if ( glConfig2.dynamicLight ) { + gl_lightMappingShaderMaterial->SetUniformBlock_Lights( tr.dlightUBO ); + + // bind u_LightTiles + if ( r_dynamicLightRenderer.Get() == Util::ordinal( dynamicLightRenderer_t::TILED ) ) { + gl_lightMappingShaderMaterial->SetUniform_LightTilesIntBindless( + GL_BindToTMU( BIND_LIGHTTILES, tr.lighttileRenderImage ) + ); + } + } + + // u_DeformGen + gl_lightMappingShaderMaterial->SetUniform_Time( backEnd.refdef.floatTime - backEnd.currentEntity->e.shaderTime ); + + // u_InverseLightFactor + /* HACK: use sign to know if there is a light or not, and + then if it will receive overbright multiplication or not. */ + bool blendFunc_dstColor = ( pStage->stateBits & GLS_SRCBLEND_BITS ) == GLS_SRCBLEND_DST_COLOR; + bool noLight = pStage->shaderHasNoLight || lightMode == lightMode_t::FULLBRIGHT; + float inverseLightFactor = ( noLight && !blendFunc_dstColor ) ? tr.mapInverseLightFactor : -tr.mapInverseLightFactor; + gl_lightMappingShaderMaterial->SetUniform_InverseLightFactor( inverseLightFactor ); + + // u_ColorModulate + gl_lightMappingShaderMaterial->SetUniform_ColorModulate( rgbGen, alphaGen ); + + // u_Color + Tess_ComputeColor( pStage ); + gl_lightMappingShaderMaterial->SetUniform_Color( tess.svars.color ); + + // u_AlphaThreshold + gl_lightMappingShaderMaterial->SetUniform_AlphaTest( pStage->stateBits ); + + // bind u_HeightMap + if ( pStage->enableReliefMapping ) { + float depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale->value ); + depthScale *= shader->reliefDepthScale; + + gl_lightMappingShaderMaterial->SetUniform_ReliefDepthScale( depthScale ); + gl_lightMappingShaderMaterial->SetUniform_ReliefOffsetBias( shader->reliefOffsetBias ); + + // FIXME: if there is both, embedded heightmap in normalmap is used instead of standalone heightmap + if ( !pStage->hasHeightMapInNormalMap ) { + gl_lightMappingShaderMaterial->SetUniform_HeightMapBindless( + GL_BindToTMU( BIND_HEIGHTMAP, pStage->bundle[TB_HEIGHTMAP].image[0] ) + ); + } + } + + // bind u_DiffuseMap + gl_lightMappingShaderMaterial->SetUniform_DiffuseMapBindless( + GL_BindToTMU( BIND_DIFFUSEMAP, pStage->bundle[TB_DIFFUSEMAP].image[0] ) + ); + + if ( pStage->type != stageType_t::ST_LIGHTMAP ) { + Tess_ComputeTexMatrices( pStage ); + gl_lightMappingShaderMaterial->SetUniform_TextureMatrix( tess.svars.texMatrices[TB_DIFFUSEMAP] ); + } + + // bind u_NormalMap + if ( !!r_normalMapping->integer || pStage->hasHeightMapInNormalMap ) { + gl_lightMappingShaderMaterial->SetUniform_NormalMapBindless( + GL_BindToTMU( BIND_NORMALMAP, pStage->bundle[TB_NORMALMAP].image[0] ) + ); + } + + // bind u_NormalScale + if ( pStage->enableNormalMapping ) { + vec3_t normalScale; + SetNormalScale( pStage, normalScale ); + + gl_lightMappingShaderMaterial->SetUniform_NormalScale( normalScale ); + } + + // bind u_MaterialMap + if ( pStage->enableSpecularMapping || pStage->enablePhysicalMapping ) { + gl_lightMappingShaderMaterial->SetUniform_MaterialMapBindless( + GL_BindToTMU( BIND_MATERIALMAP, pStage->bundle[TB_MATERIALMAP].image[0] ) + ); + } + + if ( pStage->enableSpecularMapping ) { + float specExpMin = RB_EvalExpression( &pStage->specularExponentMin, r_specularExponentMin->value ); + float specExpMax = RB_EvalExpression( &pStage->specularExponentMax, r_specularExponentMax->value ); + + gl_lightMappingShaderMaterial->SetUniform_SpecularExponent( specExpMin, specExpMax ); + } + + // TODO: Move this to a per-entity buffer + // specular reflection + if ( tr.cubeHashTable != nullptr ) { + cubemapProbe_t* cubeProbeNearest; + cubemapProbe_t* cubeProbeSecondNearest; + + image_t* cubeMap0 = nullptr; + image_t* cubeMap1 = nullptr; + + float interpolation = 0.0; + + bool isWorldEntity = backEnd.currentEntity == &tr.worldEntity; + + if ( backEnd.currentEntity && !isWorldEntity ) { + R_FindTwoNearestCubeMaps( backEnd.currentEntity->e.origin, &cubeProbeNearest, &cubeProbeSecondNearest ); + } else { + // FIXME position + R_FindTwoNearestCubeMaps( backEnd.viewParms.orientation.origin, &cubeProbeNearest, &cubeProbeSecondNearest ); + } + + if ( cubeProbeNearest == nullptr && cubeProbeSecondNearest == nullptr ) { + GLimp_LogComment( "cubeProbeNearest && cubeProbeSecondNearest == NULL\n" ); + + cubeMap0 = tr.whiteCubeImage; + cubeMap1 = tr.whiteCubeImage; + } else if ( cubeProbeNearest == nullptr ) { + GLimp_LogComment( "cubeProbeNearest == NULL\n" ); + + cubeMap0 = cubeProbeSecondNearest->cubemap; + } else if ( cubeProbeSecondNearest == nullptr ) { + GLimp_LogComment( "cubeProbeSecondNearest == NULL\n" ); + + cubeMap0 = cubeProbeNearest->cubemap; + } else { + float cubeProbeNearestDistance, cubeProbeSecondNearestDistance; + + if ( backEnd.currentEntity && !isWorldEntity ) { + cubeProbeNearestDistance = Distance( backEnd.currentEntity->e.origin, cubeProbeNearest->origin ); + cubeProbeSecondNearestDistance = Distance( backEnd.currentEntity->e.origin, cubeProbeSecondNearest->origin ); + } else { + // FIXME position + cubeProbeNearestDistance = Distance( backEnd.viewParms.orientation.origin, cubeProbeNearest->origin ); + cubeProbeSecondNearestDistance = Distance( backEnd.viewParms.orientation.origin, cubeProbeSecondNearest->origin ); + } + + interpolation = cubeProbeNearestDistance / ( cubeProbeNearestDistance + cubeProbeSecondNearestDistance ); + + if ( r_logFile->integer ) { + GLimp_LogComment( va( "cubeProbeNearestDistance = %f, cubeProbeSecondNearestDistance = %f, interpolation = %f\n", + cubeProbeNearestDistance, cubeProbeSecondNearestDistance, interpolation ) ); + } + + cubeMap0 = cubeProbeNearest->cubemap; + cubeMap1 = cubeProbeSecondNearest->cubemap; + } + + /* TODO: Check why it is required to test for this, why + cubeProbeNearest->cubemap and cubeProbeSecondNearest->cubemap + can be nullptr while cubeProbeNearest and cubeProbeSecondNearest + are not. Maybe this is only required while cubemaps are building. */ + if ( cubeMap0 == nullptr ) { + cubeMap0 = tr.whiteCubeImage; + } + + if ( cubeMap1 == nullptr ) { + cubeMap1 = tr.whiteCubeImage; + } + + // bind u_EnvironmentMap0 + gl_lightMappingShaderMaterial->SetUniform_EnvironmentMap0Bindless( + GL_BindToTMU( BIND_ENVIRONMENTMAP0, cubeMap0 ) + ); + + // bind u_EnvironmentMap1 + gl_lightMappingShaderMaterial->SetUniform_EnvironmentMap1Bindless( + GL_BindToTMU( BIND_ENVIRONMENTMAP1, cubeMap1 ) + ); + + // bind u_EnvironmentInterpolation + gl_lightMappingShaderMaterial->SetUniform_EnvironmentInterpolation( interpolation ); + + updated = true; + } + + // bind u_LightMap + if ( !enableGridLighting ) { + gl_lightMappingShaderMaterial->SetUniform_LightMapBindless( + GL_BindToTMU( BIND_LIGHTMAP, lightmap ) + ); + } else { + gl_lightMappingShaderMaterial->SetUniform_LightGrid1Bindless( GL_BindToTMU( BIND_LIGHTMAP, lightmap ) ); + } + + // bind u_DeluxeMap + if ( !enableGridDeluxeMapping ) { + gl_lightMappingShaderMaterial->SetUniform_DeluxeMapBindless( + GL_BindToTMU( BIND_DELUXEMAP, deluxemap ) + ); + } else { + gl_lightMappingShaderMaterial->SetUniform_LightGrid2Bindless( GL_BindToTMU( BIND_DELUXEMAP, deluxemap ) ); + } + + // bind u_GlowMap + if ( !!r_glowMapping->integer ) { + gl_lightMappingShaderMaterial->SetUniform_GlowMapBindless( + GL_BindToTMU( BIND_GLOWMAP, pStage->bundle[TB_GLOWMAP].image[0] ) + ); + } + + gl_lightMappingShaderMaterial->WriteUniformsToBuffer( materials ); +} + +static void UpdateSurfaceDataReflection( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { + shader_t* shader = drawSurf->shader; + shaderStage_t* pStage = &shader->stages[stage]; + + const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); + materials += paddedOffset; + + bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; + if ( !updated ) { + return; + } + drawSurf->initialized[stage] = true; + + gl_reflectionShaderMaterial->SetUniform_VertexInterpolation( false ); + + // bind u_NormalMap + gl_reflectionShaderMaterial->SetUniform_NormalMapBindless( + GL_BindToTMU( 1, pStage->bundle[TB_NORMALMAP].image[0] ) + ); + + // bind u_ColorMap + if ( backEnd.currentEntity && ( backEnd.currentEntity != &tr.worldEntity ) ) { + GL_BindNearestCubeMap( gl_reflectionShaderMaterial->GetUniformLocation_ColorMap(), backEnd.currentEntity->e.origin ); + } else { + GL_BindNearestCubeMap( gl_reflectionShaderMaterial->GetUniformLocation_ColorMap(), backEnd.viewParms.orientation.origin ); + } + + if ( pStage->enableNormalMapping ) { + vec3_t normalScale; + SetNormalScale( pStage, normalScale ); + + gl_reflectionShaderMaterial->SetUniform_NormalScale( normalScale ); + } + + // bind u_HeightMap u_depthScale u_reliefOffsetBias + if ( pStage->enableReliefMapping ) { + float depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale->value ); + float reliefDepthScale = shader->reliefDepthScale; + depthScale *= reliefDepthScale == 0 ? 1 : reliefDepthScale; + gl_reflectionShaderMaterial->SetUniform_ReliefDepthScale( depthScale ); + gl_reflectionShaderMaterial->SetUniform_ReliefOffsetBias( shader->reliefOffsetBias ); + + // FIXME: if there is both, embedded heightmap in normalmap is used instead of standalone heightmap + if ( !pStage->hasHeightMapInNormalMap ) { + gl_reflectionShaderMaterial->SetUniform_HeightMapBindless( + GL_BindToTMU( 15, pStage->bundle[TB_HEIGHTMAP].image[0] ) + ); + } + } + + gl_reflectionShaderMaterial->WriteUniformsToBuffer( materials ); +} + +static void UpdateSurfaceDataSkybox( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { + shader_t* shader = drawSurf->shader; + shaderStage_t* pStage = &shader->stages[stage]; + + const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); + materials += paddedOffset; + + bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; + if ( !updated ) { + return; + } + drawSurf->initialized[stage] = true; + + gl_skyboxShaderMaterial->BindProgram( material.deformIndex ); + + // bind u_ColorMap + gl_skyboxShaderMaterial->SetUniform_ColorMapCubeBindless( + GL_BindToTMU( 0, pStage->bundle[TB_COLORMAP].image[0] ) + ); + + // u_AlphaThreshold + gl_skyboxShaderMaterial->SetUniform_AlphaTest( GLS_ATEST_NONE ); + + // u_InverseLightFactor + gl_skyboxShaderMaterial->SetUniform_InverseLightFactor( tr.mapInverseLightFactor ); + + gl_skyboxShaderMaterial->WriteUniformsToBuffer( materials ); +} + +static void UpdateSurfaceDataScreen( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { + shader_t* shader = drawSurf->shader; + shaderStage_t* pStage = &shader->stages[stage]; + + const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); + materials += paddedOffset; + + bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; + if ( !updated ) { + return; + } + drawSurf->initialized[stage] = true; + + gl_screenShaderMaterial->BindProgram( pStage->deformIndex ); + + // bind u_CurrentMap + gl_screenShaderMaterial->SetUniform_CurrentMapBindless( BindAnimatedImage( 0, &drawSurf->shader->stages[stage].bundle[TB_COLORMAP] ) ); + + gl_screenShaderMaterial->WriteUniformsToBuffer( materials ); +} + +static void UpdateSurfaceDataHeatHaze( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { + shader_t* shader = drawSurf->shader; + shaderStage_t* pStage = &shader->stages[stage]; + + const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); + materials += paddedOffset; + + bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; + if ( !updated ) { + return; + } + drawSurf->initialized[stage] = true; + + // bind u_NormalMap + gl_heatHazeShaderMaterial->SetUniform_NormalMapBindless( + GL_BindToTMU( 0, pStage->bundle[TB_NORMALMAP].image[0] ) + ); + + float deformMagnitude = RB_EvalExpression( &pStage->deformMagnitudeExp, 1.0 ); + gl_heatHazeShaderMaterial->SetUniform_DeformMagnitude( deformMagnitude ); + + if ( pStage->enableNormalMapping ) { + vec3_t normalScale; + SetNormalScale( pStage, normalScale ); + + // bind u_NormalScale + gl_heatHazeShaderMaterial->SetUniform_NormalScale( normalScale ); + } + + // bind u_CurrentMap + gl_heatHazeShaderMaterial->SetUniform_CurrentMapBindless( + GL_BindToTMU( 1, tr.currentRenderImage[backEnd.currentMainFBO] ) + ); + + gl_heatHazeShaderMaterial->WriteUniformsToBuffer( materials ); +} + +static void UpdateSurfaceDataLiquid( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { + shader_t* shader = drawSurf->shader; + shaderStage_t* pStage = &shader->stages[stage]; + + const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); + materials += paddedOffset; + + bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; + if ( !updated ) { + return; + } + drawSurf->initialized[stage] = true; + + float fogDensity = RB_EvalExpression( &pStage->fogDensityExp, 0.001 ); + vec4_t fogColor; + Tess_ComputeColor( pStage ); + VectorCopy( tess.svars.color.ToArray(), fogColor ); + + gl_liquidShaderMaterial->SetUniform_RefractionIndex( RB_EvalExpression( &pStage->refractionIndexExp, 1.0 ) ); + gl_liquidShaderMaterial->SetUniform_FresnelPower( RB_EvalExpression( &pStage->fresnelPowerExp, 2.0 ) ); + gl_liquidShaderMaterial->SetUniform_FresnelScale( RB_EvalExpression( &pStage->fresnelScaleExp, 1.0 ) ); + gl_liquidShaderMaterial->SetUniform_FresnelBias( RB_EvalExpression( &pStage->fresnelBiasExp, 0.05 ) ); + gl_liquidShaderMaterial->SetUniform_FogDensity( fogDensity ); + gl_liquidShaderMaterial->SetUniform_FogColor( fogColor ); + + gl_liquidShaderMaterial->SetUniform_UnprojectMatrix( backEnd.viewParms.unprojectionMatrix ); + gl_liquidShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); + gl_liquidShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); + + // NOTE: specular component is computed by shader. + // FIXME: physical mapping is not implemented. + if ( pStage->enableSpecularMapping ) { + float specMin = RB_EvalExpression( &pStage->specularExponentMin, r_specularExponentMin->value ); + float specMax = RB_EvalExpression( &pStage->specularExponentMax, r_specularExponentMax->value ); + gl_liquidShaderMaterial->SetUniform_SpecularExponent( specMin, specMax ); + } + + // bind u_CurrentMap + gl_liquidShaderMaterial->SetUniform_CurrentMapBindless( GL_BindToTMU( 0, tr.currentRenderImage[backEnd.currentMainFBO] ) ); + + // bind u_PortalMap + gl_liquidShaderMaterial->SetUniform_PortalMapBindless( GL_BindToTMU( 1, tr.portalRenderImage ) ); + + // depth texture + gl_liquidShaderMaterial->SetUniform_DepthMapBindless( GL_BindToTMU( 2, tr.currentDepthImage ) ); + + // bind u_HeightMap u_depthScale u_reliefOffsetBias + if ( pStage->enableReliefMapping ) { + float depthScale; + float reliefDepthScale; + + depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale->value ); + reliefDepthScale = tess.surfaceShader->reliefDepthScale; + depthScale *= reliefDepthScale == 0 ? 1 : reliefDepthScale; + gl_liquidShaderMaterial->SetUniform_ReliefDepthScale( depthScale ); + gl_liquidShaderMaterial->SetUniform_ReliefOffsetBias( tess.surfaceShader->reliefOffsetBias ); + + // FIXME: if there is both, embedded heightmap in normalmap is used instead of standalone heightmap + if ( !pStage->hasHeightMapInNormalMap ) { + gl_liquidShaderMaterial->SetUniform_HeightMapBindless( GL_BindToTMU( 15, pStage->bundle[TB_HEIGHTMAP].image[0] ) ); + } + } + + // bind u_NormalMap + gl_liquidShaderMaterial->SetUniform_NormalMapBindless( GL_BindToTMU( 3, pStage->bundle[TB_NORMALMAP].image[0] ) ); + + // bind u_NormalScale + if ( pStage->enableNormalMapping ) { + vec3_t normalScale; + // FIXME: NormalIntensity default was 0.5 + SetNormalScale( pStage, normalScale ); + + gl_liquidShaderMaterial->SetUniform_NormalScale( normalScale ); + } + + gl_liquidShaderMaterial->WriteUniformsToBuffer( materials ); +} + +/* +* Buffer layout: +* // Static surfaces data: +* // Material0 +* // Surface/stage0_0: +* uniform0_0 +* uniform0_1 +* .. +* uniform0_x +* optional_struct_padding +* // Surface/stage0_1: +* .. +* // Surface/stage0_y: +* uniform0_0 +* uniform0_1 +* .. +* uniform0_x +* optional_struct_padding +* optional_material1_padding +* // Material1 +* // Surface/stage1_0: +* .. +* // Surface/stage1_y: +* .. +* .. +* // Materialz: +* .. +* .. +* // Dynamic surfaces data: +* // Same as the static layout +*/ +// Buffer is separated into static and dynamic parts so we can just update the whole dynamic range at once +// This will generate the actual buffer with per-stage values AFTER materials are generated +void MaterialSystem::GenerateWorldMaterialsBuffer() { + Log::Debug( "Generating materials buffer" ); + + uint32_t offset = 0; + + materialsSSBO.BindBuffer(); + + // Compute data size for static surfaces + for ( MaterialPack& pack : materialPacks ) { + for ( Material& material : pack.materials ) { + // Any new material in the buffer must start on an offset that is an integer multiple of + // the padded size of the material struct + const uint32_t paddedSize = material.shader->GetPaddedSize(); + const uint32_t padding = ( offset % paddedSize == 0 ) ? 0 : paddedSize - ( offset % paddedSize ); + + offset += padding; + material.staticMaterialsSSBOOffset = offset; + offset += paddedSize * material.totalStaticDrawSurfCount; + } + } + + dynamicDrawSurfsOffset = offset; + + // Compute data size for dynamic surfaces + for ( MaterialPack& pack : materialPacks ) { + for ( Material& material : pack.materials ) { + // Any new material in the buffer must start on an offset that is an integer multiple of + // the padded size of the material struct + const uint32_t paddedSize = material.shader->GetPaddedSize(); + const uint32_t padding = ( offset % paddedSize == 0 ) ? 0 : paddedSize - ( offset % paddedSize ); + + offset += padding; + material.dynamicMaterialsSSBOOffset = offset; + offset += paddedSize * material.totalDynamicDrawSurfCount; + } + } + + dynamicDrawSurfsSize = offset - dynamicDrawSurfsOffset; + + // 4 bytes per component + glBufferData( GL_SHADER_STORAGE_BUFFER, offset * sizeof( uint32_t ), nullptr, GL_DYNAMIC_DRAW ); + uint32_t* materialsData = materialsSSBO.MapBufferRange( offset ); + memset( materialsData, 0, offset * sizeof( uint32_t ) ); + + for ( uint32_t materialPackID = 0; materialPackID < 3; materialPackID++ ) { + for ( Material& material : materialPacks[materialPackID].materials ) { + + for ( drawSurf_t* drawSurf : material.drawSurfs ) { + bool hasDynamicStages = false; + + uint32_t stage = 0; + for ( shaderStage_t* pStage = drawSurf->shader->stages; pStage < drawSurf->shader->lastStage; pStage++ ) { + if ( drawSurf->materialIDs[stage] != material.id || drawSurf->materialPackIDs[stage] != materialPackID ) { + continue; + } + + uint32_t SSBOOffset = 0; + uint32_t drawSurfCount = 0; + if ( pStage->dynamic ) { + SSBOOffset = material.dynamicMaterialsSSBOOffset; + drawSurfCount = material.currentDynamicDrawSurfCount; + material.currentDynamicDrawSurfCount++; + } else { + SSBOOffset = material.staticMaterialsSSBOOffset; + drawSurfCount = material.currentStaticDrawSurfCount; + material.currentStaticDrawSurfCount++; + } + + drawSurf->materialsSSBOOffset[stage] = ( SSBOOffset + drawSurfCount * material.shader->GetPaddedSize() ) / + material.shader->GetPaddedSize(); + + if ( pStage->dynamic ) { + hasDynamicStages = true; + } + + AddStageTextures( drawSurf, pStage, &material ); + + switch ( pStage->type ) { + case stageType_t::ST_COLORMAP: + // generic2D + UpdateSurfaceDataGeneric( materialsData, material, drawSurf, stage ); + break; + case stageType_t::ST_STYLELIGHTMAP: + case stageType_t::ST_STYLECOLORMAP: + UpdateSurfaceDataGeneric( materialsData, material, drawSurf, stage ); + break; + case stageType_t::ST_LIGHTMAP: + case stageType_t::ST_DIFFUSEMAP: + case stageType_t::ST_COLLAPSE_COLORMAP: + case stageType_t::ST_COLLAPSE_DIFFUSEMAP: + UpdateSurfaceDataLightMapping( materialsData, material, drawSurf, stage ); + break; + case stageType_t::ST_REFLECTIONMAP: + case stageType_t::ST_COLLAPSE_REFLECTIONMAP: + UpdateSurfaceDataReflection( materialsData, material, drawSurf, stage ); + break; + case stageType_t::ST_REFRACTIONMAP: + case stageType_t::ST_DISPERSIONMAP: + // Not implemented yet + break; + case stageType_t::ST_SKYBOXMAP: + UpdateSurfaceDataSkybox( materialsData, material, drawSurf, stage ); + break; + case stageType_t::ST_SCREENMAP: + UpdateSurfaceDataScreen( materialsData, material, drawSurf, stage ); + break; + case stageType_t::ST_PORTALMAP: + // This is supposedly used for alphagen portal and portal surfaces should never get here + ASSERT_UNREACHABLE(); + break; + case stageType_t::ST_HEATHAZEMAP: + UpdateSurfaceDataHeatHaze( materialsData, material, drawSurf, stage ); + break; + case stageType_t::ST_LIQUIDMAP: + UpdateSurfaceDataLiquid( materialsData, material, drawSurf, stage ); + break; + + default: + break; + } + + tess.currentDrawSurf = drawSurf; + + tess.currentSSBOOffset = tess.currentDrawSurf->materialsSSBOOffset[stage]; + tess.materialID = tess.currentDrawSurf->materialIDs[stage]; + tess.materialPackID = tess.currentDrawSurf->materialPackIDs[stage]; + + tess.multiDrawPrimitives = 0; + tess.numIndexes = 0; + tess.numVertexes = 0; + tess.attribsSet = 0; + + rb_surfaceTable[Util::ordinal( *drawSurf->surface )]( drawSurf->surface ); + + pStage->colorRenderer( pStage ); + + if ( pStage->dynamic ) { + drawSurf->materialsSSBOOffset[stage] = ( SSBOOffset - dynamicDrawSurfsOffset + drawSurfCount * + material.shader->GetPaddedSize() ) / material.shader->GetPaddedSize(); + } + + stage++; + } + + if ( hasDynamicStages ) { + // We need a copy here because the memory pointed to by drawSurf will change later + // We'll probably need a separate buffer for entities other than world entity + ensure we don't store a drawSurf with + // invalid pointers + dynamicDrawSurfs.emplace_back( *drawSurf ); + } + } + } + } + + materialsSSBO.UnmapBuffer(); +} + +// This generates the buffer GLIndirect commands +void MaterialSystem::GenerateWorldCommandBuffer() { + Log::Debug( "Generating world command buffer" ); + + uint32_t count = 0; + for ( const MaterialPack& pack : materialPacks ) { + for ( const Material& material : pack.materials ) { + count += material.drawCommands.size(); + } + } + + if ( count == 0 ) { + return; + } + + Log::Debug( "CmdBuffer size: %u", count ); + + commandBuffer.BindBuffer(); + glBufferData( GL_DRAW_INDIRECT_BUFFER, count * sizeof( GLIndirectBuffer::GLIndirectCommand ), nullptr, GL_STATIC_DRAW ); + + GLIndirectBuffer::GLIndirectCommand* commands = commandBuffer.MapBufferRange( count ); + uint32_t offset = 0; + for ( MaterialPack& pack : materialPacks ) { + for ( Material& material : pack.materials ) { + material.staticCommandOffset = offset; + + for ( const DrawCommand& drawCmd : material.drawCommands ) { + memcpy( commands, &drawCmd.cmd, sizeof( GLIndirectBuffer::GLIndirectCommand ) ); + commands++; + offset++; + } + } + } + + commandBuffer.UnmapBuffer(); + GL_CheckErrors(); +} + +static void BindShaderGeneric( Material* material ) { + gl_genericShaderMaterial->SetVertexAnimation( material->vertexAnimation ); + + gl_genericShaderMaterial->SetTCGenEnvironment( material->tcGenEnvironment ); + gl_genericShaderMaterial->SetTCGenLightmap( material->tcGen_Lightmap ); + + gl_genericShaderMaterial->SetDepthFade( material->hasDepthFade ); + gl_genericShaderMaterial->SetVertexSprite( material->vboVertexSprite ); + + gl_genericShaderMaterial->BindProgram( material->deformIndex ); +} + +static void BindShaderLightMapping( Material* material ) { + gl_lightMappingShaderMaterial->SetVertexAnimation( material->vertexAnimation ); + gl_lightMappingShaderMaterial->SetBspSurface( material->bspSurface ); + + gl_lightMappingShaderMaterial->SetDeluxeMapping( material->enableDeluxeMapping ); + + gl_lightMappingShaderMaterial->SetGridLighting( material->enableGridLighting ); + + gl_lightMappingShaderMaterial->SetGridDeluxeMapping( material->enableGridDeluxeMapping ); + + gl_lightMappingShaderMaterial->SetHeightMapInNormalMap( material->hasHeightMapInNormalMap ); + + gl_lightMappingShaderMaterial->SetReliefMapping( material->enableReliefMapping ); + + gl_lightMappingShaderMaterial->SetReflectiveSpecular( material->enableNormalMapping && tr.cubeHashTable != nullptr ); + + gl_lightMappingShaderMaterial->SetPhysicalShading( material->enablePhysicalMapping ); + + gl_lightMappingShaderMaterial->BindProgram( material->deformIndex ); +} + +static void BindShaderReflection( Material* material ) { + gl_reflectionShaderMaterial->SetHeightMapInNormalMap( material->hasHeightMapInNormalMap ); + + gl_reflectionShaderMaterial->SetReliefMapping( material->enableReliefMapping ); + + gl_reflectionShaderMaterial->SetVertexAnimation( material->vertexAnimation ); + + gl_reflectionShaderMaterial->BindProgram( material->deformIndex ); +} + +static void BindShaderSkybox( Material* material ) { + gl_skyboxShaderMaterial->BindProgram( material->deformIndex ); +} + +static void BindShaderScreen( Material* material ) { + gl_screenShaderMaterial->BindProgram( material->deformIndex ); +} + +static void BindShaderHeatHaze( Material* material ) { + gl_heatHazeShaderMaterial->SetVertexAnimation( material->vertexAnimation ); + + gl_heatHazeShaderMaterial->SetVertexSprite( material->vboVertexSprite ); + + gl_heatHazeShaderMaterial->BindProgram( material->deformIndex ); +} + +static void BindShaderLiquid( Material* material ) { + gl_liquidShaderMaterial->SetHeightMapInNormalMap( material->hasHeightMapInNormalMap ); + + gl_liquidShaderMaterial->SetReliefMapping( material->enableReliefMapping ); + + gl_liquidShaderMaterial->BindProgram( material->deformIndex ); +} + +// ProcessMaterial*() are essentially same as BindShader*(), but only set the GL program id to the material, +// without actually binding it +static void ProcessMaterialGeneric( Material* material, shaderStage_t* pStage, shader_t* shader ) { + material->shader = gl_genericShaderMaterial; + + material->vertexAnimation = false; + material->tcGenEnvironment = pStage->tcGen_Environment; + material->tcGen_Lightmap = pStage->tcGen_Lightmap; + material->vboVertexSprite = shader->autoSpriteMode != 0; + material->deformIndex = pStage->deformIndex; + + gl_genericShaderMaterial->SetVertexAnimation( false ); + + gl_genericShaderMaterial->SetTCGenEnvironment( pStage->tcGen_Environment ); + gl_genericShaderMaterial->SetTCGenLightmap( pStage->tcGen_Lightmap ); + + bool hasDepthFade = pStage->hasDepthFade && !shader->autoSpriteMode; + material->hasDepthFade = hasDepthFade; + gl_genericShaderMaterial->SetDepthFade( hasDepthFade ); + gl_genericShaderMaterial->SetVertexSprite( shader->autoSpriteMode != 0 ); + + material->program = gl_genericShaderMaterial->GetProgram( pStage->deformIndex ); +} + +static void ProcessMaterialLightMapping( Material* material, shaderStage_t* pStage, drawSurf_t* drawSurf ) { + material->shader = gl_lightMappingShaderMaterial; + + material->vertexAnimation = false; + material->bspSurface = false; + + gl_lightMappingShaderMaterial->SetVertexAnimation( false ); + gl_lightMappingShaderMaterial->SetBspSurface( drawSurf->bspSurface ); + + lightMode_t lightMode = lightMode_t::FULLBRIGHT; + deluxeMode_t deluxeMode = deluxeMode_t::NONE; + + bool hack = drawSurf->shader->lastStage != drawSurf->shader->stages + && drawSurf->shader->stages[0].rgbGen == colorGen_t::CGEN_VERTEX; + if ( ( tess.surfaceShader->surfaceFlags & SURF_NOLIGHTMAP ) && !hack ) { + // Use fullbright on “surfaceparm nolightmap” materials. + } else if ( pStage->type == stageType_t::ST_COLLAPSE_COLORMAP ) { + /* Use fullbright for collapsed stages without lightmaps, + for example: + { + map textures/texture_d + heightMap textures/texture_h + } + + This is doable for some complex multi-stage materials. */ + } else if ( drawSurf->bspSurface ) { + lightMode = tr.worldLight; + deluxeMode = tr.worldDeluxe; + + if ( lightMode == lightMode_t::MAP ) { + bool hasLightMap = ( drawSurf->lightmapNum() >= 0 ); + + if ( !hasLightMap ) { + lightMode = lightMode_t::VERTEX; + deluxeMode = deluxeMode_t::NONE; + } + } + } else { + lightMode = tr.modelLight; + deluxeMode = tr.modelDeluxe; + } + + bool enableDeluxeMapping = ( deluxeMode == deluxeMode_t::MAP ); + bool enableGridLighting = ( lightMode == lightMode_t::GRID ); + bool enableGridDeluxeMapping = ( deluxeMode == deluxeMode_t::GRID ); + + DAEMON_ASSERT( !( enableDeluxeMapping && enableGridDeluxeMapping ) ); + + material->enableDeluxeMapping = enableDeluxeMapping; + material->enableGridLighting = enableGridLighting; + material->enableGridDeluxeMapping = enableGridDeluxeMapping; + material->hasHeightMapInNormalMap = pStage->hasHeightMapInNormalMap; + material->enableReliefMapping = pStage->enableReliefMapping; + material->enableNormalMapping = pStage->enableNormalMapping && tr.cubeHashTable != nullptr; + material->enablePhysicalMapping = pStage->enablePhysicalMapping; + material->deformIndex = pStage->deformIndex; + + gl_lightMappingShaderMaterial->SetDeluxeMapping( enableDeluxeMapping ); + + gl_lightMappingShaderMaterial->SetGridLighting( enableGridLighting ); + + gl_lightMappingShaderMaterial->SetGridDeluxeMapping( enableGridDeluxeMapping ); + + gl_lightMappingShaderMaterial->SetHeightMapInNormalMap( pStage->hasHeightMapInNormalMap ); + + gl_lightMappingShaderMaterial->SetReliefMapping( pStage->enableReliefMapping ); + + gl_lightMappingShaderMaterial->SetReflectiveSpecular( pStage->enableNormalMapping && tr.cubeHashTable != nullptr ); + + gl_lightMappingShaderMaterial->SetPhysicalShading( pStage->enablePhysicalMapping ); + + material->program = gl_lightMappingShaderMaterial->GetProgram( pStage->deformIndex ); +} + +static void ProcessMaterialReflection( Material* material, shaderStage_t* pStage ) { + material->shader = gl_reflectionShaderMaterial; + + material->hasHeightMapInNormalMap = pStage->hasHeightMapInNormalMap; + material->enableReliefMapping = pStage->enableReliefMapping; + material->vertexAnimation = false; + material->deformIndex = pStage->deformIndex; + + gl_reflectionShaderMaterial->SetHeightMapInNormalMap( pStage->hasHeightMapInNormalMap ); + + gl_reflectionShaderMaterial->SetReliefMapping( pStage->enableReliefMapping ); + + gl_reflectionShaderMaterial->SetVertexAnimation( false ); + + material->program = gl_reflectionShaderMaterial->GetProgram( pStage->deformIndex ); +} + +static void ProcessMaterialSkybox( Material* material, shaderStage_t* pStage ) { + material->shader = gl_skyboxShaderMaterial; + + material->deformIndex = pStage->deformIndex; + + material->program = gl_skyboxShaderMaterial->GetProgram( pStage->deformIndex ); +} + +static void ProcessMaterialScreen( Material* material, shaderStage_t* pStage ) { + material->shader = gl_screenShaderMaterial; + + material->deformIndex = pStage->deformIndex; + + material->program = gl_screenShaderMaterial->GetProgram( pStage->deformIndex ); +} + +static void ProcessMaterialHeatHaze( Material* material, shaderStage_t* pStage, shader_t* shader ) { + material->shader = gl_heatHazeShaderMaterial; + + material->vertexAnimation = false; + material->deformIndex = pStage->deformIndex; + + gl_heatHazeShaderMaterial->SetVertexAnimation( false ); + if ( shader->autoSpriteMode ) { + gl_heatHazeShaderMaterial->SetVertexSprite( true ); + } else { + gl_heatHazeShaderMaterial->SetVertexSprite( false ); + } + + material->program = gl_heatHazeShaderMaterial->GetProgram( pStage->deformIndex ); +} +static void ProcessMaterialLiquid( Material* material, shaderStage_t* pStage ) { + material->shader = gl_liquidShaderMaterial; + + material->hasHeightMapInNormalMap = pStage->hasHeightMapInNormalMap; + material->enableReliefMapping = pStage->enableReliefMapping; + material->deformIndex = pStage->deformIndex; + + gl_liquidShaderMaterial->SetHeightMapInNormalMap( pStage->hasHeightMapInNormalMap ); + + gl_liquidShaderMaterial->SetReliefMapping( pStage->enableReliefMapping ); + + material->program = gl_liquidShaderMaterial->GetProgram( pStage->deformIndex ); +} + +/* This will only generate the materials themselves +* A material represents a distinct global OpenGL state (e. g. blend function, depth test, depth write etc.) +* Materials can have a dependency on other materials to make sure that consecutive stages are rendered in the proper order */ +void MaterialSystem::GenerateWorldMaterials() { + const int current_r_nocull = r_nocull->integer; + const int current_r_drawworld = r_drawworld->integer; + r_nocull->integer = 1; + r_drawworld->integer = 1; + generatingWorldCommandBuffer = true; + + Log::Debug( "Generating world materials" ); + + R_AddWorldSurfaces(); + + Log::Notice( "World bounds: min: %f %f %f max: %f %f %f", tr.viewParms.visBounds[0][0], tr.viewParms.visBounds[0][1], + tr.viewParms.visBounds[0][2], tr.viewParms.visBounds[1][0], tr.viewParms.visBounds[1][1], tr.viewParms.visBounds[1][2] ); + VectorCopy( tr.viewParms.visBounds[0], worldViewBounds[0] ); + VectorCopy( tr.viewParms.visBounds[1], worldViewBounds[1] ); + + backEnd.currentEntity = &tr.worldEntity; + + drawSurf_t* drawSurf; + + uint32_t id = 0; + uint32_t previousMaterialID = 0; + uint32_t packIDs[3] = { 0, 0, 0 }; + skipDrawCommands = true; + + for ( int i = 0; i < tr.refdef.numDrawSurfs; i++ ) { + drawSurf = &tr.refdef.drawSurfs[i]; + if ( drawSurf->entity != &tr.worldEntity ) { + continue; + } + + shader_t* shader = drawSurf->shader; + if ( !shader ) { + continue; + } + + shader = shader->remappedShader ? shader->remappedShader : shader; + if ( shader->isSky || shader->isPortal ) { + continue; + } + + // Don't add SF_SKIP surfaces + if ( *drawSurf->surface == surfaceType_t::SF_SKIP ) { + continue; + } + + rb_surfaceTable[Util::ordinal( *( drawSurf->surface ) )]( drawSurf->surface ); + + uint32_t stage = 0; + for ( shaderStage_t* pStage = drawSurf->shader->stages; pStage < drawSurf->shader->lastStage; pStage++ ) { + Material material; + + uint32_t materialPack = 0; + if ( shader->sort == Util::ordinal( shaderSort_t::SS_DEPTH ) ) { + materialPack = 0; + } else if ( shader->sort >= Util::ordinal( shaderSort_t::SS_ENVIRONMENT_FOG ) + && shader->sort <= Util::ordinal( shaderSort_t::SS_OPAQUE ) ) { + materialPack = 1; + } else { + materialPack = 2; + } + id = packIDs[materialPack]; + + // In surfaces with multiple stages each consecutive stage must be drawn after the previous stage, + // except if an opaque stage follows a transparent stage etc. + if ( stage > 0 ) { + material.useSync = true; + material.syncMaterial = previousMaterialID; + } + + material.stateBits = pStage->stateBits; + // GLS_ATEST_BITS don't matter here as they don't change GL state + material.stateBits &= GLS_DEPTHFUNC_BITS | GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS | GLS_POLYMODE_LINE | GLS_DEPTHTEST_DISABLE + | GLS_COLORMASK_BITS | GLS_DEPTHMASK_TRUE; + material.stageType = pStage->type; + material.cullType = shader->cullType; + material.usePolygonOffset = shader->polygonOffset; + + material.vbo = glState.currentVBO; + material.ibo = glState.currentIBO; + + ComputeDynamics( pStage ); + + if ( pStage->texturesDynamic ) { + drawSurf->texturesDynamic[stage] = true; + } + + switch ( pStage->type ) { + case stageType_t::ST_COLORMAP: + // generic2D also uses this, but it's for ui only, so skip that for now + ProcessMaterialGeneric( &material, pStage, drawSurf->shader ); + break; + case stageType_t::ST_STYLELIGHTMAP: + case stageType_t::ST_STYLECOLORMAP: + ProcessMaterialGeneric( &material, pStage, drawSurf->shader ); + break; + case stageType_t::ST_LIGHTMAP: + case stageType_t::ST_DIFFUSEMAP: + case stageType_t::ST_COLLAPSE_COLORMAP: + case stageType_t::ST_COLLAPSE_DIFFUSEMAP: + ProcessMaterialLightMapping( &material, pStage, drawSurf ); + break; + case stageType_t::ST_REFLECTIONMAP: + case stageType_t::ST_COLLAPSE_REFLECTIONMAP: + ProcessMaterialReflection( &material, pStage ); + break; + case stageType_t::ST_REFRACTIONMAP: + case stageType_t::ST_DISPERSIONMAP: + // Not implemented yet + break; + case stageType_t::ST_SKYBOXMAP: + ProcessMaterialSkybox( &material, pStage ); + break; + case stageType_t::ST_SCREENMAP: + ProcessMaterialScreen( &material, pStage ); + break; + case stageType_t::ST_PORTALMAP: + // This is supposedly used for alphagen portal and portal surfaces should never get here + ASSERT_UNREACHABLE(); + break; + case stageType_t::ST_HEATHAZEMAP: + // FIXME: This requires 2 draws per surface stage rather than 1 + ProcessMaterialHeatHaze( &material, pStage, drawSurf->shader ); + break; + case stageType_t::ST_LIQUIDMAP: + ProcessMaterialLiquid( &material, pStage ); + break; + + default: + break; + } + + std::vector& materials = materialPacks[materialPack].materials; + std::vector::iterator currentSearchIt = materials.begin(); + std::vector::iterator materialIt; + // Look for this material in the ones we already have + while( true ) { + materialIt = std::find( currentSearchIt, materials.end(), material ); + if ( materialIt == materials.end() ) { + break; + } + if ( material.useSync && materialIt->id < material.syncMaterial ) { + currentSearchIt = materialIt + 1; + } else { + break; + } + } + + // Add it at the back if not found + if ( materialIt == materials.end() ) { + material.id = id; + previousMaterialID = id; + materials.emplace_back( material ); + id++; + } else { + previousMaterialID = materialIt->id; + } + + pStage->useMaterialSystem = true; + materials[previousMaterialID].totalDrawSurfCount++; + if ( pStage->dynamic ) { + materials[previousMaterialID].totalDynamicDrawSurfCount++; + } else { + materials[previousMaterialID].totalStaticDrawSurfCount++; + } + + if ( std::find( materials[previousMaterialID].drawSurfs.begin(), materials[previousMaterialID].drawSurfs.end(), drawSurf ) + == materials[previousMaterialID].drawSurfs.end() ) { + materials[previousMaterialID].drawSurfs.emplace_back( drawSurf ); + } + + drawSurf->materialIDs[stage] = previousMaterialID; + drawSurf->materialPackIDs[stage] = materialPack; + + packIDs[materialPack] = id; + + stage++; + } + } + skipDrawCommands = false; + + GenerateWorldMaterialsBuffer(); + + uint32_t totalCount = 0; + for ( MaterialPack& pack : materialPacks ) { + totalCount += pack.materials.size(); + } + Log::Notice( "Generated %u materials from %u surfaces", totalCount, tr.refdef.numDrawSurfs ); + /* for ( const MaterialPack& materialPack : materialPacks ) { + Log::Notice( "materialPack sort: %i %i", Util::ordinal( materialPack.fromSort ), Util::ordinal( materialPack.toSort ) ); + for ( const Material& material : materialPack.materials ) { + Log::Notice( "id: %u, useSync: %b, sync: %u, program: %i, stateBits: %u, totalDrawSurfCount: %u, shader: %s, vbo: %s, ibo: %s" + ", staticDrawSurfs: %u, dynamicDrawSurfs: %u, culling: %i", + material.id, material.useSync, material.syncMaterial, material.program, material.stateBits, material.totalDrawSurfCount, + material.shader->GetName(), material.vbo->name, material.ibo->name, material.currentStaticDrawSurfCount, + material.currentDynamicDrawSurfCount, material.cullType ); + } + } */ + + r_nocull->integer = current_r_nocull; + r_drawworld->integer = current_r_drawworld; + AddAllWorldSurfaces(); + + skipDrawCommands = true; + GeneratePortalBoundingSpheres(); + skipDrawCommands = false; + + generatedWorldCommandBuffer = true; +} + +void MaterialSystem::AddAllWorldSurfaces() { + GenerateWorldCommandBuffer(); + + generatingWorldCommandBuffer = false; +} + +void MaterialSystem::AddStageTextures( drawSurf_t* drawSurf, shaderStage_t* pStage, Material* material ) { + for ( const textureBundle_t& bundle : pStage->bundle ) { + if ( bundle.isVideoMap ) { + material->AddTexture( tr.cinematicImage[bundle.videoMapHandle]->texture ); + continue; + } + + for ( image_t* image : bundle.image ) { + if ( image ) { + material->AddTexture( image->texture ); + } + } + } + + // Add lightmap and deluxemap for this surface to the material as well + + lightMode_t lightMode = lightMode_t::FULLBRIGHT; + deluxeMode_t deluxeMode = deluxeMode_t::NONE; + + bool hack = drawSurf->shader->lastStage != drawSurf->shader->stages + && drawSurf->shader->stages[0].rgbGen == colorGen_t::CGEN_VERTEX; + + if ( ( drawSurf->shader->surfaceFlags & SURF_NOLIGHTMAP ) && !hack ) { + // Use fullbright on “surfaceparm nolightmap” materials. + } else if ( pStage->type == stageType_t::ST_COLLAPSE_COLORMAP ) { + /* Use fullbright for collapsed stages without lightmaps, + for example: + + { + map textures/texture_d + heightMap textures/texture_h + } + + This is doable for some complex multi-stage materials. */ + } else if ( drawSurf->bspSurface ) { + lightMode = tr.worldLight; + deluxeMode = tr.worldDeluxe; + + if ( lightMode == lightMode_t::MAP ) { + bool hasLightMap = static_cast< size_t >( drawSurf->lightmapNum() ) < tr.lightmaps.size(); + + if ( !hasLightMap ) { + lightMode = lightMode_t::VERTEX; + deluxeMode = deluxeMode_t::NONE; + } + } + } else { + lightMode = tr.modelLight; + deluxeMode = tr.modelDeluxe; + } + + // u_Map, u_DeluxeMap + image_t* lightmap = tr.whiteImage; + image_t* deluxemap = tr.whiteImage; + + switch ( lightMode ) { + case lightMode_t::VERTEX: + break; + + case lightMode_t::GRID: + lightmap = tr.lightGrid1Image; + break; + + case lightMode_t::MAP: + lightmap = GetLightMap( drawSurf ); + break; + + default: + break; + } + + switch ( deluxeMode ) { + case deluxeMode_t::MAP: + deluxemap = GetDeluxeMap( drawSurf ); + break; + + case deluxeMode_t::GRID: + deluxemap = tr.lightGrid2Image; + break; + + default: + break; + } + + material->AddTexture( lightmap->texture ); + material->AddTexture( deluxemap->texture ); + + if ( glConfig2.dynamicLight ) { + if ( r_dynamicLightRenderer.Get() == Util::ordinal( dynamicLightRenderer_t::TILED ) ) { + material->AddTexture( tr.lighttileRenderImage->texture ); + } + } +} + +// Dynamic surfaces are those whose values in the SSBO can be updated +void MaterialSystem::UpdateDynamicSurfaces() { + if ( dynamicDrawSurfsSize == 0 ) { + return; + } + + materialsSSBO.BindBuffer(); + uint32_t* materialsData = materialsSSBO.MapBufferRange( dynamicDrawSurfsOffset, dynamicDrawSurfsSize ); + // Shader uniforms are set to 0 if they're not specified, so make sure we do that here too + memset( materialsData, 0, 4 * dynamicDrawSurfsSize ); + for ( drawSurf_t& drawSurf : dynamicDrawSurfs ) { + uint32_t stage = 0; + for ( shaderStage_t* pStage = drawSurf.shader->stages; pStage < drawSurf.shader->lastStage; pStage++ ) { + Material& material = materialPacks[drawSurf.materialPackIDs[stage]].materials[drawSurf.materialIDs[stage]]; + + switch ( pStage->type ) { + case stageType_t::ST_COLORMAP: + // generic2D also uses this, but it's for ui only, so skip that for now + UpdateSurfaceDataGeneric( materialsData, material, &drawSurf, stage ); + break; + case stageType_t::ST_STYLELIGHTMAP: + case stageType_t::ST_STYLECOLORMAP: + UpdateSurfaceDataGeneric( materialsData, material, &drawSurf, stage ); + break; + case stageType_t::ST_LIGHTMAP: + case stageType_t::ST_DIFFUSEMAP: + case stageType_t::ST_COLLAPSE_COLORMAP: + case stageType_t::ST_COLLAPSE_DIFFUSEMAP: + UpdateSurfaceDataLightMapping( materialsData, material, &drawSurf, stage ); + break; + case stageType_t::ST_REFLECTIONMAP: + case stageType_t::ST_COLLAPSE_REFLECTIONMAP: + UpdateSurfaceDataReflection( materialsData, material, &drawSurf, stage ); + break; + case stageType_t::ST_REFRACTIONMAP: + case stageType_t::ST_DISPERSIONMAP: + // Not implemented yet + break; + case stageType_t::ST_SKYBOXMAP: + UpdateSurfaceDataSkybox( materialsData, material, &drawSurf, stage ); + break; + case stageType_t::ST_SCREENMAP: + UpdateSurfaceDataScreen( materialsData, material, &drawSurf, stage ); + break; + case stageType_t::ST_PORTALMAP: + // This is supposedly used for alphagen portal and portal surfaces should never get here + ASSERT_UNREACHABLE(); + break; + case stageType_t::ST_HEATHAZEMAP: + UpdateSurfaceDataHeatHaze( materialsData, material, &drawSurf, stage ); + break; + case stageType_t::ST_LIQUIDMAP: + UpdateSurfaceDataLiquid( materialsData, material, &drawSurf, stage ); + break; + + default: + break; + } + + stage++; + } + } + materialsSSBO.UnmapBuffer(); +} + +void MaterialSystem::GeneratePortalBoundingSpheres() { + Log::Debug( "Generating portal bounding spheres" ); + + for ( drawSurf_t* drawSurf : portalSurfacesTmp ) { + tess.numVertexes = 0; + rb_surfaceTable[Util::ordinal( *( drawSurf->surface ) )]( drawSurf->surface ); + const int numVerts = tess.numVertexes; + vec3_t portalCenter{ 0.0, 0.0, 0.0 }; + for ( int vertIndex = 0; vertIndex < numVerts; vertIndex++ ) { + VectorAdd( portalCenter, tess.verts[vertIndex].xyz, portalCenter ); + } + VectorScale( portalCenter, 1.0 / numVerts, portalCenter ); + + float furthestDistance = 0.0; + for ( int vertIndex = 0; vertIndex < numVerts; vertIndex++ ) { + const float distance = Distance( portalCenter, tess.verts[vertIndex].xyz ); + furthestDistance = distance > furthestDistance ? distance : furthestDistance; + } + + portalSurfaces.emplace_back( *drawSurf ); + drawSurfBoundingSphere sphere; + VectorCopy( portalCenter, sphere.origin ); + sphere.radius = furthestDistance; + sphere.drawSurfID = portalSurfaces.size() - 1; + + portalBounds.emplace_back( sphere ); + } + + portalSurfacesTmp.clear(); +} + +void MaterialSystem::Free() { + generatedWorldCommandBuffer = false; + + dynamicDrawSurfs.clear(); + portalSurfaces.clear(); + portalSurfacesTmp.clear(); + portalBounds.clear(); + skyShaders.clear(); + renderedMaterials.clear(); + + for ( MaterialPack& pack : materialPacks ) { + for ( Material& material : pack.materials ) { + material.drawCommands.clear(); + material.drawSurfs.clear(); + } + pack.materials.clear(); + } +} + +// This gets the information for the surface vertex/index data through Tess +void MaterialSystem::AddDrawCommand( const uint32_t materialID, const uint32_t materialPackID, const uint32_t materialsSSBOOffset, + const GLuint count, const GLuint firstIndex ) { + // Don't add surfaces here if we're just trying to get some VBO/IBO information + if ( skipDrawCommands ) { + return; + } + + cmd.cmd.count = count; + cmd.cmd.instanceCount = 1; + cmd.cmd.firstIndex = firstIndex; + cmd.cmd.baseVertex = 0; + cmd.cmd.baseInstance = materialsSSBOOffset; + cmd.materialsSSBOOffset = materialsSSBOOffset; + + materialPacks[materialPackID].materials[materialID].drawCommands.emplace_back(cmd); + cmd.textureCount = 0; +} + +void MaterialSystem::AddTexture( Texture* texture ) { + if ( cmd.textureCount > MAX_DRAWCOMMAND_TEXTURES ) { + Sys::Drop( "Exceeded max DrawCommand textures" ); + } + cmd.textures[cmd.textureCount] = texture; + cmd.textureCount++; +} + +void MaterialSystem::AddPortalSurfaces() { + // Very inefficient + // TODO: Mark portals in the cull shader and do a readback to only add portals that can actually be seen + std::sort( portalBounds.begin(), portalBounds.end(), + []( const drawSurfBoundingSphere& lhs, const drawSurfBoundingSphere& rhs ) { + return Distance( backEnd.viewParms.orientation.origin, lhs.origin ) - lhs.radius < + Distance( backEnd.viewParms.orientation.origin, rhs.origin ) - rhs.radius; + } ); + for ( const drawSurfBoundingSphere& sphere : portalBounds ) { + R_MirrorViewBySurface( &portalSurfaces[sphere.drawSurfID] ); + } +} + +void MaterialSystem::RenderMaterials( const shaderSort_t fromSort, const shaderSort_t toSort ) { + if ( !r_drawworld->integer ) { + return; + } + + if ( frameStart ) { + renderedMaterials.clear(); + UpdateDynamicSurfaces(); + frameStart = false; + } + + materialsSSBO.BindBufferBase(); + + for ( MaterialPack& materialPack : materialPacks ) { + if ( materialPack.fromSort >= fromSort && materialPack.toSort <= toSort ) { + for ( Material& material : materialPack.materials ) { + RenderMaterial( material ); + renderedMaterials.emplace_back( &material ); + } + } + } + + // Draw the skybox here because we skipped R_AddWorldSurfaces() + const bool environmentFogDraw = ( fromSort <= shaderSort_t::SS_ENVIRONMENT_FOG ) && ( toSort >= shaderSort_t::SS_ENVIRONMENT_FOG ); + const bool environmentNoFogDraw = ( fromSort <= shaderSort_t::SS_ENVIRONMENT_NOFOG ) && toSort >= ( shaderSort_t::SS_ENVIRONMENT_NOFOG ); + if ( tr.hasSkybox && ( environmentFogDraw || environmentNoFogDraw ) ) { + const bool noFogPass = toSort >= shaderSort_t::SS_ENVIRONMENT_NOFOG; + for ( shader_t* skyShader : skyShaders ) { + if ( skyShader->noFog != noFogPass ) { + continue; + } + + tr.drawingSky = true; + Tess_Begin( Tess_StageIteratorSky, skyShader, nullptr, false, -1, 0, false ); + Tess_End(); + } + } +} + +void MaterialSystem::RenderMaterial( Material& material ) { + backEnd.currentEntity = &tr.worldEntity; + + GL_State( material.stateBits ); + if ( material.usePolygonOffset ) { + glEnable( GL_POLYGON_OFFSET_FILL ); + GL_PolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); + } else { + glDisable( GL_POLYGON_OFFSET_FILL ); + } + GL_Cull( material.cullType ); + + backEnd.orientation = backEnd.viewParms.world; + GL_LoadModelViewMatrix( backEnd.orientation.modelViewMatrix ); + + switch ( material.stageType ) { + case stageType_t::ST_COLORMAP: + case stageType_t::ST_STYLELIGHTMAP: + case stageType_t::ST_STYLECOLORMAP: + BindShaderGeneric( &material ); + + if ( material.tcGenEnvironment || material.vboVertexSprite ) { + gl_genericShaderMaterial->SetUniform_ViewOrigin( backEnd.orientation.viewOrigin ); + gl_genericShaderMaterial->SetUniform_ViewUp( backEnd.orientation.axis[2] ); + } + + gl_genericShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); + gl_genericShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); + break; + case stageType_t::ST_LIGHTMAP: + case stageType_t::ST_DIFFUSEMAP: + case stageType_t::ST_COLLAPSE_COLORMAP: + case stageType_t::ST_COLLAPSE_DIFFUSEMAP: + BindShaderLightMapping( &material ); + if ( tr.world ) { + gl_lightMappingShaderMaterial->SetUniform_LightGridOrigin( tr.world->lightGridGLOrigin ); + gl_lightMappingShaderMaterial->SetUniform_LightGridScale( tr.world->lightGridGLScale ); + } + // FIXME: else + + gl_lightMappingShaderMaterial->SetUniform_ViewOrigin( backEnd.orientation.viewOrigin ); + gl_lightMappingShaderMaterial->SetUniform_numLights( backEnd.refdef.numLights ); + gl_lightMappingShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); + gl_lightMappingShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); + break; + case stageType_t::ST_LIQUIDMAP: + BindShaderLiquid( &material ); + gl_liquidShaderMaterial->SetUniform_ViewOrigin( backEnd.viewParms.orientation.origin ); + gl_liquidShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); + gl_liquidShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); + break; + case stageType_t::ST_REFLECTIONMAP: + case stageType_t::ST_COLLAPSE_REFLECTIONMAP: + BindShaderReflection( &material ); + gl_reflectionShaderMaterial->SetUniform_ViewOrigin( backEnd.viewParms.orientation.origin ); + gl_reflectionShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); + gl_reflectionShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); + break; + case stageType_t::ST_REFRACTIONMAP: + case stageType_t::ST_DISPERSIONMAP: + // Not implemented yet + break; + case stageType_t::ST_SKYBOXMAP: + BindShaderSkybox( &material ); + gl_skyboxShaderMaterial->SetUniform_ViewOrigin( backEnd.viewParms.orientation.origin ); + gl_skyboxShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); + gl_skyboxShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); + break; + case stageType_t::ST_SCREENMAP: + BindShaderScreen( &material ); + gl_screenShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); + break; + case stageType_t::ST_PORTALMAP: + // This is supposedly used for alphagen portal and portal surfaces should never get here + ASSERT_UNREACHABLE(); + break; + case stageType_t::ST_HEATHAZEMAP: + // FIXME: This requires 2 draws per surface stage rather than 1 + BindShaderHeatHaze( &material ); + + if ( material.vboVertexSprite ) { + gl_heatHazeShaderMaterial->SetUniform_ViewOrigin( backEnd.orientation.viewOrigin ); + gl_heatHazeShaderMaterial->SetUniform_ViewUp( backEnd.orientation.axis[2] ); + } + + gl_heatHazeShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); + gl_heatHazeShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); + break; + default: + break; + } + + R_BindVBO( material.vbo ); + R_BindIBO( material.ibo ); + material.shader->SetRequiredVertexPointers(); + + if ( !material.texturesResident ) { + for ( Texture* texture : material.textures ) { + if ( !texture->IsResident() ) { + texture->MakeResident(); + + bool resident = glIsTextureHandleResidentARB( texture->bindlessTextureHandle ); + + if ( resident ) { + continue; + } + + for ( Material* mat : renderedMaterials ) { + Log::Warn( "Making material %u textures non-resident (%u)", mat->id, mat->textures.size() ); + for ( Texture* tex : mat->textures ) { + if ( tex->IsResident() ) { + tex->MakeNonResident(); + } + } + mat->texturesResident = false; + } + + texture->MakeResident(); + + resident = glIsTextureHandleResidentARB( texture->bindlessTextureHandle ); + + if( !resident ) { + Log::Warn( "Not enough texture space! Some textures may be missing" ); + break; + } + } + } + } + material.texturesResident = true; + + glMultiDrawElementsIndirect( GL_TRIANGLES, GL_UNSIGNED_INT, + BUFFER_OFFSET( material.staticCommandOffset * sizeof( GLIndirectBuffer::GLIndirectCommand ) ), + material.drawCommands.size(), 0 ); + + if ( material.usePolygonOffset ) { + glDisable( GL_POLYGON_OFFSET_FILL ); + } +} diff --git a/src/engine/renderer/Material.h b/src/engine/renderer/Material.h new file mode 100644 index 0000000000..664f8913ca --- /dev/null +++ b/src/engine/renderer/Material.h @@ -0,0 +1,201 @@ +/* +=========================================================================== + +Daemon BSD Source Code +Copyright (c) 2024 Daemon Developers +All rights reserved. + +This file is part of the Daemon BSD Source Code (Daemon Source Code). + +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. + +=========================================================================== +*/ +// Material.h + +#ifndef MATERIAL_H +#define MATERIAL_H + +#include + +#include "gl_shader.h" +#include "tr_local.h" + +static constexpr uint32_t MAX_DRAWCOMMAND_TEXTURES = 64; + +struct DrawCommand { + GLIndirectBuffer::GLIndirectCommand cmd; + uint32_t materialsSSBOOffset = 0; + uint32_t textureCount = 0; + Texture* textures[MAX_DRAWCOMMAND_TEXTURES]; + + DrawCommand() { + } + + DrawCommand( const DrawCommand& other ) { + cmd = other.cmd; + materialsSSBOOffset = other.materialsSSBOOffset; + textureCount = other.textureCount; + memcpy( textures, other.textures, textureCount * sizeof( Texture* ) ); + } +}; + +struct Material { + uint32_t materialsSSBOOffset = 0; + uint32_t staticMaterialsSSBOOffset = 0; + uint32_t dynamicMaterialsSSBOOffset = 0; + uint32_t totalDrawSurfCount = 0; + uint32_t totalStaticDrawSurfCount = 0; + uint32_t totalDynamicDrawSurfCount = 0; + uint32_t currentDrawSurfCount = 0; + uint32_t currentStaticDrawSurfCount = 0; + uint32_t currentDynamicDrawSurfCount = 0; + + uint32_t staticCommandOffset = 0; + + uint32_t id = 0; + bool useSync = false; + uint32_t syncMaterial = 0; // Must not be drawn before the material with this id + + uint32_t stateBits = 0; + stageType_t stageType; + GLuint program = 0; + GLShader* shader; + + int deformIndex; + bool vertexAnimation; + bool tcGenEnvironment; + bool tcGen_Lightmap; + bool hasDepthFade; + bool vboVertexSprite; + bool alphaTest; + + bool bspSurface; + bool enableDeluxeMapping; + bool enableGridLighting; + bool enableGridDeluxeMapping; + bool hasHeightMapInNormalMap; + bool enableReliefMapping; + bool enableNormalMapping; + bool enablePhysicalMapping; + + cullType_t cullType; + + bool usePolygonOffset = false; + + VBO_t* vbo; + IBO_t* ibo; + + std::vector drawSurfs; + std::vector drawCommands; + bool texturesResident = false; + std::vector textures; + + bool operator==( const Material& other ) { + return program == other.program && stateBits == other.stateBits && vbo == other.vbo && ibo == other.ibo + && cullType == other.cullType && usePolygonOffset == other.usePolygonOffset; + } + + void AddTexture( Texture* texture ) { + if ( !texture->hasBindlessHandle ) { + texture->GenBindlessHandle(); + } + + if ( std::find( textures.begin(), textures.end(), texture ) == textures.end() ) { + textures.emplace_back( texture ); + } + } +}; + +struct drawSurfBoundingSphere { + vec3_t origin; + float radius; + + uint32_t drawSurfID; +}; + +class MaterialSystem { + public: + bool generatedWorldCommandBuffer = false; + bool skipDrawCommands; + bool generatingWorldCommandBuffer = false; + vec3_t worldViewBounds[2] = {}; + + std::vector portalSurfacesTmp; + std::vector portalSurfaces; + std::vector portalBounds; + std::vector skyShaders; + + std::vector renderedMaterials; + + struct MaterialPack { + const shaderSort_t fromSort; + const shaderSort_t toSort; + std::vector materials; + + MaterialPack( const shaderSort_t newFromSort, const shaderSort_t newToSort ) : + fromSort( newFromSort ), + toSort( newToSort ) { + } + }; + + MaterialPack materialPacks[3]{ + { shaderSort_t::SS_DEPTH, shaderSort_t::SS_DEPTH }, + { shaderSort_t::SS_ENVIRONMENT_FOG, shaderSort_t::SS_OPAQUE }, + { shaderSort_t::SS_ENVIRONMENT_NOFOG, shaderSort_t::SS_POST_PROCESS } + }; + + bool frameStart = true; + + void AddTexture( Texture* texture ); + void AddDrawCommand( const uint32_t materialID, const uint32_t materialPackID, const uint32_t materialsSSBOOffset, + const GLuint count, const GLuint firstIndex ); + + void AddPortalSurfaces(); + void RenderMaterials( const shaderSort_t fromSort, const shaderSort_t toSort ); + void UpdateDynamicSurfaces(); + + void AddStageTextures( drawSurf_t* drawSurf, shaderStage_t* pStage, Material* material ); + void GenerateWorldMaterials(); + void GenerateWorldMaterialsBuffer(); + void GenerateWorldCommandBuffer(); + void GeneratePortalBoundingSpheres(); + + void AddAllWorldSurfaces(); + + void Free(); + + private: + DrawCommand cmd; + std::vector dynamicDrawSurfs; + uint32_t dynamicDrawSurfsOffset = 0; + uint32_t dynamicDrawSurfsSize = 0; + + void RenderMaterial( Material& material ); +}; + +extern GLSSBO materialsSSBO; +extern GLIndirectBuffer commandBuffer; +extern MaterialSystem materialSystem; + +#endif // MATERIAL_H diff --git a/src/engine/renderer/TextureManager.cpp b/src/engine/renderer/TextureManager.cpp new file mode 100644 index 0000000000..192fac60f6 --- /dev/null +++ b/src/engine/renderer/TextureManager.cpp @@ -0,0 +1,121 @@ +/* +=========================================================================== + +Daemon BSD Source Code +Copyright (c) 2024 Daemon Developers +All rights reserved. + +This file is part of the Daemon BSD Source Code (Daemon Source Code). + +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. + +=========================================================================== +*/ +// TextureManager.cpp + +#include "TextureManager.h" +#include "tr_local.h" + +Texture::Texture() { +} + +Texture::~Texture() { + if ( bindlessTextureResident ) { + MakeNonResident(); + } +} + +bool Texture::IsResident() const { + return bindlessTextureResident; +} + +void Texture::MakeResident() { + glMakeTextureHandleResidentARB( bindlessTextureHandle ); + bindlessTextureResident = true; +} + +void Texture::MakeNonResident() { + glMakeTextureHandleNonResidentARB( bindlessTextureHandle ); + bindlessTextureResident = false; +} + +void Texture::GenBindlessHandle() { + bindlessTextureHandle = glGetTextureHandleARB( textureHandle ); + + if ( bindlessTextureHandle == 0 ) { + Sys::Drop( "Failed to generate bindless texture handle" ); + } + + hasBindlessHandle = true; +} + +TextureManager::TextureManager() = default; +TextureManager::~TextureManager() = default; + +GLuint64 TextureManager::BindTexture( const GLint location, Texture *texture ) { + if( location == -1 ) { + return 0; + } + + if ( texture->IsResident() ) { + return texture->bindlessTextureHandle; + } + + if( std::find( textures.begin(), textures.end(), texture ) == textures.end() ) { + textures.push_back( texture ); + } + + // Bindless textures make the texture state immutable, so generate the handle as late as possible + if ( !texture->hasBindlessHandle ) { + texture->GenBindlessHandle(); + } + + texture->MakeResident(); + + // Make lowest priority textures non-resident first + int i = textures.size() - 1; + while ( !glIsTextureHandleResidentARB( texture->bindlessTextureHandle ) ) { + if ( i < 0 ) { + Sys::Drop( "No texture space available" ); + } + + if ( textures[i]->IsResident() ) { + textures[i]->MakeNonResident(); + texture->MakeResident(); + } + i--; + } + + GL_CheckErrors(); + + return texture->bindlessTextureHandle; +} + +void TextureManager::BindReservedTexture( const GLenum target, const GLuint handle ) { + glActiveTexture( GL_TEXTURE0 ); + glBindTexture( target, handle ); +} + +void TextureManager::FreeTextures() { + textures.clear(); +} diff --git a/src/engine/renderer/TextureManager.h b/src/engine/renderer/TextureManager.h new file mode 100644 index 0000000000..75c28b3bd9 --- /dev/null +++ b/src/engine/renderer/TextureManager.h @@ -0,0 +1,76 @@ +/* +=========================================================================== + +Daemon BSD Source Code +Copyright (c) 2024 Daemon Developers +All rights reserved. + +This file is part of the Daemon BSD Source Code (Daemon Source Code). + +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. + +=========================================================================== +*/ +// TextureManager.h + +#ifndef TEXTURE_MANAGER_H +#define TEXTURE_MANAGER_H + +#include +#include "GL/glew.h" + +class Texture { + public: + GLuint textureHandle = 0; + GLuint64 bindlessTextureHandle = 0; + bool hasBindlessHandle = false; + + GLenum target = GL_TEXTURE_2D; + + Texture(); + ~Texture(); + + bool IsResident() const; + void MakeResident(); + void MakeNonResident(); + + void GenBindlessHandle();; + + private: + bool bindlessTextureResident = false; +}; + +class TextureManager { + public: + TextureManager(); + ~TextureManager(); + + GLuint64 BindTexture( const GLint location, Texture* texture ); + void BindReservedTexture( const GLenum target, const GLuint handle ); + void FreeTextures(); + + private: + std::vector textures; +}; + +#endif // TEXTURE_MANAGER_H diff --git a/src/engine/renderer/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp index 2f0cbe4ff1..f782d015d0 100644 --- a/src/engine/renderer/gl_shader.cpp +++ b/src/engine/renderer/gl_shader.cpp @@ -41,17 +41,24 @@ ShaderKind shaderKind = ShaderKind::Unknown; GLShader_generic2D *gl_generic2DShader = nullptr; GLShader_generic *gl_genericShader = nullptr; +GLShader_genericMaterial *gl_genericShaderMaterial = nullptr; GLShader_lightMapping *gl_lightMappingShader = nullptr; +GLShader_lightMappingMaterial *gl_lightMappingShaderMaterial = nullptr; GLShader_forwardLighting_omniXYZ *gl_forwardLightingShader_omniXYZ = nullptr; GLShader_forwardLighting_projXYZ *gl_forwardLightingShader_projXYZ = nullptr; GLShader_forwardLighting_directionalSun *gl_forwardLightingShader_directionalSun = nullptr; GLShader_shadowFill *gl_shadowFillShader = nullptr; GLShader_reflection *gl_reflectionShader = nullptr; +GLShader_reflectionMaterial *gl_reflectionShaderMaterial = nullptr; GLShader_skybox *gl_skyboxShader = nullptr; +GLShader_skyboxMaterial *gl_skyboxShaderMaterial = nullptr; GLShader_fogQuake3 *gl_fogQuake3Shader = nullptr; +GLShader_fogQuake3Material *gl_fogQuake3ShaderMaterial = nullptr; GLShader_fogGlobal *gl_fogGlobalShader = nullptr; GLShader_heatHaze *gl_heatHazeShader = nullptr; +GLShader_heatHazeMaterial *gl_heatHazeShaderMaterial = nullptr; GLShader_screen *gl_screenShader = nullptr; +GLShader_screenMaterial *gl_screenShaderMaterial = nullptr; GLShader_portal *gl_portalShader = nullptr; GLShader_contrast *gl_contrastShader = nullptr; GLShader_cameraEffects *gl_cameraEffectsShader = nullptr; @@ -59,6 +66,7 @@ GLShader_blurX *gl_blurXShader = nullptr; GLShader_blurY *gl_blurYShader = nullptr; GLShader_debugShadowMap *gl_debugShadowMapShader = nullptr; GLShader_liquid *gl_liquidShader = nullptr; +GLShader_liquidMaterial *gl_liquidShaderMaterial = nullptr; GLShader_motionblur *gl_motionblurShader = nullptr; GLShader_ssao *gl_ssaoShader = nullptr; GLShader_depthtile1 *gl_depthtile1Shader = nullptr; @@ -374,14 +382,12 @@ static std::string BuildDeformSteps( deformStage_t *deforms, int numDeforms ) return steps; } -static void addExtension( std::string &str, bool available, int minGlslVersion, const std::string &name ) { - if ( !available ) - { +static void addExtension( std::string& str, bool available, int minGlslVersion, const std::string& name ) { + if ( !available ) { return; } - if( glConfig2.shadingLanguageVersion < minGlslVersion ) - { + if ( ( glConfig2.shadingLanguageVersion < minGlslVersion ) || ( minGlslVersion == -1 ) ) { str += Str::Format( "#extension GL_%s : require\n", name ); } @@ -406,8 +412,8 @@ static void AddConst( std::string& str, const std::string& name, float v1, float static std::string GenVersionDeclaration() { // Basic version declaration std::string str = Str::Format( "#version %d %s\n", - glConfig2.shadingLanguageVersion, - glConfig2.shadingLanguageVersion >= 150 ? (glConfig2.glCoreProfile ? "core" : "compatibility") : ""); + glConfig2.shadingLanguageVersion, + glConfig2.shadingLanguageVersion >= 150 ? ( glConfig2.glCoreProfile ? "core" : "compatibility" ) : "" ); // add supported GLSL extensions struct extension_t { @@ -423,10 +429,13 @@ static std::string GenVersionDeclaration() { { glConfig2.textureIntegerAvailable, 0, "EXT_texture_integer" }, { glConfig2.textureRGAvailable, 0, "ARB_texture_rg" }, { glConfig2.uniformBufferObjectAvailable, 140, "ARB_uniform_buffer_object" }, + { glConfig2.bindlessTexturesAvailable, -1, "ARB_bindless_texture" }, + // ARB_shader_draw_parameters set to -1, because we might get a 4.6 GL context, where the core variables have different names + { glConfig2.shaderDrawParametersAvailable, -1, "ARB_shader_draw_parameters" }, + { glConfig2.SSBOAvailable, 430, "ARB_shader_storage_buffer_object" }, }; - for ( const auto& extension : extensions ) - { + for ( const auto& extension : extensions ) { addExtension( str, extension.available, extension.minGlslVersion, extension.name ); } @@ -488,6 +497,13 @@ static std::string GenVertexHeader() { "#define OUT(mode) varying\n"; } + if ( glConfig2.shaderDrawParametersAvailable ) { + str += "OUT(flat) int in_drawID;\n"; + str += "OUT(flat) int in_baseInstance;\n"; + str += "#define drawID gl_DrawIDARB\n"; + str += "#define baseInstance gl_BaseInstanceARB\n\n"; + } + return str; } @@ -511,6 +527,17 @@ static std::string GenFragmentHeader() { "#define DECLARE_OUTPUT(type) /* empty*/\n"; } + if ( glConfig2.bindlessTexturesAvailable ) { + str += "layout(bindless_sampler) uniform;\n"; + } + + if ( glConfig2.shaderDrawParametersAvailable ) { + str += "IN(flat) int in_drawID;\n"; + str += "IN(flat) int in_baseInstance;\n"; + str += "#define drawID in_drawID\n"; + str += "#define baseInstance in_baseInstance\n\n"; + } + return str; } @@ -745,9 +772,8 @@ int GLShaderManager::getDeformShaderIndex( deformStage_t *deforms, int numDeform } std::string GLShaderManager::BuildGPUShaderText( Str::StringRef mainShaderName, - Str::StringRef libShaderNames, - GLenum shaderType ) const -{ + Str::StringRef libShaderNames, + GLenum shaderType ) const { char filename[MAX_QPATH]; const char* libNames = libShaderNames.c_str(); @@ -806,14 +832,14 @@ std::string GLShaderManager::BuildGPUShaderText( Str::StringRef mainShaderNa AddDefine( env, "r_SpecularScale", r_specularScale->value ); AddDefine( env, "r_zNear", r_znear->value ); - AddDefine( env, "M_PI", static_cast( M_PI ) ); + AddDefine( env, "M_PI", static_cast< float >( M_PI ) ); AddDefine( env, "MAX_SHADOWMAPS", MAX_SHADOWMAPS ); AddDefine( env, "MAX_REF_LIGHTS", MAX_REF_LIGHTS ); AddDefine( env, "TILE_SIZE", TILE_SIZE ); AddDefine( env, "r_FBufSize", glConfig.vidWidth, glConfig.vidHeight ); - AddDefine( env, "r_tileStep", glState.tileStep[ 0 ], glState.tileStep[ 1 ] ); + AddDefine( env, "r_tileStep", glState.tileStep[0], glState.tileStep[1] ); // We added a lot of stuff but if we do something bad // in the GLSL shaders then we want the proper line @@ -976,22 +1002,21 @@ void GLShaderManager::buildAll() Log::Notice( "glsl shaders took %d msec to build", _totalBuildTime ); } -void GLShaderManager::InitShader( GLShader *shader ) -{ - shader->_shaderPrograms = std::vector( static_cast(1) << shader->_compileMacros.size() ); +void GLShaderManager::InitShader( GLShader* shader ) { + shader->_shaderPrograms = std::vector( static_cast< size_t >( 1 ) << shader->_compileMacros.size() ); + + shader->PostProcessUniforms(); shader->_uniformStorageSize = 0; - for ( std::size_t i = 0; i < shader->_uniforms.size(); i++ ) - { - GLUniform *uniform = shader->_uniforms[ i ]; + for ( std::size_t i = 0; i < shader->_uniforms.size(); i++ ) { + GLUniform* uniform = shader->_uniforms[i]; uniform->SetLocationIndex( i ); uniform->SetFirewallIndex( shader->_uniformStorageSize ); shader->_uniformStorageSize += uniform->GetSize(); } - for ( std::size_t i = 0; i < shader->_uniformBlocks.size(); i++ ) - { - GLUniformBlock *uniformBlock = shader->_uniformBlocks[ i ]; + for ( std::size_t i = 0; i < shader->_uniformBlocks.size(); i++ ) { + GLUniformBlock* uniformBlock = shader->_uniformBlocks[i]; uniformBlock->SetLocationIndex( i ); } @@ -1014,6 +1039,11 @@ void GLShaderManager::InitShader( GLShader *shader ) shader->_computeShaderText = BuildGPUShaderText( shader->GetMainShaderName(), computeInlines, GL_COMPUTE_SHADER ); } + if ( glConfig2.materialSystemAvailable && shader->_useMaterialSystem ) { + shader->_vertexShaderText = ShaderPostProcess( shader, shader->_vertexShaderText ); + shader->_fragmentShaderText = ShaderPostProcess( shader, shader->_fragmentShaderText ); + } + std::string combinedShaderText; if ( shader->_hasVertexShader || shader->_hasFragmentShader ) { combinedShaderText = @@ -1266,6 +1296,108 @@ void GLShaderManager::CompileAndLinkGPUShaderProgram( GLShader *shader, shaderPr LinkProgram( program->program ); } +// This will generate all the extra code for material system shaders +std::string GLShaderManager::ShaderPostProcess( GLShader *shader, const std::string& shaderText ) { + std::string newShaderText; + std::string materialStruct = "\nstruct Material {\n"; + std::string materialBlock = "layout(std430, binding = 0) readonly buffer materialsSSBO {\n" + " Material materials[];\n" + "};\n\n"; + std::string materialDefines; + + /* Generate the struct and defines in the form of: + * struct Material { + * type uniform0; + * type uniform1; + * .. + * type uniformn; + * } + * + * #define uniformx materials[baseInstance].uniformx + */ + + for( GLUniform* uniform : shader->_uniforms ) { + if ( uniform->IsGlobal() ) { + continue; + } + + if ( uniform->IsTexture() ) { + materialStruct += " uvec2 "; + materialStruct += uniform->GetName(); + } else { + materialStruct += " " + uniform->GetType() + " " + uniform->GetName(); + } + + if ( uniform->GetComponentSize() ) { + materialStruct += "[ " + std::to_string( uniform->GetComponentSize() ) + " ]"; + } + materialStruct += ";\n"; + + // vec3 is aligned to 4 components, so just pad it with int + // TODO: Try to move 1 component uniforms here to avoid wasting memory + if ( uniform->GetSTD430Size() == 3 ) { + materialStruct += " int "; + materialStruct += uniform->GetName(); + materialStruct += "_padding;\n"; + } + + materialDefines += "#define "; + materialDefines += uniform->GetName(); + + if ( uniform->IsTexture() ) { // Driver bug: AMD compiler crashes when using the SSBO value directly + materialDefines += "_initial uvec2("; // We'll need this to create sampler objects later + } + + materialDefines += " materials[baseInstance]."; + materialDefines += uniform->GetName(); + + if ( uniform->IsTexture() ) { + materialDefines += " )"; + } + + materialDefines += "\n"; + } + + // Array of structs is aligned to the largest member of the struct + for ( uint i = 0; i < shader->padding; i++ ) { + materialStruct += " int material_padding" + std::to_string( i ); + materialStruct += ";\n"; + } + + materialStruct += "};\n\n"; + materialDefines += "\n"; + + std::istringstream shaderTextStream( shaderText ); + std::string shaderMain; + + std::string line; + + /* Remove local uniform declarations, but avoid removing uniform / storage blocks; + * their values will be sourced from a buffer instead + * Global uniforms (like u_ViewUp and u_ViewOrigin) will still be set as regular uniforms */ + while( std::getline( shaderTextStream, line, '\n' ) ) { + if( !( line.find( "uniform" ) == std::string::npos || line.find( ";" ) == std::string::npos ) ) { + continue; + } + shaderMain += line + "\n"; + } + + for ( GLUniform* uniform : shader->_uniforms ) { + if ( uniform->IsGlobal() ) { + materialDefines += "uniform " + uniform->GetType() + " " + uniform->GetName(); + if ( uniform->GetComponentSize() ) { + materialDefines += "[ " + std::to_string( uniform->GetComponentSize() ) + " ]"; + } + materialDefines += ";\n"; + } + } + + materialDefines += "\n"; + + newShaderText = "#define USE_MATERIAL_SYSTEM\n" + materialStruct + materialBlock + materialDefines + shaderMain; + return newShaderText; +} + GLuint GLShaderManager::CompileShader( Str::StringRef programName, Str::StringRef shaderText, std::initializer_list headers, @@ -1601,6 +1733,87 @@ bool GLCompileMacro_USE_BSP_SURFACE::HasConflictingMacros(size_t permutation, co return false; } +GLuint GLUniform::GetSTD430Size() const { + return _std430Size; +} + +GLuint GLUniform::GetSTD430Alignment() const { + return _std430Alignment; +} + +uint32_t* GLUniform::WriteToBuffer( uint32_t* buffer ) { + return buffer; +} + +void GLShader::RegisterUniform( GLUniform* uniform ) { + _uniforms.push_back( uniform ); + textureCount += uniform->IsTexture(); +} + +GLint GLShader::GetUniformLocation( const GLchar *uniformName ) const { + shaderProgram_t* p = GetProgram(); + return glGetUniformLocation( p->program, uniformName ); +} + +// Compute std430 size/alignment and sort uniforms from highest to lowest alignment +void GLShader::PostProcessUniforms() { + if ( !_useMaterialSystem ) { + return; + } + + std::vector tmp; + + std::vector globalUniforms; + for ( GLUniform* uniform : _uniforms ) { + if ( uniform->IsGlobal() ) { + globalUniforms.emplace_back( uniform ); + } + } + for ( GLUniform* uniform : globalUniforms ) { + _uniforms.erase( std::remove( _uniforms.begin(), _uniforms.end(), uniform ), _uniforms.end() ); + } + + // Sort uniforms from highest to lowest alignment so we don't need to pad uniforms (other than vec3s) + const uint numUniforms = _uniforms.size(); + GLuint structAlignment = 0; + GLuint structSize = 0; + while ( tmp.size() < numUniforms ) { + // Higher-alignment uniforms first to avoid wasting memory + GLuint highestAlignment = 0; + int highestUniform = 0; + for( uint i = 0; i < _uniforms.size(); i++ ) { + if ( _uniforms[i]->GetSTD430Alignment() > highestAlignment ) { + highestAlignment = _uniforms[i]->GetSTD430Alignment(); + highestUniform = i; + } + if ( highestAlignment > structAlignment ) { + structAlignment = highestAlignment; + } + if ( highestAlignment == 4 ) { + break; // 4-component is the highest alignment in std430 + } + } + + const GLuint size = _uniforms[highestUniform]->GetSTD430Size(); + if ( _uniforms[highestUniform]->GetComponentSize() != 0 ) { + structSize += ( size == 3 ) ? 4 * _uniforms[highestUniform]->GetComponentSize() : + size * _uniforms[highestUniform]->GetComponentSize(); + } else { + structSize += ( size == 3 ) ? 4 : size; + } + + tmp.emplace_back( _uniforms[highestUniform] ); + _uniforms.erase( _uniforms.begin() + highestUniform ); + } + _uniforms = tmp; + + padding = ( structAlignment - ( structSize % structAlignment ) ) % structAlignment; + std430Size = structSize; + for ( GLUniform* uniform : globalUniforms ) { + _uniforms.emplace_back( uniform ); + } +} + bool GLShader::GetCompileMacrosString( size_t permutation, std::string &compileMacrosOut ) const { compileMacrosOut.clear(); @@ -1643,6 +1856,38 @@ int GLShader::SelectProgram() return index; } +GLuint GLShader::GetProgram( int deformIndex ) { + int macroIndex = SelectProgram(); + size_t index = macroIndex + ( size_t( deformIndex ) << _compileMacros.size() ); + + // program may not be loaded yet because the shader manager hasn't yet gotten to it + // so try to load it now + if ( index >= _shaderPrograms.size() || !_shaderPrograms[index].program ) { + _shaderManager->buildPermutation( this, macroIndex, deformIndex ); + } + + // program is still not loaded + if ( index >= _shaderPrograms.size() || !_shaderPrograms[index].program ) { + std::string activeMacros; + size_t numMacros = _compileMacros.size(); + + for ( size_t j = 0; j < numMacros; j++ ) { + GLCompileMacro* macro = _compileMacros[j]; + + int bit = macro->GetBit(); + + if ( IsMacroSet( bit ) ) { + activeMacros += macro->GetName(); + activeMacros += " "; + } + } + + ThrowShaderError( Str::Format( "Invalid shader configuration: shader = '%s', macros = '%s'", _name, activeMacros ) ); + } + + return _shaderPrograms[index].program; +} + void GLShader::BindProgram( int deformIndex ) { int macroIndex = SelectProgram(); @@ -1722,8 +1967,19 @@ void GLShader::SetRequiredVertexPointers( bool vboVertexSprite ) GL_VertexAttribsState( attribs ); } +void GLShader::WriteUniformsToBuffer( uint32_t* buffer ) { + uint32_t* bufPtr = buffer; + for ( GLUniform* uniform : _uniforms ) { + if ( !uniform->IsGlobal() ) { + bufPtr = uniform->WriteToBuffer( bufPtr ); + } + } +} + GLShader_generic2D::GLShader_generic2D( GLShaderManager *manager ) : GLShader( "generic2D", "generic", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + u_ColorMap( this ), + u_DepthMap( this ), u_TextureMatrix( this ), u_AlphaThreshold( this ), u_ModelMatrix( this ), @@ -1754,6 +2010,8 @@ void GLShader_generic2D::SetShaderProgramUniforms( shaderProgram_t *shaderProgra GLShader_generic::GLShader_generic( GLShaderManager *manager ) : GLShader( "generic", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + u_ColorMap( this ), + u_DepthMap( this ), u_TextureMatrix( this ), u_ViewOrigin( this ), u_ViewUp( this ), @@ -1787,9 +2045,57 @@ void GLShader_generic::SetShaderProgramUniforms( shaderProgram_t *shaderProgram glUniform1i( glGetUniformLocation( shaderProgram->program, "u_DepthMap" ), 1 ); } +GLShader_genericMaterial::GLShader_genericMaterial( GLShaderManager* manager ) : + GLShader( "genericMaterial", "generic", true, ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + u_ColorMap( this ), + u_DepthMap( this ), + u_TextureMatrix( this ), + u_ViewOrigin( this ), + u_ViewUp( this ), + u_AlphaThreshold( this ), + u_ModelMatrix( this ), + u_ModelViewProjectionMatrix( this ), + u_InverseLightFactor( this ), + u_ColorModulate( this ), + u_Color( this ), + // u_Bones( this ), + u_VertexInterpolation( this ), + u_DepthScale( this ), + GLDeformStage( this ), + // GLCompileMacro_USE_VERTEX_SKINNING( this ), + GLCompileMacro_USE_VERTEX_ANIMATION( this ), + GLCompileMacro_USE_VERTEX_SPRITE( this ), + GLCompileMacro_USE_TCGEN_ENVIRONMENT( this ), + GLCompileMacro_USE_TCGEN_LIGHTMAP( this ), + GLCompileMacro_USE_DEPTH_FADE( this ) { +} + +void GLShader_genericMaterial::BuildShaderVertexLibNames( std::string& vertexInlines ) { + vertexInlines += "vertexSimple vertexSkinning vertexAnimation vertexSprite "; +} + +void GLShader_genericMaterial::SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) { + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_ColorMap" ), 0 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_DepthMap" ), 1 ); +} + GLShader_lightMapping::GLShader_lightMapping( GLShaderManager *manager ) : GLShader( "lightMapping", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT | ATTR_COLOR, manager ), + u_DiffuseMap( this ), + u_NormalMap( this ), + u_HeightMap( this ), + u_MaterialMap( this ), + u_LightMap( this ), + u_DeluxeMap( this ), + u_GlowMap( this ), + u_EnvironmentMap0( this ), + u_EnvironmentMap1( this ), + u_LightGrid1( this ), + u_LightGrid2( this ), + u_LightTiles( this ), + u_LightTilesInt( this ), + u_LightsTexture( this ), u_TextureMatrix( this ), u_SpecularExponent( this ), u_ColorModulate( this ), @@ -1842,20 +2148,106 @@ void GLShader_lightMapping::SetShaderProgramUniforms( shaderProgram_t *shaderPro glUniform1i( glGetUniformLocation( shaderProgram->program, "u_DiffuseMap" ), BIND_DIFFUSEMAP ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_NormalMap" ), BIND_NORMALMAP ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_HeightMap" ), BIND_HEIGHTMAP ); - glUniform1i( glGetUniformLocation( shaderProgram->program, "u_MaterialMap" ), BIND_MATERIALMAP ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_MaterialMap" ), BIND_MATERIALMAP ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_LightMap" ), BIND_LIGHTMAP ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_LightGrid1" ), BIND_LIGHTMAP ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_DeluxeMap" ), BIND_DELUXEMAP ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_LightGrid2" ), BIND_DELUXEMAP ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_GlowMap" ), BIND_GLOWMAP ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_EnvironmentMap0" ), BIND_ENVIRONMENTMAP0 ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_EnvironmentMap1" ), BIND_ENVIRONMENTMAP1 ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_LightTiles" ), BIND_LIGHTTILES ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_LightTilesInt" ), BIND_LIGHTTILES ); if( !glConfig2.uniformBufferObjectAvailable ) { glUniform1i( glGetUniformLocation( shaderProgram->program, "u_Lights" ), BIND_LIGHTS ); } } +GLShader_lightMappingMaterial::GLShader_lightMappingMaterial( GLShaderManager* manager ) : + GLShader( "lightMappingMaterial", "lightMapping", true, + ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT | ATTR_COLOR, manager ), + u_DiffuseMap( this ), + u_NormalMap( this ), + u_HeightMap( this ), + u_MaterialMap( this ), + u_LightMap( this ), + u_DeluxeMap( this ), + u_GlowMap( this ), + u_EnvironmentMap0( this ), + u_EnvironmentMap1( this ), + u_LightGrid1( this ), + u_LightGrid2( this ), + u_LightTilesInt( this ), + u_TextureMatrix( this ), + u_SpecularExponent( this ), + u_ColorModulate( this ), + u_Color( this ), + u_AlphaThreshold( this ), + u_ViewOrigin( this ), + u_ModelMatrix( this ), + u_ModelViewProjectionMatrix( this ), + u_InverseLightFactor( this ), + // u_Bones( this ), + u_VertexInterpolation( this ), + u_ReliefDepthScale( this ), + u_ReliefOffsetBias( this ), + u_NormalScale( this ), + u_EnvironmentInterpolation( this ), + u_LightGridOrigin( this ), + u_LightGridScale( this ), + u_numLights( this ), + u_Lights( this ), + GLDeformStage( this ), + GLCompileMacro_USE_BSP_SURFACE( this ), + // GLCompileMacro_USE_VERTEX_SKINNING( this ), + GLCompileMacro_USE_VERTEX_ANIMATION( this ), + GLCompileMacro_USE_DELUXE_MAPPING( this ), + GLCompileMacro_USE_GRID_LIGHTING( this ), + GLCompileMacro_USE_GRID_DELUXE_MAPPING( this ), + GLCompileMacro_USE_HEIGHTMAP_IN_NORMALMAP( this ), + GLCompileMacro_USE_RELIEF_MAPPING( this ), + GLCompileMacro_USE_REFLECTIVE_SPECULAR( this ), + GLCompileMacro_USE_PHYSICAL_MAPPING( this ) { +} + +void GLShader_lightMappingMaterial::BuildShaderVertexLibNames( std::string& vertexInlines ) { + vertexInlines += "vertexSimple vertexSkinning vertexAnimation vertexSprite "; +} + +void GLShader_lightMappingMaterial::BuildShaderFragmentLibNames( std::string& fragmentInlines ) { + fragmentInlines += "computeLight reliefMapping"; +} + +void GLShader_lightMappingMaterial::BuildShaderCompileMacros( std::string& /*compileMacros*/ ) { +} + +void GLShader_lightMappingMaterial::SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) { + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_DiffuseMap" ), BIND_DIFFUSEMAP ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_NormalMap" ), BIND_NORMALMAP ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_HeightMap" ), BIND_HEIGHTMAP ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_MaterialMap" ), BIND_MATERIALMAP ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_LightMap" ), BIND_LIGHTMAP ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_DeluxeMap" ), BIND_DELUXEMAP ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_GlowMap" ), BIND_GLOWMAP ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_EnvironmentMap0" ), BIND_ENVIRONMENTMAP0 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_EnvironmentMap1" ), BIND_ENVIRONMENTMAP1 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_LightTiles" ), BIND_LIGHTTILES ); + if ( !glConfig2.uniformBufferObjectAvailable ) { + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_Lights" ), BIND_LIGHTS ); + } +} + GLShader_forwardLighting_omniXYZ::GLShader_forwardLighting_omniXYZ( GLShaderManager *manager ): GLShader("forwardLighting_omniXYZ", "forwardLighting", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager), + u_DiffuseMap( this ), + u_NormalMap( this ), + u_MaterialMap( this ), + u_AttenuationMapXY( this ), + u_AttenuationMapZ( this ), + u_ShadowMap( this ), + u_ShadowClipMap( this ), + u_RandomMap( this ), + u_HeightMap( this ), u_TextureMatrix( this ), u_SpecularExponent( this ), u_AlphaThreshold( this ), @@ -1915,6 +2307,15 @@ void GLShader_forwardLighting_omniXYZ::SetShaderProgramUniforms( shaderProgram_t GLShader_forwardLighting_projXYZ::GLShader_forwardLighting_projXYZ( GLShaderManager *manager ): GLShader("forwardLighting_projXYZ", "forwardLighting", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager), + u_DiffuseMap( this ), + u_NormalMap( this ), + u_MaterialMap( this ), + u_AttenuationMapXY( this ), + u_AttenuationMapZ( this ), + u_ShadowMap0( this ), + u_ShadowClipMap0( this ), + u_RandomMap( this ), + u_HeightMap( this ), u_TextureMatrix( this ), u_SpecularExponent( this ), u_AlphaThreshold( this ), @@ -1976,6 +2377,20 @@ void GLShader_forwardLighting_projXYZ::SetShaderProgramUniforms( shaderProgram_t GLShader_forwardLighting_directionalSun::GLShader_forwardLighting_directionalSun( GLShaderManager *manager ): GLShader("forwardLighting_directionalSun", "forwardLighting", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager), + u_DiffuseMap( this ), + u_NormalMap( this ), + u_MaterialMap( this ), + u_ShadowMap0( this ), + u_ShadowMap1( this ), + u_ShadowMap2( this ), + u_ShadowMap3( this ), + u_ShadowMap4( this ), + u_ShadowClipMap0( this ), + u_ShadowClipMap1( this ), + u_ShadowClipMap2( this ), + u_ShadowClipMap3( this ), + u_ShadowClipMap4( this ), + u_HeightMap( this ), u_TextureMatrix( this ), u_SpecularExponent( this ), u_AlphaThreshold( this ), @@ -2046,6 +2461,7 @@ void GLShader_forwardLighting_directionalSun::SetShaderProgramUniforms( shaderPr GLShader_shadowFill::GLShader_shadowFill( GLShaderManager *manager ) : GLShader( "shadowFill", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + u_ColorMap( this ), u_TextureMatrix( this ), u_ViewOrigin( this ), u_AlphaThreshold( this ), @@ -2075,6 +2491,9 @@ void GLShader_shadowFill::SetShaderProgramUniforms( shaderProgram_t *shaderProgr GLShader_reflection::GLShader_reflection( GLShaderManager *manager ): GLShader("reflection", "reflection_CB", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + u_ColorMap( this ), + u_NormalMap( this ), + u_HeightMap( this ), u_TextureMatrix( this ), u_ViewOrigin( this ), u_ModelMatrix( this ), @@ -2113,8 +2532,48 @@ void GLShader_reflection::SetShaderProgramUniforms( shaderProgram_t *shaderProgr glUniform1i( glGetUniformLocation( shaderProgram->program, "u_HeightMap" ), 15 ); } +GLShader_reflectionMaterial::GLShader_reflectionMaterial( GLShaderManager* manager ) : + GLShader( "reflectionMaterial", "reflection", true, ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + u_ColorMap( this ), + u_NormalMap( this ), + u_HeightMap( this ), + u_TextureMatrix( this ), + u_ViewOrigin( this ), + u_ModelMatrix( this ), + u_ModelViewProjectionMatrix( this ), + // u_Bones( this ), + u_ReliefDepthScale( this ), + u_ReliefOffsetBias( this ), + u_NormalScale( this ), + u_VertexInterpolation( this ), + GLDeformStage( this ), + // GLCompileMacro_USE_VERTEX_SKINNING( this ), + GLCompileMacro_USE_VERTEX_ANIMATION( this ), + GLCompileMacro_USE_HEIGHTMAP_IN_NORMALMAP( this ), + GLCompileMacro_USE_RELIEF_MAPPING( this ) { +} + +void GLShader_reflectionMaterial::BuildShaderVertexLibNames( std::string& vertexInlines ) { + vertexInlines += "vertexSimple vertexSkinning vertexAnimation "; +} + +void GLShader_reflectionMaterial::BuildShaderFragmentLibNames( std::string& fragmentInlines ) { + fragmentInlines += "reliefMapping"; +} + +void GLShader_reflectionMaterial::BuildShaderCompileMacros( std::string& ) { +} + +void GLShader_reflectionMaterial::SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) { + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_ColorMap" ), 0 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_NormalMap" ), 1 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_HeightMap" ), 15 ); +} + GLShader_skybox::GLShader_skybox( GLShaderManager *manager ) : GLShader( "skybox", ATTR_POSITION, manager ), + u_ColorMapCube( this ), + u_CloudMap( this ), u_TextureMatrix( this ), u_ViewOrigin( this ), u_CloudHeight( this ), @@ -2129,12 +2588,33 @@ GLShader_skybox::GLShader_skybox( GLShaderManager *manager ) : void GLShader_skybox::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) { + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_ColorMapCube" ), 0 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_CloudMap" ), 1 ); +} + +GLShader_skyboxMaterial::GLShader_skyboxMaterial( GLShaderManager* manager ) : + GLShader( "skyboxMaterial", "skybox", true, ATTR_POSITION, manager ), + u_ColorMapCube( this ), + u_CloudMap( this ), + u_TextureMatrix( this ), + u_ViewOrigin( this ), + u_CloudHeight( this ), + u_UseCloudMap( this ), + u_AlphaThreshold( this ), + u_ModelMatrix( this ), + u_ModelViewProjectionMatrix( this ), + u_InverseLightFactor( this ), + GLDeformStage( this ) { +} + +void GLShader_skyboxMaterial::SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) { glUniform1i( glGetUniformLocation( shaderProgram->program, "u_ColorMap" ), 0 ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_CloudMap" ), 1 ); } GLShader_fogQuake3::GLShader_fogQuake3( GLShaderManager *manager ) : GLShader( "fogQuake3", ATTR_POSITION | ATTR_QTANGENT, manager ), + u_ColorMap( this ), u_ModelMatrix( this ), u_ModelViewProjectionMatrix( this ), u_InverseLightFactor( this ), @@ -2160,8 +2640,35 @@ void GLShader_fogQuake3::SetShaderProgramUniforms( shaderProgram_t *shaderProgra glUniform1i( glGetUniformLocation( shaderProgram->program, "u_ColorMap" ), 0 ); } +GLShader_fogQuake3Material::GLShader_fogQuake3Material( GLShaderManager* manager ) : + GLShader( "fogQuake3Material", "fogQuake3", true, ATTR_POSITION | ATTR_QTANGENT, manager ), + u_ColorMap( this ), + u_ModelMatrix( this ), + u_ModelViewProjectionMatrix( this ), + u_InverseLightFactor( this ), + u_Color( this ), + // u_Bones( this ), + u_VertexInterpolation( this ), + u_FogDistanceVector( this ), + u_FogDepthVector( this ), + u_FogEyeT( this ), + GLDeformStage( this ), + // GLCompileMacro_USE_VERTEX_SKINNING( this ), + GLCompileMacro_USE_VERTEX_ANIMATION( this ) { +} + +void GLShader_fogQuake3Material::BuildShaderVertexLibNames( std::string& vertexInlines ) { + vertexInlines += "vertexSimple vertexSkinning vertexAnimation "; +} + +void GLShader_fogQuake3Material::SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) { + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_ColorMap" ), 0 ); +} + GLShader_fogGlobal::GLShader_fogGlobal( GLShaderManager *manager ) : GLShader( "fogGlobal", ATTR_POSITION, manager ), + u_ColorMap( this ), + u_DepthMap( this ), u_ViewOrigin( this ), u_ViewMatrix( this ), u_ModelViewProjectionMatrix( this ), @@ -2181,6 +2688,9 @@ void GLShader_fogGlobal::SetShaderProgramUniforms( shaderProgram_t *shaderProgra GLShader_heatHaze::GLShader_heatHaze( GLShaderManager *manager ) : GLShader( "heatHaze", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + u_CurrentMap( this ), + u_NormalMap( this ), + u_HeightMap( this ), u_TextureMatrix( this ), u_ViewOrigin( this ), u_ViewUp( this ), @@ -2218,8 +2728,47 @@ void GLShader_heatHaze::SetShaderProgramUniforms( shaderProgram_t *shaderProgram glUniform1i( glGetUniformLocation( shaderProgram->program, "u_HeightMap" ), 15 ); } +GLShader_heatHazeMaterial::GLShader_heatHazeMaterial( GLShaderManager* manager ) : + GLShader( "heatHazeMaterial", "heatHaze", true, ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + u_CurrentMap( this ), + u_NormalMap( this ), + u_HeightMap( this ), + u_TextureMatrix( this ), + u_ViewOrigin( this ), + u_ViewUp( this ), + u_DeformMagnitude( this ), + u_ModelMatrix( this ), + u_ModelViewProjectionMatrix( this ), + u_ModelViewMatrixTranspose( this ), + u_ProjectionMatrixTranspose( this ), + u_ColorModulate( this ), + u_Color( this ), + // u_Bones( this ), + u_NormalScale( this ), + u_VertexInterpolation( this ), + GLDeformStage( this ), + // GLCompileMacro_USE_VERTEX_SKINNING( this ), + GLCompileMacro_USE_VERTEX_ANIMATION( this ), + GLCompileMacro_USE_VERTEX_SPRITE( this ) { +} + +void GLShader_heatHazeMaterial::BuildShaderVertexLibNames( std::string& vertexInlines ) { + vertexInlines += "vertexSimple vertexSkinning vertexAnimation vertexSprite "; +} + +void GLShader_heatHazeMaterial::BuildShaderFragmentLibNames( std::string& fragmentInlines ) { + fragmentInlines += "reliefMapping"; +} + +void GLShader_heatHazeMaterial::SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) { + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_NormalMap" ), 0 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_CurrentMap" ), 1 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_HeightMap" ), 15 ); +} + GLShader_screen::GLShader_screen( GLShaderManager *manager ) : GLShader( "screen", ATTR_POSITION, manager ), + u_CurrentMap( this ), u_ModelViewProjectionMatrix( this ) { } @@ -2229,8 +2778,19 @@ void GLShader_screen::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) glUniform1i( glGetUniformLocation( shaderProgram->program, "u_CurrentMap" ), 0 ); } +GLShader_screenMaterial::GLShader_screenMaterial( GLShaderManager* manager ) : + GLShader( "screenMaterial", "screen", true, ATTR_POSITION, manager ), + u_CurrentMap( this ), + u_ModelViewProjectionMatrix( this ) { +} + +void GLShader_screenMaterial::SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) { + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_CurrentMap" ), 0 ); +} + GLShader_portal::GLShader_portal( GLShaderManager *manager ) : GLShader( "portal", ATTR_POSITION, manager ), + u_CurrentMap( this ), u_ModelViewMatrix( this ), u_ModelViewProjectionMatrix( this ), u_PortalRange( this ) @@ -2244,6 +2804,7 @@ void GLShader_portal::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) GLShader_contrast::GLShader_contrast( GLShaderManager *manager ) : GLShader( "contrast", ATTR_POSITION, manager ), + u_ColorMap( this ), u_ModelViewProjectionMatrix( this ), u_InverseLightFactor( this ) { @@ -2256,6 +2817,8 @@ void GLShader_contrast::SetShaderProgramUniforms( shaderProgram_t *shaderProgram GLShader_cameraEffects::GLShader_cameraEffects( GLShaderManager *manager ) : GLShader( "cameraEffects", ATTR_POSITION | ATTR_TEXCOORD, manager ), + u_ColorMap3D( this ), + u_CurrentMap( this ), u_ColorModulate( this ), u_TextureMatrix( this ), u_ModelViewProjectionMatrix( this ), @@ -2268,11 +2831,12 @@ GLShader_cameraEffects::GLShader_cameraEffects( GLShaderManager *manager ) : void GLShader_cameraEffects::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) { glUniform1i( glGetUniformLocation( shaderProgram->program, "u_CurrentMap" ), 0 ); - glUniform1i( glGetUniformLocation( shaderProgram->program, "u_ColorMap" ), 3 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_ColorMap3D" ), 3 ); } GLShader_blurX::GLShader_blurX( GLShaderManager *manager ) : GLShader( "blurX", ATTR_POSITION, manager ), + u_ColorMap( this ), u_ModelViewProjectionMatrix( this ), u_DeformMagnitude( this ), u_TexScale( this ) @@ -2286,6 +2850,7 @@ void GLShader_blurX::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) GLShader_blurY::GLShader_blurY( GLShaderManager *manager ) : GLShader( "blurY", ATTR_POSITION, manager ), + u_ColorMap( this ), u_ModelViewProjectionMatrix( this ), u_DeformMagnitude( this ), u_TexScale( this ) @@ -2299,6 +2864,7 @@ void GLShader_blurY::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) GLShader_debugShadowMap::GLShader_debugShadowMap( GLShaderManager *manager ) : GLShader( "debugShadowMap", ATTR_POSITION, manager ), + u_CurrentMap( this ), u_ModelViewProjectionMatrix( this ) { } @@ -2310,6 +2876,13 @@ void GLShader_debugShadowMap::SetShaderProgramUniforms( shaderProgram_t *shaderP GLShader_liquid::GLShader_liquid( GLShaderManager *manager ) : GLShader( "liquid", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + u_CurrentMap( this ), + u_DepthMap( this ), + u_NormalMap( this ), + u_PortalMap( this ), + u_LightGrid1( this ), + u_LightGrid2( this ), + u_HeightMap( this ), u_TextureMatrix( this ), u_ViewOrigin( this ), u_RefractionIndex( this ), @@ -2337,7 +2910,52 @@ void GLShader_liquid::BuildShaderFragmentLibNames( std::string& fragmentInlines fragmentInlines += "computeLight reliefMapping"; } -void GLShader_liquid::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) +void GLShader_liquid::SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) { + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_CurrentMap" ), 0 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_PortalMap" ), 1 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_DepthMap" ), 2 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_NormalMap" ), 3 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_LightGrid1" ), 6 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_LightGrid2" ), 7 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_HeightMap" ), 15 ); +} + +GLShader_liquidMaterial::GLShader_liquidMaterial( GLShaderManager* manager ) : + GLShader( "liquidMaterial", "liquid", true, ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + u_CurrentMap( this ), + u_DepthMap( this ), + u_NormalMap( this ), + u_PortalMap( this ), + u_LightGrid1( this ), + u_LightGrid2( this ), + u_HeightMap( this ), + u_TextureMatrix( this ), + u_ViewOrigin( this ), + u_RefractionIndex( this ), + u_ModelMatrix( this ), + u_ModelViewProjectionMatrix( this ), + u_UnprojectMatrix( this ), + u_FresnelPower( this ), + u_FresnelScale( this ), + u_FresnelBias( this ), + u_ReliefDepthScale( this ), + u_ReliefOffsetBias( this ), + u_NormalScale( this ), + u_FogDensity( this ), + u_FogColor( this ), + u_LightTilesInt( this ), + u_SpecularExponent( this ), + u_LightGridOrigin( this ), + u_LightGridScale( this ), + GLCompileMacro_USE_HEIGHTMAP_IN_NORMALMAP( this ), + GLCompileMacro_USE_RELIEF_MAPPING( this ) { +} + +void GLShader_liquidMaterial::BuildShaderFragmentLibNames( std::string& fragmentInlines ) { + fragmentInlines += "computeLight reliefMapping"; +} + +void GLShader_liquidMaterial::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) { glUniform1i( glGetUniformLocation( shaderProgram->program, "u_CurrentMap" ), 0 ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_PortalMap" ), 1 ); @@ -2350,6 +2968,8 @@ void GLShader_liquid::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) GLShader_motionblur::GLShader_motionblur( GLShaderManager *manager ) : GLShader( "motionblur", ATTR_POSITION, manager ), + u_ColorMap( this ), + u_DepthMap( this ), u_ModelViewProjectionMatrix( this ), u_blurVec( this ) { @@ -2363,6 +2983,7 @@ void GLShader_motionblur::SetShaderProgramUniforms( shaderProgram_t *shaderProgr GLShader_ssao::GLShader_ssao( GLShaderManager *manager ) : GLShader( "ssao", ATTR_POSITION, manager ), + u_DepthMap( this ), u_ModelViewProjectionMatrix( this ), u_UnprojectionParams( this ), u_zFar( this ) @@ -2376,6 +2997,7 @@ void GLShader_ssao::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) GLShader_depthtile1::GLShader_depthtile1( GLShaderManager *manager ) : GLShader( "depthtile1", ATTR_POSITION, manager ), + u_DepthMap( this ), u_ModelViewProjectionMatrix( this ), u_zFar( this ) { @@ -2388,6 +3010,7 @@ void GLShader_depthtile1::SetShaderProgramUniforms( shaderProgram_t *shaderProgr GLShader_depthtile2::GLShader_depthtile2( GLShaderManager *manager ) : GLShader( "depthtile2", ATTR_POSITION, manager ), + u_DepthMap( this ), u_ModelViewProjectionMatrix( this ) { } @@ -2399,10 +3022,12 @@ void GLShader_depthtile2::SetShaderProgramUniforms( shaderProgram_t *shaderProgr GLShader_lighttile::GLShader_lighttile( GLShaderManager *manager ) : GLShader( "lighttile", ATTR_POSITION | ATTR_TEXCOORD, manager ), - u_ModelMatrix( this ), + u_DepthMap( this ), + u_Lights( this ), + u_LightsTexture( this ), u_numLights( this ), u_lightLayer( this ), - u_Lights( this ), + u_ModelMatrix( this ), u_zFar( this ) { } @@ -2418,6 +3043,7 @@ void GLShader_lighttile::SetShaderProgramUniforms( shaderProgram_t *shaderProgra GLShader_fxaa::GLShader_fxaa( GLShaderManager *manager ) : GLShader( "fxaa", ATTR_POSITION, manager ), + u_ColorMap( this ), u_ModelViewProjectionMatrix( this ) { } diff --git a/src/engine/renderer/gl_shader.h b/src/engine/renderer/gl_shader.h index e3ef96ed7b..bc6898bb47 100644 --- a/src/engine/renderer/gl_shader.h +++ b/src/engine/renderer/gl_shader.h @@ -61,6 +61,7 @@ struct GLBinaryHeader }; class GLUniform; +class GLShader; class GLUniformBlock; class GLCompileMacro; class GLShaderManager; @@ -99,6 +100,10 @@ class GLShader std::string _name; std::string _mainShaderName; + const bool _useMaterialSystem; + GLuint std430Size = 0; + uint padding = 0; + uint textureCount = 0; protected: int _activeMacros; unsigned int _checkSum; @@ -129,6 +134,7 @@ class GLShader const bool hasVertexShader = true, const bool hasFragmentShader = true, const bool hasComputeShader = false ) : _name( name ), _mainShaderName( name ), + _useMaterialSystem( false ), _activeMacros( 0 ), _checkSum( 0 ), _currentProgram( nullptr ), @@ -146,6 +152,7 @@ class GLShader const bool hasVertexShader = true, const bool hasFragmentShader = true, const bool hasComputeShader = false ) : _name( name ), _mainShaderName( mainShaderName ), + _useMaterialSystem( false ), _activeMacros( 0 ), _checkSum( 0 ), _currentProgram( nullptr ), @@ -159,6 +166,24 @@ class GLShader { } + GLShader( const std::string& name, const std::string& mainShaderName, const bool useMaterialSystem, uint32_t vertexAttribsRequired, + GLShaderManager* manager, + const bool hasVertexShader = true, const bool hasFragmentShader = true, const bool hasComputeShader = false ) : + _name( name ), + _mainShaderName( mainShaderName ), + _useMaterialSystem( useMaterialSystem ), + _activeMacros( 0 ), + _checkSum( 0 ), + _currentProgram( nullptr ), + _vertexAttribsRequired( vertexAttribsRequired ), + _vertexAttribs( 0 ), + _shaderManager( manager ), + _hasVertexShader( hasVertexShader ), + _hasFragmentShader( hasFragmentShader ), + _hasComputeShader( hasComputeShader ), + _uniformStorageSize( 0 ) { + } + public: virtual ~GLShader() { @@ -202,10 +227,7 @@ class GLShader } } - void RegisterUniform( GLUniform *uniform ) - { - _uniforms.push_back( uniform ); - } + void RegisterUniform( GLUniform* uniform ); void RegisterUniformBlock( GLUniformBlock *uniformBlock ) { @@ -227,6 +249,8 @@ class GLShader return _compileMacros.size(); } + GLint GetUniformLocation( const GLchar *uniformName ) const; + shaderProgram_t *GetProgram() const { return _currentProgram; @@ -243,6 +267,7 @@ class GLShader } protected: + void PostProcessUniforms(); bool GetCompileMacrosString( size_t permutation, std::string &compileMacrosOut ) const; virtual void BuildShaderVertexLibNames( std::string& /*vertexInlines*/ ) { }; virtual void BuildShaderFragmentLibNames( std::string& /*fragmentInlines*/ ) { }; @@ -251,6 +276,7 @@ class GLShader virtual void SetShaderProgramUniforms( shaderProgram_t* /*shaderProgram*/ ) { }; int SelectProgram(); public: + GLuint GetProgram( int deformIndex ); void BindProgram( int deformIndex ); void DispatchCompute( const GLuint globalWorkgroupX, const GLuint globalWorkgroupY, const GLuint globalWorkgroupZ ); void DispatchComputeIndirect( const GLintptr indirectBuffer ); @@ -285,6 +311,28 @@ class GLShader { _vertexAttribs &= ~bit; } + + GLuint GetSTD430Size() const { + return std430Size; + } + + uint GetPadding() const { + return padding; + } + + uint GetPaddedSize() const { + return std430Size + padding; + } + + uint GetTextureCount() const { + return textureCount; + } + + bool UseMaterialSystem() const { + return _useMaterialSystem; + } + + void WriteUniformsToBuffer( uint32_t* buffer ); }; class GLShaderManager @@ -342,6 +390,7 @@ class GLShaderManager const std::string &compileMacros ); void CompileAndLinkGPUShaderProgram( GLShader *shader, shaderProgram_t *program, Str::StringRef compileMacros, int deformIndex ); + std::string ShaderPostProcess( GLShader *shader, const std::string& shaderText ); std::string BuildDeformShaderText( const std::string& steps ); std::string BuildGPUShaderText( Str::StringRef mainShader, Str::StringRef libShaders, GLenum shaderType ) const; void LinkProgram( GLuint program ) const; @@ -357,12 +406,29 @@ class GLUniform protected: GLShader *_shader; std::string _name; + const std::string _type; + + // In multiples of 4 bytes + const GLuint _std430Size; + const GLuint _std430Alignment; + + const bool _global; // This uniform won't go into materials SSBO if true + const int _components; + const bool _isTexture; + size_t _firewallIndex; size_t _locationIndex; - GLUniform( GLShader *shader, const char *name ) : + GLUniform( GLShader *shader, const char *name, const char* type, const GLuint std430Size, const GLuint std430Alignment, + const bool global, const int components = 0, const bool isTexture = false ) : _shader( shader ), _name( name ), + _type( type ), + _std430Size( std430Size ), + _std430Alignment( std430Alignment ), + _global( global ), + _components( components ), + _isTexture( isTexture ), _firewallIndex( 0 ), _locationIndex( 0 ) { @@ -387,6 +453,29 @@ class GLUniform return _name.c_str(); } + const std::string GetType() const { + return _type; + } + + GLuint GetSTD430Size() const; + + GLuint GetSTD430Alignment() const; + + int GetComponentSize() const { + return _components; + } + + bool IsGlobal() const { + return _global; + } + + bool IsTexture() const { + return _isTexture; + } + + // This should return a pointer to the memory right after the one this uniform wrote to + virtual uint32_t* WriteToBuffer( uint32_t* buffer ); + void UpdateShaderProgramUniformLocation( shaderProgram_t *shaderProgram ) { shaderProgram->uniformLocations[ _locationIndex ] = glGetUniformLocation( shaderProgram->program, GetName() ); @@ -398,11 +487,176 @@ class GLUniform } }; +class GLUniformSampler : protected GLUniform { + protected: + GLUniformSampler( GLShader* shader, const char* name, const char* type, const GLuint size ) : + GLUniform( shader, name, type, glConfig2.bindlessTexturesAvailable ? size * 2 : size, + glConfig2.bindlessTexturesAvailable ? size * 2 : size, false, 0, true ) { + } + + inline GLint GetLocation() { + shaderProgram_t* p = _shader->GetProgram(); + + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } + + return p->uniformLocations[_locationIndex]; + } + + inline size_t GetFirewallIndex() const { + return _firewallIndex; + } + + public: + size_t GetSize() override { + return sizeof( GLuint64 ); + } + + void SetValue( GLuint value ) { + currentValue = value; + } + + void SetValueBindless( GLint64 value ) { + currentValueBindless = value; + + if ( glConfig2.bindlessTexturesAvailable && ( !_shader->UseMaterialSystem() || _global ) ) { + glUniformHandleui64ARB( GetLocation(), currentValueBindless ); + } + } + + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + uint32_t* bufferNext = buffer; + if ( glConfig2.bindlessTexturesAvailable ) { + memcpy( buffer, ¤tValueBindless, sizeof( GLuint64 ) ); + bufferNext += 2; + } else { + memcpy( buffer, ¤tValue, sizeof( GLint ) ); + bufferNext += 1; + } + return bufferNext; + } + + private: + GLuint64 currentValueBindless = 0; + GLuint currentValue = 0; +}; + +class GLUniformSampler1D : protected GLUniformSampler { + protected: + GLUniformSampler1D( GLShader* shader, const char* name ) : + GLUniformSampler( shader, name, "sampler1D", 1 ) { + } + + inline GLint GetLocation() { + shaderProgram_t* p = _shader->GetProgram(); + + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } + + return p->uniformLocations[_locationIndex]; + } + + public: + size_t GetSize() override { + return sizeof( GLuint64 ); + } +}; + +class GLUniformSampler2D : protected GLUniformSampler { + protected: + GLUniformSampler2D( GLShader* shader, const char* name ) : + GLUniformSampler( shader, name, "sampler2D", 1 ) { + } + + inline GLint GetLocation() { + shaderProgram_t* p = _shader->GetProgram(); + + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } + + return p->uniformLocations[_locationIndex]; + } + + public: + size_t GetSize() override { + return sizeof( GLuint64 ); + } +}; + +class GLUniformSampler3D : protected GLUniformSampler { + protected: + GLUniformSampler3D( GLShader* shader, const char* name ) : + GLUniformSampler( shader, name, "sampler3D", 1 ) { + } + + inline GLint GetLocation() { + shaderProgram_t* p = _shader->GetProgram(); + + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } + + return p->uniformLocations[_locationIndex]; + } + + public: + size_t GetSize() override { + return sizeof( GLuint64 ); + } +}; + +class GLUniformUSampler3D : protected GLUniformSampler { + protected: + GLUniformUSampler3D( GLShader* shader, const char* name ) : + GLUniformSampler( shader, name, "usampler3D", 1 ) { + } + + inline GLint GetLocation() { + shaderProgram_t* p = _shader->GetProgram(); + + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } + + return p->uniformLocations[_locationIndex]; + } + + public: + size_t GetSize() override { + return sizeof( GLuint64 ); + } +}; + +class GLUniformSamplerCube : protected GLUniformSampler { + protected: + GLUniformSamplerCube( GLShader* shader, const char* name ) : + GLUniformSampler( shader, name, "samplerCube", 1 ) { + } + + inline GLint GetLocation() { + shaderProgram_t* p = _shader->GetProgram(); + + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } + + return p->uniformLocations[_locationIndex]; + } + + public: + size_t GetSize() override { + return sizeof( GLuint64 ); + } +}; + class GLUniform1i : protected GLUniform { protected: - GLUniform1i( GLShader *shader, const char *name ) : - GLUniform( shader, name ) + GLUniform1i( GLShader *shader, const char *name, const bool global = false ) : + GLUniform( shader, name, "int", 1, 1, global ) { } @@ -410,7 +664,9 @@ class GLUniform1i : protected GLUniform { shaderProgram_t *p = _shader->GetProgram(); - ASSERT_EQ(p, glState.currentProgram); + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } #if defined( LOG_GLSL_UNIFORMS ) if ( r_logFile->integer ) @@ -419,6 +675,12 @@ class GLUniform1i : protected GLUniform this->GetName(), _shader->GetName().c_str(), value ) ); } #endif + + if ( _shader->UseMaterialSystem() && !_global ) { + currentValue = value; + return; + } + #if defined( USE_UNIFORM_FIREWALL ) int *firewall = ( int * ) &p->uniformFirewall[ _firewallIndex ]; @@ -436,13 +698,73 @@ class GLUniform1i : protected GLUniform { return sizeof( int ); } + + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + memcpy( buffer, ¤tValue, sizeof( int ) ); + return buffer + 1; + } + + private: + int currentValue = 0; +}; + +class GLUniform1Bool : protected GLUniform { + protected: + // GLSL std430 bool is always 4 bytes, which might not correspond to C++ bool + GLUniform1Bool( GLShader* shader, const char* name ) : + GLUniform( shader, name, "bool", 1, 1, false ) { + } + + inline void SetValue( int value ) { + shaderProgram_t* p = _shader->GetProgram(); + + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } + +#if defined( LOG_GLSL_UNIFORMS ) + if ( r_logFile->integer ) { + GLimp_LogComment( va( "GLSL_SetUniform1i( %s, shader: %s, value: %d ) ---\n", + this->GetName(), _shader->GetName().c_str(), value ) ); + } +#endif + + if ( _shader->UseMaterialSystem() && !_global ) { + currentValue = value; + return; + } + +#if defined( USE_UNIFORM_FIREWALL ) + int* firewall = ( int* ) &p->uniformFirewall[_firewallIndex]; + + if ( *firewall == value ) { + return; + } + + *firewall = value; +#endif + glUniform1i( p->uniformLocations[_locationIndex], value ); + } + + public: + size_t GetSize() override { + return sizeof( int ); + } + + uint32_t* WriteToBuffer( uint32_t *buffer ) override { + memcpy( buffer, ¤tValue, sizeof( bool ) ); + return buffer + 1; + } + + private: + int currentValue = 0; }; class GLUniform1f : protected GLUniform { protected: GLUniform1f( GLShader *shader, const char *name ) : - GLUniform( shader, name ) + GLUniform( shader, name, "float", 1, 1, false ) { } @@ -450,7 +772,9 @@ class GLUniform1f : protected GLUniform { shaderProgram_t *p = _shader->GetProgram(); - ASSERT_EQ(p, glState.currentProgram); + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } #if defined( LOG_GLSL_UNIFORMS ) if ( r_logFile->integer ) @@ -459,6 +783,12 @@ class GLUniform1f : protected GLUniform this->GetName(), _shader->GetName().c_str(), value ) ); } #endif + + if ( _shader->UseMaterialSystem() && !_global ) { + currentValue = value; + return; + } + #if defined( USE_UNIFORM_FIREWALL ) float *firewall = ( float * ) &p->uniformFirewall[ _firewallIndex ]; @@ -476,21 +806,32 @@ class GLUniform1f : protected GLUniform { return sizeof( float ); } + + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + memcpy( buffer, ¤tValue, sizeof( float ) ); + return buffer + 1; + } + + private: + float currentValue = 0; }; class GLUniform1fv : protected GLUniform { protected: - GLUniform1fv( GLShader *shader, const char *name ) : - GLUniform( shader, name ) + GLUniform1fv( GLShader *shader, const char *name, const int size ) : + GLUniform( shader, name, "float", 1, 1, false, size ) { + currentValue.reserve( size ); } inline void SetValue( int numFloats, float *f ) { shaderProgram_t *p = _shader->GetProgram(); - ASSERT_EQ(p, glState.currentProgram); + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } #if defined( LOG_GLSL_UNIFORMS ) if ( r_logFile->integer ) @@ -499,23 +840,41 @@ class GLUniform1fv : protected GLUniform this->GetName(), _shader->GetName().c_str(), numFloats ) ); } #endif + + if ( _shader->UseMaterialSystem() && !_global ) { + memcpy( currentValue.data(), f, numFloats * sizeof( float ) ); + return; + } + glUniform1fv( p->uniformLocations[ _locationIndex ], numFloats, f ); } + + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + memcpy( buffer, currentValue.data(), currentValue.size() * sizeof( float ) ); + return buffer + _components; + } + + private: + std::vector currentValue; }; class GLUniform2f : protected GLUniform { protected: GLUniform2f( GLShader *shader, const char *name ) : - GLUniform( shader, name ) + GLUniform( shader, name, "vec2", 2, 2, false ) { + currentValue[0] = 0.0; + currentValue[1] = 0.0; } inline void SetValue( const vec2_t v ) { shaderProgram_t *p = _shader->GetProgram(); - ASSERT_EQ(p, glState.currentProgram); + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } #if defined( LOG_GLSL_UNIFORMS ) if ( r_logFile->integer ) @@ -524,6 +883,12 @@ class GLUniform2f : protected GLUniform this->GetName(), _shader->GetName().c_str(), v[ 0 ], v[ 1 ] ) ); } #endif + + if ( _shader->UseMaterialSystem() && !_global ) { + Vector2Copy( v, currentValue ); + return; + } + #if defined( USE_UNIFORM_FIREWALL ) vec2_t *firewall = ( vec2_t * ) &p->uniformFirewall[ _firewallIndex ]; @@ -542,21 +907,34 @@ class GLUniform2f : protected GLUniform { return sizeof( vec2_t ); } + + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + memcpy( buffer, ¤tValue, sizeof( vec2_t ) ); + return buffer + 2; + } + + private: + vec2_t currentValue; }; class GLUniform3f : protected GLUniform { protected: - GLUniform3f( GLShader *shader, const char *name ) : - GLUniform( shader, name ) + GLUniform3f( GLShader *shader, const char *name, const bool global = false ) : + GLUniform( shader, name, "vec3", 3, 4, global ) { + currentValue[0] = 0.0; + currentValue[1] = 0.0; + currentValue[2] = 0.0; } inline void SetValue( const vec3_t v ) { shaderProgram_t *p = _shader->GetProgram(); - ASSERT_EQ(p, glState.currentProgram); + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } #if defined( LOG_GLSL_UNIFORMS ) if ( r_logFile->integer ) @@ -565,6 +943,12 @@ class GLUniform3f : protected GLUniform this->GetName(), _shader->GetName().c_str(), v[ 0 ], v[ 1 ], v[ 2 ] ) ); } #endif + + if ( _shader->UseMaterialSystem() && !_global ) { + VectorCopy( v, currentValue ); + return; + } + #if defined( USE_UNIFORM_FIREWALL ) vec3_t *firewall = ( vec3_t * ) &p->uniformFirewall[ _firewallIndex ]; @@ -582,21 +966,35 @@ class GLUniform3f : protected GLUniform { return sizeof( vec3_t ); } + + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + memcpy( buffer, ¤tValue, sizeof( vec3_t ) ); + return buffer + 4; // vec3 is aligned to 4 components + } + + private: + vec3_t currentValue; }; class GLUniform4f : protected GLUniform { protected: GLUniform4f( GLShader *shader, const char *name ) : - GLUniform( shader, name ) + GLUniform( shader, name, "vec4", 4, 4, false ) { + currentValue[0] = 0.0; + currentValue[1] = 0.0; + currentValue[2] = 0.0; + currentValue[3] = 0.0; } inline void SetValue( const vec4_t v ) { shaderProgram_t *p = _shader->GetProgram(); - ASSERT_EQ(p, glState.currentProgram); + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } #if defined( LOG_GLSL_UNIFORMS ) if ( r_logFile->integer ) @@ -605,6 +1003,12 @@ class GLUniform4f : protected GLUniform this->GetName(), _shader->GetName().c_str(), v[ 0 ], v[ 1 ], v[ 2 ], v[ 3 ] ) ); } #endif + + if ( _shader->UseMaterialSystem() && !_global ) { + Vector4Copy( v, currentValue ); + return; + } + #if defined( USE_UNIFORM_FIREWALL ) vec4_t *firewall = ( vec4_t * ) &p->uniformFirewall[ _firewallIndex ]; @@ -622,21 +1026,32 @@ class GLUniform4f : protected GLUniform { return sizeof( vec4_t ); } + + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + memcpy( buffer, ¤tValue, sizeof( vec4_t ) ); + return buffer + 4; + } + + private: + vec4_t currentValue; }; class GLUniform4fv : protected GLUniform { protected: - GLUniform4fv( GLShader *shader, const char *name ) : - GLUniform( shader, name ) + GLUniform4fv( GLShader *shader, const char *name, const int size ) : + GLUniform( shader, name, "vec4", 4, 4, false, size ) { + currentValue.reserve( size ); } inline void SetValue( int numV, vec4_t *v ) { shaderProgram_t *p = _shader->GetProgram(); - ASSERT_EQ(p, glState.currentProgram); + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } #if defined( LOG_GLSL_UNIFORMS ) if ( r_logFile->integer ) @@ -645,23 +1060,41 @@ class GLUniform4fv : protected GLUniform this->GetName(), _shader->GetName().c_str(), numV ) ); } #endif + + if ( _shader->UseMaterialSystem() && !_global ) { + memcpy( currentValue.data(), v, numV * sizeof( vec4_t ) ); + return; + } + glUniform4fv( p->uniformLocations[ _locationIndex ], numV, &v[ 0 ][ 0 ] ); } + + public: + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + memcpy( buffer, currentValue.data(), currentValue.size() * sizeof( float ) ); + return buffer + 4 * _components; + } + + private: + std::vector currentValue; }; class GLUniformMatrix4f : protected GLUniform { protected: - GLUniformMatrix4f( GLShader *shader, const char *name ) : - GLUniform( shader, name ) + GLUniformMatrix4f( GLShader *shader, const char *name, const bool global = false ) : + GLUniform( shader, name, "mat4", 16, 4, global ) { + MatrixIdentity( currentValue ); } inline void SetValue( GLboolean transpose, const matrix_t m ) { shaderProgram_t *p = _shader->GetProgram(); - ASSERT_EQ(p, glState.currentProgram); + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } #if defined( LOG_GLSL_UNIFORMS ) if ( r_logFile->integer ) @@ -672,6 +1105,12 @@ class GLUniformMatrix4f : protected GLUniform m[ 13 ], m[ 14 ], m[ 15 ] ) ); } #endif + + if ( _shader->UseMaterialSystem() && !_global ) { + MatrixCopy( m, currentValue ); + return; + } + #if defined( USE_UNIFORM_FIREWALL ) matrix_t *firewall = ( matrix_t * ) &p->uniformFirewall[ _firewallIndex ]; @@ -689,21 +1128,32 @@ class GLUniformMatrix4f : protected GLUniform { return sizeof( matrix_t ); } + + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + memcpy( buffer, ¤tValue, sizeof( matrix_t ) ); + return buffer + 16; + } + + private: + matrix_t currentValue; }; class GLUniformMatrix4fv : protected GLUniform { protected: - GLUniformMatrix4fv( GLShader *shader, const char *name ) : - GLUniform( shader, name ) + GLUniformMatrix4fv( GLShader *shader, const char *name, const int size ) : + GLUniform( shader, name, "mat4", 16, 4, false, size ) { + currentValue.reserve( size * 16 ); } inline void SetValue( int numMatrices, GLboolean transpose, const matrix_t *m ) { shaderProgram_t *p = _shader->GetProgram(); - ASSERT_EQ(p, glState.currentProgram); + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } #if defined( LOG_GLSL_UNIFORMS ) if ( r_logFile->integer ) @@ -712,15 +1162,30 @@ class GLUniformMatrix4fv : protected GLUniform this->GetName(), _shader->GetName().c_str(), numMatrices, transpose ) ); } #endif + + if ( _shader->UseMaterialSystem() && !_global ) { + memcpy( currentValue.data(), m, numMatrices * sizeof( matrix_t ) ); + return; + } + glUniformMatrix4fv( p->uniformLocations[ _locationIndex ], numMatrices, transpose, &m[ 0 ][ 0 ] ); } + + public: + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + memcpy( buffer, currentValue.data(), currentValue.size() * sizeof( float ) ); + return buffer + 16 * _components; + } + + private: + std::vector currentValue; }; class GLUniformMatrix34fv : protected GLUniform { protected: - GLUniformMatrix34fv( GLShader *shader, const char *name ) : - GLUniform( shader, name ) + GLUniformMatrix34fv( GLShader *shader, const char *name, const int size ) : + GLUniform( shader, name, "mat3x4", 12, 4, false, size ) { } @@ -728,7 +1193,10 @@ class GLUniformMatrix34fv : protected GLUniform { shaderProgram_t *p = _shader->GetProgram(); - ASSERT_EQ(p, glState.currentProgram); + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } + #if defined( LOG_GLSL_UNIFORMS ) if ( r_logFile->integer ) { @@ -736,8 +1204,23 @@ class GLUniformMatrix34fv : protected GLUniform this->GetName(), _shader->GetName().c_str(), numMatrices, transpose ) ); } #endif + + if ( _shader->UseMaterialSystem() && !_global ) { + memcpy( currentValue.data(), m, numMatrices * sizeof( matrix_t ) ); + return; + } + glUniformMatrix3x4fv( p->uniformLocations[ _locationIndex ], numMatrices, transpose, m ); } + + public: + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + memcpy( buffer, currentValue.data(), currentValue.size() * sizeof( float ) ); + return buffer + 12 * _components; + } + + private: + std::vector currentValue; }; class GLUniformBlock @@ -783,16 +1266,129 @@ class GLUniformBlock } }; -class GLCompileMacro -{ -private: - int _bit; +class GLSSBO { + public: + std::string _name; + const GLuint _bindingPoint; -protected: - GLShader *_shader; + GLSSBO( const char* name, const GLuint bindingPoint ) : + _name( name ), + _bindingPoint( bindingPoint ) { + } - GLCompileMacro( GLShader *shader ) : - _shader( shader ) + public: + const char* GetName() { + return _name.c_str(); + } + + void BindBufferBase() { + glBindBufferBase( GL_SHADER_STORAGE_BUFFER, _bindingPoint, handle ); + } + + void BindBuffer() { + glBindBuffer( GL_SHADER_STORAGE_BUFFER, handle ); + } + + uint32_t* MapBufferRange( const GLuint count ) { + if ( !mapped ) { + mapped = true; + data = ( uint32_t* ) glMapBufferRange( GL_SHADER_STORAGE_BUFFER, + 0, count * sizeof( uint32_t ), + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT ); + } + + return data; + } + + uint32_t* MapBufferRange( const GLuint offset, const GLuint count ) { + if ( !mapped ) { + mapped = true; + data = ( uint32_t* ) glMapBufferRange( GL_SHADER_STORAGE_BUFFER, + offset * sizeof( uint32_t ), count * sizeof( uint32_t ), + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT ); + } + + return data; + } + + void UnmapBuffer() { + mapped = false; + glUnmapBuffer( GL_SHADER_STORAGE_BUFFER ); + } + + void GenBuffer() { + glGenBuffers( 1, &handle ); + } + + void DelBuffer() { + glDeleteBuffers( 1, &handle ); + } + + private: + GLuint handle; + bool mapped = false; + uint32_t* data; +}; + +class GLIndirectBuffer { + public: + + struct GLIndirectCommand { + GLuint count; + GLuint instanceCount; + GLuint firstIndex; + GLint baseVertex; + GLuint baseInstance; + }; + + std::string _name; + + GLIndirectBuffer( const char* name ) : + _name( name ) { + } + + public: + + const char* GetName() { + return _name.c_str(); + } + + void BindBuffer() { + glBindBuffer( GL_DRAW_INDIRECT_BUFFER, handle ); + } + + GLIndirectCommand* MapBufferRange( const GLuint count ) { + return (GLIndirectCommand*) glMapBufferRange( GL_DRAW_INDIRECT_BUFFER, + 0, count * sizeof( GLIndirectCommand ), + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT ); + } + + void UnmapBuffer() const { + glUnmapBuffer( GL_DRAW_INDIRECT_BUFFER ); + } + + void GenBuffer() { + glGenBuffers( 1, &handle ); + } + + void DelBuffer() { + glDeleteBuffers( 1, &handle ); + } + + private: + GLuint handle; +}; + +class GLCompileMacro +{ +private: + int _bit; + +protected: + GLShader *_shader; + + GLCompileMacro( GLShader *shader ) : + _shader( shader ) { _bit = BIT( _shader->GetNumOfCompiledMacros() ); _shader->RegisterCompileMacro( this ); @@ -1191,140 +1787,716 @@ class GLCompileMacro_USE_REFLECTIVE_SPECULAR : return EGLCompileMacro::USE_REFLECTIVE_SPECULAR; } - void SetReflectiveSpecular( bool enable ) - { - SetMacro( enable ); + void SetReflectiveSpecular( bool enable ) + { + SetMacro( enable ); + } +}; + +class GLCompileMacro_LIGHT_DIRECTIONAL : + GLCompileMacro +{ +public: + GLCompileMacro_LIGHT_DIRECTIONAL( GLShader *shader ) : + GLCompileMacro( shader ) + { + } + + const char *GetName() const override + { + return "LIGHT_DIRECTIONAL"; + } + + EGLCompileMacro GetType() const override + { + return EGLCompileMacro::LIGHT_DIRECTIONAL; + } + + void SetMacro_LIGHT_DIRECTIONAL( bool enable ) + { + SetMacro( enable ); + } +}; + +class GLCompileMacro_USE_SHADOWING : + GLCompileMacro +{ +public: + GLCompileMacro_USE_SHADOWING( GLShader *shader ) : + GLCompileMacro( shader ) + { + } + + const char *GetName() const override + { + return "USE_SHADOWING"; + } + + EGLCompileMacro GetType() const override + { + return EGLCompileMacro::USE_SHADOWING; + } + + void SetShadowing( bool enable ) + { + SetMacro( enable ); + } +}; + +class GLCompileMacro_USE_DEPTH_FADE : + GLCompileMacro +{ +public: + GLCompileMacro_USE_DEPTH_FADE( GLShader *shader ) : + GLCompileMacro( shader ) + { + } + + const char *GetName() const override + { + return "USE_DEPTH_FADE"; + } + + bool HasConflictingMacros(size_t permutation, const std::vector ¯os) const override; + EGLCompileMacro GetType() const override + { + return EGLCompileMacro::USE_DEPTH_FADE; + } + + void SetDepthFade( bool enable ) + { + SetMacro( enable ); + } +}; + +class GLCompileMacro_USE_PHYSICAL_MAPPING : + GLCompileMacro +{ +public: + GLCompileMacro_USE_PHYSICAL_MAPPING( GLShader *shader ) : + GLCompileMacro( shader ) + { + } + + const char *GetName() const override + { + return "USE_PHYSICAL_MAPPING"; + } + + EGLCompileMacro GetType() const override + { + return USE_PHYSICAL_MAPPING; + } + + void SetPhysicalShading( bool enable ) + { + SetMacro( enable ); + } +}; + +class u_LightFactor : + GLUniform1f +{ +public: + u_LightFactor( GLShader *shader ) : + GLUniform1f( shader, "u_LightFactor" ) + { + } + + void SetUniform_LightFactor( const float lightFactor ) + { + this->SetValue( lightFactor ); + } +}; + +class u_InverseLightFactor : + GLUniform1f +{ +public: + u_InverseLightFactor( GLShader *shader ) : + GLUniform1f( shader, "u_InverseLightFactor" ) + { + } + + void SetUniform_InverseLightFactor( const float inverseLightFactor ) + { + this->SetValue( inverseLightFactor ); + } +}; + +class u_ColorMap : + GLUniformSampler2D { + public: + u_ColorMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ColorMap" ) { + } + + void SetUniform_ColorMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_ColorMap() { + return this->GetLocation(); + } +}; + +class u_ColorMap3D : + GLUniformSampler3D { + public: + u_ColorMap3D( GLShader* shader ) : + GLUniformSampler3D( shader, "u_ColorMap3D" ) { + } + + void SetUniform_ColorMap3DBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_ColorMap3D() { + return this->GetLocation(); + } +}; + +class u_ColorMapCube : + GLUniformSamplerCube { + public: + u_ColorMapCube( GLShader* shader ) : + GLUniformSamplerCube( shader, "u_ColorMapCube" ) { + } + + void SetUniform_ColorMapCubeBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_ColorMapCube() { + return this->GetLocation(); + } +}; + +class u_DepthMap : + GLUniformSampler2D { + public: + u_DepthMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_DepthMap" ) { + } + + void SetUniform_DepthMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_DepthMap() { + return this->GetLocation(); + } +}; + +class u_DiffuseMap : + GLUniformSampler2D { + public: + u_DiffuseMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_DiffuseMap" ) { + } + + void SetUniform_DiffuseMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_DiffuseMap() { + return this->GetLocation(); + } +}; + +class u_HeightMap : + GLUniformSampler2D { + public: + u_HeightMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_HeightMap" ) { + } + + void SetUniform_HeightMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_HeightMap() { + return this->GetLocation(); + } +}; + +class u_NormalMap : + GLUniformSampler2D { + public: + u_NormalMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_NormalMap" ) { + } + + void SetUniform_NormalMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_NormalMap() { + return this->GetLocation(); + } +}; + +class u_MaterialMap : + GLUniformSampler2D { + public: + u_MaterialMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_MaterialMap" ) { + } + + void SetUniform_MaterialMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_MaterialMap() { + return this->GetLocation(); + } +}; + +class u_LightMap : + GLUniformSampler { + public: + u_LightMap( GLShader* shader ) : + GLUniformSampler( shader, "u_LightMap", "sampler2D", 1 ) { + } + + void SetUniform_LightMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_LightMap() { + return this->GetLocation(); + } +}; + +class u_DeluxeMap : + GLUniformSampler { + public: + u_DeluxeMap( GLShader* shader ) : + GLUniformSampler( shader, "u_DeluxeMap", "sampler2D", 1 ) { + } + + void SetUniform_DeluxeMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_DeluxeMap() { + return this->GetLocation(); + } +}; + +class u_GlowMap : + GLUniformSampler2D { + public: + u_GlowMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_GlowMap" ) { + } + + void SetUniform_GlowMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_GlowMap() { + return this->GetLocation(); + } +}; + +class u_RandomMap : + GLUniformSampler2D { + public: + u_RandomMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_RandomMap" ) { + } + + void SetUniform_RandomMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_RandomMap() { + return this->GetLocation(); + } +}; + +class u_PortalMap : + GLUniformSampler2D { + public: + u_PortalMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_PortalMap" ) { + } + + void SetUniform_PortalMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_PortalMap() { + return this->GetLocation(); + } +}; + +class u_CloudMap : + GLUniformSampler2D { + public: + u_CloudMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_CloudMap" ) { + } + + void SetUniform_CloudMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_CloudMap() { + return this->GetLocation(); + } +}; + +class u_LightsTexture : + GLUniformSampler2D { + public: + u_LightsTexture( GLShader* shader ) : + GLUniformSampler2D( shader, "u_LightsTexture" ) { + } + + void SetUniform_LightsTextureBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_LightsTexture() { + return this->GetLocation(); + } +}; + +class u_LightTiles : + GLUniformSampler3D { + public: + u_LightTiles( GLShader* shader ) : + GLUniformSampler3D( shader, "u_LightTiles" ) { + } + + void SetUniform_LightTilesBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_LightTiles() { + return this->GetLocation(); + } +}; + +class u_LightTilesInt : + GLUniformUSampler3D { + public: + u_LightTilesInt( GLShader* shader ) : + GLUniformUSampler3D( shader, "u_LightTilesInt" ) { + } + + void SetUniform_LightTilesIntBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_LightTilesInt() { + return this->GetLocation(); + } +}; + +class u_LightGrid1 : + GLUniformSampler3D { + public: + u_LightGrid1( GLShader* shader ) : + GLUniformSampler3D( shader, "u_LightGrid1" ) { + } + + void SetUniform_LightGrid1Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_LightGrid1() { + return this->GetLocation(); + } +}; + +class u_LightGrid2 : + GLUniformSampler3D { + public: + u_LightGrid2( GLShader* shader ) : + GLUniformSampler3D( shader, "u_LightGrid2" ) { + } + + void SetUniform_LightGrid2Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_LightGrid2() { + return this->GetLocation(); + } +}; + +class u_EnvironmentMap0 : + GLUniformSamplerCube { + public: + u_EnvironmentMap0( GLShader* shader ) : + GLUniformSamplerCube( shader, "u_EnvironmentMap0" ) { + } + + void SetUniform_EnvironmentMap0Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_EnvironmentMap0() { + return this->GetLocation(); + } +}; + +class u_EnvironmentMap1 : + GLUniformSamplerCube { + public: + u_EnvironmentMap1( GLShader* shader ) : + GLUniformSamplerCube( shader, "u_EnvironmentMap1" ) { + } + + void SetUniform_EnvironmentMap1Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_EnvironmentMap1() { + return this->GetLocation(); + } +}; + +class u_CurrentMap : + GLUniformSampler2D { + public: + u_CurrentMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_CurrentMap" ) { + } + + void SetUniform_CurrentMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_CurrentMap() { + return this->GetLocation(); + } +}; + +class u_AttenuationMapXY : + GLUniformSampler2D { + public: + u_AttenuationMapXY( GLShader* shader ) : + GLUniformSampler2D( shader, "u_AttenuationMapXY" ) { + } + + void SetUniform_AttenuationMapXYBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_AttenuationMapXY() { + return this->GetLocation(); + } +}; + +class u_AttenuationMapZ : + GLUniformSampler2D { + public: + u_AttenuationMapZ( GLShader* shader ) : + GLUniformSampler2D( shader, "u_AttenuationMapZ" ) { + } + + void SetUniform_AttenuationMapZBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_AttenuationMapZ() { + return this->GetLocation(); + } +}; + +class u_ShadowMap : + GLUniformSampler2D { + public: + u_ShadowMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowMap" ) { + } + + void SetUniform_ShadowMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_ShadowMap() { + return this->GetLocation(); + } +}; + +class u_ShadowMap0 : + GLUniformSampler2D { + public: + u_ShadowMap0( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowMap0" ) { + } + + void SetUniform_ShadowMap0Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_ShadowMap0() { + return this->GetLocation(); + } +}; + +class u_ShadowMap1 : + GLUniformSampler2D { + public: + u_ShadowMap1( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowMap1" ) { + } + + void SetUniform_ShadowMap1Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_ShadowMap1() { + return this->GetLocation(); + } +}; + +class u_ShadowMap2 : + GLUniformSampler2D { + public: + u_ShadowMap2( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowMap2" ) { + } + + void SetUniform_ShadowMap2Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_ShadowMap2() { + return this->GetLocation(); + } +}; + +class u_ShadowMap3 : + GLUniformSampler2D { + public: + u_ShadowMap3( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowMap3" ) { + } + + void SetUniform_ShadowMap3Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); } -}; -class GLCompileMacro_LIGHT_DIRECTIONAL : - GLCompileMacro -{ -public: - GLCompileMacro_LIGHT_DIRECTIONAL( GLShader *shader ) : - GLCompileMacro( shader ) - { + GLint GetUniformLocation_ShadowMap3() { + return this->GetLocation(); } +}; - const char *GetName() const override - { - return "LIGHT_DIRECTIONAL"; +class u_ShadowMap4 : + GLUniformSampler2D { + public: + u_ShadowMap4( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowMap4" ) { } - EGLCompileMacro GetType() const override - { - return EGLCompileMacro::LIGHT_DIRECTIONAL; + void SetUniform_ShadowMap4Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); } - void SetMacro_LIGHT_DIRECTIONAL( bool enable ) - { - SetMacro( enable ); + GLint GetUniformLocation_ShadowMap4() { + return this->GetLocation(); } }; -class GLCompileMacro_USE_SHADOWING : - GLCompileMacro -{ -public: - GLCompileMacro_USE_SHADOWING( GLShader *shader ) : - GLCompileMacro( shader ) - { +class u_ShadowClipMap : + GLUniformSampler2D { + public: + u_ShadowClipMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowClipMap" ) { } - const char *GetName() const override - { - return "USE_SHADOWING"; + void SetUniform_ShadowClipMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); } - EGLCompileMacro GetType() const override - { - return EGLCompileMacro::USE_SHADOWING; + GLint GetUniformLocation_ShadowClipMap() { + return this->GetLocation(); } +}; - void SetShadowing( bool enable ) - { - SetMacro( enable ); +class u_ShadowClipMap0 : + GLUniformSampler2D { + public: + u_ShadowClipMap0( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowClipMap0" ) { } -}; -class GLCompileMacro_USE_DEPTH_FADE : - GLCompileMacro -{ -public: - GLCompileMacro_USE_DEPTH_FADE( GLShader *shader ) : - GLCompileMacro( shader ) - { + void SetUniform_ShadowClipMap0Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); } - const char *GetName() const override - { - return "USE_DEPTH_FADE"; + GLint GetUniformLocation_ShadowClipMap0() { + return this->GetLocation(); } +}; - bool HasConflictingMacros(size_t permutation, const std::vector ¯os) const override; - EGLCompileMacro GetType() const override - { - return EGLCompileMacro::USE_DEPTH_FADE; +class u_ShadowClipMap1 : + GLUniformSampler2D { + public: + u_ShadowClipMap1( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowClipMap1" ) { } - void SetDepthFade( bool enable ) - { - SetMacro( enable ); + void SetUniform_ShadowClipMap1Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); } -}; -class GLCompileMacro_USE_PHYSICAL_MAPPING : - GLCompileMacro -{ -public: - GLCompileMacro_USE_PHYSICAL_MAPPING( GLShader *shader ) : - GLCompileMacro( shader ) - { + GLint GetUniformLocation_ShadowClipMap1() { + return this->GetLocation(); } +}; - const char *GetName() const override - { - return "USE_PHYSICAL_MAPPING"; +class u_ShadowClipMap2 : + GLUniformSampler2D { + public: + u_ShadowClipMap2( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowClipMap2" ) { } - EGLCompileMacro GetType() const override - { - return USE_PHYSICAL_MAPPING; + void SetUniform_ShadowClipMap2Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); } - void SetPhysicalShading( bool enable ) - { - SetMacro( enable ); + GLint GetUniformLocation_ShadowClipMap2() { + return this->GetLocation(); } }; -class u_LightFactor : - GLUniform1f -{ -public: - u_LightFactor( GLShader *shader ) : - GLUniform1f( shader, "u_LightFactor" ) - { +class u_ShadowClipMap3 : + GLUniformSampler2D { + public: + u_ShadowClipMap3( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowClipMap3" ) { } - void SetUniform_LightFactor( const float lightFactor ) - { - this->SetValue( lightFactor ); + void SetUniform_ShadowClipMap3Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_ShadowClipMap3() { + return this->GetLocation(); } }; -class u_InverseLightFactor : - GLUniform1f -{ -public: - u_InverseLightFactor( GLShader *shader ) : - GLUniform1f( shader, "u_InverseLightFactor" ) - { +class u_ShadowClipMap4 : + GLUniformSampler2D { + public: + u_ShadowClipMap4( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowClipMap4" ) { } - void SetUniform_InverseLightFactor( const float inverseLightFactor ) - { - this->SetValue( inverseLightFactor ); + void SetUniform_ShadowClipMap4Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_ShadowClipMap4() { + return this->GetLocation(); } }; @@ -1406,7 +2578,7 @@ class u_ViewOrigin : { public: u_ViewOrigin( GLShader *shader ) : - GLUniform3f( shader, "u_ViewOrigin" ) + GLUniform3f( shader, "u_ViewOrigin", true ) { } @@ -1421,7 +2593,7 @@ class u_ViewUp : { public: u_ViewUp( GLShader *shader ) : - GLUniform3f( shader, "u_ViewUp" ) + GLUniform3f( shader, "u_ViewUp", true ) { } @@ -1526,7 +2698,7 @@ class u_LightFrustum : { public: u_LightFrustum( GLShader *shader ) : - GLUniform4fv( shader, "u_LightFrustum" ) + GLUniform4fv( shader, "u_LightFrustum", 6 ) { } @@ -1571,7 +2743,7 @@ class u_ShadowMatrix : { public: u_ShadowMatrix( GLShader *shader ) : - GLUniformMatrix4fv( shader, "u_ShadowMatrix" ) + GLUniformMatrix4fv( shader, "u_ShadowMatrix", MAX_SHADOWMAPS ) { } @@ -1735,7 +2907,7 @@ class u_ModelMatrix : { public: u_ModelMatrix( GLShader *shader ) : - GLUniformMatrix4f( shader, "u_ModelMatrix" ) + GLUniformMatrix4f( shader, "u_ModelMatrix", true ) { } @@ -1810,7 +2982,7 @@ class u_ModelViewProjectionMatrix : { public: u_ModelViewProjectionMatrix( GLShader *shader ) : - GLUniformMatrix4f( shader, "u_ModelViewProjectionMatrix" ) + GLUniformMatrix4f( shader, "u_ModelViewProjectionMatrix", true ) { } @@ -1836,10 +3008,10 @@ class u_UnprojectMatrix : }; class u_UseCloudMap : - GLUniform1i { + GLUniform1Bool { public: u_UseCloudMap( GLShader* shader ) : - GLUniform1i( shader, "u_UseCloudMap" ) { + GLUniform1Bool( shader, "u_UseCloudMap" ) { } void SetUniform_UseCloudMap( const bool useCloudMap ) { @@ -1852,7 +3024,7 @@ class u_Bones : { public: u_Bones( GLShader *shader ) : - GLUniform4fv( shader, "u_Bones" ) + GLUniform4fv( shader, "u_Bones", MAX_BONES * 0 + 1 ) { } @@ -2176,7 +3348,7 @@ class u_LightGridOrigin : { public: u_LightGridOrigin( GLShader *shader ) : - GLUniform3f( shader, "u_LightGridOrigin" ) + GLUniform3f( shader, "u_LightGridOrigin", true ) { } @@ -2191,7 +3363,7 @@ class u_LightGridScale : { public: u_LightGridScale( GLShader *shader ) : - GLUniform3f( shader, "u_LightGridScale" ) + GLUniform3f( shader, "u_LightGridScale", true ) { } @@ -2233,7 +3405,7 @@ class u_numLights : { public: u_numLights( GLShader *shader ) : - GLUniform1i( shader, "u_numLights" ) + GLUniform1i( shader, "u_numLights", true ) { } @@ -2279,6 +3451,8 @@ class u_Lights : // TODO: Write a more minimal 2D rendering shader. class GLShader_generic2D : public GLShader, + public u_ColorMap, + public u_DepthMap, public u_TextureMatrix, public u_AlphaThreshold, public u_ModelMatrix, @@ -2298,6 +3472,8 @@ class GLShader_generic2D : class GLShader_generic : public GLShader, + public u_ColorMap, + public u_DepthMap, public u_TextureMatrix, public u_ViewOrigin, public u_ViewUp, @@ -2324,8 +3500,51 @@ class GLShader_generic : void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) override; }; +class GLShader_genericMaterial : + public GLShader, + public u_ColorMap, + public u_DepthMap, + public u_TextureMatrix, + public u_ViewOrigin, + public u_ViewUp, + public u_AlphaThreshold, + public u_ModelMatrix, + public u_ModelViewProjectionMatrix, + public u_InverseLightFactor, + public u_ColorModulate, + public u_Color, + // public u_Bones, + public u_VertexInterpolation, + public u_DepthScale, + public GLDeformStage, + // public GLCompileMacro_USE_VERTEX_SKINNING, + public GLCompileMacro_USE_VERTEX_ANIMATION, + public GLCompileMacro_USE_VERTEX_SPRITE, + public GLCompileMacro_USE_TCGEN_ENVIRONMENT, + public GLCompileMacro_USE_TCGEN_LIGHTMAP, + public GLCompileMacro_USE_DEPTH_FADE { + public: + GLShader_genericMaterial( GLShaderManager* manager ); + void BuildShaderVertexLibNames( std::string& vertexInlines ) override; + void SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) override; +}; + class GLShader_lightMapping : public GLShader, + public u_DiffuseMap, + public u_NormalMap, + public u_HeightMap, + public u_MaterialMap, + public u_LightMap, + public u_DeluxeMap, + public u_GlowMap, + public u_EnvironmentMap0, + public u_EnvironmentMap1, + public u_LightGrid1, + public u_LightGrid2, + public u_LightTiles, + public u_LightTilesInt, + public u_LightsTexture, public u_TextureMatrix, public u_SpecularExponent, public u_ColorModulate, @@ -2365,8 +3584,69 @@ class GLShader_lightMapping : void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) override; }; +class GLShader_lightMappingMaterial : + public GLShader, + public u_DiffuseMap, + public u_NormalMap, + public u_HeightMap, + public u_MaterialMap, + public u_LightMap, + public u_DeluxeMap, + public u_GlowMap, + public u_EnvironmentMap0, + public u_EnvironmentMap1, + public u_LightGrid1, + public u_LightGrid2, + public u_LightTilesInt, + public u_TextureMatrix, + public u_SpecularExponent, + public u_ColorModulate, + public u_Color, + public u_AlphaThreshold, + public u_ViewOrigin, + public u_ModelMatrix, + public u_ModelViewProjectionMatrix, + public u_InverseLightFactor, + // public u_Bones, + public u_VertexInterpolation, + public u_ReliefDepthScale, + public u_ReliefOffsetBias, + public u_NormalScale, + public u_EnvironmentInterpolation, + public u_LightGridOrigin, + public u_LightGridScale, + public u_numLights, + public u_Lights, + public GLDeformStage, + public GLCompileMacro_USE_BSP_SURFACE, + // public GLCompileMacro_USE_VERTEX_SKINNING, + public GLCompileMacro_USE_VERTEX_ANIMATION, + public GLCompileMacro_USE_DELUXE_MAPPING, + public GLCompileMacro_USE_GRID_LIGHTING, + public GLCompileMacro_USE_GRID_DELUXE_MAPPING, + public GLCompileMacro_USE_HEIGHTMAP_IN_NORMALMAP, + public GLCompileMacro_USE_RELIEF_MAPPING, + public GLCompileMacro_USE_REFLECTIVE_SPECULAR, + public GLCompileMacro_USE_PHYSICAL_MAPPING { + public: + GLShader_lightMappingMaterial( GLShaderManager* manager ); + void BuildShaderVertexLibNames( std::string& vertexInlines ) override; + void BuildShaderFragmentLibNames( std::string& fragmentInlines ) override; + void BuildShaderCompileMacros( std::string& compileMacros ) override; + void SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) override; +}; + class GLShader_forwardLighting_omniXYZ : public GLShader, + public u_DiffuseMap, + public u_NormalMap, + public u_MaterialMap, + public u_AttenuationMapXY, + public u_AttenuationMapZ, + public u_ShadowMap, + public u_ShadowClipMap, + public u_RandomMap, + public u_HeightMap, public u_TextureMatrix, public u_SpecularExponent, public u_AlphaThreshold, @@ -2405,6 +3685,15 @@ class GLShader_forwardLighting_omniXYZ : class GLShader_forwardLighting_projXYZ : public GLShader, + public u_DiffuseMap, + public u_NormalMap, + public u_MaterialMap, + public u_AttenuationMapXY, + public u_AttenuationMapZ, + public u_ShadowMap0, + public u_ShadowClipMap0, + public u_RandomMap, + public u_HeightMap, public u_TextureMatrix, public u_SpecularExponent, public u_AlphaThreshold, @@ -2444,6 +3733,20 @@ class GLShader_forwardLighting_projXYZ : class GLShader_forwardLighting_directionalSun : public GLShader, + public u_DiffuseMap, + public u_NormalMap, + public u_MaterialMap, + public u_ShadowMap0, + public u_ShadowMap1, + public u_ShadowMap2, + public u_ShadowMap3, + public u_ShadowMap4, + public u_ShadowClipMap0, + public u_ShadowClipMap1, + public u_ShadowClipMap2, + public u_ShadowClipMap3, + public u_ShadowClipMap4, + public u_HeightMap, public u_TextureMatrix, public u_SpecularExponent, public u_AlphaThreshold, @@ -2485,6 +3788,7 @@ class GLShader_forwardLighting_directionalSun : class GLShader_shadowFill : public GLShader, + public u_ColorMap, public u_TextureMatrix, public u_ViewOrigin, public u_AlphaThreshold, @@ -2508,6 +3812,9 @@ class GLShader_shadowFill : class GLShader_reflection : public GLShader, + public u_ColorMap, + public u_NormalMap, + public u_HeightMap, public u_TextureMatrix, public u_ViewOrigin, public u_ModelMatrix, @@ -2531,8 +3838,37 @@ class GLShader_reflection : void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) override; }; +class GLShader_reflectionMaterial : + public GLShader, + public u_ColorMap, + public u_NormalMap, + public u_HeightMap, + public u_TextureMatrix, + public u_ViewOrigin, + public u_ModelMatrix, + public u_ModelViewProjectionMatrix, + // public u_Bones, + public u_ReliefDepthScale, + public u_ReliefOffsetBias, + public u_NormalScale, + public u_VertexInterpolation, + public GLDeformStage, + // public GLCompileMacro_USE_VERTEX_SKINNING, + public GLCompileMacro_USE_VERTEX_ANIMATION, + public GLCompileMacro_USE_HEIGHTMAP_IN_NORMALMAP, + public GLCompileMacro_USE_RELIEF_MAPPING { + public: + GLShader_reflectionMaterial( GLShaderManager* manager ); + void BuildShaderVertexLibNames( std::string& vertexInlines ) override; + void BuildShaderFragmentLibNames( std::string& fragmentInlines ) override; + void BuildShaderCompileMacros( std::string& compileMacros ) override; + void SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) override; +}; + class GLShader_skybox : public GLShader, + public u_ColorMapCube, + public u_CloudMap, public u_TextureMatrix, public u_ViewOrigin, public u_CloudHeight, @@ -2548,8 +3884,27 @@ class GLShader_skybox : void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) override; }; +class GLShader_skyboxMaterial : + public GLShader, + public u_ColorMapCube, + public u_CloudMap, + public u_TextureMatrix, + public u_ViewOrigin, + public u_CloudHeight, + public u_UseCloudMap, + public u_AlphaThreshold, + public u_ModelMatrix, + public u_ModelViewProjectionMatrix, + public u_InverseLightFactor, + public GLDeformStage { + public: + GLShader_skyboxMaterial( GLShaderManager* manager ); + void SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) override; +}; + class GLShader_fogQuake3 : public GLShader, + public u_ColorMap, public u_ModelMatrix, public u_ModelViewProjectionMatrix, public u_InverseLightFactor, @@ -2569,8 +3924,31 @@ class GLShader_fogQuake3 : void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) override; }; +class GLShader_fogQuake3Material : + public GLShader, + public u_ColorMap, + public u_ModelMatrix, + public u_ModelViewProjectionMatrix, + public u_InverseLightFactor, + public u_Color, + // public u_Bones, + public u_VertexInterpolation, + public u_FogDistanceVector, + public u_FogDepthVector, + public u_FogEyeT, + public GLDeformStage, + // public GLCompileMacro_USE_VERTEX_SKINNING, + public GLCompileMacro_USE_VERTEX_ANIMATION { + public: + GLShader_fogQuake3Material( GLShaderManager* manager ); + void BuildShaderVertexLibNames( std::string& vertexInlines ) override; + void SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) override; +}; + class GLShader_fogGlobal : public GLShader, + public u_ColorMap, + public u_DepthMap, public u_ViewOrigin, public u_ViewMatrix, public u_ModelViewProjectionMatrix, @@ -2587,6 +3965,9 @@ class GLShader_fogGlobal : class GLShader_heatHaze : public GLShader, + public u_CurrentMap, + public u_NormalMap, + public u_HeightMap, public u_TextureMatrix, public u_ViewOrigin, public u_ViewUp, @@ -2612,8 +3993,38 @@ class GLShader_heatHaze : void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) override; }; +class GLShader_heatHazeMaterial : + public GLShader, + public u_CurrentMap, + public u_NormalMap, + public u_HeightMap, + public u_TextureMatrix, + public u_ViewOrigin, + public u_ViewUp, + public u_DeformMagnitude, + public u_ModelMatrix, + public u_ModelViewProjectionMatrix, + public u_ModelViewMatrixTranspose, + public u_ProjectionMatrixTranspose, + public u_ColorModulate, + public u_Color, + // public u_Bones, + public u_NormalScale, + public u_VertexInterpolation, + public GLDeformStage, + // public GLCompileMacro_USE_VERTEX_SKINNING, + public GLCompileMacro_USE_VERTEX_ANIMATION, + public GLCompileMacro_USE_VERTEX_SPRITE { + public: + GLShader_heatHazeMaterial( GLShaderManager* manager ); + void BuildShaderVertexLibNames( std::string& vertexInlines ) override; + void BuildShaderFragmentLibNames( std::string& fragmentInlines ) override; + void SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) override; +}; + class GLShader_screen : public GLShader, + public u_CurrentMap, public u_ModelViewProjectionMatrix { public: @@ -2621,8 +4032,18 @@ class GLShader_screen : void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) override; }; +class GLShader_screenMaterial : + public GLShader, + public u_CurrentMap, + public u_ModelViewProjectionMatrix { + public: + GLShader_screenMaterial( GLShaderManager* manager ); + void SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) override; +}; + class GLShader_portal : public GLShader, + public u_CurrentMap, public u_ModelViewMatrix, public u_ModelViewProjectionMatrix, public u_PortalRange @@ -2634,6 +4055,7 @@ class GLShader_portal : class GLShader_contrast : public GLShader, + public u_ColorMap, public u_ModelViewProjectionMatrix, public u_InverseLightFactor { @@ -2644,6 +4066,8 @@ class GLShader_contrast : class GLShader_cameraEffects : public GLShader, + public u_ColorMap3D, + public u_CurrentMap, public u_ColorModulate, public u_TextureMatrix, public u_ModelViewProjectionMatrix, @@ -2658,6 +4082,7 @@ class GLShader_cameraEffects : class GLShader_blurX : public GLShader, + public u_ColorMap, public u_ModelViewProjectionMatrix, public u_DeformMagnitude, public u_TexScale @@ -2669,6 +4094,7 @@ class GLShader_blurX : class GLShader_blurY : public GLShader, + public u_ColorMap, public u_ModelViewProjectionMatrix, public u_DeformMagnitude, public u_TexScale @@ -2680,6 +4106,7 @@ class GLShader_blurY : class GLShader_debugShadowMap : public GLShader, + public u_CurrentMap, public u_ModelViewProjectionMatrix { public: @@ -2689,6 +4116,13 @@ class GLShader_debugShadowMap : class GLShader_liquid : public GLShader, + public u_CurrentMap, + public u_DepthMap, + public u_NormalMap, + public u_PortalMap, + public u_LightGrid1, + public u_LightGrid2, + public u_HeightMap, public u_TextureMatrix, public u_ViewOrigin, public u_RefractionIndex, @@ -2715,8 +4149,45 @@ class GLShader_liquid : void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) override; }; +class GLShader_liquidMaterial : + public GLShader, + public u_CurrentMap, + public u_DepthMap, + public u_NormalMap, + public u_PortalMap, + public u_LightGrid1, + public u_LightGrid2, + public u_HeightMap, + public u_TextureMatrix, + public u_ViewOrigin, + public u_RefractionIndex, + public u_ModelMatrix, + public u_ModelViewProjectionMatrix, + public u_UnprojectMatrix, + public u_FresnelPower, + public u_FresnelScale, + public u_FresnelBias, + public u_ReliefDepthScale, + public u_ReliefOffsetBias, + public u_NormalScale, + public u_FogDensity, + public u_FogColor, + public u_LightTilesInt, + public u_SpecularExponent, + public u_LightGridOrigin, + public u_LightGridScale, + public GLCompileMacro_USE_HEIGHTMAP_IN_NORMALMAP, + public GLCompileMacro_USE_RELIEF_MAPPING { + public: + GLShader_liquidMaterial( GLShaderManager* manager ); + void BuildShaderFragmentLibNames( std::string& fragmentInlines ) override; + void SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) override; +}; + class GLShader_motionblur : public GLShader, + public u_ColorMap, + public u_DepthMap, public u_ModelViewProjectionMatrix, public u_blurVec { @@ -2727,6 +4198,7 @@ class GLShader_motionblur : class GLShader_ssao : public GLShader, + public u_DepthMap, public u_ModelViewProjectionMatrix, public u_UnprojectionParams, public u_zFar @@ -2738,6 +4210,7 @@ class GLShader_ssao : class GLShader_depthtile1 : public GLShader, + public u_DepthMap, public u_ModelViewProjectionMatrix, public u_zFar { @@ -2748,6 +4221,7 @@ class GLShader_depthtile1 : class GLShader_depthtile2 : public GLShader, + public u_DepthMap, public u_ModelViewProjectionMatrix { public: @@ -2757,10 +4231,12 @@ class GLShader_depthtile2 : class GLShader_lighttile : public GLShader, - public u_ModelMatrix, + public u_DepthMap, + public u_Lights, + public u_LightsTexture, public u_numLights, public u_lightLayer, - public u_Lights, + public u_ModelMatrix, public u_zFar { public: @@ -2770,6 +4246,7 @@ class GLShader_lighttile : class GLShader_fxaa : public GLShader, + public u_ColorMap, public u_ModelViewProjectionMatrix { public: @@ -2784,17 +4261,24 @@ extern ShaderKind shaderKind; extern GLShader_generic2D *gl_generic2DShader; extern GLShader_generic *gl_genericShader; +extern GLShader_genericMaterial *gl_genericShaderMaterial; extern GLShader_lightMapping *gl_lightMappingShader; +extern GLShader_lightMappingMaterial *gl_lightMappingShaderMaterial; extern GLShader_forwardLighting_omniXYZ *gl_forwardLightingShader_omniXYZ; extern GLShader_forwardLighting_projXYZ *gl_forwardLightingShader_projXYZ; -extern GLShader_forwardLighting_directionalSun *gl_forwardLightingShader_directionalSun; +extern GLShader_forwardLighting_directionalSun *gl_forwardLightingShader_directionalSun; extern GLShader_shadowFill *gl_shadowFillShader; extern GLShader_reflection *gl_reflectionShader; +extern GLShader_reflectionMaterial *gl_reflectionShaderMaterial; extern GLShader_skybox *gl_skyboxShader; +extern GLShader_skyboxMaterial *gl_skyboxShaderMaterial; extern GLShader_fogQuake3 *gl_fogQuake3Shader; +extern GLShader_fogQuake3Material *gl_fogQuake3ShaderMaterial; extern GLShader_fogGlobal *gl_fogGlobalShader; extern GLShader_heatHaze *gl_heatHazeShader; +extern GLShader_heatHazeMaterial *gl_heatHazeShaderMaterial; extern GLShader_screen *gl_screenShader; +extern GLShader_screenMaterial *gl_screenShaderMaterial; extern GLShader_portal *gl_portalShader; extern GLShader_contrast *gl_contrastShader; extern GLShader_cameraEffects *gl_cameraEffectsShader; @@ -2802,6 +4286,7 @@ extern GLShader_blurX *gl_blurXShader; extern GLShader_blurY *gl_blurYShader; extern GLShader_debugShadowMap *gl_debugShadowMapShader; extern GLShader_liquid *gl_liquidShader; +extern GLShader_liquidMaterial *gl_liquidShaderMaterial; extern GLShader_motionblur *gl_motionblurShader; extern GLShader_ssao *gl_ssaoShader; extern GLShader_depthtile1 *gl_depthtile1Shader; diff --git a/src/engine/renderer/glsl_source/cameraEffects_fp.glsl b/src/engine/renderer/glsl_source/cameraEffects_fp.glsl index 1659bc2b1b..74cfa0789c 100644 --- a/src/engine/renderer/glsl_source/cameraEffects_fp.glsl +++ b/src/engine/renderer/glsl_source/cameraEffects_fp.glsl @@ -23,9 +23,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* cameraEffects_fp.glsl */ uniform sampler2D u_CurrentMap; -uniform sampler3D u_ColorMap; +uniform sampler3D u_ColorMap3D; uniform float u_LightFactor; + uniform vec4 u_ColorModulate; uniform float u_InverseGamma; @@ -47,10 +48,10 @@ void main() // apply color grading vec3 colCoord = color.rgb * 15.0 / 16.0 + 0.5 / 16.0; colCoord.z *= 0.25; - color.rgb = u_ColorModulate.x * texture3D(u_ColorMap, colCoord).rgb; - color.rgb += u_ColorModulate.y * texture3D(u_ColorMap, colCoord + vec3(0.0, 0.0, 0.25)).rgb; - color.rgb += u_ColorModulate.z * texture3D(u_ColorMap, colCoord + vec3(0.0, 0.0, 0.50)).rgb; - color.rgb += u_ColorModulate.w * texture3D(u_ColorMap, colCoord + vec3(0.0, 0.0, 0.75)).rgb; + color.rgb = u_ColorModulate.x * texture3D(u_ColorMap3D, colCoord).rgb; + color.rgb += u_ColorModulate.y * texture3D(u_ColorMap3D, colCoord + vec3(0.0, 0.0, 0.25)).rgb; + color.rgb += u_ColorModulate.z * texture3D(u_ColorMap3D, colCoord + vec3(0.0, 0.0, 0.50)).rgb; + color.rgb += u_ColorModulate.w * texture3D(u_ColorMap3D, colCoord + vec3(0.0, 0.0, 0.75)).rgb; color.xyz = pow(color.xyz, vec3(u_InverseGamma)); diff --git a/src/engine/renderer/glsl_source/computeLight_fp.glsl b/src/engine/renderer/glsl_source/computeLight_fp.glsl index ce874dd770..2724dd4798 100644 --- a/src/engine/renderer/glsl_source/computeLight_fp.glsl +++ b/src/engine/renderer/glsl_source/computeLight_fp.glsl @@ -21,6 +21,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // computeLight_fp.glsl - Light computing helper functions +#define COMPUTELIGHT_GLSL + #if !defined(USE_BSP_SURFACE) #define USE_MODEL_SURFACE #endif @@ -47,7 +49,7 @@ layout(std140) uniform u_Lights { }; #define GetLight(idx, component) lights[idx].component #else // !HAVE_ARB_uniform_buffer_object -uniform sampler2D u_Lights; +uniform sampler2D u_LightsTexture; #define idxToTC( idx, w, h ) vec2( floor( ( idx * ( 1.0 / w ) ) + 0.5 ) * ( 1.0 / h ), \ fract( ( idx + 0.5 ) * (1.0 / w ) ) ) const struct GetLightOffsets { @@ -55,7 +57,7 @@ const struct GetLightOffsets { int color_type; int direction_angle; } getLightOffsets = GetLightOffsets(0, 1, 2); -#define GetLight(idx, component) texture2D( u_Lights, idxToTC(3 * idx + getLightOffsets.component, 64.0, float( 3 * MAX_REF_LIGHTS / 64 ) ) ) +#define GetLight(idx, component) texture2D( u_LightsTexture, idxToTC(3 * idx + getLightOffsets.component, 64.0, float( 3 * MAX_REF_LIGHTS / 64 ) ) ) #endif // HAVE_ARB_uniform_buffer_object uniform int u_numLights; @@ -75,9 +77,16 @@ void computeLight(in vec3 lightColor, vec4 diffuseColor, inout vec4 color) { color.rgb += lightColor.rgb * diffuseColor.rgb; } +#if defined(USE_REFLECTIVE_SPECULAR) +void computeDeluxeLight( vec3 lightDir, vec3 normal, vec3 viewDir, vec3 lightColor, + vec4 diffuseColor, vec4 materialColor, + inout vec4 color, in samplerCube u_EnvironmentMap0, in samplerCube u_EnvironmentMap1 ) +#else // !USE_REFLECTIVE_SPECULAR void computeDeluxeLight( vec3 lightDir, vec3 normal, vec3 viewDir, vec3 lightColor, vec4 diffuseColor, vec4 materialColor, - inout vec4 color ) { + inout vec4 color ) +#endif // !USE_REFLECTIVE_SPECULAR +{ vec3 H = normalize( lightDir + viewDir ); #if defined(USE_PHYSICAL_MAPPING) || defined(r_specularMapping) @@ -149,10 +158,10 @@ void computeDeluxeLight( vec3 lightDir, vec3 normal, vec3 viewDir, vec3 lightCol #if defined(HAVE_EXT_texture_integer) && defined(r_highPrecisionRendering) const int lightsPerLayer = 16; -uniform usampler3D u_LightTiles; +uniform usampler3D u_LightTilesInt; #define idxs_t uvec4 -idxs_t fetchIdxs( in vec3 coords ) { - return texture3D( u_LightTiles, coords ); +idxs_t fetchIdxs( in vec3 coords, in usampler3D u_LightTilesInt ) { + return texture3D( u_LightTilesInt, coords ); } int nextIdx( inout idxs_t idxs ) { uvec4 tmp = ( idxs & uvec4( 3 ) ) * uvec4( 0x40, 0x10, 0x04, 0x01 ); @@ -176,10 +185,15 @@ int nextIdx( inout idxs_t idxs ) { const int numLayers = MAX_REF_LIGHTS / 256; -// This code is only used by the tiled dynamic light renderer. #if defined(r_dynamicLight) && r_dynamicLightRenderer == 1 +#if defined(USE_REFLECTIVE_SPECULAR) void computeDynamicLight( int idx, vec3 P, vec3 normal, vec3 viewDir, vec4 diffuse, - vec4 material, inout vec4 color ) { + vec4 material, inout vec4 color, in samplerCube u_EnvironmentMap0, in samplerCube u_EnvironmentMap1 ) +#else // !USE_REFLECTIVE_SPECULAR +void computeDynamicLight( int idx, vec3 P, vec3 normal, vec3 viewDir, vec4 diffuse, + vec4 material, inout vec4 color ) +#endif // !USE_REFLECTIVE_SPECULAR +{ vec4 center_radius = GetLight( idx, center_radius ); vec4 color_type = GetLight( idx, color_type ); vec3 L; @@ -211,13 +225,25 @@ void computeDynamicLight( int idx, vec3 P, vec3 normal, vec3 viewDir, vec4 diffu L = GetLight( idx, direction_angle ).xyz; attenuation = 1.0; } + #if defined(USE_REFLECTIVE_SPECULAR) + computeDeluxeLight( L, normal, viewDir, + attenuation * attenuation * color_type.xyz, + diffuse, material, color, u_EnvironmentMap0, u_EnvironmentMap1 ); + #else // !USE_REFLECTIVE_SPECULAR computeDeluxeLight( L, normal, viewDir, attenuation * attenuation * color_type.xyz, diffuse, material, color ); + #endif // !USE_REFLECTIVE_SPECULAR } +#if defined(USE_REFLECTIVE_SPECULAR) +void computeDynamicLights( vec3 P, vec3 normal, vec3 viewDir, vec4 diffuse, vec4 material, + inout vec4 color, in usampler3D u_LightTilesInt, in samplerCube u_EnvironmentMap0, in samplerCube u_EnvironmentMap1 ) +#else // !USE_REFLECTIVE_SPECULAR void computeDynamicLights( vec3 P, vec3 normal, vec3 viewDir, vec4 diffuse, vec4 material, - inout vec4 color ) { + inout vec4 color, in usampler3D u_LightTilesInt ) +#endif // !USE_REFLECTIVE_SPECULAR +{ vec2 tile = floor( gl_FragCoord.xy * (1.0 / float( TILE_SIZE ) ) ) + 0.5; vec3 tileScale = vec3( r_tileStep, 1.0/numLayers ); @@ -226,7 +252,7 @@ void computeDynamicLights( vec3 P, vec3 normal, vec3 viewDir, vec4 diffuse, vec4 #endif for( int layer = 0; layer < numLayers; layer++ ) { - idxs_t idxs = fetchIdxs( tileScale * vec3( tile, float( layer ) + 0.5 ) ); + idxs_t idxs = fetchIdxs( tileScale * vec3( tile, float( layer ) + 0.5 ), u_LightTilesInt ); for( int i = 0; i < lightsPerLayer; i++ ) { int idx = numLayers * nextIdx( idxs ) + layer; @@ -234,8 +260,12 @@ void computeDynamicLights( vec3 P, vec3 normal, vec3 viewDir, vec4 diffuse, vec4 { break; } - - computeDynamicLight( idx, P, normal, viewDir, diffuse, material, color ); + + #if defined(USE_REFLECTIVE_SPECULAR) + computeDynamicLight( idx, P, normal, viewDir, diffuse, material, color, u_EnvironmentMap0, u_EnvironmentMap1 ); + #else // !USE_REFLECTIVE_SPECULAR + computeDynamicLight( idx, P, normal, viewDir, diffuse, material, color ); + #endif // !USE_REFLECTIVE_SPECULAR #if defined(r_showLightTiles) numLights++; diff --git a/src/engine/renderer/glsl_source/fogQuake3_fp.glsl b/src/engine/renderer/glsl_source/fogQuake3_fp.glsl index 7b8751a645..e14a642870 100644 --- a/src/engine/renderer/glsl_source/fogQuake3_fp.glsl +++ b/src/engine/renderer/glsl_source/fogQuake3_fp.glsl @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* fogQuake3_fp.glsl */ +#define FOGQUAKE3_GLSL + uniform sampler2D u_ColorMap; uniform float u_InverseLightFactor; @@ -33,6 +35,8 @@ DECLARE_OUTPUT(vec4) void main() { + #insert material_fp + vec4 color = texture2D(u_ColorMap, var_TexCoords); color *= var_Color; diff --git a/src/engine/renderer/glsl_source/fogQuake3_vp.glsl b/src/engine/renderer/glsl_source/fogQuake3_vp.glsl index 9eaae25117..8b1099d401 100644 --- a/src/engine/renderer/glsl_source/fogQuake3_vp.glsl +++ b/src/engine/renderer/glsl_source/fogQuake3_vp.glsl @@ -47,6 +47,8 @@ void DeformVertex( inout vec4 pos, void main() { + #insert material_vp + vec4 position; localBasis LB; vec2 texCoord, lmCoord; diff --git a/src/engine/renderer/glsl_source/generic_fp.glsl b/src/engine/renderer/glsl_source/generic_fp.glsl index ac79f5b560..e9f04ef1df 100644 --- a/src/engine/renderer/glsl_source/generic_fp.glsl +++ b/src/engine/renderer/glsl_source/generic_fp.glsl @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* generic_fp.glsl */ +#define GENERIC_GLSL + uniform sampler2D u_ColorMap; uniform float u_AlphaThreshold; @@ -41,6 +43,8 @@ DECLARE_OUTPUT(vec4) void main() { + #insert material_fp + vec4 color = texture2D(u_ColorMap, var_TexCoords); if( abs(color.a + u_AlphaThreshold) <= 1.0 ) diff --git a/src/engine/renderer/glsl_source/generic_vp.glsl b/src/engine/renderer/glsl_source/generic_vp.glsl index adcab067ca..5d82b3a074 100644 --- a/src/engine/renderer/glsl_source/generic_vp.glsl +++ b/src/engine/renderer/glsl_source/generic_vp.glsl @@ -55,6 +55,8 @@ void DeformVertex( inout vec4 pos, void main() { + #insert material_vp + vec4 position; localBasis LB; vec4 color; @@ -92,10 +94,13 @@ void main() var_TexCoords = (u_TextureMatrix * vec4(texCoord, 0.0, 1.0)).xy; #endif -#if defined(USE_DEPTH_FADE) || defined(USE_VERTEX_SPRITE) +#if defined(USE_DEPTH_FADE) // compute z of end of fading effect vec4 fadeDepth = u_ModelViewProjectionMatrix * (position - u_DepthScale * vec4(LB.normal, 0.0)); var_FadeDepth = fadeDepth.zw; +#elif defined(USE_VERTEX_SPRITE) + vec4 fadeDepth = u_ModelViewProjectionMatrix * (position - depthScale * vec4(LB.normal, 0.0)); + var_FadeDepth = fadeDepth.zw; #endif var_Color = color; diff --git a/src/engine/renderer/glsl_source/heatHaze_fp.glsl b/src/engine/renderer/glsl_source/heatHaze_fp.glsl index 99914adb30..d1d2bf9a4b 100644 --- a/src/engine/renderer/glsl_source/heatHaze_fp.glsl +++ b/src/engine/renderer/glsl_source/heatHaze_fp.glsl @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* heatHaze_fp.glsl */ +#define HEATHAZE_GLSL + uniform sampler2D u_CurrentMap; uniform float u_AlphaThreshold; @@ -32,10 +34,16 @@ DECLARE_OUTPUT(vec4) void main() { + #insert material_fp + vec4 color; // compute normal in tangent space from normalmap - vec3 normal = NormalInTangentSpace(var_TexCoords); + #if defined(r_normalMapping) + vec3 normal = NormalInTangentSpace(var_TexCoords, u_NormalMap); + #else // !r_normalMapping + vec3 normal = NormalInTangentSpace(var_TexCoords); + #endif // !r_normalMapping // calculate the screen texcoord in the 0.0 to 1.0 range vec2 st = gl_FragCoord.st / r_FBufSize; diff --git a/src/engine/renderer/glsl_source/heatHaze_vp.glsl b/src/engine/renderer/glsl_source/heatHaze_vp.glsl index a7fe1f3d7f..4c7ceb06bd 100644 --- a/src/engine/renderer/glsl_source/heatHaze_vp.glsl +++ b/src/engine/renderer/glsl_source/heatHaze_vp.glsl @@ -42,6 +42,8 @@ void DeformVertex( inout vec4 pos, void main() { + #insert material_vp + vec4 deformVec; float d1, d2; diff --git a/src/engine/renderer/glsl_source/lightMapping_fp.glsl b/src/engine/renderer/glsl_source/lightMapping_fp.glsl index 1aa67b33c2..a2a858cfec 100644 --- a/src/engine/renderer/glsl_source/lightMapping_fp.glsl +++ b/src/engine/renderer/glsl_source/lightMapping_fp.glsl @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* lightMapping_fp.glsl */ +#define LIGHTMAPPING_GLSL + uniform sampler2D u_DiffuseMap; uniform sampler2D u_MaterialMap; uniform sampler2D u_GlowMap; @@ -37,19 +39,11 @@ IN(smooth) vec3 var_Tangent; IN(smooth) vec3 var_Binormal; IN(smooth) vec3 var_Normal; -#if defined(USE_LIGHT_MAPPING) - uniform sampler2D u_LightMap; -#elif defined(USE_GRID_LIGHTING) - uniform sampler3D u_LightMap; - #define u_LightGrid1 u_LightMap -#endif +uniform sampler2D u_LightMap; +uniform sampler3D u_LightGrid1; -#if defined(USE_DELUXE_MAPPING) - uniform sampler2D u_DeluxeMap; -#elif defined(USE_GRID_DELUXE_MAPPING) - uniform sampler3D u_DeluxeMap; - #define u_LightGrid2 u_DeluxeMap -#endif +uniform sampler2D u_DeluxeMap; +uniform sampler3D u_LightGrid2; #if defined(USE_LIGHT_MAPPING) || defined(USE_DELUXE_MAPPING) IN(smooth) vec2 var_TexLight; @@ -64,6 +58,8 @@ DECLARE_OUTPUT(vec4) void main() { + #insert material_fp + // Compute view direction in world space. vec3 viewDir = normalize(u_ViewOrigin - var_Position); @@ -73,7 +69,7 @@ void main() #if defined(USE_RELIEF_MAPPING) // Compute texcoords offset from heightmap. - vec2 texOffset = ReliefTexOffset(texCoords, viewDir, tangentToWorldMatrix); + vec2 texOffset = ReliefTexOffset(texCoords, viewDir, tangentToWorldMatrix, u_HeightMap); texCoords += texOffset; #endif @@ -91,7 +87,11 @@ void main() } // Compute normal in world space from normalmap. - vec3 normal = NormalInWorldSpace(texCoords, tangentToWorldMatrix); + #if defined(r_normalMapping) + vec3 normal = NormalInWorldSpace(texCoords, tangentToWorldMatrix, u_NormalMap); + #else // !r_normalMapping + vec3 normal = NormalInWorldSpace(texCoords, tangentToWorldMatrix); + #endif // !r_normalMapping // Compute the material term. vec4 material = texture2D(u_MaterialMap, texCoords); @@ -156,14 +156,23 @@ void main() // Blend static light. #if defined(USE_DELUXE_MAPPING) || defined(USE_GRID_DELUXE_MAPPING) - computeDeluxeLight(lightDir, normal, viewDir, lightColor, diffuse, material, color); + #if defined(USE_REFLECTIVE_SPECULAR) + computeDeluxeLight(lightDir, normal, viewDir, lightColor, diffuse, material, color, u_EnvironmentMap0, u_EnvironmentMap1); + #else // !USE_REFLECTIVE_SPECULAR + computeDeluxeLight(lightDir, normal, viewDir, lightColor, diffuse, material, color); + #endif // !USE_REFLECTIVE_SPECULAR #else computeLight(lightColor, diffuse, color); #endif - // Blend dynamic lights, this code is only used by the tiled dynamic light renderer. + // Blend dynamic lights. #if defined(r_dynamicLight) && r_dynamicLightRenderer == 1 - computeDynamicLights(var_Position, normal, viewDir, diffuse, material, color); + #if defined(USE_REFLECTIVE_SPECULAR) + computeDynamicLights(var_Position, normal, viewDir, diffuse, material, color, u_LightTilesInt, + u_EnvironmentMap0, u_EnvironmentMap1); + #else // !USE_REFLECTIVE_SPECULAR + computeDynamicLights(var_Position, normal, viewDir, diffuse, material, color, u_LightTilesInt); + #endif // !USE_REFLECTIVE_SPECULAR #endif // Add Rim Lighting to highlight the edges on model entities. @@ -196,6 +205,7 @@ void main() outputColor = color; + // Debugging. #if defined(r_showNormalMaps) // Convert normal to [0,1] color space. diff --git a/src/engine/renderer/glsl_source/lightMapping_vp.glsl b/src/engine/renderer/glsl_source/lightMapping_vp.glsl index 5e0e1ff2f5..40a88d4f24 100644 --- a/src/engine/renderer/glsl_source/lightMapping_vp.glsl +++ b/src/engine/renderer/glsl_source/lightMapping_vp.glsl @@ -60,6 +60,8 @@ void DeformVertex(inout vec4 pos, inout vec3 normal, inout vec2 st, inout vec4 c void main() { + #insert material_vp + localBasis LB; vec4 position, color; vec2 texCoord, lmCoord; diff --git a/src/engine/renderer/glsl_source/liquid_fp.glsl b/src/engine/renderer/glsl_source/liquid_fp.glsl index ed0b3fa649..85de80601f 100644 --- a/src/engine/renderer/glsl_source/liquid_fp.glsl +++ b/src/engine/renderer/glsl_source/liquid_fp.glsl @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* liquid_fp.glsl */ +#define LIQUID_GLSL + uniform sampler2D u_CurrentMap; uniform sampler2D u_PortalMap; uniform sampler2D u_DepthMap; @@ -50,6 +52,8 @@ DECLARE_OUTPUT(vec4) void main() { + #insert material_fp + // compute incident ray vec3 viewDir = normalize(u_ViewOrigin - var_Position); @@ -64,17 +68,20 @@ void main() vec2 texNormal = var_TexCoords; #if defined(USE_RELIEF_MAPPING) - // ray intersect in view direction // compute texcoords offset from heightmap - vec2 texOffset = ReliefTexOffset(texNormal, viewDir, tangentToWorldMatrix); + vec2 texOffset = ReliefTexOffset(texNormal, viewDir, tangentToWorldMatrix, u_HeightMap); texScreen += texOffset; texNormal += texOffset; #endif // compute normal in world space from normalmap - vec3 normal = NormalInWorldSpace(texNormal, tangentToWorldMatrix); + #if defined(r_normalMapping) + vec3 normal = NormalInWorldSpace(texNormal, tangentToWorldMatrix, u_NormalMap); + #else // !r_normalMapping + vec3 normal = NormalInWorldSpace(texNormal, tangentToWorldMatrix); + #endif // !r_normalMapping // compute fresnel term float fresnel = clamp(u_FresnelBias + pow(1.0 - dot(viewDir, normal), u_FresnelPower) * @@ -129,7 +136,11 @@ void main() vec4 diffuse = vec4(0.0, 0.0, 0.0, 1.0); // compute the specular term - computeDeluxeLight(lightDir, normal, viewDir, lightColor, diffuse, reflectColor, color); + #if defined(USE_REFLECTIVE_SPECULAR) + computeDeluxeLight(lightDir, normal, viewDir, lightColor, diffuse, reflectColor, color, u_EnvironmentMap0, u_EnvironmentMap1); + #else // !USE_REFLECTIVE_SPECULAR + computeDeluxeLight(lightDir, normal, viewDir, lightColor, diffuse, reflectColor, color); + #endif // !USE_REFLECTIVE_SPECULAR outputColor = color; diff --git a/src/engine/renderer/glsl_source/liquid_vp.glsl b/src/engine/renderer/glsl_source/liquid_vp.glsl index 66d6b0de13..b65e2f44e9 100644 --- a/src/engine/renderer/glsl_source/liquid_vp.glsl +++ b/src/engine/renderer/glsl_source/liquid_vp.glsl @@ -40,6 +40,8 @@ OUT(smooth) vec3 var_Normal; void main() { + #insert material_vp + // transform vertex position into homogenous clip-space gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); diff --git a/src/engine/renderer/glsl_source/material_fp.glsl b/src/engine/renderer/glsl_source/material_fp.glsl new file mode 100644 index 0000000000..bf72a5cf6f --- /dev/null +++ b/src/engine/renderer/glsl_source/material_fp.glsl @@ -0,0 +1,132 @@ +/* +=========================================================================== + +Daemon BSD Source Code +Copyright (c) 2024 Daemon Developers +All rights reserved. + +This file is part of the Daemon BSD Source Code (Daemon Source Code). + +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. + +=========================================================================== +*/ + +/* material_fp.glsl */ + +/* +* For use with material system +* All changes to uniform samplers in shaders which use this system must be reflected here +* Any shader using this system should add #define SHADERNAME_GLSL in the beginning (including lib shaders) +* It should then be added here in the material system and bindless texture ifdefs: +* #if defined(SHADERNAME_GLSL) +* sampler* samplerName = sampler*( samplerName_initial ); +* #endif // !SHADERNAME_GLSL +* In the main shader add +* #insert material +* in the beginning of main() once +* Any texture samplers should be passed to functions from main() or other functions +*/ + +#if defined(USE_MATERIAL_SYSTEM) + +#ifdef HAVE_ARB_bindless_texture + +#if defined(COMPUTELIGHT_GLSL) +#if defined(USE_REFLECTIVE_SPECULAR) +samplerCube u_EnvironmentMap0 = samplerCube( u_EnvironmentMap0_initial ); +samplerCube u_EnvironmentMap1 = samplerCube( u_EnvironmentMap1_initial ); +#endif // !USE_REFLECTIVE_SPECULAR +usampler3D u_LightTilesInt = usampler3D( u_LightTilesInt_initial ); +#endif // !COMPUTELIGHT_GLSL + +#if defined(FOGQUAKE3_GLSL) +sampler2D u_ColorMap = sampler2D( u_ColorMap_initial ); +#endif // !FOGQUAKE3_GLSL + +#if defined(GENERIC_GLSL) +sampler2D u_ColorMap = sampler2D( u_ColorMap_initial ); +#if defined(USE_DEPTH_FADE) || defined(USE_VERTEX_SPRITE) +sampler2D u_DepthMap = sampler2D( u_DepthMap_initial ); +#endif // !(USE_DEPTH_FADE || USE_VERTEX_SPRITE) +#endif // !GENERIC_GLSL + +#if defined(HEATHAZE_GLSL) +sampler2D u_CurrentMap = sampler2D( u_CurrentMap_initial ); +#endif // !HEATHAZE_GLSL + +#if defined(LIGHTMAPPING_GLSL) +sampler2D u_DiffuseMap = sampler2D( u_DiffuseMap_initial ); +sampler2D u_MaterialMap = sampler2D( u_MaterialMap_initial ); +sampler2D u_GlowMap = sampler2D( u_GlowMap_initial ); +sampler2D u_LightMap = sampler2D( u_LightMap_initial ); +sampler3D u_LightGrid1 = sampler3D( u_LightGrid1_initial ); +sampler2D u_DeluxeMap = sampler2D( u_DeluxeMap_initial ); +sampler3D u_LightGrid2 = sampler3D( u_LightGrid2_initial ); +#endif // !LIGHTMAPPING_GLSL + +#if defined(LIQUID_GLSL) +sampler2D u_CurrentMap = sampler2D( u_CurrentMap_initial ); +sampler2D u_PortalMap = sampler2D( u_PortalMap_initial ); +sampler2D u_DepthMap = sampler2D( u_DepthMap_initial ); +sampler3D u_LightGrid1 = sampler3D( u_LightGrid1_initial ); +sampler3D u_LightGrid2 = sampler3D( u_LightGrid2_initial ); +#endif // !LIQUID_GLSL + +#if defined(REFLECTION_CB_GLSL) +samplerCube u_ColorMap = samplerCube( u_ColorMap_initial ); +#endif // !REFLECTION_CB_GLSL + +#if defined(RELIEFMAPPING_GLSL) +#if defined(r_normalMapping) || defined(USE_HEIGHTMAP_IN_NORMALMAP) +sampler2D u_NormalMap = sampler2D( u_NormalMap_initial ); +#endif // r_normalMapping || USE_HEIGHTMAP_IN_NORMALMAP + +#if defined(USE_RELIEF_MAPPING) +#if !defined(USE_HEIGHTMAP_IN_NORMALMAP) +sampler2D u_HeightMap = sampler2D( u_HeightMap_initial ); +#else +sampler2D u_HeightMap = sampler2D( u_NormalMap_initial ); +#endif // !USE_HEIGHTMAP_IN_NORMALMAP +#endif // USE_RELIEF_MAPPING +#endif // !RELIEFMAPPING_GLSL + +#if defined(SCREEN_GLSL) +sampler2D u_CurrentMap = sampler2D( u_CurrentMap_initial ); +#endif // !SCREEN_GLSL + +#if defined(SKYBOX_GLSL) +samplerCube u_ColorMapCube = samplerCube( u_ColorMapCube_initial ); +sampler2D u_CloudMap = sampler2D( u_CloudMap_initial ); +#endif // !SKYBOX_GLSL + +#else // !HAVE_ARB_bindless_texture +#endif + +#else // !USE_MATERIAL_SYSTEM + +#if defined(USE_HEIGHTMAP_IN_NORMALMAP) +#define u_HeightMap u_NormalMap +#endif // !USE_HEIGHTMAP_IN_NORMALMAP + +#endif // !USE_MATERIAL_SYSTEM diff --git a/src/engine/renderer/glsl_source/material_vp.glsl b/src/engine/renderer/glsl_source/material_vp.glsl new file mode 100644 index 0000000000..c08c75e967 --- /dev/null +++ b/src/engine/renderer/glsl_source/material_vp.glsl @@ -0,0 +1,44 @@ +/* +=========================================================================== + +Daemon BSD Source Code +Copyright (c) 2024 Daemon Developers +All rights reserved. + +This file is part of the Daemon BSD Source Code (Daemon Source Code). + +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. + +=========================================================================== +*/ + +/* material_vp.glsl */ + +#if defined(USE_MATERIAL_SYSTEM) + +#ifdef HAVE_ARB_shader_draw_parameters + in_drawID = drawID; + in_baseInstance = baseInstance; +#endif // !HAVE_ARB_shader_draw_parameters + +#endif // !USE_MATERIAL_SYSTEM diff --git a/src/engine/renderer/glsl_source/reflection_CB_fp.glsl b/src/engine/renderer/glsl_source/reflection_CB_fp.glsl index 3d73f961d0..d5f49b1161 100644 --- a/src/engine/renderer/glsl_source/reflection_CB_fp.glsl +++ b/src/engine/renderer/glsl_source/reflection_CB_fp.glsl @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* reflection_CB_fp.glsl */ +#define REFLECTION_CB_GLSL + uniform samplerCube u_ColorMap; uniform vec3 u_ViewOrigin; uniform mat4 u_ModelMatrix; @@ -36,6 +38,8 @@ DECLARE_OUTPUT(vec4) void main() { + #insert material_fp + // compute view direction in world space vec3 viewDir = normalize(var_Position - u_ViewOrigin); @@ -45,13 +49,17 @@ void main() #if defined(USE_RELIEF_MAPPING) // compute texcoords offset from heightmap - vec2 texOffset = ReliefTexOffset(texNormal, viewDir, tangentToWorldMatrix); + vec2 texOffset = ReliefTexOffset(texNormal, viewDir, tangentToWorldMatrix, u_HeightMap); texNormal += texOffset; #endif // USE_RELIEF_MAPPING // compute normal in tangent space from normal map - vec3 normal = NormalInWorldSpace(texNormal, tangentToWorldMatrix); + #if defined(r_normalMapping) + vec3 normal = NormalInWorldSpace(texNormal, tangentToWorldMatrix, u_NormalMap); + #else // !r_normalMapping + vec3 normal = NormalInWorldSpace(texNormal, tangentToWorldMatrix); + #endif // !r_normalMapping // compute reflection ray vec3 reflectionRay = reflect(viewDir, normal); diff --git a/src/engine/renderer/glsl_source/reflection_CB_vp.glsl b/src/engine/renderer/glsl_source/reflection_CB_vp.glsl index 6a09fb574b..45df2a0733 100644 --- a/src/engine/renderer/glsl_source/reflection_CB_vp.glsl +++ b/src/engine/renderer/glsl_source/reflection_CB_vp.glsl @@ -42,6 +42,8 @@ void DeformVertex( inout vec4 pos, void main() { + #insert material_vp + vec4 position; localBasis LB; vec2 texCoord, lmCoord; diff --git a/src/engine/renderer/glsl_source/reliefMapping_fp.glsl b/src/engine/renderer/glsl_source/reliefMapping_fp.glsl index de394d756f..02e6e99020 100644 --- a/src/engine/renderer/glsl_source/reliefMapping_fp.glsl +++ b/src/engine/renderer/glsl_source/reliefMapping_fp.glsl @@ -21,6 +21,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // reliefMapping_fp.glsl - Relief mapping helper functions +#define RELIEFMAPPING_GLSL + #if defined(r_normalMapping) || defined(USE_HEIGHTMAP_IN_NORMALMAP) uniform sampler2D u_NormalMap; #endif // r_normalMapping || USE_HEIGHTMAP_IN_NORMALMAP @@ -38,7 +40,11 @@ uniform float u_ReliefOffsetBias; #endif // USE_RELIEF_MAPPING // compute normal in tangent space +#if defined(r_normalMapping) +vec3 NormalInTangentSpace(vec2 texNormal, in sampler2D u_NormalMap) +#else // !r_normalMapping vec3 NormalInTangentSpace(vec2 texNormal) +#endif // !r_normalMapping { vec3 normal; @@ -102,6 +108,15 @@ vec3 NormalInTangentSpace(vec2 texNormal) } // compute normal in worldspace from normalmap +#if defined(r_normalMapping) +vec3 NormalInWorldSpace(vec2 texNormal, mat3 tangentToWorldMatrix, in sampler2D u_NormalMap) +{ + // compute normal in tangent space from normalmap + vec3 normal = NormalInTangentSpace(texNormal, u_NormalMap); + // transform normal into world space + return normalize(tangentToWorldMatrix * normal); +} +#else // !r_normalMapping vec3 NormalInWorldSpace(vec2 texNormal, mat3 tangentToWorldMatrix) { // compute normal in tangent space from normalmap @@ -109,13 +124,14 @@ vec3 NormalInWorldSpace(vec2 texNormal, mat3 tangentToWorldMatrix) // transform normal into world space return normalize(tangentToWorldMatrix * normal); } +#endif // !r_normalMapping #if defined(USE_RELIEF_MAPPING) // compute texcoords offset from heightmap // most of the code doing somewhat the same is likely to be named // RayIntersectDisplaceMap in other id tech3-based engines // so please keep the comment above to enable cross-tree look-up -vec2 ReliefTexOffset(vec2 rayStartTexCoords, vec3 viewDir, mat3 tangentToWorldMatrix) +vec2 ReliefTexOffset(vec2 rayStartTexCoords, vec3 viewDir, mat3 tangentToWorldMatrix, in sampler2D u_HeightMap) { // compute view direction in tangent space vec3 tangentViewDir = normalize(viewDir * tangentToWorldMatrix); @@ -143,7 +159,7 @@ vec2 ReliefTexOffset(vec2 rayStartTexCoords, vec3 viewDir, mat3 tangentToWorldMa currentDepth += currentSize; #if defined(USE_HEIGHTMAP_IN_NORMALMAP) - float depth = texture2D(u_NormalMap, rayStartTexCoords + displacement * currentDepth).a; + float depth = texture2D(u_HeightMap, rayStartTexCoords + displacement * currentDepth).a; #else // !USE_HEIGHTMAP_IN_NORMALMAP float depth = texture2D(u_HeightMap, rayStartTexCoords + displacement * currentDepth).g; #endif // !USE_HEIGHTMAP_IN_NORMALMAP @@ -167,7 +183,7 @@ vec2 ReliefTexOffset(vec2 rayStartTexCoords, vec3 viewDir, mat3 tangentToWorldMa currentSize *= 0.5; #if defined(USE_HEIGHTMAP_IN_NORMALMAP) - float depth = texture2D(u_NormalMap, rayStartTexCoords + displacement * currentDepth).a; + float depth = texture2D(u_HeightMap, rayStartTexCoords + displacement * currentDepth).a; #else // !USE_HEIGHTMAP_IN_NORMALMAP float depth = texture2D(u_HeightMap, rayStartTexCoords + displacement * currentDepth).g; #endif // !USE_HEIGHTMAP_IN_NORMALMAP diff --git a/src/engine/renderer/glsl_source/screen_fp.glsl b/src/engine/renderer/glsl_source/screen_fp.glsl index 75b6f504cb..8af646bcbd 100644 --- a/src/engine/renderer/glsl_source/screen_fp.glsl +++ b/src/engine/renderer/glsl_source/screen_fp.glsl @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* screen_fp.glsl */ +#define SCREEN_GLSL + uniform sampler2D u_CurrentMap; IN(smooth) vec4 var_Color; @@ -30,6 +32,8 @@ DECLARE_OUTPUT(vec4) void main() { + #insert material_fp + // calculate the screen texcoord in the 0.0 to 1.0 range vec2 st = gl_FragCoord.st / r_FBufSize; diff --git a/src/engine/renderer/glsl_source/screen_vp.glsl b/src/engine/renderer/glsl_source/screen_vp.glsl index 7d0afb53e1..fd35a2885e 100644 --- a/src/engine/renderer/glsl_source/screen_vp.glsl +++ b/src/engine/renderer/glsl_source/screen_vp.glsl @@ -31,6 +31,8 @@ OUT(smooth) vec4 var_Color; void main() { + #insert material_vp + // transform vertex position into homogenous clip-space gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); diff --git a/src/engine/renderer/glsl_source/skybox_fp.glsl b/src/engine/renderer/glsl_source/skybox_fp.glsl index 59549da0f3..c900e69512 100644 --- a/src/engine/renderer/glsl_source/skybox_fp.glsl +++ b/src/engine/renderer/glsl_source/skybox_fp.glsl @@ -22,9 +22,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* skybox_fp.glsl */ +#define SKYBOX_GLSL + const float radiusWorld = 4096.0; // Value used by quake 3 skybox code -uniform samplerCube u_ColorMap; +uniform samplerCube u_ColorMapCube; uniform float u_InverseLightFactor; uniform sampler2D u_CloudMap; @@ -52,12 +54,14 @@ float ComputeCloudParametric( vec3 skyVec, float radiusWorld, float cloudHeight void main() { + #insert material_fp + // compute incident ray vec3 incidentRay = normalize(var_Position); vec4 color; if( !u_UseCloudMap ) { - color = textureCube(u_ColorMap, incidentRay).rgba; + color = textureCube(u_ColorMapCube, incidentRay).rgba; } else { incidentRay *= ComputeCloudParametric( incidentRay, radiusWorld, u_CloudHeight ); incidentRay.z += radiusWorld; diff --git a/src/engine/renderer/glsl_source/skybox_vp.glsl b/src/engine/renderer/glsl_source/skybox_vp.glsl index 382f10a072..e3e236c420 100644 --- a/src/engine/renderer/glsl_source/skybox_vp.glsl +++ b/src/engine/renderer/glsl_source/skybox_vp.glsl @@ -30,6 +30,8 @@ OUT(smooth) vec3 var_Position; void main() { + #insert material_vp + // transform vertex position into homogenous clip-space gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); diff --git a/src/engine/renderer/glsl_source/vertexSprite_vp.glsl b/src/engine/renderer/glsl_source/vertexSprite_vp.glsl index 1a7537870d..8b914c4307 100644 --- a/src/engine/renderer/glsl_source/vertexSprite_vp.glsl +++ b/src/engine/renderer/glsl_source/vertexSprite_vp.glsl @@ -31,7 +31,7 @@ IN vec4 attr_Orientation; uniform vec3 u_ViewOrigin; uniform vec3 u_ViewUp; -float u_DepthScale; +float depthScale; void VertexFetch(out vec4 position, out localBasis normalBasis, @@ -77,6 +77,6 @@ void VertexFetch(out vec4 position, lmCoord = abs( attr_TexCoord0.zw ); color = attr_Color; - u_DepthScale = 2.0 * radius; + depthScale = 2.0 * radius; } #endif diff --git a/src/engine/renderer/shaders.cpp b/src/engine/renderer/shaders.cpp index 53f89c6636..b9aee09c9e 100644 --- a/src/engine/renderer/shaders.cpp +++ b/src/engine/renderer/shaders.cpp @@ -58,6 +58,8 @@ #include "shadowFill_fp.glsl.h" #include "shadowFill_vp.glsl.h" #include "skybox_fp.glsl.h" +#include "material_vp.glsl.h" +#include "material_fp.glsl.h" std::unordered_map shadermap({ { "glsl/blurX_fp.glsl", std::string(reinterpret_cast(blurX_fp_glsl), sizeof(blurX_fp_glsl)) }, @@ -97,6 +99,8 @@ std::unordered_map shadermap({ { "glsl/lighttile_vp.glsl", std::string(reinterpret_cast(lighttile_vp_glsl), sizeof(lighttile_vp_glsl)) }, { "glsl/liquid_fp.glsl", std::string(reinterpret_cast(liquid_fp_glsl), sizeof(liquid_fp_glsl)) }, { "glsl/liquid_vp.glsl", std::string(reinterpret_cast(liquid_vp_glsl), sizeof(liquid_vp_glsl)) }, + { "glsl/material_vp.glsl", std::string( reinterpret_cast< const char* >( material_vp_glsl ), sizeof( material_vp_glsl ) ) }, + { "glsl/material_fp.glsl", std::string( reinterpret_cast< const char* >( material_fp_glsl ), sizeof( material_fp_glsl ) ) }, { "glsl/motionblur_fp.glsl", std::string(reinterpret_cast(motionblur_fp_glsl), sizeof(motionblur_fp_glsl)) }, { "glsl/motionblur_vp.glsl", std::string(reinterpret_cast(motionblur_vp_glsl), sizeof(motionblur_vp_glsl)) }, { "glsl/portal_fp.glsl", std::string(reinterpret_cast(portal_fp_glsl), sizeof(portal_fp_glsl)) }, diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index c651c51780..39665b4ef4 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -24,6 +24,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "tr_local.h" #include "gl_shader.h" +#include "TextureManager.h" +#include "Material.h" #if defined( REFBONE_NAMES ) #include #endif @@ -57,6 +59,11 @@ void GL_Bind( image_t *image ) texnum = tr.blackImage->texnum; } + if ( glConfig2.bindlessTexturesAvailable ) { + tr.textureManager.BindReservedTexture( image->type, texnum ); + return; + } + if ( tr.currenttextures[ glState.currenttmu ] != texnum ) { image->frameUsed = tr.frameCount; @@ -73,7 +80,7 @@ void GL_Unbind( image_t *image ) glBindTexture( image->type, 0 ); } -void BindAnimatedImage( textureBundle_t *bundle ) +GLuint64 BindAnimatedImage( int unit, textureBundle_t *bundle ) { int index; @@ -85,16 +92,15 @@ void BindAnimatedImage( textureBundle_t *bundle ) } else { - GL_Bind( tr.defaultImage ); + return GL_BindToTMU( unit, tr.defaultImage ); } - return; + return tr.cinematicImage[bundle->videoMapHandle]->texture->bindlessTextureHandle; } if ( bundle->numImages <= 1 ) { - GL_Bind( bundle->image[ 0 ] ); - return; + return GL_BindToTMU( unit, bundle->image[ 0 ] ); } // it is necessary to do this messy calc to make sure animations line up @@ -109,7 +115,7 @@ void BindAnimatedImage( textureBundle_t *bundle ) index %= bundle->numImages; - GL_Bind( bundle->image[ index ] ); + return GL_BindToTMU( unit, bundle->image[ index ] ); } void GL_BindProgram( shaderProgram_t *program ) @@ -143,6 +149,7 @@ void GL_BindNullProgram() void GL_SelectTexture( int unit ) { + if ( glState.currenttmu == unit ) { return; @@ -165,7 +172,7 @@ void GL_SelectTexture( int unit ) glState.currenttmu = unit; } -void GL_BindToTMU( int unit, image_t *image ) +GLuint64 GL_BindToTMU( int unit, image_t *image ) { if ( !image ) { @@ -173,6 +180,15 @@ void GL_BindToTMU( int unit, image_t *image ) image = tr.defaultImage; } + if ( glConfig2.bindlessTexturesAvailable ) { + if ( materialSystem.generatingWorldCommandBuffer ) { + materialSystem.AddTexture( image->texture ); + return image->texture->bindlessTextureHandle; + } + + return tr.textureManager.BindTexture( 0, image->texture ); + } + int texnum = image->texnum; if ( unit < 0 || unit >= glConfig2.maxTextureUnits ) @@ -182,11 +198,12 @@ void GL_BindToTMU( int unit, image_t *image ) if ( tr.currenttextures[ unit ] == texnum ) { - return; + return 0; } GL_SelectTexture( unit ); GL_Bind( image ); + return 0; } void GL_BlendFunc( GLenum sfactor, GLenum dfactor ) @@ -872,6 +889,7 @@ static void RB_RenderDrawSurfaces( shaderSort_t fromSort, shaderSort_t toSort, for ( i = backEnd.viewParms.firstDrawSurf[ Util::ordinal(fromSort) ]; i < lastSurf; i++ ) { drawSurf = &backEnd.viewParms.drawSurfs[ i ]; + tess.currentDrawSurf = drawSurf; // FIXME: investigate why this happens. if( drawSurf->surface == nullptr ) @@ -1369,7 +1387,7 @@ static void RB_SetupLightForShadowing( trRefLight_t *light, int index, GL_BindProgram( nullptr ); GL_State( GLS_DEFAULT ); - GL_BindToTMU( 0, tr.whiteImage ); + GL_Bind( tr.whiteImage ); int cubeSide = index; int splitFrustumIndex = index; interaction_t *ia = light->firstInteraction; @@ -1877,7 +1895,9 @@ static void RB_SetupLightForLighting( trRefLight_t *light ) gl_debugShadowMapShader->BindProgram( 0 ); - GL_BindToTMU( 0, tr.sunShadowMapFBOImage[ frustumIndex ] ); + gl_debugShadowMapShader->SetUniform_CurrentMapBindless( + GL_BindToTMU( 0, tr.sunShadowMapFBOImage[frustumIndex] ) + ); w = 200; h = 200; @@ -1914,7 +1934,9 @@ static void RB_SetupLightForLighting( trRefLight_t *light ) GL_Cull( cullType_t::CT_TWO_SIDED ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); gl_genericShader->SetUniform_ModelViewProjectionMatrix( light->shadowMatrices[ frustumIndex ] ); @@ -2054,7 +2076,7 @@ static void RB_BlurShadowMap( const trRefLight_t *light, int i ) GL_Cull( cullType_t::CT_TWO_SIDED ); GL_State( GLS_DEPTHTEST_DISABLE ); - GL_BindToTMU( 0, images[ index ] ); + // GL_BindToTMU( 0, images[ index ] ); GL_PushMatrix(); @@ -2065,17 +2087,22 @@ static void RB_BlurShadowMap( const trRefLight_t *light, int i ) gl_blurXShader->SetUniform_DeformMagnitude( 1 ); gl_blurXShader->SetUniform_TexScale( texScale ); + gl_blurXShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, images[index] ) + ); + Tess_InstantQuad( *gl_blurXShader, 0, 0, fbos[ index ]->width, fbos[ index ]->height ); R_AttachFBOTexture2D( images[ index ]->type, images[ index ]->texnum, 0 ); glClear( GL_COLOR_BUFFER_BIT ); - GL_BindToTMU( 0, images[ index + MAX_SHADOWMAPS ] ); - gl_blurYShader->BindProgram( 0 ); gl_blurYShader->SetUniform_DeformMagnitude( 1 ); gl_blurYShader->SetUniform_TexScale( texScale ); + gl_blurYShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, images[index + MAX_SHADOWMAPS] ) + ); Tess_InstantQuad( *gl_blurYShader, 0, 0, fbos[index]->width, fbos[index]->height ); @@ -2780,7 +2807,9 @@ void RB_RunVisTests( ) gl_genericShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( tess.svars.texMatrices[ TB_COLORMAP ] ); GL_State( GLS_DEPTHTEST_DISABLE | GLS_COLORMASK_BITS ); @@ -2857,7 +2886,9 @@ void RB_RenderPostDepthLightTile() zParams[ 2 ] = backEnd.viewParms.zFar; gl_depthtile1Shader->SetUniform_zFar( zParams ); - GL_BindToTMU( 0, tr.currentDepthImage ); + gl_depthtile1Shader->SetUniform_DepthMapBindless( + GL_BindToTMU( 0, tr.currentDepthImage ) + ); matrix_t ortho; GL_PushMatrix(); @@ -2880,7 +2911,9 @@ void RB_RenderPostDepthLightTile() GL_Scissor( 0, 0, w, h ); gl_depthtile2Shader->BindProgram( 0 ); - GL_BindToTMU( 0, tr.depthtile1RenderImage ); + gl_depthtile2Shader->SetUniform_DepthMapBindless( + GL_BindToTMU( 0, tr.depthtile1RenderImage ) + ); Tess_InstantQuad( *gl_depthtile2Shader, backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, @@ -2903,10 +2936,14 @@ void RB_RenderPostDepthLightTile() if( glConfig2.uniformBufferObjectAvailable ) { gl_lighttileShader->SetUniformBlock_Lights( tr.dlightUBO ); } else { - GL_BindToTMU( 1, tr.dlightImage ); + gl_lighttileShader->SetUniform_LightsTextureBindless( + GL_BindToTMU( 1, tr.dlightImage ) + ); } - GL_BindToTMU( 0, tr.depthtile2RenderImage ); + gl_lighttileShader->SetUniform_DepthMapBindless( + GL_BindToTMU( 1, tr.depthtile2RenderImage ) + ); R_BindVBO( tr.lighttileVBO ); @@ -3009,10 +3046,14 @@ void RB_RenderGlobalFog() gl_fogGlobalShader->SetUniform_UnprojectMatrix( backEnd.viewParms.unprojectionMatrix ); // bind u_ColorMap - GL_BindToTMU( 0, tr.fogImage ); + gl_fogGlobalShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.fogImage ) + ); // bind u_DepthMap - GL_BindToTMU( 1, tr.currentDepthImage ); + gl_fogGlobalShader->SetUniform_DepthMapBindless( + GL_BindToTMU( 0, tr.currentDepthImage ) + ); // set 2D virtual screen size GL_PushMatrix(); @@ -3070,7 +3111,9 @@ void RB_RenderBloom() // u_InverseLightFactor gl_contrastShader->SetUniform_InverseLightFactor( tr.mapInverseLightFactor ); - GL_BindToTMU( 0, tr.currentRenderImage[ backEnd.currentMainFBO ] ); + gl_contrastShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.currentRenderImage[backEnd.currentMainFBO] ) + ); GL_PopMatrix(); // special 1/4th of the screen contrastRenderFBO ortho @@ -3084,7 +3127,9 @@ void RB_RenderBloom() backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); // render bloom in multiple passes - GL_BindToTMU( 0, tr.contrastRenderFBOImage ); + gl_contrastShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.contrastRenderFBOImage ) + ); for ( i = 0; i < 2; i++ ) { for ( j = 0; j < r_bloomPasses->integer; j++ ) @@ -3112,6 +3157,9 @@ void RB_RenderBloom() gl_blurXShader->SetUniform_DeformMagnitude( r_bloomBlur->value ); gl_blurXShader->SetUniform_TexScale( texScale ); + gl_blurXShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.bloomRenderFBOImage[flip] ) + ); Tess_InstantQuad( *gl_blurXShader, backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); @@ -3122,6 +3170,9 @@ void RB_RenderBloom() gl_blurYShader->SetUniform_DeformMagnitude( r_bloomBlur->value ); gl_blurYShader->SetUniform_TexScale( texScale ); + gl_blurYShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.bloomRenderFBOImage[flip] ) + ); Tess_InstantQuad( *gl_blurYShader, backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); @@ -3142,6 +3193,7 @@ void RB_RenderBloom() GL_BindToTMU( 0, tr.blackImage ); + gl_screenShader->SetUniform_CurrentMapBindless( GL_BindToTMU( 0, tr.blackImage ) ); Tess_InstantQuad( *gl_screenShader, backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); @@ -3167,15 +3219,20 @@ void RB_RenderMotionBlur() GL_State( GLS_DEPTHTEST_DISABLE ); GL_Cull( cullType_t::CT_TWO_SIDED ); + gl_motionblurShader->BindProgram( 0 ); + // Swap main FBOs - GL_BindToTMU( 0, tr.currentRenderImage[ backEnd.currentMainFBO ] ); + gl_motionblurShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.currentRenderImage[backEnd.currentMainFBO] ) + ); backEnd.currentMainFBO = 1 - backEnd.currentMainFBO; R_BindFBO( tr.mainFBO[ backEnd.currentMainFBO ] ); - gl_motionblurShader->BindProgram( 0 ); gl_motionblurShader->SetUniform_blurVec(tr.refdef.blurVec); - GL_BindToTMU( 1, tr.currentDepthImage ); + gl_motionblurShader->SetUniform_DepthMapBindless( + GL_BindToTMU( 1, tr.currentDepthImage ) + ); matrix_t ortho; GL_PushMatrix(); @@ -3234,7 +3291,9 @@ void RB_RenderSSAO() gl_ssaoShader->SetUniform_UnprojectionParams( unprojectionParams ); - GL_BindToTMU( 0, tr.currentDepthImage ); + gl_ssaoShader->SetUniform_DepthMapBindless( + GL_BindToTMU( 0, tr.currentDepthImage ) + ); matrix_t ortho; GL_PushMatrix(); @@ -3273,14 +3332,16 @@ void RB_FXAA() GL_State( GLS_DEPTHTEST_DISABLE ); GL_Cull( cullType_t::CT_TWO_SIDED ); + // set the shader parameters + gl_fxaaShader->BindProgram( 0 ); + // Swap main FBOs - GL_BindToTMU( 0, tr.currentRenderImage[ backEnd.currentMainFBO ] ); + gl_fxaaShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.currentRenderImage[backEnd.currentMainFBO] ) + ); backEnd.currentMainFBO = 1 - backEnd.currentMainFBO; R_BindFBO( tr.mainFBO[ backEnd.currentMainFBO ] ); - // set the shader parameters - gl_fxaaShader->BindProgram( 0 ); - matrix_t ortho; GL_PushMatrix(); MatrixOrthogonalProjection( ortho, backEnd.viewParms.viewportX, @@ -3334,8 +3395,12 @@ void RB_CameraPostFX() // This shader is run last, so let it render to screen instead of // tr.mainFBO R_BindNullFBO(); - GL_BindToTMU( 0, tr.currentRenderImage[ backEnd.currentMainFBO ] ); - GL_BindToTMU( 3, tr.colorGradeImage ); + gl_cameraEffectsShader->SetUniform_CurrentMapBindless( + GL_BindToTMU( 0, tr.currentRenderImage[backEnd.currentMainFBO] ) + ); + gl_cameraEffectsShader->SetUniform_ColorMap3DBindless( + GL_BindToTMU( 3, tr.colorGradeImage ) + ); // draw viewport Tess_InstantQuad( *gl_cameraEffectsShader, @@ -3379,7 +3444,9 @@ static void RB_RenderDebugUtils() gl_genericShader->SetRequiredVertexPointers(); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); ia = nullptr; @@ -3538,7 +3605,9 @@ static void RB_RenderDebugUtils() gl_genericShader->SetUniform_Color( Color::Black ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); for ( iaCount = 0, ia = &backEnd.viewParms.interactions[ 0 ]; iaCount < backEnd.viewParms.numInteractions; ia++, iaCount++ ) @@ -3662,7 +3731,9 @@ static void RB_RenderDebugUtils() gl_genericShader->SetUniform_Color( Color::Black ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); ent = backEnd.refdef.entities; @@ -3738,11 +3809,13 @@ static void RB_RenderDebugUtils() // bind u_ColorMap #if defined( REFBONE_NAMES ) - GL_BindToTMU( 0, r_imageHashTable [ tr.charsetImageHash ] ); + GL_BindToTMU( gl_genericShader->GetUniformLocation_ColorMap(), r_imageHashTable [ tr.charsetImageHash ] ); int width = r_imageHashTable [ tr.charsetImageHash ]->width; int height = r_imageHashTable [ tr.charsetImageHash ]->height; #else - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); #endif gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); @@ -3964,7 +4037,9 @@ static void RB_RenderDebugUtils() gl_genericShader->SetUniform_ColorModulate( colorGen_t::CGEN_CUSTOM_RGB, alphaGen_t::AGEN_CUSTOM ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); // set 2D virtual screen size @@ -4050,7 +4125,9 @@ static void RB_RenderDebugUtils() } // bind u_ColorMap - GL_BindToTMU( 0, cubeProbe->cubemap ); + gl_reflectionShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, cubeProbe->cubemap ) + ); Tess_AddCubeWithNormals( cubeProbe->origin, mins, maxs, Color::White ); } @@ -4087,7 +4164,9 @@ static void RB_RenderDebugUtils() gl_genericShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); GL_CheckErrors(); @@ -4163,7 +4242,9 @@ static void RB_RenderDebugUtils() gl_genericShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); GL_CheckErrors(); @@ -4247,7 +4328,9 @@ static void RB_RenderDebugUtils() gl_genericShader->SetUniform_ColorModulate( colorGen_t::CGEN_CUSTOM_RGB, alphaGen_t::AGEN_CUSTOM ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); GL_CheckErrors(); @@ -4339,7 +4422,9 @@ static void RB_RenderDebugUtils() GL_Cull( cullType_t::CT_TWO_SIDED ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); gl_genericShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); @@ -4541,7 +4626,9 @@ static void RB_RenderDebugUtils() gl_genericShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); GL_CheckErrors(); @@ -4632,7 +4719,9 @@ void DebugDrawBegin( debugDrawMode_t mode, float size ) { gl_genericShader->SetUniform_Color( colorClear ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); // render in world space @@ -4763,7 +4852,12 @@ static void RB_RenderView( bool depthPass ) startTime = ri.Milliseconds(); } + materialSystem.frameStart = true; + if( depthPass ) { + if ( glConfig2.materialSystemAvailable ) { + materialSystem.RenderMaterials( shaderSort_t::SS_DEPTH, shaderSort_t::SS_DEPTH ); + } RB_RenderDrawSurfaces( shaderSort_t::SS_DEPTH, shaderSort_t::SS_DEPTH, DRAWSURFACES_ALL ); RB_RunVisTests(); if ( !backEnd.postDepthLightTileRendered && !backEnd.viewParms.hasNestedViews ) { @@ -4778,6 +4872,9 @@ static void RB_RenderView( bool depthPass ) tr.refdef.blurVec[2] != 0.0f ) { // draw everything that is not the gun + if ( glConfig2.materialSystemAvailable ) { + materialSystem.RenderMaterials( shaderSort_t::SS_ENVIRONMENT_FOG, shaderSort_t::SS_OPAQUE ); + } RB_RenderDrawSurfaces( shaderSort_t::SS_ENVIRONMENT_FOG, shaderSort_t::SS_OPAQUE, DRAWSURFACES_ALL_FAR ); RB_RenderMotionBlur(); @@ -4788,6 +4885,9 @@ static void RB_RenderView( bool depthPass ) else { // draw everything that is opaque + if ( glConfig2.materialSystemAvailable ) { + materialSystem.RenderMaterials( shaderSort_t::SS_ENVIRONMENT_FOG, shaderSort_t::SS_OPAQUE ); + } RB_RenderDrawSurfaces( shaderSort_t::SS_ENVIRONMENT_FOG, shaderSort_t::SS_OPAQUE, DRAWSURFACES_ALL ); } @@ -4817,6 +4917,9 @@ static void RB_RenderView( bool depthPass ) RB_RenderGlobalFog(); // draw everything that is translucent + if ( glConfig2.materialSystemAvailable ) { + materialSystem.RenderMaterials( shaderSort_t::SS_ENVIRONMENT_NOFOG, shaderSort_t::SS_POST_PROCESS ); + } RB_RenderDrawSurfaces( shaderSort_t::SS_ENVIRONMENT_NOFOG, shaderSort_t::SS_POST_PROCESS, DRAWSURFACES_ALL ); GL_CheckErrors(); @@ -4909,6 +5012,11 @@ void RE_UploadCinematic( int cols, int rows, const byte *data, int client, bool glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER ); glTexParameterfv( GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, Color::Black.ToArray() ); + + // Getting bindless handle makes the texture immutable, so generate it again because we used glTexParameter* + if ( glConfig2.bindlessTexturesAvailable ) { + tr.cinematicImage[ client ]->texture->GenBindlessHandle(); + } } else { @@ -5455,7 +5563,9 @@ const RenderCommand *SetupLightsCommand::ExecuteSelf( ) const glUnmapBuffer( bufferTarget ); if( !glConfig2.uniformBufferObjectAvailable ) { - GL_BindToTMU( 0, tr.dlightImage ); + gl_lighttileShader->SetUniform_LightsTextureBindless( + GL_BindToTMU( 1, tr.dlightImage ) + ); glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, tr.dlightImage->width, tr.dlightImage->height, GL_RGBA, GL_FLOAT, nullptr ); } glBindBuffer( bufferTarget, 0 ); @@ -5795,7 +5905,9 @@ void RB_ShowImages() } // bind u_ColorMap - GL_Bind( image ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, image ) + ); Tess_InstantQuad( *gl_genericShader, x, y, w, h ); } @@ -5921,6 +6033,7 @@ void RB_ExecuteRenderCommands( const void *data ) { cmd = cmd->ExecuteSelf(); } + // stop rendering on this thread t2 = ri.Milliseconds(); backEnd.pc.msec = t2 - t1; diff --git a/src/engine/renderer/tr_bsp.cpp b/src/engine/renderer/tr_bsp.cpp index aa0cfd7e18..50f841e1ab 100644 --- a/src/engine/renderer/tr_bsp.cpp +++ b/src/engine/renderer/tr_bsp.cpp @@ -6425,7 +6425,7 @@ vertexHash_t *AddVertexToHashTable( vertexHash_t **hashTable, vec3_t xyz, void * return vertexHash; } -void GL_BindNearestCubeMap( const vec3_t xyz ) +void GL_BindNearestCubeMap( int unit, const vec3_t xyz ) { float distance, maxDistance; cubemapProbe_t *cubeProbe; @@ -6461,7 +6461,7 @@ void GL_BindNearestCubeMap( const vec3_t xyz ) } } - GL_Bind( tr.autoCubeImage ); + GL_BindToTMU( unit, tr.autoCubeImage ); } void R_FindTwoNearestCubeMaps( const vec3_t position, cubemapProbe_t **cubeProbeNearest, cubemapProbe_t **cubeProbeSecondNearest ) diff --git a/src/engine/renderer/tr_image.cpp b/src/engine/renderer/tr_image.cpp index 0934c1cf55..8fe80f51da 100644 --- a/src/engine/renderer/tr_image.cpp +++ b/src/engine/renderer/tr_image.cpp @@ -126,6 +126,11 @@ void GL_TextureMode( const char *string ) { glTexParameterf( image->type, GL_TEXTURE_MAX_ANISOTROPY_EXT, glConfig2.textureAnisotropy ); } + + // Getting bindless handle makes the texture immutable, so generate it again because we used glTexParameter* + if ( glConfig2.bindlessTexturesAvailable ) { + image->texture->GenBindlessHandle(); + } } } } @@ -1344,8 +1349,10 @@ image_t *R_AllocImage( const char *name, bool linkIntoHashTable ) image = (image_t*) ri.Hunk_Alloc( sizeof( image_t ), ha_pref::h_low ); *image = {}; + image->texture = new Texture(); glGenTextures( 1, &image->texnum ); + image->texture->textureHandle = image->texnum; tr.images.push_back( image ); @@ -1399,6 +1406,7 @@ image_t *R_CreateImage( const char *name, const byte **pic, int width, int heigh } image->type = GL_TEXTURE_2D; + image->texture->target = GL_TEXTURE_2D; image->width = width; image->height = height; @@ -1431,6 +1439,7 @@ image_t *R_CreateGlyph( const char *name, const byte *pic, int width, int height } image->type = GL_TEXTURE_2D; + image->texture->target = GL_TEXTURE_2D; image->width = width; image->height = height; image->bits = IF_NOPICMIP; @@ -1477,6 +1486,7 @@ image_t *R_CreateCubeImage( const char *name, const byte *pic[ 6 ], int width, i } image->type = GL_TEXTURE_CUBE_MAP; + image->texture->target = GL_TEXTURE_CUBE_MAP; image->width = width; image->height = height; @@ -1514,6 +1524,7 @@ image_t *R_Create3DImage( const char *name, const byte *pic, int width, int heig } image->type = GL_TEXTURE_3D; + image->texture->target = GL_TEXTURE_3D; image->width = width; image->height = height; @@ -3039,8 +3050,14 @@ void R_ShutdownImages() for ( image_t *image : tr.images ) { + if ( image->texture->IsResident() ) { + image->texture->MakeNonResident(); + } + glDeleteTextures( 1, &image->texnum ); + delete image->texture; } + tr.textureManager.FreeTextures(); tr.currenttextures.clear(); diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index ebb1288347..b5a733b93f 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -23,6 +23,7 @@ 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" #include "framework/CvarSystem.h" +#include "Material.h" glconfig_t glConfig; glconfig2_t glConfig2; @@ -81,6 +82,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Cvar::Cvar r_mapOverBrightBits("r_mapOverBrightBits", "default map light color shift", Cvar::NONE, 2); Cvar::Cvar r_forceLegacyOverBrightClamping("r_forceLegacyOverBrightClamping", "clamp over bright of legacy maps (enable multiplied color clamping and normalization)", Cvar::NONE, false); Cvar::Range> r_lightMode("r_lightMode", "lighting mode: 0: fullbright (cheat), 1: vertex light, 2: grid light (cheat), 3: light map", Cvar::NONE, Util::ordinal(lightMode_t::MAP), Util::ordinal(lightMode_t::FULLBRIGHT), Util::ordinal(lightMode_t::MAP)); + Cvar::Cvar r_materialSystem( "r_materialSystem", "Use Material System", Cvar::NONE, false ); cvar_t *r_lightStyles; cvar_t *r_exportTextures; cvar_t *r_heatHaze; @@ -1160,6 +1162,7 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p Cvar::Latch( r_dynamicLightRenderer ); Cvar::Latch( r_dynamicLight ); Cvar::Latch( r_staticLight ); + Cvar::Latch( r_materialSystem ); r_drawworld = Cvar_Get( "r_drawworld", "1", CVAR_CHEAT ); r_portalOnly = Cvar_Get( "r_portalOnly", "0", CVAR_CHEAT ); @@ -1488,6 +1491,8 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p R_DoneFreeType(); + materialSystem.Free(); + // shut down platform specific OpenGL stuff if ( destroyWindow ) { diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 83ec647b54..388f51f3d6 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -31,6 +31,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "botlib/bot_debug.h" #include "tr_public.h" #include "iqm.h" +#include "TextureManager.h" #define GLEW_NO_GLU #include @@ -609,6 +610,7 @@ enum class dynamicLightRenderer_t { LEGACY, TILED }; GLenum type; GLuint texnum; // gl texture binding + Texture *texture; uint16_t width, height, numLayers; // source image uint16_t uploadWidth, uploadHeight; // after power of two and picmip but not including clamp to MAX_TEXTURE_SIZE @@ -1184,6 +1186,14 @@ enum class dynamicLightRenderer_t { LEGACY, TILED }; expression_t deformMagnitudeExp; bool noFog; // used only for shaders that have fog disabled, so we can enable it for individual stages + + bool useMaterialSystem = false; + uint materialPackID = 0; + uint materialID = 0; + bool dynamic = false; + bool colorDynamic = false; + bool texMatricesDynamic = false; + bool texturesDynamic = false; }; enum cullType_t : int @@ -1642,6 +1652,12 @@ enum class dynamicLightRenderer_t { LEGACY, TILED }; uint64_t sort; bool bspSurface; + uint materialsSSBOOffset[ MAX_SHADER_STAGES ]; + bool initialized[ MAX_SHADER_STAGES ]; + uint materialIDs[ MAX_SHADER_STAGES ]; + uint materialPackIDs[ MAX_SHADER_STAGES ]; + bool texturesDynamic[ MAX_SHADER_STAGES ]; + inline int index() const { return int( ( sort & SORT_INDEX_MASK ) ); } @@ -2630,6 +2646,8 @@ enum class dynamicLightRenderer_t { LEGACY, TILED }; world_t *world; + TextureManager textureManager; + const byte *externalVisData; // from RE_SetWorldVisData, shared with CM_Load // Maximum reported is 192, see https://opengl.gpuinfo.org/displaycapability.php?name=GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS @@ -2736,6 +2754,7 @@ enum class dynamicLightRenderer_t { LEGACY, TILED }; drawSurf_t *genericQuad; bool hasSkybox; + bool drawingSky = false; drawSurf_t *skybox; vec3_t sunLight; // from the sky shader for this level @@ -2854,6 +2873,7 @@ enum class dynamicLightRenderer_t { LEGACY, TILED }; extern Cvar::Cvar r_mapOverBrightBits; extern Cvar::Cvar r_forceLegacyOverBrightClamping; extern Cvar::Range> r_lightMode; + extern Cvar::Cvar r_materialSystem; extern cvar_t *r_lightStyles; extern cvar_t *r_exportTextures; extern cvar_t *r_heatHaze; @@ -3032,6 +3052,7 @@ inline bool checkGLErrors() float R_NoiseGet4f( float x, float y, float z, float t ); void R_NoiseInit(); + bool R_MirrorViewBySurface( drawSurf_t* drawSurf ); void R_RenderView( viewParms_t *parms ); void R_RenderPostProcess(); @@ -3125,12 +3146,12 @@ inline bool checkGLErrors() ==================================================================== */ void GL_Bind( image_t *image ); - void GL_BindNearestCubeMap( const vec3_t xyz ); + void GL_BindNearestCubeMap( int unit, const vec3_t xyz ); void GL_Unbind( image_t *image ); - void BindAnimatedImage( textureBundle_t *bundle ); + GLuint64 BindAnimatedImage( int unit, textureBundle_t *bundle ); void GL_TextureFilter( image_t *image, filterType_t filterType ); void GL_BindProgram( shaderProgram_t *program ); - void GL_BindToTMU( int unit, image_t *image ); + GLuint64 GL_BindToTMU( int unit, image_t *image ); void GL_BindNullProgram(); void GL_SetDefaultState(); void GL_SelectTexture( int unit ); @@ -3331,6 +3352,12 @@ inline bool checkGLErrors() uint32_t numIndexes; uint32_t numVertexes; + // Material system stuff for setting up correct SSBO offsets + uint materialPackID = 0; + uint materialID = 0; + uint currentSSBOOffset = 0; + drawSurf_t* currentDrawSurf; + // Must be set by the stage iterator function if needed. These are *not* // automatically cleared by the likes of Tess_End. stageVars_t svars; @@ -3354,6 +3381,7 @@ inline bool checkGLErrors() int multiDrawPrimitives; glIndex_t *multiDrawIndexes[ MAX_MULTIDRAW_PRIMITIVES ]; int multiDrawCounts[ MAX_MULTIDRAW_PRIMITIVES ]; + uint multiDrawOffsets[ MAX_MULTIDRAW_PRIMITIVES ]; // enabled when a skeletal model VBO is used bool vboVertexSkinning; @@ -3410,7 +3438,10 @@ inline bool checkGLErrors() void Tess_DrawArrays( GLenum elementType ); void Tess_CheckOverflow( int verts, int indexes ); + void SetNormalScale( const shaderStage_t* pStage, vec3_t normalScale ); + void SetRgbaGen( const shaderStage_t* pStage, colorGen_t* rgbGen, alphaGen_t* alphaGen ); void Tess_ComputeColor( shaderStage_t *pStage ); + void Tess_ComputeTexMatrices( shaderStage_t* pStage ); void Tess_StageIteratorDebug(); void Tess_StageIteratorColor(); diff --git a/src/engine/renderer/tr_main.cpp b/src/engine/renderer/tr_main.cpp index 061baee517..9494c4035a 100644 --- a/src/engine/renderer/tr_main.cpp +++ b/src/engine/renderer/tr_main.cpp @@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // tr_main.c -- main control flow for each frame #include "tr_local.h" +#include "Material.h" trGlobals_t tr; @@ -834,6 +835,11 @@ static void SetFarClip() vec3_t v; float distance; + if ( glConfig2.materialSystemAvailable ) { + VectorCopy( materialSystem.worldViewBounds[0], tr.viewParms.visBounds[0] ); + VectorCopy( materialSystem.worldViewBounds[1], tr.viewParms.visBounds[1] ); + } + if ( i & 1 ) { v[ 0 ] = tr.viewParms.visBounds[ 0 ][ 0 ]; @@ -1841,7 +1847,7 @@ R_MirrorViewBySurface Returns true if another view has been rendered ======================== */ -static bool R_MirrorViewBySurface(drawSurf_t *drawSurf) +bool R_MirrorViewBySurface(drawSurf_t *drawSurf) { orientation_t surface, camera; screenRect_t surfRect; @@ -2007,6 +2013,20 @@ void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int lightmapNum, i tr.refdef.numDrawSurfs++; + // Portal and sky surfaces are not handled by the material system at all + if ( materialSystem.generatingWorldCommandBuffer && ( shader->isPortal || shader->isSky ) ) { + if ( shader->isSky && std::find( materialSystem.skyShaders.begin(), materialSystem.skyShaders.end(), shader ) + == materialSystem.skyShaders.end() ) { + materialSystem.skyShaders.emplace_back( shader ); + } + + if ( shader->isPortal && std::find( materialSystem.portalSurfacesTmp.begin(), materialSystem.portalSurfacesTmp.end(), drawSurf ) + == materialSystem.portalSurfacesTmp.end() ) { + materialSystem.portalSurfacesTmp.emplace_back( drawSurf ); + } + return; + } + if ( shader->depthShader != nullptr ) { R_AddDrawSurf( surface, shader->depthShader, 0, 0, bspSurface ); } @@ -2024,7 +2044,7 @@ static void R_SortDrawSurfs() int i, sort; // it is possible for some views to not have any surfaces - if ( tr.viewParms.numDrawSurfs < 1 ) + if ( !glConfig2.materialSystemAvailable && tr.viewParms.numDrawSurfs < 1 ) { // we still need to add it for hyperspace cases R_AddDrawViewCmd( false ); @@ -2101,6 +2121,10 @@ static void R_SortDrawSurfs() } } + if ( glConfig2.materialSystemAvailable ) { + materialSystem.AddPortalSurfaces(); + } + // tell renderer backend to render this view R_AddDrawViewCmd( false ); } @@ -2802,7 +2826,6 @@ static void R_DebugGraphics() GL_BindProgram( nullptr ); - GL_SelectTexture( 0 ); GL_Bind( tr.whiteImage ); GL_Cull( cullType_t::CT_FRONT_SIDED ); @@ -2860,7 +2883,13 @@ void R_RenderView( viewParms_t *parms ) // because it requires the decalBits R_CullDecalProjectors(); - R_AddWorldSurfaces(); + if ( glConfig2.materialSystemAvailable && !materialSystem.generatedWorldCommandBuffer ) { + materialSystem.GenerateWorldMaterials(); + } + + if ( !glConfig2.materialSystemAvailable ) { + R_AddWorldSurfaces(); + } R_AddPolygonSurfaces(); diff --git a/src/engine/renderer/tr_public.h b/src/engine/renderer/tr_public.h index cfe4af47ad..770658f217 100644 --- a/src/engine/renderer/tr_public.h +++ b/src/engine/renderer/tr_public.h @@ -85,6 +85,11 @@ struct glconfig2_t bool textureIntegerAvailable; bool textureRGAvailable; bool computeShaderAvailable; + bool bindlessTexturesAvailable; + bool shaderDrawParametersAvailable; + bool SSBOAvailable; + bool multiDrawIndirectAvailable; + bool materialSystemAvailable; bool gpuShader4Available; bool gpuShader5Available; bool textureGatherAvailable; diff --git a/src/engine/renderer/tr_scene.cpp b/src/engine/renderer/tr_scene.cpp index f64ec6d748..f793aee0ac 100644 --- a/src/engine/renderer/tr_scene.cpp +++ b/src/engine/renderer/tr_scene.cpp @@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // tr_scene.c #include "tr_local.h" +#include "Material.h" static int r_firstSceneDrawSurf; static int r_firstSceneInteraction; @@ -625,6 +626,9 @@ void RE_RenderScene( const refdef_t *fd ) VectorCopy( fd->vieworg, parms.pvsOrigin ); Vector4Copy( fd->gradingWeights, parms.gradingWeights ); + // TODO: Add cmds for updating dynamic surfaces and for culling here + materialSystem.frameStart = true; + R_AddClearBufferCmd(); R_AddSetupLightsCmd(); diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index 812d4b645f..11b1fecfe0 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // tr_shade.c #include "tr_local.h" #include "gl_shader.h" +#include "Material.h" /* ================================================================================= @@ -78,6 +79,15 @@ static void GLSL_InitGPUShadersOrError() gl_shaderManager.load( gl_generic2DShader ); gl_shaderManager.load( gl_genericShader ); + // Material system shaders that are always loaded if material system is available + if ( glConfig2.materialSystemAvailable ) { + gl_shaderManager.load( gl_genericShaderMaterial ); + gl_shaderManager.load( gl_lightMappingShaderMaterial ); + gl_shaderManager.load( gl_skyboxShaderMaterial ); + gl_shaderManager.load( gl_fogQuake3ShaderMaterial ); + gl_shaderManager.load( gl_heatHazeShaderMaterial ); + } + // standard light mapping gl_shaderManager.load( gl_lightMappingShader ); @@ -127,6 +137,9 @@ static void GLSL_InitGPUShadersOrError() { // bumped cubemap reflection for abitrary polygons ( EMBM ) gl_shaderManager.load( gl_reflectionShader ); + if ( glConfig2.materialSystemAvailable ) { + gl_shaderManager.load( gl_reflectionShaderMaterial ); + } } // skybox drawing for abitrary polygons @@ -146,6 +159,9 @@ static void GLSL_InitGPUShadersOrError() { // screen post process effect gl_shaderManager.load( gl_screenShader ); + if ( glConfig2.materialSystemAvailable ) { + gl_shaderManager.load( gl_screenShaderMaterial ); + } } // portal process effect @@ -168,6 +184,9 @@ static void GLSL_InitGPUShadersOrError() if ( r_liquidMapping->integer != 0 ) { gl_shaderManager.load( gl_liquidShader ); + if ( glConfig2.materialSystemAvailable ) { + gl_shaderManager.load( gl_liquidShaderMaterial ); + } } /* NOTE: motionblur is enabled by cg_motionblur which is a client cvar @@ -271,17 +290,24 @@ void GLSL_ShutdownGPUShaders() gl_shaderManager.freeAll(); gl_genericShader = nullptr; + gl_genericShaderMaterial = nullptr; gl_lightMappingShader = nullptr; + gl_lightMappingShaderMaterial = nullptr; gl_forwardLightingShader_omniXYZ = nullptr; gl_forwardLightingShader_projXYZ = nullptr; gl_forwardLightingShader_directionalSun = nullptr; gl_shadowFillShader = nullptr; gl_reflectionShader = nullptr; + gl_reflectionShaderMaterial = nullptr; gl_skyboxShader = nullptr; + gl_skyboxShaderMaterial = nullptr; gl_fogQuake3Shader = nullptr; + gl_fogQuake3ShaderMaterial = nullptr; gl_fogGlobalShader = nullptr; gl_heatHazeShader = nullptr; + gl_heatHazeShaderMaterial = nullptr; gl_screenShader = nullptr; + gl_screenShaderMaterial = nullptr; gl_portalShader = nullptr; gl_contrastShader = nullptr; gl_cameraEffectsShader = nullptr; @@ -289,6 +315,7 @@ void GLSL_ShutdownGPUShaders() gl_blurYShader = nullptr; gl_debugShadowMapShader = nullptr; gl_liquidShader = nullptr; + gl_liquidShaderMaterial = nullptr; gl_motionblurShader = nullptr; gl_ssaoShader = nullptr; gl_depthtile1Shader = nullptr; @@ -325,7 +352,9 @@ void Tess_DrawElements() { if ( tess.multiDrawPrimitives ) { - glMultiDrawElements( GL_TRIANGLES, tess.multiDrawCounts, GL_INDEX_TYPE, ( const GLvoid ** ) tess.multiDrawIndexes, tess.multiDrawPrimitives ); + if ( !materialSystem.generatingWorldCommandBuffer ) { + glMultiDrawElements( GL_TRIANGLES, tess.multiDrawCounts, GL_INDEX_TYPE, ( const GLvoid** ) tess.multiDrawIndexes, tess.multiDrawPrimitives ); + } backEnd.pc.c_multiDrawElements++; backEnd.pc.c_multiDrawPrimitives += tess.multiDrawPrimitives; @@ -336,6 +365,10 @@ void Tess_DrawElements() { backEnd.pc.c_multiVboIndexes += tess.multiDrawCounts[ i ]; backEnd.pc.c_indexes += tess.multiDrawCounts[ i ]; + if ( materialSystem.generatingWorldCommandBuffer ) { + materialSystem.AddDrawCommand( tess.materialID, tess.materialPackID, tess.currentSSBOOffset, + ( GLuint ) tess.multiDrawCounts[i], tess.multiDrawOffsets[i] ); + } } } else @@ -346,7 +379,11 @@ void Tess_DrawElements() base = tess.indexBase * sizeof( glIndex_t ); } - glDrawRangeElements( GL_TRIANGLES, 0, tess.numVertexes, tess.numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET( base ) ); + if ( materialSystem.generatingWorldCommandBuffer ) { + materialSystem.AddDrawCommand( tess.materialID, tess.materialPackID, tess.currentSSBOOffset, tess.numIndexes, tess.indexBase ); + } else { + glDrawRangeElements( GL_TRIANGLES, 0, tess.numVertexes, tess.numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET( base ) ); + } backEnd.pc.c_drawElements++; @@ -359,7 +396,11 @@ void Tess_DrawElements() } else { - glDrawElements( GL_TRIANGLES, tess.numIndexes, GL_INDEX_TYPE, tess.indexes ); + if ( materialSystem.generatingWorldCommandBuffer ) { + materialSystem.AddDrawCommand( tess.materialID, tess.materialPackID, tess.currentSSBOOffset, tess.numIndexes, tess.indexBase ); + } else { + glDrawElements( GL_TRIANGLES, tess.numIndexes, GL_INDEX_TYPE, tess.indexes ); + } backEnd.pc.c_drawElements++; @@ -481,7 +522,9 @@ static void DrawTris() gl_genericShader->SetUniform_Time( backEnd.refdef.floatTime - backEnd.currentEntity->e.shaderTime ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( tess.svars.texMatrices[ TB_COLORMAP ] ); gl_genericShader->SetRequiredVertexPointers( vboVertexSprite ); @@ -561,7 +604,7 @@ void Tess_Begin( void ( *stageIteratorFunc )(), } } -static void SetNormalScale( const shaderStage_t *pStage, vec3_t normalScale ) +void SetNormalScale( const shaderStage_t *pStage, vec3_t normalScale ) { float normalIntensity = RB_EvalExpression( &pStage->normalIntensityExp, 1.0 ); @@ -577,7 +620,7 @@ static void SetNormalScale( const shaderStage_t *pStage, vec3_t normalScale ) normalScale[ 2 ] = pStage->normalScale[ 2 ] * r_normalScale->value; } -static void SetRgbaGen( const shaderStage_t *pStage, colorGen_t *rgbGen, alphaGen_t *alphaGen ) +void SetRgbaGen( const shaderStage_t *pStage, colorGen_t *rgbGen, alphaGen_t *alphaGen ) { switch ( pStage->rgbGen ) { @@ -650,8 +693,7 @@ static void Render_generic2D( shaderStage_t *pStage ) gl_generic2DShader->SetUniform_Time( backEnd.refdef.floatTime - backEnd.currentEntity->e.shaderTime ); // bind u_ColorMap - GL_SelectTexture( 0 ); - BindAnimatedImage( &pStage->bundle[ TB_COLORMAP ] ); + gl_generic2DShader->SetUniform_ColorMapBindless( BindAnimatedImage( 0, &pStage->bundle[TB_COLORMAP] ) ); gl_generic2DShader->SetUniform_TextureMatrix( tess.svars.texMatrices[ TB_COLORMAP ] ); if ( glConfig2.depthClampAvailable ) @@ -666,12 +708,15 @@ static void Render_generic2D( shaderStage_t *pStage ) if ( needDepthMap ) { - GL_BindToTMU( 1, tr.currentDepthImage ); + gl_generic2DShader->SetUniform_DepthMapBindless( + GL_BindToTMU( 1, tr.currentDepthImage ) + ); } gl_generic2DShader->SetRequiredVertexPointers( vboVertexSprite ); Tess_DrawElements(); + GL_CheckErrors(); if ( glConfig2.depthClampAvailable ) { @@ -687,6 +732,11 @@ void Render_generic3D( shaderStage_t *pStage ) { GLimp_LogComment( "--- Render_generic3D ---\n" ); + if ( materialSystem.generatingWorldCommandBuffer ) { + Tess_DrawElements(); + return; + } + GL_State( pStage->stateBits ); bool hasDepthFade = pStage->hasDepthFade && !tess.surfaceShader->autoSpriteMode; @@ -748,16 +798,17 @@ void Render_generic3D( shaderStage_t *pStage ) // u_DeformGen gl_genericShader->SetUniform_Time( backEnd.refdef.floatTime - backEnd.currentEntity->e.shaderTime ); - // bind u_ColorMap - GL_SelectTexture( 0 ); - + // bind u_ColorMap= if ( pStage->type == stageType_t::ST_STYLELIGHTMAP ) { - GL_Bind( GetLightMap() ); + // GL_Bind( GetLightMap() ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, GetLightMap() ) + ); } else { - BindAnimatedImage( &pStage->bundle[ TB_COLORMAP ] ); + gl_genericShader->SetUniform_ColorMapBindless( BindAnimatedImage( 0, &pStage->bundle[TB_COLORMAP] ) ); } gl_genericShader->SetUniform_TextureMatrix( tess.svars.texMatrices[ TB_COLORMAP ] ); @@ -769,7 +820,9 @@ void Render_generic3D( shaderStage_t *pStage ) if ( needDepthMap ) { - GL_BindToTMU( 1, tr.currentDepthImage ); + gl_genericShader->SetUniform_DepthMapBindless( + GL_BindToTMU( 1, tr.currentDepthImage ) + ); } gl_genericShader->SetRequiredVertexPointers( vboVertexSprite ); @@ -828,6 +881,11 @@ void Render_lightMapping( shaderStage_t *pStage ) { GLimp_LogComment( "--- Render_lightMapping ---\n" ); + if ( materialSystem.generatingWorldCommandBuffer ) { + Tess_DrawElements(); + return; + } + lightMode_t lightMode = lightMode_t::FULLBRIGHT; deluxeMode_t deluxeMode = deluxeMode_t::NONE; @@ -1011,14 +1069,18 @@ void Render_lightMapping( shaderStage_t *pStage ) gl_lightMappingShader->SetUniformBlock_Lights( tr.dlightUBO ); } else { - GL_BindToTMU( BIND_LIGHTS, tr.dlightImage ); + gl_lightMappingShader->SetUniform_LightsTextureBindless( + GL_BindToTMU( BIND_LIGHTS, tr.dlightImage ) + ); } } // bind u_LightTiles if ( r_dynamicLightRenderer.Get() == Util::ordinal( dynamicLightRenderer_t::TILED ) ) { - GL_BindToTMU( BIND_LIGHTTILES, tr.lighttileRenderImage ); + gl_lightMappingShader->SetUniform_LightTilesIntBindless( + GL_BindToTMU( BIND_LIGHTTILES, tr.lighttileRenderImage ) + ); } } @@ -1054,12 +1116,16 @@ void Render_lightMapping( shaderStage_t *pStage ) // FIXME: if there is both, embedded heightmap in normalmap is used instead of standalone heightmap if ( !pStage->hasHeightMapInNormalMap ) { - GL_BindToTMU( BIND_HEIGHTMAP, pStage->bundle[ TB_HEIGHTMAP ].image[ 0 ] ); + gl_lightMappingShader->SetUniform_HeightMapBindless( + GL_BindToTMU( BIND_HEIGHTMAP, pStage->bundle[TB_HEIGHTMAP].image[0] ) + ); } } // bind u_DiffuseMap - GL_BindToTMU( BIND_DIFFUSEMAP, pStage->bundle[ TB_DIFFUSEMAP ].image[ 0 ] ); + gl_lightMappingShader->SetUniform_DiffuseMapBindless( + GL_BindToTMU( BIND_DIFFUSEMAP, pStage->bundle[TB_DIFFUSEMAP].image[0] ) + ); if ( pStage->type != stageType_t::ST_LIGHTMAP ) { @@ -1069,7 +1135,9 @@ void Render_lightMapping( shaderStage_t *pStage ) // bind u_NormalMap if ( !!r_normalMapping->integer || pStage->hasHeightMapInNormalMap ) { - GL_BindToTMU( BIND_NORMALMAP, pStage->bundle[ TB_NORMALMAP ].image[ 0 ] ); + gl_lightMappingShader->SetUniform_NormalMapBindless( + GL_BindToTMU( BIND_NORMALMAP, pStage->bundle[TB_NORMALMAP].image[0] ) + ); } // bind u_NormalScale @@ -1084,7 +1152,9 @@ void Render_lightMapping( shaderStage_t *pStage ) // bind u_MaterialMap if ( pStage->enableSpecularMapping || pStage->enablePhysicalMapping ) { - GL_BindToTMU( BIND_MATERIALMAP, pStage->bundle[ TB_MATERIALMAP ].image[ 0 ] ); + gl_lightMappingShader->SetUniform_MaterialMapBindless( + GL_BindToTMU( BIND_MATERIALMAP, pStage->bundle[TB_MATERIALMAP].image[0] ) + ); } if ( pStage->enableSpecularMapping ) @@ -1179,10 +1249,14 @@ void Render_lightMapping( shaderStage_t *pStage ) } // bind u_EnvironmentMap0 - GL_BindToTMU( BIND_ENVIRONMENTMAP0, cubeMap0 ); + gl_lightMappingShader->SetUniform_EnvironmentMap0Bindless( + GL_BindToTMU( BIND_ENVIRONMENTMAP0, cubeMap0 ) + ); // bind u_EnvironmentMap1 - GL_BindToTMU( BIND_ENVIRONMENTMAP1, cubeMap1 ); + gl_lightMappingShader->SetUniform_EnvironmentMap1Bindless( + GL_BindToTMU( BIND_ENVIRONMENTMAP1, cubeMap1 ) + ); // bind u_EnvironmentInterpolation gl_lightMappingShader->SetUniform_EnvironmentInterpolation( interpolation ); @@ -1200,15 +1274,29 @@ void Render_lightMapping( shaderStage_t *pStage ) } // bind u_LightMap - GL_BindToTMU( BIND_LIGHTMAP, lightmap ); + if ( !enableGridLighting ) { + gl_lightMappingShader->SetUniform_LightMapBindless( + GL_BindToTMU( BIND_LIGHTMAP, lightmap ) + ); + } else { + gl_lightMappingShader->SetUniform_LightGrid1Bindless( GL_BindToTMU( BIND_LIGHTMAP, lightmap ) ); + } // bind u_DeluxeMap - GL_BindToTMU( BIND_DELUXEMAP, deluxemap ); + if ( !enableGridDeluxeMapping ) { + gl_lightMappingShader->SetUniform_DeluxeMapBindless( + GL_BindToTMU( BIND_DELUXEMAP, deluxemap ) + ); + } else { + gl_lightMappingShader->SetUniform_LightGrid2Bindless( GL_BindToTMU( BIND_DELUXEMAP, deluxemap ) ); + } // bind u_GlowMap if ( !!r_glowMapping->integer ) { - GL_BindToTMU( BIND_GLOWMAP, pStage->bundle[ TB_GLOWMAP ].image[ 0 ] ); + gl_lightMappingShader->SetUniform_GlowMapBindless( + GL_BindToTMU( BIND_GLOWMAP, pStage->bundle[TB_GLOWMAP].image[0] ) + ); } gl_lightMappingShader->SetRequiredVertexPointers(); @@ -1224,6 +1312,10 @@ static void Render_shadowFill( shaderStage_t *pStage ) GLimp_LogComment( "--- Render_shadowFill ---\n" ); + if ( materialSystem.generatingWorldCommandBuffer ) { + return; + } + // remove blend modes stateBits = pStage->stateBits; stateBits &= ~( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ); @@ -1274,12 +1366,16 @@ static void Render_shadowFill( shaderStage_t *pStage ) // bind u_ColorMap if ( ( pStage->stateBits & GLS_ATEST_BITS ) != 0 ) { - GL_BindToTMU( 0, pStage->bundle[ TB_COLORMAP ].image[ 0 ] ); + gl_shadowFillShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, pStage->bundle[TB_COLORMAP].image[0] ) + ); gl_shadowFillShader->SetUniform_TextureMatrix( tess.svars.texMatrices[ TB_COLORMAP ] ); } else { - GL_BindToTMU( 0, tr.whiteImage ); + gl_shadowFillShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); } Tess_DrawElements(); @@ -1341,7 +1437,9 @@ static void Render_forwardLighting_DBS_omni( shaderStage_t *pStage, // FIXME: if there is both, embedded heightmap in normalmap is used instead of standalone heightmap if ( !pStage->hasHeightMapInNormalMap ) { - GL_BindToTMU( 15, pStage->bundle[ TB_HEIGHTMAP ].image[ 0 ] ); + gl_forwardLightingShader_omniXYZ->SetUniform_HeightMapBindless( + GL_BindToTMU( 15, pStage->bundle[TB_HEIGHTMAP].image[0] ) + ); } } @@ -1397,7 +1495,9 @@ static void Render_forwardLighting_DBS_omni( shaderStage_t *pStage, GL_CheckErrors(); // bind u_DiffuseMap - GL_BindToTMU( 0, pStage->bundle[ TB_DIFFUSEMAP ].image[ 0 ] ); + gl_forwardLightingShader_omniXYZ->SetUniform_DiffuseMapBindless( + GL_BindToTMU( 0, pStage->bundle[TB_DIFFUSEMAP].image[0] ) + ); if ( pStage->type != stageType_t::ST_LIGHTMAP ) { @@ -1405,7 +1505,9 @@ static void Render_forwardLighting_DBS_omni( shaderStage_t *pStage, } // bind u_NormalMap - GL_BindToTMU( 1, pStage->bundle[ TB_NORMALMAP ].image[ 0 ] ); + gl_forwardLightingShader_omniXYZ->SetUniform_NormalMapBindless( + GL_BindToTMU( 1, pStage->bundle[TB_NORMALMAP].image[0] ) + ); // bind u_NormalScale if ( pStage->enableNormalMapping ) @@ -1417,7 +1519,9 @@ static void Render_forwardLighting_DBS_omni( shaderStage_t *pStage, } // bind u_MaterialMap - GL_BindToTMU( 2, pStage->bundle[ TB_MATERIALMAP ].image[ 0 ] ); + gl_forwardLightingShader_omniXYZ->SetUniform_MaterialMapBindless( + GL_BindToTMU( 2, pStage->bundle[TB_MATERIALMAP].image[0] ) + ); // FIXME: physical mapping is not implemented. if ( pStage->enableSpecularMapping ) @@ -1429,22 +1533,26 @@ static void Render_forwardLighting_DBS_omni( shaderStage_t *pStage, } // bind u_AttenuationMapXY - GL_SelectTexture( 3 ); - BindAnimatedImage( &attenuationXYStage->bundle[ TB_COLORMAP ] ); + gl_forwardLightingShader_omniXYZ->SetUniform_AttenuationMapXYBindless( + BindAnimatedImage( 3, &attenuationXYStage->bundle[TB_COLORMAP]) ); // bind u_AttenuationMapZ - GL_SelectTexture( 4 ); - BindAnimatedImage( &attenuationZStage->bundle[ TB_COLORMAP ] ); + gl_forwardLightingShader_omniXYZ->SetUniform_AttenuationMapZBindless( + BindAnimatedImage( 4, &attenuationZStage->bundle[TB_COLORMAP] ) ); // bind u_ShadowMap if ( shadowCompare ) { - GL_BindToTMU( 5, tr.shadowCubeFBOImage[ light->shadowLOD ] ); - GL_BindToTMU( 7, tr.shadowClipCubeFBOImage[ light->shadowLOD ] ); + gl_forwardLightingShader_omniXYZ->SetUniform_ShadowMapBindless( + GL_BindToTMU( 5, tr.shadowCubeFBOImage[light->shadowLOD] ) ); + gl_forwardLightingShader_omniXYZ->SetUniform_ShadowClipMapBindless( + GL_BindToTMU( 7, tr.shadowClipCubeFBOImage[light->shadowLOD] ) ); } // bind u_RandomMap - GL_BindToTMU( 6, tr.randomNormalsImage ); + gl_forwardLightingShader_omniXYZ->SetUniform_RandomMapBindless( + GL_BindToTMU( 6, tr.randomNormalsImage ) + ); gl_forwardLightingShader_omniXYZ->SetRequiredVertexPointers(); @@ -1507,7 +1615,9 @@ static void Render_forwardLighting_DBS_proj( shaderStage_t *pStage, // FIXME: if there is both, embedded heightmap in normalmap is used instead of standalone heightmap if ( !pStage->hasHeightMapInNormalMap ) { - GL_BindToTMU( 15, pStage->bundle[ TB_HEIGHTMAP ].image[ 0 ] ); + gl_forwardLightingShader_projXYZ->SetUniform_HeightMapBindless( + GL_BindToTMU( 15, pStage->bundle[TB_HEIGHTMAP].image[0] ) + ); } } @@ -1564,7 +1674,9 @@ static void Render_forwardLighting_DBS_proj( shaderStage_t *pStage, GL_CheckErrors(); // bind u_DiffuseMap - GL_BindToTMU( 0, pStage->bundle[ TB_DIFFUSEMAP ].image[ 0 ] ); + gl_forwardLightingShader_projXYZ->SetUniform_DiffuseMapBindless( + GL_BindToTMU( 0, pStage->bundle[TB_DIFFUSEMAP].image[0] ) + ); if ( pStage->type != stageType_t::ST_LIGHTMAP ) { @@ -1572,7 +1684,9 @@ static void Render_forwardLighting_DBS_proj( shaderStage_t *pStage, } // bind u_NormalMap - GL_BindToTMU( 1, pStage->bundle[ TB_NORMALMAP ].image[ 0 ] ); + gl_forwardLightingShader_projXYZ->SetUniform_NormalMapBindless( + GL_BindToTMU( 1, pStage->bundle[TB_NORMALMAP].image[0] ) + ); // bind u_NormalScale if ( pStage->enableNormalMapping ) @@ -1584,7 +1698,9 @@ static void Render_forwardLighting_DBS_proj( shaderStage_t *pStage, } // bind u_MaterialMap - GL_BindToTMU( 2, pStage->bundle[ TB_MATERIALMAP ].image[ 0 ] ); + gl_forwardLightingShader_projXYZ->SetUniform_MaterialMapBindless( + GL_BindToTMU( 2, pStage->bundle[TB_MATERIALMAP].image[0] ) + ); // FIXME: physical mapping is not implemented. if ( pStage->enableSpecularMapping ) @@ -1596,22 +1712,28 @@ static void Render_forwardLighting_DBS_proj( shaderStage_t *pStage, } // bind u_AttenuationMapXY - GL_SelectTexture( 3 ); - BindAnimatedImage( &attenuationXYStage->bundle[ TB_COLORMAP ] ); + gl_forwardLightingShader_projXYZ->SetUniform_AttenuationMapXYBindless( + BindAnimatedImage( 3, &attenuationXYStage->bundle[TB_COLORMAP] ) ); // bind u_AttenuationMapZ - GL_SelectTexture( 4 ); - BindAnimatedImage( &attenuationZStage->bundle[ TB_COLORMAP ] ); + gl_forwardLightingShader_projXYZ->SetUniform_AttenuationMapZBindless( + BindAnimatedImage( 4, &attenuationZStage->bundle[TB_COLORMAP] ) ); // bind u_ShadowMap if ( shadowCompare ) { - GL_BindToTMU( 5, tr.shadowMapFBOImage[ light->shadowLOD ] ); - GL_BindToTMU( 7, tr.shadowClipMapFBOImage[ light->shadowLOD ] ); + gl_forwardLightingShader_projXYZ->SetUniform_ShadowMap0Bindless( + GL_BindToTMU( 5, tr.shadowMapFBOImage[light->shadowLOD] ) + ); + gl_forwardLightingShader_projXYZ->SetUniform_ShadowClipMap0Bindless( + GL_BindToTMU( 7, tr.shadowClipMapFBOImage[light->shadowLOD] ) + ); } // bind u_RandomMap - GL_BindToTMU( 6, tr.randomNormalsImage ); + gl_forwardLightingShader_projXYZ->SetUniform_RandomMapBindless( + GL_BindToTMU( 6, tr.randomNormalsImage ) + ); gl_forwardLightingShader_projXYZ->SetRequiredVertexPointers(); @@ -1672,7 +1794,9 @@ static void Render_forwardLighting_DBS_directional( shaderStage_t *pStage, trRef // FIXME: if there is both, embedded heightmap in normalmap is used instead of standalone heightmap if ( !pStage->hasHeightMapInNormalMap ) { - GL_BindToTMU( 15, pStage->bundle[ TB_HEIGHTMAP ].image[ 0 ] ); + gl_forwardLightingShader_directionalSun->SetUniform_HeightMapBindless( + GL_BindToTMU( 15, pStage->bundle[TB_HEIGHTMAP].image[0] ) + ); } } @@ -1733,7 +1857,9 @@ static void Render_forwardLighting_DBS_directional( shaderStage_t *pStage, trRef GL_CheckErrors(); // bind u_DiffuseMap - GL_BindToTMU( 0, pStage->bundle[ TB_DIFFUSEMAP ].image[ 0 ] ); + gl_forwardLightingShader_directionalSun->SetUniform_DiffuseMapBindless( + GL_BindToTMU( 0, pStage->bundle[TB_DIFFUSEMAP].image[0] ) + ); if ( pStage->type != stageType_t::ST_LIGHTMAP ) { @@ -1741,7 +1867,9 @@ static void Render_forwardLighting_DBS_directional( shaderStage_t *pStage, trRef } // bind u_NormalMap - GL_BindToTMU( 1, pStage->bundle[ TB_NORMALMAP ].image[ 0 ] ); + gl_forwardLightingShader_directionalSun->SetUniform_NormalMapBindless( + GL_BindToTMU( 1, pStage->bundle[TB_NORMALMAP].image[0] ) + ); // bind u_NormalScale if ( pStage->enableNormalMapping ) @@ -1753,7 +1881,9 @@ static void Render_forwardLighting_DBS_directional( shaderStage_t *pStage, trRef } // bind u_MaterialMap - GL_BindToTMU( 2, pStage->bundle[ TB_MATERIALMAP ].image[ 0 ] ); + gl_forwardLightingShader_directionalSun->SetUniform_MaterialMapBindless( + GL_BindToTMU( 2, pStage->bundle[TB_MATERIALMAP].image[0] ) + ); // FIXME: physical mapping is not implemented. if ( pStage->enableSpecularMapping ) @@ -1766,31 +1896,51 @@ static void Render_forwardLighting_DBS_directional( shaderStage_t *pStage, trRef // bind u_ShadowMap if ( shadowCompare ) { - GL_BindToTMU( 5, tr.sunShadowMapFBOImage[ 0 ] ); - GL_BindToTMU( 10, tr.sunShadowClipMapFBOImage[ 0 ] ); + gl_forwardLightingShader_directionalSun->SetUniform_ShadowMap0Bindless( + GL_BindToTMU( 5, tr.sunShadowMapFBOImage[ 0 ] ) + ); + gl_forwardLightingShader_directionalSun->SetUniform_ShadowClipMap0Bindless( + GL_BindToTMU( 10, tr.sunShadowClipMapFBOImage[ 0 ] ) + ); if ( r_parallelShadowSplits->integer >= 1 ) { - GL_BindToTMU( 6, tr.sunShadowMapFBOImage[ 1 ] ); - GL_BindToTMU( 11, tr.sunShadowClipMapFBOImage[ 1 ] ); + gl_forwardLightingShader_directionalSun->SetUniform_ShadowMap1Bindless( + GL_BindToTMU( 6, tr.sunShadowMapFBOImage[ 1 ] ) + ); + gl_forwardLightingShader_directionalSun->SetUniform_ShadowClipMap1Bindless( + GL_BindToTMU( 11, tr.sunShadowClipMapFBOImage[ 1 ] ) + ); } if ( r_parallelShadowSplits->integer >= 2 ) { - GL_BindToTMU( 7, tr.sunShadowMapFBOImage[ 2 ] ); ; - GL_BindToTMU( 12, tr.sunShadowClipMapFBOImage[ 2 ] ); + gl_forwardLightingShader_directionalSun->SetUniform_ShadowMap2Bindless( + GL_BindToTMU( 7, tr.sunShadowMapFBOImage[ 2 ] ) + ); + gl_forwardLightingShader_directionalSun->SetUniform_ShadowClipMap2Bindless( + GL_BindToTMU( 12, tr.sunShadowClipMapFBOImage[ 2 ] ) + ); } if ( r_parallelShadowSplits->integer >= 3 ) { - GL_BindToTMU( 8, tr.sunShadowMapFBOImage[ 3 ] ); - GL_BindToTMU( 13, tr.sunShadowClipMapFBOImage[ 3 ] ); + gl_forwardLightingShader_directionalSun->SetUniform_ShadowMap3Bindless( + GL_BindToTMU( 8, tr.sunShadowMapFBOImage[ 3 ] ) + ); + gl_forwardLightingShader_directionalSun->SetUniform_ShadowClipMap3Bindless( + GL_BindToTMU( 13, tr.sunShadowClipMapFBOImage[ 3 ] ) + ); } if ( r_parallelShadowSplits->integer >= 4 ) { - GL_BindToTMU( 9, tr.sunShadowMapFBOImage[ 4 ] ); - GL_BindToTMU( 14, tr.sunShadowClipMapFBOImage[ 4 ] ); + gl_forwardLightingShader_directionalSun->SetUniform_ShadowMap4Bindless( + GL_BindToTMU( 9, tr.sunShadowMapFBOImage[ 4 ] ) + ); + gl_forwardLightingShader_directionalSun->SetUniform_ShadowClipMap4Bindless( + GL_BindToTMU( 14, tr.sunShadowClipMapFBOImage[ 4 ] ) + ); } } @@ -1805,6 +1955,11 @@ void Render_reflection_CB( shaderStage_t *pStage ) { GLimp_LogComment( "--- Render_reflection_CB ---\n" ); + if ( materialSystem.generatingWorldCommandBuffer ) { + Tess_DrawElements(); + return; + } + GL_State( pStage->stateBits ); // choose right shader program ---------------------------------- @@ -1836,18 +1991,19 @@ void Render_reflection_CB( shaderStage_t *pStage ) } // bind u_ColorMap - GL_SelectTexture( 0 ); if ( backEnd.currentEntity && ( backEnd.currentEntity != &tr.worldEntity ) ) { - GL_BindNearestCubeMap( backEnd.currentEntity->e.origin ); + GL_BindNearestCubeMap( 0, backEnd.currentEntity->e.origin ); } else { - GL_BindNearestCubeMap( backEnd.viewParms.orientation.origin ); + GL_BindNearestCubeMap( 0, backEnd.viewParms.orientation.origin ); } // bind u_NormalMap - GL_BindToTMU( 1, pStage->bundle[ TB_NORMALMAP ].image[ 0 ] ); + gl_reflectionShader->SetUniform_NormalMapBindless( + GL_BindToTMU( 1, pStage->bundle[TB_NORMALMAP].image[0] ) + ); // bind u_NormalScale if ( pStage->enableNormalMapping ) @@ -1872,7 +2028,9 @@ void Render_reflection_CB( shaderStage_t *pStage ) // FIXME: if there is both, embedded heightmap in normalmap is used instead of standalone heightmap if ( !pStage->hasHeightMapInNormalMap ) { - GL_BindToTMU( 15, pStage->bundle[ TB_HEIGHTMAP ].image[ 0 ] ); + gl_reflectionShader->SetUniform_HeightMapBindless( + GL_BindToTMU( 15, pStage->bundle[TB_HEIGHTMAP].image[0] ) + ); } } @@ -1887,6 +2045,11 @@ void Render_skybox( shaderStage_t *pStage ) { GLimp_LogComment( "--- Render_skybox ---\n" ); + if ( materialSystem.generatingWorldCommandBuffer ) { + Tess_DrawElements(); + return; + } + GL_State( pStage->stateBits ); gl_skyboxShader->BindProgram( pStage->deformIndex ); @@ -1897,7 +2060,9 @@ void Render_skybox( shaderStage_t *pStage ) gl_skyboxShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); // bind u_ColorMap - GL_BindToTMU( 0, pStage->bundle[ TB_COLORMAP ].image[ 0 ] ); + gl_skyboxShader->SetUniform_ColorMapCubeBindless( + GL_BindToTMU( 0, pStage->bundle[TB_COLORMAP].image[0] ) + ); // u_AlphaThreshold gl_skyboxShader->SetUniform_AlphaTest( GLS_ATEST_NONE ); @@ -1916,6 +2081,11 @@ void Render_screen( shaderStage_t *pStage ) { GLimp_LogComment( "--- Render_screen ---\n" ); + if ( materialSystem.generatingWorldCommandBuffer ) { + Tess_DrawElements(); + return; + } + GL_State( pStage->stateBits ); gl_screenShader->BindProgram( pStage->deformIndex ); @@ -1928,8 +2098,7 @@ void Render_screen( shaderStage_t *pStage ) gl_screenShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); // bind u_CurrentMap - GL_SelectTexture( 0 ); - BindAnimatedImage( &pStage->bundle[ TB_COLORMAP ] ); + gl_screenShader->SetUniform_CurrentMapBindless( BindAnimatedImage( 0, &pStage->bundle[TB_COLORMAP] ) ); Tess_DrawElements(); @@ -1956,8 +2125,7 @@ void Render_portal( shaderStage_t *pStage ) gl_portalShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); // bind u_CurrentMap - GL_SelectTexture( 0 ); - BindAnimatedImage( &pStage->bundle[ TB_COLORMAP ] ); + gl_portalShader->SetUniform_CurrentMapBindless( BindAnimatedImage( 0, &pStage->bundle[TB_COLORMAP] ) ); Tess_DrawElements(); @@ -1971,6 +2139,11 @@ void Render_heatHaze( shaderStage_t *pStage ) GLimp_LogComment( "--- Render_heatHaze ---\n" ); + // Skip this until heatHaze is working with material system + if ( materialSystem.generatingWorldCommandBuffer ) { + return; + } + // remove alpha test stateBits = pStage->stateBits; stateBits &= ~GLS_ATEST_BITS; @@ -2025,7 +2198,9 @@ void Render_heatHaze( shaderStage_t *pStage ) R_BindFBO( tr.mainFBO[ 1 - backEnd.currentMainFBO ] ); // bind u_NormalMap - GL_BindToTMU( 0, pStage->bundle[ TB_NORMALMAP ].image[ 0 ] ); + gl_heatHazeShader->SetUniform_NormalMapBindless( + GL_BindToTMU( 0, pStage->bundle[TB_NORMALMAP].image[0] ) + ); if ( pStage->enableNormalMapping ) { @@ -2039,7 +2214,9 @@ void Render_heatHaze( shaderStage_t *pStage ) } // bind u_CurrentMap - GL_BindToTMU( 1, tr.currentRenderImage[ backEnd.currentMainFBO ] ); + gl_heatHazeShader->SetUniform_CurrentMapBindless( + GL_BindToTMU( 1, tr.currentRenderImage[backEnd.currentMainFBO] ) + ); gl_heatHazeShader->SetRequiredVertexPointers( vboVertexSprite ); @@ -2047,7 +2224,9 @@ void Render_heatHaze( shaderStage_t *pStage ) // copy to foreground image R_BindFBO( tr.mainFBO[ backEnd.currentMainFBO ] ); - GL_BindToTMU( 1, tr.currentRenderImage[ 1 - backEnd.currentMainFBO ] ); + gl_heatHazeShader->SetUniform_CurrentMapBindless( + GL_BindToTMU( 1, tr.currentRenderImage[1 - backEnd.currentMainFBO] ) + ); gl_heatHazeShader->SetUniform_DeformMagnitude( 0.0f ); Tess_DrawElements(); @@ -2062,6 +2241,11 @@ void Render_liquid( shaderStage_t *pStage ) GLimp_LogComment( "--- Render_liquid ---\n" ); + if ( materialSystem.generatingWorldCommandBuffer ) { + Tess_DrawElements(); + return; + } + // Tr3B: don't allow blend effects GL_State( pStage->stateBits & ~( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS | GLS_DEPTHMASK_TRUE ) ); @@ -2102,13 +2286,13 @@ void Render_liquid( shaderStage_t *pStage ) } // bind u_CurrentMap - GL_BindToTMU( 0, tr.currentRenderImage[ backEnd.currentMainFBO ] ); + gl_liquidShader->SetUniform_CurrentMapBindless( GL_BindToTMU( 0, tr.currentRenderImage[backEnd.currentMainFBO] ) ); // bind u_PortalMap - GL_BindToTMU( 1, tr.portalRenderImage ); + gl_liquidShader->SetUniform_PortalMapBindless( GL_BindToTMU( 1, tr.portalRenderImage ) ); // depth texture - GL_BindToTMU( 2, tr.currentDepthImage ); + gl_liquidShader->SetUniform_DepthMapBindless( GL_BindToTMU( 2, tr.currentDepthImage ) ); // bind u_HeightMap u_depthScale u_reliefOffsetBias if ( pStage->enableReliefMapping ) @@ -2122,12 +2306,12 @@ void Render_liquid( shaderStage_t *pStage ) // FIXME: if there is both, embedded heightmap in normalmap is used instead of standalone heightmap if ( !pStage->hasHeightMapInNormalMap ) { - GL_BindToTMU( 15, pStage->bundle[ TB_HEIGHTMAP ].image[ 0 ] ); + gl_liquidShader->SetUniform_HeightMapBindless( GL_BindToTMU( 15, pStage->bundle[TB_HEIGHTMAP].image[0] ) ); } } // bind u_NormalMap - GL_BindToTMU( 3, pStage->bundle[ TB_NORMALMAP ].image[ 0 ] ); + gl_liquidShader->SetUniform_NormalMapBindless( GL_BindToTMU( 3, pStage->bundle[TB_NORMALMAP].image[0] ) ); // bind u_NormalScale if ( pStage->enableNormalMapping ) @@ -2257,7 +2441,9 @@ static void Render_fog() gl_fogQuake3Shader->SetUniform_Time( backEnd.refdef.floatTime - backEnd.currentEntity->e.shaderTime ); // bind u_ColorMap - GL_BindToTMU( 0, tr.fogImage ); + gl_fogQuake3Shader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.fogImage ) + ); gl_fogQuake3Shader->SetRequiredVertexPointers(); @@ -2508,7 +2694,7 @@ void Tess_ComputeColor( shaderStage_t *pStage ) Tess_ComputeTexMatrices =============== */ -static void Tess_ComputeTexMatrices( shaderStage_t *pStage ) +void Tess_ComputeTexMatrices( shaderStage_t *pStage ) { GLimp_LogComment( "--- Tess_ComputeTexMatrices ---\n" ); @@ -2577,9 +2763,10 @@ void Tess_StageIteratorColor() } // call shader function + uint stage = 0; for ( shaderStage_t *pStage = tess.surfaceStages; pStage < tess.surfaceLastStage; pStage++ ) { - if ( !RB_EvalExpression( &pStage->ifExp, 1.0 ) ) + if ( !RB_EvalExpression( &pStage->ifExp, 1.0 ) && !( materialSystem.generatingWorldCommandBuffer && pStage->useMaterialSystem ) ) { continue; } @@ -2587,7 +2774,15 @@ void Tess_StageIteratorColor() Tess_ComputeColor( pStage ); Tess_ComputeTexMatrices( pStage ); + if ( materialSystem.generatingWorldCommandBuffer && pStage->useMaterialSystem ) { + tess.currentSSBOOffset = tess.currentDrawSurf->materialsSSBOOffset[stage]; + tess.materialID = tess.currentDrawSurf->materialIDs[stage]; + tess.materialPackID = tess.currentDrawSurf->materialPackIDs[stage]; + } + pStage->colorRenderer( pStage ); + + stage++; } if ( !r_noFog->integer && tess.fogNum >= 1 && tess.surfaceShader->fogPass != fogPass_t::FP_NONE ) @@ -2806,7 +3001,7 @@ Render tesselated data */ void Tess_End() { - if ( ( tess.numIndexes == 0 || tess.numVertexes == 0 ) && tess.multiDrawPrimitives == 0 ) + if ( ( tess.numIndexes == 0 || tess.numVertexes == 0 ) && tess.multiDrawPrimitives == 0 && !tr.drawingSky ) { return; } diff --git a/src/engine/renderer/tr_sky.cpp b/src/engine/renderer/tr_sky.cpp index 01d97d4c9f..b98a05cbfb 100644 --- a/src/engine/renderer/tr_sky.cpp +++ b/src/engine/renderer/tr_sky.cpp @@ -26,19 +26,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA //====================================================================================== -static void Tess_ComputeTexMatrices( shaderStage_t* pStage ) { - int i; - vec_t* matrix; - - GLimp_LogComment( "--- Tess_ComputeTexMatrices ---\n" ); - - for ( i = 0; i < MAX_TEXTURE_BUNDLES; i++ ) { - matrix = tess.svars.texMatrices[i]; - - RB_CalcTexMatrix( &pStage->bundle[i], matrix ); - } -} - /* ================ Tess_StageIteratorSky @@ -60,6 +47,8 @@ void Tess_StageIteratorSky() tess.numVertexes, tess.numIndexes / 3 ) ); } + tr.drawingSky = false; + if ( r_fastsky->integer ) { return; @@ -126,7 +115,9 @@ void Tess_StageIteratorSky() GL_State( GLS_DEFAULT ); // bind u_ColorMap - GL_BindToTMU( 0, tess.surfaceShader->sky.outerbox ); + gl_skyboxShader->SetUniform_ColorMapCubeBindless( + GL_BindToTMU( 0, tess.surfaceShader->sky.outerbox ) + ); // Only render the outer skybox at this stage gl_skyboxShader->SetUniform_UseCloudMap( false ); @@ -151,7 +142,9 @@ void Tess_StageIteratorSky() gl_skyboxShader->SetUniform_TextureMatrix( tess.svars.texMatrices[TB_COLORMAP] ); - GL_BindToTMU( 1, pStage->bundle[TB_COLORMAP].image[0] ); + gl_skyboxShader->SetUniform_CloudMapBindless( + GL_BindToTMU( 1, pStage->bundle[TB_COLORMAP].image[0] ) + ); // u_AlphaThreshold gl_skyboxShader->SetUniform_AlphaTest( pStage->stateBits ); diff --git a/src/engine/renderer/tr_surface.cpp b/src/engine/renderer/tr_surface.cpp index e934de7152..c2af5df58a 100644 --- a/src/engine/renderer/tr_surface.cpp +++ b/src/engine/renderer/tr_surface.cpp @@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // tr_surface.c #include "tr_local.h" #include "gl_shader.h" +#include "Material.h" /* ============================================================================== @@ -207,11 +208,13 @@ static bool Tess_SurfaceVBO( VBO_t *vbo, IBO_t *ibo, int numIndexes, int firstIn else if ( mergeBack ) { tess.multiDrawIndexes[ tess.multiDrawPrimitives - 1 ] = firstIndexOffset; + tess.multiDrawOffsets[ tess.multiDrawPrimitives - 1 ] = (GLuint) firstIndex; tess.multiDrawCounts[ tess.multiDrawPrimitives - 1 ] += numIndexes; } else { tess.multiDrawIndexes[ tess.multiDrawPrimitives ] = firstIndexOffset; + tess.multiDrawOffsets[ tess.multiDrawPrimitives ] = (GLuint) firstIndex; tess.multiDrawCounts[ tess.multiDrawPrimitives ] = numIndexes; tess.multiDrawPrimitives++; diff --git a/src/engine/renderer/tr_vbo.cpp b/src/engine/renderer/tr_vbo.cpp index fec34a85b5..f085f8dc8c 100644 --- a/src/engine/renderer/tr_vbo.cpp +++ b/src/engine/renderer/tr_vbo.cpp @@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // tr_vbo.c #include "tr_local.h" +#include "Material.h" // "templates" for VBO vertex data layouts @@ -1029,6 +1030,13 @@ static void R_InitLightUBO() } } +static void R_InitMaterialBuffers() { + if( glConfig2.materialSystemAvailable ) { + materialsSSBO.GenBuffer(); + commandBuffer.GenBuffer(); + } +} + /* ============ R_InitVBOs @@ -1076,6 +1084,8 @@ void R_InitVBOs() R_InitLightUBO(); + R_InitMaterialBuffers(); + GL_CheckErrors(); } @@ -1144,6 +1154,11 @@ void R_ShutdownVBOs() tr.dlightUBO = 0; } + if ( glConfig2.materialSystemAvailable ) { + materialsSSBO.DelBuffer(); + commandBuffer.DelBuffer(); + } + tess.verts = tess.vertsBuffer = nullptr; tess.indexes = tess.indexesBuffer = nullptr; } diff --git a/src/engine/renderer/tr_world.cpp b/src/engine/renderer/tr_world.cpp index 2698ef71a7..79860210d7 100644 --- a/src/engine/renderer/tr_world.cpp +++ b/src/engine/renderer/tr_world.cpp @@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "tr_local.h" #include "gl_shader.h" +#include "Material.h" static Cvar::Modified> r_showCluster( "r_showCluster", "print PVS cluster at current location", Cvar::CHEAT, false ); @@ -435,7 +436,7 @@ static void R_RecursiveWorldNode( bspNode_t *node, int planeBits, int decalBits do { // if the node wasn't marked as potentially visible, exit - if ( node->visCounts[ tr.visIndex ] != tr.visCounts[ tr.visIndex ] ) + if ( node->visCounts[ tr.visIndex ] != tr.visCounts[ tr.visIndex ] && !materialSystem.generatingWorldCommandBuffer ) { return; } diff --git a/src/engine/sys/sdl_glimp.cpp b/src/engine/sys/sdl_glimp.cpp index 8a82d24d2d..7203c6b9bb 100644 --- a/src/engine/sys/sdl_glimp.cpp +++ b/src/engine/sys/sdl_glimp.cpp @@ -54,6 +54,12 @@ static Cvar::Cvar r_availableModes( "r_availableModes", "list of available resolutions", Cvar::ROM, ""); // OpenGL extension cvars. +/* Driver bug: Mesa versions > 24.0.9 produce garbage rendering when r_arb_bindless_texture is enabled, +and the shader compiler crashes with material shaders +24.0.9 is the latest known working version, 24.1.1 is the earliest known broken version +So this defaults to disabled */ +static Cvar::Cvar r_arb_bindless_texture( "r_arb_bindless_texture", + "Use GL_ARB_bindless_texture if available", Cvar::NONE, false ); static Cvar::Cvar r_arb_buffer_storage( "r_arb_buffer_storage", "Use GL_ARB_buffer_storage if available", Cvar::NONE, true ); static Cvar::Cvar r_arb_compute_shader( "r_arb_compute_shader", @@ -66,6 +72,12 @@ static Cvar::Cvar r_arb_gpu_shader5( "r_arb_gpu_shader5", "Use GL_ARB_gpu_shader5 if available", Cvar::NONE, true ); static Cvar::Cvar r_arb_map_buffer_range( "r_arb_map_buffer_range", "Use GL_ARB_map_buffer_range if available", Cvar::NONE, true ); +static Cvar::Cvar r_arb_multi_draw_indirect( "r_arb_multi_draw_indirect", + "Use GL_ARB_multi_draw_indirect if available", Cvar::NONE, true ); +static Cvar::Cvar r_arb_shader_draw_parameters( "r_arb_shader_draw_parameters", + "Use GL_ARB_shader_draw_parameters if available", Cvar::NONE, true ); +static Cvar::Cvar r_arb_shader_storage_buffer_object( "r_arb_shader_storage_buffer_object", + "Use GL_ARB_shader_storage_buffer_object if available", Cvar::NONE, true ); static Cvar::Cvar r_arb_sync( "r_arb_sync", "Use GL_ARB_sync if available", Cvar::NONE, true ); static Cvar::Cvar r_arb_texture_gather( "r_arb_texture_gather", @@ -1782,12 +1794,16 @@ static void GLimp_InitExtensions() { logger.Notice("Initializing OpenGL extensions" ); + Cvar::Latch( r_arb_bindless_texture ); Cvar::Latch( r_arb_buffer_storage ); Cvar::Latch( r_arb_compute_shader ); Cvar::Latch( r_arb_debug_output ); Cvar::Latch( r_arb_depth_clamp ); Cvar::Latch( r_arb_gpu_shader5 ); Cvar::Latch( r_arb_map_buffer_range ); + Cvar::Latch( r_arb_multi_draw_indirect ); + Cvar::Latch( r_arb_shader_draw_parameters ); + Cvar::Latch( r_arb_shader_storage_buffer_object ); Cvar::Latch( r_arb_sync ); Cvar::Latch( r_arb_texture_gather ); Cvar::Latch( r_arb_uniform_buffer_object ); @@ -2011,6 +2027,60 @@ static void GLimp_InitExtensions() // made required in OpenGL 4.3 glConfig2.computeShaderAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_compute_shader, r_arb_compute_shader.Get() ); + // Some of the mesa 24.x driver versions have a bug in their shader compiler related to bindless textures, + // which results in either glitches or the shader compiler crashing (when material system is enabled) + { + bool foundMesa241 = false; + std::string mesaVersion = ""; + + static const std::vector>> versions = { + { "1.0", { "1.0-devel", "1.0-rc1", "1.0-rc2", "1.0-rc3", "1.0-rc4", "1.0", } }, + { "1.", { "1.1", "1.2", "1.3", "1.4", } }, + { "2.0", { "2.0-devel", "2.0-rc1", } }, + }; + + for ( auto& vp : versions ) { + mesaVersion = Str::Format( "Mesa 24.%s", vp.first ); + + if ( Q_stristr( glConfig.version_string, mesaVersion.c_str() ) ) { + for ( auto& v : vp.second ) { + mesaVersion = Str::Format( "Mesa 24.%s", v ); + + if ( Q_stristr( glConfig.version_string, mesaVersion.c_str() ) ) { + foundMesa241 = true; + break; + } + } + + break; + } + } + + if ( foundMesa241 ) { + logger.Warn( "...found buggy %s driver, ARB_bindless_texture disabled", mesaVersion ); + } + + // not required by any OpenGL version + glConfig2.bindlessTexturesAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_bindless_texture, r_arb_bindless_texture.Get() && !foundMesa241 ); + } + + // made required in OpenGL 4.6 + glConfig2.shaderDrawParametersAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_shader_draw_parameters, r_arb_shader_draw_parameters.Get() ); + + // made required in OpenGL 4.3 + glConfig2.SSBOAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_shader_storage_buffer_object, r_arb_shader_storage_buffer_object.Get() ); + + // made required in OpenGL 4.0 + glConfig2.multiDrawIndirectAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_multi_draw_indirect, r_arb_multi_draw_indirect.Get() ); + + glConfig2.materialSystemAvailable = glConfig2.shaderDrawParametersAvailable && glConfig2.SSBOAvailable && + glConfig2.multiDrawIndirectAvailable && glConfig2.bindlessTexturesAvailable + && r_smp->integer == 0 // Currently doesn't work with r_smp 1 + && r_materialSystem.Get(); // Allow disabling it without disabling any extensions + if ( r_materialSystem.Get() && r_smp->integer ) { + Log::Warn( "Material system disabled because r_smp is not 0" ); + } + GL_CheckErrors(); }