diff --git a/src/gl/dynlights/gl_lightbuffer.h b/src/gl/dynlights/gl_lightbuffer.h index 8781ccb57c..49fc87cd9f 100644 --- a/src/gl/dynlights/gl_lightbuffer.h +++ b/src/gl/dynlights/gl_lightbuffer.h @@ -2,7 +2,7 @@ #define __GL_LIGHTBUFFER_H #include "tarray.h" -struct FDynLightData; +#include "hwrenderer/dynlights/hw_dynlightdata.h" class FLightBuffer { @@ -35,5 +35,9 @@ public: int GetIndex(int i) const { return mIndices[i]; } }; +int gl_SetDynModelLight(AActor *self, int dynlightindex); + +extern thread_local FDynLightData lightdata; + #endif diff --git a/src/gl/renderer/gl_renderstate.h b/src/gl/renderer/gl_renderstate.h index 7444e849ec..0903362352 100644 --- a/src/gl/renderer/gl_renderstate.h +++ b/src/gl/renderer/gl_renderstate.h @@ -535,7 +535,7 @@ public: void SetPlaneTextureRotation(GLSectorPlane *plane, FMaterial *texture) { - if (gl_SetPlaneTextureRotation(plane, texture, mTextureMatrix)) + if (hw_SetPlaneTextureRotation(plane, texture, mTextureMatrix)) { EnableTextureMatrix(true); } diff --git a/src/gl/scene/gl_flats.cpp b/src/gl/scene/gl_flats.cpp index 5ceee553b3..8befbfb799 100644 --- a/src/gl/scene/gl_flats.cpp +++ b/src/gl/scene/gl_flats.cpp @@ -53,7 +53,6 @@ // Flats // //========================================================================== -extern FDynLightData lightdata; void FDrawInfo::SetupSubsectorLights(GLFlat *flat, int pass, subsector_t * sub, int *dli) { @@ -63,7 +62,7 @@ void FDrawInfo::SetupSubsectorLights(GLFlat *flat, int pass, subsector_t * sub, (*dli)++; return; } - if (flat->SetupSubsectorLights(pass, sub)) + if (flat->SetupSubsectorLights(pass, sub, lightdata)) { int d = GLRenderer->mLights->UploadLights(lightdata); if (pass == GLPASS_LIGHTSONLY) diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index 380b50f144..042f4817bf 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -42,6 +42,7 @@ #include "gl/system/gl_interface.h" #include "hwrenderer/utility/hw_cvars.h" +#include "hwrenderer/scene/hw_drawstructs.h" #include "gl/renderer/gl_lightdata.h" #include "gl/renderer/gl_renderstate.h" #include "gl/renderer/gl_renderer.h" @@ -49,6 +50,7 @@ #include "gl/scene/gl_scenedrawer.h" #include "gl/models/gl_models.h" #include "gl/renderer/gl_quaddrawer.h" +#include "gl/dynlights/gl_lightbuffer.h" extern uint32_t r_renderercaps; @@ -62,6 +64,36 @@ void gl_SetRenderStyle(FRenderStyle style, bool drawopaque, bool allowcolorblend gl_RenderState.SetTextureMode(tm); } +int gl_SetDynModelLight(AActor *self, int dynlightindex) +{ + if (gl.legacyMode) + { + float out[3]; + hw_GetDynSpriteLight(self, nullptr, out); + gl_RenderState.SetDynLight(out[0], out[1], out[2]); + return -1; + } + else + { + // For deferred light mode this function gets called twice. First time for list upload, and second for draw. + if (gl.lightmethod == LM_DEFERRED && dynlightindex != -1) + { + gl_RenderState.SetDynLight(0, 0, 0); + return dynlightindex; + } + hw_GetDynModelLight(self, lightdata); + + dynlightindex = GLRenderer->mLights->UploadLights(lightdata); + + if (gl.lightmethod != LM_DEFERRED) + { + gl_RenderState.SetDynLight(0, 0, 0); + } + return dynlightindex; + + } +} + //========================================================================== // // @@ -164,7 +196,11 @@ void FDrawInfo::DrawSprite(GLSprite *sprite, int pass) if (sprite->modelframe && !sprite->particle) sprite->dynlightindex = gl_SetDynModelLight(gl_light_sprites ? sprite->actor : nullptr, sprite->dynlightindex); else - gl_SetDynSpriteLight(gl_light_sprites ? sprite->actor : nullptr, gl_light_particles ? sprite->particle : nullptr); + { + float out[3]; + hw_GetDynSpriteLight(gl_light_sprites ? sprite->actor : nullptr, gl_light_particles ? sprite->particle : nullptr, out); + gl_RenderState.SetDynLight(out[0], out[1], out[2]); + } } sector_t *cursec = sprite->actor ? sprite->actor->Sector : sprite->particle ? sprite->particle->subsector->sector : nullptr; if (cursec != nullptr) diff --git a/src/gl/scene/gl_spritelight.cpp b/src/gl/scene/gl_spritelight.cpp index af58d037eb..864e74a99f 100644 --- a/src/gl/scene/gl_spritelight.cpp +++ b/src/gl/scene/gl_spritelight.cpp @@ -54,13 +54,13 @@ T smoothstep(const T edge0, const T edge1, const T x) // //========================================================================== -void gl_SetDynSpriteLight(AActor *self, float x, float y, float z, subsector_t * subsec) +void hw_GetDynSpriteLight(AActor *self, float x, float y, float z, subsector_t * subsec, float *out) { ADynamicLight *light; float frac, lr, lg, lb; float radius; - float out[3] = { 0.0f, 0.0f, 0.0f }; + out[0] = out[1] = out[2] = 0.f; // Go through both light lists FLightNode * node = subsec->lighthead; while (node) @@ -131,18 +131,17 @@ void gl_SetDynSpriteLight(AActor *self, float x, float y, float z, subsector_t * } node = node->nextLight; } - gl_RenderState.SetDynLight(out[0], out[1], out[2]); } -void gl_SetDynSpriteLight(AActor *thing, particle_t *particle) +void hw_GetDynSpriteLight(AActor *thing, particle_t *particle, float *out) { if (thing != NULL) { - gl_SetDynSpriteLight(thing, thing->X(), thing->Y(), thing->Center(), thing->subsector); + hw_GetDynSpriteLight(thing, thing->X(), thing->Y(), thing->Center(), thing->subsector, out); } else if (particle != NULL) { - gl_SetDynSpriteLight(NULL, particle->Pos.X, particle->Pos.Y, particle->Pos.Z, particle->subsector); + hw_GetDynSpriteLight(NULL, particle->Pos.X, particle->Pos.Y, particle->Pos.Z, particle->subsector, out); } } @@ -189,31 +188,19 @@ void BSPWalkCircle(float x, float y, float radiusSquared, const Callback &callba BSPNodeWalkCircle(level.HeadNode(), x, y, radiusSquared, callback); } -int gl_SetDynModelLight(AActor *self, int dynlightindex) +// static so that we build up a reserve (memory allocations stop) +// For multithread processing each worker thread needs its own copy, though. +static thread_local TArray addedLightsArray; + +void hw_GetDynModelLight(AActor *self, FDynLightData &modellightdata) { - static FDynLightData modellightdata; // If this ever gets multithreaded, this variable must either be made non-static or thread_local. - - // For deferred light mode this function gets called twice. First time for list upload, and second for draw. - if (gl.lightmethod == LM_DEFERRED && dynlightindex != -1) - { - gl_RenderState.SetDynLight(0, 0, 0); - return dynlightindex; - } - - // Legacy render path gets the old flat model light - if (gl.lightmethod == LM_LEGACY) - { - gl_SetDynSpriteLight(self, nullptr); - return -1; - } - modellightdata.Clear(); if (self) { - static std::vector addedLights; // static so that we build up a reserve (memory allocations stop) + auto &addedLights = addedLightsArray; // avoid going through the thread local storage for each use. - addedLights.clear(); + addedLights.Clear(); float x = self->X(); float y = self->Y(); @@ -240,7 +227,7 @@ int gl_SetDynModelLight(AActor *self, int dynlightindex) if (std::find(addedLights.begin(), addedLights.end(), light) == addedLights.end()) // Check if we already added this light from a different subsector { modellightdata.AddLightToList(group, light); - addedLights.push_back(light); + addedLights.Push(light); } } } @@ -248,12 +235,4 @@ int gl_SetDynModelLight(AActor *self, int dynlightindex) } }); } - - dynlightindex = GLRenderer->mLights->UploadLights(modellightdata); - - if (gl.lightmethod != LM_DEFERRED) - { - gl_RenderState.SetDynLight(0, 0, 0); - } - return dynlightindex; } diff --git a/src/gl/scene/gl_wall.h b/src/gl/scene/gl_wall.h index 2562aa612d..9b1d421867 100644 --- a/src/gl/scene/gl_wall.h +++ b/src/gl/scene/gl_wall.h @@ -19,8 +19,5 @@ struct particle_t; // Light + color -void gl_SetDynSpriteLight(AActor *self, float x, float y, float z, subsector_t *subsec); -void gl_SetDynSpriteLight(AActor *actor, particle_t *particle); -int gl_SetDynModelLight(AActor *self, int dynlightindex); #endif diff --git a/src/gl/scene/gl_walls_draw.cpp b/src/gl/scene/gl_walls_draw.cpp index 2e62a17376..ebec1bab93 100644 --- a/src/gl/scene/gl_walls_draw.cpp +++ b/src/gl/scene/gl_walls_draw.cpp @@ -42,8 +42,8 @@ EXTERN_CVAR(Bool, gl_seamless) -FDynLightData lightdata; - +// 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. +thread_local FDynLightData lightdata; //========================================================================== // @@ -489,8 +489,10 @@ void FDrawInfo::DrawDecal(GLDecal *gldecal) { // Note: This should be replaced with proper shader based lighting. double x, y; + float out[3]; decal->GetXY(seg->sidedef, x, y); - gl_SetDynSpriteLight(nullptr, x, y, gldecal->zcenter, wall->sub); + hw_GetDynSpriteLight(nullptr, x, y, gldecal->zcenter, wall->sub, out); + gl_RenderState.SetDynLight(out[0], out[1], out[2]); } // alpha color only has an effect when using an alpha texture. diff --git a/src/gl/scene/gl_weapon.cpp b/src/gl/scene/gl_weapon.cpp index f781aa8c7c..11fcd27349 100644 --- a/src/gl/scene/gl_weapon.cpp +++ b/src/gl/scene/gl_weapon.cpp @@ -44,6 +44,7 @@ #include "gl/models/gl_models.h" #include "gl/renderer/gl_quaddrawer.h" #include "gl/stereo3d/gl_stereo3d.h" +#include "gl/dynlights/gl_lightbuffer.h" EXTERN_CVAR (Bool, r_drawplayersprites) EXTERN_CVAR(Float, transsouls) @@ -449,10 +450,16 @@ void GLSceneDrawer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep) if (gl_lights && GLRenderer->mLightCount && FixedColormap == CM_DEFAULT && gl_light_sprites) { FSpriteModelFrame *smf = playermo->player->ReadyWeapon ? gl_FindModelFrame(playermo->player->ReadyWeapon->GetClass(), psp->GetState()->sprite, psp->GetState()->GetFrame(), false) : nullptr; - if (smf) + if (smf && !gl.legacyMode) + { gl_SetDynModelLight(playermo, weapondynlightindex[psp]); + } else - gl_SetDynSpriteLight(playermo, NULL); + { + float out[3]; + hw_GetDynSpriteLight(playermo, nullptr, out); + gl_RenderState.SetDynLight(out[0], out[1], out[2]); + } } SetColor(ll, 0, cmc, trans, true); } diff --git a/src/hwrenderer/scene/hw_drawstructs.h b/src/hwrenderer/scene/hw_drawstructs.h index 5d6d7779f7..1452bc4300 100644 --- a/src/hwrenderer/scene/hw_drawstructs.h +++ b/src/hwrenderer/scene/hw_drawstructs.h @@ -311,7 +311,7 @@ public: int dynlightindex; - bool SetupSubsectorLights(int pass, subsector_t * sub); + bool SetupSubsectorLights(int pass, subsector_t * sub, FDynLightData &lightdata); void PutFlat(HWDrawInfo *di, bool fog = false); void Process(HWDrawInfo *di, sector_t * model, int whichplane, bool notexture); @@ -431,5 +431,9 @@ inline float Dist2(float x1,float y1,float x2,float y2) return sqrtf((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } -bool gl_SetPlaneTextureRotation(const GLSectorPlane * secplane, FMaterial * gltexture, VSMatrix &mat); +bool hw_SetPlaneTextureRotation(const GLSectorPlane * secplane, FMaterial * gltexture, VSMatrix &mat); +void hw_GetDynSpriteLight(AActor *self, float x, float y, float z, subsector_t *subsec, float *out); +void hw_GetDynSpriteLight(AActor *actor, particle_t *particle, float *out); +void hw_GetDynModelLight(AActor *self, FDynLightData &modellightdata); + extern const float LARGE_VALUE; diff --git a/src/hwrenderer/scene/hw_flats.cpp b/src/hwrenderer/scene/hw_flats.cpp index 5f09c63263..050110c9f1 100644 --- a/src/hwrenderer/scene/hw_flats.cpp +++ b/src/hwrenderer/scene/hw_flats.cpp @@ -54,7 +54,7 @@ CVAR(Int, gl_breaksec, -1, 0) // //========================================================================== -bool gl_SetPlaneTextureRotation(const GLSectorPlane * secplane, FMaterial * gltexture, VSMatrix &dest) +bool hw_SetPlaneTextureRotation(const GLSectorPlane * secplane, FMaterial * gltexture, VSMatrix &dest) { // only manipulate the texture matrix if needed. if (!secplane->Offs.isZero() || @@ -92,9 +92,8 @@ bool gl_SetPlaneTextureRotation(const GLSectorPlane * secplane, FMaterial * glte // Flats // //========================================================================== -extern FDynLightData lightdata; -bool GLFlat::SetupSubsectorLights(int pass, subsector_t * sub) +bool GLFlat::SetupSubsectorLights(int pass, subsector_t * sub, FDynLightData &lightdata) { Plane p;