- some reorganization of portal code.

This commit is contained in:
Christoph Oelckers 2018-10-23 22:32:00 +02:00
parent 93599e483f
commit 93dac4e4d8
12 changed files with 148 additions and 192 deletions

View file

@ -59,6 +59,7 @@ public:
unsigned int mFBID;
unsigned int mVAOID;
unsigned int PortalQueryObject;
unsigned int mStencilValue = 0;
int mOldFBID;

View file

@ -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)

View file

@ -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;

View file

@ -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);
}
//==========================================================================
//

View file

@ -51,6 +51,7 @@ 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();

View file

@ -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<FDrawInfo*>(di)->EndDrawInfo();
GLRenderer->mViewpoints->Bind(static_cast<FDrawInfo*>(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<FDrawInfo*>(di)->EndDrawInfo();
GLRenderer->mViewpoints->Bind(static_cast<FDrawInfo*>(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);
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

View file

@ -63,6 +63,9 @@ private:
ActorRenderFlags savedvisibility;
TArray<unsigned int> mPrimIndices;
void SetupStencil(HWDrawInfo *di, FRenderState &state, bool usestencil);
void RemoveStencil(HWDrawInfo *di, FRenderState &state, bool usestencil);
protected:
int level;

View file

@ -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;
};

View file

@ -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;
}

View file

@ -117,6 +117,8 @@ inline IPortal::IPortal(FPortalSceneState *s, bool local) : mState(s)
}
class HWScenePortalBase
{
protected:

View file

@ -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);

View file

@ -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;