From 7967082e603cb13fe45f14d40bd2f4485bcf4e1c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 1 Aug 2014 20:59:39 +0200 Subject: [PATCH] - use the light buffer to handle dynamic lighting. --- src/gl/dynlights/gl_dynlight1.cpp | 33 ------- src/gl/dynlights/gl_lightbuffer.cpp | 118 +++++++++++++----------- src/gl/dynlights/gl_lightbuffer.h | 20 ++-- src/gl/renderer/gl_renderer.cpp | 4 + src/gl/renderer/gl_renderer.h | 2 + src/gl/renderer/gl_renderstate.cpp | 26 +++--- src/gl/renderer/gl_renderstate.h | 27 ++---- src/gl/scene/gl_flats.cpp | 21 +---- src/gl/scene/gl_scene.cpp | 2 + src/gl/scene/gl_wall.h | 2 +- src/gl/scene/gl_walls_draw.cpp | 12 +-- src/gl/shaders/gl_shader.cpp | 25 +++-- src/gl/shaders/gl_shader.h | 6 +- src/gl/system/gl_interface.cpp | 5 + src/gl/system/gl_interface.h | 1 + wadsrc/static/shaders/glsl/main.fp | 85 +++++++++-------- wadsrc/static/shaders/glsl/shaderdefs.i | 2 +- 17 files changed, 194 insertions(+), 197 deletions(-) diff --git a/src/gl/dynlights/gl_dynlight1.cpp b/src/gl/dynlights/gl_dynlight1.cpp index cee31ee42..c504a33c4 100644 --- a/src/gl/dynlights/gl_dynlight1.cpp +++ b/src/gl/dynlights/gl_dynlight1.cpp @@ -144,36 +144,3 @@ bool gl_GetLight(Plane & p, ADynamicLight * light, bool checkside, bool forceadd } -//========================================================================== -// -// -// -//========================================================================== - -#if 0 -void gl_UploadLights(FDynLightData &data) -{ - ParameterBufferElement *pptr; - int size0 = data.arrays[0].Size()/4; - int size1 = data.arrays[1].Size()/4; - int size2 = data.arrays[2].Size()/4; - - if (size0 + size1 + size2 > 0) - { - int sizetotal = size0 + size1 + size2 + 1; - int index = GLRenderer->mParmBuffer->Reserve(sizetotal, &pptr); - - float parmcnt[] = { index + 1, index + 1 + size0, index + 1 + size0 + size1, index + 1 + size0 + size1 + size2 }; - - memcpy(&pptr[0], parmcnt, 4 * sizeof(float)); - memcpy(&pptr[1], &data.arrays[0][0], 4 * size0*sizeof(float)); - memcpy(&pptr[1 + size0], &data.arrays[1][0], 4 * size1*sizeof(float)); - memcpy(&pptr[1 + size0 + size1], &data.arrays[2][0], 4 * size2*sizeof(float)); - gl_RenderState.SetDynLightIndex(index); - } - else - { - gl_RenderState.SetDynLightIndex(-1); - } -} -#endif diff --git a/src/gl/dynlights/gl_lightbuffer.cpp b/src/gl/dynlights/gl_lightbuffer.cpp index 663631240..b91b0fe55 100644 --- a/src/gl/dynlights/gl_lightbuffer.cpp +++ b/src/gl/dynlights/gl_lightbuffer.cpp @@ -39,93 +39,79 @@ */ #include "gl/system/gl_system.h" +#include "gl/shaders/gl_shader.h" #include "gl/dynlights/gl_lightbuffer.h" #include "gl/dynlights/gl_dynlight.h" #include "gl/system/gl_interface.h" +#include "gl/utility//gl_clock.h" -static const int LIGHTBUF_BINDINGPOINT = 1; +static const int BUFFER_SIZE = 160000; // This means 80000 lights per frame and 160000*16 bytes == 2.56 MB. FLightBuffer::FLightBuffer() { if (gl.flags & RFL_SHADER_STORAGE_BUFFER) { mBufferType = GL_SHADER_STORAGE_BUFFER; - mBufferSize = 80000; // 40000 lights per scene should be plenty. The largest I've ever seen was around 5000. + mBlockAlign = 0; } else { mBufferType = GL_UNIFORM_BUFFER; - mBufferSize = gl.maxuniformblock / 4 - 100; // we need to be a bit careful here so don't use the full buffer size + mBlockSize = 2048;// gl.maxuniformblock / 4 - 100; + mBlockAlign = 1024;// ((mBlockSize * 2) & ~(gl.uniformblockalignment - 1)) / 4; // count in vec4's } - AddBuffer(); + + glGenBuffers(1, &mBufferId); + glBindBuffer(mBufferType, mBufferId); + unsigned int bytesize = BUFFER_SIZE * 4 * sizeof(float); + if (gl.flags & RFL_BUFFER_STORAGE) + { + glBufferStorage(mBufferType, bytesize, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); + void *map = glMapBufferRange(mBufferType, 0, bytesize, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); + mBufferPointer = (float*)map; + glBindBufferBase(mBufferType, LIGHTBUF_BINDINGPOINT, mBufferId); + } + else + { + glBufferData(mBufferType, bytesize, NULL, GL_STREAM_DRAW); + mBufferPointer = NULL; + } + Clear(); + mLastMappedIndex = UINT_MAX; } FLightBuffer::~FLightBuffer() { glBindBuffer(mBufferType, 0); - for (unsigned int i = 0; i < mBufferIds.Size(); i++) - { - glDeleteBuffers(1, &mBufferIds[i]); - } -} - -void FLightBuffer::AddBuffer() -{ - unsigned int id; - glGenBuffers(1, &id); - mBufferIds.Push(id); - glBindBuffer(mBufferType, id); - unsigned int bytesize = mBufferSize * 8 * sizeof(float); - if (gl.flags & RFL_BUFFER_STORAGE) - { - glBufferStorage(mBufferType, bytesize, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); - void *map = glMapBufferRange(mBufferType, 0, bytesize, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); - mBufferPointers.Push((float*)map); - } - else - { - glBufferData(mBufferType, bytesize, NULL, GL_STREAM_DRAW); - } + glDeleteBuffers(1, &mBufferId); } void FLightBuffer::Clear() { - mBufferNum = 0; mIndex = 0; mBufferArray.Clear(); - mBufferStart.Clear(); } -void FLightBuffer::UploadLights(FDynLightData &data, unsigned int &buffernum, unsigned int &bufferindex) +int FLightBuffer::UploadLights(FDynLightData &data) { int size0 = data.arrays[0].Size()/4; int size1 = data.arrays[1].Size()/4; int size2 = data.arrays[2].Size()/4; int totalsize = size0 + size1 + size2 + 1; - if (totalsize == 0) return; + if (totalsize <= 1) return -1; - if (mIndex + totalsize > mBufferSize) + if (mIndex + totalsize > BUFFER_SIZE) { - if (gl.flags & RFL_SHADER_STORAGE_BUFFER) - { - return; // we do not want multiple shader storage blocks. 40000 lights is too much already - } - else - { - mBufferNum++; - mBufferStart.Push(mIndex); - mIndex = 0; - if (mBufferIds.Size() <= mBufferNum) AddBuffer(); - } + return -1; // we ran out of space. All following lights will be ignored } float *copyptr; - if (gl.flags & RFL_BUFFER_STORAGE) + if (mBufferPointer != NULL) { - copyptr = mBufferPointers[mBufferNum] + mIndex * 4; + copyptr = mBufferPointer + mIndex * 4; } else { @@ -133,20 +119,48 @@ void FLightBuffer::UploadLights(FDynLightData &data, unsigned int &buffernum, un copyptr = &mBufferArray[pos]; } - float parmcnt[] = { mIndex + 1, mIndex + 1 + size0, mIndex + 1 + size0 + size1, mIndex + totalsize }; + float parmcnt[] = { 0, size0, size0 + size1, size0 + size1 + size2 }; memcpy(©ptr[0], parmcnt, 4 * sizeof(float)); - memcpy(©ptr[1], &data.arrays[0][0], 4 * size0*sizeof(float)); - memcpy(©ptr[1 + size0], &data.arrays[1][0], 4 * size1*sizeof(float)); - memcpy(©ptr[1 + size0 + size1], &data.arrays[2][0], 4 * size2*sizeof(float)); - buffernum = mBufferNum; - bufferindex = mIndex; + memcpy(©ptr[4], &data.arrays[0][0], 4 * size0*sizeof(float)); + memcpy(©ptr[4 + 4*size0], &data.arrays[1][0], 4 * size1*sizeof(float)); + memcpy(©ptr[4 + 4*(size0 + size1)], &data.arrays[2][0], 4 * size2*sizeof(float)); + + if (mBufferPointer == NULL) // if we can't persistently map the buffer we need to upload it after all lights have been added. + { + glBindBuffer(mBufferType, mBufferId); + glBufferSubData(mBufferType, mIndex, totalsize * 4 * sizeof(float), copyptr); + } + + unsigned int bufferindex = mIndex; mIndex += totalsize; + draw_dlight += (totalsize-1) / 2; + return bufferindex; } void FLightBuffer::Finish() { - //glBindBufferBase(mBufferType, LIGHTBUF_BINDINGPOINT, mBufferIds[0]); + /* + if (!(gl.flags & RFL_BUFFER_STORAGE)) // if we can't persistently map the buffer we need to upload it after all lights have been added. + { + glBindBuffer(mBufferType, mBufferId); + glBufferSubData(mBufferType, 0, mBufferArray.Size() * sizeof(float), &mBufferArray[0]); + } + */ + Clear(); +} + +int FLightBuffer::BindUBO(unsigned int index) +{ + unsigned int offset = (index / mBlockAlign) * mBlockAlign; + + if (offset != mLastMappedIndex) + { + // this will only get called if a uniform buffer is used. For a shader storage buffer we only need to bind the buffer once at the start to all shader programs + mLastMappedIndex = offset; + glBindBufferRange(GL_UNIFORM_BUFFER, LIGHTBUF_BINDINGPOINT, mBufferId, offset*16, mBlockSize*16); // we go from counting vec4's to counting bytes here. + } + return (index - offset); } diff --git a/src/gl/dynlights/gl_lightbuffer.h b/src/gl/dynlights/gl_lightbuffer.h index 57e6bf0c8..8e50555c3 100644 --- a/src/gl/dynlights/gl_lightbuffer.h +++ b/src/gl/dynlights/gl_lightbuffer.h @@ -7,23 +7,25 @@ struct FDynLightData; class FLightBuffer { TArray mBufferArray; - TArray mBufferIds; - TArray mBufferStart; - TArray mBufferPointers; - unsigned int mBufferType; - unsigned int mBufferSize; - unsigned int mIndex; - unsigned int mBufferNum; + unsigned int mBufferId; + float * mBufferPointer; - void AddBuffer(); + unsigned int mBufferType; + unsigned int mIndex; + unsigned int mLastMappedIndex; + unsigned int mBlockAlign; + unsigned int mBlockSize; public: FLightBuffer(); ~FLightBuffer(); void Clear(); - void UploadLights(FDynLightData &data, unsigned int &buffernum, unsigned int &bufferindex); + int UploadLights(FDynLightData &data); void Finish(); + int BindUBO(unsigned int index); + unsigned int GetBlockSize() const { return mBlockSize; } + unsigned int GetBufferType() const { return mBufferType; } }; #endif diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 42773496e..ceb553f86 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -67,6 +67,7 @@ #include "gl/utility/gl_clock.h" #include "gl/utility/gl_templates.h" #include "gl/models/gl_models.h" +#include "gl/dynlights/gl_lightbuffer.h" //=========================================================================== // @@ -97,6 +98,7 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb) gl_spriteindex = 0; mShaderManager = NULL; glpart2 = glpart = mirrortexture = NULL; + mLights = NULL; } void FGLRenderer::Initialize() @@ -108,6 +110,7 @@ void FGLRenderer::Initialize() mVBO = new FFlatVertexBuffer; mSkyVBO = new FSkyVertexBuffer; mModelVBO = new FModelVertexBuffer; + mLights = new FLightBuffer; gl_RenderState.SetVertexBuffer(mVBO); mFBID = 0; SetupLevel(); @@ -124,6 +127,7 @@ FGLRenderer::~FGLRenderer() if (mVBO != NULL) delete mVBO; if (mModelVBO) delete mModelVBO; if (mSkyVBO != NULL) delete mSkyVBO; + if (mLights != NULL) delete mLights; if (glpart2) delete glpart2; if (glpart) delete glpart; if (mirrortexture) delete mirrortexture; diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index a2679f665..15c8a2e16 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -17,6 +17,7 @@ struct pspdef_t; class FShaderManager; class GLPortal; class FGLThreadManager; +class FLightBuffer; enum SectorRenderFlags { @@ -72,6 +73,7 @@ public: FFlatVertexBuffer *mVBO; FSkyVertexBuffer *mSkyVBO; FModelVertexBuffer *mModelVBO; + FLightBuffer *mLights; FGLRenderer(OpenGLFrameBuffer *fb); diff --git a/src/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp index 24492c495..464880895 100644 --- a/src/gl/renderer/gl_renderstate.cpp +++ b/src/gl/renderer/gl_renderstate.cpp @@ -48,6 +48,7 @@ #include "gl/renderer/gl_renderer.h" #include "gl/renderer/gl_renderstate.h" #include "gl/renderer/gl_colormap.h" +#include "gl/dynlights//gl_lightbuffer.h" void gl_SetTextureMode(int type); @@ -68,9 +69,10 @@ TArray gl_MatrixStack; void FRenderState::Reset() { mTextureEnabled = true; - mBrightmapEnabled = mFogEnabled = mGlowEnabled = mLightEnabled = false; + mBrightmapEnabled = mFogEnabled = mGlowEnabled = false; mFogColor.d = -1; mTextureMode = -1; + mLightIndex = -1; mDesaturation = 0; mSrcBlend = GL_SRC_ALPHA; mDstBlend = GL_ONE_MINUS_SRC_ALPHA; @@ -98,7 +100,6 @@ void FRenderState::Reset() bool FRenderState::ApplyShader() { - FShader *activeShader; if (mSpecialEffect > EFF_NONE) { activeShader = GLRenderer->mShaderManager->BindEffect(mSpecialEffect); @@ -139,6 +140,7 @@ bool FRenderState::ApplyShader() activeShader->muClipHeightBottom.Set(mClipHeightBottom); activeShader->muTimer.Set(gl_frameMS * mShaderTimer / 1000.f); activeShader->muAlphaThreshold.Set(mAlphaThreshold); + activeShader->muLightIndex.Set(mLightIndex); // will always be -1 for now if (mGlowEnabled) { @@ -159,17 +161,6 @@ bool FRenderState::ApplyShader() activeShader->currentglowstate = 0; } - if (mLightEnabled) - { - activeShader->muLightRange.Set(mNumLights); - glUniform4fv(activeShader->lights_index, mNumLights[3], mLightData); - } - else - { - static const int nulint[] = { 0, 0, 0, 0 }; - activeShader->muLightRange.Set(nulint); - } - if (mColormapState != activeShader->currentfixedcolormap) { float r, g, b; @@ -282,3 +273,12 @@ void FRenderState::ApplyMatrices() GLRenderer->mShaderManager->ApplyMatrices(&mProjectionMatrix, &mViewMatrix); } } + +void FRenderState::ApplyLightIndex(int index) +{ + if (GLRenderer->mLights->GetBufferType() == GL_UNIFORM_BUFFER && index > -1) + { + index = GLRenderer->mLights->BindUBO(index); + } + activeShader->muLightIndex.Set(index); +} \ No newline at end of file diff --git a/src/gl/renderer/gl_renderstate.h b/src/gl/renderer/gl_renderstate.h index 562cfb0ef..0e290adb3 100644 --- a/src/gl/renderer/gl_renderstate.h +++ b/src/gl/renderer/gl_renderstate.h @@ -9,6 +9,7 @@ #include "r_defs.h" class FVertexBuffer; +class FShader; extern TArray gl_MatrixStack; EXTERN_CVAR(Bool, gl_direct_state_change) @@ -43,24 +44,22 @@ class FRenderState bool mTextureEnabled; bool mFogEnabled; bool mGlowEnabled; - bool mLightEnabled; bool mBrightmapEnabled; + int mLightIndex; int mSpecialEffect; int mTextureMode; int mDesaturation; int mSoftLight; float mLightParms[4]; - int mNumLights[4]; - float *mLightData; int mSrcBlend, mDstBlend; float mAlphaThreshold; - bool mAlphaTest; int mBlendEquation; + bool mAlphaTest; bool m2D; - float mInterpolationFactor; - float mClipHeightTop, mClipHeightBottom; bool mModelMatrixEnabled; bool mTextureMatrixEnabled; + float mInterpolationFactor; + float mClipHeightTop, mClipHeightBottom; float mShaderTimer; FVertexBuffer *mVertexBuffer, *mCurrentVertexBuffer; @@ -80,6 +79,8 @@ class FRenderState bool stAlphaTest; int stBlendEquation; + FShader *activeShader; + bool ApplyShader(); public: @@ -104,6 +105,7 @@ public: void Apply(); void ApplyMatrices(); + void ApplyLightIndex(int index); void SetVertexBuffer(FVertexBuffer *vb) { @@ -185,9 +187,9 @@ public: mGlowEnabled = on; } - void EnableLight(bool on) + void SetLightIndex(int n) { - mLightEnabled = on; + mLightIndex = n; } void EnableBrightmap(bool on) @@ -251,15 +253,6 @@ public: mLightParms[0] = d; } - void SetLights(int *numlights, float *lightdata) - { - mNumLights[0] = 0; - mNumLights[1] = numlights[0]; - mNumLights[2] = numlights[1]; - mNumLights[3] = numlights[2]; - mLightData = lightdata; // caution: the data must be preserved by the caller until the 'apply' call! - } - void SetFixedColormap(int cm) { mColormapState = cm; diff --git a/src/gl/scene/gl_flats.cpp b/src/gl/scene/gl_flats.cpp index 60b1237d5..9e4a8ec6d 100644 --- a/src/gl/scene/gl_flats.cpp +++ b/src/gl/scene/gl_flats.cpp @@ -56,6 +56,7 @@ #include "gl/data/gl_vertexbuffer.h" #include "gl/dynlights/gl_dynlight.h" #include "gl/dynlights/gl_glow.h" +#include "gl/dynlights/gl_lightbuffer.h" #include "gl/scene/gl_drawinfo.h" #include "gl/shaders/gl_shader.h" #include "gl/textures/gl_material.h" @@ -142,22 +143,8 @@ bool GLFlat::SetupSubsectorLights(bool lightsapplied, subsector_t * sub) node = node->nextLight; } - int numlights[3]; - - lightdata.Combine(numlights, gl.MaxLights()); - if (numlights[2] > 0) - { - draw_dlightf+=numlights[2]/2; - gl_RenderState.EnableLight(true); - gl_RenderState.SetLights(numlights, &lightdata.arrays[0][0]); - gl_RenderState.Apply(); - return true; - } - if (lightsapplied) - { - gl_RenderState.EnableLight(false); - gl_RenderState.Apply(); - } + dynlightindex = GLRenderer->mLights->UploadLights(lightdata); + gl_RenderState.ApplyLightIndex(dynlightindex); return false; } @@ -271,7 +258,6 @@ void GLFlat::DrawSubsectors(int pass, bool istrans) } } } - gl_RenderState.EnableLight(false); } @@ -450,6 +436,7 @@ void GLFlat::ProcessSector(sector_t * frontsector) sector=§ors[frontsector->sectornum]; extsector_t::xfloor &x = sector->e->XFloor; this->sub=NULL; + dynlightindex = -1; byte &srf = gl_drawinfo->sectorrenderflags[sector->sectornum]; diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 0a73a06f6..e301b3da6 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -57,6 +57,7 @@ #include "p_local.h" #include "gl/gl_functions.h" +#include "gl/dynlights/gl_lightbuffer.h" #include "gl/system/gl_interface.h" #include "gl/system/gl_framebuffer.h" #include "gl/system/gl_cvars.h" @@ -348,6 +349,7 @@ void FGLRenderer::RenderScene(int recursion) gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f); glDisable(GL_POLYGON_OFFSET_FILL); // just in case + GLRenderer->mLights->Finish(); int pass; diff --git a/src/gl/scene/gl_wall.h b/src/gl/scene/gl_wall.h index e17f61c3e..36d4d2fc3 100644 --- a/src/gl/scene/gl_wall.h +++ b/src/gl/scene/gl_wall.h @@ -135,7 +135,7 @@ public: float topglowcolor[4]; float bottomglowcolor[4]; - unsigned int dynlightindex, dynlightbuffer; + int dynlightindex; int firstwall, numwalls; // splitting info. union diff --git a/src/gl/scene/gl_walls_draw.cpp b/src/gl/scene/gl_walls_draw.cpp index b9965972c..98bc9f661 100644 --- a/src/gl/scene/gl_walls_draw.cpp +++ b/src/gl/scene/gl_walls_draw.cpp @@ -53,6 +53,7 @@ #include "gl/data/gl_vertexbuffer.h" #include "gl/dynlights/gl_dynlight.h" #include "gl/dynlights/gl_glow.h" +#include "gl/dynlights/gl_lightbuffer.h" #include "gl/scene/gl_drawinfo.h" #include "gl/scene/gl_portal.h" #include "gl/shaders/gl_shader.h" @@ -150,15 +151,8 @@ void GLWall::SetupLights() } node = node->nextLight; } - int numlights[3]; - lightdata.Combine(numlights, gl.MaxLights()); - if (numlights[2] > 0) - { - draw_dlight+=numlights[2]/2; - gl_RenderState.EnableLight(true); - gl_RenderState.SetLights(numlights, &lightdata.arrays[0][0]); - } + dynlightindex = GLRenderer->mLights->UploadLights(lightdata); } @@ -187,6 +181,7 @@ void GLWall::RenderWall(int textured, unsigned int *store) if (!(textured & RWF_NORENDER)) { gl_RenderState.Apply(); + gl_RenderState.ApplyLightIndex(dynlightindex); } // the rest of the code is identical for textured rendering and lights @@ -383,7 +378,6 @@ void GLWall::Draw(int pass) gltexture->Bind(flags, 0); RenderWall(RWF_TEXTURED|RWF_GLOW); gl_RenderState.EnableGlow(false); - gl_RenderState.EnableLight(false); break; case GLPASS_DECALS: diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index 1ddb58076..00683dd20 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -57,6 +57,7 @@ #include "gl/system/gl_cvars.h" #include "gl/shaders/gl_shader.h" #include "gl/textures/gl_material.h" +#include "gl/dynlights/gl_lightbuffer.h" //========================================================================== // @@ -86,10 +87,19 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * // // The following code uses GetChars on the strings to get rid of terminating 0 characters. Do not remove or the code may break! // + unsigned int lightbuffertype = GLRenderer->mLights->GetBufferType(); + unsigned int lightbuffersize = GLRenderer->mLights->GetBlockSize(); - FString vp_comb = "#version 130\n"; - // todo when using shader storage buffers, add - // "#version 400 compatibility\n#extension GL_ARB_shader_storage_buffer_object : require\n" instead. + FString vp_comb; + + if (lightbuffertype == GL_UNIFORM_BUFFER) + { + vp_comb.Format("#version 130\n#extension GL_ARB_uniform_buffer_object : require\n#define NUM_UBO_LIGHTS %d\n", lightbuffersize); + } + else + { + vp_comb = "#version 400 compatibility\n#extension GL_ARB_shader_storage_buffer_object : require\n#define SHADER_STORAGE_LIGHTS\n"; + } if (!(gl.flags & RFL_BUFFER_STORAGE)) { @@ -196,7 +206,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * muLightParms.Init(hShader, "uLightAttr"); muColormapStart.Init(hShader, "uFixedColormapStart"); muColormapRange.Init(hShader, "uFixedColormapRange"); - muLightRange.Init(hShader, "uLightRange"); + muLightIndex.Init(hShader, "uLightIndex"); muFogColor.Init(hShader, "uFogColor"); muDynLightColor.Init(hShader, "uDynLightColor"); muObjectColor.Init(hShader, "uObjectColor"); @@ -218,10 +228,13 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * modelmatrix_index = glGetUniformLocation(hShader, "ModelMatrix"); texturematrix_index = glGetUniformLocation(hShader, "TextureMatrix"); + int tempindex = glGetUniformBlockIndex(hShader, "LightBufferUBO"); + if (tempindex != -1) glUniformBlockBinding(hShader, tempindex, LIGHTBUF_BINDINGPOINT); + glUseProgram(hShader); - int texture_index = glGetUniformLocation(hShader, "texture2"); - if (texture_index > 0) glUniform1i(texture_index, 1); + tempindex = glGetUniformLocation(hShader, "texture2"); + if (tempindex > 0) glUniform1i(tempindex, 1); glUseProgram(0); return !!linked; diff --git a/src/gl/shaders/gl_shader.h b/src/gl/shaders/gl_shader.h index c825996ee..e100e9bf1 100644 --- a/src/gl/shaders/gl_shader.h +++ b/src/gl/shaders/gl_shader.h @@ -187,7 +187,7 @@ class FShader FUniform1i muFixedColormap; FUniform4f muColormapStart; FUniform4f muColormapRange; - FBufferedUniform4i muLightRange; + FBufferedUniform1i muLightIndex; FBufferedUniformPE muFogColor; FBufferedUniform4f muDynLightColor; FBufferedUniformPE muObjectColor; @@ -281,6 +281,10 @@ public: #define FIRST_USER_SHADER 12 +enum +{ + LIGHTBUF_BINDINGPOINT = 1 +}; #endif diff --git a/src/gl/system/gl_interface.cpp b/src/gl/system/gl_interface.cpp index 404c068d7..ee30084f0 100644 --- a/src/gl/system/gl_interface.cpp +++ b/src/gl/system/gl_interface.cpp @@ -133,6 +133,7 @@ void gl_LoadExtensions() if (CheckExtension("GL_ARB_texture_compression")) gl.flags|=RFL_TEXTURE_COMPRESSION; if (CheckExtension("GL_EXT_texture_compression_s3tc")) gl.flags|=RFL_TEXTURE_COMPRESSION_S3TC; + if (CheckExtension("GL_ARB_shader_storage_buffer_object")) gl.flags |= RFL_SHADER_STORAGE_BUFFER; if (CheckExtension("GL_ARB_buffer_storage") && !Args->CheckParm("-nopersistentbuffers")) { gl.flags |= RFL_BUFFER_STORAGE; // the cmdline option is for testing the fallback implementation on newer hardware. @@ -178,6 +179,10 @@ void gl_PrintStartupLog() glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &v); Printf ("Max. uniform block size: %d\n", v); gl.maxuniformblock = v; + glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &v); + Printf ("Uniform block alignment: %d\n", v); + gl.uniformblockalignment = v; + glGetIntegerv(GL_MAX_VARYING_FLOATS, &v); Printf ("Max. varying: %d\n", v); glGetIntegerv(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, &v); diff --git a/src/gl/system/gl_interface.h b/src/gl/system/gl_interface.h index a88133929..9a5c18ac4 100644 --- a/src/gl/system/gl_interface.h +++ b/src/gl/system/gl_interface.h @@ -30,6 +30,7 @@ struct RenderContext unsigned int flags; unsigned int maxuniforms; unsigned int maxuniformblock; + unsigned int uniformblockalignment; float version; float glslversion; int max_texturesize; diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index 482afc0ca..532529f0b 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -7,14 +7,15 @@ in vec4 vColor; out vec4 FragColor; #ifdef SHADER_STORAGE_LIGHTS - layout(std430, binding = 3) buffer ParameterBuffer + layout(std430, binding = 1) buffer LightBufferSSO { vec4 lights[]; }; -#elif defined MAXLIGHTS128 - uniform vec4 lights[256]; #else - uniform vec4 lights[128]; + layout(std140) uniform LightBufferUBO + { + vec4 lights[NUM_UBO_LIGHTS]; + }; #endif @@ -169,29 +170,33 @@ vec4 getLightColor(float fogdist, float fogfactor) vec4 dynlight = uDynLightColor; - if (uLightRange.z > uLightRange.x) + if (uLightIndex >= 0) { - // - // modulated lights - // - for(int i=uLightRange.x; i lightRange.x) { - vec4 lightpos = lights[i]; - vec4 lightcolor = lights[i+1]; - - lightcolor.rgb *= max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w; - dynlight.rgb += lightcolor.rgb; - } - // - // subtractive lights - // - for(int i=uLightRange.y; i uLightRange.z) + if (uLightIndex >= 0) { - vec4 addlight = vec4(0.0,0.0,0.0,0.0); - - // - // additive lights - these can be done after the alpha test. - // - for(int i=uLightRange.z; i lightRange.z) { - vec4 lightpos = lights[i]; - vec4 lightcolor = lights[i+1]; - - lightcolor.rgb *= max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w; - addlight.rgb += lightcolor.rgb; + vec4 addlight = vec4(0.0,0.0,0.0,0.0); + + // + // additive lights - these can be done after the alpha test. + // + for(int i=lightRange.z; i