mirror of
https://github.com/libretro/ppsspp.git
synced 2024-11-24 08:39:51 +00:00
OpenGL: Generate vertex shaders directly from the shader ID.
This commit is contained in:
parent
39f04ab5d6
commit
87f45ed307
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 <stdio.h>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <locale.h>
|
||||
|
||||
#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<GETexMapMode>(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<GETexProjMapMode>(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<GELightType>(id.Bits(BIT_LIGHT0_TYPE + 4*i, 2));
|
||||
GELightComputation comp = static_cast<GELightComputation>(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<GELightType>(id.Bits(BIT_LIGHT0_TYPE + 4*i, 2));
|
||||
GELightComputation comp = static_cast<GELightComputation>(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<GELightType>(id.Bits(BIT_LIGHT0_TYPE + 4*i, 2));
|
||||
GELightComputation comp = static_cast<GELightComputation>(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");
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user