Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/GPU/Common/GPUStateUtils.h
5665 views
1
#pragma once
2
3
#include <cstdint>
4
#include "Common/CommonTypes.h"
5
6
#include "GPU/ge_constants.h"
7
#include "GPU/GPUState.h"
8
9
// TODO: Replace enums and structs with same from thin3d.h, for convenient mapping.
10
11
enum StencilValueType {
12
STENCIL_VALUE_UNIFORM,
13
STENCIL_VALUE_ZERO,
14
STENCIL_VALUE_ONE,
15
STENCIL_VALUE_KEEP,
16
STENCIL_VALUE_INVERT,
17
STENCIL_VALUE_INCR_4,
18
STENCIL_VALUE_INCR_8,
19
STENCIL_VALUE_DECR_4,
20
STENCIL_VALUE_DECR_8,
21
};
22
23
enum ReplaceAlphaType {
24
REPLACE_ALPHA_NO = 0,
25
REPLACE_ALPHA_YES = 1,
26
REPLACE_ALPHA_DUALSOURCE = 2,
27
};
28
29
enum ReplaceBlendType {
30
REPLACE_BLEND_NO, // Blend function handled directly with blend states.
31
32
REPLACE_BLEND_STANDARD,
33
34
// SRC part of blend function handled in-shader.
35
REPLACE_BLEND_PRE_SRC,
36
REPLACE_BLEND_PRE_SRC_2X_ALPHA,
37
REPLACE_BLEND_2X_ALPHA,
38
REPLACE_BLEND_2X_SRC,
39
40
// Full blend equation runs in shader.
41
// We might have to make a copy of the framebuffer target to read from.
42
REPLACE_BLEND_READ_FRAMEBUFFER,
43
44
// Color blend mode and color gets copied to alpha blend mode.
45
REPLACE_BLEND_BLUE_TO_ALPHA,
46
};
47
48
enum SimulateLogicOpType {
49
LOGICOPTYPE_NORMAL,
50
LOGICOPTYPE_ONE,
51
LOGICOPTYPE_INVERT,
52
};
53
54
bool IsAlphaTestTriviallyTrue();
55
bool IsColorTestAgainstZero();
56
bool IsColorTestTriviallyTrue();
57
bool IsAlphaTestAgainstZero();
58
bool NeedsTestDiscard();
59
bool IsDepthTestEffectivelyDisabled();
60
bool IsStencilTestOutputDisabled();
61
62
StencilValueType ReplaceAlphaWithStencilType();
63
ReplaceAlphaType ReplaceAlphaWithStencil(ReplaceBlendType replaceBlend);
64
ReplaceBlendType ReplaceBlendWithShader(GEBufferFormat bufferFormat);
65
66
// This is for the fallback path if real logic ops are not available.
67
SimulateLogicOpType SimulateLogicOpShaderTypeIfNeeded();
68
69
// Common representation, should be able to set this directly with any modern API.
70
struct ViewportAndScissor {
71
int scissorX;
72
int scissorY;
73
int scissorW;
74
int scissorH;
75
float viewportX;
76
float viewportY;
77
float viewportW;
78
float viewportH;
79
float depthRangeMin;
80
float depthRangeMax;
81
float widthScale;
82
float heightScale;
83
float depthScale;
84
float xOffset;
85
float yOffset;
86
float zOffset;
87
bool throughMode;
88
};
89
90
// config is only used for non-buffered rendering.
91
struct DisplayLayoutConfig;
92
void ConvertViewportAndScissor(const DisplayLayoutConfig &config, bool useBufferedRendering, float renderWidth, float renderHeight, int bufferWidth, int bufferHeight, ViewportAndScissor &out);
93
void UpdateCachedViewportState(const ViewportAndScissor &vpAndScissor);
94
95
// NOTE: See the .cpp file for detailed comment about how the use flags are interpreted.
96
class DepthScaleFactors {
97
public:
98
// This should only be used from GetDepthScaleFactors.
99
DepthScaleFactors(double offset, double scale) : offset_(offset), scale_(scale) {}
100
101
// Decodes a value from a depth buffer to a value of range 0..65536
102
float DecodeToU16(float z) const {
103
return (float)((z - offset_) * scale_);
104
}
105
106
// Encodes a value from the range 0..65536 to a normalized depth value (0-1), in the
107
// range that we write to the depth buffer.
108
float EncodeFromU16(float z_u16) const {
109
return (float)(((double)z_u16 / scale_) + offset_);
110
}
111
112
float Offset() const { return (float)offset_; }
113
114
float ScaleU16() const { return (float)scale_; }
115
float Scale() const { return (float)(scale_ / 65535.0); }
116
117
private:
118
// Doubles hardly cost anything these days, and precision matters here.
119
double offset_;
120
double scale_;
121
};
122
123
DepthScaleFactors GetDepthScaleFactors(u32 useFlags);
124
125
// These are common to all modern APIs and can be easily converted with a lookup table.
126
enum class BlendFactor : uint8_t {
127
ZERO,
128
ONE,
129
SRC_COLOR,
130
ONE_MINUS_SRC_COLOR,
131
DST_COLOR,
132
ONE_MINUS_DST_COLOR,
133
SRC_ALPHA,
134
ONE_MINUS_SRC_ALPHA,
135
DST_ALPHA,
136
ONE_MINUS_DST_ALPHA,
137
CONSTANT_COLOR,
138
ONE_MINUS_CONSTANT_COLOR,
139
CONSTANT_ALPHA,
140
ONE_MINUS_CONSTANT_ALPHA,
141
SRC1_COLOR,
142
ONE_MINUS_SRC1_COLOR,
143
SRC1_ALPHA,
144
ONE_MINUS_SRC1_ALPHA,
145
INVALID,
146
COUNT,
147
};
148
149
enum class BlendEq : uint8_t {
150
ADD,
151
SUBTRACT,
152
REVERSE_SUBTRACT,
153
MIN,
154
MAX,
155
COUNT
156
};
157
158
// Computed blend setup, including shader stuff.
159
struct GenericBlendState {
160
bool applyFramebufferRead;
161
bool dirtyShaderBlendFixValues;
162
163
// Shader generation state
164
ReplaceAlphaType replaceAlphaWithStencil;
165
ReplaceBlendType replaceBlend;
166
SimulateLogicOpType simulateLogicOpType;
167
168
// Resulting hardware blend state
169
bool blendEnabled;
170
171
BlendFactor srcColor;
172
BlendFactor dstColor;
173
BlendFactor srcAlpha;
174
BlendFactor dstAlpha;
175
176
BlendEq eqColor;
177
BlendEq eqAlpha;
178
179
bool useBlendColor;
180
u32 blendColor;
181
182
void setFactors(BlendFactor srcC, BlendFactor dstC, BlendFactor srcA, BlendFactor dstA) {
183
srcColor = srcC;
184
dstColor = dstC;
185
srcAlpha = srcA;
186
dstAlpha = dstA;
187
}
188
void setEquation(BlendEq eqC, BlendEq eqA) {
189
eqColor = eqC;
190
eqAlpha = eqA;
191
}
192
void setBlendColor(uint32_t color, uint8_t alpha) {
193
blendColor = color | ((uint32_t)alpha << 24);
194
useBlendColor = true;
195
}
196
void defaultBlendColor(uint8_t alpha) {
197
blendColor = 0xFFFFFF | ((uint32_t)alpha << 24);
198
useBlendColor = true;
199
}
200
201
void Log();
202
};
203
204
void ApplyStencilReplaceAndLogicOpIgnoreBlend(ReplaceAlphaType replaceAlphaWithStencil, GenericBlendState &blendState);
205
206
struct GenericMaskState {
207
bool applyFramebufferRead;
208
uint32_t uniformMask; // For each bit, opposite to the PSP.
209
210
// The hardware channel masks, 1 bit per color component. From bit 0, order is RGBA like in all APIs!
211
uint8_t channelMask;
212
213
void ConvertToShaderBlend() {
214
// If we have to do it in the shader, we simply pass through all channels but mask only in the shader instead.
215
// Some GPUs have minor penalties for masks that are not all-channels-on or all-channels-off.
216
channelMask = 0xF;
217
applyFramebufferRead = true;
218
}
219
220
void Log();
221
};
222
223
struct GenericStencilFuncState {
224
bool enabled;
225
GEComparison testFunc;
226
u8 testRef;
227
u8 testMask;
228
u8 writeMask;
229
GEStencilOp sFail;
230
GEStencilOp zFail;
231
GEStencilOp zPass;
232
};
233
void ConvertStencilFuncState(GenericStencilFuncState &stencilFuncState);
234
235
struct GenericLogicState {
236
// If set, logic op is applied in the shader INSTEAD of in hardware.
237
// In this case, simulateLogicOpType and all that should be off.
238
bool applyFramebufferRead;
239
240
// Hardware
241
bool logicOpEnabled;
242
243
// Hardware and shader generation
244
GELogicOp logicOp;
245
246
void ApplyToBlendState(GenericBlendState &blendState);
247
void ConvertToShaderBlend() {
248
if (logicOp != GE_LOGIC_COPY) {
249
logicOpEnabled = false;
250
applyFramebufferRead = true;
251
// Same logicOp is kept.
252
}
253
}
254
};
255
256
struct ComputedPipelineState {
257
GenericBlendState blendState;
258
GenericMaskState maskState;
259
GenericLogicState logicState;
260
261
void Convert(bool shaderBitOpsSupported, bool fbReadAllowed);
262
263
bool FramebufferRead() const {
264
// If blending is off, its applyFramebufferRead can be false even after state propagation.
265
// So it's not enough to check just that one.
266
return blendState.applyFramebufferRead || maskState.applyFramebufferRead || logicState.applyFramebufferRead;
267
}
268
};
269
270
// See issue #15898
271
inline bool SpongebobDepthInverseConditions(const GenericStencilFuncState &stencilState) {
272
// Check that the depth/stencil state matches the conditions exactly.
273
// Always with a depth test that's not writing to the depth buffer (only stencil.)
274
if (!gstate.isDepthTestEnabled() || gstate.isDepthWriteEnabled())
275
return false;
276
// Always GREATER_EQUAL, which we flip to LESS.
277
if (gstate.getDepthTestFunction() != GE_COMP_GEQUAL)
278
return false;
279
280
// The whole purpose here is a depth fail that we need to write to alpha.
281
if (stencilState.zFail != GE_STENCILOP_ZERO || stencilState.sFail != GE_STENCILOP_KEEP || stencilState.zPass != GE_STENCILOP_KEEP)
282
return false;
283
if (stencilState.testFunc != GE_COMP_ALWAYS || stencilState.writeMask != 0xFF)
284
return false;
285
286
// Lastly, verify no color is written. Natural way is a mask, in case another game uses it.
287
// Note that the PSP masks are reversed compared to typical APIs.
288
if (gstate.getColorMask() == 0xFFFFFF00)
289
return true;
290
291
// These games specifically use simple alpha blending with a constant zero alpha.
292
if (!gstate.isAlphaBlendEnabled() || gstate.getBlendFuncA() != GE_SRCBLEND_SRCALPHA || gstate.getBlendFuncB() != GE_DSTBLEND_INVSRCALPHA)
293
return false;
294
295
// Also make sure there's no texture, in case its alpha gets involved.
296
if (gstate.isTextureMapEnabled())
297
return false;
298
299
// Spongebob uses material alpha.
300
if (gstate.getMaterialAmbientA() == 0x00 && gstate.getMaterialUpdate() == 0)
301
return true;
302
// MX vs ATV : Reflex uses vertex colors, should really check them...
303
if (gstate.getMaterialUpdate() == 1)
304
return true;
305
306
// Okay, color is most likely being used if we didn't hit the above.
307
return false;
308
}
309
310