From fd3681dae22e6fa41841d7e37b66c3f4aff7d481 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 May 2018 13:33:28 +0200 Subject: [PATCH 01/10] - 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 5ff6c77108..84ecfc31d0 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 ce32b3ab4f..301b6bc1c4 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 28fe8f45ce..b21fcd2d3f 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 ff55d1161e..41e4e0e691 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 86bf782619..a5149a60e2 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 9a45558b5b..2f0b1d5f48 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 4254c92d49..5c6096f842 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 56850f6a01..dba5a109e3 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 24a7fd5fd0..ef2b08b8f3 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 a9e7e57c75..b3ee3e96bc 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); } From 2125f8b9d1a12b14d9ff5159b14ffad34b68bab5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 May 2018 14:42:25 +0200 Subject: [PATCH 02/10] - use triangles instead of triangle fans to render flats. --- src/gl/scene/gl_flats.cpp | 7 +++---- src/hwrenderer/data/flatvertices.cpp | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/gl/scene/gl_flats.cpp b/src/gl/scene/gl_flats.cpp index 41e4e0e691..ac6415b439 100644 --- a/src/gl/scene/gl_flats.cpp +++ b/src/gl/scene/gl_flats.cpp @@ -181,24 +181,23 @@ void FDrawInfo::DrawSubsectors(GLFlat *flat, int pass, bool processlights, bool for (int i=0; isector->subsectorcount; i++) { subsector_t * sub = flat->sector->subsectors[i]; + if (sub->numlines <= 2) continue; if (gl_drawinfo->ss_renderflags[sub->Index()]& flat->renderflags || istrans) { if (processlights) SetupSubsectorLights(flat, GLPASS_ALL, sub, &dli); drawcalls.Clock(); - //glDrawArrays(GL_TRIANGLE_FAN, index, sub->numlines); - glDrawElements(GL_TRIANGLE_FAN, sub->numlines, GL_UNSIGNED_INT, GLRenderer->mVBO->GetIndexPointer() + index); + glDrawElements(GL_TRIANGLES, (sub->numlines - 2) * 3, GL_UNSIGNED_INT, GLRenderer->mVBO->GetIndexPointer() + index); drawcalls.Unclock(); flatvertices += sub->numlines; flatprimitives++; } - index += sub->numlines; + index += (sub->numlines - 2) * 3; } } else { // Draw the subsectors belonging to this sector - // (can this case even happen?) for (int i=0; isector->subsectorcount; i++) { subsector_t * sub = flat->sector->subsectors[i]; diff --git a/src/hwrenderer/data/flatvertices.cpp b/src/hwrenderer/data/flatvertices.cpp index a5149a60e2..cfa929d31e 100644 --- a/src/hwrenderer/data/flatvertices.cpp +++ b/src/hwrenderer/data/flatvertices.cpp @@ -234,11 +234,20 @@ void FFlatVertexGenerator::CreateFlatVertices() 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++) + if (sub->numlines < 3) return -1; + + int idx = ibo_data.Reserve((sub->numlines - 2) * 3); + int idxc = idx; + int firstndx = gen.GetIndex(sub->firstline[0].v1); + int secondndx = gen.GetIndex(sub->firstline[1].v1); + for (unsigned int k = 2; knumlines; k++) { auto ndx = gen.GetIndex(sub->firstline[k].v1); - ibo_data[idx + k] = vi + ndx; + + ibo_data[idx++] = vi + firstndx; + ibo_data[idx++] = vi + secondndx; + ibo_data[idx++] = vi + ndx; + secondndx = ndx; } return idx; } From 352279a52fa8fde81da9cf32ba90eb51f6f75b74 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 May 2018 14:44:16 +0200 Subject: [PATCH 03/10] - removed the non-indexed flat setup. This won't be needed any longer. --- src/hwrenderer/data/flatvertices.cpp | 114 --------------------------- src/hwrenderer/data/flatvertices.h | 5 -- 2 files changed, 119 deletions(-) diff --git a/src/hwrenderer/data/flatvertices.cpp b/src/hwrenderer/data/flatvertices.cpp index cfa929d31e..0fba9a50fe 100644 --- a/src/hwrenderer/data/flatvertices.cpp +++ b/src/hwrenderer/data/flatvertices.cpp @@ -118,120 +118,6 @@ static F3DFloor *Find3DFloor(sector_t *target, sector_t *model) // //========================================================================== -int FFlatVertexGenerator::CreateSubsectorVertices(subsector_t *sub, const secplane_t &plane, int floor) -{ - int idx = vbo_shadowdata.Reserve(sub->numlines); - for(unsigned int k=0; knumlines; k++, idx++) - { - vbo_shadowdata[idx].SetFlatVertex(sub->firstline[k].v1, plane); - if (sub->sector->transdoor && floor) vbo_shadowdata[idx].z -= 1.f; - } - return idx; -} - -//========================================================================== -// -// Creates the vertices for one plane in one subsector -// -//========================================================================== - -int FFlatVertexGenerator::CreateSectorVertices(sector_t *sec, const secplane_t &plane, int floor) -{ - int rt = vbo_shadowdata.Size(); - // First calculate the vertices for the sector itself - for(int j=0; jsubsectorcount; j++) - { - subsector_t *sub = sec->subsectors[j]; - CreateSubsectorVertices(sub, plane, floor); - } - return rt; -} - -//========================================================================== -// -// -// -//========================================================================== - -int FFlatVertexGenerator::CreateVertices(int h, sector_t *sec, const secplane_t &plane, int floor) -{ - // First calculate the vertices for the sector itself - sec->vboheight[h] = sec->GetPlaneTexZ(h); - sec->vboindex[h] = CreateSectorVertices(sec, plane, floor); - - // Next are all sectors using this one as heightsec - TArray &fakes = sec->e->FakeFloor.Sectors; - for (unsigned g=0; gvboindex[2+h] = CreateSectorVertices(fsec, plane, false); - } - - // 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 = CreateSectorVertices(fsec, plane, false); - 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::CreateFlatVertices() -{ - for (int h = sector_t::floor; h <= sector_t::ceiling; h++) - { - for(auto &sec : level.sectors) - { - CreateVertices(h, &sec, sec.GetSecPlane(h), h == sector_t::floor); - } - } - - // 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]; - } - } - } -} - -//========================================================================== -// -// 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) { if (sub->numlines < 3) return -1; diff --git a/src/hwrenderer/data/flatvertices.h b/src/hwrenderer/data/flatvertices.h index 2f0b1d5f48..9f46612611 100644 --- a/src/hwrenderer/data/flatvertices.h +++ b/src/hwrenderer/data/flatvertices.h @@ -88,11 +88,6 @@ public: void OutputResized(int width, int height); private: - int CreateSubsectorVertices(subsector_t *sub, const secplane_t &plane, int floor); - 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); From 3e204080ae3b2459e16d956b37d71a61adb64c2d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 May 2018 15:20:46 +0200 Subject: [PATCH 04/10] - render sector planes in one draw call. On a fast and modern graphics card this is a lot faster than doing it per subsector but it may not be without drawbacks on older hardware so it will require some testing on older hardware. For me Frozen Time's view over the bridge went from 46 fps to 51 fps with this change, the time saved was roughly 2 ms. --- src/gl/scene/gl_drawinfo.h | 1 + src/gl/scene/gl_flats.cpp | 60 ++++++++++++++++++++++--- src/hwrenderer/data/flatvertices.cpp | 1 + src/hwrenderer/scene/hw_drawstructs.h | 2 + src/hwrenderer/scene/hw_flats.cpp | 16 +++++-- src/hwrenderer/scene/hw_renderhacks.cpp | 2 + 6 files changed, 72 insertions(+), 10 deletions(-) diff --git a/src/gl/scene/gl_drawinfo.h b/src/gl/scene/gl_drawinfo.h index 05ca3dd8d9..1add3bf4d0 100644 --- a/src/gl/scene/gl_drawinfo.h +++ b/src/gl/scene/gl_drawinfo.h @@ -121,6 +121,7 @@ struct FDrawInfo : public HWDrawInfo void ProcessLights(GLFlat *flat, bool istrans); void DrawSubsector(GLFlat *flat, subsector_t * sub); void SetupSubsectorLights(GLFlat *flat, int pass, subsector_t * sub, int *dli); + void SetupSectorLights(GLFlat *flat, int pass, int *dli); // Sprite drawer void DrawSprite(GLSprite *sprite, int pass); diff --git a/src/gl/scene/gl_flats.cpp b/src/gl/scene/gl_flats.cpp index ac6415b439..d4105c5691 100644 --- a/src/gl/scene/gl_flats.cpp +++ b/src/gl/scene/gl_flats.cpp @@ -62,7 +62,35 @@ void FDrawInfo::SetupSubsectorLights(GLFlat *flat, int pass, subsector_t * sub, (*dli)++; return; } - if (flat->SetupSubsectorLights(pass, sub, lightdata)) + if (flat->SetupSectorLights(pass, flat->sector, lightdata)) + { + int d = GLRenderer->mLights->UploadLights(lightdata); + if (pass == GLPASS_LIGHTSONLY) + { + GLRenderer->mLights->StoreIndex(d); + } + else + { + gl_RenderState.ApplyLightIndex(d); + } + } +} + +//========================================================================== +// +// +// +//========================================================================== + +void FDrawInfo::SetupSectorLights(GLFlat *flat, int pass, int *dli) +{ + if (dli != NULL && *dli != -1) + { + gl_RenderState.ApplyLightIndex(GLRenderer->mLights->GetIndex(*dli)); + (*dli)++; + return; + } + if (flat->SetupSectorLights(pass, flat->sector, lightdata)) { int d = GLRenderer->mLights->UploadLights(lightdata); if (pass == GLPASS_LIGHTSONLY) @@ -137,13 +165,20 @@ void FDrawInfo::ProcessLights(GLFlat *flat, bool istrans) { flat->dynlightindex = GLRenderer->mLights->GetIndexPtr(); - // Draw the subsectors belonging to this sector - for (int i=0; i< flat->sector->subsectorcount; i++) + if (flat->sector->ibocount > 0) { - subsector_t * sub = flat->sector->subsectors[i]; - if (gl_drawinfo->ss_renderflags[sub->Index()]& flat->renderflags || istrans) + SetupSectorLights(flat, GLPASS_LIGHTSONLY, nullptr); + } + else + { + // Draw the subsectors belonging to this sector + for (int i = 0; i < flat->sector->subsectorcount; i++) { - SetupSubsectorLights(flat, GLPASS_LIGHTSONLY, sub, nullptr); + subsector_t * sub = flat->sector->subsectors[i]; + if (gl_drawinfo->ss_renderflags[sub->Index()] & flat->renderflags || istrans) + { + SetupSubsectorLights(flat, GLPASS_LIGHTSONLY, sub, nullptr); + } } } @@ -175,7 +210,18 @@ void FDrawInfo::DrawSubsectors(GLFlat *flat, int pass, bool processlights, bool gl_RenderState.Apply(); if (gl.legacyMode) processlights = false; - if (flat->vboindex >= 0) + + auto vcount = flat->sector->ibocount; + if (vcount > 0) + { + if (processlights) SetupSectorLights(flat, GLPASS_ALL, &dli); + drawcalls.Clock(); + glDrawElements(GL_TRIANGLES, vcount, GL_UNSIGNED_INT, GLRenderer->mVBO->GetIndexPointer() + flat->vboindex); + drawcalls.Unclock(); + flatvertices += vcount; + flatprimitives++; + } + else if (flat->vboindex >= 0) { int index = flat->vboindex; for (int i=0; isector->subsectorcount; i++) diff --git a/src/hwrenderer/data/flatvertices.cpp b/src/hwrenderer/data/flatvertices.cpp index 0fba9a50fe..cba80b11a0 100644 --- a/src/hwrenderer/data/flatvertices.cpp +++ b/src/hwrenderer/data/flatvertices.cpp @@ -165,6 +165,7 @@ int FFlatVertexGenerator::CreateIndexedSectorVertices(sector_t *sec, const secpl subsector_t *sub = sec->subsectors[j]; CreateIndexedSubsectorVertices(sub, plane, floor, vi, gen); } + sec->ibocount = ibo_data.Size() - rt; return rt; } diff --git a/src/hwrenderer/scene/hw_drawstructs.h b/src/hwrenderer/scene/hw_drawstructs.h index 7aa7e0b7df..56c74a8f79 100644 --- a/src/hwrenderer/scene/hw_drawstructs.h +++ b/src/hwrenderer/scene/hw_drawstructs.h @@ -311,7 +311,9 @@ public: int dynlightindex; + bool SetupLights(int pass, FLightNode *head, FDynLightData &lightdata, int portalgroup); bool SetupSubsectorLights(int pass, subsector_t * sub, FDynLightData &lightdata); + bool SetupSectorLights(int pass, sector_t * sec, FDynLightData &lightdata); void PutFlat(HWDrawInfo *di, bool fog = false); void Process(HWDrawInfo *di, sector_t * model, int whichplane, bool notexture); diff --git a/src/hwrenderer/scene/hw_flats.cpp b/src/hwrenderer/scene/hw_flats.cpp index dabee535d6..0aafadc266 100644 --- a/src/hwrenderer/scene/hw_flats.cpp +++ b/src/hwrenderer/scene/hw_flats.cpp @@ -92,14 +92,13 @@ bool hw_SetPlaneTextureRotation(const GLSectorPlane * secplane, FMaterial * glte // //========================================================================== -bool GLFlat::SetupSubsectorLights(int pass, subsector_t * sub, FDynLightData &lightdata) +bool GLFlat::SetupLights(int pass, FLightNode * node, FDynLightData &lightdata, int portalgroup) { Plane p; if (renderstyle == STYLE_Add && !level.lightadditivesurfaces) return false; // no lights on additively blended surfaces. lightdata.Clear(); - FLightNode * node = sub->lighthead; while (node) { ADynamicLight * light = node->lightsource; @@ -121,13 +120,23 @@ bool GLFlat::SetupSubsectorLights(int pass, subsector_t * sub, FDynLightData &li } p.Set(plane.plane.Normal(), plane.plane.fD()); - lightdata.GetLight(sub->sector->PortalGroup, p, light, false); + lightdata.GetLight(portalgroup, p, light, false); node = node->nextLight; } return true; } +bool GLFlat::SetupSubsectorLights(int pass, subsector_t * sub, FDynLightData &lightdata) +{ + return SetupLights(pass, sub->lighthead, lightdata, sub->sector->PortalGroup); +} + +bool GLFlat::SetupSectorLights(int pass, sector_t * sec, FDynLightData &lightdata) +{ + return SetupLights(pass, sec->lighthead, lightdata, sec->PortalGroup); +} + //========================================================================== // // GLFlat::PutFlat @@ -252,6 +261,7 @@ void GLFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector) sector = &level.sectors[frontsector->sectornum]; extsector_t::xfloor &x = sector->e->XFloor; dynlightindex = -1; + vertexcount = sector->ibocount; uint8_t &srf = di->sectorrenderflags[sector->sectornum]; diff --git a/src/hwrenderer/scene/hw_renderhacks.cpp b/src/hwrenderer/scene/hw_renderhacks.cpp index 5eacd9dfcb..bfc7b38d3a 100644 --- a/src/hwrenderer/scene/hw_renderhacks.cpp +++ b/src/hwrenderer/scene/hw_renderhacks.cpp @@ -1077,6 +1077,7 @@ void HWDrawInfo::ProcessSectorStacks(area_t in_area) { subsector_t *sub = HandledSubsectors[j]; ss_renderflags[sub->Index()] &= ~SSRF_RENDERCEILING; + sub->sector->ibocount = -1; // cannot render this sector in one go. if (sub->portalcoverage[sector_t::ceiling].subsectors == NULL) { @@ -1122,6 +1123,7 @@ void HWDrawInfo::ProcessSectorStacks(area_t in_area) { subsector_t *sub = HandledSubsectors[j]; ss_renderflags[sub->Index()] &= ~SSRF_RENDERFLOOR; + sub->sector->ibocount = -1; // cannot render this sector in one go. if (sub->portalcoverage[sector_t::floor].subsectors == NULL) { From f54cf561abf1df8ca2cb1e21745ccab5e4fe8d90 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 May 2018 15:40:33 +0200 Subject: [PATCH 05/10] - missed this. --- src/hwrenderer/scene/hw_flats.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hwrenderer/scene/hw_flats.cpp b/src/hwrenderer/scene/hw_flats.cpp index 0aafadc266..fa1ff287a7 100644 --- a/src/hwrenderer/scene/hw_flats.cpp +++ b/src/hwrenderer/scene/hw_flats.cpp @@ -261,7 +261,6 @@ void GLFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector) sector = &level.sectors[frontsector->sectornum]; extsector_t::xfloor &x = sector->e->XFloor; dynlightindex = -1; - vertexcount = sector->ibocount; uint8_t &srf = di->sectorrenderflags[sector->sectornum]; From cc65490062c902f9187094d5eeaef14cec26bf7d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 May 2018 19:18:38 +0200 Subject: [PATCH 06/10] - added CVAR to disable WGL_EXT_swap_control_tear. At least on faster NVidia hardware, setting this to false and gl_finishbeforeswap to true gives a better experience because it reduces screen tearing - but the same setting will reduce frame rate quite dramatically on Intel and can cause bad stalls on some older GPUs when rendering camera textures. --- src/win32/win32gliface.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/win32/win32gliface.cpp b/src/win32/win32gliface.cpp index bd4600bb0f..cb6da5ff9b 100644 --- a/src/win32/win32gliface.cpp +++ b/src/win32/win32gliface.cpp @@ -1159,10 +1159,15 @@ bool SystemFrameBuffer::IsFullscreen() // // //========================================================================== +EXTERN_CVAR(Bool, vid_vsync); +CUSTOM_CVAR(Bool, gl_control_tear, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + vid_vsync.Callback(); +} void SystemFrameBuffer::SetVSync (bool vsync) { - if (myWglSwapIntervalExtProc != NULL) myWglSwapIntervalExtProc(vsync ? SwapInterval : 0); + if (myWglSwapIntervalExtProc != NULL) myWglSwapIntervalExtProc(vsync ? (gl_control_tear? SwapInterval : 1) : 0); } void SystemFrameBuffer::SwapBuffers() From 5cffa8873aec25ab2afa52b4b0910a68311b6e4e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 May 2018 19:19:48 +0200 Subject: [PATCH 07/10] - added a CVAR to disable per-plane rendering. This will require some comparisons on older hardware. On my Geforce 1060 rendering the full plane with one draw call is clearly faster in all cases I tested. --- src/gl/scene/gl_flats.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gl/scene/gl_flats.cpp b/src/gl/scene/gl_flats.cpp index d4105c5691..39ab921b49 100644 --- a/src/gl/scene/gl_flats.cpp +++ b/src/gl/scene/gl_flats.cpp @@ -48,6 +48,8 @@ #include "gl/scene/gl_scenedrawer.h" #include "gl/renderer/gl_quaddrawer.h" +CVAR(Bool, gl_render_subsectors, false, 0) + //========================================================================== // // Flats @@ -165,7 +167,7 @@ void FDrawInfo::ProcessLights(GLFlat *flat, bool istrans) { flat->dynlightindex = GLRenderer->mLights->GetIndexPtr(); - if (flat->sector->ibocount > 0) + if (flat->sector->ibocount > 0 && !gl_render_subsectors) { SetupSectorLights(flat, GLPASS_LIGHTSONLY, nullptr); } @@ -212,7 +214,7 @@ void FDrawInfo::DrawSubsectors(GLFlat *flat, int pass, bool processlights, bool if (gl.legacyMode) processlights = false; auto vcount = flat->sector->ibocount; - if (vcount > 0) + if (vcount > 0 && !gl_render_subsectors) { if (processlights) SetupSectorLights(flat, GLPASS_ALL, &dli); drawcalls.Clock(); From 3dc6ddbcc3981dd298cc66bc1a0309d9935aec1f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 May 2018 19:20:45 +0200 Subject: [PATCH 08/10] - check light direction in the shader. There are situations where lights on the wrong side of a linedef may be passed and those need to be skipped in the shader code. --- wadsrc/static/shaders/glsl/material_normal.fp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/wadsrc/static/shaders/glsl/material_normal.fp b/wadsrc/static/shaders/glsl/material_normal.fp index b048f45597..c251351d93 100644 --- a/wadsrc/static/shaders/glsl/material_normal.fp +++ b/wadsrc/static/shaders/glsl/material_normal.fp @@ -9,6 +9,9 @@ vec3 lightContribution(int i, vec3 normal) float lightdistance = distance(lightpos.xyz, pixelpos.xyz); if (lightpos.w < lightdistance) return vec3(0.0); // Early out lights touching surface but not this fragment + + float dotprod = dot(normal, lightdir); + if (dotprod < 0.0) return vec3(0.0); // light hits from the backside. This can happen with full sector light lists and must be rejected for all cases. float attenuation = clamp((lightpos.w - lightdistance) / lightpos.w, 0.0, 1.0); @@ -18,7 +21,7 @@ vec3 lightContribution(int i, vec3 normal) if (lightcolor.a < 0.0) // Sign bit is the attenuated light flag { vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz); - attenuation *= clamp(dot(normal, lightdir), 0.0, 1.0); + attenuation *= clamp(dotprod, 0.0, 1.0); } if (attenuation > 0.0) // Skip shadow map test if possible From 1266339c0fd50df27bc987b2a4d00b2afe0d6269 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 19 May 2018 21:17:58 +0200 Subject: [PATCH 09/10] - fixed shader compilation. --- wadsrc/static/shaders/glsl/material_normal.fp | 2 +- wadsrc/static/zscript/statusbar/sbarinfowrapper.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wadsrc/static/shaders/glsl/material_normal.fp b/wadsrc/static/shaders/glsl/material_normal.fp index c251351d93..6b65de6a3b 100644 --- a/wadsrc/static/shaders/glsl/material_normal.fp +++ b/wadsrc/static/shaders/glsl/material_normal.fp @@ -10,6 +10,7 @@ vec3 lightContribution(int i, vec3 normal) if (lightpos.w < lightdistance) return vec3(0.0); // Early out lights touching surface but not this fragment + vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz); float dotprod = dot(normal, lightdir); if (dotprod < 0.0) return vec3(0.0); // light hits from the backside. This can happen with full sector light lists and must be rejected for all cases. @@ -20,7 +21,6 @@ vec3 lightContribution(int i, vec3 normal) if (lightcolor.a < 0.0) // Sign bit is the attenuated light flag { - vec3 lightdir = normalize(lightpos.xyz - pixelpos.xyz); attenuation *= clamp(dotprod, 0.0, 1.0); } diff --git a/wadsrc/static/zscript/statusbar/sbarinfowrapper.txt b/wadsrc/static/zscript/statusbar/sbarinfowrapper.txt index efc6bedc8b..96f0063208 100644 --- a/wadsrc/static/zscript/statusbar/sbarinfowrapper.txt +++ b/wadsrc/static/zscript/statusbar/sbarinfowrapper.txt @@ -12,7 +12,7 @@ struct SBarInfo native ui } -// The sole purpose of this wrapper is to elimintate the native dependencies of the status bar object +// The sole purpose of this wrapper is to eliminate the native dependencies of the status bar object // because those would seriously impede the script conversion of the base class. class SBarInfoWrapper : BaseStatusBar From 2d4b8549c6302728c52cab824cea1c991fe5d2a9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 20 May 2018 08:56:29 +0200 Subject: [PATCH 10/10] - per-sector plane rendering needs to be disabled when processing a line portal with hardware that has no working clip plane support. In this case there are no means to discard the parts of the rendered sectors that lie behind the portal so it should only render the parts that are flagged as visible. --- src/gl/renderer/gl_renderstate.cpp | 2 +- src/gl/renderer/gl_renderstate.h | 11 +++++++++++ src/gl/scene/gl_flats.cpp | 4 ++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp index 305a5177cc..a0a1c5cc81 100644 --- a/src/gl/renderer/gl_renderstate.cpp +++ b/src/gl/renderer/gl_renderstate.cpp @@ -62,7 +62,7 @@ static void matrixToGL(const VSMatrix &mat, int loc) void FRenderState::Reset() { mTextureEnabled = true; - mClipLineEnabled = mSplitEnabled = mBrightmapEnabled = mFogEnabled = mGlowEnabled = false; + mClipLineShouldBeActive = mClipLineEnabled = mSplitEnabled = mBrightmapEnabled = mFogEnabled = mGlowEnabled = false; mColorMask[0] = mColorMask[1] = mColorMask[2] = mColorMask[3] = true; currentColorMask[0] = currentColorMask[1] = currentColorMask[2] = currentColorMask[3] = true; mFogColor.d = -1; diff --git a/src/gl/renderer/gl_renderstate.h b/src/gl/renderer/gl_renderstate.h index 1db6602a57..8aa4d00938 100644 --- a/src/gl/renderer/gl_renderstate.h +++ b/src/gl/renderer/gl_renderstate.h @@ -81,6 +81,7 @@ class FRenderState bool mGlowEnabled; bool mSplitEnabled; bool mClipLineEnabled; + bool mClipLineShouldBeActive; bool mBrightmapEnabled; bool mColorMask[4]; bool currentColorMask[4]; @@ -201,6 +202,11 @@ public: return mClipLineEnabled; } + bool GetClipLineShouldBeActive() + { + return mClipLineShouldBeActive; + } + void SetClipHeight(float height, float direction); void SetNormal(FVector3 norm) @@ -326,6 +332,11 @@ public: glDisable(GL_CLIP_DISTANCE0); } } + else + { + // this needs to be flagged because in this case per-sector plane rendering needs to be disabled if a clip plane is active. + mClipLineShouldBeActive = on; + } } void EnableBrightmap(bool on) diff --git a/src/gl/scene/gl_flats.cpp b/src/gl/scene/gl_flats.cpp index 39ab921b49..1810508bcc 100644 --- a/src/gl/scene/gl_flats.cpp +++ b/src/gl/scene/gl_flats.cpp @@ -167,7 +167,7 @@ void FDrawInfo::ProcessLights(GLFlat *flat, bool istrans) { flat->dynlightindex = GLRenderer->mLights->GetIndexPtr(); - if (flat->sector->ibocount > 0 && !gl_render_subsectors) + if (flat->sector->ibocount > 0 && !gl_render_subsectors && !gl_RenderState.GetClipLineShouldBeActive()) { SetupSectorLights(flat, GLPASS_LIGHTSONLY, nullptr); } @@ -214,7 +214,7 @@ void FDrawInfo::DrawSubsectors(GLFlat *flat, int pass, bool processlights, bool if (gl.legacyMode) processlights = false; auto vcount = flat->sector->ibocount; - if (vcount > 0 && !gl_render_subsectors) + if (vcount > 0 && !gl_render_subsectors && !gl_RenderState.GetClipLineShouldBeActive()) { if (processlights) SetupSectorLights(flat, GLPASS_ALL, &dli); drawcalls.Clock();