From c30165db0d17bdb5e3e593659149e35d5451aa03 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Apr 2020 19:58:17 +0200 Subject: [PATCH] - removed the remaining dependencies of the shadowmap code on game data. Everything is handled with callbacks now. --- .../hwrenderer/dynlights/hw_aabbtree.cpp | 5 +- .../hwrenderer/dynlights/hw_dynlightdata.cpp | 12 +++- .../hwrenderer/dynlights/hw_shadowmap.cpp | 66 ++----------------- .../hwrenderer/dynlights/hw_shadowmap.h | 26 +++++--- src/rendering/hwrenderer/hw_entrypoint.cpp | 38 +++++++++++ 5 files changed, 71 insertions(+), 76 deletions(-) diff --git a/src/rendering/hwrenderer/dynlights/hw_aabbtree.cpp b/src/rendering/hwrenderer/dynlights/hw_aabbtree.cpp index 61e6da9477..0a8c819009 100644 --- a/src/rendering/hwrenderer/dynlights/hw_aabbtree.cpp +++ b/src/rendering/hwrenderer/dynlights/hw_aabbtree.cpp @@ -20,8 +20,7 @@ //-------------------------------------------------------------------------- // -#include "r_state.h" -#include "g_levellocals.h" +#include #include "hw_aabbtree.h" namespace hwrenderer @@ -82,7 +81,7 @@ double LevelAABBTree::RayTest(const DVector3 &ray_start, const DVector3 &ray_end else if (nodes[node_index].line_index != -1) // isLeaf(node_index) { // We reached a leaf node. Do a ray/line intersection test to see if we hit the line. - hit_fraction = MIN(IntersectRayLine(ray_start, ray_end, nodes[node_index].line_index, raydelta, rayd, raydist2), hit_fraction); + hit_fraction = std::min(IntersectRayLine(ray_start, ray_end, nodes[node_index].line_index, raydelta, rayd, raydist2), hit_fraction); stack_pos--; } else if (stack_pos == 32) diff --git a/src/rendering/hwrenderer/dynlights/hw_dynlightdata.cpp b/src/rendering/hwrenderer/dynlights/hw_dynlightdata.cpp index c7107f8470..82087a8519 100644 --- a/src/rendering/hwrenderer/dynlights/hw_dynlightdata.cpp +++ b/src/rendering/hwrenderer/dynlights/hw_dynlightdata.cpp @@ -28,6 +28,7 @@ #include "actorinlines.h" #include "a_dynlight.h" #include "hw_dynlightdata.h" +#include"hw_cvars.h" #include "hwrenderer/scene/hw_drawstructs.h" // If we want to share the array to avoid constant allocations it needs to be thread local unless it'd be littered with expensive synchronization. @@ -105,10 +106,15 @@ void AddLightToList(FDynLightData &dld, int group, FDynamicLight * light, bool f i = 1; } - float shadowIndex = light->mShadowmapIndex + 1.0f; + float shadowIndex; + if (gl_light_shadowmap) + { + shadowIndex = light->mShadowmapIndex + 1.0f; - // Store attenuate flag in the sign bit of the float. - if (light->IsAttenuated() || forceAttenuate) shadowIndex = -shadowIndex; + // Store attenuate flag in the sign bit of the float. + if (light->IsAttenuated() || forceAttenuate) shadowIndex = -shadowIndex; + } + else shadowIndex = 1025.f; float lightType = 0.0f; float spotInnerAngle = 0.0f; diff --git a/src/rendering/hwrenderer/dynlights/hw_shadowmap.cpp b/src/rendering/hwrenderer/dynlights/hw_shadowmap.cpp index 5510de719d..20b6f53a32 100644 --- a/src/rendering/hwrenderer/dynlights/hw_shadowmap.cpp +++ b/src/rendering/hwrenderer/dynlights/hw_shadowmap.cpp @@ -25,10 +25,6 @@ #include "hw_dynlightdata.h" #include "hwrenderer/data/buffers.h" #include "hwrenderer/data/shaderuniforms.h" -#include "stats.h" -#include "g_levellocals.h" -#include "v_video.h" -#include "a_dynlight.h" #include "hwrenderer/postprocessing/hw_postprocess.h" /* @@ -63,6 +59,8 @@ cycle_t IShadowMap::UpdateCycles; int IShadowMap::LightsProcessed; int IShadowMap::LightsShadowmapped; +CVAR(Bool, gl_light_shadowmap, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) + ADD_STAT(shadowmap) { FString out; @@ -85,68 +83,14 @@ CUSTOM_CVAR(Int, gl_shadowmap_quality, 512, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) } } -CUSTOM_CVAR (Bool, gl_light_shadowmap, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -{ - if (!self) for (auto Level : AllLevels()) - { - auto light = Level->lights; - while (light) - { - light->mShadowmapIndex = 1024; - light = light->next; - } - } -} - bool IShadowMap::ShadowTest(const DVector3 &lpos, const DVector3 &pos) { - if (mAABBTree) + if (mAABBTree && gl_light_shadowmap) return mAABBTree->RayTest(lpos, pos) >= 1.0f; else return true; } -bool IShadowMap::IsEnabled() const -{ - return gl_light_shadowmap && (screen->hwcaps & RFL_SHADER_STORAGE_BUFFER); -} - -void IShadowMap::CollectLights() -{ - if (mLights.Size() != 1024 * 4) mLights.Resize(1024 * 4); - int lightindex = 0; - auto Level = &level; - - // Todo: this should go through the blockmap in a spiral pattern around the player so that closer lights are preferred. - for (auto light = Level->lights; light; light = light->next) - { - LightsProcessed++; - if (light->shadowmapped && light->IsActive() && lightindex < 1024 * 4) - { - LightsShadowmapped++; - - light->mShadowmapIndex = lightindex >> 2; - - mLights[lightindex] = (float)light->X(); - mLights[lightindex+1] = (float)light->Y(); - mLights[lightindex+2] = (float)light->Z(); - mLights[lightindex+3] = light->GetRadius(); - lightindex += 4; - } - else - { - light->mShadowmapIndex = 1024; - } - - } - - for (; lightindex < 1024 * 4; lightindex++) - { - mLights[lightindex] = 0; - } -} - - bool IShadowMap::PerformUpdate() { UpdateCycles.Reset(); @@ -154,7 +98,7 @@ bool IShadowMap::PerformUpdate() LightsProcessed = 0; LightsShadowmapped = 0; - if (IsEnabled()) + if (gl_light_shadowmap && (screen->hwcaps & RFL_SHADER_STORAGE_BUFFER) && CollectLights != nullptr) { UpdateCycles.Clock(); UploadAABBTree(); @@ -166,6 +110,7 @@ bool IShadowMap::PerformUpdate() void IShadowMap::UploadLights() { + mLights.Resize(1024 * 4); CollectLights(); if (mLightList == nullptr) @@ -207,3 +152,4 @@ IShadowMap::~IShadowMap() { Reset(); } + diff --git a/src/rendering/hwrenderer/dynlights/hw_shadowmap.h b/src/rendering/hwrenderer/dynlights/hw_shadowmap.h index 08c44d1cf6..5a65e7620f 100644 --- a/src/rendering/hwrenderer/dynlights/hw_shadowmap.h +++ b/src/rendering/hwrenderer/dynlights/hw_shadowmap.h @@ -5,10 +5,7 @@ #include "stats.h" #include -struct FDynamicLight; -struct level_info_t; class IDataBuffer; -struct FLevelLocals; class IShadowMap { @@ -21,9 +18,6 @@ public: // Test if a world position is in shadow relative to the specified light and returns false if it is bool ShadowTest(const DVector3 &lpos, const DVector3 &pos); - // Returns true if gl_light_shadowmap is enabled and supported by the hardware - bool IsEnabled() const; - static cycle_t UpdateCycles; static int LightsProcessed; static int LightsShadowmapped; @@ -46,13 +40,23 @@ public: mNewTree = true; } -protected: - void CollectLights(); + void SetCollectLights(std::function func) + { + CollectLights = std::move(func); + } + void SetLight(int index, float x, float y, float z, float r) + { + index *= 4; + mLights[index] = x; + mLights[index + 1] = y; + mLights[index + 2] = z; + mLights[index + 3] = r; + } + +protected: // Upload the AABB-tree to the GPU void UploadAABBTree(); - - // Upload light list to the GPU void UploadLights(); // Working buffer for creating the list of lights. Stored here to avoid allocating memory each frame @@ -74,4 +78,6 @@ public: IDataBuffer *mNodesBuffer = nullptr; IDataBuffer *mLinesBuffer = nullptr; + std::function CollectLights = nullptr; + }; diff --git a/src/rendering/hwrenderer/hw_entrypoint.cpp b/src/rendering/hwrenderer/hw_entrypoint.cpp index 70b1d5e05e..abe499df1b 100644 --- a/src/rendering/hwrenderer/hw_entrypoint.cpp +++ b/src/rendering/hwrenderer/hw_entrypoint.cpp @@ -59,6 +59,41 @@ void CleanSWDrawer() swdrawer = nullptr; } +#include "g_levellocals.h" +#include "a_dynlight.h" + + +void CollectLights(FLevelLocals* Level) +{ + IShadowMap* sm = &screen->mShadowMap; + int lightindex = 0; + + // Todo: this should go through the blockmap in a spiral pattern around the player so that closer lights are preferred. + for (auto light = Level->lights; light; light = light->next) + { + IShadowMap::LightsProcessed++; + if (light->shadowmapped && light->IsActive() && lightindex < 1024 * 4) + { + IShadowMap::LightsShadowmapped++; + + light->mShadowmapIndex = lightindex; + sm->SetLight(lightindex, (float)light->X(), (float)light->Y(), (float)light->Z(), light->GetRadius()); + lightindex++; + } + else + { + light->mShadowmapIndex = 1024; + } + + } + + for (; lightindex < 1024; lightindex++) + { + sm->SetLight(lightindex, 0, 0, 0, 0); + } +} + + //----------------------------------------------------------------------------- // // Renders one viewpoint in a scene @@ -75,6 +110,9 @@ sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bou { screen->SetAABBTree(camera->Level->aabbTree); screen->UpdateShadowMap(); + screen->mShadowMap.SetCollectLights([=] { + CollectLights(camera->Level); + }); } // Update the attenuation flag of all light defaults for each viewpoint.