From fd3681dae22e6fa41841d7e37b66c3f4aff7d481 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 May 2018 13:33:28 +0200 Subject: [PATCH] - use an indexed vertex buffer to render the flats. Right now this has no advantage but it allows optimizing the data, e.g. rendering an entire sector in one go instead of per subsector. --- src/gl/compatibility/gl_20.cpp | 1 + src/gl/data/gl_vertexbuffer.cpp | 13 +++ src/gl/data/gl_vertexbuffer.h | 6 ++ src/gl/scene/gl_flats.cpp | 3 +- src/hwrenderer/data/flatvertices.cpp | 150 ++++++++++++++++++++++++++- src/hwrenderer/data/flatvertices.h | 30 +++++- src/p_3dfloors.cpp | 1 + src/p_setup.cpp | 1 + src/p_udmf.cpp | 1 + src/r_defs.h | 5 +- 10 files changed, 202 insertions(+), 9 deletions(-) diff --git a/src/gl/compatibility/gl_20.cpp b/src/gl/compatibility/gl_20.cpp index 5ff6c7710..84ecfc31d 100644 --- a/src/gl/compatibility/gl_20.cpp +++ b/src/gl/compatibility/gl_20.cpp @@ -588,6 +588,7 @@ bool FDrawInfo::PutFlatCompat(GLFlat *flat, bool fog) int list = list_indices[masked][foggy]; auto newflat = gl_drawinfo->dldrawlists[list].NewFlat(); *newflat = *flat; + newflat->vboindex = -1; // don't use the vertex buffer with legacy lights to ensure all passes use the same render logic. return true; } diff --git a/src/gl/data/gl_vertexbuffer.cpp b/src/gl/data/gl_vertexbuffer.cpp index ce32b3ab4..301b6bc1c 100644 --- a/src/gl/data/gl_vertexbuffer.cpp +++ b/src/gl/data/gl_vertexbuffer.cpp @@ -125,6 +125,8 @@ void FSimpleVertexBuffer::set(FSimpleVertex *verts, int count) FFlatVertexBuffer::FFlatVertexBuffer(int width, int height) : FVertexBuffer(!gl.legacyMode), FFlatVertexGenerator(width, height) { + ibo_id = 0; + if (gl.buffermethod != BM_LEGACY) glGenBuffers(1, &ibo_id); switch (gl.buffermethod) { case BM_PERSISTENT: @@ -170,6 +172,11 @@ FFlatVertexBuffer::~FFlatVertexBuffer() glUnmapBuffer(GL_ARRAY_BUFFER); glBindBuffer(GL_ARRAY_BUFFER, 0); } + if (ibo_id != 0) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glDeleteBuffers(1, &ibo_id); + } if (gl.legacyMode) { delete[] map; @@ -188,6 +195,7 @@ void FFlatVertexBuffer::OutputResized(int width, int height) void FFlatVertexBuffer::BindVBO() { glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_id); if (!gl.legacyMode) { glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FFlatVertex), &VTO->x); @@ -245,4 +253,9 @@ void FFlatVertexBuffer::CreateVBO() Map(); memcpy(map, &vbo_shadowdata[0], vbo_shadowdata.Size() * sizeof(FFlatVertex)); Unmap(); + if (ibo_id > 0) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_id); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, ibo_data.Size() * sizeof(uint32_t), &ibo_data[0], GL_STATIC_DRAW); + } } diff --git a/src/gl/data/gl_vertexbuffer.h b/src/gl/data/gl_vertexbuffer.h index 28fe8f45c..b21fcd2d3 100644 --- a/src/gl/data/gl_vertexbuffer.h +++ b/src/gl/data/gl_vertexbuffer.h @@ -95,6 +95,7 @@ public: class FFlatVertexBuffer : public FVertexBuffer, public FFlatVertexGenerator { + unsigned int ibo_id; FFlatVertex *map; unsigned int mIndex; std::atomic mCurIndex; @@ -177,6 +178,11 @@ public: #endif + uint32_t *GetIndexPointer() const + { + return ibo_id == 0 ? &ibo_data[0] : nullptr; + } + void CheckPlanes(sector_t *sector) { FFlatVertexGenerator::CheckPlanes(sector, map); diff --git a/src/gl/scene/gl_flats.cpp b/src/gl/scene/gl_flats.cpp index ff55d1161..41e4e0e69 100644 --- a/src/gl/scene/gl_flats.cpp +++ b/src/gl/scene/gl_flats.cpp @@ -186,7 +186,8 @@ void FDrawInfo::DrawSubsectors(GLFlat *flat, int pass, bool processlights, bool { if (processlights) SetupSubsectorLights(flat, GLPASS_ALL, sub, &dli); drawcalls.Clock(); - glDrawArrays(GL_TRIANGLE_FAN, index, sub->numlines); + //glDrawArrays(GL_TRIANGLE_FAN, index, sub->numlines); + glDrawElements(GL_TRIANGLE_FAN, sub->numlines, GL_UNSIGNED_INT, GLRenderer->mVBO->GetIndexPointer() + index); drawcalls.Unclock(); flatvertices += sub->numlines; flatprimitives++; diff --git a/src/hwrenderer/data/flatvertices.cpp b/src/hwrenderer/data/flatvertices.cpp index 86bf78261..a5149a60e 100644 --- a/src/hwrenderer/data/flatvertices.cpp +++ b/src/hwrenderer/data/flatvertices.cpp @@ -181,10 +181,9 @@ int FFlatVertexGenerator::CreateVertices(int h, sector_t *sec, const secplane_t if (dotop || dobottom) { - if (dotop) ffloor->top.vindex = vbo_shadowdata.Size(); - if (dobottom) ffloor->bottom.vindex = vbo_shadowdata.Size(); - - CreateSectorVertices(fsec, plane, false); + auto ndx = CreateSectorVertices(fsec, plane, false); + if (dotop) ffloor->top.vindex = ndx; + if (dobottom) ffloor->bottom.vindex = ndx; } } } @@ -227,6 +226,147 @@ void FFlatVertexGenerator::CreateFlatVertices() } } +//========================================================================== +// +// Creates the vertices for one plane in one subsector +// +//========================================================================== + +int FFlatVertexGenerator::CreateIndexedSubsectorVertices(subsector_t *sub, const secplane_t &plane, int floor, int vi, FFlatVertexGenerator::FIndexGenerationInfo &gen) +{ + int idx = ibo_data.Reserve(sub->numlines); + for (unsigned int k = 0; knumlines; k++) + { + auto ndx = gen.GetIndex(sub->firstline[k].v1); + ibo_data[idx + k] = vi + ndx; + } + return idx; +} + +//========================================================================== +// +// Creates the vertices for one plane in one subsector +// +//========================================================================== + +int FFlatVertexGenerator::CreateIndexedSectorVertices(sector_t *sec, const secplane_t &plane, int floor, FFlatVertexGenerator::FIndexGenerationInfo &gen) +{ + int rt = ibo_data.Size(); + int vi = vbo_shadowdata.Reserve(gen.vertices.Size()); + float diff; + + // Create the actual vertices. + if (sec->transdoor && floor) diff = -1.f; + else diff = 0.f; + for (unsigned i = 0; i < gen.vertices.Size(); i++) + { + vbo_shadowdata[vi + i].SetFlatVertex(gen.vertices[i], plane); + vbo_shadowdata[vi + i].z += diff; + } + + // Create the indices for the subsectors + for (int j = 0; jsubsectorcount; j++) + { + subsector_t *sub = sec->subsectors[j]; + CreateIndexedSubsectorVertices(sub, plane, floor, vi, gen); + } + return rt; +} + +//========================================================================== +// +// +// +//========================================================================== + +int FFlatVertexGenerator::CreateIndexedVertices(int h, sector_t *sec, const secplane_t &plane, int floor, TArray &gen) +{ + // First calculate the vertices for the sector itself + sec->vboheight[h] = sec->GetPlaneTexZ(h); + sec->vboindex[h] = CreateIndexedSectorVertices(sec, plane, floor, gen[sec->Index()]); + + // Next are all sectors using this one as heightsec + TArray &fakes = sec->e->FakeFloor.Sectors; + for (unsigned g = 0; gvboindex[2 + h] = CreateIndexedSectorVertices(fsec, plane, false, gen[fsec->Index()]); + } + + // and finally all attached 3D floors + TArray &xf = sec->e->XFloor.attached; + for (unsigned g = 0; gflags & FF_RENDERPLANES) + { + bool dotop = (ffloor->top.model == sec) && (ffloor->top.isceiling == h); + bool dobottom = (ffloor->bottom.model == sec) && (ffloor->bottom.isceiling == h); + + if (dotop || dobottom) + { + auto ndx = CreateIndexedSectorVertices(fsec, plane, false, gen[fsec->Index()]); + if (dotop) ffloor->top.vindex = ndx; + if (dobottom) ffloor->bottom.vindex = ndx; + } + } + } + sec->vbocount[h] = vbo_shadowdata.Size() - sec->vboindex[h]; + return sec->vboindex[h]; +} + + +//========================================================================== +// +// +// +//========================================================================== + +void FFlatVertexGenerator::CreateIndexedFlatVertices() +{ + TArray gen; + gen.Resize(level.sectors.Size()); + // This must be generated up front so that the following code knows how many vertices a sector contains. + for (unsigned i = 0; i < level.sectors.Size(); i++) + { + for (int j = 0; j < level.sectors[i].subsectorcount; j++) + { + auto sub = level.sectors[i].subsectors[j]; + for (unsigned k = 0; k < sub->numlines; k++) + { + auto vert = sub->firstline[k].v1; + gen[i].AddVertex(vert); + } + } + } + for (int h = sector_t::floor; h <= sector_t::ceiling; h++) + { + for (auto &sec : level.sectors) + { + CreateIndexedVertices(h, &sec, sec.GetSecPlane(h), h == sector_t::floor, gen); + } + } + + // We need to do a final check for Vavoom water and FF_FIX sectors. + // No new vertices are needed here. The planes come from the actual sector + for (auto &sec : level.sectors) + { + for (auto ff : sec.e->XFloor.ffloors) + { + if (ff->top.model == &sec) + { + ff->top.vindex = sec.vboindex[ff->top.isceiling]; + } + if (ff->bottom.model == &sec) + { + ff->bottom.vindex = sec.vboindex[ff->top.isceiling]; + } + } + } +} + //========================================================================== // // @@ -257,7 +397,7 @@ void FFlatVertexGenerator::UpdatePlaneVertices(sector_t *sec, int plane, FFlatVe void FFlatVertexGenerator::CreateVertices() { vbo_shadowdata.Resize(NUM_RESERVED); - CreateFlatVertices(); + CreateIndexedFlatVertices(); } //========================================================================== diff --git a/src/hwrenderer/data/flatvertices.h b/src/hwrenderer/data/flatvertices.h index 9a45558b5..2f0b1d5f4 100644 --- a/src/hwrenderer/data/flatvertices.h +++ b/src/hwrenderer/data/flatvertices.h @@ -45,9 +45,31 @@ class FFlatVertexGenerator { protected: TArray vbo_shadowdata; + TArray ibo_data; + // Temporary data for creating an indexed buffer + struct FIndexGenerationInfo + { + TArray vertices; + TMap vertexmap; + + uint32_t AddVertex(vertex_t *vert) + { + auto check = vertexmap.CheckKey(vert); + if (check != nullptr) return *check; + auto index = vertices.Push(vert); + vertexmap[vert] = index; + return index; + } + + uint32_t GetIndex(vertex_t *vert) + { + auto check = vertexmap.CheckKey(vert); + if (check != nullptr) return *check; + return ~0; + } + }; - void CheckPlanes(sector_t *sector); public: enum @@ -70,6 +92,12 @@ private: int CreateSectorVertices(sector_t *sec, const secplane_t &plane, int floor); int CreateVertices(int h, sector_t *sec, const secplane_t &plane, int floor); void CreateFlatVertices(); + + int CreateIndexedSubsectorVertices(subsector_t *sub, const secplane_t &plane, int floor, int vi, FIndexGenerationInfo &gen); + int CreateIndexedSectorVertices(sector_t *sec, const secplane_t &plane, int floor, FIndexGenerationInfo &gen); + int CreateIndexedVertices(int h, sector_t *sec, const secplane_t &plane, int floor, TArray &gen); + void CreateIndexedFlatVertices(); + void UpdatePlaneVertices(sector_t *sec, int plane, FFlatVertex *map); protected: void CreateVertices(); diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 4254c92d4..5c6096f84 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -120,6 +120,7 @@ static void P_Add3DFloor(sector_t* sec, sector_t* sec2, line_t* master, int flag ffloor->top.copied = ffloor->bottom.copied = false; ffloor->top.model = ffloor->bottom.model = ffloor->model = sec2; ffloor->target = sec; + ffloor->top.vindex = ffloor->bottom.vindex = -1; if (!(flags&FF_THINFLOOR)) { diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 56850f6a0..dba5a109e 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1510,6 +1510,7 @@ void P_LoadSectors (MapData *map, FMissingTextureTracker &missingtex) ss->friction = ORIG_FRICTION; ss->movefactor = ORIG_FRICTION_FACTOR; ss->sectornum = i; + ss->ibocount = -1; } delete[] msp; } diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 24a7fd5fd..ef2b08b8f 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1375,6 +1375,7 @@ public: sec->sectornum = index; sec->damageinterval = 32; sec->terrainnum[sector_t::ceiling] = sec->terrainnum[sector_t::floor] = -1; + sec->ibocount = -1; memset(sec->SpecialColors, -1, sizeof(sec->SpecialColors)); if (floordrop) sec->Flags = SECF_FLOORDROP; // killough 3/7/98: end changes diff --git a/src/r_defs.h b/src/r_defs.h index a9e7e57c7..b3ee3e96b 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -1087,9 +1087,10 @@ public: vbo_fakeceiling = ceiling+2, }; - int vboindex[4]; // VBO indices of the 4 planes this sector uses during rendering + int vboindex[4]; // VBO/IBO indices of the 4 planes this sector uses during rendering double vboheight[2]; // Last calculated height for the 2 planes of this actual sector - int vbocount[2]; // Total count of vertices belonging to this sector's planes + int vbocount[2]; // Total count of vertices belonging to this sector's planes. This is used when a sector height changes and also contains all attached planes. + int ibocount; // number of indices per plane (identical for all planes.) If this is -1 the index buffer is not in use. float GetReflect(int pos) { return gl_plane_reflection_i? reflect[pos] : 0; } bool VBOHeightcheck(int pos) const { return vboheight[pos] == GetPlaneTexZ(pos); }