From 7d3beb665b7a3e802ef57091ff423dffc7bf29b5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 10 May 2014 21:47:07 +0200 Subject: [PATCH] - rewrote vertex buffer code to require GL_ARB_BUFFER_STORAGE extension. This means it won't work anymore on anything that doesn't support OpenGL 4.0, but I don't think this is a problem. On older NVidia cards performance gains could not be seen and on older AMDs using the vertex buffer was even worse as long as it got mixed with immediate mode rendering. --- src/gl/data/gl_vertexbuffer.cpp | 106 ++++++++++------------------- src/gl/data/gl_vertexbuffer.h | 19 +++--- src/gl/models/gl_voxels.cpp | 26 +++---- src/gl/renderer/gl_renderstate.cpp | 8 +++ src/gl/renderer/gl_renderstate.h | 9 +++ src/gl/scene/gl_flats.cpp | 2 +- src/gl/scene/gl_scene.cpp | 3 +- src/gl/system/gl_interface.cpp | 43 ++++-------- src/gl/system/gl_interface.h | 13 +--- 9 files changed, 97 insertions(+), 132 deletions(-) diff --git a/src/gl/data/gl_vertexbuffer.cpp b/src/gl/data/gl_vertexbuffer.cpp index c07b6cea3..c5703a8ef 100644 --- a/src/gl/data/gl_vertexbuffer.cpp +++ b/src/gl/data/gl_vertexbuffer.cpp @@ -49,20 +49,18 @@ #include "gl/data/gl_vertexbuffer.h" +const int BUFFER_SIZE = 2000000; + CUSTOM_CVAR(Int, gl_usevbo, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) { - if (self < -1 || self > 2) + if (self < -1 || self > 1 || !(gl.flags & RFL_BUFFER_STORAGE)) { self = 0; } else if (self == -1) { - if (!(gl.flags & RFL_NVIDIA)) self = 0; - else self = 2; - } - else if (GLRenderer != NULL && GLRenderer->mVBO != NULL && GLRenderer->mVBO->vbo_arg != self) - { - Printf("Vertex buffer use will be changed for the next level.\n"); + if (!(gl.flags & RFL_BUFFER_STORAGE)) self = 0; + else self = 1; } } @@ -96,13 +94,24 @@ FVertexBuffer::~FVertexBuffer() FFlatVertexBuffer::FFlatVertexBuffer() : FVertexBuffer() { - vbo_arg = gl_usevbo; - map = NULL; + if (gl.flags & RFL_BUFFER_STORAGE) + { + unsigned int bytesize = BUFFER_SIZE * sizeof(FFlatVertex); + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + glBufferStorage(GL_ARRAY_BUFFER, bytesize, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); + map = (FFlatVertex*)glMapBufferRange(GL_ARRAY_BUFFER, 0, bytesize, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); + } + else + { + map = NULL; + } } FFlatVertexBuffer::~FFlatVertexBuffer() { - UnmapVBO(); + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + glUnmapBuffer(GL_ARRAY_BUFFER); + glBindBuffer(GL_ARRAY_BUFFER, 0); } //========================================================================== @@ -118,7 +127,6 @@ void FFlatVertex::SetFlatVertex(vertex_t *vt, const secplane_t & plane) z = plane.ZatPoint(vt->fx, vt->fy); u = vt->fx/64.f; v = -vt->fy/64.f; - w = /*dc = df =*/ 0; } //========================================================================== @@ -260,58 +268,18 @@ void FFlatVertexBuffer::CreateFlatVBO() // //========================================================================== -void FFlatVertexBuffer::MapVBO() -{ - if (map == NULL) - { - glBindBuffer(GL_ARRAY_BUFFER, vbo_id); - map = (FFlatVertex*)glMapBufferRange(GL_ARRAY_BUFFER, 0, vbo_shadowdata.Size() * sizeof(FFlatVertex), - GL_MAP_WRITE_BIT|GL_MAP_FLUSH_EXPLICIT_BIT|GL_MAP_UNSYNCHRONIZED_BIT); - } -} - -//========================================================================== -// -// -// -//========================================================================== - -void FFlatVertexBuffer::UnmapVBO() -{ - if (map != NULL) - { - glUnmapBuffer(GL_ARRAY_BUFFER); - map = NULL; - } -} - -//========================================================================== -// -// -// -//========================================================================== - void FFlatVertexBuffer::UpdatePlaneVertices(sector_t *sec, int plane) { int startvt = sec->vboindex[plane]; int countvt = sec->vbocount[plane]; secplane_t &splane = sec->GetSecPlane(plane); FFlatVertex *vt = &vbo_shadowdata[startvt]; + FFlatVertex *mapvt = &map[startvt]; for(int i=0; iz = splane.ZatPoint(vt->x, vt->y); if (plane == sector_t::floor && sec->transdoor) vt->z -= 1; - } - if (gl.flags & RFL_MAP_BUFFER_RANGE) - { - MapVBO(); - if (map == NULL) return; // Error - memcpy(&map[startvt], &vbo_shadowdata[startvt], countvt * sizeof(FFlatVertex)); - glFlushMappedBufferRange(GL_ARRAY_BUFFER, startvt * sizeof(FFlatVertex), countvt * sizeof(FFlatVertex)); - } - else - { - glBufferSubData(GL_ARRAY_BUFFER, startvt * sizeof(FFlatVertex), countvt * sizeof(FFlatVertex), &vbo_shadowdata[startvt]); + mapvt->z = vt->z; } } @@ -324,11 +292,10 @@ void FFlatVertexBuffer::UpdatePlaneVertices(sector_t *sec, int plane) void FFlatVertexBuffer::CreateVBO() { vbo_shadowdata.Clear(); - if (vbo_arg > 0) + if (gl.flags & RFL_BUFFER_STORAGE) { CreateFlatVBO(); - glBindBuffer(GL_ARRAY_BUFFER, vbo_id); - glBufferData(GL_ARRAY_BUFFER, vbo_shadowdata.Size() * sizeof(FFlatVertex), &vbo_shadowdata[0], GL_DYNAMIC_DRAW); + memcpy(map, &vbo_shadowdata[0], vbo_shadowdata.Size() * sizeof(FFlatVertex)); } else if (sectors) { @@ -350,16 +317,14 @@ void FFlatVertexBuffer::CreateVBO() void FFlatVertexBuffer::BindVBO() { - if (vbo_arg > 0) + if (gl.flags & RFL_BUFFER_STORAGE) { - UnmapVBO(); glBindBuffer(GL_ARRAY_BUFFER, vbo_id); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glVertexPointer(3,GL_FLOAT, sizeof(FFlatVertex), &VTO->x); glTexCoordPointer(2,GL_FLOAT, sizeof(FFlatVertex), &VTO->u); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_INDEX_ARRAY); } } @@ -371,20 +336,23 @@ void FFlatVertexBuffer::BindVBO() void FFlatVertexBuffer::CheckPlanes(sector_t *sector) { - if (sector->GetPlaneTexZ(sector_t::ceiling) != sector->vboheight[sector_t::ceiling]) + if (gl.flags & RFL_BUFFER_STORAGE) { - if (sector->ceilingdata == NULL) // only update if there's no thinker attached + if (sector->GetPlaneTexZ(sector_t::ceiling) != sector->vboheight[sector_t::ceiling]) { - UpdatePlaneVertices(sector, sector_t::ceiling); - sector->vboheight[sector_t::ceiling] = sector->GetPlaneTexZ(sector_t::ceiling); + //if (sector->ceilingdata == NULL) // only update if there's no thinker attached + { + UpdatePlaneVertices(sector, sector_t::ceiling); + sector->vboheight[sector_t::ceiling] = sector->GetPlaneTexZ(sector_t::ceiling); + } } - } - if (sector->GetPlaneTexZ(sector_t::floor) != sector->vboheight[sector_t::floor]) - { - if (sector->floordata == NULL) // only update if there's no thinker attached + if (sector->GetPlaneTexZ(sector_t::floor) != sector->vboheight[sector_t::floor]) { - UpdatePlaneVertices(sector, sector_t::floor); - sector->vboheight[sector_t::floor] = sector->GetPlaneTexZ(sector_t::floor); + //if (sector->floordata == NULL) // only update if there's no thinker attached + { + UpdatePlaneVertices(sector, sector_t::floor); + sector->vboheight[sector_t::floor] = sector->GetPlaneTexZ(sector_t::floor); + } } } } diff --git a/src/gl/data/gl_vertexbuffer.h b/src/gl/data/gl_vertexbuffer.h index 49db1c7db..2755b6494 100644 --- a/src/gl/data/gl_vertexbuffer.h +++ b/src/gl/data/gl_vertexbuffer.h @@ -20,11 +20,10 @@ public: virtual void BindVBO() = 0; }; -struct FFlatVertex // exactly 32 bytes large +struct FFlatVertex { - float x,z,y,w; // w only for padding to make one vertex 32 bytes - maybe it will find some use later + float x,z,y; // world position float u,v; // texture coordinates - //float dc, df; // distance to floor and ceiling on walls - used for glowing void SetFlatVertex(vertex_t *vt, const secplane_t &plane); }; @@ -35,27 +34,27 @@ struct FFlatVertex // exactly 32 bytes large class FFlatVertexBuffer : public FVertexBuffer { FFlatVertex *map; + unsigned int mIndex; - void MapVBO(); void CheckPlanes(sector_t *sector); public: int vbo_arg; - TArray vbo_shadowdata; // this is kept around for non-VBO rendering + TArray vbo_shadowdata; // this is kept around for updating the actual (non-readable) buffer -public: FFlatVertexBuffer(); ~FFlatVertexBuffer(); + void CreateVBO(); + void BindVBO(); + void CheckUpdate(sector_t *sector); + +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 CreateFlatVBO(); - void CreateVBO(); void UpdatePlaneVertices(sector_t *sec, int plane); - void BindVBO(); - void CheckUpdate(sector_t *sector); - void UnmapVBO(); }; diff --git a/src/gl/models/gl_voxels.cpp b/src/gl/models/gl_voxels.cpp index f47685216..14ed5985c 100644 --- a/src/gl/models/gl_voxels.cpp +++ b/src/gl/models/gl_voxels.cpp @@ -506,25 +506,27 @@ void FVoxelModel::RenderFrame(FTexture * skin, int frame, int cm, int translatio { FMaterial * tex = FMaterial::ValidateTexture(skin); tex->Bind(cm, 0, translation); - gl_RenderState.Apply(); if (mVBO == NULL) MakeGLData(); if (mVBO != NULL) { - mVBO->BindVBO(); - glDrawElements(GL_QUADS, mIndices.Size(), mVBO->IsInt()? GL_UNSIGNED_INT:GL_UNSIGNED_SHORT, 0); - GLRenderer->mVBO->BindVBO(); - return; + gl_RenderState.SetVertexBuffer(mVBO); + gl_RenderState.Apply(); + glDrawElements(GL_QUADS, mIndices.Size(), mVBO->IsInt() ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0); + gl_RenderState.SetVertexBuffer(GLRenderer->mVBO); } - - glBegin(GL_QUADS); - for(unsigned i=0;i < mIndices.Size(); i++) + else { - FVoxelVertex *vert = &mVertices[mIndices[i]]; - glTexCoord2fv(&vert->u); - glVertex3fv(&vert->x); + gl_RenderState.Apply(); + glBegin(GL_QUADS); + for (unsigned i = 0; i < mIndices.Size(); i++) + { + FVoxelVertex *vert = &mVertices[mIndices[i]]; + glTexCoord2fv(&vert->u); + glVertex3fv(&vert->x); + } + glEnd(); } - glEnd(); } //=========================================================================== diff --git a/src/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp index 73cc5ec90..f0ceb40fa 100644 --- a/src/gl/renderer/gl_renderstate.cpp +++ b/src/gl/renderer/gl_renderstate.cpp @@ -41,6 +41,7 @@ #include "gl/system/gl_system.h" #include "gl/system/gl_interface.h" #include "gl/data/gl_data.h" +#include "gl/data/gl_vertexbuffer.h" #include "gl/system/gl_cvars.h" #include "gl/shaders/gl_shader.h" #include "gl/renderer/gl_renderer.h" @@ -79,6 +80,7 @@ void FRenderState::Reset() mBlendEquation = GL_FUNC_ADD; glBlendEquation = -1; m2D = true; + mVertexBuffer = mCurrentVertexBuffer = NULL; } @@ -300,6 +302,12 @@ void FRenderState::Apply(bool forcenoshader) } } + if (mVertexBuffer != mCurrentVertexBuffer) + { + if (mVertexBuffer == NULL) glBindBuffer(GL_ARRAY_BUFFER, 0); + else mVertexBuffer->BindVBO(); + mCurrentVertexBuffer = mVertexBuffer; + } if (forcenoshader || !ApplyShader()) { GLRenderer->mShaderManager->SetActiveShader(NULL); diff --git a/src/gl/renderer/gl_renderstate.h b/src/gl/renderer/gl_renderstate.h index 061f5c2df..7e611f7a5 100644 --- a/src/gl/renderer/gl_renderstate.h +++ b/src/gl/renderer/gl_renderstate.h @@ -5,6 +5,8 @@ #include "c_cvars.h" #include "r_defs.h" +class FVertexBuffer; + EXTERN_CVAR(Bool, gl_direct_state_change) struct FStateAttr @@ -104,6 +106,8 @@ class FRenderState int mBlendEquation; bool m2D; + FVertexBuffer *mVertexBuffer, *mCurrentVertexBuffer; + FStateVec3 mCameraPos; FStateVec4 mGlowTop, mGlowBottom; FStateVec4 mGlowTopPlane, mGlowBottomPlane; @@ -140,6 +144,11 @@ public: int SetupShader(bool cameratexture, int &shaderindex, int &cm, float warptime); void Apply(bool forcenoshader = false); + void SetVertexBuffer(FVertexBuffer *vb) + { + mVertexBuffer = vb; + } + void SetTextureMode(int mode) { mTextureMode = mode; diff --git a/src/gl/scene/gl_flats.cpp b/src/gl/scene/gl_flats.cpp index 3efdcba8b..7ff3d7110 100644 --- a/src/gl/scene/gl_flats.cpp +++ b/src/gl/scene/gl_flats.cpp @@ -272,7 +272,7 @@ void GLFlat::DrawSubsectors(int pass, bool istrans) } else { - if (vboindex >= 0) + if (gl_usevbo && vboindex >= 0) { //glColor3f( 1.f,.5f,.5f); int index = vboindex; diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 513abaa57..47f990796 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -353,7 +353,6 @@ void FGLRenderer::CreateScene() gl_drawinfo->HandleHackedSubsectors(); // open sector hacks for deep water gl_drawinfo->ProcessSectorStacks(); // merge visplanes of sector stacks - GLRenderer->mVBO->UnmapVBO (); ProcessAll.Unclock(); } @@ -931,7 +930,7 @@ void FGLRenderer::RenderView (player_t* player) LastCamera=player->camera; } - mVBO->BindVBO(); + gl_RenderState.SetVertexBuffer(mVBO); // reset statistics counters ResetProfilingData(); diff --git a/src/gl/system/gl_interface.cpp b/src/gl/system/gl_interface.cpp index 2d311f0bb..25797e4fa 100644 --- a/src/gl/system/gl_interface.cpp +++ b/src/gl/system/gl_interface.cpp @@ -155,41 +155,28 @@ void gl_LoadExtensions() if (CheckExtension("GL_ARB_texture_compression")) gl.flags|=RFL_TEXTURE_COMPRESSION; if (CheckExtension("GL_EXT_texture_compression_s3tc")) gl.flags|=RFL_TEXTURE_COMPRESSION_S3TC; - if (strstr(gl.vendorstring, "NVIDIA")) gl.flags|=RFL_NVIDIA; - else if (strstr(gl.vendorstring, "ATI Technologies")) gl.flags|=RFL_ATI; + if (CheckExtension("GL_ARB_buffer_storage")) gl.flags |= RFL_BUFFER_STORAGE; - if (strcmp(version, "2.0") >= 0) gl.flags|=RFL_GL_20; - if (strcmp(version, "2.1") >= 0) gl.flags|=RFL_GL_21; - if (strcmp(version, "3.0") >= 0) gl.flags|=RFL_GL_30; + gl.version = strtod((char*)glGetString(GL_VERSION), NULL); glGetIntegerv(GL_MAX_TEXTURE_SIZE,&gl.max_texturesize); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - if (gl.flags & RFL_GL_20) - { - // Rules: - // SM4 will always use shaders. No option to switch them off is needed here. - // SM3 has shaders optional but they are off by default (they will have a performance impact - // SM2 only uses shaders for colormaps on camera textures and has no option to use them in general. - // On SM2 cards the shaders will be too slow and show visual bugs (at least on GF 6800.) - if (strcmp((const char*)glGetString(GL_SHADING_LANGUAGE_VERSION), "1.3") >= 0) gl.shadermodel = 4; - else if (CheckExtension("GL_NV_GPU_shader4")) gl.shadermodel = 4; // for pre-3.0 drivers that support GF8xxx. - else if (CheckExtension("GL_EXT_GPU_shader4")) gl.shadermodel = 4; // for pre-3.0 drivers that support GF8xxx. - else if (CheckExtension("GL_NV_vertex_program3")) gl.shadermodel = 3; - else if (!strstr(gl.vendorstring, "NVIDIA")) gl.shadermodel = 3; - else gl.shadermodel = 2; // Only for older NVidia cards which had notoriously bad shader support. + // Rules: + // SM4 will always use shaders. No option to switch them off is needed here. + // SM3 has shaders optional but they are off by default (they will have a performance impact + // SM2 only uses shaders for colormaps on camera textures and has no option to use them in general. + // On SM2 cards the shaders will be too slow and show visual bugs (at least on GF 6800.) + if (strcmp((const char*)glGetString(GL_SHADING_LANGUAGE_VERSION), "1.3") >= 0) gl.shadermodel = 4; + else if (CheckExtension("GL_NV_vertex_program3")) gl.shadermodel = 3; + else if (!strstr(gl.vendorstring, "NVIDIA")) gl.shadermodel = 3; + else gl.shadermodel = 2; // Only for older NVidia cards which had notoriously bad shader support. - // Command line overrides for testing and problem cases. - if (Args->CheckParm("-sm2") && gl.shadermodel > 2) gl.shadermodel = 2; - else if (Args->CheckParm("-sm3") && gl.shadermodel > 3) gl.shadermodel = 3; - } + // Command line overrides for testing and problem cases. + if (Args->CheckParm("-sm2") && gl.shadermodel > 2) gl.shadermodel = 2; + else if (Args->CheckParm("-sm3") && gl.shadermodel > 3) gl.shadermodel = 3; - if (CheckExtension("GL_ARB_map_buffer_range")) - { - gl.flags|=RFL_MAP_BUFFER_RANGE; - } - - if (gl.flags & RFL_GL_30) + if (gl.version >= 3.f) { gl.flags|=RFL_FRAMEBUFFER; } diff --git a/src/gl/system/gl_interface.h b/src/gl/system/gl_interface.h index 79623c07f..fdadd67d9 100644 --- a/src/gl/system/gl_interface.h +++ b/src/gl/system/gl_interface.h @@ -9,16 +9,8 @@ enum RenderFlags RFL_TEXTURE_COMPRESSION=8, RFL_TEXTURE_COMPRESSION_S3TC=16, - RFL_MAP_BUFFER_RANGE = 64, - RFL_FRAMEBUFFER = 128, - RFL_TEXTUREBUFFER = 256, - RFL_NVIDIA = 512, - RFL_ATI = 1024, - - - RFL_GL_20 = 0x10000000, - RFL_GL_21 = 0x20000000, - RFL_GL_30 = 0x40000000, + RFL_FRAMEBUFFER = 32, + RFL_BUFFER_STORAGE = 64, }; enum TexMode @@ -40,6 +32,7 @@ struct RenderContext unsigned int flags; unsigned int shadermodel; unsigned int maxuniforms; + float version; int max_texturesize; char * vendorstring;