4
#include "Common/StringUtils.h"
5
#include "Core/Config.h"
7
#include "GPU/ge_constants.h"
8
#include "GPU/GPUState.h"
9
#include "GPU/Common/GPUStateUtils.h"
10
#include "GPU/Common/ShaderId.h"
11
#include "GPU/Common/VertexDecoderCommon.h"
13
std::string VertexShaderDesc(const ShaderID &id) {
14
std::stringstream desc;
15
desc << StringFromFormat("%08x:%08x ", id.d[1], id.d[0]);
16
if (id.Bit(VS_BIT_IS_THROUGH)) desc << "THR ";
17
if (id.Bit(VS_BIT_USE_HW_TRANSFORM)) desc << "HWX ";
18
if (id.Bit(VS_BIT_HAS_COLOR)) desc << "C ";
19
if (id.Bit(VS_BIT_HAS_TEXCOORD)) desc << "T ";
20
if (id.Bit(VS_BIT_HAS_NORMAL)) desc << "N ";
21
if (id.Bit(VS_BIT_LMODE)) desc << "LM ";
22
if (id.Bit(VS_BIT_ENABLE_FOG)) desc << "Fog ";
23
if (id.Bit(VS_BIT_NORM_REVERSE)) desc << "RevN ";
24
if (id.Bit(VS_BIT_DO_TEXTURE)) desc << "Tex ";
25
if (id.Bit(VS_BIT_DO_TEXTURE_PROJ)) desc << "TexProj ";
26
int uvgMode = id.Bits(VS_BIT_UVGEN_MODE, 2);
27
const char *uvgModes[4] = { "UV ", "UVMtx ", "UVEnv ", "UVUnk " };
28
int ls0 = id.Bits(VS_BIT_LS0, 2);
29
int ls1 = id.Bits(VS_BIT_LS1, 2);
31
if (uvgMode) desc << uvgModes[uvgMode];
32
if (id.Bit(VS_BIT_ENABLE_BONES)) desc << "Bones:" << (id.Bits(VS_BIT_BONES, 3) + 1) << " ";
34
if (id.Bit(VS_BIT_LIGHTING_ENABLE)) {
36
for (int i = 0; i < 4; i++) {
37
if (id.Bit(VS_BIT_LIGHT0_ENABLE + i) || (uvgMode == GE_TEXMAP_ENVIRONMENT_MAP && (ls0 == i || ls1 == i))) {
39
desc << "c:" << id.Bits(VS_BIT_LIGHT0_COMP + 4 * i, 2) << " t:" << id.Bits(VS_BIT_LIGHT0_TYPE + 4 * i, 2) << " ";
43
if (id.Bits(VS_BIT_MATERIAL_UPDATE, 3)) desc << "MatUp:" << id.Bits(VS_BIT_MATERIAL_UPDATE, 3) << " ";
44
if (id.Bits(VS_BIT_WEIGHT_FMTSCALE, 2)) desc << "WScale " << id.Bits(VS_BIT_WEIGHT_FMTSCALE, 2) << " ";
45
if (id.Bits(VS_BIT_TEXCOORD_FMTSCALE, 2)) desc << "TCScale " << id.Bits(VS_BIT_TEXCOORD_FMTSCALE, 2) << " ";
46
if (id.Bit(VS_BIT_FLATSHADE)) desc << "Flat ";
53
void ComputeVertexShaderID(ShaderID *id_out, u32 vertType, bool useHWTransform) {
54
bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear();
55
bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX;
56
bool doShadeMapping = doTexture && (gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP);
57
bool doFlatShading = gstate.getShadeMode() == GE_SHADE_FLAT && !gstate.isModeClear();
59
bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0;
60
bool hasNormal = (vertType & GE_VTYPE_NRM_MASK) != 0;
61
bool hasTexcoord = (vertType & GE_VTYPE_TC_MASK) != 0;
62
bool enableFog = gstate.isFogEnabled() && !gstate.isModeThrough() && !gstate.isModeClear();
63
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled();
64
// lmode: && !isModeThrough!?
67
id.SetBit(VS_BIT_LMODE, lmode);
68
id.SetBit(VS_BIT_IS_THROUGH, gstate.isModeThrough());
69
id.SetBit(VS_BIT_ENABLE_FOG, enableFog);
70
id.SetBit(VS_BIT_HAS_COLOR, hasColor);
73
id.SetBit(VS_BIT_DO_TEXTURE);
74
id.SetBit(VS_BIT_DO_TEXTURE_PROJ, doTextureProjection);
78
id.SetBit(VS_BIT_USE_HW_TRANSFORM);
79
id.SetBit(VS_BIT_HAS_NORMAL, hasNormal);
81
// UV generation mode. doShadeMapping is implicitly stored here.
82
id.SetBits(VS_BIT_UVGEN_MODE, 2, gstate.getUVGenMode());
84
// The next bits are used differently depending on UVgen mode
85
if (doTextureProjection) {
86
id.SetBits(VS_BIT_UVPROJ_MODE, 2, gstate.getUVProjMode());
87
} else if (doShadeMapping) {
88
id.SetBits(VS_BIT_LS0, 2, gstate.getUVLS0());
89
id.SetBits(VS_BIT_LS1, 2, gstate.getUVLS1());
93
bool enableBones = vertTypeIsSkinningEnabled(vertType);
94
id.SetBit(VS_BIT_ENABLE_BONES, enableBones);
96
id.SetBits(VS_BIT_BONES, 3, TranslateNumBones(vertTypeGetNumBoneWeights(vertType)) - 1);
97
// 2 bits. We should probably send in the weight scalefactor as a uniform instead,
98
// or simply preconvert all weights to floats.
99
id.SetBits(VS_BIT_WEIGHT_FMTSCALE, 2, (vertType & GE_VTYPE_WEIGHT_MASK) >> GE_VTYPE_WEIGHT_SHIFT);
102
// Okay, d[1] coming up. ==============
103
if (gstate.isLightingEnabled() || doShadeMapping) {
104
// doShadeMapping is stored as UVGenMode, so this is enough for isLightingEnabled.
105
if (gstate.isLightingEnabled()) {
106
id.SetBits(VS_BIT_MATERIAL_UPDATE, 3, gstate.getMaterialUpdate() & 7);
107
id.SetBit(VS_BIT_LIGHTING_ENABLE);
110
for (int i = 0; i < 4; i++) {
111
bool chanEnabled = gstate.isLightChanEnabled(i) != 0 && gstate.isLightingEnabled();
112
id.SetBit(VS_BIT_LIGHT0_ENABLE + i, chanEnabled);
113
if (chanEnabled || (doShadeMapping && (gstate.getUVLS0() == i || gstate.getUVLS1() == i))) {
114
id.SetBits(VS_BIT_LIGHT0_COMP + 4 * i, 2, gstate.getLightComputation(i));
115
id.SetBits(VS_BIT_LIGHT0_TYPE + 4 * i, 2, gstate.getLightType(i));
120
id.SetBit(VS_BIT_NORM_REVERSE, gstate.areNormalsReversed());
121
id.SetBit(VS_BIT_HAS_TEXCOORD, hasTexcoord);
122
if (doTextureProjection && gstate.getUVProjMode() == GE_PROJMAP_UV) {
123
id.SetBits(VS_BIT_TEXCOORD_FMTSCALE, 2, (vertType & GE_VTYPE_TC_MASK) >> GE_VTYPE_TC_SHIFT); // two bits
125
id.SetBits(VS_BIT_TEXCOORD_FMTSCALE, 2, 3); // float - no scaling
129
id.SetBit(VS_BIT_FLATSHADE, doFlatShading);
135
static const char *alphaTestFuncs[] = { "NEVER", "ALWAYS", "==", "!=", "<", "<=", ">", ">=" };
137
std::string FragmentShaderDesc(const ShaderID &id) {
138
std::stringstream desc;
139
desc << StringFromFormat("%08x:%08x ", id.d[1], id.d[0]);
140
if (id.Bit(FS_BIT_CLEARMODE)) desc << "Clear ";
141
if (id.Bit(FS_BIT_DO_TEXTURE)) desc << "Tex ";
142
if (id.Bit(FS_BIT_DO_TEXTURE_PROJ)) desc << "TexProj ";
143
if (id.Bit(FS_BIT_TEXALPHA)) desc << "TexAlpha ";
144
if (id.Bit(FS_BIT_TEXTURE_AT_OFFSET)) desc << "TexOffs ";
145
if (id.Bit(FS_BIT_LMODE)) desc << "LM ";
146
if (id.Bit(FS_BIT_ENABLE_FOG)) desc << "Fog ";
147
if (id.Bit(FS_BIT_COLOR_DOUBLE)) desc << "2x ";
148
if (id.Bit(FS_BIT_FLATSHADE)) desc << "Flat ";
149
if (id.Bit(FS_BIT_BGRA_TEXTURE)) desc << "BGRA ";
150
if (id.Bit(FS_BIT_SHADER_TEX_CLAMP)) {
152
if (id.Bit(FS_BIT_CLAMP_S)) desc << "S";
153
if (id.Bit(FS_BIT_CLAMP_T)) desc << "T";
156
if (id.Bits(FS_BIT_REPLACE_BLEND, 3)) {
157
desc << "ReplaceBlend_" << id.Bits(FS_BIT_REPLACE_BLEND, 3) << "A:" << id.Bits(FS_BIT_BLENDFUNC_A, 4) << "_B:" << id.Bits(FS_BIT_BLENDFUNC_B, 4) << "_Eq:" << id.Bits(FS_BIT_BLENDEQ, 3) << " ";
160
switch (id.Bits(FS_BIT_STENCIL_TO_ALPHA, 2)) {
161
case REPLACE_ALPHA_NO: break;
162
case REPLACE_ALPHA_YES: desc << "StenToAlpha "; break;
163
case REPLACE_ALPHA_DUALSOURCE: desc << "StenToAlphaDual "; break;
165
if (id.Bits(FS_BIT_STENCIL_TO_ALPHA, 2) != REPLACE_ALPHA_NO) {
166
switch (id.Bits(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, 4)) {
167
case STENCIL_VALUE_UNIFORM: desc << "StenUniform "; break;
168
case STENCIL_VALUE_ZERO: desc << "Sten0 "; break;
169
case STENCIL_VALUE_ONE: desc << "Sten1 "; break;
170
case STENCIL_VALUE_KEEP: desc << "StenKeep "; break;
171
case STENCIL_VALUE_INVERT: desc << "StenInv "; break;
172
case STENCIL_VALUE_INCR_4: desc << "StenIncr4 "; break;
173
case STENCIL_VALUE_INCR_8: desc << "StenIncr8 "; break;
174
case STENCIL_VALUE_DECR_4: desc << "StenDecr4 "; break;
175
case STENCIL_VALUE_DECR_8: desc << "StenDecr4 "; break;
176
default: desc << "StenUnknown"; break;
179
if (id.Bit(FS_BIT_DO_TEXTURE)) {
180
switch (id.Bits(FS_BIT_TEXFUNC, 3)) {
181
case GE_TEXFUNC_ADD: desc << "TFuncAdd "; break;
182
case GE_TEXFUNC_BLEND: desc << "TFuncBlend "; break;
183
case GE_TEXFUNC_DECAL: desc << "TFuncDecal "; break;
184
case GE_TEXFUNC_MODULATE: desc << "TFuncMod "; break;
185
case GE_TEXFUNC_REPLACE: desc << "TFuncRepl "; break;
186
default: desc << "TFuncUnk "; break;
190
if (id.Bit(FS_BIT_ALPHA_AGAINST_ZERO)) desc << "AlphaTest0 " << alphaTestFuncs[id.Bits(FS_BIT_ALPHA_TEST_FUNC, 3)] << " ";
191
else if (id.Bit(FS_BIT_ALPHA_TEST)) desc << "AlphaTest " << alphaTestFuncs[id.Bits(FS_BIT_ALPHA_TEST_FUNC, 3)] << " ";
192
if (id.Bit(FS_BIT_COLOR_AGAINST_ZERO)) desc << "ColorTest0 " << alphaTestFuncs[id.Bits(FS_BIT_COLOR_TEST_FUNC, 2)] << " "; // first 4 match;
193
else if (id.Bit(FS_BIT_COLOR_TEST)) desc << "ColorTest " << alphaTestFuncs[id.Bits(FS_BIT_COLOR_TEST_FUNC, 2)] << " "; // first 4 match
198
// Here we must take all the bits of the gstate that determine what the fragment shader will
199
// look like, and concatenate them together into an ID.
200
void ComputeFragmentShaderID(ShaderID *id_out) {
202
if (gstate.isModeClear()) {
203
// We only need one clear shader, so let's ignore the rest of the bits.
204
id.SetBit(FS_BIT_CLEARMODE);
206
bool isModeThrough = gstate.isModeThrough();
207
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !isModeThrough;
208
bool enableFog = gstate.isFogEnabled() && !isModeThrough;
209
bool enableAlphaTest = gstate.isAlphaTestEnabled() && !IsAlphaTestTriviallyTrue() && !g_Config.bDisableAlphaTest;
210
bool enableColorTest = gstate.isColorTestEnabled() && !IsColorTestTriviallyTrue();
211
bool enableColorDoubling = gstate.isColorDoublingEnabled() && gstate.isTextureMapEnabled();
212
bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX;
213
bool doTextureAlpha = gstate.isTextureAlphaUsed();
214
bool doFlatShading = gstate.getShadeMode() == GE_SHADE_FLAT;
216
ReplaceBlendType replaceBlend = ReplaceBlendWithShader(gstate_c.allowShaderBlend, gstate.FrameBufFormat());
217
ReplaceAlphaType stencilToAlpha = ReplaceAlphaWithStencil(replaceBlend);
219
// All texfuncs except replace are the same for RGB as for RGBA with full alpha.
220
if (gstate_c.textureFullAlpha && gstate.getTextureFunction() != GE_TEXFUNC_REPLACE)
221
doTextureAlpha = false;
223
if (gstate.isTextureMapEnabled()) {
224
id.SetBit(FS_BIT_DO_TEXTURE);
225
id.SetBits(FS_BIT_TEXFUNC, 3, gstate.getTextureFunction());
226
id.SetBit(FS_BIT_TEXALPHA, doTextureAlpha & 1); // rgb or rgba
227
if (gstate_c.needShaderTexClamp) {
228
bool textureAtOffset = gstate_c.curTextureXOffset != 0 || gstate_c.curTextureYOffset != 0;
230
id.SetBit(FS_BIT_SHADER_TEX_CLAMP);
231
id.SetBit(FS_BIT_CLAMP_S, gstate.isTexCoordClampedS());
232
id.SetBit(FS_BIT_CLAMP_T, gstate.isTexCoordClampedT());
233
id.SetBit(FS_BIT_TEXTURE_AT_OFFSET, textureAtOffset);
235
id.SetBit(FS_BIT_BGRA_TEXTURE, gstate_c.bgraTexture);
238
id.SetBit(FS_BIT_LMODE, lmode);
239
if (enableAlphaTest) {
241
id.SetBit(FS_BIT_ALPHA_TEST);
242
id.SetBits(FS_BIT_ALPHA_TEST_FUNC, 3, gstate.getAlphaTestFunction());
243
id.SetBit(FS_BIT_ALPHA_AGAINST_ZERO, IsAlphaTestAgainstZero());
245
if (enableColorTest) {
247
id.SetBit(FS_BIT_COLOR_TEST);
248
id.SetBits(FS_BIT_COLOR_TEST_FUNC, 2, gstate.getColorTestFunction());
249
id.SetBit(FS_BIT_COLOR_AGAINST_ZERO, IsColorTestAgainstZero());
252
id.SetBit(FS_BIT_ENABLE_FOG, enableFog);
253
id.SetBit(FS_BIT_DO_TEXTURE_PROJ, doTextureProjection);
254
id.SetBit(FS_BIT_COLOR_DOUBLE, enableColorDoubling);
257
id.SetBits(FS_BIT_STENCIL_TO_ALPHA, 2, stencilToAlpha);
259
if (stencilToAlpha != REPLACE_ALPHA_NO) {
261
id.SetBits(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, 4, ReplaceAlphaWithStencilType());
265
id.SetBits(FS_BIT_REPLACE_LOGIC_OP_TYPE, 2, ReplaceLogicOpType());
267
// If replaceBlend == REPLACE_BLEND_STANDARD (or REPLACE_BLEND_NO) nothing is done, so we kill these bits.
268
if (replaceBlend > REPLACE_BLEND_STANDARD) {
270
id.SetBits(FS_BIT_REPLACE_BLEND, 3, replaceBlend);
272
id.SetBits(FS_BIT_BLENDEQ, 3, gstate.getBlendEq());
273
id.SetBits(FS_BIT_BLENDFUNC_A, 4, gstate.getBlendFuncA());
274
id.SetBits(FS_BIT_BLENDFUNC_B, 4, gstate.getBlendFuncB());
276
id.SetBit(FS_BIT_FLATSHADE, doFlatShading);