mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-30 07:41:22 +00:00
- let the light buffer use IDataBuffer as well.
This commit is contained in:
parent
54de0bf59f
commit
bd7df13200
7 changed files with 58 additions and 100 deletions
|
@ -25,8 +25,6 @@
|
||||||
**
|
**
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#include "gl_load/gl_system.h"
|
|
||||||
#include "gl/shaders/gl_shader.h"
|
|
||||||
#include "gl/dynlights/gl_lightbuffer.h"
|
#include "gl/dynlights/gl_lightbuffer.h"
|
||||||
#include "hwrenderer/utility/hw_clock.h"
|
#include "hwrenderer/utility/hw_clock.h"
|
||||||
#include "hwrenderer/dynlights/hw_dynlightdata.h"
|
#include "hwrenderer/dynlights/hw_dynlightdata.h"
|
||||||
|
@ -40,42 +38,30 @@ FLightBuffer::FLightBuffer()
|
||||||
{
|
{
|
||||||
int maxNumberOfLights = 40000;
|
int maxNumberOfLights = 40000;
|
||||||
|
|
||||||
mPersistentBuffer = screen->BuffersArePersistent();
|
|
||||||
mBufferSize = maxNumberOfLights * ELEMENTS_PER_LIGHT;
|
mBufferSize = maxNumberOfLights * ELEMENTS_PER_LIGHT;
|
||||||
mByteSize = mBufferSize * ELEMENT_SIZE;
|
mByteSize = mBufferSize * ELEMENT_SIZE;
|
||||||
|
|
||||||
// Hack alert: On Intel's GL driver SSBO's perform quite worse than UBOs.
|
// Hack alert: On Intel's GL driver SSBO's perform quite worse than UBOs.
|
||||||
// We only want to disable using SSBOs for lights but not disable the feature entirely.
|
// We only want to disable using SSBOs for lights but not disable the feature entirely.
|
||||||
// Note that using an uniform buffer here will limit the number of lights per surface so it isn't done for NVidia and AMD.
|
// Note that using an uniform buffer here will limit the number of lights per surface so it isn't done for NVidia and AMD.
|
||||||
if (gl.flags & RFL_SHADER_STORAGE_BUFFER && !strstr(gl.vendorstring, "Intel"))
|
if (screen->hwcaps & RFL_SHADER_STORAGE_BUFFER && !strstr(screen->gl_vendorstring, "Intel"))
|
||||||
{
|
{
|
||||||
mBufferType = GL_SHADER_STORAGE_BUFFER;
|
mBufferType = true;
|
||||||
mBlockAlign = 0;
|
mBlockAlign = 0;
|
||||||
mBlockSize = mBufferSize;
|
mBlockSize = mBufferSize;
|
||||||
mMaxUploadSize = mBlockSize;
|
mMaxUploadSize = mBlockSize;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mBufferType = GL_UNIFORM_BUFFER;
|
mBufferType = false;
|
||||||
mBlockSize = gl.maxuniformblock / ELEMENT_SIZE;
|
mBlockSize = screen->maxuniformblock / ELEMENT_SIZE;
|
||||||
mBlockAlign = gl.uniformblockalignment / ELEMENT_SIZE;
|
mBlockAlign = screen->uniformblockalignment / ELEMENT_SIZE;
|
||||||
mMaxUploadSize = (mBlockSize - mBlockAlign);
|
mMaxUploadSize = (mBlockSize - mBlockAlign);
|
||||||
mByteSize += gl.maxuniformblock; // to avoid mapping beyond the end of the buffer.
|
mByteSize += screen->maxuniformblock; // to avoid mapping beyond the end of the buffer.
|
||||||
}
|
}
|
||||||
|
|
||||||
glGenBuffers(1, &mBufferId);
|
mBuffer = screen->CreateDataBuffer(LIGHTBUF_BINDINGPOINT, mBufferType);
|
||||||
glBindBufferBase(mBufferType, LIGHTBUF_BINDINGPOINT, mBufferId);
|
mBuffer->SetData(mByteSize, nullptr, false);
|
||||||
glBindBuffer(mBufferType, mBufferId); // Note: Some older AMD drivers don't do that in glBindBufferBase, as they should.
|
|
||||||
if (mPersistentBuffer)
|
|
||||||
{
|
|
||||||
glBufferStorage(mBufferType, mByteSize, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
|
|
||||||
mBufferPointer = (float*)glMapBufferRange(mBufferType, 0, mByteSize, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
glBufferData(mBufferType, mByteSize, NULL, GL_DYNAMIC_DRAW);
|
|
||||||
mBufferPointer = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Clear();
|
Clear();
|
||||||
mLastMappedIndex = UINT_MAX;
|
mLastMappedIndex = UINT_MAX;
|
||||||
|
@ -83,8 +69,7 @@ FLightBuffer::FLightBuffer()
|
||||||
|
|
||||||
FLightBuffer::~FLightBuffer()
|
FLightBuffer::~FLightBuffer()
|
||||||
{
|
{
|
||||||
glBindBuffer(mBufferType, 0);
|
delete mBuffer;
|
||||||
glDeleteBuffers(1, &mBufferId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FLightBuffer::Clear()
|
void FLightBuffer::Clear()
|
||||||
|
@ -94,20 +79,7 @@ void FLightBuffer::Clear()
|
||||||
|
|
||||||
void FLightBuffer::CheckSize()
|
void FLightBuffer::CheckSize()
|
||||||
{
|
{
|
||||||
// reallocate the buffer with twice the size
|
// create the new buffer's storage (at least twice as large as the old one)
|
||||||
unsigned int newbuffer;
|
|
||||||
|
|
||||||
// first unmap the old buffer
|
|
||||||
glBindBuffer(mBufferType, mBufferId);
|
|
||||||
glUnmapBuffer(mBufferType);
|
|
||||||
|
|
||||||
// create and bind the new buffer, bind the old one to a copy target (too bad that DSA is not yet supported well enough to omit this crap.)
|
|
||||||
glGenBuffers(1, &newbuffer);
|
|
||||||
glBindBufferBase(mBufferType, LIGHTBUF_BINDINGPOINT, newbuffer);
|
|
||||||
glBindBuffer(mBufferType, newbuffer); // Note: Some older AMD drivers don't do that in glBindBufferBase, as they should.
|
|
||||||
glBindBuffer(GL_COPY_READ_BUFFER, mBufferId);
|
|
||||||
|
|
||||||
// create the new buffer's storage (twice as large as the old one)
|
|
||||||
int oldbytesize = mByteSize;
|
int oldbytesize = mByteSize;
|
||||||
unsigned int bufferbytesize = mBufferedData.Size() * 4;
|
unsigned int bufferbytesize = mBufferedData.Size() * 4;
|
||||||
if (bufferbytesize > mByteSize)
|
if (bufferbytesize > mByteSize)
|
||||||
|
@ -119,27 +91,12 @@ void FLightBuffer::CheckSize()
|
||||||
mByteSize *= 2;
|
mByteSize *= 2;
|
||||||
}
|
}
|
||||||
mBufferSize = mByteSize / ELEMENT_SIZE;
|
mBufferSize = mByteSize / ELEMENT_SIZE;
|
||||||
|
mBuffer->Resize(mByteSize);
|
||||||
if (mPersistentBuffer)
|
|
||||||
{
|
|
||||||
glBufferStorage(mBufferType, mByteSize, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
|
|
||||||
mBufferPointer = (float*)glMapBufferRange(mBufferType, 0, mByteSize, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
glBufferData(mBufferType, mByteSize, NULL, GL_DYNAMIC_DRAW);
|
|
||||||
mBufferPointer = (float*)glMapBufferRange(mBufferType, 0, mByteSize, GL_MAP_WRITE_BIT|GL_MAP_INVALIDATE_BUFFER_BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy contents and delete the old buffer.
|
Map();
|
||||||
glCopyBufferSubData(GL_COPY_READ_BUFFER, mBufferType, 0, 0, mByteSize/2);
|
memcpy(((float*)mBuffer->Memory()) + mBlockSize*4, &mBufferedData[0], bufferbytesize);
|
||||||
glBindBuffer(GL_COPY_READ_BUFFER, 0);
|
|
||||||
glDeleteBuffers(1, &mBufferId);
|
|
||||||
mBufferId = newbuffer;
|
|
||||||
Begin();
|
|
||||||
memcpy(mBufferPointer + mBlockSize*4, &mBufferedData[0], bufferbytesize);
|
|
||||||
mBufferedData.Clear();
|
mBufferedData.Clear();
|
||||||
Finish();
|
Unmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
int FLightBuffer::UploadLights(FDynLightData &data)
|
int FLightBuffer::UploadLights(FDynLightData &data)
|
||||||
|
@ -168,6 +125,7 @@ int FLightBuffer::UploadLights(FDynLightData &data)
|
||||||
totalsize = size0 + size1 + size2 + 1;
|
totalsize = size0 + size1 + size2 + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float *mBufferPointer = (float*)mBuffer->Memory();
|
||||||
assert(mBufferPointer != nullptr);
|
assert(mBufferPointer != nullptr);
|
||||||
if (mBufferPointer == nullptr) return -1;
|
if (mBufferPointer == nullptr) return -1;
|
||||||
if (totalsize <= 1) return -1; // there are no lights
|
if (totalsize <= 1) return -1; // there are no lights
|
||||||
|
@ -200,35 +158,15 @@ int FLightBuffer::UploadLights(FDynLightData &data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FLightBuffer::Begin()
|
int FLightBuffer::DoBindUBO(unsigned int index)
|
||||||
{
|
|
||||||
if (!mPersistentBuffer)
|
|
||||||
{
|
|
||||||
glBindBuffer(mBufferType, mBufferId);
|
|
||||||
mBufferPointer = (float*)glMapBufferRange(mBufferType, 0, mByteSize, GL_MAP_WRITE_BIT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FLightBuffer::Finish()
|
|
||||||
{
|
|
||||||
if (!mPersistentBuffer)
|
|
||||||
{
|
|
||||||
glBindBuffer(mBufferType, mBufferId);
|
|
||||||
glUnmapBuffer(mBufferType);
|
|
||||||
mBufferPointer = NULL;
|
|
||||||
}
|
|
||||||
if (mBufferedData.Size() > 0) CheckSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
int FLightBuffer::BindUBO(unsigned int index)
|
|
||||||
{
|
{
|
||||||
|
// this function 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.
|
||||||
unsigned int offset = (index / mBlockAlign) * mBlockAlign;
|
unsigned int offset = (index / mBlockAlign) * mBlockAlign;
|
||||||
|
|
||||||
if (offset != mLastMappedIndex)
|
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;
|
mLastMappedIndex = offset;
|
||||||
glBindBufferRange(GL_UNIFORM_BUFFER, LIGHTBUF_BINDINGPOINT, mBufferId, offset * ELEMENT_SIZE, mBlockSize * ELEMENT_SIZE);
|
mBuffer->BindRange(offset * ELEMENT_SIZE, mBlockSize * ELEMENT_SIZE);
|
||||||
}
|
}
|
||||||
return (index - offset);
|
return (index - offset);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,15 +3,17 @@
|
||||||
|
|
||||||
#include "tarray.h"
|
#include "tarray.h"
|
||||||
#include "hwrenderer/dynlights/hw_dynlightdata.h"
|
#include "hwrenderer/dynlights/hw_dynlightdata.h"
|
||||||
|
#include "hwrenderer/data/buffers.h"
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
|
class FRenderState;
|
||||||
|
|
||||||
class FLightBuffer
|
class FLightBuffer
|
||||||
{
|
{
|
||||||
unsigned int mBufferId;
|
IDataBuffer *mBuffer;
|
||||||
float * mBufferPointer;
|
|
||||||
|
|
||||||
unsigned int mBufferType;
|
bool mBufferType;
|
||||||
std::atomic<unsigned int> mIndex;
|
std::atomic<unsigned int> mIndex;
|
||||||
unsigned int mLastMappedIndex;
|
unsigned int mLastMappedIndex;
|
||||||
unsigned int mBlockAlign;
|
unsigned int mBlockAlign;
|
||||||
|
@ -19,24 +21,25 @@ class FLightBuffer
|
||||||
unsigned int mBufferSize;
|
unsigned int mBufferSize;
|
||||||
unsigned int mByteSize;
|
unsigned int mByteSize;
|
||||||
unsigned int mMaxUploadSize;
|
unsigned int mMaxUploadSize;
|
||||||
bool mPersistentBuffer;
|
|
||||||
|
|
||||||
std::mutex mBufferMutex;
|
std::mutex mBufferMutex;
|
||||||
TArray<float> mBufferedData;
|
TArray<float> mBufferedData;
|
||||||
|
|
||||||
|
void CheckSize();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
FLightBuffer();
|
FLightBuffer();
|
||||||
~FLightBuffer();
|
~FLightBuffer();
|
||||||
void Clear();
|
void Clear();
|
||||||
int UploadLights(FDynLightData &data);
|
int UploadLights(FDynLightData &data);
|
||||||
void Begin();
|
void Map() { mBuffer->Map(); }
|
||||||
void Finish();
|
void Unmap() { mBuffer->Unmap(); if (mBufferedData.Size() > 0) CheckSize(); }
|
||||||
void CheckSize();
|
|
||||||
int BindUBO(unsigned int index);
|
|
||||||
unsigned int GetBlockSize() const { return mBlockSize; }
|
unsigned int GetBlockSize() const { return mBlockSize; }
|
||||||
unsigned int GetBufferType() const { return mBufferType; }
|
bool GetBufferType() const { return mBufferType; }
|
||||||
|
|
||||||
|
int DoBindUBO(unsigned int index);
|
||||||
|
|
||||||
int ShaderIndex(unsigned int index) const
|
int ShaderIndex(unsigned int index) const
|
||||||
{
|
{
|
||||||
if (mBlockAlign == 0) return index;
|
if (mBlockAlign == 0) return index;
|
||||||
|
@ -45,6 +48,22 @@ public:
|
||||||
return int(index-offset);
|
return int(index-offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only relevant for OpenGL, so this does not need access to the render state.
|
||||||
|
int BindUBO(unsigned int index)
|
||||||
|
{
|
||||||
|
if (!mBufferType && index > -1)
|
||||||
|
{
|
||||||
|
index = DoBindUBO(index);
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The parameter is a reminder for Vulkan.
|
||||||
|
void BindBase(FRenderState &state)
|
||||||
|
{
|
||||||
|
mBuffer->BindBase();
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int gl_SetDynModelLight(AActor *self, int dynlightindex);
|
int gl_SetDynModelLight(AActor *self, int dynlightindex);
|
||||||
|
|
|
@ -200,11 +200,7 @@ bool FGLRenderState::ApplyShader()
|
||||||
matrixToGL(identityMatrix, activeShader->normalmodelmatrix_index);
|
matrixToGL(identityMatrix, activeShader->normalmodelmatrix_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto index = mLightIndex;
|
auto index = GLRenderer->mLights->BindUBO(mLightIndex);
|
||||||
if (index > -1 && GLRenderer->mLights->GetBufferType() == GL_UNIFORM_BUFFER)
|
|
||||||
{
|
|
||||||
index = GLRenderer->mLights->BindUBO(index);
|
|
||||||
}
|
|
||||||
activeShader->muLightIndex.Set(index);
|
activeShader->muLightIndex.Set(index);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -105,7 +105,7 @@ void FDrawInfo::CreateScene()
|
||||||
// clip the scene and fill the drawlists
|
// clip the scene and fill the drawlists
|
||||||
Bsp.Clock();
|
Bsp.Clock();
|
||||||
screen->mVertexData->Map();
|
screen->mVertexData->Map();
|
||||||
GLRenderer->mLights->Begin();
|
GLRenderer->mLights->Map();
|
||||||
|
|
||||||
// Give the DrawInfo the viewpoint in fixed point because that's what the nodes are.
|
// Give the DrawInfo the viewpoint in fixed point because that's what the nodes are.
|
||||||
viewx = FLOAT2FIXED(vp.Pos.X);
|
viewx = FLOAT2FIXED(vp.Pos.X);
|
||||||
|
@ -130,7 +130,7 @@ void FDrawInfo::CreateScene()
|
||||||
HandleHackedSubsectors(); // open sector hacks for deep water
|
HandleHackedSubsectors(); // open sector hacks for deep water
|
||||||
ProcessSectorStacks(in_area); // merge visplanes of sector stacks
|
ProcessSectorStacks(in_area); // merge visplanes of sector stacks
|
||||||
PrepareUnhandledMissingTextures();
|
PrepareUnhandledMissingTextures();
|
||||||
GLRenderer->mLights->Finish();
|
GLRenderer->mLights->Unmap();
|
||||||
screen->mVertexData->Unmap();
|
screen->mVertexData->Unmap();
|
||||||
|
|
||||||
ProcessAll.Unclock();
|
ProcessAll.Unclock();
|
||||||
|
@ -153,6 +153,7 @@ void FDrawInfo::RenderScene(int recursion)
|
||||||
glDepthMask(true);
|
glDepthMask(true);
|
||||||
if (!gl_no_skyclear) screen->mPortalState->RenderFirstSkyPortal(recursion, this);
|
if (!gl_no_skyclear) screen->mPortalState->RenderFirstSkyPortal(recursion, this);
|
||||||
|
|
||||||
|
GLRenderer->mLights->BindBase(gl_RenderState); // not needed for OpenGL but necessary for Vulkan command buffers to do it here!
|
||||||
gl_RenderState.EnableFog(true);
|
gl_RenderState.EnableFog(true);
|
||||||
gl_RenderState.SetRenderStyle(STYLE_Source);
|
gl_RenderState.SetRenderStyle(STYLE_Source);
|
||||||
|
|
||||||
|
|
|
@ -168,9 +168,9 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
|
||||||
|
|
||||||
assert(GLRenderer->mLights != NULL);
|
assert(GLRenderer->mLights != NULL);
|
||||||
|
|
||||||
unsigned int lightbuffertype = GLRenderer->mLights->GetBufferType();
|
bool lightbuffertype = GLRenderer->mLights->GetBufferType();
|
||||||
unsigned int lightbuffersize = GLRenderer->mLights->GetBlockSize();
|
unsigned int lightbuffersize = GLRenderer->mLights->GetBlockSize();
|
||||||
if (lightbuffertype == GL_UNIFORM_BUFFER)
|
if (!lightbuffertype)
|
||||||
{
|
{
|
||||||
vp_comb.Format("#version 330 core\n#define NUM_UBO_LIGHTS %d\n", lightbuffersize);
|
vp_comb.Format("#version 330 core\n#define NUM_UBO_LIGHTS %d\n", lightbuffersize);
|
||||||
}
|
}
|
||||||
|
@ -344,7 +344,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
|
||||||
texturematrix_index = glGetUniformLocation(hShader, "TextureMatrix");
|
texturematrix_index = glGetUniformLocation(hShader, "TextureMatrix");
|
||||||
normalmodelmatrix_index = glGetUniformLocation(hShader, "NormalModelMatrix");
|
normalmodelmatrix_index = glGetUniformLocation(hShader, "NormalModelMatrix");
|
||||||
|
|
||||||
if (lightbuffertype == GL_UNIFORM_BUFFER)
|
if (!lightbuffertype)
|
||||||
{
|
{
|
||||||
int tempindex = glGetUniformBlockIndex(hShader, "LightBufferUBO");
|
int tempindex = glGetUniformBlockIndex(hShader, "LightBufferUBO");
|
||||||
if (tempindex != -1) glUniformBlockBinding(hShader, tempindex, LIGHTBUF_BINDINGPOINT);
|
if (tempindex != -1) glUniformBlockBinding(hShader, tempindex, LIGHTBUF_BINDINGPOINT);
|
||||||
|
|
|
@ -119,6 +119,8 @@ void OpenGLFrameBuffer::InitializeState()
|
||||||
hwcaps = gl.flags;
|
hwcaps = gl.flags;
|
||||||
glslversion = gl.glslversion;
|
glslversion = gl.glslversion;
|
||||||
uniformblockalignment = gl.uniformblockalignment;
|
uniformblockalignment = gl.uniformblockalignment;
|
||||||
|
maxuniformblock = gl.maxuniformblock;
|
||||||
|
gl_vendorstring = gl.vendorstring;
|
||||||
|
|
||||||
if (first)
|
if (first)
|
||||||
{
|
{
|
||||||
|
|
|
@ -374,6 +374,8 @@ public:
|
||||||
int stencilValue = 0; // Global stencil test value
|
int stencilValue = 0; // Global stencil test value
|
||||||
bool enable_quadbuffered = false; // Quad-buffered stereo available?
|
bool enable_quadbuffered = false; // Quad-buffered stereo available?
|
||||||
unsigned int uniformblockalignment = 256; // Hardware dependent uniform buffer alignment.
|
unsigned int uniformblockalignment = 256; // Hardware dependent uniform buffer alignment.
|
||||||
|
unsigned int maxuniformblock = 65536;
|
||||||
|
const char *gl_vendorstring; // On OpenGL (not Vulkan) we have to account for some issues with Intel.
|
||||||
FPortalSceneState *mPortalState; // global portal state.
|
FPortalSceneState *mPortalState; // global portal state.
|
||||||
FSkyVertexBuffer *mSkyData = nullptr; // the sky vertex buffer
|
FSkyVertexBuffer *mSkyData = nullptr; // the sky vertex buffer
|
||||||
FFlatVertexBuffer *mVertexData = nullptr; // Global vertex data
|
FFlatVertexBuffer *mVertexData = nullptr; // Global vertex data
|
||||||
|
|
Loading…
Reference in a new issue