From 6a66d0255db59e0b72dfb95d05b8640c4e57858d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 6 Aug 2016 14:12:40 +0200 Subject: [PATCH] - use a dedicated vertex buffer for rendering the wipes. - fixed: The postprocessing shaders clobbered the render state's vertex buffer info by bypassing and not notifying it of the change. --- src/gl/data/gl_vertexbuffer.h | 10 -- src/gl/renderer/gl_postprocess.cpp | 29 +++-- src/gl/renderer/gl_renderer.h | 1 + src/gl/system/gl_framebuffer.h | 8 ++ src/gl/system/gl_interface.cpp | 1 - src/gl/system/gl_wipe.cpp | 203 +++++++++++++++++++---------- 6 files changed, 160 insertions(+), 92 deletions(-) diff --git a/src/gl/data/gl_vertexbuffer.h b/src/gl/data/gl_vertexbuffer.h index c82ea707ba..edb38733a0 100644 --- a/src/gl/data/gl_vertexbuffer.h +++ b/src/gl/data/gl_vertexbuffer.h @@ -98,16 +98,6 @@ public: if (pcount) *pcount = count; } - void RenderScreenQuad(float maxU = 1.0f, float maxV = 1.0f) - { - FFlatVertex *ptr = GetBuffer(); - ptr->Set(-1.0f, -1.0f, 0, 0.0f, 0.0f); ptr++; - ptr->Set(-1.0f, 1.0f, 0, 0.0f, maxV); ptr++; - ptr->Set(1.0f, -1.0f, 0, maxU, 0.0f); ptr++; - ptr->Set(1.0f, 1.0f, 0, maxU, maxV); ptr++; - RenderCurrent(ptr, GL_TRIANGLE_STRIP); - } - #endif void Reset() { diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index da7031afe8..a997f5b479 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -106,6 +106,19 @@ CVAR(Float, gl_lens_chromatic, 1.12f, 0) EXTERN_CVAR(Float, vid_brightness) EXTERN_CVAR(Float, vid_contrast) + +void FGLRenderer::RenderScreenQuad(float maxU, float maxV) +{ + FFlatVertex *ptr = mVBO->GetBuffer(); + mVBO->BindVBO(); + gl_RenderState.ResetVertexBuffer(); + ptr->Set(-1.0f, -1.0f, 0, 0.0f, 0.0f); ptr++; + ptr->Set(-1.0f, 1.0f, 0, 0.0f, maxV); ptr++; + ptr->Set(1.0f, -1.0f, 0, maxU, 0.0f); ptr++; + ptr->Set(1.0f, 1.0f, 0, maxU, maxV); ptr++; + mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); +} + //----------------------------------------------------------------------------- // // Adds bloom contribution to scene texture @@ -134,8 +147,7 @@ void FGLRenderer::BloomScene() mBloomExtractShader->Bind(); mBloomExtractShader->SceneTexture.Set(0); mBloomExtractShader->Exposure.Set(mCameraExposure); - mVBO->BindVBO(); - mVBO->RenderScreenQuad(); + RenderScreenQuad(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -166,7 +178,7 @@ void FGLRenderer::BloomScene() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); mBloomCombineShader->Bind(); mBloomCombineShader->BloomTexture.Set(0); - mVBO->RenderScreenQuad(); + RenderScreenQuad(); } mBlurShader->BlurHorizontal(mVBO, blurAmount, sampleCount, level0.VTexture, level0.HFramebuffer, level0.Width, level0.Height); @@ -184,7 +196,7 @@ void FGLRenderer::BloomScene() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); mBloomCombineShader->Bind(); mBloomCombineShader->BloomTexture.Set(0); - mVBO->RenderScreenQuad(); + RenderScreenQuad(); } //----------------------------------------------------------------------------- @@ -205,8 +217,7 @@ void FGLRenderer::TonemapScene() mTonemapShader->Bind(); mTonemapShader->SceneTexture.Set(0); mTonemapShader->Exposure.Set(mCameraExposure); - mVBO->BindVBO(); - mVBO->RenderScreenQuad(); + RenderScreenQuad(); mBuffers->NextTexture(); } @@ -258,8 +269,7 @@ void FGLRenderer::LensDistortScene() mLensShader->Scale.Set(scale); mLensShader->LensDistortionCoefficient.Set(k); mLensShader->CubicDistortionValue.Set(kcube); - mVBO->BindVBO(); - mVBO->RenderScreenQuad(); + RenderScreenQuad(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); mBuffers->NextTexture(); @@ -348,7 +358,6 @@ void FGLRenderer::CopyToBackbuffer(const GL_IRECT *bounds, bool applyGamma) mBuffers->BindCurrentTexture(0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - mVBO->BindVBO(); - mVBO->RenderScreenQuad(mScreenViewport.width / (float)mBuffers->GetWidth(), mScreenViewport.height / (float)mBuffers->GetHeight()); + RenderScreenQuad(mScreenViewport.width / (float)mBuffers->GetWidth(), mScreenViewport.height / (float)mBuffers->GetHeight()); } } diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 9be66bbfb1..9caace177d 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -157,6 +157,7 @@ public: unsigned char *GetTextureBuffer(FTexture *tex, int &w, int &h); void SetupLevel(); + void RenderScreenQuad(float maxU = 1.0f, float maxV = 1.0f); void SetFixedColormap (player_t *player); void WriteSavePic (player_t *player, FILE *file, int width, int height); void EndDrawScene(sector_t * viewsector); diff --git a/src/gl/system/gl_framebuffer.h b/src/gl/system/gl_framebuffer.h index 3da60fac42..2ba90ff5b1 100644 --- a/src/gl/system/gl_framebuffer.h +++ b/src/gl/system/gl_framebuffer.h @@ -94,7 +94,15 @@ private: class Wiper { + class WipeVertexBuffer; + + protected: + WipeVertexBuffer *mVertexBuf; + + void MakeVBO(OpenGLFrameBuffer *fb); + public: + Wiper(); virtual ~Wiper(); virtual bool Run(int ticks, OpenGLFrameBuffer *fb) = 0; }; diff --git a/src/gl/system/gl_interface.cpp b/src/gl/system/gl_interface.cpp index bf926cd93d..6b1105ee48 100644 --- a/src/gl/system/gl_interface.cpp +++ b/src/gl/system/gl_interface.cpp @@ -197,7 +197,6 @@ void gl_LoadExtensions() { //if (CheckExtension("GL_NV_GPU_shader4") || CheckExtension("GL_EXT_GPU_shader4")) gl.glslversion = 1.21f; // for pre-3.0 drivers that support capable hardware. Needed for Apple. //else gl.glslversion = 0; - gl.glslversion = 1.21f; if (!CheckExtension("GL_EXT_packed_float")) gl.flags |= RFL_NO_RGBA16F; if (!CheckExtension("GL_EXT_packed_depth_stencil")) gl.flags |= RFL_NO_DEPTHSTENCIL; diff --git a/src/gl/system/gl_wipe.cpp b/src/gl/system/gl_wipe.cpp index 0d1973131e..bc1708061b 100644 --- a/src/gl/system/gl_wipe.cpp +++ b/src/gl/system/gl_wipe.cpp @@ -97,6 +97,7 @@ class OpenGLFrameBuffer::Wiper_Melt : public OpenGLFrameBuffer::Wiper { public: Wiper_Melt(); + int MakeVBO(int ticks, OpenGLFrameBuffer *fb, bool &done); bool Run(int ticks, OpenGLFrameBuffer *fb); private: @@ -217,29 +218,28 @@ void OpenGLFrameBuffer::WipeEndScreen() bool OpenGLFrameBuffer::WipeDo(int ticks) { + bool done = true; // Sanity checks. - if (wipestartscreen == NULL || wipeendscreen == NULL) + if (wipestartscreen != nullptr && wipeendscreen != nullptr) { - return true; + Lock(true); + + gl_RenderState.EnableTexture(true); + gl_RenderState.EnableFog(false); + glDisable(GL_DEPTH_TEST); + glDepthMask(false); + + if (FGLRenderBuffers::IsEnabled()) + { + GLRenderer->mBuffers->BindCurrentFB(); + const auto &bounds = GLRenderer->mScreenViewport; + glViewport(bounds.left, bounds.top, bounds.width, bounds.height); + } + + done = ScreenWipe->Run(ticks, this); + glDepthMask(true); } - - Lock(true); - - gl_RenderState.EnableTexture(true); - gl_RenderState.EnableFog(false); - glDisable(GL_DEPTH_TEST); - glDepthMask(false); - - if (FGLRenderBuffers::IsEnabled()) - { - GLRenderer->mBuffers->BindCurrentFB(); - const auto &bounds = GLRenderer->mScreenViewport; - glViewport(bounds.left, bounds.top, bounds.width, bounds.height); - } - - bool done = ScreenWipe->Run(ticks, this); - glDepthMask(true); - //DrawLetterbox(); + gl_RenderState.SetVertexBuffer(GLRenderer->mVBO); return done; } @@ -273,12 +273,80 @@ void OpenGLFrameBuffer::WipeCleanup() //========================================================================== // -// OpenGLFrameBuffer :: Wiper Constructor +// The wiper vertex buffer +// +// Note that this will recreate the buffer each frame, although +// only for melt its contents will change. +// +// But since this is no time critical code, ease of implementation +// was chosen over maximum efficiency. // //========================================================================== +class OpenGLFrameBuffer::Wiper::WipeVertexBuffer : public FVertexBuffer +{ +public: + WipeVertexBuffer() + { + } + void BindVBO() + { + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + if (gl.glslversion > 0) + { + glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FFlatVertex), &VTO->x); + glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, false, sizeof(FFlatVertex), &VTO->u); + glDisableVertexAttribArray(VATTR_COLOR); + glDisableVertexAttribArray(VATTR_VERTEX2); + } + else + { + 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_COLOR_ARRAY); + } + } + void set(FFlatVertex *verts, int count) + { + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + gl_RenderState.SetVertexBuffer(this); + glBufferData(GL_ARRAY_BUFFER, count * sizeof(*verts), verts, GL_STREAM_DRAW); + } +}; + +//========================================================================== +// +// OpenGLFrameBuffer :: Wiper Constructor +// +//========================================================================== +OpenGLFrameBuffer::Wiper::Wiper() +{ + mVertexBuf = new WipeVertexBuffer; +} + OpenGLFrameBuffer::Wiper::~Wiper() { + delete mVertexBuf; +} + +void OpenGLFrameBuffer::Wiper::MakeVBO(OpenGLFrameBuffer *fb) +{ + FFlatVertex make[4]; + FFlatVertex *ptr = make; + + float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth()); + float vb = fb->GetHeight() / FHardwareTexture::GetTexDimension(fb->GetHeight()); + + ptr->Set(0, 0, 0, 0, vb); + ptr++; + ptr->Set(0, fb->Height, 0, 0, 0); + ptr++; + ptr->Set(fb->Width, 0, 0, ur, vb); + ptr++; + ptr->Set(fb->Width, fb->Height, 0, ur, 0); + mVertexBuf->set(make, 4); } // WIPE: CROSSFADE --------------------------------------------------------- @@ -306,32 +374,21 @@ bool OpenGLFrameBuffer::Wiper_Crossfade::Run(int ticks, OpenGLFrameBuffer *fb) { Clock += ticks; - float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth()); - float vb = fb->GetHeight() / FHardwareTexture::GetTexDimension(fb->GetHeight()); + MakeVBO(fb); gl_RenderState.SetTextureMode(TM_OPAQUE); gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f); gl_RenderState.ResetColor(); gl_RenderState.Apply(); fb->wipestartscreen->Bind(0, 0, false); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - FFlatVertex *ptr; - unsigned int offset, count; - ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(0, 0, 0, 0, vb); - ptr++; - ptr->Set(0, fb->Height, 0, 0, 0); - ptr++; - ptr->Set(fb->Width, 0, 0, ur, vb); - ptr++; - ptr->Set(fb->Width, fb->Height, 0, ur, 0); - ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP, &offset, &count); - - fb->wipeendscreen->Bind(0, 0, false); - gl_RenderState.SetColorAlpha(0xffffff, clamp(Clock/32.f, 0.f, 1.f)); + float a = clamp(Clock / 32.f, 0.f, 1.f); + Printf("%f\n", a); + gl_RenderState.SetColorAlpha(0xffffff, a); gl_RenderState.Apply(); - GLRenderer->mVBO->RenderArray(GL_TRIANGLE_STRIP, offset, count); + fb->wipeendscreen->Bind(0, 0, false); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); gl_RenderState.AlphaFunc(GL_GEQUAL, 0.5f); gl_RenderState.SetTextureMode(TM_MODULATE); @@ -366,18 +423,15 @@ OpenGLFrameBuffer::Wiper_Melt::Wiper_Melt() // //========================================================================== -bool OpenGLFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLFrameBuffer *fb) +int OpenGLFrameBuffer::Wiper_Melt::MakeVBO(int ticks, OpenGLFrameBuffer *fb, bool &done) { + FFlatVertex *make = new FFlatVertex[321*4]; + FFlatVertex *ptr = make; + int dy; + float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth()); float vb = fb->GetHeight() / FHardwareTexture::GetTexDimension(fb->GetHeight()); - // Draw the new screen on the bottom. - gl_RenderState.SetTextureMode(TM_OPAQUE); - gl_RenderState.ResetColor(); - gl_RenderState.Apply(); - fb->wipeendscreen->Bind(0, 0, false); - FFlatVertex *ptr; - ptr = GLRenderer->mVBO->GetBuffer(); ptr->Set(0, 0, 0, 0, vb); ptr++; ptr->Set(0, fb->Height, 0, 0, 0); @@ -386,31 +440,26 @@ bool OpenGLFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLFrameBuffer *fb) ptr++; ptr->Set(fb->Width, fb->Height, 0, ur, 0); ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); - int i, dy; - bool done = false; - - fb->wipestartscreen->Bind(0, 0, false); // Copy the old screen in vertical strips on top of the new one. while (ticks--) { done = true; - for (i = 0; i < WIDTH; i++) + for (int i = 0; i < WIDTH; i++) { if (y[i] < 0) { y[i]++; done = false; - } + } else if (y[i] < HEIGHT) { - dy = (y[i] < 16) ? y[i]+1 : 8; + dy = (y[i] < 16) ? y[i] + 1 : 8; y[i] = MIN(y[i] + dy, HEIGHT); done = false; } if (ticks == 0) - { + { // Only draw for the final tick. // No need for optimization. Wipes won't ever be drawn with anything else. RECT rect; @@ -429,7 +478,6 @@ bool OpenGLFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLFrameBuffer *fb) rect.bottom = fb->Height - rect.bottom; rect.top = fb->Height - rect.top; - ptr = GLRenderer->mVBO->GetBuffer(); ptr->Set(rect.left, rect.bottom, 0, rect.left / tw, rect.top / th); ptr++; ptr->Set(rect.left, rect.top, 0, rect.left / tw, rect.bottom / th); @@ -438,12 +486,34 @@ bool OpenGLFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLFrameBuffer *fb) ptr++; ptr->Set(rect.right, rect.top, 0, rect.right / tw, rect.bottom / th); ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); } } } } + int numverts = int(ptr - make); + mVertexBuf->set(make, numverts); + delete[] make; + return numverts; +} + +bool OpenGLFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLFrameBuffer *fb) +{ + bool done = false; + int maxvert = MakeVBO(ticks, fb, done); + + // Draw the new screen on the bottom. + gl_RenderState.SetTextureMode(TM_OPAQUE); + gl_RenderState.ResetColor(); + gl_RenderState.Apply(); + fb->wipeendscreen->Bind(0, 0, false); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + fb->wipestartscreen->Bind(0, 0, false); gl_RenderState.SetTextureMode(TM_MODULATE); + for (int i = 4; i < maxvert; i += 4) + { + glDrawArrays(GL_TRIANGLE_STRIP, i, 4); + } return done; } @@ -486,6 +556,8 @@ bool OpenGLFrameBuffer::Wiper_Burn::Run(int ticks, OpenGLFrameBuffer *fb) { bool done; + MakeVBO(fb); + BurnTime += ticks; ticks *= 2; @@ -524,18 +596,7 @@ bool OpenGLFrameBuffer::Wiper_Burn::Run(int ticks, OpenGLFrameBuffer *fb) gl_RenderState.ResetColor(); gl_RenderState.Apply(); fb->wipestartscreen->Bind(0, 0, false); - FFlatVertex *ptr; - unsigned int offset, count; - ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(0, 0, 0, 0, vb); - ptr++; - ptr->Set(0, fb->Height, 0, 0, 0); - ptr++; - ptr->Set(fb->Width, 0, 0, ur, vb); - ptr++; - ptr->Set(fb->Width, fb->Height, 0, ur, 0); - ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP, &offset, &count); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); gl_RenderState.SetTextureMode(TM_MODULATE); gl_RenderState.SetEffect(EFF_BURN); @@ -547,7 +608,7 @@ bool OpenGLFrameBuffer::Wiper_Burn::Run(int ticks, OpenGLFrameBuffer *fb) BurnTexture->CreateTexture(rgb_buffer, WIDTH, HEIGHT, 1, true, 0); - GLRenderer->mVBO->RenderArray(GL_TRIANGLE_STRIP, offset, count); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); gl_RenderState.SetEffect(EFF_NONE); // The fire may not always stabilize, so the wipe is forced to end