Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpenGL: Efficiency improvements for stencil commands #17478

Merged
merged 3 commits into from
May 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 25 additions & 7 deletions Common/GPU/OpenGL/GLQueueRunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,13 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last
bool clipDistanceEnabled[8]{};
GLuint blendEqColor = (GLuint)-1;
GLuint blendEqAlpha = (GLuint)-1;
GLuint stencilWriteMask = (GLuint)-1;
GLenum stencilFunc = (GLenum)-1;
GLuint stencilRef = (GLuint)-1;
GLuint stencilCompareMask = (GLuint)-1;
GLenum stencilSFail = (GLenum)-1;
GLenum stencilZFail = (GLenum)-1;
GLenum stencilPass = (GLenum)-1;

GLRTexture *curTex[MAX_GL_TEXTURE_SLOTS]{};

Expand All @@ -862,23 +869,34 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last
depthEnabled = false;
}
break;
case GLRRenderCommand::STENCILFUNC:
if (c.stencilFunc.enabled) {
case GLRRenderCommand::STENCIL:
if (c.stencil.enabled) {
if (!stencilEnabled) {
glEnable(GL_STENCIL_TEST);
stencilEnabled = true;
}
glStencilFunc(c.stencilFunc.func, c.stencilFunc.ref, c.stencilFunc.compareMask);
if (c.stencil.func != stencilFunc || c.stencil.ref != stencilRef || c.stencil.compareMask != stencilCompareMask) {
glStencilFunc(c.stencil.func, c.stencil.ref, c.stencil.compareMask);
stencilFunc = c.stencil.func;
stencilRef = c.stencil.ref;
stencilCompareMask = c.stencil.compareMask;
}
if (c.stencil.sFail != stencilSFail || c.stencil.zFail != stencilZFail || c.stencil.pass != stencilPass) {
glStencilOp(c.stencil.sFail, c.stencil.zFail, c.stencil.pass);
stencilSFail = c.stencil.sFail;
stencilZFail = c.stencil.zFail;
stencilPass = c.stencil.pass;
}
if (c.stencil.writeMask != stencilWriteMask) {
glStencilMask(c.stencil.writeMask);
stencilWriteMask = c.stencil.writeMask;
}
} else if (/* !c.stencilFunc.enabled && */stencilEnabled) {
glDisable(GL_STENCIL_TEST);
stencilEnabled = false;
}
CHECK_GL_ERROR_IF_DEBUG();
break;
case GLRRenderCommand::STENCILOP:
glStencilOp(c.stencilOp.sFail, c.stencilOp.zFail, c.stencilOp.pass);
glStencilMask(c.stencilOp.writeMask);
break;
case GLRRenderCommand::BLEND:
if (c.blend.enabled) {
if (!blendEnabled) {
Expand Down
7 changes: 2 additions & 5 deletions Common/GPU/OpenGL/GLQueueRunner.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ class GLRInputLayout;

enum class GLRRenderCommand : uint8_t {
DEPTH,
STENCILFUNC,
STENCILOP,
STENCIL,
BLEND,
BLENDCOLOR,
LOGICOP,
Expand Down Expand Up @@ -100,13 +99,11 @@ struct GLRRenderData {
GLenum func;
uint8_t ref;
uint8_t compareMask;
} stencilFunc;
struct {
GLenum sFail;
GLenum zFail;
GLenum pass;
uint8_t writeMask;
} stencilOp; // also write mask
} stencil;
struct {
GLRInputLayout *inputLayout;
GLRBuffer *buffer;
Expand Down
31 changes: 12 additions & 19 deletions Common/GPU/OpenGL/GLRenderManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -664,32 +664,25 @@ class GLRenderManager {
}
#endif

void SetStencilFunc(bool enabled, GLenum func, uint8_t refValue, uint8_t compareMask) {
void SetStencil(bool enabled, GLenum func, uint8_t refValue, uint8_t compareMask, uint8_t writeMask, GLenum sFail, GLenum zFail, GLenum pass) {
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
data.cmd = GLRRenderCommand::STENCILFUNC;
data.stencilFunc.enabled = enabled;
data.stencilFunc.func = func;
data.stencilFunc.ref = refValue;
data.stencilFunc.compareMask = compareMask;
}

void SetStencilOp(uint8_t writeMask, GLenum sFail, GLenum zFail, GLenum pass) {
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
data.cmd = GLRRenderCommand::STENCILOP;
data.stencilOp.writeMask = writeMask;
data.stencilOp.sFail = sFail;
data.stencilOp.zFail = zFail;
data.stencilOp.pass = pass;
data.cmd = GLRRenderCommand::STENCIL;
data.stencil.enabled = enabled;
data.stencil.func = func;
data.stencil.ref = refValue;
data.stencil.compareMask = compareMask;
data.stencil.writeMask = writeMask;
data.stencil.sFail = sFail;
data.stencil.zFail = zFail;
data.stencil.pass = pass;
}

void SetStencilDisabled() {
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
GLRRenderData &data = curRenderStep_->commands.push_uninitialized();
data.cmd = GLRRenderCommand::STENCILFUNC;
data.stencilFunc.enabled = false;
// When enabled = false, the others aren't read so we don't zero-initialize them.
data.cmd = GLRRenderCommand::STENCIL;
data.stencil.enabled = false;
}

void SetBlendFactor(const float color[4]) {
Expand Down
10 changes: 5 additions & 5 deletions Common/GPU/OpenGL/thin3d_gl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,9 @@ class OpenGLDepthStencilState : public DepthStencilState {

void Apply(GLRenderManager *render, uint8_t stencilRef, uint8_t stencilWriteMask, uint8_t stencilCompareMask) {
render->SetDepth(depthTestEnabled, depthWriteEnabled, depthComp);
render->SetStencilFunc(stencilEnabled, stencilCompareOp, stencilRef, stencilCompareMask);
render->SetStencilOp(stencilWriteMask, stencilFail, stencilZFail, stencilPass);
render->SetStencil(
stencilEnabled, stencilCompareOp, stencilRef, stencilCompareMask,
stencilWriteMask, stencilFail, stencilZFail, stencilPass);
}
};

Expand Down Expand Up @@ -407,12 +408,11 @@ class OpenGLContext : public DrawContext {
stencilWriteMask_ = writeMask;
stencilCompareMask_ = compareMask;
// Do we need to update on the fly here?
renderManager_.SetStencilFunc(
renderManager_.SetStencil(
curPipeline_->depthStencil->stencilEnabled,
curPipeline_->depthStencil->stencilCompareOp,
refValue,
compareMask);
renderManager_.SetStencilOp(
compareMask,
writeMask,
curPipeline_->depthStencil->stencilFail,
curPipeline_->depthStencil->stencilZFail,
Expand Down
16 changes: 9 additions & 7 deletions GPU/GLES/StateMappingGLES.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,9 @@ void DrawEngineGLES::ApplyDrawState(int prim) {

if (gstate.isModeClear()) {
// Depth Test
renderManager->SetStencilFunc(gstate.isClearModeAlphaMask(), GL_ALWAYS, 0xFF, 0xFF);
renderManager->SetStencilOp(stencilState.writeMask, GL_REPLACE, GL_REPLACE, GL_REPLACE);
renderManager->SetStencil(
gstate.isClearModeAlphaMask(), GL_ALWAYS, 0xFF, 0xFF,
stencilState.writeMask, GL_REPLACE, GL_REPLACE, GL_REPLACE);
renderManager->SetDepth(true, gstate.isClearModeDepthMask() ? true : false, GL_ALWAYS);
} else {
// Depth Test
Expand All @@ -259,17 +260,17 @@ void DrawEngineGLES::ApplyDrawState(int prim) {

// Stencil Test
if (stencilState.enabled) {
renderManager->SetStencilFunc(stencilState.enabled, compareOps[stencilState.testFunc], stencilState.testRef, stencilState.testMask);
renderManager->SetStencilOp(stencilState.writeMask, stencilOps[stencilState.sFail], stencilOps[stencilState.zFail], stencilOps[stencilState.zPass]);
renderManager->SetStencil(
stencilState.enabled, compareOps[stencilState.testFunc], stencilState.testRef, stencilState.testMask,
stencilState.writeMask, stencilOps[stencilState.sFail], stencilOps[stencilState.zFail], stencilOps[stencilState.zPass]);

// Nasty special case for Spongebob and similar where it tries to write zeros to alpha/stencil during
// depth-fail. We can't write to alpha then because the pixel is killed. However, we can invert the depth
// test and modify the alpha function...
if (SpongebobDepthInverseConditions(stencilState)) {
renderManager->SetBlendAndMask(0x8, true, GL_ZERO, GL_ZERO, GL_ZERO, GL_ZERO, GL_FUNC_ADD, GL_FUNC_ADD);
renderManager->SetDepth(true, false, GL_LESS);
renderManager->SetStencilFunc(true, GL_ALWAYS, 0xFF, 0xFF);
renderManager->SetStencilOp(0xFF, GL_ZERO, GL_KEEP, GL_ZERO);
renderManager->SetStencil(true, GL_ALWAYS, 0xFF, 0xFF, 0xFF, GL_ZERO, GL_KEEP, GL_ZERO);

dirtyRequiresRecheck_ |= DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE;
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE);
Expand Down Expand Up @@ -301,7 +302,8 @@ void DrawEngineGLES::ApplyDrawState(int prim) {

void DrawEngineGLES::ApplyDrawStateLate(bool setStencilValue, int stencilValue) {
if (setStencilValue) {
render_->SetStencilFunc(GL_TRUE, GL_ALWAYS, stencilValue, 255);
render_->SetStencil(true, GL_ALWAYS, stencilValue, 255, 0xFF, GL_REPLACE, GL_REPLACE, GL_REPLACE);
gstate_c.Dirty(DIRTY_DEPTHSTENCIL_STATE); // For the next time.
}

// At this point, we know if the vertices are full alpha or not.
Expand Down