📄 nvvertparse.c
字号:
srcReg->RelAddr = GL_FALSE;
srcReg->Negate = GL_FALSE;
srcReg->Swizzle = SWIZZLE_NOOP;
/* Register can be R<n>, c[n], c[n +/- offset], a named vertex attrib,
* or an o[n] output register.
*/
if (token[0] == 'R') {
srcReg->File = PROGRAM_TEMPORARY;
if (!Parse_TempReg(parseState, &idx))
RETURN_ERROR;
srcReg->Index = idx;
}
else if (token[0] == 'c') {
srcReg->File = PROGRAM_ENV_PARAM;
if (!Parse_ParamReg(parseState, srcReg))
RETURN_ERROR;
}
else if (token[0] == 'v') {
srcReg->File = PROGRAM_INPUT;
if (!Parse_AttribReg(parseState, &idx))
RETURN_ERROR;
srcReg->Index = idx;
}
else if (token[0] == 'o') {
srcReg->File = PROGRAM_OUTPUT;
if (!Parse_OutputReg(parseState, &idx))
RETURN_ERROR;
srcReg->Index = idx;
}
else {
RETURN_ERROR2("Bad source register name", token);
}
}
else {
srcReg->File = 0;
}
/* semicolon */
if (!Parse_String(parseState, ";"))
RETURN_ERROR;
return GL_TRUE;
}
static GLboolean
Parse_OptionSequence(struct parse_state *parseState,
struct vp_instruction program[])
{
(void) program;
while (1) {
if (!Parse_String(parseState, "OPTION"))
return GL_TRUE; /* ok, not an OPTION statement */
if (Parse_String(parseState, "NV_position_invariant")) {
parseState->isPositionInvariant = GL_TRUE;
}
else {
RETURN_ERROR1("unexpected OPTION statement");
}
if (!Parse_String(parseState, ";"))
return GL_FALSE;
}
}
static GLboolean
Parse_InstructionSequence(struct parse_state *parseState,
struct vp_instruction program[])
{
while (1) {
struct vp_instruction *inst = program + parseState->numInst;
/* Initialize the instruction */
inst->SrcReg[0].File = PROGRAM_UNDEFINED;
inst->SrcReg[1].File = PROGRAM_UNDEFINED;
inst->SrcReg[2].File = PROGRAM_UNDEFINED;
inst->DstReg.File = PROGRAM_UNDEFINED;
inst->Data = NULL;
if (Parse_String(parseState, "MOV")) {
if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_MOV))
RETURN_ERROR;
}
else if (Parse_String(parseState, "LIT")) {
if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_LIT))
RETURN_ERROR;
}
else if (Parse_String(parseState, "ABS")) {
if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_ABS))
RETURN_ERROR;
}
else if (Parse_String(parseState, "MUL")) {
if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MUL))
RETURN_ERROR;
}
else if (Parse_String(parseState, "ADD")) {
if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_ADD))
RETURN_ERROR;
}
else if (Parse_String(parseState, "DP3")) {
if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DP3))
RETURN_ERROR;
}
else if (Parse_String(parseState, "DP4")) {
if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DP4))
RETURN_ERROR;
}
else if (Parse_String(parseState, "DST")) {
if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DST))
RETURN_ERROR;
}
else if (Parse_String(parseState, "MIN")) {
if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MIN))
RETURN_ERROR;
}
else if (Parse_String(parseState, "MAX")) {
if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MAX))
RETURN_ERROR;
}
else if (Parse_String(parseState, "SLT")) {
if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SLT))
RETURN_ERROR;
}
else if (Parse_String(parseState, "SGE")) {
if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SGE))
RETURN_ERROR;
}
else if (Parse_String(parseState, "DPH")) {
if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DPH))
RETURN_ERROR;
}
else if (Parse_String(parseState, "SUB")) {
if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SUB))
RETURN_ERROR;
}
else if (Parse_String(parseState, "MAD")) {
if (!Parse_TriOpInstruction(parseState, inst, VP_OPCODE_MAD))
RETURN_ERROR;
}
else if (Parse_String(parseState, "RCP")) {
if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RCP))
RETURN_ERROR;
}
else if (Parse_String(parseState, "RSQ")) {
if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RSQ))
RETURN_ERROR;
}
else if (Parse_String(parseState, "EXP")) {
if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_EXP))
RETURN_ERROR;
}
else if (Parse_String(parseState, "LOG")) {
if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_LOG))
RETURN_ERROR;
}
else if (Parse_String(parseState, "RCC")) {
if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RCC))
RETURN_ERROR;
}
else if (Parse_String(parseState, "ARL")) {
if (!Parse_AddressInstruction(parseState, inst))
RETURN_ERROR;
}
else if (Parse_String(parseState, "PRINT")) {
if (!Parse_PrintInstruction(parseState, inst))
RETURN_ERROR;
}
else if (Parse_String(parseState, "END")) {
if (!Parse_EndInstruction(parseState, inst))
RETURN_ERROR;
else {
parseState->numInst++;
return GL_TRUE; /* all done */
}
}
else {
/* bad instruction name */
RETURN_ERROR1("Unexpected token");
}
/* examine input/output registers */
if (inst->DstReg.File == PROGRAM_OUTPUT)
parseState->outputsWritten |= (1 << inst->DstReg.Index);
else if (inst->DstReg.File == PROGRAM_ENV_PARAM)
parseState->anyProgRegsWritten = GL_TRUE;
if (inst->SrcReg[0].File == PROGRAM_INPUT)
parseState->inputsRead |= (1 << inst->SrcReg[0].Index);
if (inst->SrcReg[1].File == PROGRAM_INPUT)
parseState->inputsRead |= (1 << inst->SrcReg[1].Index);
if (inst->SrcReg[2].File == PROGRAM_INPUT)
parseState->inputsRead |= (1 << inst->SrcReg[2].Index);
parseState->numInst++;
if (parseState->numInst >= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS)
RETURN_ERROR1("Program too long");
}
RETURN_ERROR;
}
static GLboolean
Parse_Program(struct parse_state *parseState,
struct vp_instruction instBuffer[])
{
if (parseState->isVersion1_1) {
if (!Parse_OptionSequence(parseState, instBuffer)) {
return GL_FALSE;
}
}
return Parse_InstructionSequence(parseState, instBuffer);
}
/**
* Parse/compile the 'str' returning the compiled 'program'.
* ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
* indicates the position of the error in 'str'.
*/
void
_mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum dstTarget,
const GLubyte *str, GLsizei len,
struct vertex_program *program)
{
struct parse_state parseState;
struct vp_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS];
struct vp_instruction *newInst;
GLenum target;
GLubyte *programString;
/* Make a null-terminated copy of the program string */
programString = (GLubyte *) MALLOC(len + 1);
if (!programString) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
return;
}
MEMCPY(programString, str, len);
programString[len] = 0;
/* Get ready to parse */
parseState.ctx = ctx;
parseState.start = programString;
parseState.isPositionInvariant = GL_FALSE;
parseState.isVersion1_1 = GL_FALSE;
parseState.numInst = 0;
parseState.inputsRead = 0;
parseState.outputsWritten = 0;
parseState.anyProgRegsWritten = GL_FALSE;
/* Reset error state */
_mesa_set_program_error(ctx, -1, NULL);
/* check the program header */
if (_mesa_strncmp((const char *) programString, "!!VP1.0", 7) == 0) {
target = GL_VERTEX_PROGRAM_NV;
parseState.pos = programString + 7;
parseState.isStateProgram = GL_FALSE;
}
else if (_mesa_strncmp((const char *) programString, "!!VP1.1", 7) == 0) {
target = GL_VERTEX_PROGRAM_NV;
parseState.pos = programString + 7;
parseState.isStateProgram = GL_FALSE;
parseState.isVersion1_1 = GL_TRUE;
}
else if (_mesa_strncmp((const char *) programString, "!!VSP1.0", 8) == 0) {
target = GL_VERTEX_STATE_PROGRAM_NV;
parseState.pos = programString + 8;
parseState.isStateProgram = GL_TRUE;
}
else {
/* invalid header */
ctx->Program.ErrorPos = 0;
_mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
return;
}
/* make sure target and header match */
if (target != dstTarget) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glLoadProgramNV(target mismatch)");
return;
}
if (Parse_Program(&parseState, instBuffer)) {
/* successful parse! */
if (parseState.isStateProgram) {
if (!parseState.anyProgRegsWritten) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glLoadProgramNV(c[#] not written)");
return;
}
}
else {
if (!parseState.isPositionInvariant &&
!(parseState.outputsWritten & 1)) {
/* bit 1 = HPOS register */
_mesa_error(ctx, GL_INVALID_OPERATION,
"glLoadProgramNV(HPOS not written)");
return;
}
}
/* copy the compiled instructions */
assert(parseState.numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS);
newInst = (struct vp_instruction *)
MALLOC(parseState.numInst * sizeof(struct vp_instruction));
if (!newInst) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
FREE(programString);
return; /* out of memory */
}
MEMCPY(newInst, instBuffer,
parseState.numInst * sizeof(struct vp_instruction));
/* install the program */
program->Base.Target = target;
if (program->Base.String) {
FREE(program->Base.String);
}
program->Base.String = programString;
program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
if (program->Instructions) {
FREE(program->Instructions);
}
program->Instructions = newInst;
program->InputsRead = parseState.inputsRead;
program->OutputsWritten = parseState.outputsWritten;
program->IsPositionInvariant = parseState.isPositionInvariant;
program->IsNVProgram = GL_TRUE;
#ifdef DEBUG_foo
_mesa_printf("--- glLoadProgramNV result ---\n");
_mesa_print_nv_vertex_program(program);
_mesa_printf("------------------------------\n");
#endif
}
else {
/* Error! */
_mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
/* NOTE: _mesa_set_program_error would have been called already */
/* GL_NV_vertex_program isn't supposed to set the error string
* so we reset it here.
*/
_mesa_set_program_error(ctx, ctx->Program.ErrorPos, NULL);
}
}
static void
PrintSrcReg(const struct vp_src_register *src)
{
static const char comps[5] = "xyzw";
if (src->Negate)
_mesa_printf("-");
if (src->RelAddr) {
if (src->Index > 0)
_mesa_printf("c[A0.x + %d]", src->Index);
else if (src->Index < 0)
_mesa_printf("c[A0.x - %d]", -src->Index);
else
_mesa_printf("c[A0.x]");
}
else if (src->File == PROGRAM_OUTPUT) {
_mesa_printf("o[%s]", OutputRegisters[src->Index]);
}
else if (src->File == PROGRAM_INPUT) {
_mesa_printf("v[%s]", InputRegisters[src->Index]);
}
else if (src->File == PROGRAM_ENV_PARAM) {
_mesa_printf("c[%d]", src->Index);
}
else {
ASSERT(src->File == PROGRAM_TEMPORARY);
_mesa_printf("R%d", src->Index);
}
if (GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 1) &&
GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 2) &&
GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 3)) {
_mesa_printf(".%c", comps[GET_SWZ(src->Swizzle, 0)]);
}
else if (src->Swizzle != SWIZZLE_NOOP) {
_mesa_printf(".%c%c%c%c",
comps[GET_SWZ(src->Swizzle, 0)],
comps[GET_SWZ(src->Swizzle, 1)],
comps[GET_SWZ(src->Swizzle, 2)],
comps[GET_SWZ(src->Swizzle, 3)]);
}
}
static void
PrintDstReg(const struct vp_dst_register *dst)
{
if (dst->File == PROGRAM_OUTPUT) {
_mesa_printf("o[%s]", OutputRegisters[dst->Index]);
}
else if (dst->File == PROGRAM_INPUT) {
_mesa_printf("v[%s]", InputRegisters[dst->Index]);
}
else if (dst->File == PROGRAM_ENV_PARAM) {
_mesa_printf("c[%d]", dst->Index);
}
else {
ASSERT(dst->File == PROGRAM_TEMPORARY);
_mesa_printf("R%d", dst->Index);
}
if (dst->WriteMask != 0 && dst->WriteMask != 0xf) {
_mesa_printf(".");
if (dst->WriteMask & 0x1)
_mesa_printf("x");
if (dst->WriteMask & 0x2)
_mesa_printf("y");
if (dst->WriteMask & 0x4)
_mesa_printf("z");
if (dst->WriteMask & 0x8)
_mesa_printf("w");
}
}
/**
* Print a single NVIDIA vertex program instruction.
*/
void
_mesa_print_nv_vertex_instruction(const struct vp_instruction *inst)
{
switch (inst->Opcode) {
case VP_OPCODE_MOV:
case VP_OPCODE_LIT:
case VP_OPCODE_RCP:
case VP_OPCODE_RSQ:
case VP_OPCODE_EXP:
case VP_OPCODE_LOG:
case VP_OPCODE_RCC:
case VP_OPCODE_ABS:
_mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
PrintDstReg(&inst->DstReg);
_mesa_printf(", ");
PrintSrcReg(&inst->SrcReg[0]);
_mesa_printf(";\n");
break;
case VP_OPCODE_MUL:
case VP_OPCODE_ADD:
case VP_OPCODE_DP3:
case VP_OPCODE_DP4:
case VP_OPCODE_DST:
case VP_OPCODE_MIN:
case VP_OPCODE_MAX:
case VP_OPCODE_SLT:
case VP_OPCODE_SGE:
case VP_OPCODE_DPH:
case VP_OPCODE_SUB:
_mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
PrintDstReg(&inst->DstReg);
_mesa_printf(", ");
PrintSrcReg(&inst->SrcReg[0]);
_mesa_printf(", ");
PrintSrcReg(&inst->SrcReg[1]);
_mesa_printf(";\n");
break;
case VP_OPCODE_MAD:
_mesa_printf("MAD ");
PrintDstReg(&inst->DstReg);
_mesa_printf(", ");
PrintSrcReg(&inst->SrcReg[0]);
_mesa_printf(", ");
PrintSrcReg(&inst->SrcReg[1]);
_mesa_printf(", ");
PrintSrcReg(&inst->SrcReg[2]);
_mesa_printf(";\n");
break;
case VP_OPCODE_ARL:
_mesa_printf("ARL A0.x, ");
PrintSrcReg(&inst->SrcReg[0]);
_mesa_printf(";\n");
break;
case VP_OPCODE_PRINT:
_mesa_printf("PRINT '%s'", inst->Data);
if (inst->SrcReg[0].File) {
_mesa_printf(", ");
PrintSrcReg(&inst->SrcReg[0]);
_mesa_printf(";\n");
}
else {
_mesa_printf("\n");
}
break;
case VP_OPCODE_END:
_mesa_printf("END\n");
break;
default:
_mesa_printf("BAD INSTRUCTION\n");
}
}
/**
* Print (unparse) the given vertex program. Just for debugging.
*/
void
_mesa_print_nv_vertex_program(const struct vertex_program *program)
{
const struct vp_instruction *inst;
for (inst = program->Instructions; ; inst++) {
_mesa_print_nv_vertex_instruction(inst);
if (inst->Opcode == VP_OPCODE_END)
return;
}
}
const char *
_mesa_nv_vertex_input_register_name(GLuint i)
{
ASSERT(i < MAX_NV_VERTEX_PROGRAM_INPUTS);
return InputRegisters[i];
}
const char *
_mesa_nv_vertex_output_register_name(GLuint i)
{
ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS);
return OutputRegisters[i];
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -