From 3e4dcbe2b4361e856121112085d70f9f85b41f94 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 24 Oct 2018 00:19:07 +0200 Subject: [PATCH] - groundwork for separating the portal data from the renderer. With GLPortal being responsible for all the setup a lot of code was tied to the backend. Now FDrawInfo will manage the setup and only call pure data generation functions in the actual portal object. --- src/gl/scene/gl_drawinfo.cpp | 43 ++++++ src/gl/scene/gl_drawinfo.h | 3 + src/gl/scene/gl_portal.cpp | 240 ++++++++--------------------- src/gl/scene/gl_portal.h | 9 +- src/hwrenderer/scene/hw_drawinfo.h | 7 +- src/hwrenderer/scene/hw_portal.cpp | 19 ++- src/hwrenderer/scene/hw_portal.h | 20 +-- 7 files changed, 131 insertions(+), 210 deletions(-) diff --git a/src/gl/scene/gl_drawinfo.cpp b/src/gl/scene/gl_drawinfo.cpp index 33c471428..f1aa10d36 100644 --- a/src/gl/scene/gl_drawinfo.cpp +++ b/src/gl/scene/gl_drawinfo.cpp @@ -40,6 +40,7 @@ #include "hwrenderer/scene/hw_clipper.h" #include "gl/scene/gl_portal.h" #include "gl/renderer/gl_renderstate.h" +#include "gl/data/gl_viewpointbuffer.h" #include "gl/dynlights/gl_lightbuffer.h" #include "gl/models/gl_models.h" @@ -311,6 +312,18 @@ void FDrawInfo::DrawHUDModel(HUDSprite *huds, FRenderState &state) renderer.RenderHUDModel(huds->weapon, huds->mx, huds->my); } +void FDrawInfo::RenderPortal(IPortal *p, bool usestencil) +{ + auto gp = static_cast(p); + gp->SetupStencil(this, gl_RenderState, usestencil); + auto new_di = StartDrawInfo(Viewpoint, &VPUniforms); + new_di->mCurrentPortal = gp; + gp->DrawContents(new_di); + new_di->EndDrawInfo(); + GLRenderer->mViewpoints->Bind(vpIndex); + gp->RemoveStencil(this, gl_RenderState, usestencil); + +} void FDrawInfo::SetDepthMask(bool on) { @@ -323,6 +336,11 @@ void FDrawInfo::SetDepthFunc(int func) glDepthFunc(df2gl[func]); } +void FDrawInfo::SetDepthRange(float min, float max) +{ + glDepthRange(min, max); +} + void FDrawInfo::EnableDrawBufferAttachments(bool on) { gl_RenderState.EnableDrawBuffers(on? gl_RenderState.GetPassDrawBufferCount() : 1); @@ -342,6 +360,31 @@ void FDrawInfo::SetStencil(int offs, int op, int flags) glDisable(GL_DEPTH_TEST); else glEnable(GL_DEPTH_TEST); + if (flags & SF_DepthClear) + glClear(GL_DEPTH_BUFFER_BIT); +} + + +//========================================================================== +// +// +// +//========================================================================== +void FDrawInfo::ClearScreen() +{ + bool multi = !!glIsEnabled(GL_MULTISAMPLE); + + GLRenderer->mViewpoints->Set2D(SCREENWIDTH, SCREENHEIGHT); + gl_RenderState.SetColor(0, 0, 0); + gl_RenderState.Apply(); + + glDisable(GL_MULTISAMPLE); + glDisable(GL_DEPTH_TEST); + + glDrawArrays(GL_TRIANGLE_STRIP, FFlatVertexBuffer::FULLSCREEN_INDEX, 4); + + glEnable(GL_DEPTH_TEST); + if (multi) glEnable(GL_MULTISAMPLE); } diff --git a/src/gl/scene/gl_drawinfo.h b/src/gl/scene/gl_drawinfo.h index fbcd9758c..3706e24e6 100644 --- a/src/gl/scene/gl_drawinfo.h +++ b/src/gl/scene/gl_drawinfo.h @@ -47,9 +47,11 @@ struct FDrawInfo : public HWDrawInfo void DrawIndexed(EDrawType dt, FRenderState &state, int index, int count, bool apply = true) override; void DrawModel(GLSprite *spr, FRenderState &state) override; void DrawHUDModel(HUDSprite *spr, FRenderState &state) override; + void RenderPortal(IPortal *p, bool stencil) override; void SetDepthMask(bool on) override; void SetDepthFunc(int func) override; + void SetDepthRange(float min, float max) override; void EnableDrawBufferAttachments(bool on) override; void SetStencil(int offs, int op, int flags) override; @@ -69,6 +71,7 @@ struct FDrawInfo : public HWDrawInfo void EndDrawScene(sector_t * viewsector); void DrawEndScene2D(sector_t * viewsector); bool SetDepthClamp(bool on) override; + void ClearScreen() override; static FDrawInfo *StartDrawInfo(FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms); FDrawInfo *EndDrawInfo(); diff --git a/src/gl/scene/gl_portal.cpp b/src/gl/scene/gl_portal.cpp index cafe2bc69..3ac86b27b 100644 --- a/src/gl/scene/gl_portal.cpp +++ b/src/gl/scene/gl_portal.cpp @@ -54,38 +54,14 @@ //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -EXTERN_CVAR(Bool, gl_portals) -EXTERN_CVAR(Bool, gl_noquery) EXTERN_CVAR(Int, r_mirror_recursions) -//========================================================================== -// -// -// -//========================================================================== -void GLPortal::ClearScreen(HWDrawInfo *di) -{ - bool multi = !!glIsEnabled(GL_MULTISAMPLE); - - GLRenderer->mViewpoints->Set2D(SCREENWIDTH, SCREENHEIGHT); - gl_RenderState.SetColor(0, 0, 0); - gl_RenderState.Apply(); - - glDisable(GL_MULTISAMPLE); - glDisable(GL_DEPTH_TEST); - - glDrawArrays(GL_TRIANGLE_STRIP, FFlatVertexBuffer::FULLSCREEN_INDEX, 4); - - glEnable(GL_DEPTH_TEST); - if (multi) glEnable(GL_MULTISAMPLE); -} - //----------------------------------------------------------------------------- // // DrawPortalStencil // //----------------------------------------------------------------------------- -void GLPortal::DrawPortalStencil(int pass) +void GLPortal::DrawPortalStencil(HWDrawInfo *di, FRenderState &state, int pass) { if (mPrimIndices.Size() == 0) { @@ -97,18 +73,17 @@ void GLPortal::DrawPortalStencil(int pass) mPrimIndices[i * 2 + 1] = lines[i].vertcount; } } - gl_RenderState.Apply(); for (unsigned int i = 0; i < mPrimIndices.Size(); i += 2) { - GLRenderer->mVBO->RenderArray(GL_TRIANGLE_FAN, mPrimIndices[i], mPrimIndices[i + 1]); + di->Draw(DT_TriangleFan, state, mPrimIndices[i], mPrimIndices[i + 1], i==0); } if (NeedCap() && lines.Size() > 1) { - if (pass == STP_AllInOne) glDepthMask(false); - else if (pass == STP_DepthRestore) glDepthRange(1, 1); - GLRenderer->mVBO->RenderArray(GL_TRIANGLE_FAN, FFlatVertexBuffer::STENCILTOP_INDEX, 4); - GLRenderer->mVBO->RenderArray(GL_TRIANGLE_FAN, FFlatVertexBuffer::STENCILBOTTOM_INDEX, 4); - if (pass == STP_DepthRestore) glDepthRange(0, 1); + // The cap's depth handling needs special treatment so that it won't block further portal caps. + if (pass == STP_DepthRestore) di->SetDepthRange(1, 1); + di->Draw(DT_TriangleFan, state, FFlatVertexBuffer::STENCILTOP_INDEX, 4); + di->Draw(DT_TriangleFan, state, FFlatVertexBuffer::STENCILBOTTOM_INDEX, 4); + if (pass == STP_DepthRestore) di->SetDepthRange(0, 1); } } @@ -120,58 +95,46 @@ void GLPortal::DrawPortalStencil(int pass) void GLPortal::SetupStencil(HWDrawInfo *di, FRenderState &state, bool usestencil) { + Clocker c(PortalAll); + + rendered_portals++; if (usestencil) { - // Create stencil - glStencilFunc(GL_EQUAL, screen->stencilValue, ~0); // create stencil - glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // increment stencil of valid pixels - glColorMask(0, 0, 0, 0); // don't write to the graphics buffer - gl_RenderState.SetEffect(EFF_STENCIL); - gl_RenderState.EnableTexture(false); - gl_RenderState.ResetColor(); - glDepthFunc(GL_LESS); - gl_RenderState.Apply(); + state.SetEffect(EFF_STENCIL); + state.EnableTexture(false); + state.ResetColor(); if (NeedDepthBuffer()) { - glDepthMask(false); // don't write to Z-buffer! - - DrawPortalStencil(STP_Stencil); + di->SetStencil(0, SOP_Increment, SF_ColorMaskOff | SF_DepthMaskOff); + di->SetDepthFunc(DF_Less); + DrawPortalStencil(di, state, STP_Stencil); // Clear Z-buffer - glStencilFunc(GL_EQUAL, screen->stencilValue + 1, ~0); // draw sky into stencil - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // this stage doesn't modify the stencil - glDepthMask(true); // enable z-buffer again - glDepthRange(1, 1); - glDepthFunc(GL_ALWAYS); - DrawPortalStencil(STP_DepthClear); + di->SetStencil(1, SOP_Keep, SF_ColorMaskOff); + di->SetDepthRange(1, 1); + di->SetDepthFunc(DF_Always); + DrawPortalStencil(di, state, STP_DepthClear); // set normal drawing mode - gl_RenderState.EnableTexture(true); - glDepthFunc(GL_LESS); - glColorMask(1, 1, 1, 1); - gl_RenderState.SetEffect(EFF_NONE); - glDepthRange(0, 1); - - GLuint sampleCount = 1; + state.EnableTexture(true); + di->SetStencil(1, SOP_Keep, SF_AllOn); + di->SetDepthRange(0, 1); + di->SetDepthFunc(DF_Less); + state.SetEffect(EFF_NONE); } else { // No z-buffer is needed therefore we can skip all the complicated stuff that is involved - // No occlusion queries will be done here. For these portals the overhead is far greater - // than the benefit. // Note: We must draw the stencil with z-write enabled here because there is no second pass! + di->SetStencil(0, SOP_Increment, SF_ColorMaskOff); + di->SetDepthFunc(DF_Less); + DrawPortalStencil(di, state, STP_AllInOne); - glDepthMask(true); - DrawPortalStencil(STP_AllInOne); - glStencilFunc(GL_EQUAL, screen->stencilValue + 1, ~0); // draw sky into stencil - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // this stage doesn't modify the stencil - gl_RenderState.EnableTexture(true); - glColorMask(1, 1, 1, 1); - gl_RenderState.SetEffect(EFF_NONE); - glDisable(GL_DEPTH_TEST); - glDepthMask(false); // don't write to Z-buffer! + di->SetStencil(1, SOP_Keep, SF_DepthTestOff | SF_DepthMaskOff); + state.EnableTexture(true); + state.SetEffect(EFF_NONE); } screen->stencilValue++; @@ -180,139 +143,66 @@ void GLPortal::SetupStencil(HWDrawInfo *di, FRenderState &state, bool usestencil { if (!NeedDepthBuffer()) { - glDepthMask(false); - glDisable(GL_DEPTH_TEST); + di->SetStencil(0, SOP_Keep, SF_DepthTestOff | SF_DepthMaskOff); } } + + // save viewpoint + savedvisibility = di->Viewpoint.camera ? di->Viewpoint.camera->renderflags & RF_MAYBEINVISIBLE : ActorRenderFlags::FromInt(0); } void GLPortal::RemoveStencil(HWDrawInfo *di, FRenderState &state, bool usestencil) { + Clocker c(PortalAll); bool needdepth = NeedDepthBuffer(); + // Restore the old view + auto &vp = di->Viewpoint; + if (vp.camera != nullptr) vp.camera->renderflags = (vp.camera->renderflags & ~RF_MAYBEINVISIBLE) | savedvisibility; + if (usestencil) { - glColorMask(0, 0, 0, 0); // no graphics - gl_RenderState.SetEffect(EFF_NONE); - gl_RenderState.ResetColor(); - gl_RenderState.EnableTexture(false); - gl_RenderState.Apply(); + state.SetEffect(EFF_NONE); + state.ResetColor(); + state.EnableTexture(false); if (needdepth) { // first step: reset the depth buffer to max. depth - glDepthRange(1, 1); // always - glDepthFunc(GL_ALWAYS); // write the farthest depth value - DrawPortalStencil(STP_DepthClear); - } - else - { - glEnable(GL_DEPTH_TEST); + di->SetStencil(0, SOP_Keep, SF_ColorMaskOff); + di->SetDepthRange(1, 1); // always + di->SetDepthFunc(DF_Always); // write the farthest depth value + DrawPortalStencil(di, state, STP_DepthClear); } // second step: restore the depth buffer to the previous values and reset the stencil - glDepthFunc(GL_LEQUAL); - glDepthRange(0, 1); - glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); - glStencilFunc(GL_EQUAL, screen->stencilValue, ~0); // draw sky into stencil - DrawPortalStencil(STP_DepthRestore); - glDepthFunc(GL_LESS); + di->SetStencil(0, SOP_Decrement, SF_ColorMaskOff); + di->SetDepthRange(0, 1); + di->SetDepthFunc(DF_LEqual); + DrawPortalStencil(di, state, STP_DepthRestore); - - gl_RenderState.EnableTexture(true); - gl_RenderState.SetEffect(EFF_NONE); - glColorMask(1, 1, 1, 1); + state.EnableTexture(true); + state.SetEffect(EFF_NONE); screen->stencilValue--; - - // restore old stencil op. - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glStencilFunc(GL_EQUAL, screen->stencilValue, ~0); // draw sky into stencil } else { - if (needdepth) - { - glClear(GL_DEPTH_BUFFER_BIT); - } - else - { - glEnable(GL_DEPTH_TEST); - glDepthMask(true); - } - auto &vp = di->Viewpoint; + state.ResetColor(); + state.SetEffect(EFF_STENCIL); + state.EnableTexture(false); + state.SetRenderStyle(STYLE_Source); - // Restore the old view - if (vp.camera != nullptr) vp.camera->renderflags = (vp.camera->renderflags & ~RF_MAYBEINVISIBLE) | savedvisibility; + di->SetStencil(0, SOP_Keep, needdepth? SF_ColorMaskOff | SF_DepthClear : SF_ColorMaskOff); + di->SetDepthRange(0, 1); + di->SetDepthFunc(DF_LEqual); + DrawPortalStencil(di, state, STP_DepthRestore); - // This draws a valid z-buffer into the stencil's contents to ensure it - // doesn't get overwritten by the level's geometry. - - gl_RenderState.ResetColor(); - glDepthFunc(GL_LEQUAL); - glDepthRange(0, 1); - glColorMask(0, 0, 0, 1); // mark portal in alpha channel but don't touch color - gl_RenderState.SetEffect(EFF_STENCIL); - gl_RenderState.EnableTexture(false); - gl_RenderState.SetRenderStyle(STYLE_Source); - gl_RenderState.Apply(); - DrawPortalStencil(STP_DepthRestore); - gl_RenderState.SetEffect(EFF_NONE); - gl_RenderState.EnableTexture(true); - glColorMask(1, 1, 1, 1); // mark portal in alpha channel but don't touch color - - glDepthFunc(GL_LESS); + state.SetEffect(EFF_NONE); + state.EnableTexture(true); } + di->SetStencil(0, SOP_Keep, SF_AllOn); } -//----------------------------------------------------------------------------- -// -// Start -// -//----------------------------------------------------------------------------- - -bool GLPortal::Start(bool usestencil, bool doquery, HWDrawInfo *outer_di, HWDrawInfo **pDi) -{ - *pDi = nullptr; - rendered_portals++; - Clocker c(PortalAll); - - if (!gl_portals) - { - return false; - } - - SetupStencil(outer_di, gl_RenderState, usestencil); - - *pDi = FDrawInfo::StartDrawInfo(outer_di->Viewpoint, &outer_di->VPUniforms); - (*pDi)->mCurrentPortal = this; - - // save viewpoint - savedvisibility = outer_di->Viewpoint.camera ? outer_di->Viewpoint.camera->renderflags & RF_MAYBEINVISIBLE : ActorRenderFlags::FromInt(0); - - return true; -} - - -//----------------------------------------------------------------------------- -// -// End -// -//----------------------------------------------------------------------------- -void GLPortal::End(HWDrawInfo *di, bool usestencil) -{ - Clocker c(PortalAll); - - di = static_cast(di)->EndDrawInfo(); - GLRenderer->mViewpoints->Bind(static_cast(di)->vpIndex); - auto &vp = di->Viewpoint; - - // Restore the old view - if (vp.camera != nullptr) vp.camera->renderflags = (vp.camera->renderflags & ~RF_MAYBEINVISIBLE) | savedvisibility; - - RemoveStencil(di, gl_RenderState, usestencil); -} - - //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // @@ -402,7 +292,7 @@ void GLHorizonPortal::DrawContents(HWDrawInfo *hwdi) gltexture=FMaterial::ValidateTexture(sp->texture, false, true); if (!gltexture) { - ClearScreen(di); + di->ClearScreen(); return; } di->SetCameraPos(vp.Pos); diff --git a/src/gl/scene/gl_portal.h b/src/gl/scene/gl_portal.h index a4ab20b8e..e9adb4222 100644 --- a/src/gl/scene/gl_portal.h +++ b/src/gl/scene/gl_portal.h @@ -58,11 +58,12 @@ private: STP_DepthRestore, STP_AllInOne }; - void DrawPortalStencil(int pass); + void DrawPortalStencil(HWDrawInfo *di, FRenderState &state, int pass); ActorRenderFlags savedvisibility; TArray mPrimIndices; +public: void SetupStencil(HWDrawInfo *di, FRenderState &state, bool usestencil); void RemoveStencil(HWDrawInfo *di, FRenderState &state, bool usestencil); @@ -70,10 +71,6 @@ protected: int level; GLPortal(FPortalSceneState *state, bool local = false) : IPortal(state, local) { } - - bool Start(bool usestencil, bool doquery, HWDrawInfo *outer_di, HWDrawInfo **pDi) override; - void End(HWDrawInfo *di, bool usestencil) override; - void ClearScreen(HWDrawInfo *di); }; class GLScenePortal : public GLPortal @@ -98,7 +95,7 @@ public: static_cast(di)->DrawScene(DM_PORTAL); mScene->Shutdown(di); } - else ClearScreen(di); + else di->ClearScreen(); } virtual void RenderAttached(HWDrawInfo *di) { return mScene->RenderAttached(di); } }; diff --git a/src/hwrenderer/scene/hw_drawinfo.h b/src/hwrenderer/scene/hw_drawinfo.h index ccf00fc4f..0cf112c63 100644 --- a/src/hwrenderer/scene/hw_drawinfo.h +++ b/src/hwrenderer/scene/hw_drawinfo.h @@ -29,7 +29,8 @@ enum EStencilFlags SF_AllOn = 0, SF_ColorMaskOff = 1, SF_DepthMaskOff = 2, - SF_DepthTestOff = 4 + SF_DepthTestOff = 4, + SF_DepthClear = 8 }; enum EStencilOp @@ -332,16 +333,18 @@ public: virtual std::pair AllocVertices(unsigned int count) = 0; + virtual void ClearScreen() = 0; virtual void Draw(EDrawType dt, FRenderState &state, int index, int count, bool apply = true) = 0; virtual void DrawIndexed(EDrawType dt, FRenderState &state, int index, int count, bool apply = true) = 0; virtual void DrawModel(GLSprite *spr, FRenderState &state) = 0; virtual void DrawHUDModel(HUDSprite *spr, FRenderState &state) = 0; - + virtual void RenderPortal(IPortal *p, bool usestencil) = 0; // Immediate render state change commands. These only change infrequently and should not clutter the render state. virtual void SetDepthMask(bool on) = 0; virtual void SetDepthFunc(int func) = 0; + virtual void SetDepthRange(float min, float max) = 0; virtual void EnableDrawBufferAttachments(bool on) = 0; virtual void SetStencil(int offs, int op, int flags) = 0; diff --git a/src/hwrenderer/scene/hw_portal.cpp b/src/hwrenderer/scene/hw_portal.cpp index 84cca96d7..8980588ca 100644 --- a/src/hwrenderer/scene/hw_portal.cpp +++ b/src/hwrenderer/scene/hw_portal.cpp @@ -34,6 +34,7 @@ #include "g_levellocals.h" EXTERN_CVAR(Int, r_mirror_recursions) +EXTERN_CVAR(Bool, gl_portals) //----------------------------------------------------------------------------- // @@ -82,20 +83,15 @@ void FPortalSceneState::EndFrame(HWDrawInfo *di) indent += " "; } - // Only use occlusion query if there are more than 2 portals. - // Otherwise there's too much overhead. - // (And don't forget to consider the separating null pointers!) - bool usequery = di->Portals.Size() > 2 + (unsigned)renderdepth; - while (di->Portals.Pop(p) && p) { if (gl_portalinfo) { - Printf("%sProcessing %s, depth = %d, query = %d\n", indent.GetChars(), p->GetName(), renderdepth, usequery); + Printf("%sProcessing %s, depth = %d\n", indent.GetChars(), p->GetName(), renderdepth); } if (p->lines.Size() > 0) { - p->RenderPortal(true, usequery, di); + RenderPortal(p, true, di); } delete p; } @@ -146,13 +142,20 @@ bool FPortalSceneState::RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di if (best) { portals.Delete(bestindex); - best->RenderPortal(false, false, outer_di); + RenderPortal(best, false, outer_di); delete best; return true; } return false; } + +void FPortalSceneState::RenderPortal(IPortal *p, bool usestencil, HWDrawInfo *outer_di) +{ + if (gl_portals) outer_di->RenderPortal(p, usestencil); +} + + //----------------------------------------------------------------------------- // // diff --git a/src/hwrenderer/scene/hw_portal.h b/src/hwrenderer/scene/hw_portal.h index 12a5d8047..2d4c49299 100644 --- a/src/hwrenderer/scene/hw_portal.h +++ b/src/hwrenderer/scene/hw_portal.h @@ -53,27 +53,12 @@ public: virtual bool NeedDepthBuffer() { return true; } virtual void DrawContents(HWDrawInfo *di) = 0; virtual void RenderAttached(HWDrawInfo *di) {} - virtual bool Start(bool usestencil, bool doquery, HWDrawInfo *outer_di, HWDrawInfo **pDi) = 0; - virtual void End(HWDrawInfo *di, bool usestencil) = 0; void AddLine(GLWall * l) { lines.Push(*l); } - void RenderPortal(bool usestencil, bool doquery, HWDrawInfo *outer_di) - { - // Start may perform an occlusion query. If that returns 0 there - // is no need to draw the stencil's contents and there's also no - // need to restore the affected area becasue there is none! - HWDrawInfo *di; - if (Start(usestencil, doquery, outer_di, &di)) - { - DrawContents(di); - End(di, usestencil); - } - } - }; @@ -107,8 +92,7 @@ struct FPortalSceneState void StartFrame(); bool RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di); void EndFrame(HWDrawInfo *outer_di); - - + void RenderPortal(IPortal *p, bool usestencil, HWDrawInfo *outer_di); }; inline IPortal::IPortal(FPortalSceneState *s, bool local) : mState(s) @@ -117,8 +101,6 @@ inline IPortal::IPortal(FPortalSceneState *s, bool local) : mState(s) } - - class HWScenePortalBase { protected: