Extract blend state mapping into a function.

This commit is contained in:
Henrik Rydgard 2015-11-08 20:09:30 +01:00
parent ce28ee28f1
commit e97d771e0f
3 changed files with 230 additions and 139 deletions

View File

@ -65,3 +65,57 @@ struct ViewportAndScissor {
bool dirtyProj;
};
void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, float renderHeight, int bufferWidth, int bufferHeight, ViewportAndScissor &out);
// These are common to all modern APIs and can be easily converted with a lookup table.
enum class BlendFactor : uint8_t {
ZERO,
ONE,
SRC_COLOR,
ONE_MINUS_SRC_COLOR,
DST_COLOR,
ONE_MINUS_DST_COLOR,
SRC_ALPHA,
ONE_MINUS_SRC_ALPHA,
DST_ALPHA,
ONE_MINUS_DST_ALPHA,
CONSTANT_COLOR,
ONE_MINUS_CONSTANT_COLOR,
CONSTANT_ALPHA,
ONE_MINUS_CONSTANT_ALPHA,
SRC1_ALPHA,
ONE_MINUS_SRC1_ALPHA,
INVALID,
COUNT,
};
enum class BlendEq : uint8_t {
ADD,
SUBTRACT,
REVERSE_SUBTRACT,
MIN,
MAX,
COUNT
};
struct GenericBlendState {
bool enabled;
BlendFactor srcColor;
BlendFactor dstColor;
BlendFactor srcAlpha;
BlendFactor dstAlpha;
BlendEq eqColor;
BlendEq eqAlpha;
void setFactors(BlendFactor srcC, BlendFactor dstC, BlendFactor srcA, BlendFactor dstA) {
srcColor = srcC;
dstColor = dstC;
srcAlpha = srcA;
dstAlpha = dstA;
}
void setEquation(BlendEq eqC, BlendEq eqA) {
eqColor = eqC;
eqAlpha = eqA;
}
};

View File

@ -36,56 +36,83 @@
#include "GPU/GLES/Framebuffer.h"
#include "GPU/GLES/FragmentShaderGenerator.h"
static const GLushort aLookup[11] = {
static const BlendFactor genericALookup[11] = {
BlendFactor::DST_COLOR,
BlendFactor::ONE_MINUS_DST_COLOR,
BlendFactor::SRC_ALPHA,
BlendFactor::ONE_MINUS_SRC_ALPHA,
BlendFactor::DST_ALPHA,
BlendFactor::ONE_MINUS_DST_ALPHA,
BlendFactor::SRC_ALPHA, // GE_SRCBLEND_DOUBLESRCALPHA
BlendFactor::ONE_MINUS_SRC_ALPHA, // GE_SRCBLEND_DOUBLEINVSRCALPHA
BlendFactor::DST_ALPHA, // GE_SRCBLEND_DOUBLEDSTALPHA
BlendFactor::ONE_MINUS_DST_ALPHA, // GE_SRCBLEND_DOUBLEINVDSTALPHA
BlendFactor::CONSTANT_COLOR, // FIXA
};
static const BlendFactor genericBLookup[11] = {
BlendFactor::SRC_COLOR,
BlendFactor::ONE_MINUS_SRC_COLOR,
BlendFactor::SRC_ALPHA,
BlendFactor::ONE_MINUS_SRC_ALPHA,
BlendFactor::DST_ALPHA,
BlendFactor::ONE_MINUS_DST_ALPHA,
BlendFactor::SRC_ALPHA, // GE_SRCBLEND_DOUBLESRCALPHA
BlendFactor::ONE_MINUS_SRC_ALPHA, // GE_SRCBLEND_DOUBLEINVSRCALPHA
BlendFactor::DST_ALPHA, // GE_SRCBLEND_DOUBLEDSTALPHA
BlendFactor::ONE_MINUS_DST_ALPHA, // GE_SRCBLEND_DOUBLEINVDSTALPHA
BlendFactor::CONSTANT_COLOR, // FIXB
};
static const BlendEq eqLookupNoMinMax[] = {
BlendEq::ADD,
BlendEq::SUBTRACT,
BlendEq::REVERSE_SUBTRACT,
BlendEq::ADD, // GE_BLENDMODE_MIN
BlendEq::ADD, // GE_BLENDMODE_MAX
BlendEq::ADD, // GE_BLENDMODE_ABSDIFF
};
static const BlendEq eqLookup[] = {
BlendEq::ADD,
BlendEq::SUBTRACT,
BlendEq::REVERSE_SUBTRACT,
BlendEq::MIN, // GE_BLENDMODE_MIN
BlendEq::MAX, // GE_BLENDMODE_MAX
BlendEq::ADD, // GE_BLENDMODE_ABSDIFF
};
static const GLushort glBlendFactorLookup[(size_t)BlendFactor::COUNT] = {
GL_ZERO,
GL_ONE,
GL_SRC_COLOR,
GL_ONE_MINUS_SRC_COLOR,
GL_DST_COLOR,
GL_ONE_MINUS_DST_COLOR,
GL_SRC_ALPHA,
GL_ONE_MINUS_SRC_ALPHA,
GL_DST_ALPHA,
GL_ONE_MINUS_DST_ALPHA,
GL_SRC_ALPHA, // GE_SRCBLEND_DOUBLESRCALPHA
GL_ONE_MINUS_SRC_ALPHA, // GE_SRCBLEND_DOUBLEINVSRCALPHA
GL_DST_ALPHA, // GE_SRCBLEND_DOUBLEDSTALPHA
GL_ONE_MINUS_DST_ALPHA, // GE_SRCBLEND_DOUBLEINVDSTALPHA
GL_CONSTANT_COLOR, // FIXA
};
static const GLushort bLookup[11] = {
GL_SRC_COLOR,
GL_ONE_MINUS_SRC_COLOR,
GL_SRC_ALPHA,
GL_ONE_MINUS_SRC_ALPHA,
GL_DST_ALPHA,
GL_ONE_MINUS_DST_ALPHA,
GL_SRC_ALPHA, // GE_DSTBLEND_DOUBLESRCALPHA
GL_ONE_MINUS_SRC_ALPHA, // GE_DSTBLEND_DOUBLEINVSRCALPHA
GL_DST_ALPHA, // GE_DSTBLEND_DOUBLEDSTALPHA
GL_ONE_MINUS_DST_ALPHA, // GE_DSTBLEND_DOUBLEINVDSTALPHA
GL_CONSTANT_COLOR, // FIXB
};
static const GLushort eqLookupNoMinMax[] = {
GL_FUNC_ADD,
GL_FUNC_SUBTRACT,
GL_FUNC_REVERSE_SUBTRACT,
GL_FUNC_ADD, // GE_BLENDMODE_MIN
GL_FUNC_ADD, // GE_BLENDMODE_MAX
GL_FUNC_ADD, // GE_BLENDMODE_ABSDIFF
};
static const GLushort eqLookup[] = {
GL_FUNC_ADD,
GL_FUNC_SUBTRACT,
GL_FUNC_REVERSE_SUBTRACT,
#ifdef USING_GLES2
GL_MIN_EXT, // GE_BLENDMODE_MIN
GL_MAX_EXT, // GE_BLENDMODE_MAX
GL_MAX_EXT, // GE_BLENDMODE_ABSDIFF
GL_CONSTANT_COLOR,
GL_ONE_MINUS_CONSTANT_COLOR,
GL_CONSTANT_ALPHA,
GL_ONE_MINUS_CONSTANT_ALPHA,
#if !defined(USING_GLES2) // TODO: Remove when we have better headers
GL_SRC1_ALPHA,
GL_ONE_MINUS_SRC1_ALPHA,
#else
GL_MIN, // GE_BLENDMODE_MIN
GL_MAX, // GE_BLENDMODE_MAX
GL_MAX, // GE_BLENDMODE_ABSDIFF
GL_INVALID_ENUM,
GL_INVALID_ENUM,
#endif
GL_INVALID_ENUM,
};
static const GLushort glBlendEqLookup[(size_t)BlendEq::COUNT] = {
GL_FUNC_ADD,
GL_FUNC_SUBTRACT,
GL_FUNC_REVERSE_SUBTRACT,
GL_MIN,
GL_MAX,
};
static const GLushort cullingMode[] = {
@ -130,34 +157,34 @@ static const GLushort logicOps[] = {
};
#endif
static GLenum toDualSource(GLenum blendfunc) {
static BlendFactor toDualSource(BlendFactor blendfunc) {
switch (blendfunc) {
#if !defined(USING_GLES2) // TODO: Remove when we have better headers
case GL_SRC_ALPHA:
return GL_SRC1_ALPHA;
case GL_ONE_MINUS_SRC_ALPHA:
return GL_ONE_MINUS_SRC1_ALPHA;
case BlendFactor::SRC_ALPHA:
return BlendFactor::SRC1_ALPHA;
case BlendFactor::ONE_MINUS_SRC_ALPHA:
return BlendFactor::ONE_MINUS_SRC1_ALPHA;
#endif
default:
return blendfunc;
}
}
static GLenum blendColor2Func(u32 fix, bool &approx) {
static BlendFactor blendColor2Func(u32 fix, bool &approx) {
if (fix == 0xFFFFFF)
return GL_ONE;
return BlendFactor::ONE;
if (fix == 0)
return GL_ZERO;
return BlendFactor::ZERO;
// Otherwise, it's approximate if we pick ONE/ZERO.
approx = true;
const Vec3f fix3 = Vec3f::FromRGB(fix);
if (fix3.x >= 0.99 && fix3.y >= 0.99 && fix3.z >= 0.99)
return GL_ONE;
return BlendFactor::ONE;
else if (fix3.x <= 0.01 && fix3.y <= 0.01 && fix3.z <= 0.01)
return GL_ZERO;
return GL_INVALID_ENUM;
return BlendFactor::ZERO;
return BlendFactor::INVALID;
}
static inline bool blendColorSimilar(const Vec3f &a, const Vec3f &b, float margin = 0.1f) {
@ -207,23 +234,22 @@ inline void TransformDrawEngine::ResetShaderBlending() {
}
// Try to simulate some common logic ops.
void TransformDrawEngine::ApplyStencilReplaceAndLogicOp(ReplaceAlphaType replaceAlphaWithStencil) {
void TransformDrawEngine::ApplyStencilReplaceAndLogicOp(ReplaceAlphaType replaceAlphaWithStencil, GenericBlendState &blendState) {
StencilValueType stencilType = STENCIL_VALUE_KEEP;
if (replaceAlphaWithStencil == REPLACE_ALPHA_YES) {
stencilType = ReplaceAlphaWithStencilType();
}
// Normally, we would add src + 0, but the logic op may have us do differently.
GLenum srcBlend = GL_ONE;
GLenum dstBlend = GL_ZERO;
GLenum blendOp = GL_FUNC_ADD;
BlendFactor srcBlend = BlendFactor::ONE;
BlendFactor dstBlend = BlendFactor::ZERO;
BlendEq blendEq = BlendEq::ADD;
if (!gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) {
if (gstate.isLogicOpEnabled()) {
switch (gstate.getLogicOp())
{
switch (gstate.getLogicOp()) {
case GE_LOGIC_CLEAR:
srcBlend = GL_ZERO;
srcBlend = BlendFactor::ZERO;
break;
case GE_LOGIC_AND:
case GE_LOGIC_AND_REVERSE:
@ -243,14 +269,14 @@ void TransformDrawEngine::ApplyStencilReplaceAndLogicOp(ReplaceAlphaType replace
WARN_LOG_REPORT_ONCE(d3dLogicOpAndInverted, G3D, "Attempted invert for logic op: %x", gstate.getLogicOp());
break;
case GE_LOGIC_INVERTED:
srcBlend = GL_ONE;
dstBlend = GL_ONE;
blendOp = GL_FUNC_SUBTRACT;
srcBlend = BlendFactor::ONE;
dstBlend = BlendFactor::ONE;
blendEq = BlendEq::SUBTRACT;
WARN_LOG_REPORT_ONCE(d3dLogicOpInverted, G3D, "Attempted inverse for logic op: %x", gstate.getLogicOp());
break;
case GE_LOGIC_NOOP:
srcBlend = GL_ZERO;
dstBlend = GL_ONE;
srcBlend = BlendFactor::ZERO;
dstBlend = BlendFactor::ONE;
break;
case GE_LOGIC_XOR:
WARN_LOG_REPORT_ONCE(d3dLogicOpOrXor, G3D, "Unsupported XOR logic op: %x", gstate.getLogicOp());
@ -258,14 +284,14 @@ void TransformDrawEngine::ApplyStencilReplaceAndLogicOp(ReplaceAlphaType replace
case GE_LOGIC_OR:
case GE_LOGIC_OR_INVERTED:
// Inverted in shader.
dstBlend = GL_ONE;
dstBlend = BlendFactor::ONE;
WARN_LOG_REPORT_ONCE(d3dLogicOpOr, G3D, "Attempted or for logic op: %x", gstate.getLogicOp());
break;
case GE_LOGIC_OR_REVERSE:
WARN_LOG_REPORT_ONCE(d3dLogicOpOrReverse, G3D, "Unsupported OR REVERSE logic op: %x", gstate.getLogicOp());
break;
case GE_LOGIC_SET:
dstBlend = GL_ONE;
dstBlend = BlendFactor::ONE;
WARN_LOG_REPORT_ONCE(d3dLogicOpSet, G3D, "Attempted set for logic op: %x", gstate.getLogicOp());
break;
}
@ -278,33 +304,33 @@ void TransformDrawEngine::ApplyStencilReplaceAndLogicOp(ReplaceAlphaType replace
case STENCIL_VALUE_INCR_4:
case STENCIL_VALUE_INCR_8:
// We'll add the incremented value output by the shader.
glstate.blendFuncSeparate.set(srcBlend, dstBlend, GL_ONE, GL_ONE);
glstate.blendEquationSeparate.set(blendOp, GL_FUNC_ADD);
glstate.blend.enable();
blendState.enabled = true;
blendState.setFactors(srcBlend, dstBlend, BlendFactor::ONE, BlendFactor::ONE);
blendState.setEquation(blendEq, BlendEq::ADD);
break;
case STENCIL_VALUE_DECR_4:
case STENCIL_VALUE_DECR_8:
// We'll subtract the incremented value output by the shader.
glstate.blendFuncSeparate.set(srcBlend, dstBlend, GL_ONE, GL_ONE);
glstate.blendEquationSeparate.set(blendOp, GL_FUNC_SUBTRACT);
glstate.blend.enable();
blendState.enabled = true;
blendState.setFactors(srcBlend, dstBlend, BlendFactor::ONE, BlendFactor::ONE);
blendState.setEquation(blendEq, BlendEq::SUBTRACT);
break;
case STENCIL_VALUE_INVERT:
// The shader will output one, and reverse subtracting will essentially invert.
glstate.blendFuncSeparate.set(srcBlend, dstBlend, GL_ONE, GL_ONE);
glstate.blendEquationSeparate.set(blendOp, GL_FUNC_REVERSE_SUBTRACT);
glstate.blend.enable();
blendState.enabled = true;
blendState.setFactors(srcBlend, dstBlend, BlendFactor::ONE, BlendFactor::ONE);
blendState.setEquation(blendEq, BlendEq::REVERSE_SUBTRACT);
break;
default:
if (srcBlend == GL_ONE && dstBlend == GL_ZERO && blendOp == GL_FUNC_ADD) {
glstate.blend.disable();
if (srcBlend == BlendFactor::ONE && dstBlend == BlendFactor::ZERO && blendEq == BlendEq::ADD) {
blendState.enabled = false;
} else {
glstate.blendFuncSeparate.set(srcBlend, dstBlend, GL_ONE, GL_ZERO);
glstate.blendEquationSeparate.set(blendOp, GL_FUNC_ADD);
glstate.blend.enable();
blendState.enabled = true;
blendState.setFactors(srcBlend, dstBlend, BlendFactor::ONE, BlendFactor::ZERO);
blendState.setEquation(blendEq, BlendEq::ADD);
}
break;
}
@ -312,7 +338,7 @@ void TransformDrawEngine::ApplyStencilReplaceAndLogicOp(ReplaceAlphaType replace
// Called even if AlphaBlendEnable == false - it also deals with stencil-related blend state.
void TransformDrawEngine::ApplyBlendState() {
void TransformDrawEngine::ConvertBlendState(GenericBlendState &blendState) {
// Blending is a bit complex to emulate. This is due to several reasons:
//
// * Doubled blend modes (src, dst, inversed) aren't supported in OpenGL.
@ -332,13 +358,13 @@ void TransformDrawEngine::ApplyBlendState() {
case REPLACE_BLEND_NO:
ResetShaderBlending();
// We may still want to do something about stencil -> alpha.
ApplyStencilReplaceAndLogicOp(replaceAlphaWithStencil);
ApplyStencilReplaceAndLogicOp(replaceAlphaWithStencil, blendState);
return;
case REPLACE_BLEND_COPY_FBO:
if (ApplyShaderBlending()) {
// We may still want to do something about stencil -> alpha.
ApplyStencilReplaceAndLogicOp(replaceAlphaWithStencil);
ApplyStencilReplaceAndLogicOp(replaceAlphaWithStencil, blendState);
return;
}
// Until next time, force it off.
@ -356,12 +382,12 @@ void TransformDrawEngine::ApplyBlendState() {
break;
}
glstate.blend.enable();
blendState.enabled = true;
ResetShaderBlending();
const GEBlendMode blendFuncEq = gstate.getBlendEq();
int blendFuncA = gstate.getBlendFuncA();
int blendFuncB = gstate.getBlendFuncB();
GEBlendSrcFactor blendFuncA = gstate.getBlendFuncA();
GEBlendDstFactor blendFuncB = gstate.getBlendFuncB();
const u32 fixA = gstate.getFixA();
const u32 fixB = gstate.getFixB();
@ -371,7 +397,7 @@ void TransformDrawEngine::ApplyBlendState() {
blendFuncB = GE_DSTBLEND_FIXB;
float constantAlpha = 1.0f;
GLenum constantAlphaGL = GL_ONE;
BlendFactor constantAlphaGL = BlendFactor::ONE;
if (gstate.isStencilTestEnabled() && replaceAlphaWithStencil == REPLACE_ALPHA_NO) {
switch (ReplaceAlphaWithStencilType()) {
case STENCIL_VALUE_UNIFORM:
@ -394,35 +420,35 @@ void TransformDrawEngine::ApplyBlendState() {
// Otherwise it will stay GL_ONE.
if (constantAlpha <= 0.0f) {
constantAlphaGL = GL_ZERO;
constantAlphaGL = BlendFactor::ZERO;
} else if (constantAlpha < 1.0f) {
constantAlphaGL = GL_CONSTANT_ALPHA;
constantAlphaGL = BlendFactor::CONSTANT_ALPHA;
}
}
// Shortcut by using GL_ONE where possible, no need to set blendcolor
bool approxFuncA = false;
GLuint glBlendFuncA = blendFuncA == GE_SRCBLEND_FIXA ? blendColor2Func(fixA, approxFuncA) : aLookup[blendFuncA];
BlendFactor glBlendFuncA = blendFuncA == GE_SRCBLEND_FIXA ? blendColor2Func(fixA, approxFuncA) : genericALookup[blendFuncA];
bool approxFuncB = false;
GLuint glBlendFuncB = blendFuncB == GE_DSTBLEND_FIXB ? blendColor2Func(fixB, approxFuncB) : bLookup[blendFuncB];
BlendFactor glBlendFuncB = blendFuncB == GE_DSTBLEND_FIXB ? blendColor2Func(fixB, approxFuncB) : genericBLookup[blendFuncB];
if (gstate.FrameBufFormat() == GE_FORMAT_565) {
if (blendFuncA == GE_SRCBLEND_DSTALPHA || blendFuncA == GE_SRCBLEND_DOUBLEDSTALPHA) {
glBlendFuncA = GL_ZERO;
glBlendFuncA = BlendFactor::ZERO;
}
if (blendFuncA == GE_SRCBLEND_INVDSTALPHA || blendFuncA == GE_SRCBLEND_DOUBLEINVDSTALPHA) {
glBlendFuncA = GL_ONE;
glBlendFuncA = BlendFactor::ONE;
}
if (blendFuncB == GE_DSTBLEND_DSTALPHA || blendFuncB == GE_DSTBLEND_DOUBLEDSTALPHA) {
glBlendFuncB = GL_ZERO;
glBlendFuncB = BlendFactor::ZERO;
}
if (blendFuncB == GE_DSTBLEND_INVDSTALPHA || blendFuncB == GE_DSTBLEND_DOUBLEINVDSTALPHA) {
glBlendFuncB = GL_ONE;
glBlendFuncB = BlendFactor::ONE;
}
}
if (usePreSrc) {
glBlendFuncA = GL_ONE;
glBlendFuncA = BlendFactor::ONE;
// Need to pull in the fixed color.
if (blendFuncA == GE_SRCBLEND_FIXA) {
shaderManager_->DirtyUniform(DIRTY_SHADERBLEND);
@ -439,7 +465,7 @@ void TransformDrawEngine::ApplyBlendState() {
glstate.blendColor.set(blendColor);
};
auto defaultBlendColor = [&]() {
if (constantAlphaGL == GL_CONSTANT_ALPHA) {
if (constantAlphaGL == BlendFactor::CONSTANT_ALPHA) {
const float blendColor[4] = {1.0f, 1.0f, 1.0f, constantAlpha};
glstate.blendColor.set(blendColor);
}
@ -448,22 +474,22 @@ void TransformDrawEngine::ApplyBlendState() {
if (blendFuncA == GE_SRCBLEND_FIXA || blendFuncB == GE_DSTBLEND_FIXB) {
const Vec3f fixAVec = Vec3f::FromRGB(fixA);
const Vec3f fixBVec = Vec3f::FromRGB(fixB);
if (glBlendFuncA == GL_INVALID_ENUM && glBlendFuncB != GL_INVALID_ENUM) {
if (glBlendFuncA == BlendFactor::INVALID && glBlendFuncB != BlendFactor::INVALID) {
// Can use blendcolor trivially.
setBlendColorv(fixAVec);
glBlendFuncA = GL_CONSTANT_COLOR;
} else if (glBlendFuncA != GL_INVALID_ENUM && glBlendFuncB == GL_INVALID_ENUM) {
glBlendFuncA = BlendFactor::CONSTANT_COLOR;
} else if (glBlendFuncA != BlendFactor::INVALID && glBlendFuncB == BlendFactor::INVALID) {
// Can use blendcolor trivially.
setBlendColorv(fixBVec);
glBlendFuncB = GL_CONSTANT_COLOR;
} else if (glBlendFuncA == GL_INVALID_ENUM && glBlendFuncB == GL_INVALID_ENUM) {
glBlendFuncB = BlendFactor::CONSTANT_COLOR;
} else if (glBlendFuncA == BlendFactor::INVALID && glBlendFuncB == BlendFactor::INVALID) {
if (blendColorSimilar(fixAVec, Vec3f::AssignToAll(1.0f) - fixBVec)) {
glBlendFuncA = GL_CONSTANT_COLOR;
glBlendFuncB = GL_ONE_MINUS_CONSTANT_COLOR;
glBlendFuncA = BlendFactor::CONSTANT_COLOR;
glBlendFuncB = BlendFactor::ONE_MINUS_CONSTANT_COLOR;
setBlendColorv(fixAVec);
} else if (blendColorSimilar(fixAVec, fixBVec)) {
glBlendFuncA = GL_CONSTANT_COLOR;
glBlendFuncB = GL_CONSTANT_COLOR;
glBlendFuncA = BlendFactor::CONSTANT_COLOR;
glBlendFuncB = BlendFactor::CONSTANT_COLOR;
setBlendColorv(fixAVec);
} else {
DEBUG_LOG(G3D, "ERROR INVALID blendcolorstate: FixA=%06x FixB=%06x FuncA=%i FuncB=%i", fixA, fixB, blendFuncA, blendFuncB);
@ -471,23 +497,23 @@ void TransformDrawEngine::ApplyBlendState() {
const bool nearZeroA = blendColorSimilar(fixAVec, Vec3f::AssignToAll(0.0f), 0.25f);
const bool nearZeroB = blendColorSimilar(fixBVec, Vec3f::AssignToAll(0.0f), 0.25f);
if (nearZeroA || blendColorSimilar(fixAVec, Vec3f::AssignToAll(1.0f), 0.25f)) {
glBlendFuncA = nearZeroA ? GL_ZERO : GL_ONE;
glBlendFuncB = GL_CONSTANT_COLOR;
glBlendFuncA = nearZeroA ? BlendFactor::ZERO : BlendFactor::ONE;
glBlendFuncB = BlendFactor::CONSTANT_COLOR;
setBlendColorv(fixBVec);
} else {
// We need to pick something. Let's go with A as the fixed color.
glBlendFuncA = GL_CONSTANT_COLOR;
glBlendFuncB = nearZeroB ? GL_ZERO : GL_ONE;
glBlendFuncA = BlendFactor::CONSTANT_COLOR;
glBlendFuncB = nearZeroB ? BlendFactor::ZERO : BlendFactor::ONE;
setBlendColorv(fixAVec);
}
}
} else {
// We optimized both, but that's probably not necessary, so let's pick one to be constant.
if (blendFuncA == GE_SRCBLEND_FIXA && !usePreSrc && approxFuncA) {
glBlendFuncA = GL_CONSTANT_COLOR;
glBlendFuncA = BlendFactor::CONSTANT_COLOR;
setBlendColorv(fixAVec);
} else if (approxFuncB) {
glBlendFuncB = GL_CONSTANT_COLOR;
glBlendFuncB = BlendFactor::CONSTANT_COLOR;
setBlendColorv(fixBVec);
} else {
defaultBlendColor();
@ -501,10 +527,10 @@ void TransformDrawEngine::ApplyBlendState() {
// So in non-buffered rendering, we will simply consider the dest alpha to be zero in blending equations.
#ifdef ANDROID
if (g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) {
if (glBlendFuncA == GL_DST_ALPHA) glBlendFuncA = GL_ZERO;
if (glBlendFuncB == GL_DST_ALPHA) glBlendFuncB = GL_ZERO;
if (glBlendFuncA == GL_ONE_MINUS_DST_ALPHA) glBlendFuncA = GL_ONE;
if (glBlendFuncB == GL_ONE_MINUS_DST_ALPHA) glBlendFuncB = GL_ONE;
if (glBlendFuncA == BlendFactor::DST_ALPHA) glBlendFuncA = BlendFactor::ZERO;
if (glBlendFuncB == BlendFactor::DST_ALPHA) glBlendFuncB = BlendFactor::ZERO;
if (glBlendFuncA == BlendFactor::ONE_MINUS_DST_ALPHA) glBlendFuncA = BlendFactor::ONE;
if (glBlendFuncB == BlendFactor::ONE_MINUS_DST_ALPHA) glBlendFuncB = BlendFactor::ONE;
}
#endif
@ -513,75 +539,75 @@ void TransformDrawEngine::ApplyBlendState() {
// The stencil-to-alpha in fragment shader doesn't apply here (blending is enabled), and we shouldn't
// do any blending in the alpha channel as that doesn't seem to happen on PSP. So, we attempt to
// apply the stencil to the alpha, since that's what should be stored.
GLenum alphaEq = GL_FUNC_ADD;
BlendEq alphaEq = BlendEq::ADD;
if (replaceAlphaWithStencil != REPLACE_ALPHA_NO) {
// Let the fragment shader take care of it.
switch (ReplaceAlphaWithStencilType()) {
case STENCIL_VALUE_INCR_4:
case STENCIL_VALUE_INCR_8:
// We'll add the increment value.
glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_ONE, GL_ONE);
blendState.setFactors(glBlendFuncA, glBlendFuncB, BlendFactor::ONE, BlendFactor::ONE);
break;
case STENCIL_VALUE_DECR_4:
case STENCIL_VALUE_DECR_8:
// Like add with a small value, but subtracting.
glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_ONE, GL_ONE);
alphaEq = GL_FUNC_SUBTRACT;
blendState.setFactors(glBlendFuncA, glBlendFuncB, BlendFactor::ONE, BlendFactor::ONE);
alphaEq = BlendEq::SUBTRACT;
break;
case STENCIL_VALUE_INVERT:
// This will subtract by one, effectively inverting the bits.
glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_ONE, GL_ONE);
alphaEq = GL_FUNC_REVERSE_SUBTRACT;
blendState.setFactors(glBlendFuncA, glBlendFuncB, BlendFactor::ONE, BlendFactor::ONE);
alphaEq = BlendEq::REVERSE_SUBTRACT;
break;
default:
glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_ONE, GL_ZERO);
blendState.setFactors(glBlendFuncA, glBlendFuncB, BlendFactor::ONE, BlendFactor::ZERO);
break;
}
} else if (gstate.isStencilTestEnabled()) {
switch (ReplaceAlphaWithStencilType()) {
case STENCIL_VALUE_KEEP:
glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_ZERO, GL_ONE);
blendState.setFactors(glBlendFuncA, glBlendFuncB, BlendFactor::ZERO, BlendFactor::ONE);
break;
case STENCIL_VALUE_ONE:
// This won't give one but it's our best shot...
glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_ONE, GL_ONE);
blendState.setFactors(glBlendFuncA, glBlendFuncB, BlendFactor::ONE, BlendFactor::ONE);
break;
case STENCIL_VALUE_ZERO:
glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_ZERO, GL_ZERO);
blendState.setFactors(glBlendFuncA, glBlendFuncB, BlendFactor::ZERO, BlendFactor::ZERO);
break;
case STENCIL_VALUE_UNIFORM:
// This won't give a correct value (it multiplies) but it may be better than random values.
glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, constantAlphaGL, GL_ZERO);
blendState.setFactors(glBlendFuncA, glBlendFuncB, constantAlphaGL, BlendFactor::ZERO);
break;
case STENCIL_VALUE_INCR_4:
case STENCIL_VALUE_INCR_8:
// This won't give a correct value always, but it will try to increase at least.
glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, constantAlphaGL, GL_ONE);
blendState.setFactors(glBlendFuncA, glBlendFuncB, constantAlphaGL, BlendFactor::ONE);
break;
case STENCIL_VALUE_DECR_4:
case STENCIL_VALUE_DECR_8:
// This won't give a correct value always, but it will try to decrease at least.
glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, constantAlphaGL, GL_ONE);
alphaEq = GL_FUNC_SUBTRACT;
blendState.setFactors(glBlendFuncA, glBlendFuncB, constantAlphaGL, BlendFactor::ONE);
alphaEq = BlendEq::SUBTRACT;
break;
case STENCIL_VALUE_INVERT:
glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_ONE, GL_ONE);
blendState.setFactors(glBlendFuncA, glBlendFuncB, BlendFactor::ONE, BlendFactor::ONE);
// If the output alpha is near 1, this will basically invert. It's our best shot.
alphaEq = GL_FUNC_REVERSE_SUBTRACT;
alphaEq = BlendEq::REVERSE_SUBTRACT;
break;
}
} else {
// Retain the existing value when stencil testing is off.
glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_ZERO, GL_ONE);
blendState.setFactors(glBlendFuncA, glBlendFuncB, BlendFactor::ZERO, BlendFactor::ONE);
}
if (gstate_c.Supports(GPU_SUPPORTS_BLEND_MINMAX)) {
glstate.blendEquationSeparate.set(eqLookup[blendFuncEq], alphaEq);
blendState.setEquation(eqLookup[blendFuncEq], alphaEq);
} else {
glstate.blendEquationSeparate.set(eqLookupNoMinMax[blendFuncEq], alphaEq);
blendState.setEquation(eqLookupNoMinMax[blendFuncEq], alphaEq);
}
}
@ -602,7 +628,18 @@ void TransformDrawEngine::ApplyDrawState(int prim) {
PROFILE_THIS_SCOPE("applydrawstate");
// Set blend - unless we need to do it in the shader.
ApplyBlendState();
GenericBlendState blendState;
ConvertBlendState(blendState);
if (blendState.enabled) {
glstate.blend.enable();
glstate.blendEquationSeparate.set(glBlendEqLookup[(size_t)blendState.eqColor], glBlendEqLookup[(size_t)blendState.eqAlpha]);
glstate.blendFuncSeparate.set(
glBlendFactorLookup[(size_t)blendState.srcColor], glBlendFactorLookup[(size_t)blendState.dstColor],
glBlendFactorLookup[(size_t)blendState.srcAlpha], glBlendFactorLookup[(size_t)blendState.dstAlpha]);
} else {
glstate.blend.disable();
}
bool alwaysDepthWrite = g_Config.bAlwaysDepthWrite;
bool enableStencilTest = !g_Config.bDisableStencilTest;

View File

@ -194,8 +194,8 @@ private:
void DoFlush();
void ApplyDrawState(int prim);
void ApplyDrawStateLate();
void ApplyBlendState();
void ApplyStencilReplaceAndLogicOp(ReplaceAlphaType replaceAlphaWithStencil);
void ConvertBlendState(GenericBlendState &blendState);
void ApplyStencilReplaceAndLogicOp(ReplaceAlphaType replaceAlphaWithStencil, GenericBlendState &blendState);
bool ApplyShaderBlending();
inline void ResetShaderBlending();
GLuint AllocateBuffer();