#pragma once
#include <cstdint>
#include "Common/CommonTypes.h"
#include "GPU/ge_constants.h"
#include "GPU/GPUState.h"
enum StencilValueType {
STENCIL_VALUE_UNIFORM,
STENCIL_VALUE_ZERO,
STENCIL_VALUE_ONE,
STENCIL_VALUE_KEEP,
STENCIL_VALUE_INVERT,
STENCIL_VALUE_INCR_4,
STENCIL_VALUE_INCR_8,
STENCIL_VALUE_DECR_4,
STENCIL_VALUE_DECR_8,
};
enum ReplaceAlphaType {
REPLACE_ALPHA_NO = 0,
REPLACE_ALPHA_YES = 1,
REPLACE_ALPHA_DUALSOURCE = 2,
};
enum ReplaceBlendType {
REPLACE_BLEND_NO,
REPLACE_BLEND_STANDARD,
REPLACE_BLEND_PRE_SRC,
REPLACE_BLEND_PRE_SRC_2X_ALPHA,
REPLACE_BLEND_2X_ALPHA,
REPLACE_BLEND_2X_SRC,
REPLACE_BLEND_READ_FRAMEBUFFER,
REPLACE_BLEND_BLUE_TO_ALPHA,
};
enum SimulateLogicOpType {
LOGICOPTYPE_NORMAL,
LOGICOPTYPE_ONE,
LOGICOPTYPE_INVERT,
};
bool IsAlphaTestTriviallyTrue();
bool IsColorTestAgainstZero();
bool IsColorTestTriviallyTrue();
bool IsAlphaTestAgainstZero();
bool NeedsTestDiscard();
bool IsDepthTestEffectivelyDisabled();
bool IsStencilTestOutputDisabled();
StencilValueType ReplaceAlphaWithStencilType();
ReplaceAlphaType ReplaceAlphaWithStencil(ReplaceBlendType replaceBlend);
ReplaceBlendType ReplaceBlendWithShader(GEBufferFormat bufferFormat);
SimulateLogicOpType SimulateLogicOpShaderTypeIfNeeded();
struct ViewportAndScissor {
int scissorX;
int scissorY;
int scissorW;
int scissorH;
float viewportX;
float viewportY;
float viewportW;
float viewportH;
float depthRangeMin;
float depthRangeMax;
float widthScale;
float heightScale;
float depthScale;
float xOffset;
float yOffset;
float zOffset;
bool throughMode;
};
void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, float renderHeight, int bufferWidth, int bufferHeight, ViewportAndScissor &out);
void UpdateCachedViewportState(const ViewportAndScissor &vpAndScissor);
class DepthScaleFactors {
public:
DepthScaleFactors(double offset, double scale) : offset_(offset), scale_(scale) {}
float DecodeToU16(float z) const {
return (float)((z - offset_) * scale_);
}
float EncodeFromU16(float z_u16) const {
return (float)(((double)z_u16 / scale_) + offset_);
}
float Offset() const { return (float)offset_; }
float ScaleU16() const { return (float)scale_; }
float Scale() const { return (float)(scale_ / 65535.0); }
private:
double offset_;
double scale_;
};
DepthScaleFactors GetDepthScaleFactors(u32 useFlags);
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_COLOR,
ONE_MINUS_SRC1_COLOR,
SRC1_ALPHA,
ONE_MINUS_SRC1_ALPHA,
INVALID,
COUNT,
};
enum class BlendEq : uint8_t {
ADD,
SUBTRACT,
REVERSE_SUBTRACT,
MIN,
MAX,
COUNT
};
struct GenericBlendState {
bool applyFramebufferRead;
bool dirtyShaderBlendFixValues;
ReplaceAlphaType replaceAlphaWithStencil;
ReplaceBlendType replaceBlend;
SimulateLogicOpType simulateLogicOpType;
bool blendEnabled;
BlendFactor srcColor;
BlendFactor dstColor;
BlendFactor srcAlpha;
BlendFactor dstAlpha;
BlendEq eqColor;
BlendEq eqAlpha;
bool useBlendColor;
u32 blendColor;
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;
}
void setBlendColor(uint32_t color, uint8_t alpha) {
blendColor = color | ((uint32_t)alpha << 24);
useBlendColor = true;
}
void defaultBlendColor(uint8_t alpha) {
blendColor = 0xFFFFFF | ((uint32_t)alpha << 24);
useBlendColor = true;
}
void Log();
};
void ApplyStencilReplaceAndLogicOpIgnoreBlend(ReplaceAlphaType replaceAlphaWithStencil, GenericBlendState &blendState);
struct GenericMaskState {
bool applyFramebufferRead;
uint32_t uniformMask;
uint8_t channelMask;
void ConvertToShaderBlend() {
channelMask = 0xF;
applyFramebufferRead = true;
}
void Log();
};
struct GenericStencilFuncState {
bool enabled;
GEComparison testFunc;
u8 testRef;
u8 testMask;
u8 writeMask;
GEStencilOp sFail;
GEStencilOp zFail;
GEStencilOp zPass;
};
void ConvertStencilFuncState(GenericStencilFuncState &stencilFuncState);
struct GenericLogicState {
bool applyFramebufferRead;
bool logicOpEnabled;
GELogicOp logicOp;
void ApplyToBlendState(GenericBlendState &blendState);
void ConvertToShaderBlend() {
if (logicOp != GE_LOGIC_COPY) {
logicOpEnabled = false;
applyFramebufferRead = true;
}
}
};
struct ComputedPipelineState {
GenericBlendState blendState;
GenericMaskState maskState;
GenericLogicState logicState;
void Convert(bool shaderBitOpsSupported, bool fbReadAllowed);
bool FramebufferRead() const {
return blendState.applyFramebufferRead || maskState.applyFramebufferRead || logicState.applyFramebufferRead;
}
};
inline bool SpongebobDepthInverseConditions(const GenericStencilFuncState &stencilState) {
if (!gstate.isDepthTestEnabled() || gstate.isDepthWriteEnabled())
return false;
if (gstate.getDepthTestFunction() != GE_COMP_GEQUAL)
return false;
if (stencilState.zFail != GE_STENCILOP_ZERO || stencilState.sFail != GE_STENCILOP_KEEP || stencilState.zPass != GE_STENCILOP_KEEP)
return false;
if (stencilState.testFunc != GE_COMP_ALWAYS || stencilState.writeMask != 0xFF)
return false;
if (gstate.getColorMask() == 0xFFFFFF00)
return true;
if (!gstate.isAlphaBlendEnabled() || gstate.getBlendFuncA() != GE_SRCBLEND_SRCALPHA || gstate.getBlendFuncB() != GE_DSTBLEND_INVSRCALPHA)
return false;
if (gstate.isTextureMapEnabled())
return false;
if (gstate.getMaterialAmbientA() == 0x00 && gstate.getMaterialUpdate() == 0)
return true;
if (gstate.getMaterialUpdate() == 1)
return true;
return false;
}