mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-13 07:57:58 +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
|
#ifndef __VERTEXBUFFER_H
|
||||||
#define __VERTEXBUFFER_H
|
#define __VERTEXBUFFER_H
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <thread>
|
||||||
|
#include <mutex>
|
||||||
#include "tarray.h"
|
#include "tarray.h"
|
||||||
#include "hwrenderer/utility/hw_clock.h"
|
#include "hwrenderer/utility/hw_clock.h"
|
||||||
#include "gl/system/gl_interface.h"
|
#include "gl/system/gl_interface.h"
|
||||||
|
@ -93,7 +96,8 @@ class FFlatVertexBuffer : public FVertexBuffer, public FFlatVertexGenerator
|
||||||
{
|
{
|
||||||
FFlatVertex *map;
|
FFlatVertex *map;
|
||||||
unsigned int mIndex;
|
unsigned int mIndex;
|
||||||
unsigned int mCurIndex;
|
std::atomic<unsigned int> mCurIndex;
|
||||||
|
std::mutex mBufferMutex;
|
||||||
unsigned int mNumReserved;
|
unsigned int mNumReserved;
|
||||||
|
|
||||||
|
|
||||||
|
@ -125,12 +129,22 @@ public:
|
||||||
{
|
{
|
||||||
return &map[mCurIndex];
|
return &map[mCurIndex];
|
||||||
}
|
}
|
||||||
FFlatVertex *Alloc(int num, int *poffset)
|
|
||||||
|
template<class T>
|
||||||
|
FFlatVertex *Alloc(int num, T *poffset)
|
||||||
{
|
{
|
||||||
|
again:
|
||||||
FFlatVertex *p = GetBuffer();
|
FFlatVertex *p = GetBuffer();
|
||||||
*poffset = mCurIndex;
|
auto index = mCurIndex.fetch_add(num);
|
||||||
mCurIndex += num;
|
*poffset = static_cast<T>(index);
|
||||||
if (mCurIndex >= BUFFER_SIZE_TO_USE) mCurIndex = mIndex;
|
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;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -462,11 +462,8 @@ void GLDrawList::SortWallIntoWall(SortNode * head,SortNode * sort)
|
||||||
w->ztop[0]=ws->ztop[1]=izt;
|
w->ztop[0]=ws->ztop[1]=izt;
|
||||||
w->zbottom[0]=ws->zbottom[1]=izb;
|
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;
|
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();
|
SortNode * sort2=SortNodes.GetNew();
|
||||||
memset(sort2,0,sizeof(SortNode));
|
memset(sort2,0,sizeof(SortNode));
|
||||||
|
|
|
@ -134,7 +134,6 @@ void GLPortal::DrawPortalStencil()
|
||||||
|
|
||||||
for (unsigned int i = 0; i < lines.Size(); i++)
|
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] = lines[i].vertindex;
|
||||||
mPrimIndices[i * 2 + 1] = lines[i].vertcount;
|
mPrimIndices[i * 2 + 1] = lines[i].vertcount;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,8 +35,6 @@ EXTERN_CVAR(Bool, gl_seamless)
|
||||||
|
|
||||||
void GLWall::SplitUpperEdge(FFlatVertex *&ptr)
|
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;
|
side_t *sidedef = seg->sidedef;
|
||||||
float polyw = glseg.fracright - glseg.fracleft;
|
float polyw = glseg.fracright - glseg.fracleft;
|
||||||
float facu = (tcs[UPRGT].u - tcs[UPLFT].u) / polyw;
|
float facu = (tcs[UPRGT].u - tcs[UPLFT].u) / polyw;
|
||||||
|
@ -71,8 +69,6 @@ void GLWall::SplitUpperEdge(FFlatVertex *&ptr)
|
||||||
|
|
||||||
void GLWall::SplitLowerEdge(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;
|
side_t *sidedef = seg->sidedef;
|
||||||
float polyw = glseg.fracright - glseg.fracleft;
|
float polyw = glseg.fracright - glseg.fracleft;
|
||||||
float facu = (tcs[LORGT].u - tcs[LOLFT].u) / polyw;
|
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->Set(glseg.x1, zbottom[0], glseg.y1, tcs[LOLFT].u, tcs[LOLFT].v);
|
||||||
ptr++;
|
ptr++;
|
||||||
if (split && glseg.fracleft == 0) SplitLeftEdge(ptr);
|
if (split && glseg.fracleft == 0) SplitLeftEdge(ptr);
|
||||||
ptr->Set(glseg.x1, ztop[0], glseg.y1, tcs[UPLFT].u, tcs[UPLFT].v);
|
ptr->Set(glseg.x1, ztop[0], glseg.y1, tcs[UPLFT].u, tcs[UPLFT].v);
|
||||||
ptr++;
|
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->Set(glseg.x2, ztop[1], glseg.y2, tcs[UPRGT].u, tcs[UPRGT].v);
|
||||||
ptr++;
|
ptr++;
|
||||||
if (split && glseg.fracright == 1) SplitRightEdge(ptr);
|
if (split && glseg.fracright == 1) SplitRightEdge(ptr);
|
||||||
ptr->Set(glseg.x2, zbottom[1], glseg.y2, tcs[LORGT].u, tcs[LORGT].v);
|
ptr->Set(glseg.x2, zbottom[1], glseg.y2, tcs[LORGT].u, tcs[LORGT].v);
|
||||||
ptr++;
|
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 SplitUpperEdge(FFlatVertex *&ptr);
|
||||||
void SplitLowerEdge(FFlatVertex *&ptr);
|
void SplitLowerEdge(FFlatVertex *&ptr);
|
||||||
|
|
||||||
|
int CountVertices();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
GLWall(GLSceneDrawer *drawer)
|
GLWall(GLSceneDrawer *drawer)
|
||||||
|
|
|
@ -50,7 +50,7 @@ void FDrawInfo::AddWall(GLWall *wall)
|
||||||
if (translucent) // translucent walls
|
if (translucent) // translucent walls
|
||||||
{
|
{
|
||||||
wall->ViewDistance = (r_viewpoint.Pos - (wall->seg->linedef->v1->fPos() + wall->seg->linedef->Delta() / 2)).XY().LengthSquared();
|
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();
|
auto newwall = drawlists[GLDL_TRANSLUCENT].NewWall();
|
||||||
*newwall = *wall;
|
*newwall = *wall;
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ void FDrawInfo::AddWall(GLWall *wall)
|
||||||
{
|
{
|
||||||
list = masked ? GLDL_MASKEDWALLS : GLDL_PLAINWALLS;
|
list = masked ? GLDL_MASKEDWALLS : GLDL_PLAINWALLS;
|
||||||
}
|
}
|
||||||
if (gl.buffermethod == BM_DEFERRED) wall->MakeVertices(false);
|
wall->MakeVertices(false);
|
||||||
auto newwall = drawlists[list].NewWall();
|
auto newwall = drawlists[list].NewWall();
|
||||||
*newwall = *wall;
|
*newwall = *wall;
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@ void GLWall::PutPortal(HWDrawInfo *di, int ptype)
|
||||||
{
|
{
|
||||||
GLPortal * portal;
|
GLPortal * portal;
|
||||||
|
|
||||||
if (gl.buffermethod == BM_DEFERRED) MakeVertices(false);
|
MakeVertices(false);
|
||||||
switch (ptype)
|
switch (ptype)
|
||||||
{
|
{
|
||||||
// portals don't go into the draw list.
|
// portals don't go into the draw list.
|
||||||
|
|
|
@ -154,9 +154,11 @@ void GLWall::MakeVertices(bool nosplit)
|
||||||
{
|
{
|
||||||
if (vertcount == 0)
|
if (vertcount == 0)
|
||||||
{
|
{
|
||||||
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
|
bool split = (gl_seamless && !nosplit && seg->sidedef != nullptr && !(seg->sidedef->Flags & WALLF_POLYOBJ) && !(flags & GLWF_NOSPLIT));
|
||||||
CreateVertices(ptr, nosplit);
|
vertcount = split ? CountVertices() : 4;
|
||||||
vertcount = GLRenderer->mVBO->GetCount(ptr, &vertindex);
|
|
||||||
|
FFlatVertex *ptr = GLRenderer->mVBO->Alloc(vertcount, &vertindex);
|
||||||
|
CreateVertices(ptr, split);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,25 +172,9 @@ void GLWall::MakeVertices(bool nosplit)
|
||||||
|
|
||||||
void GLWall::RenderWall(int textured)
|
void GLWall::RenderWall(int textured)
|
||||||
{
|
{
|
||||||
|
assert(vertcount > 0);
|
||||||
gl_RenderState.Apply();
|
gl_RenderState.Apply();
|
||||||
gl_RenderState.ApplyLightIndex(dynlightindex);
|
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);
|
GLRenderer->mVBO->RenderArray(GL_TRIANGLE_FAN, vertindex, vertcount);
|
||||||
vertexcount += vertcount;
|
vertexcount += vertcount;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue