/** * Add parameter representing a vertex program attribute. * \param size size of attribute (in floats), may be -1 if unknown * \param attrib the attribute index, or -1 if unknown */ GLint _mesa_add_attribute(struct gl_program_parameter_list *paramList, const char *name, GLint size, GLint attrib) { GLint i = _mesa_lookup_parameter_index(paramList, -1, name); if (i >= 0) { /* replace */ if (attrib < 0) attrib = i; paramList->Parameters[i].StateIndexes[0] = attrib; } else { /* add */ gl_state_index state[STATE_LENGTH]; state[0] = (gl_state_index) attrib; if (size < 0) size = 4; i = _mesa_add_parameter(paramList, PROGRAM_INPUT, name, size, GL_NONE, NULL, state); } return i; }
int _mesa_get_sampler_uniform_value(class ir_dereference *sampler, struct gl_shader_program *shader_program, const struct gl_program *prog) { get_sampler_name getname(sampler, shader_program); sampler->accept(&getname); GLint index = _mesa_lookup_parameter_index(prog->Parameters, -1, getname.name); if (index < 0) { fail_link(shader_program, "failed to find sampler named %s.\n", getname.name); return 0; } index += getname.offset; return prog->Parameters->ParameterValues[index][0].f; }
/** * Linking varying vars involves rearranging varying vars so that the * vertex program's output varyings matches the order of the fragment * program's input varyings. * We'll then rewrite instructions to replace PROGRAM_VARYING with either * PROGRAM_INPUT or PROGRAM_OUTPUT depending on whether it's a vertex or * fragment shader. * This is also where we set program Input/OutputFlags to indicate * which inputs are centroid-sampled, invariant, etc. */ static GLboolean link_varying_vars(GLcontext *ctx, struct gl_shader_program *shProg, struct gl_program *prog) { GLuint *map, i, firstVarying, newFile; GLbitfield *inOutFlags; map = (GLuint *) malloc(prog->Varying->NumParameters * sizeof(GLuint)); if (!map) return GL_FALSE; /* Varying variables are treated like other vertex program outputs * (and like other fragment program inputs). The position of the * first varying differs for vertex/fragment programs... * Also, replace File=PROGRAM_VARYING with File=PROGRAM_INPUT/OUTPUT. */ if (prog->Target == GL_VERTEX_PROGRAM_ARB) { firstVarying = VERT_RESULT_VAR0; newFile = PROGRAM_OUTPUT; inOutFlags = prog->OutputFlags; } else { assert(prog->Target == GL_FRAGMENT_PROGRAM_ARB); firstVarying = FRAG_ATTRIB_VAR0; newFile = PROGRAM_INPUT; inOutFlags = prog->InputFlags; } for (i = 0; i < prog->Varying->NumParameters; i++) { /* see if this varying is in the linked varying list */ const struct gl_program_parameter *var = prog->Varying->Parameters + i; GLint j = _mesa_lookup_parameter_index(shProg->Varying, -1, var->Name); if (j >= 0) { /* varying is already in list, do some error checking */ const struct gl_program_parameter *v = &shProg->Varying->Parameters[j]; if (var->Size != v->Size) { link_error(shProg, "mismatched varying variable types"); free(map); return GL_FALSE; } if (!bits_agree(var->Flags, v->Flags, PROG_PARAM_BIT_CENTROID)) { char msg[100]; _mesa_snprintf(msg, sizeof(msg), "centroid modifier mismatch for '%s'", var->Name); link_error(shProg, msg); free(map); return GL_FALSE; } if (!bits_agree(var->Flags, v->Flags, PROG_PARAM_BIT_INVARIANT)) { char msg[100]; _mesa_snprintf(msg, sizeof(msg), "invariant modifier mismatch for '%s'", var->Name); link_error(shProg, msg); free(map); return GL_FALSE; } } else { /* not already in linked list */ j = _mesa_add_varying(shProg->Varying, var->Name, var->Size, var->Flags); } if (shProg->Varying->NumParameters > ctx->Const.MaxVarying) { link_error(shProg, "Too many varying variables"); free(map); return GL_FALSE; } /* Map varying[i] to varying[j]. * Note: the loop here takes care of arrays or large (sz>4) vars. */ { GLint sz = var->Size; while (sz > 0) { inOutFlags[firstVarying + j] = var->Flags; /*printf("Link varying from %d to %d\n", i, j);*/ map[i++] = j++; sz -= 4; } i--; /* go back one */ } } /* OK, now scan the program/shader instructions looking for varying vars, * replacing the old index with the new index. */ for (i = 0; i < prog->NumInstructions; i++) { struct prog_instruction *inst = prog->Instructions + i; GLuint j; if (inst->DstReg.File == PROGRAM_VARYING) { inst->DstReg.File = newFile; inst->DstReg.Index = map[ inst->DstReg.Index ] + firstVarying; } for (j = 0; j < 3; j++) { if (inst->SrcReg[j].File == PROGRAM_VARYING) { inst->SrcReg[j].File = newFile; inst->SrcReg[j].Index = map[ inst->SrcReg[j].Index ] + firstVarying; } } } free(map); /* these will get recomputed before linking is completed */ prog->InputsRead = 0x0; prog->OutputsWritten = 0x0; return GL_TRUE; }
/** * Resolve binding of generic vertex attributes. * For example, if the vertex shader declared "attribute vec4 foobar" we'll * allocate a generic vertex attribute for "foobar" and plug that value into * the vertex program instructions. * But if the user called glBindAttributeLocation(), those bindings will * have priority. */ static GLboolean _slang_resolve_attributes(struct gl_shader_program *shProg, const struct gl_program *origProg, struct gl_program *linkedProg) { GLint attribMap[MAX_VERTEX_GENERIC_ATTRIBS]; GLuint i, j; GLbitfield usedAttributes; /* generics only, not legacy attributes */ GLbitfield inputsRead = 0x0; assert(origProg != linkedProg); assert(origProg->Target == GL_VERTEX_PROGRAM_ARB); assert(linkedProg->Target == GL_VERTEX_PROGRAM_ARB); if (!shProg->Attributes) shProg->Attributes = _mesa_new_parameter_list(); if (linkedProg->Attributes) { _mesa_free_parameter_list(linkedProg->Attributes); } linkedProg->Attributes = _mesa_new_parameter_list(); /* Build a bitmask indicating which attribute indexes have been * explicitly bound by the user with glBindAttributeLocation(). */ usedAttributes = 0x0; for (i = 0; i < shProg->Attributes->NumParameters; i++) { GLint attr = shProg->Attributes->Parameters[i].StateIndexes[0]; usedAttributes |= (1 << attr); } /* If gl_Vertex is used, that actually counts against the limit * on generic vertex attributes. This avoids the ambiguity of * whether glVertexAttrib4fv(0, v) sets legacy attribute 0 (vert pos) * or generic attribute[0]. If gl_Vertex is used, we want the former. */ if (origProg->InputsRead & VERT_BIT_POS) { usedAttributes |= 0x1; } /* initialize the generic attribute map entries to -1 */ for (i = 0; i < MAX_VERTEX_GENERIC_ATTRIBS; i++) { attribMap[i] = -1; } /* * Scan program for generic attribute references */ for (i = 0; i < linkedProg->NumInstructions; i++) { struct prog_instruction *inst = linkedProg->Instructions + i; for (j = 0; j < 3; j++) { if (inst->SrcReg[j].File == PROGRAM_INPUT) { inputsRead |= (1 << inst->SrcReg[j].Index); } if (inst->SrcReg[j].File == PROGRAM_INPUT && inst->SrcReg[j].Index >= VERT_ATTRIB_GENERIC0) { /* * OK, we've found a generic vertex attribute reference. */ const GLint k = inst->SrcReg[j].Index - VERT_ATTRIB_GENERIC0; GLint attr = attribMap[k]; if (attr < 0) { /* Need to figure out attribute mapping now. */ const char *name = origProg->Attributes->Parameters[k].Name; const GLint size = origProg->Attributes->Parameters[k].Size; const GLenum type =origProg->Attributes->Parameters[k].DataType; GLint index; /* See if there's a user-defined attribute binding for * this name. */ index = _mesa_lookup_parameter_index(shProg->Attributes, -1, name); if (index >= 0) { /* Found a user-defined binding */ attr = shProg->Attributes->Parameters[index].StateIndexes[0]; } else { /* No user-defined binding, choose our own attribute number. * Start at 1 since generic attribute 0 always aliases * glVertex/position. */ for (attr = 0; attr < MAX_VERTEX_GENERIC_ATTRIBS; attr++) { if (((1 << attr) & usedAttributes) == 0) break; } if (attr == MAX_VERTEX_GENERIC_ATTRIBS) { link_error(shProg, "Too many vertex attributes"); return GL_FALSE; } /* mark this attribute as used */ usedAttributes |= (1 << attr); } attribMap[k] = attr; /* Save the final name->attrib binding so it can be queried * with glGetAttributeLocation(). */ _mesa_add_attribute(linkedProg->Attributes, name, size, type, attr); } assert(attr >= 0); /* update the instruction's src reg */ inst->SrcReg[j].Index = VERT_ATTRIB_GENERIC0 + attr; } } } /* Handle pre-defined attributes here (gl_Vertex, gl_Normal, etc). * When the user queries the active attributes we need to include both * the user-defined attributes and the built-in ones. */ for (i = VERT_ATTRIB_POS; i < VERT_ATTRIB_GENERIC0; i++) { if (inputsRead & (1 << i)) { _mesa_add_attribute(linkedProg->Attributes, _slang_vert_attrib_name(i), 4, /* size in floats */ _slang_vert_attrib_type(i), -1 /* attrib/input */); } } return GL_TRUE; }
/** * Parse a vector source (register, constant, etc): * <vectorSrc> ::= <absVectorSrc> * | <baseVectorSrc> * <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|" */ static GLboolean Parse_VectorSrc(struct parse_state *parseState, struct prog_src_register *srcReg) { GLfloat sign = 1.0F; GLubyte token[100]; GLint idx; GLuint negateBase, negateAbs; /* * First, take care of +/- and absolute value stuff. */ if (Parse_String(parseState, "-")) sign = -1.0F; else if (Parse_String(parseState, "+")) sign = +1.0F; if (Parse_String(parseState, "|")) { srcReg->Abs = GL_TRUE; negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE; if (Parse_String(parseState, "-")) negateBase = NEGATE_XYZW; else if (Parse_String(parseState, "+")) negateBase = NEGATE_NONE; else negateBase = NEGATE_NONE; } else { srcReg->Abs = GL_FALSE; negateAbs = NEGATE_NONE; negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE; } srcReg->Negate = srcReg->Abs ? negateAbs : negateBase; /* This should be the real src vector/register name */ if (!Peek_Token(parseState, token)) RETURN_ERROR; /* Src reg can be Rn, Hn, f[n], p[n], a named parameter, a scalar * literal or vector literal. */ if (token[0] == 'R' || token[0] == 'H') { srcReg->File = PROGRAM_TEMPORARY; if (!Parse_TempReg(parseState, &idx)) RETURN_ERROR; srcReg->Index = idx; } else if (token[0] == 'f') { /* XXX this might be an identifier! */ srcReg->File = PROGRAM_INPUT; if (!Parse_FragReg(parseState, &idx)) RETURN_ERROR; srcReg->Index = idx; } else if (token[0] == 'p') { /* XXX this might be an identifier! */ srcReg->File = PROGRAM_LOCAL_PARAM; if (!Parse_ProgramParamReg(parseState, &idx)) RETURN_ERROR; srcReg->Index = idx; } else if (IsLetter(token[0])){ GLubyte ident[100]; GLint paramIndex; if (!Parse_Identifier(parseState, ident)) RETURN_ERROR; paramIndex = _mesa_lookup_parameter_index(parseState->parameters, -1, (const char *) ident); if (paramIndex < 0) { RETURN_ERROR2("Undefined constant or parameter: ", ident); } srcReg->File = PROGRAM_NAMED_PARAM; srcReg->Index = paramIndex; } else if (IsDigit(token[0]) || token[0] == '-' || token[0] == '+' || token[0] == '.'){ /* literal scalar constant */ GLfloat values[4]; GLuint paramIndex; if (!Parse_ScalarConstant(parseState, values)) RETURN_ERROR; paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values, 4, NULL); srcReg->File = PROGRAM_NAMED_PARAM; srcReg->Index = paramIndex; } else if (token[0] == '{'){ /* literal vector constant */ GLfloat values[4]; GLuint paramIndex; (void) Parse_String(parseState, "{"); if (!Parse_VectorConstant(parseState, values)) RETURN_ERROR; paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values, 4, NULL); srcReg->File = PROGRAM_NAMED_PARAM; srcReg->Index = paramIndex; } else { RETURN_ERROR2("Invalid source register name", token); } /* init swizzle fields */ srcReg->Swizzle = SWIZZLE_NOOP; /* Look for optional swizzle suffix */ if (Parse_String(parseState, ".")) { GLuint swz[4]; if (!Parse_Token(parseState, token)) RETURN_ERROR; if (!Parse_SwizzleSuffix(token, swz)) RETURN_ERROR1("Invalid swizzle suffix"); srcReg->Swizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]); } /* Finish absolute value */ if (srcReg->Abs && !Parse_String(parseState, "|")) { RETURN_ERROR1("Expected |"); } return GL_TRUE; }
static GLboolean Parse_InstructionSequence(struct parse_state *parseState, struct prog_instruction program[]) { while (1) { struct prog_instruction *inst = program + parseState->numInst; struct instruction_pattern instMatch; GLubyte token[100]; /* Initialize the instruction */ _mesa_init_instructions(inst, 1); /* special instructions */ if (Parse_String(parseState, "DEFINE")) { GLubyte id[100]; GLfloat value[7]; /* yes, 7 to be safe */ if (!Parse_Identifier(parseState, id)) RETURN_ERROR; /* XXX make sure id is not a reserved identifer, like R9 */ if (!Parse_String(parseState, "=")) RETURN_ERROR1("Expected ="); if (!Parse_VectorOrScalarConstant(parseState, value)) RETURN_ERROR; if (!Parse_String(parseState, ";")) RETURN_ERROR1("Expected ;"); if (_mesa_lookup_parameter_index(parseState->parameters, -1, (const char *) id) >= 0) { RETURN_ERROR2(id, "already defined"); } _mesa_add_named_parameter(parseState->parameters, (const char *) id, value); } else if (Parse_String(parseState, "DECLARE")) { GLubyte id[100]; GLfloat value[7] = {0, 0, 0, 0, 0, 0, 0}; /* yes, to be safe */ if (!Parse_Identifier(parseState, id)) RETURN_ERROR; /* XXX make sure id is not a reserved identifer, like R9 */ if (Parse_String(parseState, "=")) { if (!Parse_VectorOrScalarConstant(parseState, value)) RETURN_ERROR; } if (!Parse_String(parseState, ";")) RETURN_ERROR1("Expected ;"); if (_mesa_lookup_parameter_index(parseState->parameters, -1, (const char *) id) >= 0) { RETURN_ERROR2(id, "already declared"); } _mesa_add_named_parameter(parseState->parameters, (const char *) id, value); } else if (Parse_String(parseState, "END")) { inst->Opcode = OPCODE_END; parseState->numInst++; if (Parse_Token(parseState, token)) { RETURN_ERROR1("Code after END opcode."); } break; } else { /* general/arithmetic instruction */ /* get token */ if (!Parse_Token(parseState, token)) { RETURN_ERROR1("Missing END instruction."); } /* try to find matching instuction */ instMatch = MatchInstruction(token); if (instMatch.opcode >= MAX_OPCODE) { /* bad instruction name */ RETURN_ERROR2("Unexpected token: ", token); } inst->Opcode = instMatch.opcode; inst->Precision = instMatch.suffixes & (_R | _H | _X); inst->SaturateMode = (instMatch.suffixes & (_S)) ? SATURATE_ZERO_ONE : SATURATE_OFF; inst->CondUpdate = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE; /* * parse the input and output operands */ if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) { if (!Parse_MaskedDstReg(parseState, &inst->DstReg)) RETURN_ERROR; if (!Parse_String(parseState, ",")) RETURN_ERROR1("Expected ,"); } else if (instMatch.outputs == OUTPUT_NONE) { if (instMatch.opcode == OPCODE_KIL_NV) { /* This is a little weird, the cond code info is in * the dest register. */ if (!Parse_CondCodeMask(parseState, &inst->DstReg)) RETURN_ERROR; } else { ASSERT(instMatch.opcode == OPCODE_PRINT); } } if (instMatch.inputs == INPUT_1V) { if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) RETURN_ERROR; } else if (instMatch.inputs == INPUT_2V) { if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) RETURN_ERROR; if (!Parse_String(parseState, ",")) RETURN_ERROR1("Expected ,"); if (!Parse_VectorSrc(parseState, &inst->SrcReg[1])) RETURN_ERROR; } else if (instMatch.inputs == INPUT_3V) { if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) RETURN_ERROR; if (!Parse_String(parseState, ",")) RETURN_ERROR1("Expected ,"); if (!Parse_VectorSrc(parseState, &inst->SrcReg[1])) RETURN_ERROR; if (!Parse_String(parseState, ",")) RETURN_ERROR1("Expected ,"); if (!Parse_VectorSrc(parseState, &inst->SrcReg[2])) RETURN_ERROR; } else if (instMatch.inputs == INPUT_1S) { if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0])) RETURN_ERROR; } else if (instMatch.inputs == INPUT_2S) { if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0])) RETURN_ERROR; if (!Parse_String(parseState, ",")) RETURN_ERROR1("Expected ,"); if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[1])) RETURN_ERROR; } else if (instMatch.inputs == INPUT_CC) { /* XXX to-do */ } else if (instMatch.inputs == INPUT_1V_T) { GLubyte unit, idx; if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) RETURN_ERROR; if (!Parse_String(parseState, ",")) RETURN_ERROR1("Expected ,"); if (!Parse_TextureImageId(parseState, &unit, &idx)) RETURN_ERROR; inst->TexSrcUnit = unit; inst->TexSrcTarget = idx; } else if (instMatch.inputs == INPUT_3V_T) { GLubyte unit, idx; if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) RETURN_ERROR; if (!Parse_String(parseState, ",")) RETURN_ERROR1("Expected ,"); if (!Parse_VectorSrc(parseState, &inst->SrcReg[1])) RETURN_ERROR; if (!Parse_String(parseState, ",")) RETURN_ERROR1("Expected ,"); if (!Parse_VectorSrc(parseState, &inst->SrcReg[2])) RETURN_ERROR; if (!Parse_String(parseState, ",")) RETURN_ERROR1("Expected ,"); if (!Parse_TextureImageId(parseState, &unit, &idx)) RETURN_ERROR; inst->TexSrcUnit = unit; inst->TexSrcTarget = idx; } else if (instMatch.inputs == INPUT_1V_S) { if (!Parse_PrintInstruction(parseState, inst)) RETURN_ERROR; } /* end of statement semicolon */ if (!Parse_String(parseState, ";")) RETURN_ERROR1("Expected ;"); parseState->numInst++; if (parseState->numInst >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS) RETURN_ERROR1("Program too long"); } } return GL_TRUE; }
static GLboolean Parse_ScalarSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg) { GLubyte token[100]; GLfloat sign = 1.0F; GLboolean needSuffix = GL_TRUE; GLint idx; GLuint negateBase, negateAbs; /* * First, take care of +/- and absolute value stuff. */ if (Parse_String(parseState, "-")) sign = -1.0F; else if (Parse_String(parseState, "+")) sign = +1.0F; if (Parse_String(parseState, "|")) { srcReg->Abs = GL_TRUE; negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE; if (Parse_String(parseState, "-")) negateBase = NEGATE_XYZW; else if (Parse_String(parseState, "+")) negateBase = NEGATE_NONE; else negateBase = NEGATE_NONE; } else { srcReg->Abs = GL_FALSE; negateAbs = NEGATE_NONE; negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE; } srcReg->Negate = srcReg->Abs ? negateAbs : negateBase; if (!Peek_Token(parseState, token)) RETURN_ERROR; /* Src reg can be R<n>, H<n> or a named fragment attrib */ if (token[0] == 'R' || token[0] == 'H') { srcReg->File = PROGRAM_TEMPORARY; if (!Parse_TempReg(parseState, &idx)) RETURN_ERROR; srcReg->Index = idx; } else if (token[0] == 'f') { srcReg->File = PROGRAM_INPUT; if (!Parse_FragReg(parseState, &idx)) RETURN_ERROR; srcReg->Index = idx; } else if (token[0] == '{') { /* vector literal */ GLfloat values[4]; GLuint paramIndex; (void) Parse_String(parseState, "{"); if (!Parse_VectorConstant(parseState, values)) RETURN_ERROR; paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values, 4, NULL); srcReg->File = PROGRAM_NAMED_PARAM; srcReg->Index = paramIndex; } else if (IsLetter(token[0])){ /* named param/constant */ GLubyte ident[100]; GLint paramIndex; if (!Parse_Identifier(parseState, ident)) RETURN_ERROR; paramIndex = _mesa_lookup_parameter_index(parseState->parameters, -1, (const char *) ident); if (paramIndex < 0) { RETURN_ERROR2("Undefined constant or parameter: ", ident); } srcReg->File = PROGRAM_NAMED_PARAM; srcReg->Index = paramIndex; } else if (IsDigit(token[0])) { /* scalar literal */ GLfloat values[4]; GLuint paramIndex; if (!Parse_ScalarConstant(parseState, values)) RETURN_ERROR; paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values, 4, NULL); srcReg->Index = paramIndex; srcReg->File = PROGRAM_NAMED_PARAM; needSuffix = GL_FALSE; } else { RETURN_ERROR2("Invalid scalar source argument", token); } srcReg->Swizzle = 0; if (needSuffix) { /* parse .[xyzw] suffix */ if (!Parse_String(parseState, ".")) RETURN_ERROR1("Expected ."); if (!Parse_Token(parseState, token)) RETURN_ERROR; if (token[0] == 'x' && token[1] == 0) { srcReg->Swizzle = 0; } else if (token[0] == 'y' && token[1] == 0) { srcReg->Swizzle = 1; } else if (token[0] == 'z' && token[1] == 0) { srcReg->Swizzle = 2; } else if (token[0] == 'w' && token[1] == 0) { srcReg->Swizzle = 3; } else { RETURN_ERROR1("Invalid scalar source suffix"); } } /* Finish absolute value */ if (srcReg->Abs && !Parse_String(parseState, "|")) { RETURN_ERROR1("Expected |"); } return GL_TRUE; }