ppsspp/GPU/Common/ShaderId.h
Henrik Rydgård 3d376b0ab7 Remove the rather redundant DoTexture flag from vshaders.
Slightly reduces the number of unique vertex shaders but doesn't do much
for the pipeline count, as the fragment shader has a tex flag. Still
worth doing for the simplification.
2023-01-11 14:16:46 +01:00

294 lines
7.8 KiB
C++

#pragma once
#include <string>
#include <cstring>
#include <cstdint>
#include "Common/CommonFuncs.h"
// VS_BIT_LIGHT_UBERSHADER indicates that some groups of these will be
// sent to the shader and processed there. This cuts down the number of shaders ("ubershader approach").
enum VShaderBit : uint8_t {
VS_BIT_LMODE = 0,
VS_BIT_IS_THROUGH = 1,
// bit 2 is free.
VS_BIT_HAS_COLOR = 3,
// bit 4 is free.
VS_BIT_VERTEX_RANGE_CULLING = 5,
VS_BIT_SIMPLE_STEREO = 6,
// 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
// 1 bit free at position 5
FS_BIT_3D_TEXTURE = 6,
FS_BIT_SHADER_TEX_CLAMP = 7,
FS_BIT_CLAMP_S = 8,
FS_BIT_CLAMP_T = 9,
// 2 bits free
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,
// 1 free bit
FS_BIT_DO_TEXTURE_PROJ = 22,
// 1 free bit
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)
FS_BIT_SAMPLE_ARRAY_TEXTURE = 57, // For multiview, framebuffers are array textures and we need to sample the two layers correctly.
FS_BIT_STEREO = 58,
FS_BIT_USE_FRAMEBUFFER_FETCH = 59,
};
static inline FShaderBit operator +(FShaderBit bit, int i) {
return FShaderBit((int)bit + i);
}
// Some of these bits are straight from FShaderBit, since they essentially enable attributes directly.
enum GShaderBit : uint8_t {
GS_BIT_ENABLED = 0, // If not set, we don't use a geo shader.
GS_BIT_DO_TEXTURE = 1, // presence of texcoords
GS_BIT_CURVE = 2, // curve, which means don't do range culling.
};
static inline GShaderBit operator +(GShaderBit bit, int i) {
return GShaderBit((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;
}
}
bool is_invalid() const {
for (size_t i = 0; i < ARRAY_SIZE(d); i++) {
if (d[i] != 0xFFFFFFFF)
return false;
}
return true;
}
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];
}
// Note: This is a binary copy to string-as-bytes, not a human-readable representation.
void ToString(std::string *dest) const {
dest->resize(sizeof(d));
memcpy(&(*dest)[0], d, sizeof(d));
}
// Note: This is a binary copy from string-as-bytes, not a human-readable representation.
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);
}
};
struct GShaderID : ShaderID {
GShaderID() : ShaderID() {
}
explicit GShaderID(ShaderID &src) {
memcpy(d, src.d, sizeof(d));
}
bool Bit(GShaderBit bit) const {
return ShaderID::Bit((int)bit);
}
int Bits(GShaderBit bit, int count) const {
return ShaderID::Bits((int)bit, count);
}
void SetBit(GShaderBit bit, bool value = true) {
ShaderID::SetBit((int)bit, value);
}
void SetBits(GShaderBit bit, int count, int value) {
ShaderID::SetBits((int)bit, count, value);
}
};
namespace Draw {
class Bugs;
}
class VertexDecoder;
void ComputeVertexShaderID(VShaderID *id, VertexDecoder *vertexDecoder, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode);
// 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);
void ComputeGeometryShaderID(GShaderID *id, const Draw::Bugs &bugs, int prim);
std::string GeometryShaderDesc(const GShaderID &id);
// For sanity checking.
bool FragmentIdNeedsFramebufferRead(const FShaderID &id);