From b3a8dcdbd4f756340049aa7fd34916fda6e27fa4 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 090684985..460332492 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 42f1c27cf..e34642497 100644 --- a/src/gl/dynlights/gl_dynlight1.cpp +++ b/src/gl/dynlights/gl_dynlight1.cpp @@ -54,7 +54,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. @@ -119,10 +118,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 2de62864c..35854bfb6 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_renderbuffers && 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 281936f80..d6e99dfe1 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;