Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/GPU/Common/ShaderId.cpp
3186 views
1
#include <string>
2
#include <sstream>
3
#include <array>
4
5
#include "Common/GPU/thin3d.h"
6
#include "Common/StringUtils.h"
7
#include "Core/Config.h"
8
9
#include "GPU/ge_constants.h"
10
#include "GPU/GPU.h"
11
#include "GPU/GPUState.h"
12
#include "GPU/Common/GPUStateUtils.h"
13
#include "GPU/Common/ShaderId.h"
14
#include "GPU/Common/VertexDecoderCommon.h"
15
16
std::string VertexShaderDesc(const VShaderID &id) {
17
std::stringstream desc;
18
desc << StringFromFormat("%08x:%08x ", id.d[1], id.d[0]);
19
if (id.Bit(VS_BIT_IS_THROUGH)) desc << "THR ";
20
if (id.Bit(VS_BIT_USE_HW_TRANSFORM)) desc << "HWX ";
21
if (id.Bit(VS_BIT_HAS_COLOR)) desc << "C ";
22
if (id.Bit(VS_BIT_HAS_TEXCOORD)) desc << "T ";
23
if (id.Bit(VS_BIT_HAS_NORMAL)) desc << "N ";
24
if (id.Bit(VS_BIT_LMODE)) desc << "LM ";
25
if (id.Bit(VS_BIT_NORM_REVERSE)) desc << "RevN ";
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
static constexpr std::array<const char*, 4> uvgModes = { "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
if (id.Bit(VS_BIT_LIGHT_UBERSHADER)) {
43
desc << "LightUberShader ";
44
}
45
for (int i = 0; i < 4; i++) {
46
bool enabled = id.Bit(VS_BIT_LIGHT0_ENABLE + i) && id.Bit(VS_BIT_LIGHTING_ENABLE);
47
if (enabled || (uvgMode == GE_TEXMAP_ENVIRONMENT_MAP && (ls0 == i || ls1 == i))) {
48
desc << i << ": ";
49
desc << "c:" << id.Bits(VS_BIT_LIGHT0_COMP + 4 * i, 2) << " t:" << id.Bits(VS_BIT_LIGHT0_TYPE + 4 * i, 2) << " ";
50
}
51
}
52
if (id.Bits(VS_BIT_MATERIAL_UPDATE, 3)) desc << "MatUp:" << id.Bits(VS_BIT_MATERIAL_UPDATE, 3) << " ";
53
if (id.Bits(VS_BIT_WEIGHT_FMTSCALE, 2)) desc << "WScale " << id.Bits(VS_BIT_WEIGHT_FMTSCALE, 2) << " ";
54
if (id.Bit(VS_BIT_FLATSHADE)) desc << "Flat ";
55
56
if (id.Bit(VS_BIT_BEZIER)) desc << "Bezier ";
57
if (id.Bit(VS_BIT_SPLINE)) desc << "Spline ";
58
if (id.Bit(VS_BIT_HAS_COLOR_TESS)) desc << "TessC ";
59
if (id.Bit(VS_BIT_HAS_TEXCOORD_TESS)) desc << "TessT ";
60
if (id.Bit(VS_BIT_HAS_NORMAL_TESS)) desc << "TessN ";
61
if (id.Bit(VS_BIT_NORM_REVERSE_TESS)) desc << "TessRevN ";
62
if (id.Bit(VS_BIT_VERTEX_RANGE_CULLING)) desc << "Cull ";
63
64
if (id.Bit(VS_BIT_SIMPLE_STEREO)) desc << "SimpleStereo ";
65
66
return desc.str();
67
}
68
69
void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode) {
70
bool isModeThrough = (vertType & GE_VTYPE_THROUGH) != 0;
71
bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear();
72
bool doShadeMapping = doTexture && (gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP);
73
bool doFlatShading = gstate.getShadeMode() == GE_SHADE_FLAT && !gstate.isModeClear();
74
75
bool vtypeHasColor = (vertType & GE_VTYPE_COL_MASK) != 0;
76
bool vtypeHasNormal = (vertType & GE_VTYPE_NRM_MASK) != 0;
77
bool vtypeHasTexcoord = (vertType & GE_VTYPE_TC_MASK) != 0;
78
79
bool doBezier = gstate_c.submitType == SubmitType::HW_BEZIER;
80
bool doSpline = gstate_c.submitType == SubmitType::HW_SPLINE;
81
82
if (doBezier || doSpline) {
83
_assert_(vtypeHasNormal);
84
}
85
86
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !isModeThrough && !gstate.isModeClear();
87
bool vertexRangeCulling = gstate_c.Use(GPU_USE_VS_RANGE_CULLING) &&
88
!isModeThrough && gstate_c.submitType == SubmitType::DRAW; // neither hw nor sw spline/bezier. See #11692
89
90
VShaderID id;
91
id.SetBit(VS_BIT_LMODE, lmode);
92
id.SetBit(VS_BIT_IS_THROUGH, isModeThrough);
93
id.SetBit(VS_BIT_HAS_COLOR, vtypeHasColor);
94
id.SetBit(VS_BIT_VERTEX_RANGE_CULLING, vertexRangeCulling);
95
96
if (!isModeThrough && gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) {
97
id.SetBit(VS_BIT_SIMPLE_STEREO);
98
}
99
100
if (doTexture) {
101
// UV generation mode. doShadeMapping is implicitly stored here.
102
id.SetBits(VS_BIT_UVGEN_MODE, 2, gstate.getUVGenMode());
103
}
104
105
if (useHWTransform) {
106
id.SetBit(VS_BIT_USE_HW_TRANSFORM);
107
id.SetBit(VS_BIT_HAS_NORMAL, vtypeHasNormal);
108
109
// The next bits are used differently depending on UVgen mode
110
if (gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX) {
111
id.SetBits(VS_BIT_UVPROJ_MODE, 2, gstate.getUVProjMode());
112
} else if (doShadeMapping) {
113
id.SetBits(VS_BIT_LS0, 2, gstate.getUVLS0());
114
id.SetBits(VS_BIT_LS1, 2, gstate.getUVLS1());
115
}
116
117
// Bones.
118
bool enableBones = !useSkinInDecode && vertTypeIsSkinningEnabled(vertType);
119
id.SetBit(VS_BIT_ENABLE_BONES, enableBones);
120
if (enableBones) {
121
id.SetBits(VS_BIT_BONES, 3, TranslateNumBones(vertTypeGetNumBoneWeights(vertType)) - 1);
122
// 2 bits. We should probably send in the weight scalefactor as a uniform instead,
123
// or simply preconvert all weights to floats.
124
id.SetBits(VS_BIT_WEIGHT_FMTSCALE, 2, weightsAsFloat ? 0 : (vertType & GE_VTYPE_WEIGHT_MASK) >> GE_VTYPE_WEIGHT_SHIFT);
125
}
126
127
if (gstate.isLightingEnabled()) {
128
// doShadeMapping is stored as UVGenMode, and light type doesn't matter for shade mapping.
129
id.SetBit(VS_BIT_LIGHTING_ENABLE);
130
if (gstate_c.Use(GPU_USE_LIGHT_UBERSHADER)) {
131
id.SetBit(VS_BIT_LIGHT_UBERSHADER);
132
} else {
133
id.SetBits(VS_BIT_MATERIAL_UPDATE, 3, gstate.getMaterialUpdate());
134
// Light bits
135
for (int i = 0; i < 4; i++) {
136
bool chanEnabled = gstate.isLightChanEnabled(i) != 0;
137
id.SetBit(VS_BIT_LIGHT0_ENABLE + i, chanEnabled);
138
if (chanEnabled) {
139
id.SetBits(VS_BIT_LIGHT0_COMP + 4 * i, 2, gstate.getLightComputation(i));
140
id.SetBits(VS_BIT_LIGHT0_TYPE + 4 * i, 2, gstate.getLightType(i));
141
}
142
}
143
}
144
}
145
146
id.SetBit(VS_BIT_NORM_REVERSE, gstate.areNormalsReversed());
147
id.SetBit(VS_BIT_HAS_TEXCOORD, vtypeHasTexcoord);
148
149
if (useHWTessellation) {
150
id.SetBit(VS_BIT_BEZIER, doBezier);
151
id.SetBit(VS_BIT_SPLINE, doSpline);
152
if (doBezier || doSpline) {
153
// These are the original vertType's values (normalized will always have colors, etc.)
154
id.SetBit(VS_BIT_HAS_COLOR_TESS, (gstate.vertType & GE_VTYPE_COL_MASK) != 0);
155
id.SetBit(VS_BIT_HAS_TEXCOORD_TESS, (gstate.vertType & GE_VTYPE_TC_MASK) != 0);
156
id.SetBit(VS_BIT_HAS_NORMAL_TESS, (gstate.vertType & GE_VTYPE_NRM_MASK) != 0 || gstate.isLightingEnabled());
157
}
158
id.SetBit(VS_BIT_NORM_REVERSE_TESS, gstate.isPatchNormalsReversed());
159
}
160
}
161
162
id.SetBit(VS_BIT_FLATSHADE, doFlatShading);
163
164
// These two bits cannot be combined, otherwise havoc occurs. We get reports that indicate this happened somehow... "ERROR: 0:14: 'u_proj' : undeclared identifier"
165
_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!");
166
167
*id_out = id;
168
}
169
170
171
static const char * const alphaTestFuncs[] = { "NEVER", "ALWAYS", "==", "!=", "<", "<=", ">", ">=" };
172
static const char * const logicFuncs[] = {
173
"CLEAR", "AND", "AND_REV", "COPY", "AND_INV", "NOOP", "XOR", "OR",
174
"NOR", "EQUIV", "INVERTED", "OR_REV", "COPY_INV", "OR_INV", "NAND", "SET",
175
};
176
177
static bool MatrixNeedsProjection(const float m[12], GETexProjMapMode mode) {
178
// For GE_PROJMAP_UV, we can ignore m[8] since it multiplies to zero.
179
return m[2] != 0.0f || m[5] != 0.0f || (m[8] != 0.0f && mode != GE_PROJMAP_UV) || m[11] != 1.0f;
180
}
181
182
std::string FragmentShaderDesc(const FShaderID &id) {
183
std::stringstream desc;
184
desc << StringFromFormat("%08x:%08x ", id.d[1], id.d[0]);
185
if (id.Bit(FS_BIT_CLEARMODE)) desc << "Clear ";
186
if (id.Bit(FS_BIT_DO_TEXTURE)) desc << (id.Bit(FS_BIT_3D_TEXTURE) ? "Tex3D " : "Tex ");
187
if (id.Bit(FS_BIT_DO_TEXTURE_PROJ)) desc << "TexProj ";
188
if (id.Bit(FS_BIT_ENABLE_FOG)) desc << "Fog ";
189
if (id.Bit(FS_BIT_LMODE)) desc << "LM ";
190
if (id.Bit(FS_BIT_TEXALPHA)) desc << "TexAlpha ";
191
if (id.Bit(FS_BIT_DOUBLE_COLOR)) desc << "Double ";
192
if (id.Bit(FS_BIT_FLATSHADE)) desc << "Flat ";
193
if (id.Bit(FS_BIT_BGRA_TEXTURE)) desc << "BGRA ";
194
if (id.Bit(FS_BIT_UBERSHADER)) desc << "FragUber ";
195
if (id.Bit(FS_BIT_DEPTH_TEST_NEVER)) desc << "DepthNever ";
196
switch ((ShaderDepalMode)id.Bits(FS_BIT_SHADER_DEPAL_MODE, 2)) {
197
case ShaderDepalMode::OFF: break;
198
case ShaderDepalMode::NORMAL: desc << "Depal "; break;
199
case ShaderDepalMode::SMOOTHED: desc << "SmoothDepal "; break;
200
case ShaderDepalMode::CLUT8_8888: desc << "CLUT8From8888Depal"; break;
201
}
202
if (id.Bit(FS_BIT_COLOR_WRITEMASK)) desc << "WriteMask ";
203
if (id.Bit(FS_BIT_SHADER_TEX_CLAMP)) {
204
desc << "TClamp";
205
if (id.Bit(FS_BIT_CLAMP_S)) desc << "S";
206
if (id.Bit(FS_BIT_CLAMP_T)) desc << "T";
207
desc << " ";
208
}
209
int blendBits = id.Bits(FS_BIT_REPLACE_BLEND, 3);
210
if (blendBits) {
211
switch (blendBits) {
212
case ReplaceBlendType::REPLACE_BLEND_BLUE_TO_ALPHA:
213
desc << "BlueToAlpha_" << "A:" << id.Bits(FS_BIT_BLENDFUNC_A, 4);
214
break;
215
default:
216
desc << "ReplaceBlend_" << id.Bits(FS_BIT_REPLACE_BLEND, 3)
217
<< "A:" << id.Bits(FS_BIT_BLENDFUNC_A, 4)
218
<< "_B:" << id.Bits(FS_BIT_BLENDFUNC_B, 4)
219
<< "_Eq:" << id.Bits(FS_BIT_BLENDEQ, 3) << " ";
220
break;
221
}
222
}
223
224
switch (id.Bits(FS_BIT_STENCIL_TO_ALPHA, 2)) {
225
case REPLACE_ALPHA_NO: break;
226
case REPLACE_ALPHA_YES: desc << "StenToAlpha "; break;
227
case REPLACE_ALPHA_DUALSOURCE: desc << "StenToAlphaDual "; break;
228
}
229
if (id.Bits(FS_BIT_STENCIL_TO_ALPHA, 2) != REPLACE_ALPHA_NO) {
230
switch (id.Bits(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, 4)) {
231
case STENCIL_VALUE_UNIFORM: desc << "StenUniform "; break;
232
case STENCIL_VALUE_ZERO: desc << "Sten0 "; break;
233
case STENCIL_VALUE_ONE: desc << "Sten1 "; break;
234
case STENCIL_VALUE_KEEP: desc << "StenKeep "; break;
235
case STENCIL_VALUE_INVERT: desc << "StenInv "; break;
236
case STENCIL_VALUE_INCR_4: desc << "StenIncr4 "; break;
237
case STENCIL_VALUE_INCR_8: desc << "StenIncr8 "; break;
238
case STENCIL_VALUE_DECR_4: desc << "StenDecr4 "; break;
239
case STENCIL_VALUE_DECR_8: desc << "StenDecr8 "; break;
240
default: desc << "StenUnknown "; break;
241
}
242
} else if (id.Bit(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE)) {
243
desc << "StenOff ";
244
}
245
if (id.Bit(FS_BIT_DO_TEXTURE)) {
246
switch (id.Bits(FS_BIT_TEXFUNC, 3)) {
247
case GE_TEXFUNC_ADD: desc << "TFuncAdd "; break;
248
case GE_TEXFUNC_BLEND: desc << "TFuncBlend "; break;
249
case GE_TEXFUNC_DECAL: desc << "TFuncDecal "; break;
250
case GE_TEXFUNC_MODULATE: desc << "TFuncMod "; break;
251
case GE_TEXFUNC_REPLACE: desc << "TFuncRepl "; break;
252
default: desc << "TFuncUnk "; break;
253
}
254
}
255
256
if (id.Bit(FS_BIT_ALPHA_AGAINST_ZERO)) desc << "AlphaTest0 " << alphaTestFuncs[id.Bits(FS_BIT_ALPHA_TEST_FUNC, 3)] << " ";
257
else if (id.Bit(FS_BIT_ALPHA_TEST)) desc << "AlphaTest " << alphaTestFuncs[id.Bits(FS_BIT_ALPHA_TEST_FUNC, 3)] << " ";
258
if (id.Bit(FS_BIT_COLOR_AGAINST_ZERO)) desc << "ColorTest0 " << alphaTestFuncs[id.Bits(FS_BIT_COLOR_TEST_FUNC, 2)] << " "; // first 4 match;
259
else if (id.Bit(FS_BIT_COLOR_TEST)) desc << "ColorTest " << alphaTestFuncs[id.Bits(FS_BIT_COLOR_TEST_FUNC, 2)] << " "; // first 4 match
260
if (id.Bit(FS_BIT_TEST_DISCARD_TO_ZERO)) desc << "TestDiscardToZero ";
261
if (id.Bit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL)) desc << "StencilDiscardWorkaround ";
262
int logicMode = id.Bits(FS_BIT_REPLACE_LOGIC_OP, 4);
263
if ((logicMode != GE_LOGIC_COPY) && !id.Bit(FS_BIT_CLEARMODE)) desc << "RLogic(" << logicFuncs[logicMode] << ")";
264
if (id.Bit(FS_BIT_SAMPLE_ARRAY_TEXTURE)) desc << "TexArray ";
265
if (id.Bit(FS_BIT_STEREO)) desc << "Stereo ";
266
if (id.Bit(FS_BIT_USE_FRAMEBUFFER_FETCH)) desc << "(fetch)";
267
return desc.str();
268
}
269
270
bool FragmentIdNeedsFramebufferRead(const FShaderID &id) {
271
return id.Bit(FS_BIT_COLOR_WRITEMASK) ||
272
id.Bits(FS_BIT_REPLACE_LOGIC_OP, 4) != GE_LOGIC_COPY ||
273
(ReplaceBlendType)id.Bits(FS_BIT_REPLACE_BLEND, 3) == REPLACE_BLEND_READ_FRAMEBUFFER;
274
}
275
276
inline u32 SanitizeBlendMode(GEBlendMode mode) {
277
if (mode > GE_BLENDMODE_ABSDIFF)
278
return GE_BLENDMODE_MUL_AND_ADD; // Not sure what the undefined modes are.
279
else
280
return mode;
281
}
282
283
// Here we must take all the bits of the gstate that determine what the fragment shader will
284
// look like, and concatenate them together into an ID.
285
void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pipelineState, const Draw::Bugs &bugs) {
286
FShaderID id;
287
if (gstate.isModeClear()) {
288
// We only need one clear shader, so let's ignore the rest of the bits.
289
id.SetBit(FS_BIT_CLEARMODE);
290
} else {
291
bool isModeThrough = gstate.isModeThrough();
292
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !isModeThrough;
293
bool enableFog = gstate.isFogEnabled() && !isModeThrough;
294
bool enableAlphaTest = gstate.isAlphaTestEnabled() && !IsAlphaTestTriviallyTrue();
295
bool enableColorTest = gstate.isColorTestEnabled() && !IsColorTestTriviallyTrue();
296
bool enableColorDouble = gstate.isColorDoublingEnabled();
297
bool doTextureProjection = (gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX && MatrixNeedsProjection(gstate.tgenMatrix, gstate.getUVProjMode()));
298
bool doFlatShading = gstate.getShadeMode() == GE_SHADE_FLAT;
299
300
bool enableTexAlpha = gstate.isTextureAlphaUsed();
301
302
bool uberShader = gstate_c.Use(GPU_USE_FRAGMENT_UBERSHADER);
303
304
ShaderDepalMode shaderDepalMode = gstate_c.shaderDepalMode;
305
306
bool colorWriteMask = pipelineState.maskState.applyFramebufferRead;
307
ReplaceBlendType replaceBlend = pipelineState.blendState.replaceBlend;
308
GELogicOp replaceLogicOpType = pipelineState.logicState.applyFramebufferRead ? pipelineState.logicState.logicOp : GE_LOGIC_COPY;
309
310
SimulateLogicOpType simulateLogicOpType = pipelineState.blendState.simulateLogicOpType;
311
ReplaceAlphaType stencilToAlpha = pipelineState.blendState.replaceAlphaWithStencil;
312
313
if (gstate.isTextureMapEnabled()) {
314
id.SetBit(FS_BIT_DO_TEXTURE);
315
id.SetBits(FS_BIT_TEXFUNC, 3, gstate.getTextureFunction());
316
if (gstate_c.needShaderTexClamp) {
317
// 4 bits total.
318
id.SetBit(FS_BIT_SHADER_TEX_CLAMP);
319
id.SetBit(FS_BIT_CLAMP_S, gstate.isTexCoordClampedS());
320
id.SetBit(FS_BIT_CLAMP_T, gstate.isTexCoordClampedT());
321
}
322
id.SetBit(FS_BIT_BGRA_TEXTURE, gstate_c.bgraTexture);
323
id.SetBits(FS_BIT_SHADER_DEPAL_MODE, 2, (int)shaderDepalMode);
324
id.SetBit(FS_BIT_3D_TEXTURE, gstate_c.curTextureIs3D);
325
}
326
327
id.SetBit(FS_BIT_LMODE, lmode);
328
329
if (enableAlphaTest) {
330
// 5 bits total.
331
id.SetBit(FS_BIT_ALPHA_TEST);
332
id.SetBits(FS_BIT_ALPHA_TEST_FUNC, 3, gstate.getAlphaTestFunction());
333
id.SetBit(FS_BIT_ALPHA_AGAINST_ZERO, IsAlphaTestAgainstZero());
334
id.SetBit(FS_BIT_TEST_DISCARD_TO_ZERO, !NeedsTestDiscard());
335
}
336
if (enableColorTest) {
337
// 4 bits total.
338
id.SetBit(FS_BIT_COLOR_TEST);
339
id.SetBits(FS_BIT_COLOR_TEST_FUNC, 2, gstate.getColorTestFunction());
340
id.SetBit(FS_BIT_COLOR_AGAINST_ZERO, IsColorTestAgainstZero());
341
// This is alos set in enableAlphaTest - color test is uncommon, but we can skip discard the same way.
342
id.SetBit(FS_BIT_TEST_DISCARD_TO_ZERO, !NeedsTestDiscard());
343
}
344
345
id.SetBit(FS_BIT_ENABLE_FOG, enableFog); // TODO: Will be moved back to the ubershader.
346
347
id.SetBit(FS_BIT_UBERSHADER, uberShader);
348
if (!uberShader) {
349
id.SetBit(FS_BIT_TEXALPHA, enableTexAlpha);
350
id.SetBit(FS_BIT_DOUBLE_COLOR, enableColorDouble);
351
}
352
353
id.SetBit(FS_BIT_DO_TEXTURE_PROJ, doTextureProjection);
354
355
// 2 bits
356
id.SetBits(FS_BIT_STENCIL_TO_ALPHA, 2, stencilToAlpha);
357
358
if (stencilToAlpha != REPLACE_ALPHA_NO) {
359
// 4 bits
360
id.SetBits(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, 4, ReplaceAlphaWithStencilType());
361
}
362
363
// 2 bits.
364
id.SetBits(FS_BIT_SIMULATE_LOGIC_OP_TYPE, 2, simulateLogicOpType);
365
366
// 4 bits. Set to GE_LOGIC_COPY if not used, which does nothing in the shader generator.
367
id.SetBits(FS_BIT_REPLACE_LOGIC_OP, 4, (int)replaceLogicOpType);
368
369
// If replaceBlend == REPLACE_BLEND_STANDARD (or REPLACE_BLEND_NO) nothing is done, so we kill these bits.
370
if (replaceBlend == REPLACE_BLEND_BLUE_TO_ALPHA) {
371
id.SetBits(FS_BIT_REPLACE_BLEND, 3, replaceBlend);
372
id.SetBits(FS_BIT_BLENDFUNC_A, 4, gstate.getBlendFuncA());
373
} else if (replaceBlend > REPLACE_BLEND_STANDARD) {
374
// 3 bits.
375
id.SetBits(FS_BIT_REPLACE_BLEND, 3, replaceBlend);
376
// 11 bits total.
377
id.SetBits(FS_BIT_BLENDEQ, 3, SanitizeBlendMode(gstate.getBlendEq()));
378
id.SetBits(FS_BIT_BLENDFUNC_A, 4, gstate.getBlendFuncA());
379
id.SetBits(FS_BIT_BLENDFUNC_B, 4, gstate.getBlendFuncB());
380
}
381
id.SetBit(FS_BIT_FLATSHADE, doFlatShading);
382
id.SetBit(FS_BIT_COLOR_WRITEMASK, colorWriteMask);
383
384
// All framebuffers are array textures in Vulkan now.
385
if (gstate_c.textureIsArray && gstate_c.Use(GPU_USE_FRAMEBUFFER_ARRAYS)) {
386
id.SetBit(FS_BIT_SAMPLE_ARRAY_TEXTURE);
387
}
388
389
// Stereo support
390
if (gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) {
391
id.SetBit(FS_BIT_STEREO);
392
}
393
394
if (g_Config.bVendorBugChecksEnabled) {
395
if (bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL_ADRENO) || bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL_MALI)) {
396
// On Adreno, the workaround is safe, so we do simple checks.
397
bool stencilWithoutDepth = (!gstate.isDepthTestEnabled() || !gstate.isDepthWriteEnabled()) && !IsStencilTestOutputDisabled();
398
if (stencilWithoutDepth) {
399
id.SetBit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL, stencilWithoutDepth);
400
}
401
}
402
}
403
404
// Forcibly disable NEVER + depth-write on Mali.
405
// TODO: Take this from computed depth test instead of directly from the gstate.
406
// That will take more refactoring though.
407
if (bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL_MALI) &&
408
gstate.getDepthTestFunction() == GE_COMP_NEVER && gstate.isDepthTestEnabled()) {
409
id.SetBit(FS_BIT_DEPTH_TEST_NEVER);
410
}
411
412
// In case the USE flag changes (for example, in multisampling we might disable input attachments),
413
// we don't want to accidentally use the wrong cached shader here. So moved it to a bit.
414
if (FragmentIdNeedsFramebufferRead(id)) {
415
if (gstate_c.Use(GPU_USE_FRAMEBUFFER_FETCH)) {
416
id.SetBit(FS_BIT_USE_FRAMEBUFFER_FETCH);
417
}
418
}
419
}
420
421
*id_out = id;
422
}
423
424
std::string GeometryShaderDesc(const GShaderID &id) {
425
std::stringstream desc;
426
desc << StringFromFormat("%08x:%08x ", id.d[1], id.d[0]);
427
if (id.Bit(GS_BIT_ENABLED)) desc << "ENABLED ";
428
if (id.Bit(GS_BIT_DO_TEXTURE)) desc << "TEX ";
429
if (id.Bit(GS_BIT_LMODE)) desc << "LM ";
430
return desc.str();
431
}
432
433
void ComputeGeometryShaderID(GShaderID *id_out, const Draw::Bugs &bugs, int prim) {
434
GShaderID id;
435
// Early out.
436
if (!gstate_c.Use(GPU_USE_GS_CULLING)) {
437
*id_out = id;
438
return;
439
}
440
441
bool isModeThrough = gstate.isModeThrough();
442
bool isCurve = gstate_c.submitType != SubmitType::DRAW;
443
bool isTriangle = prim == GE_PRIM_TRIANGLES || prim == GE_PRIM_TRIANGLE_FAN || prim == GE_PRIM_TRIANGLE_STRIP;
444
445
bool vertexRangeCulling = !isCurve;
446
bool clipClampedDepth = gstate_c.Use(GPU_USE_DEPTH_CLAMP) && !gstate_c.Use(GPU_USE_CLIP_DISTANCE);
447
448
// Only use this for triangle primitives, and if we actually need it.
449
if ((!vertexRangeCulling && !clipClampedDepth) || isModeThrough || !isTriangle) {
450
*id_out = id;
451
return;
452
}
453
454
id.SetBit(GS_BIT_ENABLED, true);
455
// Vertex range culling doesn't seem tno happen for spline/bezier, see #11692.
456
id.SetBit(GS_BIT_CURVE, isCurve);
457
458
if (gstate.isModeClear()) {
459
// No attribute bits.
460
} else {
461
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !isModeThrough;
462
463
id.SetBit(GS_BIT_LMODE, lmode);
464
if (gstate.isTextureMapEnabled()) {
465
id.SetBit(GS_BIT_DO_TEXTURE);
466
}
467
}
468
469
*id_out = id;
470
}
471
472