ppsspp/GPU/Common/ShaderId.h
Henrik Rydgård 9d1355e137 Always do the vertex shader part of the fog computation.
In #16104, we drastically reduced the number of shader variants for
games that use flexible lighting setups. I looked at a few games and it
seems that a lot of games have the same shaders with fog on/off, while
fog is super cheap to compute. So let's just always do it, reducing
vertex shader variants further (though the amount of pipelines will probably
remain the same, since we still specialize the fragment shader).

Might also be worth adding a dynamic bool for the fragment shader, but
if so, doing it separately.
2022-09-26 09:30:54 +02:00

239 lines
6.3 KiB
C++

#pragma once
#include <string>
#include <cstring>
#include <cstdint>
#include "Common/CommonFuncs.h"
// TODO: There will be additional bits, indicating that groups of these will be
// sent to the shader and processed there. This will cut down the number of shaders ("ubershader approach")
// This is probably only really worth doing for lighting and bones.
enum VShaderBit : uint8_t {
VS_BIT_LMODE = 0,
VS_BIT_IS_THROUGH = 1,
VS_BIT_HAS_COLOR = 3,
VS_BIT_DO_TEXTURE = 4,
VS_BIT_VERTEX_RANGE_CULLING = 5,
// 6 is free,
// 7 is free.
VS_BIT_USE_HW_TRANSFORM = 8,
VS_BIT_HAS_NORMAL = 9, // conditioned on hw transform
VS_BIT_NORM_REVERSE = 10,
VS_BIT_HAS_TEXCOORD = 11,
VS_BIT_HAS_COLOR_TESS = 12, // 1 bit
VS_BIT_HAS_TEXCOORD_TESS = 13, // 1 bit
VS_BIT_NORM_REVERSE_TESS = 14, // 1 bit
VS_BIT_HAS_NORMAL_TESS = 15, // 1 bit
VS_BIT_UVGEN_MODE = 16,
VS_BIT_UVPROJ_MODE = 18, // 2, can overlap with LS0
VS_BIT_LS0 = 18, // 2
VS_BIT_LS1 = 20, // 2
VS_BIT_BONES = 22, // 3 should be enough, not 8
// 25 - 29 are free.
VS_BIT_ENABLE_BONES = 30,
// If this is set along with LIGHTING_ENABLE, all other lighting bits below
// are passed to the shader directly instead.
VS_BIT_LIGHT_UBERSHADER = 31,
VS_BIT_LIGHT0_COMP = 32, // 2 bits
VS_BIT_LIGHT0_TYPE = 34, // 2 bits
VS_BIT_LIGHT1_COMP = 36, // 2 bits
VS_BIT_LIGHT1_TYPE = 38, // 2 bits
VS_BIT_LIGHT2_COMP = 40, // 2 bits
VS_BIT_LIGHT2_TYPE = 42, // 2 bits
VS_BIT_LIGHT3_COMP = 44, // 2 bits
VS_BIT_LIGHT3_TYPE = 46, // 2 bits
VS_BIT_MATERIAL_UPDATE = 48, // 3 bits
VS_BIT_SPLINE = 51, // 1 bit
VS_BIT_LIGHT0_ENABLE = 52,
VS_BIT_LIGHT1_ENABLE = 53,
VS_BIT_LIGHT2_ENABLE = 54,
VS_BIT_LIGHT3_ENABLE = 55,
VS_BIT_LIGHTING_ENABLE = 56,
VS_BIT_WEIGHT_FMTSCALE = 57, // only two bits
// 59 - 61 are free.
VS_BIT_FLATSHADE = 62, // 1 bit
VS_BIT_BEZIER = 63, // 1 bit
// No more free
};
static inline VShaderBit operator +(VShaderBit bit, int i) {
return VShaderBit((int)bit + i);
}
// Local
enum FShaderBit : uint8_t {
FS_BIT_CLEARMODE = 0,
FS_BIT_DO_TEXTURE = 1,
FS_BIT_TEXFUNC = 2, // 3 bits
FS_BIT_TEXALPHA = 5,
FS_BIT_3D_TEXTURE = 6,
FS_BIT_SHADER_TEX_CLAMP = 7,
FS_BIT_CLAMP_S = 8,
FS_BIT_CLAMP_T = 9,
FS_BIT_TEXTURE_AT_OFFSET = 10,
FS_BIT_LMODE = 11,
FS_BIT_ALPHA_TEST = 12,
FS_BIT_ALPHA_TEST_FUNC = 13, // 3 bits
FS_BIT_ALPHA_AGAINST_ZERO = 16,
FS_BIT_COLOR_TEST = 17,
FS_BIT_COLOR_TEST_FUNC = 18, // 2 bits
FS_BIT_COLOR_AGAINST_ZERO = 20,
FS_BIT_ENABLE_FOG = 21,
FS_BIT_DO_TEXTURE_PROJ = 22,
FS_BIT_COLOR_DOUBLE = 23,
FS_BIT_STENCIL_TO_ALPHA = 24, // 2 bits
FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE = 26, // 4 bits (ReplaceAlphaType)
FS_BIT_SIMULATE_LOGIC_OP_TYPE = 30, // 2 bits
FS_BIT_REPLACE_BLEND = 32, // 3 bits (ReplaceBlendType)
FS_BIT_BLENDEQ = 35, // 3 bits
FS_BIT_BLENDFUNC_A = 38, // 4 bits
FS_BIT_BLENDFUNC_B = 42, // 4 bits
FS_BIT_FLATSHADE = 46,
FS_BIT_BGRA_TEXTURE = 47,
FS_BIT_TEST_DISCARD_TO_ZERO = 48,
FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL = 49,
FS_BIT_COLOR_WRITEMASK = 50,
FS_BIT_REPLACE_LOGIC_OP = 51, // 4 bits. GE_LOGIC_COPY means no-op/off.
FS_BIT_SHADER_DEPAL_MODE = 55, // 2 bits (ShaderDepalMode)
};
static inline FShaderBit operator +(FShaderBit bit, int i) {
return FShaderBit((int)bit + i);
}
struct ShaderID {
ShaderID() {
clear();
}
void clear() {
for (size_t i = 0; i < ARRAY_SIZE(d); i++) {
d[i] = 0;
}
}
void set_invalid() {
for (size_t i = 0; i < ARRAY_SIZE(d); i++) {
d[i] = 0xFFFFFFFF;
}
}
uint32_t d[2];
bool operator < (const ShaderID &other) const {
for (size_t i = 0; i < sizeof(d) / sizeof(uint32_t); i++) {
if (d[i] < other.d[i])
return true;
if (d[i] > other.d[i])
return false;
}
return false;
}
bool operator == (const ShaderID &other) const {
for (size_t i = 0; i < sizeof(d) / sizeof(uint32_t); i++) {
if (d[i] != other.d[i])
return false;
}
return true;
}
bool operator != (const ShaderID &other) const {
return !(*this == other);
}
uint32_t Word(int word) const {
return d[word];
}
void ToString(std::string *dest) const {
dest->resize(sizeof(d));
memcpy(&(*dest)[0], d, sizeof(d));
}
void FromString(std::string src) {
memcpy(d, &(src)[0], sizeof(d));
}
protected:
bool Bit(int bit) const {
return (d[bit >> 5] >> (bit & 31)) & 1;
}
// Does not handle crossing 32-bit boundaries. count must be 30 or smaller.
int Bits(int bit, int count) const {
const int mask = (1 << count) - 1;
return (d[bit >> 5] >> (bit & 31)) & mask;
}
void SetBit(int bit, bool value = true) {
if (value) {
d[bit >> 5] |= 1 << (bit & 31);
} else {
d[bit >> 5] &= ~(1 << (bit & 31));
}
}
void SetBits(int bit, int count, int value) {
const int mask = (1 << count) - 1;
const int shifted_mask = mask << (bit & 31);
d[bit >> 5] = (d[bit >> 5] & ~shifted_mask) | ((value & mask) << (bit & 31));
}
};
struct VShaderID : ShaderID {
VShaderID() : ShaderID() {
}
explicit VShaderID(ShaderID &src) {
memcpy(d, src.d, sizeof(d));
}
bool Bit(VShaderBit bit) const {
return ShaderID::Bit((int)bit);
}
int Bits(VShaderBit bit, int count) const {
return ShaderID::Bits((int)bit, count);
}
void SetBit(VShaderBit bit, bool value = true) {
ShaderID::SetBit((int)bit, value);
}
void SetBits(VShaderBit bit, int count, int value) {
ShaderID::SetBits((int)bit, count, value);
}
};
struct FShaderID : ShaderID {
FShaderID() : ShaderID() {
}
explicit FShaderID(ShaderID &src) {
memcpy(d, src.d, sizeof(d));
}
bool Bit(FShaderBit bit) const {
return ShaderID::Bit((int)bit);
}
int Bits(FShaderBit bit, int count) const {
return ShaderID::Bits((int)bit, count);
}
void SetBit(FShaderBit bit, bool value = true) {
ShaderID::SetBit((int)bit, value);
}
void SetBits(FShaderBit bit, int count, int value) {
ShaderID::SetBits((int)bit, count, value);
}
};
namespace Draw {
class Bugs;
}
void ComputeVertexShaderID(VShaderID *id, uint32_t vertexType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat);
// Generates a compact string that describes the shader. Useful in a list to get an overview
// of the current flora of shaders.
std::string VertexShaderDesc(const VShaderID &id);
struct ComputedPipelineState;
void ComputeFragmentShaderID(FShaderID *id, const ComputedPipelineState &pipelineState, const Draw::Bugs &bugs);
std::string FragmentShaderDesc(const FShaderID &id);