mirror of
https://github.com/libretro/ppsspp.git
synced 2024-11-24 08:39:51 +00:00
Use arrays and for loops in GLSL shaders for bone processing, to shrink the shaders which are becoming too big for some mobile GPUs. Might fix #1816.
This commit is contained in:
parent
dca2406374
commit
1b210fab14
@ -54,6 +54,9 @@ Shader::Shader(const char *code, uint32_t shaderType) {
|
||||
ERROR_LOG(G3D, "Info log: %s\n", infoLog);
|
||||
ERROR_LOG(G3D, "Shader source:\n%s\n", (const char *)code);
|
||||
Reporting::ReportMessage("Error in shader compilation: info: %s / code: %s", infoLog, (const char *)code);
|
||||
#ifdef SHADERLOG
|
||||
OutputDebugString(infoLog);
|
||||
#endif
|
||||
} else {
|
||||
DEBUG_LOG(G3D, "Compiled shader:\n%s\n", (const char *)code);
|
||||
}
|
||||
@ -102,11 +105,8 @@ LinkedShader::LinkedShader(Shader *vs, Shader *fs)
|
||||
u_view = glGetUniformLocation(program, "u_view");
|
||||
u_world = glGetUniformLocation(program, "u_world");
|
||||
u_texmtx = glGetUniformLocation(program, "u_texmtx");
|
||||
for (int i = 0; i < 8; i++) {
|
||||
char name[64];
|
||||
sprintf(name, "u_bone%i", i);
|
||||
u_bone[i] = glGetUniformLocation(program, name);
|
||||
}
|
||||
u_bone = glGetUniformLocation(program, "u_bone");
|
||||
numBones = gstate.getNumBoneWeights();
|
||||
|
||||
// Lighting, texturing
|
||||
u_ambient = glGetUniformLocation(program, "u_ambient");
|
||||
@ -141,8 +141,8 @@ LinkedShader::LinkedShader(Shader *vs, Shader *fs)
|
||||
a_color1 = glGetAttribLocation(program, "a_color1");
|
||||
a_texcoord = glGetAttribLocation(program, "a_texcoord");
|
||||
a_normal = glGetAttribLocation(program, "a_normal");
|
||||
a_weight0123 = glGetAttribLocation(program, "a_weight0123");
|
||||
a_weight4567 = glGetAttribLocation(program, "a_weight4567");
|
||||
a_weight0123 = glGetAttribLocation(program, "a_w1");
|
||||
a_weight4567 = glGetAttribLocation(program, "a_w2");
|
||||
|
||||
glUseProgram(program);
|
||||
|
||||
@ -317,9 +317,13 @@ void LinkedShader::updateUniforms() {
|
||||
if (u_texmtx != -1 && (dirtyUniforms & DIRTY_TEXMATRIX)) {
|
||||
SetMatrix4x3(u_texmtx, gstate.tgenMatrix);
|
||||
}
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (u_bone[i] != -1 && (dirtyUniforms & (DIRTY_BONEMATRIX0 << i))) {
|
||||
SetMatrix4x3(u_bone[i], gstate.boneMatrix + 12 * i);
|
||||
|
||||
// TODO: Could even set all bones in one go if they're all dirty.
|
||||
if (u_bone != -1) {
|
||||
for (int i = 0; i < numBones; i++) {
|
||||
if (dirtyUniforms & (DIRTY_BONEMATRIX0 << i)) {
|
||||
SetMatrix4x3(u_bone + i, gstate.boneMatrix + 12 * i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,8 @@ public:
|
||||
int u_view;
|
||||
int u_texmtx;
|
||||
int u_world;
|
||||
int u_bone[8];
|
||||
int u_bone; // array, size is numBones
|
||||
int numBones;
|
||||
|
||||
// Fragment processing inputs
|
||||
int u_alphacolorref;
|
||||
|
@ -106,25 +106,25 @@ void ComputeVertexShaderID(VertexShaderID *id, int prim) {
|
||||
}
|
||||
|
||||
static const char * const boneWeightAttrDecl[8] = {
|
||||
"attribute mediump float a_weight0123;\n",
|
||||
"attribute mediump vec2 a_weight0123;\n",
|
||||
"attribute mediump vec3 a_weight0123;\n",
|
||||
"attribute mediump vec4 a_weight0123;\n",
|
||||
"attribute mediump vec4 a_weight0123;\nattribute mediump float a_weight4567;\n",
|
||||
"attribute mediump vec4 a_weight0123;\nattribute mediump vec2 a_weight4567;\n",
|
||||
"attribute mediump vec4 a_weight0123;\nattribute mediump vec3 a_weight4567;\n",
|
||||
"attribute mediump vec4 a_weight0123;\nattribute mediump vec4 a_weight4567;\n",
|
||||
"attribute mediump float a_w1;\n",
|
||||
"attribute mediump vec2 a_w1;\n",
|
||||
"attribute mediump vec3 a_w1;\n",
|
||||
"attribute mediump vec4 a_w1;\n",
|
||||
"attribute mediump vec4 a_w1;\nattribute mediump float a_w2;\n",
|
||||
"attribute mediump vec4 a_w1;\nattribute mediump vec2 a_w2;\n",
|
||||
"attribute mediump vec4 a_w1;\nattribute mediump vec3 a_w2;\n",
|
||||
"attribute mediump vec4 a_w1;\nattribute mediump vec4 a_w2;\n",
|
||||
};
|
||||
|
||||
static const char * const boneWeightAttr[8] = {
|
||||
"a_weight0123.x",
|
||||
"a_weight0123.y",
|
||||
"a_weight0123.z",
|
||||
"a_weight0123.w",
|
||||
"a_weight4567.x",
|
||||
"a_weight4567.y",
|
||||
"a_weight4567.z",
|
||||
"a_weight4567.w",
|
||||
"a_w1.x",
|
||||
"a_w1.y",
|
||||
"a_w1.z",
|
||||
"a_w1.w",
|
||||
"a_w2.x",
|
||||
"a_w2.y",
|
||||
"a_w2.z",
|
||||
"a_w2.w",
|
||||
};
|
||||
|
||||
enum DoLightComputation {
|
||||
@ -135,8 +135,13 @@ enum DoLightComputation {
|
||||
|
||||
void GenerateVertexShader(int prim, char *buffer) {
|
||||
char *p = buffer;
|
||||
WRITE(p, "precision highp float;\n");
|
||||
|
||||
#define USE_FOR_LOOP
|
||||
|
||||
#if defined(USING_GLES2)
|
||||
WRITE(p, "precision highp float;\n");
|
||||
|
||||
#elif !defined(FORCE_OPENGL_2_0)
|
||||
WRITE(p, "#version 110\n");
|
||||
// Remove lowp/mediump in non-mobile implementations
|
||||
@ -220,9 +225,7 @@ void GenerateVertexShader(int prim, char *buffer) {
|
||||
WRITE(p, "uniform mediump mat4 u_texmtx;\n");
|
||||
if ((vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE) {
|
||||
int numBones = 1 + ((vertType & GE_VTYPE_WEIGHTCOUNT_MASK) >> GE_VTYPE_WEIGHTCOUNT_SHIFT);
|
||||
for (int i = 0; i < numBones; i++) {
|
||||
WRITE(p, "uniform mediump mat4 u_bone%i;\n", i);
|
||||
}
|
||||
WRITE(p, "uniform mediump mat4 u_bone[%i];\n", numBones);
|
||||
}
|
||||
if (gstate.isLightingEnabled()) {
|
||||
WRITE(p, "uniform lowp vec4 u_ambient;\n");
|
||||
@ -301,19 +304,44 @@ void GenerateVertexShader(int prim, char *buffer) {
|
||||
WRITE(p, " vec3 worldnormal = vec3(0.0, 0.0, 1.0);\n");
|
||||
|
||||
int numWeights = 1 + ((vertType & GE_VTYPE_WEIGHTCOUNT_MASK) >> GE_VTYPE_WEIGHTCOUNT_SHIFT);
|
||||
static const float rescale[4] = {0, 2*127.5f/128.f, 2*32767.5f/32768.f, 2.0f};
|
||||
float factor = rescale[(vertType & GE_VTYPE_WEIGHT_MASK) >> GE_VTYPE_WEIGHT_SHIFT];
|
||||
|
||||
#ifdef USE_FOR_LOOP
|
||||
|
||||
// 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) {
|
||||
case 1: WRITE(p, " float w[1]; w[0] = a_w1;\n"); break;
|
||||
case 2: WRITE(p, " float w[2]; w[0] = a_w1.x; w[1] = a_w1.y;\n"); break;
|
||||
case 3: WRITE(p, " float w[3]; w[0] = a_w1.x; w[1] = a_w1.y; w[2] = a_w1.z;\n"); break;
|
||||
case 4: WRITE(p, " float w[4]; w[0] = a_w1.x; w[1] = a_w1.y; w[2] = a_w1.z; w[3] = a_w1.w;\n"); break;
|
||||
case 5: WRITE(p, " float w[5]; w[0] = a_w1.x; w[1] = a_w1.y; w[2] = a_w1.z; w[3] = a_w1.w; w[4] = a_w2;\n"); break;
|
||||
case 6: WRITE(p, " float w[6]; w[0] = a_w1.x; w[1] = a_w1.y; w[2] = a_w1.z; w[3] = a_w1.w; w[4] = a_w2.x; w[5] = a_w2.y;\n"); break;
|
||||
case 7: WRITE(p, " float w[7]; w[0] = a_w1.x; w[1] = a_w1.y; w[2] = a_w1.z; w[3] = a_w1.w; w[4] = a_w2.x; w[5] = a_w2.y; w[6] = a_w2.z;\n"); break;
|
||||
case 8: WRITE(p, " float w[8]; w[0] = a_w1.x; w[1] = a_w1.y; w[2] = a_w1.z; w[3] = a_w1.w; w[4] = a_w2.x; w[5] = a_w2.y; w[6] = a_w2.z; w[7] = a_w2.w;\n"); break;
|
||||
}
|
||||
|
||||
WRITE(p, " for (int i = 0; i < %i; i++) {\n", numWeights);
|
||||
WRITE(p, " worldpos += w[i] * (u_bone[i] * vec4(a_position.xyz, 1.0)).xyz;\n");
|
||||
if (hasNormal)
|
||||
WRITE(p, " worldnormal += w[i] * (u_bone[i] * vec4(a_normal, 0.0)).xyz;\n");
|
||||
WRITE(p, " }\n");
|
||||
|
||||
#else
|
||||
for (int i = 0; i < numWeights; i++) {
|
||||
const char *weightAttr = boneWeightAttr[i];
|
||||
// workaround for "cant do .x of scalar" issue
|
||||
if (numWeights == 1 && i == 0) weightAttr = "a_weight0123";
|
||||
if (numWeights == 5 && i == 4) weightAttr = "a_weight4567";
|
||||
WRITE(p, " worldpos += %s * (u_bone%i * vec4(a_position.xyz, 1.0)).xyz;\n", weightAttr, i);
|
||||
if (numWeights == 1 && i == 0) weightAttr = "a_w1";
|
||||
if (numWeights == 5 && i == 4) weightAttr = "a_w2";
|
||||
WRITE(p, " worldpos += %s * (u_bone[%i] * vec4(a_position.xyz, 1.0)).xyz;\n", weightAttr, i);
|
||||
if (hasNormal)
|
||||
WRITE(p, " worldnormal += %s * (u_bone%i * vec4(a_normal, 0.0)).xyz;\n", weightAttr, i);
|
||||
WRITE(p, " worldnormal += %s * (u_bone[%i] * vec4(a_normal, 0.0)).xyz;\n", weightAttr, i);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Finally, multiply by world matrix (yes, we have to).
|
||||
static const float rescale[4] = {0, 2*127.5f/128.f, 2*32767.5f/32768.f, 2.0f};
|
||||
float factor = rescale[(vertType & GE_VTYPE_WEIGHT_MASK) >> GE_VTYPE_WEIGHT_SHIFT];
|
||||
|
||||
// Finally, multiply by world matrix and compensate for quantization at the same time.
|
||||
WRITE(p, " worldpos = (u_world * vec4(worldpos * %f, 1.0)).xyz;\n", factor);
|
||||
if (hasNormal)
|
||||
WRITE(p, " worldnormal = (u_world * vec4(worldnormal, 0.0)).xyz;\n");
|
||||
|
Loading…
Reference in New Issue
Block a user