diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index 7d49c90234..8bf1f69356 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -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) { @@ -284,25 +302,9 @@ void LightUpdateUniforms(UB_VS_Lights *ub, uint64_t dirtyUniforms) { Uint8x3ToFloat4(temp, gstate.materialemissive); memcpy(ub->materialEmissive, temp, 12); } - if (dirtyUniforms & DIRTY_LIGHT_CONTROL) { - // 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); - } - ub->lightControl = lightControl; + ub->lightControl = PackLightControlBits(); } - for (int i = 0; i < 4; i++) { if (dirtyUniforms & (DIRTY_LIGHT0 << i)) { if (gstate.isDirectionalLight(i)) { diff --git a/GPU/Common/ShaderUniforms.h b/GPU/Common/ShaderUniforms.h index 583a72513f..ab71309e93 100644 --- a/GPU/Common/ShaderUniforms.h +++ b/GPU/Common/ShaderUniforms.h @@ -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, }; @@ -96,7 +96,7 @@ R"( vec4 u_ambient; vec3 u_matdiffuse; vec4 u_matspecular; vec3 u_matemissive; - uint u_lightControl; // light ubershader + uint u_lightControl; // light ubershader vec3 u_lightpos0; vec3 u_lightpos1; vec3 u_lightpos2; @@ -143,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(); diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 99eb0e0b86..a5d3adf933 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -329,6 +329,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag if (doTexture) { WRITE(p, "vec4 u_uvscaleoffset : register(c%i);\n", CONST_VS_UVSCALEOFFSET); } + // No need for light ubershader support here, D3D9 doesn't do it. for (int i = 0; i < 4; i++) { if (doLight[i] != LIGHT_OFF) { // This is needed for shade mapping @@ -423,7 +424,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " vec3 v_color1 : COLOR1;\n"); if (enableFog) { - WRITE(p, " float v_fogdepth: TEXCOORD1;\n"); + WRITE(p, " float v_fogdepth : TEXCOORD1;\n"); } if (compat.shaderLanguage == HLSL_D3D9) { WRITE(p, " vec4 gl_Position : POSITION;\n"); @@ -528,6 +529,10 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, "uniform vec4 u_uvscaleoffset;\n"); *uniformMask |= DIRTY_UVSCALEOFFSET; } + if (lightUberShader) { + p.C("uniform uint u_lightControl;\n"); + *uniformMask |= DIRTY_LIGHT_CONTROL; + } for (int i = 0; i < 4; i++) { if (lightUberShader || doLight[i] != LIGHT_OFF) { // This is needed for shade mapping @@ -539,17 +544,17 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag GELightType type = static_cast(id.Bits(VS_BIT_LIGHT0_TYPE + 4 * i, 2)); GELightComputation comp = static_cast(id.Bits(VS_BIT_LIGHT0_COMP + 4 * i, 2)); - if (type != GE_LIGHTTYPE_DIRECTIONAL) + if (lightUberShader || type != GE_LIGHTTYPE_DIRECTIONAL) WRITE(p, "uniform mediump vec3 u_lightatt%i;\n", i); - if (type == GE_LIGHTTYPE_SPOT || type == GE_LIGHTTYPE_UNKNOWN) { + if (lightUberShader || type == GE_LIGHTTYPE_SPOT || type == GE_LIGHTTYPE_UNKNOWN) { WRITE(p, "uniform mediump vec3 u_lightdir%i;\n", i); WRITE(p, "uniform mediump vec2 u_lightangle_spotCoef%i;\n", i); } WRITE(p, "uniform lowp vec3 u_lightambient%i;\n", i); WRITE(p, "uniform lowp vec3 u_lightdiffuse%i;\n", i); - if (comp == GE_LIGHTCOMP_BOTH) { + if (lightUberShader || comp == GE_LIGHTCOMP_BOTH) { WRITE(p, "uniform lowp vec3 u_lightspecular%i;\n", i); } } @@ -1018,55 +1023,55 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag if (lightUberShader) { // TODO: Actually loop in the shader. For now, we write it all out. for (int i = 0; i < 4; i++) { - p.F("if ((u_lightControl & %d) != 0) {\n", 1 << i); - p.F(" uint type = (u_lightControl >> %d) & 3;\n", 4 + 4 * i); - p.F(" uint comp = (u_lightControl >> %d) & 3;\n", 4 + 4 * i + 2); - p.C(" if (type == 0) {\n"); // GE_LIGHTTYPE_DIRECTIONAL - p.F(" toLight = u_lightpos%d;\n", i); - p.C(" } else {\n"); - p.F(" toLight = u_lightpos%d - worldpos;\n", i); - p.F(" distance = length(toLight);\n", i); - p.F(" toLight /= distance;\n", i); - p.C(" }\n"); - p.C(" ldot = dot(toLight, worldnormal);\n"); - p.C(" if (comp == 2) {\n"); // GE_LIGHTCOMP_ONLYPOWDIFFUSE - p.C(" if (u_matspecular.a <= 0.0) {\n"); - p.C(" ldot = 1.0;\n"); - p.C(" } else {\n"); - p.C(" ldot = pow(max(ldot, 0.0), u_matspecular.a);\n"); - p.C(" }\n"); - p.C(" }\n"); - p.C(" switch (type) {\n");// Attenuation - p.C(" case 1:\n"); // GE_LIGHTTYPE_POINT - p.F(" lightScale = clamp(1.0 / dot(u_lightatt%i, vec3(1.0, distance, distance*distance)), 0.0, 1.0);\n", i); - p.C(" break;\n"); - p.C(" case 2:\n"); // GE_LIGHTTYPE_SPOT - p.F(" angle = length(u_lightdir%i) == 0.0 ? 0.0 : dot(normalize(u_lightdir%i), toLight);\n", i, i); - p.F(" if (angle >= u_lightangle_spotCoef%i.x) {\n", i); - p.F(" lightScale = clamp(1.0 / dot(u_lightatt%i, vec3(1.0, distance, distance*distance)), 0.0, 1.0) * (u_lightangle_spotCoef%i.y <= 0.0 ? 1.0 : pow(angle, u_lightangle_spotCoef%i.y));\n", i, i, i); - p.C(" } else {\n"); - p.C(" lightScale = 0.0;\n"); - p.C(" }\n"); - p.C(" break;\n"); - p.C(" default:\n"); // GE_LIGHTTYPE_DIRECTIONAL - p.C(" lightScale = 1.0;\n"); - p.C(" break;\n"); - p.C(" }\n"); - p.F(" diffuse = (u_lightdiffuse%i * %s) * max(ldot, 0.0);\n", i, diffuseStr); - p.C(" if (comp == 1) {\n"); // do specular - p.C(" if (ldot >= 0.0) {\n"); - p.C(" ldot = dot(normalize(toLight + vec3(0.0, 0.0, 1.0)), worldnormal);\n"); - p.C(" if (u_matspecular.a <= 0.0) {\n"); - p.C(" ldot = 1.0;\n"); - p.C(" } else {\n"); - p.C(" ldot = pow(max(ldot, 0.0), u_matspecular.a);\n"); - p.C(" }\n"); - p.C(" if (ldot > 0.0)\n"); - p.F(" lightSum1 += u_lightspecular%i * %s * ldot * lightScale;\n", i, specularStr); - p.C(" }\n"); - p.C(" }\n"); - p.F(" lightSum0.rgb += (u_lightambient%i * %s.rgb + diffuse) * lightScale;\n", i, ambientStr); - p.C(" }\n"); + p.F(" if ((u_lightControl & %du) != 0u) { \n", 1 << i); + p.F(" uint type = (u_lightControl >> %d) & 3u;\n", 4 + 4 * i); + p.F(" uint comp = (u_lightControl >> %d) & 3u;\n", 4 + 4 * i + 2); + p.C(" if (type == 0u) {\n"); // GE_LIGHTTYPE_DIRECTIONAL + p.F(" toLight = u_lightpos%d;\n", i); + p.C(" } else {\n"); + p.F(" toLight = u_lightpos%d - worldpos;\n", i); + p.F(" distance = length(toLight);\n", i); + p.F(" toLight /= distance;\n", i); + p.C(" }\n"); + p.C(" ldot = dot(toLight, worldnormal);\n"); + p.C(" if (comp == 2u) {\n"); // GE_LIGHTCOMP_ONLYPOWDIFFUSE + p.C(" if (u_matspecular.a <= 0.0) {\n"); + p.C(" ldot = 1.0;\n"); + p.C(" } else {\n"); + p.C(" ldot = pow(max(ldot, 0.0), u_matspecular.a);\n"); + p.C(" }\n"); + p.C(" }\n"); + p.C(" switch (type) {\n"); // Attenuation + p.C(" case 1u:\n"); // GE_LIGHTTYPE_POINT + p.F(" lightScale = clamp(1.0 / dot(u_lightatt%i, vec3(1.0, distance, distance*distance)), 0.0, 1.0);\n", i); + p.C(" break;\n"); + p.C(" case 2u:\n"); // GE_LIGHTTYPE_SPOT + p.F(" angle = length(u_lightdir%i) == 0.0 ? 0.0 : dot(normalize(u_lightdir%i), toLight);\n", i, i); + p.F(" if (angle >= u_lightangle_spotCoef%i.x) {\n", i); + p.F(" lightScale = clamp(1.0 / dot(u_lightatt%i, vec3(1.0, distance, distance*distance)), 0.0, 1.0) * (u_lightangle_spotCoef%i.y <= 0.0 ? 1.0 : pow(angle, u_lightangle_spotCoef%i.y));\n", i, i, i); + p.C(" } else {\n"); + p.C(" lightScale = 0.0;\n"); + p.C(" }\n"); + p.C(" break;\n"); + p.C(" default:\n"); // GE_LIGHTTYPE_DIRECTIONAL + p.C(" lightScale = 1.0;\n"); + p.C(" break;\n"); + p.C(" }\n"); + p.F(" diffuse = (u_lightdiffuse%i * %s) * max(ldot, 0.0);\n", i, diffuseStr); + p.C(" if (comp == 1u) {\n"); // do specular + p.C(" if (ldot >= 0.0) {\n"); + p.C(" ldot = dot(normalize(toLight + vec3(0.0, 0.0, 1.0)), worldnormal);\n"); + p.C(" if (u_matspecular.a <= 0.0) {\n"); + p.C(" ldot = 1.0;\n"); + p.C(" } else {\n"); + p.C(" ldot = pow(max(ldot, 0.0), u_matspecular.a);\n"); + p.C(" }\n"); + p.C(" if (ldot > 0.0)\n"); + p.F(" lightSum1 += u_lightspecular%i * %s * ldot * lightScale;\n", i, specularStr); + p.C(" }\n"); + p.C(" }\n"); + p.F(" lightSum0.rgb += (u_lightambient%i * %s.rgb + diffuse) * lightScale;\n", i, ambientStr); + p.C(" }\n"); } } else { // Calculate lights if needed. If shade mapping is enabled, lights may need to be diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 92dfa9488f..a0a8aac16d 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -152,6 +152,7 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, queries.push_back({ &u_uvscaleoffset, "u_uvscaleoffset" }); queries.push_back({ &u_texclamp, "u_texclamp" }); queries.push_back({ &u_texclampoff, "u_texclampoff" }); + queries.push_back({ &u_lightControl, "u_lightControl" }); for (int i = 0; i < 4; i++) { static const char * const lightPosNames[4] = { "u_lightpos0", "u_lightpos1", "u_lightpos2", "u_lightpos3", }; @@ -471,7 +472,6 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu } render_->SetUniformF(&u_fogcoef, 2, fogcoef); } - if (dirty & DIRTY_UVSCALEOFFSET) { const float invW = 1.0f / (float)gstate_c.curTextureWidth; const float invH = 1.0f / (float)gstate_c.curTextureHeight; @@ -605,6 +605,9 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu } // Lighting + if (dirty & DIRTY_LIGHT_CONTROL) { + render_->SetUniformUI1(&u_lightControl, PackLightControlBits()); + } if (dirty & DIRTY_AMBIENT) { SetColorUniform3Alpha(render_, &u_ambient, gstate.ambientcolor, gstate.getAmbientA()); } diff --git a/GPU/GLES/ShaderManagerGLES.h b/GPU/GLES/ShaderManagerGLES.h index 101326ee9b..2dd715cc0b 100644 --- a/GPU/GLES/ShaderManagerGLES.h +++ b/GPU/GLES/ShaderManagerGLES.h @@ -97,6 +97,7 @@ public: int u_texclampoff; // Lighting + int u_lightControl; int u_ambient; int u_matambientalpha; int u_matdiffuse;