1 #include <string>
2 #include <sstream>
3
4 #include "Common/GPU/thin3d.h"
5 #include "Common/StringUtils.h"
6 #include "Core/Config.h"
7
8 #include "GPU/ge_constants.h"
9 #include "GPU/GPUState.h"
10 #include "GPU/Common/GPUStateUtils.h"
11 #include "GPU/Common/ShaderId.h"
12 #include "GPU/Common/VertexDecoderCommon.h"
13
VertexShaderDesc(const VShaderID & id)14 std::string VertexShaderDesc(const VShaderID &id) {
15 std::stringstream desc;
16 desc << StringFromFormat("%08x:%08x ", id.d[1], id.d[0]);
17 if (id.Bit(VS_BIT_IS_THROUGH)) desc << "THR ";
18 if (id.Bit(VS_BIT_USE_HW_TRANSFORM)) desc << "HWX ";
19 if (id.Bit(VS_BIT_HAS_COLOR)) desc << "C ";
20 if (id.Bit(VS_BIT_HAS_TEXCOORD)) desc << "T ";
21 if (id.Bit(VS_BIT_HAS_NORMAL)) desc << "N ";
22 if (id.Bit(VS_BIT_LMODE)) desc << "LM ";
23 if (id.Bit(VS_BIT_ENABLE_FOG)) desc << "Fog ";
24 if (id.Bit(VS_BIT_NORM_REVERSE)) desc << "RevN ";
25 if (id.Bit(VS_BIT_DO_TEXTURE)) desc << "Tex ";
26 int uvgMode = id.Bits(VS_BIT_UVGEN_MODE, 2);
27 if (uvgMode == GE_TEXMAP_TEXTURE_MATRIX) {
28 int uvprojMode = id.Bits(VS_BIT_UVPROJ_MODE, 2);
29 const char *uvprojModes[4] = { "TexProjPos ", "TexProjUV ", "TexProjNNrm ", "TexProjNrm " };
30 desc << uvprojModes[uvprojMode];
31 }
32 const char *uvgModes[4] = { "UV ", "UVMtx ", "UVEnv ", "UVUnk " };
33 int ls0 = id.Bits(VS_BIT_LS0, 2);
34 int ls1 = id.Bits(VS_BIT_LS1, 2);
35
36 if (uvgMode) desc << uvgModes[uvgMode];
37 if (id.Bit(VS_BIT_ENABLE_BONES)) desc << "Bones:" << (id.Bits(VS_BIT_BONES, 3) + 1) << " ";
38 // Lights
39 if (id.Bit(VS_BIT_LIGHTING_ENABLE)) {
40 desc << "Light: ";
41 }
42 for (int i = 0; i < 4; i++) {
43 bool enabled = id.Bit(VS_BIT_LIGHT0_ENABLE + i) && id.Bit(VS_BIT_LIGHTING_ENABLE);
44 if (enabled || (uvgMode == GE_TEXMAP_ENVIRONMENT_MAP && (ls0 == i || ls1 == i))) {
45 desc << i << ": ";
46 desc << "c:" << id.Bits(VS_BIT_LIGHT0_COMP + 4 * i, 2) << " t:" << id.Bits(VS_BIT_LIGHT0_TYPE + 4 * i, 2) << " ";
47 }
48 }
49 if (id.Bits(VS_BIT_MATERIAL_UPDATE, 3)) desc << "MatUp:" << id.Bits(VS_BIT_MATERIAL_UPDATE, 3) << " ";
50 if (id.Bits(VS_BIT_WEIGHT_FMTSCALE, 2)) desc << "WScale " << id.Bits(VS_BIT_WEIGHT_FMTSCALE, 2) << " ";
51 if (id.Bit(VS_BIT_FLATSHADE)) desc << "Flat ";
52
53 if (id.Bit(VS_BIT_BEZIER)) desc << "Bezier ";
54 if (id.Bit(VS_BIT_SPLINE)) desc << "Spline ";
55 if (id.Bit(VS_BIT_HAS_COLOR_TESS)) desc << "TessC ";
56 if (id.Bit(VS_BIT_HAS_TEXCOORD_TESS)) desc << "TessT ";
57 if (id.Bit(VS_BIT_HAS_NORMAL_TESS)) desc << "TessN ";
58 if (id.Bit(VS_BIT_NORM_REVERSE_TESS)) desc << "TessRevN ";
59 if (id.Bit(VS_BIT_VERTEX_RANGE_CULLING)) desc << "Cull ";
60
61 return desc.str();
62 }
63
ComputeVertexShaderID(VShaderID * id_out,u32 vertType,bool useHWTransform,bool useHWTessellation,bool weightsAsFloat)64 void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat) {
65 bool isModeThrough = (vertType & GE_VTYPE_THROUGH) != 0;
66 bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear();
67 bool doShadeMapping = doTexture && (gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP);
68 bool doFlatShading = gstate.getShadeMode() == GE_SHADE_FLAT && !gstate.isModeClear();
69
70 bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0;
71 bool hasNormal = (vertType & GE_VTYPE_NRM_MASK) != 0;
72 bool hasTexcoord = (vertType & GE_VTYPE_TC_MASK) != 0;
73
74 bool doBezier = gstate_c.submitType == SubmitType::HW_BEZIER;
75 bool doSpline = gstate_c.submitType == SubmitType::HW_SPLINE;
76
77 if (doBezier || doSpline) {
78 _assert_(hasNormal);
79 }
80
81 bool enableFog = gstate.isFogEnabled() && !isModeThrough && !gstate.isModeClear();
82 bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !isModeThrough;
83 bool vertexRangeCulling = gstate_c.Supports(GPU_SUPPORTS_VS_RANGE_CULLING) &&
84 !isModeThrough && gstate_c.submitType == SubmitType::DRAW; // neither hw nor sw spline/bezier. See #11692
85
86 VShaderID id;
87 id.SetBit(VS_BIT_LMODE, lmode);
88 id.SetBit(VS_BIT_IS_THROUGH, isModeThrough);
89 id.SetBit(VS_BIT_ENABLE_FOG, enableFog);
90 id.SetBit(VS_BIT_HAS_COLOR, hasColor);
91 id.SetBit(VS_BIT_VERTEX_RANGE_CULLING, vertexRangeCulling);
92
93 if (doTexture) {
94 id.SetBit(VS_BIT_DO_TEXTURE);
95 }
96
97 if (useHWTransform) {
98 id.SetBit(VS_BIT_USE_HW_TRANSFORM);
99 id.SetBit(VS_BIT_HAS_NORMAL, hasNormal);
100
101 // UV generation mode. doShadeMapping is implicitly stored here.
102 id.SetBits(VS_BIT_UVGEN_MODE, 2, gstate.getUVGenMode());
103
104 // The next bits are used differently depending on UVgen mode
105 if (gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX) {
106 id.SetBits(VS_BIT_UVPROJ_MODE, 2, gstate.getUVProjMode());
107 } else if (doShadeMapping) {
108 id.SetBits(VS_BIT_LS0, 2, gstate.getUVLS0());
109 id.SetBits(VS_BIT_LS1, 2, gstate.getUVLS1());
110 }
111
112 // Bones.
113 bool enableBones = vertTypeIsSkinningEnabled(vertType);
114 id.SetBit(VS_BIT_ENABLE_BONES, enableBones);
115 if (enableBones) {
116 id.SetBits(VS_BIT_BONES, 3, TranslateNumBones(vertTypeGetNumBoneWeights(vertType)) - 1);
117 // 2 bits. We should probably send in the weight scalefactor as a uniform instead,
118 // or simply preconvert all weights to floats.
119 id.SetBits(VS_BIT_WEIGHT_FMTSCALE, 2, weightsAsFloat ? 0 : (vertType & GE_VTYPE_WEIGHT_MASK) >> GE_VTYPE_WEIGHT_SHIFT);
120 }
121
122 if (gstate.isLightingEnabled()) {
123 // doShadeMapping is stored as UVGenMode, and light type doesn't matter for shade mapping.
124 id.SetBits(VS_BIT_MATERIAL_UPDATE, 3, gstate.getMaterialUpdate() & 7);
125 id.SetBit(VS_BIT_LIGHTING_ENABLE);
126 // Light bits
127 for (int i = 0; i < 4; i++) {
128 bool chanEnabled = gstate.isLightChanEnabled(i) != 0;
129 id.SetBit(VS_BIT_LIGHT0_ENABLE + i, chanEnabled);
130 if (chanEnabled) {
131 id.SetBits(VS_BIT_LIGHT0_COMP + 4 * i, 2, gstate.getLightComputation(i));
132 id.SetBits(VS_BIT_LIGHT0_TYPE + 4 * i, 2, gstate.getLightType(i));
133 }
134 }
135 }
136
137 id.SetBit(VS_BIT_NORM_REVERSE, gstate.areNormalsReversed());
138 id.SetBit(VS_BIT_HAS_TEXCOORD, hasTexcoord);
139
140 if (useHWTessellation) {
141 id.SetBit(VS_BIT_BEZIER, doBezier);
142 id.SetBit(VS_BIT_SPLINE, doSpline);
143 if (doBezier || doSpline) {
144 // These are the original vertType's values (normalized will always have colors, etc.)
145 id.SetBit(VS_BIT_HAS_COLOR_TESS, (gstate.vertType & GE_VTYPE_COL_MASK) != 0);
146 id.SetBit(VS_BIT_HAS_TEXCOORD_TESS, (gstate.vertType & GE_VTYPE_TC_MASK) != 0);
147 id.SetBit(VS_BIT_HAS_NORMAL_TESS, (gstate.vertType & GE_VTYPE_NRM_MASK) != 0 || gstate.isLightingEnabled());
148 }
149 id.SetBit(VS_BIT_NORM_REVERSE_TESS, gstate.isPatchNormalsReversed());
150 }
151 }
152
153 id.SetBit(VS_BIT_FLATSHADE, doFlatShading);
154
155 // These two bits cannot be combined, otherwise havoc occurs. We get reports that indicate this happened somehow... "ERROR: 0:14: 'u_proj' : undeclared identifier"
156 _dbg_assert_msg_(!id.Bit(VS_BIT_USE_HW_TRANSFORM) || !id.Bit(VS_BIT_IS_THROUGH), "Can't have both THROUGH and USE_HW_TRANSFORM together!");
157
158 *id_out = id;
159 }
160
161
162 static const char *alphaTestFuncs[] = { "NEVER", "ALWAYS", "==", "!=", "<", "<=", ">", ">=" };
163
MatrixNeedsProjection(const float m[12])164 static bool MatrixNeedsProjection(const float m[12]) {
165 return m[2] != 0.0f || m[5] != 0.0f || m[8] != 0.0f || m[11] != 1.0f;
166 }
167
FragmentShaderDesc(const FShaderID & id)168 std::string FragmentShaderDesc(const FShaderID &id) {
169 std::stringstream desc;
170 desc << StringFromFormat("%08x:%08x ", id.d[1], id.d[0]);
171 if (id.Bit(FS_BIT_CLEARMODE)) desc << "Clear ";
172 if (id.Bit(FS_BIT_DO_TEXTURE)) desc << "Tex ";
173 if (id.Bit(FS_BIT_DO_TEXTURE_PROJ)) desc << "TexProj ";
174 if (id.Bit(FS_BIT_TEXALPHA)) desc << "TexAlpha ";
175 if (id.Bit(FS_BIT_TEXTURE_AT_OFFSET)) desc << "TexOffs ";
176 if (id.Bit(FS_BIT_LMODE)) desc << "LM ";
177 if (id.Bit(FS_BIT_ENABLE_FOG)) desc << "Fog ";
178 if (id.Bit(FS_BIT_COLOR_DOUBLE)) desc << "2x ";
179 if (id.Bit(FS_BIT_FLATSHADE)) desc << "Flat ";
180 if (id.Bit(FS_BIT_BGRA_TEXTURE)) desc << "BGRA ";
181 if (id.Bit(FS_BIT_SHADER_DEPAL)) desc << "Depal ";
182 if (id.Bit(FS_BIT_COLOR_WRITEMASK)) desc << "WriteMask ";
183 if (id.Bit(FS_BIT_SHADER_TEX_CLAMP)) {
184 desc << "TClamp";
185 if (id.Bit(FS_BIT_CLAMP_S)) desc << "S";
186 if (id.Bit(FS_BIT_CLAMP_T)) desc << "T";
187 desc << " ";
188 }
189 if (id.Bits(FS_BIT_REPLACE_BLEND, 3)) {
190 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) << " ";
191 }
192
193 switch (id.Bits(FS_BIT_STENCIL_TO_ALPHA, 2)) {
194 case REPLACE_ALPHA_NO: break;
195 case REPLACE_ALPHA_YES: desc << "StenToAlpha "; break;
196 case REPLACE_ALPHA_DUALSOURCE: desc << "StenToAlphaDual "; break;
197 }
198 if (id.Bits(FS_BIT_STENCIL_TO_ALPHA, 2) != REPLACE_ALPHA_NO) {
199 switch (id.Bits(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, 4)) {
200 case STENCIL_VALUE_UNIFORM: desc << "StenUniform "; break;
201 case STENCIL_VALUE_ZERO: desc << "Sten0 "; break;
202 case STENCIL_VALUE_ONE: desc << "Sten1 "; break;
203 case STENCIL_VALUE_KEEP: desc << "StenKeep "; break;
204 case STENCIL_VALUE_INVERT: desc << "StenInv "; break;
205 case STENCIL_VALUE_INCR_4: desc << "StenIncr4 "; break;
206 case STENCIL_VALUE_INCR_8: desc << "StenIncr8 "; break;
207 case STENCIL_VALUE_DECR_4: desc << "StenDecr4 "; break;
208 case STENCIL_VALUE_DECR_8: desc << "StenDecr4 "; break;
209 default: desc << "StenUnknown "; break;
210 }
211 } else if (id.Bit(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE)) {
212 desc << "StenOff ";
213 }
214 if (id.Bit(FS_BIT_DO_TEXTURE)) {
215 switch (id.Bits(FS_BIT_TEXFUNC, 3)) {
216 case GE_TEXFUNC_ADD: desc << "TFuncAdd "; break;
217 case GE_TEXFUNC_BLEND: desc << "TFuncBlend "; break;
218 case GE_TEXFUNC_DECAL: desc << "TFuncDecal "; break;
219 case GE_TEXFUNC_MODULATE: desc << "TFuncMod "; break;
220 case GE_TEXFUNC_REPLACE: desc << "TFuncRepl "; break;
221 default: desc << "TFuncUnk "; break;
222 }
223 }
224
225 if (id.Bit(FS_BIT_ALPHA_AGAINST_ZERO)) desc << "AlphaTest0 " << alphaTestFuncs[id.Bits(FS_BIT_ALPHA_TEST_FUNC, 3)] << " ";
226 else if (id.Bit(FS_BIT_ALPHA_TEST)) desc << "AlphaTest " << alphaTestFuncs[id.Bits(FS_BIT_ALPHA_TEST_FUNC, 3)] << " ";
227 if (id.Bit(FS_BIT_COLOR_AGAINST_ZERO)) desc << "ColorTest0 " << alphaTestFuncs[id.Bits(FS_BIT_COLOR_TEST_FUNC, 2)] << " "; // first 4 match;
228 else if (id.Bit(FS_BIT_COLOR_TEST)) desc << "ColorTest " << alphaTestFuncs[id.Bits(FS_BIT_COLOR_TEST_FUNC, 2)] << " "; // first 4 match
229
230 return desc.str();
231 }
232
233 // Here we must take all the bits of the gstate that determine what the fragment shader will
234 // look like, and concatenate them together into an ID.
ComputeFragmentShaderID(FShaderID * id_out,const Draw::Bugs & bugs)235 void ComputeFragmentShaderID(FShaderID *id_out, const Draw::Bugs &bugs) {
236 FShaderID id;
237 if (gstate.isModeClear()) {
238 // We only need one clear shader, so let's ignore the rest of the bits.
239 id.SetBit(FS_BIT_CLEARMODE);
240 } else {
241 bool isModeThrough = gstate.isModeThrough();
242 bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !isModeThrough;
243 bool enableFog = gstate.isFogEnabled() && !isModeThrough;
244 bool enableAlphaTest = gstate.isAlphaTestEnabled() && !IsAlphaTestTriviallyTrue();
245 bool enableColorTest = gstate.isColorTestEnabled() && !IsColorTestTriviallyTrue();
246 bool enableColorDoubling = gstate.isColorDoublingEnabled() && gstate.isTextureMapEnabled() && gstate.getTextureFunction() == GE_TEXFUNC_MODULATE;
247 bool doTextureProjection = (gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX && MatrixNeedsProjection(gstate.tgenMatrix));
248 bool doTextureAlpha = gstate.isTextureAlphaUsed();
249 bool doFlatShading = gstate.getShadeMode() == GE_SHADE_FLAT;
250 bool useShaderDepal = gstate_c.useShaderDepal;
251 bool colorWriteMask = IsColorWriteMaskComplex(gstate_c.allowFramebufferRead);
252
253 // Note how we here recompute some of the work already done in state mapping.
254 // Not ideal! At least we share the code.
255 ReplaceBlendType replaceBlend = ReplaceBlendWithShader(gstate_c.allowFramebufferRead, gstate.FrameBufFormat());
256 ReplaceAlphaType stencilToAlpha = ReplaceAlphaWithStencil(replaceBlend);
257
258 // All texfuncs except replace are the same for RGB as for RGBA with full alpha.
259 // Note that checking this means that we must dirty the fragment shader ID whenever textureFullAlpha changes.
260 if (gstate_c.textureFullAlpha && gstate.getTextureFunction() != GE_TEXFUNC_REPLACE)
261 doTextureAlpha = false;
262
263 if (gstate.isTextureMapEnabled()) {
264 id.SetBit(FS_BIT_DO_TEXTURE);
265 id.SetBits(FS_BIT_TEXFUNC, 3, gstate.getTextureFunction());
266 id.SetBit(FS_BIT_TEXALPHA, doTextureAlpha & 1); // rgb or rgba
267 if (gstate_c.needShaderTexClamp) {
268 bool textureAtOffset = gstate_c.curTextureXOffset != 0 || gstate_c.curTextureYOffset != 0;
269 // 4 bits total.
270 id.SetBit(FS_BIT_SHADER_TEX_CLAMP);
271 id.SetBit(FS_BIT_CLAMP_S, gstate.isTexCoordClampedS());
272 id.SetBit(FS_BIT_CLAMP_T, gstate.isTexCoordClampedT());
273 id.SetBit(FS_BIT_TEXTURE_AT_OFFSET, textureAtOffset);
274 }
275 id.SetBit(FS_BIT_BGRA_TEXTURE, gstate_c.bgraTexture);
276 id.SetBit(FS_BIT_SHADER_DEPAL, useShaderDepal);
277 }
278
279 id.SetBit(FS_BIT_LMODE, lmode);
280 if (enableAlphaTest) {
281 // 5 bits total.
282 id.SetBit(FS_BIT_ALPHA_TEST);
283 id.SetBits(FS_BIT_ALPHA_TEST_FUNC, 3, gstate.getAlphaTestFunction());
284 id.SetBit(FS_BIT_ALPHA_AGAINST_ZERO, IsAlphaTestAgainstZero());
285 id.SetBit(FS_BIT_TEST_DISCARD_TO_ZERO, !NeedsTestDiscard());
286 }
287 if (enableColorTest) {
288 // 4 bits total.
289 id.SetBit(FS_BIT_COLOR_TEST);
290 id.SetBits(FS_BIT_COLOR_TEST_FUNC, 2, gstate.getColorTestFunction());
291 id.SetBit(FS_BIT_COLOR_AGAINST_ZERO, IsColorTestAgainstZero());
292 // This is alos set in enableAlphaTest - color test is uncommon, but we can skip discard the same way.
293 id.SetBit(FS_BIT_TEST_DISCARD_TO_ZERO, !NeedsTestDiscard());
294 }
295
296 id.SetBit(FS_BIT_ENABLE_FOG, enableFog);
297 id.SetBit(FS_BIT_DO_TEXTURE_PROJ, doTextureProjection);
298 id.SetBit(FS_BIT_COLOR_DOUBLE, enableColorDoubling);
299
300 // 2 bits
301 id.SetBits(FS_BIT_STENCIL_TO_ALPHA, 2, stencilToAlpha);
302
303 if (stencilToAlpha != REPLACE_ALPHA_NO) {
304 // 4 bits
305 id.SetBits(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, 4, ReplaceAlphaWithStencilType());
306 }
307
308 // 2 bits.
309 id.SetBits(FS_BIT_REPLACE_LOGIC_OP_TYPE, 2, ReplaceLogicOpType());
310
311 // If replaceBlend == REPLACE_BLEND_STANDARD (or REPLACE_BLEND_NO) nothing is done, so we kill these bits.
312 if (replaceBlend > REPLACE_BLEND_STANDARD) {
313 // 3 bits.
314 id.SetBits(FS_BIT_REPLACE_BLEND, 3, replaceBlend);
315 // 11 bits total.
316 id.SetBits(FS_BIT_BLENDEQ, 3, gstate.getBlendEq());
317 id.SetBits(FS_BIT_BLENDFUNC_A, 4, gstate.getBlendFuncA());
318 id.SetBits(FS_BIT_BLENDFUNC_B, 4, gstate.getBlendFuncB());
319 }
320 id.SetBit(FS_BIT_FLATSHADE, doFlatShading);
321
322 id.SetBit(FS_BIT_COLOR_WRITEMASK, colorWriteMask);
323
324 if (g_Config.bVendorBugChecksEnabled) {
325 if (bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL)) {
326 id.SetBit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL, !IsStencilTestOutputDisabled() && !gstate.isDepthWriteEnabled());
327 }
328 }
329 }
330
331 *id_out = id;
332 }
333