From f57c804a5afc34a46136b5e2d858c453b8de9975 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 16 Apr 2018 08:42:37 +0200 Subject: [PATCH] store shadow map index in the light actor instead of a separate TMap This frees another file of a direct renderer dependency and generally also should be faster --- src/g_shared/a_dynlight.h | 2 ++ src/gl/dynlights/gl_dynlight1.cpp | 5 ++-- src/gl/dynlights/gl_shadowmap.cpp | 43 +++++++++++++++---------------- src/gl/dynlights/gl_shadowmap.h | 6 ----- 4 files changed, 25 insertions(+), 31 deletions(-) diff --git a/src/g_shared/a_dynlight.h b/src/g_shared/a_dynlight.h index adfaa3a4f0..1498b85eb5 100644 --- a/src/g_shared/a_dynlight.h +++ b/src/g_shared/a_dynlight.h @@ -229,5 +229,7 @@ public: LightFlags lightflags; DAngle SpotInnerAngle = 10.0; DAngle SpotOuterAngle = 25.0; + + int mShadowmapIndex = 1024; }; diff --git a/src/gl/dynlights/gl_dynlight1.cpp b/src/gl/dynlights/gl_dynlight1.cpp index 9c3e40ad01..88e9c2849b 100644 --- a/src/gl/dynlights/gl_dynlight1.cpp +++ b/src/gl/dynlights/gl_dynlight1.cpp @@ -52,7 +52,6 @@ CVAR (Bool, gl_lights_checkside, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); CVAR (Bool, gl_light_sprites, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); CVAR (Bool, gl_light_particles, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); -CVAR (Bool, gl_light_shadowmap, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); CVAR(Int, gl_attenuate, -1, 0); // This is mainly a debug option. @@ -117,10 +116,10 @@ void gl_AddLightToList(int group, ADynamicLight * light, FDynLightData &ldata) i = 1; } - // Store attenuate flag in the sign bit of the float. - float shadowIndex = GLRenderer->mShadowMap.ShadowMapIndex(light) + 1.0f; + float shadowIndex = light->mShadowmapIndex + 1.0f; bool attenuate; + // Store attenuate flag in the sign bit of the float. if (gl_attenuate == -1) attenuate = !!(light->lightflags & LF_ATTENUATE); else attenuate = !!gl_attenuate; diff --git a/src/gl/dynlights/gl_shadowmap.cpp b/src/gl/dynlights/gl_shadowmap.cpp index 9e6ee4c917..40940c26e0 100644 --- a/src/gl/dynlights/gl_shadowmap.cpp +++ b/src/gl/dynlights/gl_shadowmap.cpp @@ -42,12 +42,7 @@ the fragment shader (main.fp) needs to sample from row 20. That is, the V texture coordinate needs to be 20.5/1024. - mLightToShadowmap is a hash map storing which line each ADynamicLight is assigned to. The public - ShadowMapIndex function allows the main rendering to find the index and upload that along with the - normal light data. From there, the main.fp shader can sample from the shadow map texture, which - is currently always bound to texture unit 16. - - The texel row for each light is split into four parts. One for each direction, like a cube texture, + The texel row for each light is split into four parts. One for each direction, like a cube texture, but then only in 2D where this reduces itself to a square. When main.fp samples from the shadow map it first decides in which direction the fragment is (relative to the light), like cubemap sampling does for 3D, but once again just for the 2D case. @@ -97,6 +92,20 @@ CUSTOM_CVAR(Int, gl_shadowmap_quality, 512, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) } } +CUSTOM_CVAR (Bool, gl_light_shadowmap, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (!self) + { + // Unset any residual shadow map indices in the light actors. + TThinkerIterator it(STAT_DLIGHT); + while (auto light = it.Next()) + { + light->mShadowmapIndex = 1024; + } + } +} + + void FShadowMap::Update() { UpdateCycles.Reset(); @@ -152,42 +161,32 @@ bool FShadowMap::IsEnabled() const return gl_light_shadowmap && !!(gl.flags & RFL_SHADER_STORAGE_BUFFER); } -int FShadowMap::ShadowMapIndex(ADynamicLight *light) -{ - if (IsEnabled()) - { - auto val = mLightToShadowmap.CheckKey(light); - if (val != nullptr) return *val; - } - return 1024; -} - void FShadowMap::UploadLights() { if (mLights.Size() != 1024 * 4) mLights.Resize(1024 * 4); int lightindex = 0; - mLightToShadowmap.Clear(mLightToShadowmap.CountUsed() * 2); // To do: allow clearing a TMap while building up a reserve // Todo: this should go through the blockmap in a spiral pattern around the player so that closer lights are preferred. TThinkerIterator it(STAT_DLIGHT); while (auto light = it.Next()) { LightsProcessed++; - if (light->shadowmapped) + if (light->shadowmapped && lightindex < 1024 * 4) { LightsShadowmapped++; - mLightToShadowmap[light] = lightindex >> 2; + light->mShadowmapIndex = lightindex >> 2; mLights[lightindex] = light->X(); mLights[lightindex+1] = light->Y(); mLights[lightindex+2] = light->Z(); mLights[lightindex+3] = light->GetRadius(); lightindex += 4; - - if (lightindex == 1024*4) // Only 1024 lights for now - break; } + else + { + light->mShadowmapIndex = 1024; + } } diff --git a/src/gl/dynlights/gl_shadowmap.h b/src/gl/dynlights/gl_shadowmap.h index eea0c9f4aa..d2081ff2a3 100644 --- a/src/gl/dynlights/gl_shadowmap.h +++ b/src/gl/dynlights/gl_shadowmap.h @@ -20,9 +20,6 @@ public: // Update shadow map texture void Update(); - // Return the assigned shadow map index for a given light - int ShadowMapIndex(ADynamicLight *light); - // Test if a world position is in shadow relative to the specified light and returns false if it is bool ShadowTest(ADynamicLight *light, const DVector3 &pos); @@ -42,9 +39,6 @@ private: // Working buffer for creating the list of lights. Stored here to avoid allocating memory each frame TArray mLights; - // The assigned shadow map index for each light - TMap mLightToShadowmap; - // OpenGL storage buffers for the AABB tree int mNodesBuffer = 0; int mLinesBuffer = 0;