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);
#endif
shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &code, 0);
glShaderSource(shader, 1, &code, 0);
glCompileShader(shader);
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
@ -73,13 +73,35 @@ Shader::~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)
: useHWTransform_(useHWTransform), program(0), dirtyUniforms(0) {
program = glCreateProgram();
glAttachShader(program, vs->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);
glDetachShader(program, vs->shader);
glDetachShader(program, fs->shader);
GLint linkStatus = GL_FALSE;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if (linkStatus != GL_TRUE) {
@ -162,13 +184,16 @@ LinkedShader::LinkedShader(Shader *vs, Shader *fs, u32 vertType, bool useHWTrans
u_lightspecular[i] = glGetUniformLocation(program, temp);
}
a_position = glGetAttribLocation(program, "a_position");
a_color0 = glGetAttribLocation(program, "a_color0");
a_color1 = glGetAttribLocation(program, "a_color1");
a_texcoord = glGetAttribLocation(program, "a_texcoord");
a_normal = glGetAttribLocation(program, "a_normal");
a_weight0123 = glGetAttribLocation(program, "a_w1");
a_weight4567 = glGetAttribLocation(program, "a_w2");
attrMask = 0;
if (-1 != glGetAttribLocationL(program, "a_position")) attrMask |= 1 << ATTR_POSITION;
if (-1 != glGetAttribLocationL(program, "a_texcoord")) attrMask |= 1 << ATTR_TEXCOORD;
if (-1 != glGetAttribLocationL(program, "a_normal")) attrMask |= 1 << ATTR_NORMAL;
if (-1 != glGetAttribLocationL(program, "a_w1")) attrMask |= 1 << ATTR_W1;
if (-1 != glGetAttribLocationL(program, "a_w2")) attrMask |= 1 << ATTR_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);
@ -262,23 +287,19 @@ static void SetMatrix4x3(int uniform, const float *m4x3) {
void LinkedShader::use(u32 vertType) {
glUseProgram(program);
updateUniforms(vertType);
glEnableVertexAttribArray(a_position);
if (a_texcoord != -1) glEnableVertexAttribArray(a_texcoord);
if (a_color0 != -1) glEnableVertexAttribArray(a_color0);
if (a_color1 != -1) glEnableVertexAttribArray(a_color1);
if (a_normal != -1) glEnableVertexAttribArray(a_normal);
if (a_weight0123 != -1) glEnableVertexAttribArray(a_weight0123);
if (a_weight4567 != -1) glEnableVertexAttribArray(a_weight4567);
glEnableVertexAttribArray(0);
for (int i = 1; i < ATTR_COUNT; i++) {
if (attrMask & (1 << i))
glEnableVertexAttribArray(i);
}
}
void LinkedShader::stop() {
glDisableVertexAttribArray(a_position);
if (a_texcoord != -1) glDisableVertexAttribArray(a_texcoord);
if (a_color0 != -1) glDisableVertexAttribArray(a_color0);
if (a_color1 != -1) glDisableVertexAttribArray(a_color1);
if (a_normal != -1) glDisableVertexAttribArray(a_normal);
if (a_weight0123 != -1) glDisableVertexAttribArray(a_weight0123);
if (a_weight4567 != -1) glDisableVertexAttribArray(a_weight4567);
glDisableVertexAttribArray(0);
for (int i = 1; i < ATTR_COUNT; i++) {
if (attrMask & (1 << i))
glDisableVertexAttribArray(i);
}
}
void LinkedShader::updateUniforms(u32 vertType) {
@ -331,10 +352,10 @@ void LinkedShader::updateUniforms(u32 vertType) {
if (gstate.isModeThrough()) {
// We never get here because we don't use HW transform with through mode.
// Although - why don't we?
uvscaleoff[0] = gstate_c.uv.uScale / gstate_c.curTextureWidth;
uvscaleoff[1] = gstate_c.uv.vScale / gstate_c.curTextureHeight;
uvscaleoff[2] = gstate_c.uv.uOff / gstate_c.curTextureWidth;
uvscaleoff[3] = gstate_c.uv.vOff / gstate_c.curTextureHeight;
uvscaleoff[0] = gstate_c.uv.uScale / (float)gstate_c.curTextureWidth;
uvscaleoff[1] = gstate_c.uv.vScale / (float)gstate_c.curTextureHeight;
uvscaleoff[2] = gstate_c.uv.uOff / (float)gstate_c.curTextureWidth;
uvscaleoff[3] = gstate_c.uv.vOff / (float)gstate_c.curTextureHeight;
glUniform4fv(u_uvscaleoffset, 1, uvscaleoff);
} else {
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.
#ifdef USE_BONE_ARRAY
if (u_bone != -1) {
float allBones[8 * 16];

View File

@ -25,8 +25,20 @@
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:
LinkedShader(Shader *vs, Shader *fs, u32 vertType, bool useHWTransform);
~LinkedShader();
@ -41,14 +53,8 @@ public:
uint32_t program;
u32 dirtyUniforms;
// Pre-fetched attrs and uniforms
int a_position;
int a_color0;
int a_color1;
int a_texcoord;
int a_normal;
int a_weight0123;
int a_weight4567;
// Present attributes in the shader.
int attrMask; // 1 << ATTR_ ... or-ed together.
int u_tex;
int u_proj;
@ -63,7 +69,7 @@ public:
int u_bone[8];
#endif
int numBones;
// Fragment processing inputs
int u_alphacolorref;
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
static void SetupDecFmtForDraw(LinkedShader *program, const DecVtxFormat &decFmt, u8 *vertexData) {
VertexAttribSetup(program->a_weight0123, decFmt.w0fmt, decFmt.stride, vertexData + decFmt.w0off);
VertexAttribSetup(program->a_weight4567, decFmt.w1fmt, decFmt.stride, vertexData + decFmt.w1off);
VertexAttribSetup(program->a_texcoord, decFmt.uvfmt, decFmt.stride, vertexData + decFmt.uvoff);
VertexAttribSetup(program->a_color0, decFmt.c0fmt, decFmt.stride, vertexData + decFmt.c0off);
VertexAttribSetup(program->a_color1, decFmt.c1fmt, decFmt.stride, vertexData + decFmt.c1off);
VertexAttribSetup(program->a_normal, decFmt.nrmfmt, decFmt.stride, vertexData + decFmt.nrmoff);
VertexAttribSetup(program->a_position, decFmt.posfmt, decFmt.stride, vertexData + decFmt.posoff);
VertexAttribSetup(ATTR_W1, decFmt.w0fmt, decFmt.stride, vertexData + decFmt.w0off);
VertexAttribSetup(ATTR_W2, decFmt.w1fmt, decFmt.stride, vertexData + decFmt.w1off);
VertexAttribSetup(ATTR_TEXCOORD, decFmt.uvfmt, decFmt.stride, vertexData + decFmt.uvoff);
VertexAttribSetup(ATTR_COLOR0, decFmt.c0fmt, decFmt.stride, vertexData + decFmt.c0off);
VertexAttribSetup(ATTR_COLOR1, decFmt.c1fmt, decFmt.stride, vertexData + decFmt.c1off);
VertexAttribSetup(ATTR_NORMAL, decFmt.nrmfmt, decFmt.stride, vertexData + decFmt.nrmoff);
VertexAttribSetup(ATTR_POSITION, decFmt.posfmt, decFmt.stride, vertexData + decFmt.posoff);
}
// 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]);
}
// Clears on the PSP are best done by drawing a series of vertical strips
// in clear mode. This tries to detect that.
bool TransformDrawEngine::IsReallyAClear(int numVerts) const {
@ -395,7 +394,7 @@ bool TransformDrawEngine::IsReallyAClear(int numVerts) const {
memcpy(&vcolor, transformed[i].color0, 4);
if (vcolor != matchcolor || transformed[i].z != matchz)
return false;
if ((i & 1) == 0) {
// Top left of a rectangle
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[2] = 1.0f;
break;
case GE_TEXMAP_TEXTURE_MATRIX:
{
// Projection mapping
@ -607,11 +606,11 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
case GE_PROJMAP_POSITION: // Use model space XYZ as source
source = pos;
break;
case GE_PROJMAP_UV: // Use unscaled UV as source
source = Vec3f(ruv[0], ruv[1], 0.0f);
break;
case GE_PROJMAP_NORMALIZED_NORMAL: // Use normalized normal as source
if (reader.hasNormal()) {
source = Vec3f(norm).Normalized();
@ -620,7 +619,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
source = Vec3f(0.0f, 0.0f, 1.0f);
}
break;
case GE_PROJMAP_NORMAL: // Use non-normalized normal as source!
if (reader.hasNormal()) {
source = Vec3f(norm);
@ -638,7 +637,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
uv[2] = uvw[2];
}
break;
case GE_TEXMAP_ENVIRONMENT_MAP:
// Shade mapping - use two light sources to generate U and V.
{
@ -650,15 +649,16 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
uv[2] = 1.0f;
}
break;
default:
// Illegal
ERROR_LOG_REPORT(G3D, "Impossible UV gen mode? %d", gstate.getUVGenMode());
break;
}
uv[0] = uv[0] * widthFactor;
uv[1] = uv[1] * heightFactor;
// Transform the coord by the view matrix.
Vec3ByMatrix43(v, out, gstate.viewMatrix);
fogCoef = (v[2] + fog_end) * fog_slope;
@ -765,6 +765,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
// 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.
// 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
// RotateUV(trans);
@ -779,19 +780,19 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
}
}
// TODO: Add a post-transform cache here for multi-RECTANGLES only.
// Might help for text drawing.
// these spam the gDebugger log.
const int vertexSize = sizeof(transformed[0]);
bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX;
glBindBuffer(GL_ARRAY_BUFFER, 0);
glVertexAttribPointer(program->a_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);
if (program->a_color0 != -1) glVertexAttribPointer(program->a_color0, 4, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, ((uint8_t*)drawBuffer) + 7 * 4);
if (program->a_color1 != -1) glVertexAttribPointer(program->a_color1, 3, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, ((uint8_t*)drawBuffer) + 8 * 4);
glVertexAttribPointer(ATTR_POSITION, 4, GL_FLOAT, GL_FALSE, vertexSize, drawBuffer);
int attrMask = program->attrMask;
if (attrMask & (1 << ATTR_TEXCOORD)) glVertexAttribPointer(ATTR_TEXCOORD, doTextureProjection ? 3 : 2, GL_FLOAT, GL_FALSE, vertexSize, ((uint8_t*)drawBuffer) + 4 * 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) {
//#ifdef USING_GLES2
glDrawElements(glprim[prim], numTrans, GL_UNSIGNED_SHORT, inds);