Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate "Ubershaders" that can handle all lighting configurations #16104

Merged
merged 3 commits into from
Sep 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions GPU/Common/ShaderCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,13 @@ enum : uint64_t {
DIRTY_COLORWRITEMASK = 1ULL << 36,

DIRTY_MIPBIAS = 1ULL << 37,
DIRTY_LIGHT_CONTROL = 1ULL << 38,

// space for 4 more uniform dirty flags. Remember to update DIRTY_ALL_UNIFORMS.
// space for 1 more uniform dirty flags. Remember to update DIRTY_ALL_UNIFORMS.

DIRTY_BONE_UNIFORMS = 0xFF000000ULL,

DIRTY_ALL_UNIFORMS = 0x3FFFFFFFFFULL,
DIRTY_ALL_UNIFORMS = 0x7FFFFFFFFFULL,
DIRTY_ALL_LIGHTS = DIRTY_LIGHT0 | DIRTY_LIGHT1 | DIRTY_LIGHT2 | DIRTY_LIGHT3,

// Other dirty elements that aren't uniforms!
Expand All @@ -113,6 +114,8 @@ enum : uint64_t {
// TODO: Should we also add DIRTY_FRAMEBUF here? It kinda generally takes care of itself.
DIRTY_ALL_RENDER_STATE = DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS,

// Note that the top 8 bits (54-63) cannot be dirtied through the commonCommandTable due to packing of other flags.

DIRTY_ALL = 0xFFFFFFFFFFFFFFFF
};

Expand Down
21 changes: 14 additions & 7 deletions GPU/Common/ShaderId.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ std::string VertexShaderDesc(const VShaderID &id) {
if (id.Bit(VS_BIT_LIGHTING_ENABLE)) {
desc << "Light: ";
}
if (id.Bit(VS_BIT_LIGHT_UBERSHADER)) {
desc << "LightUberShader ";
}
for (int i = 0; i < 4; i++) {
bool enabled = id.Bit(VS_BIT_LIGHT0_ENABLE + i) && id.Bit(VS_BIT_LIGHTING_ENABLE);
if (enabled || (uvgMode == GE_TEXMAP_ENVIRONMENT_MAP && (ls0 == i || ls1 == i))) {
Expand Down Expand Up @@ -125,13 +128,17 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform,
// doShadeMapping is stored as UVGenMode, and light type doesn't matter for shade mapping.
id.SetBits(VS_BIT_MATERIAL_UPDATE, 3, gstate.getMaterialUpdate());
id.SetBit(VS_BIT_LIGHTING_ENABLE);
// Light bits
for (int i = 0; i < 4; i++) {
bool chanEnabled = gstate.isLightChanEnabled(i) != 0;
id.SetBit(VS_BIT_LIGHT0_ENABLE + i, chanEnabled);
if (chanEnabled) {
id.SetBits(VS_BIT_LIGHT0_COMP + 4 * i, 2, gstate.getLightComputation(i));
id.SetBits(VS_BIT_LIGHT0_TYPE + 4 * i, 2, gstate.getLightType(i));
if (gstate_c.Supports(GPU_USE_LIGHT_UBERSHADER)) {
id.SetBit(VS_BIT_LIGHT_UBERSHADER);
} else {
// Light bits
for (int i = 0; i < 4; i++) {
bool chanEnabled = gstate.isLightChanEnabled(i) != 0;
id.SetBit(VS_BIT_LIGHT0_ENABLE + i, chanEnabled);
if (chanEnabled) {
id.SetBits(VS_BIT_LIGHT0_COMP + 4 * i, 2, gstate.getLightComputation(i));
id.SetBits(VS_BIT_LIGHT0_TYPE + 4 * i, 2, gstate.getLightType(i));
}
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion GPU/Common/ShaderId.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ enum VShaderBit : uint8_t {
VS_BIT_BONES = 22, // 3 should be enough, not 8
// 25 - 29 are free.
VS_BIT_ENABLE_BONES = 30,
// 31 is free.

// 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
Expand Down
26 changes: 25 additions & 1 deletion GPU/Common/ShaderUniforms.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,24 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView
}
}

uint32_t PackLightControlBits() {
// Bit organization
// Bottom 4 bits are enable bits for each light.
// Then, for each light, comes 2 bits for "comp" and 2 bits for "type".
uint32_t lightControl = 0;
for (int i = 0; i < 4; i++) {
if (gstate.isLightChanEnabled(i)) {
lightControl |= 1 << i;
}

u32 computation = (u32)gstate.getLightComputation(i); // 2 bits
u32 type = (u32)gstate.getLightType(i); // 2 bits
lightControl |= computation << (4 + i * 4);
lightControl |= type << (4 + i * 4 + 2);
}
return lightControl;
}

void LightUpdateUniforms(UB_VS_Lights *ub, uint64_t dirtyUniforms) {
// Lighting
if (dirtyUniforms & DIRTY_AMBIENT) {
Expand All @@ -279,7 +297,13 @@ void LightUpdateUniforms(UB_VS_Lights *ub, uint64_t dirtyUniforms) {
Uint8x3ToFloat4_Alpha(ub->materialSpecular, gstate.materialspecular, std::max(0.0f, getFloat24(gstate.materialspecularcoef)));
}
if (dirtyUniforms & DIRTY_MATEMISSIVE) {
Uint8x3ToFloat4(ub->materialEmissive, gstate.materialemissive);
// We're not touching the fourth f32 here, because we store an u32 of control bits in it.
float temp[4];
Uint8x3ToFloat4(temp, gstate.materialemissive);
memcpy(ub->materialEmissive, temp, 12);
}
if (dirtyUniforms & DIRTY_LIGHT_CONTROL) {
ub->lightControl = PackLightControlBits();
}
for (int i = 0; i < 4; i++) {
if (dirtyUniforms & (DIRTY_LIGHT0 << i)) {
Expand Down
7 changes: 5 additions & 2 deletions GPU/Common/ShaderUniforms.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ enum : uint64_t {
DIRTY_ALPHACOLORMASK | DIRTY_SHADERBLEND | DIRTY_COLORWRITEMASK | DIRTY_UVSCALEOFFSET | DIRTY_TEXCLAMP | DIRTY_DEPTHRANGE | DIRTY_MATAMBIENTALPHA |
DIRTY_BEZIERSPLINE | DIRTY_DEPAL,
DIRTY_LIGHT_UNIFORMS =
DIRTY_LIGHT0 | DIRTY_LIGHT1 | DIRTY_LIGHT2 | DIRTY_LIGHT3 |
DIRTY_LIGHT_CONTROL | DIRTY_LIGHT0 | DIRTY_LIGHT1 | DIRTY_LIGHT2 | DIRTY_LIGHT3 |
DIRTY_MATDIFFUSE | DIRTY_MATSPECULAR | DIRTY_MATEMISSIVE | DIRTY_AMBIENT,
};

Expand Down Expand Up @@ -80,7 +80,8 @@ struct UB_VS_Lights {
float ambientColor[4];
float materialDiffuse[4];
float materialSpecular[4];
float materialEmissive[4];
float materialEmissive[3];
uint32_t lightControl;
float lpos[4][4];
float ldir[4][4];
float latt[4][4];
Expand All @@ -95,6 +96,7 @@ R"( vec4 u_ambient;
vec3 u_matdiffuse;
vec4 u_matspecular;
vec3 u_matemissive;
uint u_lightControl; // light ubershader
vec3 u_lightpos0;
vec3 u_lightpos1;
vec3 u_lightpos2;
Expand Down Expand Up @@ -141,3 +143,4 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView
void LightUpdateUniforms(UB_VS_Lights *ub, uint64_t dirtyUniforms);
void BoneUpdateUniforms(UB_VS_Bones *ub, uint64_t dirtyUniforms);

uint32_t PackLightControlBits();
Loading