mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 23:02:08 +00:00
- made GLWall ready for multithreaded processing.
* to do this efficiently the amount of required vertices needs to be calculated up-front * always create the vertices in the data generation pass, not the render pass. * added synchronisation code to the vertex buffer allocator. Without multithreading this causes a slight slowdown, due to added processing cost. (Frozen Time bridge scene drops from 47 fps to 44 fps on my test machine.
This commit is contained in:
parent
3111ec97bb
commit
9a1603b246
7 changed files with 84 additions and 42 deletions
|
@ -23,6 +23,9 @@
|
|||
#ifndef __VERTEXBUFFER_H
|
||||
#define __VERTEXBUFFER_H
|
||||
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include "tarray.h"
|
||||
#include "hwrenderer/utility/hw_clock.h"
|
||||
#include "gl/system/gl_interface.h"
|
||||
|
@ -93,7 +96,8 @@ class FFlatVertexBuffer : public FVertexBuffer, public FFlatVertexGenerator
|
|||
{
|
||||
FFlatVertex *map;
|
||||
unsigned int mIndex;
|
||||
unsigned int mCurIndex;
|
||||
std::atomic<unsigned int> mCurIndex;
|
||||
std::mutex mBufferMutex;
|
||||
unsigned int mNumReserved;
|
||||
|
||||
|
||||
|
@ -125,12 +129,22 @@ public:
|
|||
{
|
||||
return &map[mCurIndex];
|
||||
}
|
||||
FFlatVertex *Alloc(int num, int *poffset)
|
||||
|
||||
template<class T>
|
||||
FFlatVertex *Alloc(int num, T *poffset)
|
||||
{
|
||||
again:
|
||||
FFlatVertex *p = GetBuffer();
|
||||
*poffset = mCurIndex;
|
||||
mCurIndex += num;
|
||||
if (mCurIndex >= BUFFER_SIZE_TO_USE) mCurIndex = mIndex;
|
||||
auto index = mCurIndex.fetch_add(num);
|
||||
*poffset = static_cast<T>(index);
|
||||
if (index + num >= BUFFER_SIZE_TO_USE)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mBufferMutex);
|
||||
if (mCurIndex >= BUFFER_SIZE_TO_USE) // retest condition, in case another thread got here first
|
||||
mCurIndex = mIndex;
|
||||
|
||||
if (index >= BUFFER_SIZE_TO_USE) goto again;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
|
|
@ -462,11 +462,8 @@ void GLDrawList::SortWallIntoWall(SortNode * head,SortNode * sort)
|
|||
w->ztop[0]=ws->ztop[1]=izt;
|
||||
w->zbottom[0]=ws->zbottom[1]=izb;
|
||||
w->tcs[GLWall::LOLFT].u = w->tcs[GLWall::UPLFT].u = ws->tcs[GLWall::LORGT].u = ws->tcs[GLWall::UPRGT].u = iu;
|
||||
if (gl.buffermethod == BM_DEFERRED)
|
||||
{
|
||||
ws->MakeVertices(false);
|
||||
w->MakeVertices(false);
|
||||
}
|
||||
ws->MakeVertices(false);
|
||||
w->MakeVertices(false);
|
||||
|
||||
SortNode * sort2=SortNodes.GetNew();
|
||||
memset(sort2,0,sizeof(SortNode));
|
||||
|
|
|
@ -134,7 +134,6 @@ void GLPortal::DrawPortalStencil()
|
|||
|
||||
for (unsigned int i = 0; i < lines.Size(); i++)
|
||||
{
|
||||
if (gl.buffermethod != BM_DEFERRED) lines[i].MakeVertices(false);
|
||||
mPrimIndices[i * 2] = lines[i].vertindex;
|
||||
mPrimIndices[i * 2 + 1] = lines[i].vertcount;
|
||||
}
|
||||
|
|
|
@ -35,8 +35,6 @@ EXTERN_CVAR(Bool, gl_seamless)
|
|||
|
||||
void GLWall::SplitUpperEdge(FFlatVertex *&ptr)
|
||||
{
|
||||
if (seg == NULL || seg->sidedef == NULL || (seg->sidedef->Flags & WALLF_POLYOBJ) || seg->sidedef->numsegs == 1) return;
|
||||
|
||||
side_t *sidedef = seg->sidedef;
|
||||
float polyw = glseg.fracright - glseg.fracleft;
|
||||
float facu = (tcs[UPRGT].u - tcs[UPLFT].u) / polyw;
|
||||
|
@ -71,8 +69,6 @@ void GLWall::SplitUpperEdge(FFlatVertex *&ptr)
|
|||
|
||||
void GLWall::SplitLowerEdge(FFlatVertex *&ptr)
|
||||
{
|
||||
if (seg == NULL || seg->sidedef == NULL || (seg->sidedef->Flags & WALLF_POLYOBJ) || seg->sidedef->numsegs == 1) return;
|
||||
|
||||
side_t *sidedef = seg->sidedef;
|
||||
float polyw = glseg.fracright - glseg.fracleft;
|
||||
float facu = (tcs[LORGT].u - tcs[LOLFT].u) / polyw;
|
||||
|
@ -173,20 +169,68 @@ void GLWall::SplitRightEdge(FFlatVertex *&ptr)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLWall::CreateVertices(FFlatVertex *&ptr, bool nosplit)
|
||||
void GLWall::CreateVertices(FFlatVertex *&ptr, bool split)
|
||||
{
|
||||
bool split = (gl_seamless && !nosplit && seg->sidedef != nullptr && !(seg->sidedef->Flags & WALLF_POLYOBJ) && !(flags & GLWF_NOSPLIT));
|
||||
ptr->Set(glseg.x1, zbottom[0], glseg.y1, tcs[LOLFT].u, tcs[LOLFT].v);
|
||||
ptr++;
|
||||
if (split && glseg.fracleft == 0) SplitLeftEdge(ptr);
|
||||
ptr->Set(glseg.x1, ztop[0], glseg.y1, tcs[UPLFT].u, tcs[UPLFT].v);
|
||||
ptr++;
|
||||
if (split && !(flags & GLWF_NOSPLITUPPER)) SplitUpperEdge(ptr);
|
||||
if (split && !(flags & GLWF_NOSPLITUPPER && seg->sidedef->numsegs > 1)) SplitUpperEdge(ptr);
|
||||
ptr->Set(glseg.x2, ztop[1], glseg.y2, tcs[UPRGT].u, tcs[UPRGT].v);
|
||||
ptr++;
|
||||
if (split && glseg.fracright == 1) SplitRightEdge(ptr);
|
||||
ptr->Set(glseg.x2, zbottom[1], glseg.y2, tcs[LORGT].u, tcs[LORGT].v);
|
||||
ptr++;
|
||||
if (split && !(flags & GLWF_NOSPLITLOWER)) SplitLowerEdge(ptr);
|
||||
if (split && !(flags & GLWF_NOSPLITLOWER) && seg->sidedef->numsegs > 1) SplitLowerEdge(ptr);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int GLWall::CountVertices()
|
||||
{
|
||||
int cnt = 4;
|
||||
vertex_t * vi = vertexes[0];
|
||||
if (glseg.fracleft == 0 && vi != nullptr && vi->numheights)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (i<vi->numheights && vi->heightlist[i] <= zbottom[0]) i++;
|
||||
while (i<vi->numheights && vi->heightlist[i] < ztop[0])
|
||||
{
|
||||
i++;
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
auto sidedef = seg->sidedef;
|
||||
if (!(flags & (GLWF_NOSPLITLOWER | GLWF_NOSPLITUPPER)) && sidedef->numsegs > 1)
|
||||
{
|
||||
int cnt2 = 0;
|
||||
for (int i = sidedef->numsegs - 2; i >= 0; i--)
|
||||
{
|
||||
float sidefrac = sidedef->segs[i]->sidefrac;
|
||||
if (sidefrac >= glseg.fracright) continue;
|
||||
if (sidefrac <= glseg.fracleft) break;
|
||||
cnt2++;
|
||||
}
|
||||
if ((flags & (GLWF_NOSPLITLOWER | GLWF_NOSPLITUPPER)) == (GLWF_NOSPLITLOWER | GLWF_NOSPLITUPPER)) cnt2 <<= 1;
|
||||
cnt += cnt2;
|
||||
}
|
||||
vi = vertexes[1];
|
||||
if (glseg.fracright == 1 && vi != nullptr && vi->numheights)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (i<vi->numheights && vi->heightlist[i] <= zbottom[1]) i++;
|
||||
while (i<vi->numheights && vi->heightlist[i] < ztop[1])
|
||||
{
|
||||
i++;
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
}
|
|
@ -266,6 +266,8 @@ private:
|
|||
void SplitUpperEdge(FFlatVertex *&ptr);
|
||||
void SplitLowerEdge(FFlatVertex *&ptr);
|
||||
|
||||
int CountVertices();
|
||||
|
||||
public:
|
||||
|
||||
GLWall(GLSceneDrawer *drawer)
|
||||
|
|
|
@ -50,7 +50,7 @@ void FDrawInfo::AddWall(GLWall *wall)
|
|||
if (translucent) // translucent walls
|
||||
{
|
||||
wall->ViewDistance = (r_viewpoint.Pos - (wall->seg->linedef->v1->fPos() + wall->seg->linedef->Delta() / 2)).XY().LengthSquared();
|
||||
if (gl.buffermethod == BM_DEFERRED) wall->MakeVertices(true);
|
||||
wall->MakeVertices(true);
|
||||
auto newwall = drawlists[GLDL_TRANSLUCENT].NewWall();
|
||||
*newwall = *wall;
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ void FDrawInfo::AddWall(GLWall *wall)
|
|||
{
|
||||
list = masked ? GLDL_MASKEDWALLS : GLDL_PLAINWALLS;
|
||||
}
|
||||
if (gl.buffermethod == BM_DEFERRED) wall->MakeVertices(false);
|
||||
wall->MakeVertices(false);
|
||||
auto newwall = drawlists[list].NewWall();
|
||||
*newwall = *wall;
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ void GLWall::PutPortal(HWDrawInfo *di, int ptype)
|
|||
{
|
||||
GLPortal * portal;
|
||||
|
||||
if (gl.buffermethod == BM_DEFERRED) MakeVertices(false);
|
||||
MakeVertices(false);
|
||||
switch (ptype)
|
||||
{
|
||||
// portals don't go into the draw list.
|
||||
|
|
|
@ -154,9 +154,11 @@ void GLWall::MakeVertices(bool nosplit)
|
|||
{
|
||||
if (vertcount == 0)
|
||||
{
|
||||
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
|
||||
CreateVertices(ptr, nosplit);
|
||||
vertcount = GLRenderer->mVBO->GetCount(ptr, &vertindex);
|
||||
bool split = (gl_seamless && !nosplit && seg->sidedef != nullptr && !(seg->sidedef->Flags & WALLF_POLYOBJ) && !(flags & GLWF_NOSPLIT));
|
||||
vertcount = split ? CountVertices() : 4;
|
||||
|
||||
FFlatVertex *ptr = GLRenderer->mVBO->Alloc(vertcount, &vertindex);
|
||||
CreateVertices(ptr, split);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,25 +172,9 @@ void GLWall::MakeVertices(bool nosplit)
|
|||
|
||||
void GLWall::RenderWall(int textured)
|
||||
{
|
||||
assert(vertcount > 0);
|
||||
gl_RenderState.Apply();
|
||||
gl_RenderState.ApplyLightIndex(dynlightindex);
|
||||
if (gl.buffermethod != BM_DEFERRED)
|
||||
{
|
||||
MakeVertices(!!(textured&RWF_NOSPLIT));
|
||||
}
|
||||
else if (vertcount == 0)
|
||||
{
|
||||
// This should never happen but in case it actually does, use the quad drawer as fallback (without edge splitting.)
|
||||
// This way it at least gets drawn.
|
||||
FQuadDrawer qd;
|
||||
qd.Set(0, glseg.x1, zbottom[0], glseg.y1, tcs[LOLFT].u, tcs[LOLFT].v);
|
||||
qd.Set(1, glseg.x1, ztop[0], glseg.y1, tcs[UPLFT].u, tcs[UPLFT].v);
|
||||
qd.Set(2, glseg.x2, ztop[1], glseg.y2, tcs[UPRGT].u, tcs[UPRGT].v);
|
||||
qd.Set(3, glseg.x2, zbottom[1], glseg.y2, tcs[LORGT].u, tcs[LORGT].v);
|
||||
qd.Render(GL_TRIANGLE_FAN);
|
||||
vertexcount += 4;
|
||||
return;
|
||||
}
|
||||
GLRenderer->mVBO->RenderArray(GL_TRIANGLE_FAN, vertindex, vertcount);
|
||||
vertexcount += vertcount;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue