mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
This drastically reduces the shader compile stutter that happens when a lot of new light setups are created, like on the first punch in Tekken 6. There's more stuff that might benefit from being made dynamic like this. These branches are very cheap on modern GPUs since they're branching on a uniform variable, so no divergence. Only tested on Vulkan. I think we'll need to keep the old path too for gpus like Mali-450...
240 lines
6.3 KiB
C++
240 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_ENABLE_FOG = 2,
|
|
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);
|