mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-25 13:41:05 +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 "hwrenderer/utility/hw_clock.h"
|
||||
#include "hwrenderer/dynlights/hw_dynlightdata.h"
|
||||
|
@ -40,42 +38,30 @@ FLightBuffer::FLightBuffer()
|
|||
{
|
||||
int maxNumberOfLights = 40000;
|
||||
|
||||
mPersistentBuffer = screen->BuffersArePersistent();
|
||||
mBufferSize = maxNumberOfLights * ELEMENTS_PER_LIGHT;
|
||||
mByteSize = mBufferSize * ELEMENT_SIZE;
|
||||
|
||||
// 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.
|
||||
// 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;
|
||||
mBlockSize = mBufferSize;
|
||||
mMaxUploadSize = mBlockSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
mBufferType = GL_UNIFORM_BUFFER;
|
||||
mBlockSize = gl.maxuniformblock / ELEMENT_SIZE;
|
||||
mBlockAlign = gl.uniformblockalignment / ELEMENT_SIZE;
|
||||
mBufferType = false;
|
||||
mBlockSize = screen->maxuniformblock / ELEMENT_SIZE;
|
||||
mBlockAlign = screen->uniformblockalignment / ELEMENT_SIZE;
|
||||
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);
|
||||
glBindBufferBase(mBufferType, LIGHTBUF_BINDINGPOINT, mBufferId);
|
||||
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;
|
||||
}
|
||||
mBuffer = screen->CreateDataBuffer(LIGHTBUF_BINDINGPOINT, mBufferType);
|
||||
mBuffer->SetData(mByteSize, nullptr, false);
|
||||
|
||||
Clear();
|
||||
mLastMappedIndex = UINT_MAX;
|
||||
|
@ -83,8 +69,7 @@ FLightBuffer::FLightBuffer()
|
|||
|
||||
FLightBuffer::~FLightBuffer()
|
||||
{
|
||||
glBindBuffer(mBufferType, 0);
|
||||
glDeleteBuffers(1, &mBufferId);
|
||||
delete mBuffer;
|
||||
}
|
||||
|
||||
void FLightBuffer::Clear()
|
||||
|
@ -94,20 +79,7 @@ void FLightBuffer::Clear()
|
|||
|
||||
void FLightBuffer::CheckSize()
|
||||
{
|
||||
// reallocate the buffer with twice the size
|
||||
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)
|
||||
// create the new buffer's storage (at least twice as large as the old one)
|
||||
int oldbytesize = mByteSize;
|
||||
unsigned int bufferbytesize = mBufferedData.Size() * 4;
|
||||
if (bufferbytesize > mByteSize)
|
||||
|
@ -119,27 +91,12 @@ void FLightBuffer::CheckSize()
|
|||
mByteSize *= 2;
|
||||
}
|
||||
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.
|
||||
glCopyBufferSubData(GL_COPY_READ_BUFFER, mBufferType, 0, 0, mByteSize/2);
|
||||
glBindBuffer(GL_COPY_READ_BUFFER, 0);
|
||||
glDeleteBuffers(1, &mBufferId);
|
||||
mBufferId = newbuffer;
|
||||
Begin();
|
||||
memcpy(mBufferPointer + mBlockSize*4, &mBufferedData[0], bufferbytesize);
|
||||
Map();
|
||||
memcpy(((float*)mBuffer->Memory()) + mBlockSize*4, &mBufferedData[0], bufferbytesize);
|
||||
mBufferedData.Clear();
|
||||
Finish();
|
||||
Unmap();
|
||||
}
|
||||
|
||||
int FLightBuffer::UploadLights(FDynLightData &data)
|
||||
|
@ -168,6 +125,7 @@ int FLightBuffer::UploadLights(FDynLightData &data)
|
|||
totalsize = size0 + size1 + size2 + 1;
|
||||
}
|
||||
|
||||
float *mBufferPointer = (float*)mBuffer->Memory();
|
||||
assert(mBufferPointer != nullptr);
|
||||
if (mBufferPointer == nullptr) return -1;
|
||||
if (totalsize <= 1) return -1; // there are no lights
|
||||
|
@ -200,35 +158,15 @@ int FLightBuffer::UploadLights(FDynLightData &data)
|
|||
}
|
||||
}
|
||||
|
||||
void FLightBuffer::Begin()
|
||||
{
|
||||
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)
|
||||
int FLightBuffer::DoBindUBO(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;
|
||||
|
||||
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 * ELEMENT_SIZE, mBlockSize * ELEMENT_SIZE);
|
||||
mBuffer->BindRange(offset * ELEMENT_SIZE, mBlockSize * ELEMENT_SIZE);
|
||||
}
|
||||
return (index - offset);
|
||||
}
|
||||
|
|
|
@ -3,15 +3,17 @@
|
|||
|
||||
#include "tarray.h"
|
||||
#include "hwrenderer/dynlights/hw_dynlightdata.h"
|
||||
#include "hwrenderer/data/buffers.h"
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
class FRenderState;
|
||||
|
||||
class FLightBuffer
|
||||
{
|
||||
unsigned int mBufferId;
|
||||
float * mBufferPointer;
|
||||
IDataBuffer *mBuffer;
|
||||
|
||||
unsigned int mBufferType;
|
||||
bool mBufferType;
|
||||
std::atomic<unsigned int> mIndex;
|
||||
unsigned int mLastMappedIndex;
|
||||
unsigned int mBlockAlign;
|
||||
|
@ -19,23 +21,24 @@ class FLightBuffer
|
|||
unsigned int mBufferSize;
|
||||
unsigned int mByteSize;
|
||||
unsigned int mMaxUploadSize;
|
||||
bool mPersistentBuffer;
|
||||
|
||||
std::mutex mBufferMutex;
|
||||
TArray<float> mBufferedData;
|
||||
|
||||
void CheckSize();
|
||||
|
||||
public:
|
||||
|
||||
FLightBuffer();
|
||||
~FLightBuffer();
|
||||
void Clear();
|
||||
int UploadLights(FDynLightData &data);
|
||||
void Begin();
|
||||
void Finish();
|
||||
void CheckSize();
|
||||
int BindUBO(unsigned int index);
|
||||
void Map() { mBuffer->Map(); }
|
||||
void Unmap() { mBuffer->Unmap(); if (mBufferedData.Size() > 0) CheckSize(); }
|
||||
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
|
||||
{
|
||||
|
@ -45,6 +48,22 @@ public:
|
|||
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);
|
||||
|
|
|
@ -200,11 +200,7 @@ bool FGLRenderState::ApplyShader()
|
|||
matrixToGL(identityMatrix, activeShader->normalmodelmatrix_index);
|
||||
}
|
||||
|
||||
auto index = mLightIndex;
|
||||
if (index > -1 && GLRenderer->mLights->GetBufferType() == GL_UNIFORM_BUFFER)
|
||||
{
|
||||
index = GLRenderer->mLights->BindUBO(index);
|
||||
}
|
||||
auto index = GLRenderer->mLights->BindUBO(mLightIndex);
|
||||
activeShader->muLightIndex.Set(index);
|
||||
|
||||
return true;
|
||||
|
|
|
@ -105,7 +105,7 @@ void FDrawInfo::CreateScene()
|
|||
// clip the scene and fill the drawlists
|
||||
Bsp.Clock();
|
||||
screen->mVertexData->Map();
|
||||
GLRenderer->mLights->Begin();
|
||||
GLRenderer->mLights->Map();
|
||||
|
||||
// Give the DrawInfo the viewpoint in fixed point because that's what the nodes are.
|
||||
viewx = FLOAT2FIXED(vp.Pos.X);
|
||||
|
@ -130,7 +130,7 @@ void FDrawInfo::CreateScene()
|
|||
HandleHackedSubsectors(); // open sector hacks for deep water
|
||||
ProcessSectorStacks(in_area); // merge visplanes of sector stacks
|
||||
PrepareUnhandledMissingTextures();
|
||||
GLRenderer->mLights->Finish();
|
||||
GLRenderer->mLights->Unmap();
|
||||
screen->mVertexData->Unmap();
|
||||
|
||||
ProcessAll.Unclock();
|
||||
|
@ -153,6 +153,7 @@ void FDrawInfo::RenderScene(int recursion)
|
|||
glDepthMask(true);
|
||||
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.SetRenderStyle(STYLE_Source);
|
||||
|
||||
|
|
|
@ -168,9 +168,9 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
|
|||
|
||||
assert(GLRenderer->mLights != NULL);
|
||||
|
||||
unsigned int lightbuffertype = GLRenderer->mLights->GetBufferType();
|
||||
bool lightbuffertype = GLRenderer->mLights->GetBufferType();
|
||||
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);
|
||||
}
|
||||
|
@ -344,7 +344,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
|
|||
texturematrix_index = glGetUniformLocation(hShader, "TextureMatrix");
|
||||
normalmodelmatrix_index = glGetUniformLocation(hShader, "NormalModelMatrix");
|
||||
|
||||
if (lightbuffertype == GL_UNIFORM_BUFFER)
|
||||
if (!lightbuffertype)
|
||||
{
|
||||
int tempindex = glGetUniformBlockIndex(hShader, "LightBufferUBO");
|
||||
if (tempindex != -1) glUniformBlockBinding(hShader, tempindex, LIGHTBUF_BINDINGPOINT);
|
||||
|
|
|
@ -119,6 +119,8 @@ void OpenGLFrameBuffer::InitializeState()
|
|||
hwcaps = gl.flags;
|
||||
glslversion = gl.glslversion;
|
||||
uniformblockalignment = gl.uniformblockalignment;
|
||||
maxuniformblock = gl.maxuniformblock;
|
||||
gl_vendorstring = gl.vendorstring;
|
||||
|
||||
if (first)
|
||||
{
|
||||
|
|
|
@ -374,6 +374,8 @@ public:
|
|||
int stencilValue = 0; // Global stencil test value
|
||||
bool enable_quadbuffered = false; // Quad-buffered stereo available?
|
||||
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.
|
||||
FSkyVertexBuffer *mSkyData = nullptr; // the sky vertex buffer
|
||||
FFlatVertexBuffer *mVertexData = nullptr; // Global vertex data
|
||||
|
|
Loading…
Reference in a new issue