diff --git a/GPU/GLES/ShaderManager.cpp b/GPU/GLES/ShaderManager.cpp index 5b6f9a894e..87c104e8a1 100644 --- a/GPU/GLES/ShaderManager.cpp +++ b/GPU/GLES/ShaderManager.cpp @@ -799,7 +799,7 @@ Shader *ShaderManager::ApplyVertexShader(int prim, u32 vertType) { Shader *vs; if (vsIter == vsCache_.end()) { // Vertex shader not in cache. Let's compile it. - GenerateVertexShader(prim, vertType, codeBuffer_, useHWTransform); + GenerateVertexShader(VSID, codeBuffer_); vs = new Shader(codeBuffer_, GL_VERTEX_SHADER, useHWTransform, VSID); if (vs->Failed()) { @@ -813,7 +813,9 @@ Shader *ShaderManager::ApplyVertexShader(int prim, u32 vertType) { // next time and we'll do this over and over... // Can still work with software transform. - GenerateVertexShader(prim, vertType, codeBuffer_, false); + ShaderID vsidTemp; + ComputeVertexShaderID(&vsidTemp, vertType, false); + GenerateVertexShader(vsidTemp, codeBuffer_); vs = new Shader(codeBuffer_, GL_VERTEX_SHADER, false, VSID); } diff --git a/GPU/GLES/VertexShaderGenerator.cpp b/GPU/GLES/VertexShaderGenerator.cpp index b13842d5f6..69f3bc600c 100644 --- a/GPU/GLES/VertexShaderGenerator.cpp +++ b/GPU/GLES/VertexShaderGenerator.cpp @@ -15,7 +15,8 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include +#include +#include #include #include "gfx_es2/gpu_features.h" @@ -42,13 +43,53 @@ #define WRITE p+=sprintf +// These bits are internal to this file, although the resulting IDs will be externally visible. +// TODO: We will cut away many of these, turning them into uniforms. This should reduce the number +// of generated shaders drastically. +enum { + BIT_LMODE = 0, + BIT_IS_THROUGH = 1, + BIT_ENABLE_FOG = 2, + BIT_HAS_COLOR = 3, + BIT_DO_TEXTURE = 4, + BIT_FLIP_TEXTURE = 5, + BIT_DO_TEXTURE_PROJ = 6, + BIT_USE_HW_TRANSFORM = 8, + BIT_HAS_NORMAL = 9, // conditioned on hw transform + BIT_NORM_REVERSE = 10, + BIT_HAS_TEXCOORD = 11, + BIT_UVGEN_MODE = 16, + BIT_UVPROJ_MODE = 18, // 2, can overlap with LS0 + BIT_LS0 = 18, // 2 + BIT_LS1 = 20, // 2 + BIT_BONES = 22, // 3 should be enough, not 8 + BIT_ENABLE_BONES = 30, + BIT_LIGHT0_COMP = 32, + BIT_LIGHT0_TYPE = 34, + BIT_LIGHT1_COMP = 36, + BIT_LIGHT1_TYPE = 38, + BIT_LIGHT2_COMP = 40, + BIT_LIGHT2_TYPE = 42, + BIT_LIGHT3_COMP = 44, + BIT_LIGHT3_TYPE = 46, + BIT_MATERIAL_UPDATE = 48, + BIT_LIGHT0_ENABLE = 52, + BIT_LIGHT1_ENABLE = 53, + BIT_LIGHT2_ENABLE = 54, + BIT_LIGHT3_ENABLE = 55, + BIT_LIGHTING_ENABLE = 56, + BIT_WEIGHT_FMTSCALE = 57, + BIT_TEXCOORD_FMTSCALE = 60, + BIT_FLATSHADE = 62, +}; + bool CanUseHardwareTransform(int prim) { if (!g_Config.bHardwareTransform) return false; return !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES; } -void ComputeVertexShaderID(ShaderID *id, u32 vertType, bool useHWTransform) { +void ComputeVertexShaderID(ShaderID *id_out, u32 vertType, bool useHWTransform) { bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear(); bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX; bool doShadeMapping = gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP; @@ -59,67 +100,74 @@ void ComputeVertexShaderID(ShaderID *id, u32 vertType, bool useHWTransform) { bool hasTexcoord = (vertType & GE_VTYPE_TC_MASK) != 0; bool enableFog = gstate.isFogEnabled() && !gstate.isModeThrough() && !gstate.isModeClear(); bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled(); + // lmode: && !isModeThrough!? - int id0 = 0; - int id1 = 0; + ShaderID id; + id.SetBit(BIT_LMODE, lmode); + id.SetBit(BIT_IS_THROUGH, gstate.isModeThrough()); + id.SetBit(BIT_ENABLE_FOG, enableFog); + id.SetBit(BIT_HAS_COLOR, hasColor); - id0 = lmode & 1; - id0 |= (gstate.isModeThrough() & 1) << 1; - id0 |= (enableFog & 1) << 2; - id0 |= (hasColor & 1) << 3; if (doTexture) { - id0 |= 1 << 4; - id0 |= (gstate_c.flipTexture & 1) << 5; - id0 |= (doTextureProjection & 1) << 6; + id.SetBit(BIT_DO_TEXTURE); + id.SetBit(BIT_FLIP_TEXTURE, gstate_c.flipTexture); + id.SetBit(BIT_DO_TEXTURE_PROJ, doTextureProjection); } if (useHWTransform) { - id0 |= 1 << 8; - id0 |= (hasNormal & 1) << 9; + id.SetBit(BIT_USE_HW_TRANSFORM); + id.SetBit(BIT_HAS_NORMAL, hasNormal); - // UV generation mode - id0 |= gstate.getUVGenMode() << 16; + // UV generation mode. + id.SetBits(BIT_UVGEN_MODE, 2, gstate.getUVGenMode()); // The next bits are used differently depending on UVgen mode if (doTextureProjection) { - id0 |= gstate.getUVProjMode() << 18; + id.SetBits(BIT_UVPROJ_MODE, 2, gstate.getUVProjMode()); } else if (doShadeMapping) { - id0 |= gstate.getUVLS0() << 18; - id0 |= gstate.getUVLS1() << 20; + id.SetBits(BIT_LS0, 2, gstate.getUVLS0()); + id.SetBits(BIT_LS1, 2, gstate.getUVLS1()); } - // Bones - if (vertTypeIsSkinningEnabled(vertType)) - id0 |= (TranslateNumBones(vertTypeGetNumBoneWeights(vertType)) - 1) << 22; + // Bones. + bool enableBones = vertTypeIsSkinningEnabled(vertType); + id.SetBit(BIT_ENABLE_BONES, enableBones); + if (enableBones) { + id.SetBits(BIT_BONES, 3, TranslateNumBones(vertTypeGetNumBoneWeights(vertType)) - 1); + } // Okay, d[1] coming up. ============== - if (gstate.isLightingEnabled() || doShadeMapping) { // Light bits for (int i = 0; i < 4; i++) { - id1 |= gstate.getLightComputation(i) << (i * 4); - id1 |= gstate.getLightType(i) << (i * 4 + 2); + // TODO: if (gstate.isLightChanEnabled(i)) { + id.SetBits(BIT_LIGHT0_COMP + 4 * i, 2, gstate.getLightComputation(i)); + id.SetBits(BIT_LIGHT0_TYPE + 4 * i, 2, gstate.getLightType(i)); + // } } - id1 |= (gstate.materialupdate & 7) << 16; + id.SetBits(BIT_MATERIAL_UPDATE, 3, gstate.getMaterialUpdate() & 7); + // TODO: Optimize by shifting in all the light bits together. for (int i = 0; i < 4; i++) { - id1 |= (gstate.isLightChanEnabled(i) & 1) << (20 + i); + id.SetBit(BIT_LIGHT0_ENABLE + i, gstate.isLightChanEnabled(i) != 0); } // doShadeMapping is stored as UVGenMode, so this is enough for isLightingEnabled. - id1 |= 1 << 24; + id.SetBit(BIT_LIGHTING_ENABLE); } - // 2 bits. - id1 |= (vertTypeGetWeightMask(vertType) >> GE_VTYPE_WEIGHT_SHIFT) << 25; - id1 |= (gstate.areNormalsReversed() & 1) << 27; + + // 2 bits. We should probably send in the weight scalefactor as a uniform instead, + // or simply preconvert all weights to floats. + id.SetBits(BIT_WEIGHT_FMTSCALE, 2, vertTypeGetWeightMask(vertType)); + id.SetBit(BIT_NORM_REVERSE, gstate.areNormalsReversed()); if (doTextureProjection && gstate.getUVProjMode() == GE_PROJMAP_UV) { - id1 |= ((vertType & GE_VTYPE_TC_MASK) >> GE_VTYPE_TC_SHIFT) << 28; // two bits + id.SetBit(BIT_TEXCOORD_FMTSCALE, (vertType & GE_VTYPE_TC_MASK) >> GE_VTYPE_TC_SHIFT); // two bits } else { - id1 |= (hasTexcoord & 1) << 28; + id.SetBit(BIT_HAS_TEXCOORD, hasTexcoord); } } - id1 |= (doFlatShading & 1) << 29; - id->d[0] = id0; - id->d[1] = id1; + id.SetBit(BIT_FLATSHADE, doFlatShading); + + *id_out = id; } static const char * const boneWeightAttrDecl[9] = { @@ -179,10 +227,10 @@ enum DoLightComputation { // is a bit of a rare configuration, although quite common on mobile. -void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransform) { +void GenerateVertexShader(const ShaderID &id, char *buffer) { char *p = buffer; -// #define USE_FOR_LOOP + // #define USE_FOR_LOOP // In GLSL ES 3.0, you use "out" variables instead. bool glslES30 = false; @@ -208,6 +256,7 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf highpTexcoord = highpFog; } else { // TODO: Handle this in VersionGEThan? + #if !defined(FORCE_OPENGL_2_0) if (gl_extensions.VersionGEThan(3, 3, 0)) { glslES30 = true; @@ -231,40 +280,55 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf boneWeightDecl = boneWeightInDecl; } + bool lmode = id.Bit(BIT_LMODE) && !gstate.isModeThrough(); // TODO: Different expression than in shaderIDgen + bool doTexture = id.Bit(BIT_DO_TEXTURE); + bool doTextureProjection = id.Bit(BIT_DO_TEXTURE_PROJ); - bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !gstate.isModeThrough(); - bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear(); - bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX; - bool doShadeMapping = gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP; - bool doFlatShading = gstate.getShadeMode() == GE_SHADE_FLAT && !gstate.isModeClear(); + GETexMapMode uvGenMode = static_cast(id.Bits(BIT_UVGEN_MODE, 2)); - bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0 || !useHWTransform; - bool hasNormal = (vertType & GE_VTYPE_NRM_MASK) != 0 && useHWTransform; - bool hasTexcoord = (vertType & GE_VTYPE_TC_MASK) != 0 || !useHWTransform; - bool enableFog = gstate.isFogEnabled() && !gstate.isModeThrough() && !gstate.isModeClear(); - bool throughmode = (vertType & GE_VTYPE_THROUGH_MASK) != 0; - bool flipV = gstate_c.flipTexture; // This also means that we are texturing from a render target - bool flipNormal = gstate.areNormalsReversed(); + // this is only valid for some settings of uvGenMode + GETexProjMapMode uvProjMode = static_cast(id.Bits(BIT_UVPROJ_MODE, 2)); + bool doShadeMapping = uvGenMode == GE_TEXMAP_ENVIRONMENT_MAP; + bool doFlatShading = id.Bit(BIT_FLATSHADE); + + bool isModeThrough = id.Bit(BIT_IS_THROUGH); + bool useHWTransform = id.Bit(BIT_USE_HW_TRANSFORM); + bool hasColor = id.Bit(BIT_HAS_COLOR) || !useHWTransform; + bool hasNormal = id.Bit(BIT_HAS_NORMAL) && useHWTransform; + bool hasTexcoord = id.Bit(BIT_HAS_TEXCOORD) || !useHWTransform; + bool enableFog = id.Bit(BIT_ENABLE_FOG); + bool throughmode = id.Bit(BIT_IS_THROUGH); + bool flipV = id.Bit(BIT_FLIP_TEXTURE); // This also means that we are texturing from a render target + bool flipNormal = id.Bit(BIT_NORM_REVERSE); + int ls0 = id.Bits(BIT_LS0, 2); + int ls1 = id.Bits(BIT_LS1, 2); + bool enableBones = id.Bit(BIT_ENABLE_BONES); + bool enableLighting = id.Bit(BIT_LIGHTING_ENABLE); + int matUpdate = id.Bits(BIT_MATERIAL_UPDATE, 3); const char *shading = ""; if (glslES30) - shading = doFlatShading ? "flat" : ""; + shading = doFlatShading ? "flat " : ""; DoLightComputation doLight[4] = {LIGHT_OFF, LIGHT_OFF, LIGHT_OFF, LIGHT_OFF}; if (useHWTransform) { - int shadeLight0 = doShadeMapping ? gstate.getUVLS0() : -1; - int shadeLight1 = doShadeMapping ? gstate.getUVLS1() : -1; + int shadeLight0 = doShadeMapping ? ls0 : -1; + int shadeLight1 = doShadeMapping ? ls1 : -1; for (int i = 0; i < 4; i++) { if (i == shadeLight0 || i == shadeLight1) doLight[i] = LIGHT_SHADE; - if (gstate.isLightingEnabled() && gstate.isLightChanEnabled(i)) + if (id.Bit(BIT_LIGHTING_ENABLE) && id.Bit(BIT_LIGHT0_ENABLE + i)) doLight[i] = LIGHT_FULL; } } - if (vertTypeIsSkinningEnabled(vertType)) { - WRITE(p, "%s", boneWeightDecl[TranslateNumBones(vertTypeGetNumBoneWeights(vertType))]); + int numBoneWeights = 0; + int boneWeightScale = id.Bits(BIT_WEIGHT_FMTSCALE, 2); + if (enableBones) { + numBoneWeights = 1 + id.Bits(BIT_BONES, 3); + WRITE(p, "%s", boneWeightDecl[numBoneWeights]); } + int texFmtScale = id.Bits(BIT_TEXCOORD_FMTSCALE, 2); if (useHWTransform) WRITE(p, "%s vec3 position;\n", attribute); @@ -286,14 +350,14 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf WRITE(p, "%s lowp vec3 color1;\n", attribute); } - if (gstate.isModeThrough()) { + if (isModeThrough) { WRITE(p, "uniform mat4 u_proj_through;\n"); } else { WRITE(p, "uniform mat4 u_proj;\n"); // Add all the uniforms we'll need to transform properly. } - bool prescale = g_Config.bPrescaleUV && !throughmode && (gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_COORDS || gstate.getUVGenMode() == GE_TEXMAP_UNKNOWN); + bool prescale = g_Config.bPrescaleUV && !throughmode && (uvGenMode == GE_TEXMAP_TEXTURE_COORDS || uvGenMode == GE_TEXMAP_UNKNOWN); if (useHWTransform) { // When transforming by hardware, we need a great deal more uniforms... @@ -301,17 +365,16 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf WRITE(p, "uniform mat4 u_view;\n"); if (doTextureProjection) WRITE(p, "uniform mediump mat4 u_texmtx;\n"); - if (vertTypeIsSkinningEnabled(vertType)) { - int numBones = TranslateNumBones(vertTypeGetNumBoneWeights(vertType)); + if (enableBones) { #ifdef USE_BONE_ARRAY - WRITE(p, "uniform mediump mat4 u_bone[%i];\n", numBones); + WRITE(p, "uniform mediump mat4 u_bone[%i];\n", numBoneWeights); #else - for (int i = 0; i < numBones; i++) { + for (int i = 0; i < numBoneWeights; i++) { WRITE(p, "uniform mat4 u_bone%i;\n", i); } #endif } - if (doTexture && (flipV || !prescale || gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP || gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX)) { + if (doTexture && (flipV || !prescale || uvGenMode == GE_TEXMAP_ENVIRONMENT_MAP || uvGenMode == GE_TEXMAP_TEXTURE_MATRIX)) { WRITE(p, "uniform vec4 u_uvscaleoffset;\n"); } for (int i = 0; i < 4; i++) { @@ -320,12 +383,13 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf WRITE(p, "uniform vec3 u_lightpos%i;\n", i); } if (doLight[i] == LIGHT_FULL) { - GELightType type = gstate.getLightType(i); + GELightType type = static_cast(id.Bits(BIT_LIGHT0_TYPE + 4*i, 2)); + GELightComputation comp = static_cast(id.Bits(BIT_LIGHT0_COMP + 4*i, 2)); if (type != GE_LIGHTTYPE_DIRECTIONAL) WRITE(p, "uniform mediump vec3 u_lightatt%i;\n", i); - if (type == GE_LIGHTTYPE_SPOT || type == GE_LIGHTTYPE_UNKNOWN) { + if (type == GE_LIGHTTYPE_SPOT || type == GE_LIGHTTYPE_UNKNOWN) { WRITE(p, "uniform mediump vec3 u_lightdir%i;\n", i); WRITE(p, "uniform mediump float u_lightangle%i;\n", i); WRITE(p, "uniform mediump float u_lightspotCoef%i;\n", i); @@ -333,13 +397,14 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf WRITE(p, "uniform lowp vec3 u_lightambient%i;\n", i); WRITE(p, "uniform lowp vec3 u_lightdiffuse%i;\n", i); - if (gstate.isUsingSpecularLight(i)) + if (comp != GE_LIGHTCOMP_ONLYDIFFUSE) { WRITE(p, "uniform lowp vec3 u_lightspecular%i;\n", i); + } } } - if (gstate.isLightingEnabled()) { + if (enableLighting) { WRITE(p, "uniform lowp vec4 u_ambient;\n"); - if ((gstate.materialupdate & 2) == 0 || !hasColor) + if ((matUpdate & 2) == 0 || !hasColor) WRITE(p, "uniform lowp vec3 u_matdiffuse;\n"); // if ((gstate.materialupdate & 4) == 0) WRITE(p, "uniform lowp vec4 u_matspecular;\n"); // Specular coef is contained in alpha @@ -358,17 +423,18 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf WRITE(p, "uniform highp vec4 u_depthRange;\n"); } - WRITE(p, "%s %s lowp vec4 v_color0;\n", shading, varying); + WRITE(p, "%s%s lowp vec4 v_color0;\n", shading, varying); if (lmode) { - WRITE(p, "%s %s lowp vec3 v_color1;\n", shading, varying); - } - if (doTexture) { - if (doTextureProjection) - WRITE(p, "%s %s vec3 v_texcoord;\n", varying, highpTexcoord ? "highp" : "mediump"); - else - WRITE(p, "%s %s vec2 v_texcoord;\n", varying, highpTexcoord ? "highp" : "mediump"); + WRITE(p, "%s%s lowp vec3 v_color1;\n", shading, varying); } + if (doTexture) { + if (doTextureProjection) { + WRITE(p, "%s %s vec3 v_texcoord;\n", varying, highpTexcoord ? "highp" : "mediump"); + } else { + WRITE(p, "%s %s vec2 v_texcoord;\n", varying, highpTexcoord ? "highp" : "mediump"); + } + } if (enableFog) { // See the fragment shader generator @@ -380,7 +446,7 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf } // See comment above this function (GenerateVertexShader). - if (!gstate.isModeThrough() && gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { + if (!isModeThrough && gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { // Apply the projection and viewport to get the Z buffer value, floor to integer, undo the viewport and projection. WRITE(p, "\nvec4 depthRoundZVP(vec4 v) {\n"); WRITE(p, " float z = v.z / v.w;\n"); @@ -414,7 +480,7 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf if (enableFog) { WRITE(p, " v_fogdepth = position.w;\n"); } - if (gstate.isModeThrough()) { + if (isModeThrough) { WRITE(p, " gl_Position = u_proj_through * vec4(position.xyz, 1.0);\n"); } else { // The viewport is used in this case, so need to compensate for that. @@ -426,7 +492,7 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf } } else { // Step 1: World Transform / Skinning - if (!vertTypeIsSkinningEnabled(vertType)) { + if (!enableBones) { // No skinning, just standard T&L. WRITE(p, " vec3 worldpos = (u_world * vec4(position.xyz, 1.0)).xyz;\n"); if (hasNormal) @@ -434,10 +500,8 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf else WRITE(p, " mediump vec3 worldnormal = vec3(0.0, 0.0, 1.0);\n"); } else { - int numWeights = TranslateNumBones(vertTypeGetNumBoneWeights(vertType)); - static const char *rescale[4] = {"", " * 1.9921875", " * 1.999969482421875", ""}; // 2*127.5f/128.f, 2*32767.5f/32768.f, 1.0f}; - const char *factor = rescale[vertTypeGetWeightMask(vertType) >> GE_VTYPE_WEIGHT_SHIFT]; + const char *factor = rescale[texFmtScale]; static const char * const boneWeightAttr[8] = { "w1.x", "w1.y", "w1.z", "w1.w", @@ -448,7 +512,7 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf // To loop through the weights, we unfortunately need to put them in a float array. // GLSL ES sucks - no way to directly initialize an array! - switch (numWeights) { + switch (numBoneWeights) { case 1: WRITE(p, " float w[1]; w[0] = w1;\n"); break; case 2: WRITE(p, " float w[2]; w[0] = w1.x; w[1] = w1.y;\n"); break; case 3: WRITE(p, " float w[3]; w[0] = w1.x; w[1] = w1.y; w[2] = w1.z;\n"); break; @@ -460,8 +524,8 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf } WRITE(p, " mat4 skinMatrix = w[0] * u_bone[0];\n"); - if (numWeights > 1) { - WRITE(p, " for (int i = 1; i < %i; i++) {\n", numWeights); + if (numBoneWeights > 1) { + WRITE(p, " for (int i = 1; i < %i; i++) {\n", numBoneWeights); WRITE(p, " skinMatrix += w[i] * u_bone[i];\n"); WRITE(p, " }\n"); } @@ -469,29 +533,29 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf #else #ifdef USE_BONE_ARRAY - if (numWeights == 1) + if (numBoneWeights == 1) WRITE(p, " mat4 skinMatrix = w1 * u_bone[0]"); else WRITE(p, " mat4 skinMatrix = w1.x * u_bone[0]"); - for (int i = 1; i < numWeights; i++) { + for (int i = 1; i < numBoneWeights; i++) { const char *weightAttr = boneWeightAttr[i]; // workaround for "cant do .x of scalar" issue - if (numWeights == 1 && i == 0) weightAttr = "w1"; - if (numWeights == 5 && i == 4) weightAttr = "w2"; + if (numBoneWeights == 1 && i == 0) weightAttr = "w1"; + if (numBoneWeights == 5 && i == 4) weightAttr = "w2"; WRITE(p, " + %s * u_bone[%i]", weightAttr, i); } #else // Uncomment this to screw up bone shaders to check the vertex shader software fallback // WRITE(p, "THIS SHOULD ERROR! #error"); - if (numWeights == 1) + if (numBoneWeights == 1) WRITE(p, " mat4 skinMatrix = w1 * u_bone0"); else WRITE(p, " mat4 skinMatrix = w1.x * u_bone0"); - for (int i = 1; i < numWeights; i++) { + for (int i = 1; i < numBoneWeights; i++) { const char *weightAttr = boneWeightAttr[i]; // workaround for "cant do .x of scalar" issue - if (numWeights == 1 && i == 0) weightAttr = "w1"; - if (numWeights == 5 && i == 4) weightAttr = "w2"; + if (numBoneWeights == 1 && i == 0) weightAttr = "w1"; + if (numBoneWeights == 5 && i == 4) weightAttr = "w2"; WRITE(p, " + %s * u_bone%i", weightAttr, i); } #endif @@ -523,24 +587,25 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf // TODO: Declare variables for dots for shade mapping if needed. - const char *ambientStr = (gstate.materialupdate & 1) && hasColor ? "color0" : "u_matambientalpha"; - const char *diffuseStr = (gstate.materialupdate & 2) && hasColor ? "color0.rgb" : "u_matdiffuse"; - const char *specularStr = (gstate.materialupdate & 4) && hasColor ? "color0.rgb" : "u_matspecular.rgb"; + const char *ambientStr = (matUpdate & 1) && hasColor ? "color0" : "u_matambientalpha"; + const char *diffuseStr = (matUpdate & 2) && hasColor ? "color0.rgb" : "u_matdiffuse"; + const char *specularStr = (matUpdate & 4) && hasColor ? "color0.rgb" : "u_matspecular.rgb"; bool diffuseIsZero = true; bool specularIsZero = true; bool distanceNeeded = false; - if (gstate.isLightingEnabled()) { + if (enableLighting) { WRITE(p, " lowp vec4 lightSum0 = u_ambient * %s + vec4(u_matemissive, 0.0);\n", ambientStr); for (int i = 0; i < 4; i++) { + GELightType type = static_cast(id.Bits(BIT_LIGHT0_TYPE + 4*i, 2)); + GELightComputation comp = static_cast(id.Bits(BIT_LIGHT0_COMP + 4*i, 2)); if (doLight[i] != LIGHT_FULL) continue; diffuseIsZero = false; - if (gstate.isUsingSpecularLight(i)) + if (comp != GE_LIGHTCOMP_ONLYDIFFUSE) specularIsZero = false; - GELightType type = gstate.getLightType(i); if (type != GE_LIGHTTYPE_DIRECTIONAL) distanceNeeded = true; } @@ -564,7 +629,8 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf if (doLight[i] != LIGHT_FULL) continue; - GELightType type = gstate.getLightType(i); + GELightType type = static_cast(id.Bits(BIT_LIGHT0_TYPE + 4*i, 2)); + GELightComputation comp = static_cast(id.Bits(BIT_LIGHT0_COMP + 4*i, 2)); if (type == GE_LIGHTTYPE_DIRECTIONAL) { // We prenormalize light positions for directional lights. @@ -575,8 +641,8 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf WRITE(p, " toLight /= distance;\n"); } - bool doSpecular = gstate.isUsingSpecularLight(i); - bool poweredDiffuse = gstate.isUsingPoweredDiffuseLight(i); + bool doSpecular = comp != GE_LIGHTCOMP_ONLYDIFFUSE; + bool poweredDiffuse = comp == GE_LIGHTCOMP_BOTHWITHPOWDIFFUSE; WRITE(p, " mediump float dot%i = max(dot(toLight, worldnormal), 0.0);\n", i); if (poweredDiffuse) { @@ -622,7 +688,7 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf WRITE(p, " lightSum0.rgb += (u_lightambient%i * %s.rgb + diffuse)%s;\n", i, ambientStr, timesLightScale); } - if (gstate.isLightingEnabled()) { + if (id.Bit(BIT_LIGHTING_ENABLE)) { // Sum up ambient, emissive here. if (lmode) { WRITE(p, " v_color0 = clamp(lightSum0, 0.0, 1.0);\n"); @@ -652,7 +718,7 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf // Step 3: UV generation if (doTexture) { - switch (gstate.getUVGenMode()) { + switch (uvGenMode) { case GE_TEXMAP_TEXTURE_COORDS: // Scale-offset. Easy. case GE_TEXMAP_UNKNOWN: // Not sure what this is, but Riviera uses it. Treating as coords works. if (prescale && !flipV) { @@ -673,7 +739,7 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf case GE_TEXMAP_TEXTURE_MATRIX: // Projection mapping. { std::string temp_tc; - switch (gstate.getUVProjMode()) { + switch (uvProjMode) { case GE_PROJMAP_POSITION: // Use model space XYZ as source temp_tc = "vec4(position.xyz, 1.0)"; break; @@ -682,7 +748,7 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf // prescale is false here. if (hasTexcoord) { static const char *rescaleuv[4] = {"", " * 1.9921875", " * 1.999969482421875", ""}; // 2*127.5f/128.f, 2*32767.5f/32768.f, 1.0f}; - const char *factor = rescaleuv[(vertType & GE_VTYPE_TC_MASK) >> GE_VTYPE_TC_SHIFT]; + const char *factor = rescaleuv[texFmtScale]; temp_tc = StringFromFormat("vec4(texcoord.xy %s, 0.0, 1.0)", factor); } else { temp_tc = "vec4(0.0, 0.0, 0.0, 1.0)"; @@ -708,7 +774,7 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf break; case GE_TEXMAP_ENVIRONMENT_MAP: // Shade mapping - use dots from light sources. - WRITE(p, " v_texcoord = u_uvscaleoffset.xy * vec2(1.0 + dot(normalize(u_lightpos%i), worldnormal), 1.0 + dot(normalize(u_lightpos%i), worldnormal)) * 0.5;\n", gstate.getUVLS0(), gstate.getUVLS1()); + WRITE(p, " v_texcoord = u_uvscaleoffset.xy * vec2(1.0 + dot(normalize(u_lightpos%i), worldnormal), 1.0 + dot(normalize(u_lightpos%i), worldnormal)) * 0.5;\n", ls0, ls1); break; default: @@ -717,7 +783,7 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf } // Will flip in the fragment for GE_TEXMAP_TEXTURE_MATRIX. - if (flipV && gstate.getUVGenMode() != GE_TEXMAP_TEXTURE_MATRIX) + if (flipV && uvGenMode != GE_TEXMAP_TEXTURE_MATRIX) WRITE(p, " v_texcoord.y = 1.0 - v_texcoord.y;\n"); } @@ -727,4 +793,3 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf } WRITE(p, "}\n"); } - diff --git a/GPU/GLES/VertexShaderGenerator.h b/GPU/GLES/VertexShaderGenerator.h index 951b6cd281..544686df1a 100644 --- a/GPU/GLES/VertexShaderGenerator.h +++ b/GPU/GLES/VertexShaderGenerator.h @@ -26,4 +26,4 @@ struct ShaderID; bool CanUseHardwareTransform(int prim); void ComputeVertexShaderID(ShaderID *id, u32 vertexType, bool useHWTransform); -void GenerateVertexShader(int prim, u32 vertexType, char *buffer, bool useHWTransform); +void GenerateVertexShader(const ShaderID &id, char *buffer);