From 93dac4e4d8540a6c4c72482fedc29c76a3de14c7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 23 Oct 2018 22:32:00 +0200 Subject: [PATCH] - some reorganization of portal code. --- src/gl/renderer/gl_renderer.h | 1 + src/gl/renderer/gl_renderstate.cpp | 21 --- src/gl/renderer/gl_renderstate.h | 9 -- src/gl/scene/gl_drawinfo.cpp | 16 ++ src/gl/scene/gl_drawinfo.h | 3 +- src/gl/scene/gl_portal.cpp | 201 +++++++++++++------------- src/gl/scene/gl_portal.h | 3 + src/hwrenderer/scene/hw_drawinfo.h | 19 +++ src/hwrenderer/scene/hw_flats.cpp | 8 +- src/hwrenderer/scene/hw_portal.h | 2 + src/hwrenderer/scene/hw_renderstate.h | 56 ------- src/v_video.h | 1 + 12 files changed, 148 insertions(+), 192 deletions(-) diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 3a48a9ccb..ea602e956 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -59,6 +59,7 @@ public: unsigned int mFBID; unsigned int mVAOID; unsigned int PortalQueryObject; + unsigned int mStencilValue = 0; int mOldFBID; diff --git a/src/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp index 02a7125e8..4cc432f3a 100644 --- a/src/gl/renderer/gl_renderstate.cpp +++ b/src/gl/renderer/gl_renderstate.cpp @@ -38,8 +38,6 @@ #include "gl/renderer/gl_renderbuffers.h" #include "gl/textures/gl_hwtexture.h" -static int op2gl[] = { GL_KEEP, GL_INCR, GL_DECR }; - FGLRenderState gl_RenderState; static VSMatrix identityMatrix(1); @@ -60,9 +58,6 @@ static void matrixToGL(const VSMatrix &mat, int loc) void FGLRenderState::Reset() { FRenderState::Reset(); - mSrcBlend = GL_SRC_ALPHA; - mDstBlend = GL_ONE_MINUS_SRC_ALPHA; - mBlendEquation = GL_FUNC_ADD; mVertexBuffer = mCurrentVertexBuffer = nullptr; mGlossiness = 0.0f; mSpecularLevel = 0.0f; @@ -238,22 +233,6 @@ void FGLRenderState::Apply() mMaterial.mChanged = false; } - if (mStencil.mChanged) - { - glStencilFunc(GL_EQUAL, mStencil.mBaseVal + mStencil.mOffsVal, ~0); // draw sky into stencil - glStencilOp(GL_KEEP, GL_KEEP, op2gl[mStencil.mOperation]); // this stage doesn't modify the stencil - - bool cmon = !(mStencil.mFlags & SF_ColorMaskOff); - glColorMask(cmon, cmon, cmon, cmon); // don't write to the graphics buffer - glDepthMask(!(mStencil.mFlags & SF_DepthMaskOff)); - if (mStencil.mFlags & SF_DepthTestOff) - glDisable(GL_DEPTH_TEST); - else - glEnable(GL_DEPTH_TEST); - - mStencil.mChanged = false; - } - if (mBias.mChanged) { if (mBias.mFactor == 0 && mBias.mUnits == 0) diff --git a/src/gl/renderer/gl_renderstate.h b/src/gl/renderer/gl_renderstate.h index 6d651b11e..9ff961871 100644 --- a/src/gl/renderer/gl_renderstate.h +++ b/src/gl/renderer/gl_renderstate.h @@ -51,8 +51,6 @@ class FGLRenderState : public FRenderState { uint8_t mLastDepthClamp : 1; - int mSrcBlend, mDstBlend; - int mBlendEquation; float mGlossiness, mSpecularLevel; float mShaderTimer; @@ -188,13 +186,6 @@ public: { return mPassType == GBUFFER_PASS ? 3 : 1; } - - // Temporary helper. - int GetStencilCounter() - { - return mStencil.mBaseVal; - } - }; extern FGLRenderState gl_RenderState; diff --git a/src/gl/scene/gl_drawinfo.cpp b/src/gl/scene/gl_drawinfo.cpp index f31d77855..33c471428 100644 --- a/src/gl/scene/gl_drawinfo.cpp +++ b/src/gl/scene/gl_drawinfo.cpp @@ -328,6 +328,22 @@ void FDrawInfo::EnableDrawBufferAttachments(bool on) gl_RenderState.EnableDrawBuffers(on? gl_RenderState.GetPassDrawBufferCount() : 1); } +void FDrawInfo::SetStencil(int offs, int op, int flags) +{ + static int op2gl[] = { GL_KEEP, GL_INCR, GL_DECR }; + + glStencilFunc(GL_EQUAL, screen->stencilValue + offs, ~0); // draw sky into stencil + glStencilOp(GL_KEEP, GL_KEEP, op2gl[op]); // this stage doesn't modify the stencil + + bool cmon = !(flags & SF_ColorMaskOff); + glColorMask(cmon, cmon, cmon, cmon); // don't write to the graphics buffer + glDepthMask(!(flags & SF_DepthMaskOff)); + if (flags & SF_DepthTestOff) + glDisable(GL_DEPTH_TEST); + else + glEnable(GL_DEPTH_TEST); +} + //========================================================================== // diff --git a/src/gl/scene/gl_drawinfo.h b/src/gl/scene/gl_drawinfo.h index 213ae3052..fbcd9758c 100644 --- a/src/gl/scene/gl_drawinfo.h +++ b/src/gl/scene/gl_drawinfo.h @@ -51,7 +51,8 @@ struct FDrawInfo : public HWDrawInfo void SetDepthMask(bool on) override; void SetDepthFunc(int func) override; void EnableDrawBufferAttachments(bool on) override; - + void SetStencil(int offs, int op, int flags) override; + void StartScene(); void DoDrawSorted(HWDrawList *dl, SortNode * head); diff --git a/src/gl/scene/gl_portal.cpp b/src/gl/scene/gl_portal.cpp index 9f96dea28..cafe2bc69 100644 --- a/src/gl/scene/gl_portal.cpp +++ b/src/gl/scene/gl_portal.cpp @@ -112,96 +112,69 @@ void GLPortal::DrawPortalStencil(int pass) } } - //----------------------------------------------------------------------------- // // Start // //----------------------------------------------------------------------------- -bool GLPortal::Start(bool usestencil, bool doquery, HWDrawInfo *outer_di, HWDrawInfo **pDi) +void GLPortal::SetupStencil(HWDrawInfo *di, FRenderState &state, bool usestencil) { - *pDi = nullptr; - rendered_portals++; - Clocker c(PortalAll); - if (usestencil) { - if (!gl_portals) - { - return false; - } - + // Create stencil - glStencilFunc(GL_EQUAL, gl_RenderState.GetStencilCounter(), ~0); // 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(); + + if (NeedDepthBuffer()) { - glColorMask(0,0,0,0); // don't write to the graphics buffer - gl_RenderState.SetEffect(EFF_STENCIL); - gl_RenderState.EnableTexture(false); - gl_RenderState.ResetColor(); + glDepthMask(false); // don't write to Z-buffer! + + DrawPortalStencil(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); + + // set normal drawing mode + gl_RenderState.EnableTexture(true); glDepthFunc(GL_LESS); - gl_RenderState.Apply(); + glColorMask(1, 1, 1, 1); + gl_RenderState.SetEffect(EFF_NONE); + glDepthRange(0, 1); - if (NeedDepthBuffer()) - { - glDepthMask(false); // don't write to Z-buffer! - if (!NeedDepthBuffer()) doquery = false; // too much overhead and nothing to gain. - else if (gl_noquery) doquery = false; - - // Use occlusion query to avoid rendering portals that aren't visible - if (doquery) glBeginQuery(GL_SAMPLES_PASSED, GLRenderer->PortalQueryObject); - - DrawPortalStencil(STP_Stencil); - - if (doquery) glEndQuery(GL_SAMPLES_PASSED); - - // Clear Z-buffer - glStencilFunc(GL_EQUAL, gl_RenderState.GetStencilCounter() + 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); - - // 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; - - if (doquery) glGetQueryObjectuiv(GLRenderer->PortalQueryObject, GL_QUERY_RESULT, &sampleCount); - - if (sampleCount == 0) // not visible - { - // restore default stencil op. - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glStencilFunc(GL_EQUAL, gl_RenderState.GetStencilCounter(), ~0); // draw sky into stencil - return false; - } - } - 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! - - glDepthMask(true); - DrawPortalStencil(STP_AllInOne); - glStencilFunc(GL_EQUAL, gl_RenderState.GetStencilCounter() + 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! - } + GLuint sampleCount = 1; } - gl_RenderState.IncStencilValue(); + 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! + + 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! + } + + screen->stencilValue++; } else { @@ -211,36 +184,14 @@ bool GLPortal::Start(bool usestencil, bool doquery, HWDrawInfo *outer_di, HWDraw glDisable(GL_DEPTH_TEST); } } - *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) +void GLPortal::RemoveStencil(HWDrawInfo *di, FRenderState &state, bool usestencil) { bool needdepth = NeedDepthBuffer(); - Clocker c(PortalAll); - - di = static_cast(di)->EndDrawInfo(); - GLRenderer->mViewpoints->Bind(static_cast(di)->vpIndex); if (usestencil) { - auto &vp = di->Viewpoint; - - // Restore the old view - if (vp.camera != nullptr) vp.camera->renderflags = (vp.camera->renderflags & ~RF_MAYBEINVISIBLE) | savedvisibility; - glColorMask(0, 0, 0, 0); // no graphics gl_RenderState.SetEffect(EFF_NONE); gl_RenderState.ResetColor(); @@ -263,7 +214,7 @@ void GLPortal::End(HWDrawInfo *di, bool usestencil) glDepthFunc(GL_LEQUAL); glDepthRange(0, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); - glStencilFunc(GL_EQUAL, gl_RenderState.GetStencilCounter(), ~0); // draw sky into stencil + glStencilFunc(GL_EQUAL, screen->stencilValue, ~0); // draw sky into stencil DrawPortalStencil(STP_DepthRestore); glDepthFunc(GL_LESS); @@ -271,11 +222,11 @@ void GLPortal::End(HWDrawInfo *di, bool usestencil) gl_RenderState.EnableTexture(true); gl_RenderState.SetEffect(EFF_NONE); glColorMask(1, 1, 1, 1); - gl_RenderState.DecStencilValue(); + screen->stencilValue--; // restore old stencil op. glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glStencilFunc(GL_EQUAL, gl_RenderState.GetStencilCounter(), ~0); // draw sky into stencil + glStencilFunc(GL_EQUAL, screen->stencilValue, ~0); // draw sky into stencil } else { @@ -313,6 +264,54 @@ void GLPortal::End(HWDrawInfo *di, bool usestencil) } } +//----------------------------------------------------------------------------- +// +// 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); +} + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- diff --git a/src/gl/scene/gl_portal.h b/src/gl/scene/gl_portal.h index dd645109d..a4ab20b8e 100644 --- a/src/gl/scene/gl_portal.h +++ b/src/gl/scene/gl_portal.h @@ -63,6 +63,9 @@ private: ActorRenderFlags savedvisibility; TArray mPrimIndices; + void SetupStencil(HWDrawInfo *di, FRenderState &state, bool usestencil); + void RemoveStencil(HWDrawInfo *di, FRenderState &state, bool usestencil); + protected: int level; diff --git a/src/hwrenderer/scene/hw_drawinfo.h b/src/hwrenderer/scene/hw_drawinfo.h index 3aa39dff2..ccf00fc4f 100644 --- a/src/hwrenderer/scene/hw_drawinfo.h +++ b/src/hwrenderer/scene/hw_drawinfo.h @@ -24,6 +24,23 @@ enum EDepthFunc DF_Always }; +enum EStencilFlags +{ + SF_AllOn = 0, + SF_ColorMaskOff = 1, + SF_DepthMaskOff = 2, + SF_DepthTestOff = 4 +}; + +enum EStencilOp +{ + SOP_Keep = 0, + SOP_Increment = 1, + SOP_Decrement = 2 +}; + + + struct FSectorPortalGroup; struct FLinePortalSpan; struct FFlatVertex; @@ -326,6 +343,8 @@ public: virtual void SetDepthMask(bool on) = 0; virtual void SetDepthFunc(int func) = 0; virtual void EnableDrawBufferAttachments(bool on) = 0; + virtual void SetStencil(int offs, int op, int flags) = 0; + }; diff --git a/src/hwrenderer/scene/hw_flats.cpp b/src/hwrenderer/scene/hw_flats.cpp index 7527fc4b9..1bff9142f 100644 --- a/src/hwrenderer/scene/hw_flats.cpp +++ b/src/hwrenderer/scene/hw_flats.cpp @@ -248,26 +248,26 @@ void GLFlat::DrawSubsectors(HWDrawInfo *di, FRenderState &state) // Create stencil state.SetEffect(EFF_STENCIL); state.EnableTexture(false); - state.SetStencil(0, SOP_Increment, SF_ColorMaskOff); + di->SetStencil(0, SOP_Increment, SF_ColorMaskOff); di->Draw(DT_TriangleFan, state, fnode->vertexindex, 4); // Draw projected plane into stencil - state.SetStencil(1, SOP_Keep, SF_DepthMaskOff | SF_DepthTestOff); state.EnableTexture(true); state.SetEffect(EFF_NONE); + di->SetStencil(1, SOP_Keep, SF_DepthMaskOff | SF_DepthTestOff); di->Draw(DT_TriangleFan, state, fnode->vertexindex + 4, 4); // clear stencil state.SetEffect(EFF_STENCIL); state.EnableTexture(false); - state.SetStencil(1, SOP_Decrement, SF_ColorMaskOff | SF_DepthMaskOff | SF_DepthTestOff); + di->SetStencil(1, SOP_Decrement, SF_ColorMaskOff | SF_DepthMaskOff | SF_DepthTestOff); di->Draw(DT_TriangleFan, state, fnode->vertexindex, 4); // restore old stencil op. - state.SetStencil(0, SOP_Keep, SF_AllOn); state.EnableTexture(true); state.SetEffect(EFF_NONE); state.SetDepthBias(0, 0); + di->SetStencil(0, SOP_Keep, SF_AllOn); fnode = fnode->next; } diff --git a/src/hwrenderer/scene/hw_portal.h b/src/hwrenderer/scene/hw_portal.h index 36047a3f5..12a5d8047 100644 --- a/src/hwrenderer/scene/hw_portal.h +++ b/src/hwrenderer/scene/hw_portal.h @@ -117,6 +117,8 @@ inline IPortal::IPortal(FPortalSceneState *s, bool local) : mState(s) } + + class HWScenePortalBase { protected: diff --git a/src/hwrenderer/scene/hw_renderstate.h b/src/hwrenderer/scene/hw_renderstate.h index 46c099bfb..e3707ee83 100644 --- a/src/hwrenderer/scene/hw_renderstate.h +++ b/src/hwrenderer/scene/hw_renderstate.h @@ -26,21 +26,6 @@ enum EAlphaFunc Alpha_Greater = 1 }; -enum EStencilOp -{ - SOP_Keep = 0, - SOP_Increment = 1, - SOP_Decrement = 2 -}; - -enum EStencilFlags -{ - SF_AllOn = 0, - SF_ColorMaskOff = 1, - SF_DepthMaskOff = 2, - SF_DepthTestOff = 4 -}; - struct FStateVec4 { float vec[4]; @@ -72,24 +57,6 @@ struct FMaterialState } }; -struct FStencilState -{ - int mBaseVal; - int mOffsVal; - int mOperation; - int mFlags; - bool mChanged; - - void Reset() - { - mBaseVal = 0; - mOffsVal = 0; - mOperation = SOP_Keep; - mFlags = SF_AllOn; - mChanged = false; - } -}; - struct FDepthBiasState { float mFactor; @@ -136,7 +103,6 @@ protected: FRenderStyle mRenderStyle; FMaterialState mMaterial; - FStencilState mStencil; FDepthBiasState mBias; void SetShaderLight(float level, float olight); @@ -167,7 +133,6 @@ public: mLightIndex = -1; mRenderStyle = DefaultRenderStyle(); mMaterial.Reset(); - mStencil.Reset(); mBias.Reset(); mColor.Set(1.0f, 1.0f, 1.0f, 1.0f); @@ -396,27 +361,6 @@ public: mMaterial.mChanged = true; } - void SetStencil(int offs, int op, int flags) - { - mStencil.mOffsVal = offs; - mStencil.mOperation = op; - mStencil.mFlags = flags; - mStencil.mChanged = true; - } - - void IncStencilValue() - { - mStencil.mBaseVal++; - mStencil.mChanged = true; - } - - void DecStencilValue() - { - mStencil.mBaseVal--; - mStencil.mChanged = true; - } - - void SetColor(int sectorlightlevel, int rellight, bool fullbright, const FColormap &cm, float alpha, bool weapon = false); void SetFog(int lightlevel, int rellight, bool fullbright, const FColormap *cmap, bool isadditive); diff --git a/src/v_video.h b/src/v_video.h index e96b67bc9..e9655a007 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -364,6 +364,7 @@ public: int hwcaps = 0; float glslversion = 0; // This is here so that the differences between old OpenGL and new OpenGL/Vulkan can be handled by platform independent code. int instack[2] = { 0,0 }; // this is globally maintained state for portal recursion avoidance. + int stencilValue = 0; // Global stencil test value bool enable_quadbuffered = false; IntRect mScreenViewport;