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