Use glBindAttribLocation to simplify shader usage a little.

This commit is contained in:
Henrik Rydgård 2013-10-08 17:18:59 +02:00
parent df29da0b13
commit 0ecac31abd
3 changed files with 87 additions and 60 deletions

View File

@ -44,7 +44,7 @@ Shader::Shader(const char *code, uint32_t shaderType, bool useHWTransform) : fai
OutputDebugStringUTF8(code); OutputDebugStringUTF8(code);
#endif #endif
shader = glCreateShader(shaderType); shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &code, 0); glShaderSource(shader, 1, &code, 0);
glCompileShader(shader); glCompileShader(shader);
GLint success; GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success); glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
@ -73,13 +73,35 @@ Shader::~Shader() {
glDeleteShader(shader); glDeleteShader(shader);
} }
static int glGetAttribLocationL(int program, const char *name) {
int attrLoc = glGetAttribLocation(program, name);
ERROR_LOG(HLE, "Attr Loc: %i %i %s", program, attrLoc, name);
return attrLoc;
}
LinkedShader::LinkedShader(Shader *vs, Shader *fs, u32 vertType, bool useHWTransform) LinkedShader::LinkedShader(Shader *vs, Shader *fs, u32 vertType, bool useHWTransform)
: useHWTransform_(useHWTransform), program(0), dirtyUniforms(0) { : useHWTransform_(useHWTransform), program(0), dirtyUniforms(0) {
program = glCreateProgram(); program = glCreateProgram();
glAttachShader(program, vs->shader); glAttachShader(program, vs->shader);
glAttachShader(program, fs->shader); glAttachShader(program, fs->shader);
// Bind attribute locations to fixed locations so that they're
// the same in all shaders. We can use this later to minimize the calls to
// glEnableVertexAttribArray and glDisableVertexAttribArray.
glBindAttribLocation(program, ATTR_POSITION, "a_position");
glBindAttribLocation(program, ATTR_TEXCOORD, "a_texcoord");
glBindAttribLocation(program, ATTR_NORMAL, "a_normal");
glBindAttribLocation(program, ATTR_W1, "a_w1");
glBindAttribLocation(program, ATTR_W2, "a_w2");
glBindAttribLocation(program, ATTR_COLOR0, "a_color0");
glBindAttribLocation(program, ATTR_COLOR1, "a_color1");
glLinkProgram(program); glLinkProgram(program);
glDetachShader(program, vs->shader);
glDetachShader(program, fs->shader);
GLint linkStatus = GL_FALSE; GLint linkStatus = GL_FALSE;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if (linkStatus != GL_TRUE) { if (linkStatus != GL_TRUE) {
@ -162,13 +184,16 @@ LinkedShader::LinkedShader(Shader *vs, Shader *fs, u32 vertType, bool useHWTrans
u_lightspecular[i] = glGetUniformLocation(program, temp); u_lightspecular[i] = glGetUniformLocation(program, temp);
} }
a_position = glGetAttribLocation(program, "a_position"); attrMask = 0;
a_color0 = glGetAttribLocation(program, "a_color0"); if (-1 != glGetAttribLocationL(program, "a_position")) attrMask |= 1 << ATTR_POSITION;
a_color1 = glGetAttribLocation(program, "a_color1"); if (-1 != glGetAttribLocationL(program, "a_texcoord")) attrMask |= 1 << ATTR_TEXCOORD;
a_texcoord = glGetAttribLocation(program, "a_texcoord"); if (-1 != glGetAttribLocationL(program, "a_normal")) attrMask |= 1 << ATTR_NORMAL;
a_normal = glGetAttribLocation(program, "a_normal"); if (-1 != glGetAttribLocationL(program, "a_w1")) attrMask |= 1 << ATTR_W1;
a_weight0123 = glGetAttribLocation(program, "a_w1"); if (-1 != glGetAttribLocationL(program, "a_w2")) attrMask |= 1 << ATTR_W2;
a_weight4567 = glGetAttribLocation(program, "a_w2"); if (-1 != glGetAttribLocationL(program, "a_color0")) attrMask |= 1 << ATTR_COLOR0;
if (-1 != glGetAttribLocationL(program, "a_color1")) attrMask |= 1 << ATTR_COLOR1;
ELOG("AttrMask: %02x", attrMask);
glUseProgram(program); glUseProgram(program);
@ -262,23 +287,19 @@ static void SetMatrix4x3(int uniform, const float *m4x3) {
void LinkedShader::use(u32 vertType) { void LinkedShader::use(u32 vertType) {
glUseProgram(program); glUseProgram(program);
updateUniforms(vertType); updateUniforms(vertType);
glEnableVertexAttribArray(a_position); glEnableVertexAttribArray(0);
if (a_texcoord != -1) glEnableVertexAttribArray(a_texcoord); for (int i = 1; i < ATTR_COUNT; i++) {
if (a_color0 != -1) glEnableVertexAttribArray(a_color0); if (attrMask & (1 << i))
if (a_color1 != -1) glEnableVertexAttribArray(a_color1); glEnableVertexAttribArray(i);
if (a_normal != -1) glEnableVertexAttribArray(a_normal); }
if (a_weight0123 != -1) glEnableVertexAttribArray(a_weight0123);
if (a_weight4567 != -1) glEnableVertexAttribArray(a_weight4567);
} }
void LinkedShader::stop() { void LinkedShader::stop() {
glDisableVertexAttribArray(a_position); glDisableVertexAttribArray(0);
if (a_texcoord != -1) glDisableVertexAttribArray(a_texcoord); for (int i = 1; i < ATTR_COUNT; i++) {
if (a_color0 != -1) glDisableVertexAttribArray(a_color0); if (attrMask & (1 << i))
if (a_color1 != -1) glDisableVertexAttribArray(a_color1); glDisableVertexAttribArray(i);
if (a_normal != -1) glDisableVertexAttribArray(a_normal); }
if (a_weight0123 != -1) glDisableVertexAttribArray(a_weight0123);
if (a_weight4567 != -1) glDisableVertexAttribArray(a_weight4567);
} }
void LinkedShader::updateUniforms(u32 vertType) { void LinkedShader::updateUniforms(u32 vertType) {
@ -331,10 +352,10 @@ void LinkedShader::updateUniforms(u32 vertType) {
if (gstate.isModeThrough()) { if (gstate.isModeThrough()) {
// We never get here because we don't use HW transform with through mode. // We never get here because we don't use HW transform with through mode.
// Although - why don't we? // Although - why don't we?
uvscaleoff[0] = gstate_c.uv.uScale / gstate_c.curTextureWidth; uvscaleoff[0] = gstate_c.uv.uScale / (float)gstate_c.curTextureWidth;
uvscaleoff[1] = gstate_c.uv.vScale / gstate_c.curTextureHeight; uvscaleoff[1] = gstate_c.uv.vScale / (float)gstate_c.curTextureHeight;
uvscaleoff[2] = gstate_c.uv.uOff / gstate_c.curTextureWidth; uvscaleoff[2] = gstate_c.uv.uOff / (float)gstate_c.curTextureWidth;
uvscaleoff[3] = gstate_c.uv.vOff / gstate_c.curTextureHeight; uvscaleoff[3] = gstate_c.uv.vOff / (float)gstate_c.curTextureHeight;
glUniform4fv(u_uvscaleoffset, 1, uvscaleoff); glUniform4fv(u_uvscaleoffset, 1, uvscaleoff);
} else { } else {
int w = gstate.getTextureWidth(0); int w = gstate.getTextureWidth(0);
@ -372,7 +393,6 @@ void LinkedShader::updateUniforms(u32 vertType) {
// TODO: Could even set all bones in one go if they're all dirty. // TODO: Could even set all bones in one go if they're all dirty.
#ifdef USE_BONE_ARRAY #ifdef USE_BONE_ARRAY
if (u_bone != -1) { if (u_bone != -1) {
float allBones[8 * 16]; float allBones[8 * 16];

View File

@ -25,8 +25,20 @@
class Shader; class Shader;
class LinkedShader // Pre-fetched attrs and uniforms
{ enum {
ATTR_POSITION = 0,
ATTR_TEXCOORD = 1,
ATTR_NORMAL = 2,
ATTR_W1 = 3,
ATTR_W2 = 4,
ATTR_COLOR0 = 5,
ATTR_COLOR1 = 6,
ATTR_COUNT,
};
class LinkedShader {
public: public:
LinkedShader(Shader *vs, Shader *fs, u32 vertType, bool useHWTransform); LinkedShader(Shader *vs, Shader *fs, u32 vertType, bool useHWTransform);
~LinkedShader(); ~LinkedShader();
@ -41,14 +53,8 @@ public:
uint32_t program; uint32_t program;
u32 dirtyUniforms; u32 dirtyUniforms;
// Pre-fetched attrs and uniforms // Present attributes in the shader.
int a_position; int attrMask; // 1 << ATTR_ ... or-ed together.
int a_color0;
int a_color1;
int a_texcoord;
int a_normal;
int a_weight0123;
int a_weight4567;
int u_tex; int u_tex;
int u_proj; int u_proj;
@ -63,7 +69,7 @@ public:
int u_bone[8]; int u_bone[8];
#endif #endif
int numBones; int numBones;
// Fragment processing inputs // Fragment processing inputs
int u_alphacolorref; int u_alphacolorref;
int u_colormask; int u_colormask;

View File

@ -329,13 +329,13 @@ static inline void VertexAttribSetup(int attrib, int fmt, int stride, u8 *ptr) {
// TODO: Use VBO and get rid of the vertexData pointers - with that, we will supply only offsets // TODO: Use VBO and get rid of the vertexData pointers - with that, we will supply only offsets
static void SetupDecFmtForDraw(LinkedShader *program, const DecVtxFormat &decFmt, u8 *vertexData) { static void SetupDecFmtForDraw(LinkedShader *program, const DecVtxFormat &decFmt, u8 *vertexData) {
VertexAttribSetup(program->a_weight0123, decFmt.w0fmt, decFmt.stride, vertexData + decFmt.w0off); VertexAttribSetup(ATTR_W1, decFmt.w0fmt, decFmt.stride, vertexData + decFmt.w0off);
VertexAttribSetup(program->a_weight4567, decFmt.w1fmt, decFmt.stride, vertexData + decFmt.w1off); VertexAttribSetup(ATTR_W2, decFmt.w1fmt, decFmt.stride, vertexData + decFmt.w1off);
VertexAttribSetup(program->a_texcoord, decFmt.uvfmt, decFmt.stride, vertexData + decFmt.uvoff); VertexAttribSetup(ATTR_TEXCOORD, decFmt.uvfmt, decFmt.stride, vertexData + decFmt.uvoff);
VertexAttribSetup(program->a_color0, decFmt.c0fmt, decFmt.stride, vertexData + decFmt.c0off); VertexAttribSetup(ATTR_COLOR0, decFmt.c0fmt, decFmt.stride, vertexData + decFmt.c0off);
VertexAttribSetup(program->a_color1, decFmt.c1fmt, decFmt.stride, vertexData + decFmt.c1off); VertexAttribSetup(ATTR_COLOR1, decFmt.c1fmt, decFmt.stride, vertexData + decFmt.c1off);
VertexAttribSetup(program->a_normal, decFmt.nrmfmt, decFmt.stride, vertexData + decFmt.nrmoff); VertexAttribSetup(ATTR_NORMAL, decFmt.nrmfmt, decFmt.stride, vertexData + decFmt.nrmoff);
VertexAttribSetup(program->a_position, decFmt.posfmt, decFmt.stride, vertexData + decFmt.posoff); VertexAttribSetup(ATTR_POSITION, decFmt.posfmt, decFmt.stride, vertexData + decFmt.posoff);
} }
// The verts are in the order: BR BL TL TR // The verts are in the order: BR BL TL TR
@ -375,7 +375,6 @@ static void RotateUVThrough(TransformedVertex v[4]) {
SwapUVs(v[1], v[3]); SwapUVs(v[1], v[3]);
} }
// Clears on the PSP are best done by drawing a series of vertical strips // Clears on the PSP are best done by drawing a series of vertical strips
// in clear mode. This tries to detect that. // in clear mode. This tries to detect that.
bool TransformDrawEngine::IsReallyAClear(int numVerts) const { bool TransformDrawEngine::IsReallyAClear(int numVerts) const {
@ -395,7 +394,7 @@ bool TransformDrawEngine::IsReallyAClear(int numVerts) const {
memcpy(&vcolor, transformed[i].color0, 4); memcpy(&vcolor, transformed[i].color0, 4);
if (vcolor != matchcolor || transformed[i].z != matchz) if (vcolor != matchcolor || transformed[i].z != matchz)
return false; return false;
if ((i & 1) == 0) { if ((i & 1) == 0) {
// Top left of a rectangle // Top left of a rectangle
if (transformed[i].y != 0) if (transformed[i].y != 0)
@ -598,7 +597,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
uv[1] = vscale * (ruv[1]*gstate_c.uv.vScale + gstate_c.uv.vOff); uv[1] = vscale * (ruv[1]*gstate_c.uv.vScale + gstate_c.uv.vOff);
uv[2] = 1.0f; uv[2] = 1.0f;
break; break;
case GE_TEXMAP_TEXTURE_MATRIX: case GE_TEXMAP_TEXTURE_MATRIX:
{ {
// Projection mapping // Projection mapping
@ -607,11 +606,11 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
case GE_PROJMAP_POSITION: // Use model space XYZ as source case GE_PROJMAP_POSITION: // Use model space XYZ as source
source = pos; source = pos;
break; break;
case GE_PROJMAP_UV: // Use unscaled UV as source case GE_PROJMAP_UV: // Use unscaled UV as source
source = Vec3f(ruv[0], ruv[1], 0.0f); source = Vec3f(ruv[0], ruv[1], 0.0f);
break; break;
case GE_PROJMAP_NORMALIZED_NORMAL: // Use normalized normal as source case GE_PROJMAP_NORMALIZED_NORMAL: // Use normalized normal as source
if (reader.hasNormal()) { if (reader.hasNormal()) {
source = Vec3f(norm).Normalized(); source = Vec3f(norm).Normalized();
@ -620,7 +619,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
source = Vec3f(0.0f, 0.0f, 1.0f); source = Vec3f(0.0f, 0.0f, 1.0f);
} }
break; break;
case GE_PROJMAP_NORMAL: // Use non-normalized normal as source! case GE_PROJMAP_NORMAL: // Use non-normalized normal as source!
if (reader.hasNormal()) { if (reader.hasNormal()) {
source = Vec3f(norm); source = Vec3f(norm);
@ -638,7 +637,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
uv[2] = uvw[2]; uv[2] = uvw[2];
} }
break; break;
case GE_TEXMAP_ENVIRONMENT_MAP: case GE_TEXMAP_ENVIRONMENT_MAP:
// Shade mapping - use two light sources to generate U and V. // Shade mapping - use two light sources to generate U and V.
{ {
@ -650,15 +649,16 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
uv[2] = 1.0f; uv[2] = 1.0f;
} }
break; break;
default: default:
// Illegal // Illegal
ERROR_LOG_REPORT(G3D, "Impossible UV gen mode? %d", gstate.getUVGenMode()); ERROR_LOG_REPORT(G3D, "Impossible UV gen mode? %d", gstate.getUVGenMode());
break; break;
} }
uv[0] = uv[0] * widthFactor; uv[0] = uv[0] * widthFactor;
uv[1] = uv[1] * heightFactor; uv[1] = uv[1] * heightFactor;
// Transform the coord by the view matrix. // Transform the coord by the view matrix.
Vec3ByMatrix43(v, out, gstate.viewMatrix); Vec3ByMatrix43(v, out, gstate.viewMatrix);
fogCoef = (v[2] + fog_end) * fog_slope; fogCoef = (v[2] + fog_end) * fog_slope;
@ -765,6 +765,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
// Apparently, non-through RotateUV just breaks things. // Apparently, non-through RotateUV just breaks things.
// If we find a game where it helps, we'll just have to figure out how they differ. // If we find a game where it helps, we'll just have to figure out how they differ.
// Possibly, it has something to do with flipped viewport Y axis, which a few games use. // Possibly, it has something to do with flipped viewport Y axis, which a few games use.
// One game might be one of the Metal Gear ones, can't find the issue right now though.
// else // else
// RotateUV(trans); // RotateUV(trans);
@ -779,19 +780,19 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
} }
} }
// TODO: Add a post-transform cache here for multi-RECTANGLES only. // TODO: Add a post-transform cache here for multi-RECTANGLES only.
// Might help for text drawing. // Might help for text drawing.
// these spam the gDebugger log. // these spam the gDebugger log.
const int vertexSize = sizeof(transformed[0]); const int vertexSize = sizeof(transformed[0]);
bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX; bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX;
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
glVertexAttribPointer(program->a_position, 4, GL_FLOAT, GL_FALSE, vertexSize, drawBuffer); glVertexAttribPointer(ATTR_POSITION, 4, GL_FLOAT, GL_FALSE, vertexSize, drawBuffer);
if (program->a_texcoord != -1) glVertexAttribPointer(program->a_texcoord, doTextureProjection ? 3 : 2, GL_FLOAT, GL_FALSE, vertexSize, ((uint8_t*)drawBuffer) + 4 * 4); int attrMask = program->attrMask;
if (program->a_color0 != -1) glVertexAttribPointer(program->a_color0, 4, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, ((uint8_t*)drawBuffer) + 7 * 4); if (attrMask & (1 << ATTR_TEXCOORD)) glVertexAttribPointer(ATTR_TEXCOORD, doTextureProjection ? 3 : 2, GL_FLOAT, GL_FALSE, vertexSize, ((uint8_t*)drawBuffer) + 4 * 4);
if (program->a_color1 != -1) glVertexAttribPointer(program->a_color1, 3, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, ((uint8_t*)drawBuffer) + 8 * 4); if (attrMask & (1 << ATTR_COLOR0)) glVertexAttribPointer(ATTR_COLOR0, 4, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, ((uint8_t*)drawBuffer) + 7 * 4);
if (attrMask & (1 << ATTR_COLOR1)) glVertexAttribPointer(ATTR_COLOR1, 3, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, ((uint8_t*)drawBuffer) + 8 * 4);
if (drawIndexed) { if (drawIndexed) {
//#ifdef USING_GLES2 //#ifdef USING_GLES2
glDrawElements(glprim[prim], numTrans, GL_UNSIGNED_SHORT, inds); glDrawElements(glprim[prim], numTrans, GL_UNSIGNED_SHORT, inds);