00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "std3d.h"
00026 #include "vertex_program_parse.h"
00027
00028
00029
00030
00031 bool CVPParser::parseWriteMask(uint &mask, std::string &errorOutput)
00032 {
00033
00034 if (*_CurrChar != '.')
00035 {
00036
00037 mask = 0xf;
00038 return true;
00039 }
00040 else
00041 {
00042 ++ _CurrChar;
00043 mask = 0;
00044 for(uint k = 0; k < 4; ++k)
00045 {
00046 uint maskIndex;
00047 switch(*_CurrChar)
00048 {
00049 case 'x': maskIndex = 0; break;
00050 case 'y': maskIndex = 1; break;
00051 case 'z': maskIndex = 2; break;
00052 case 'w': maskIndex = 3; break;
00053 default:
00054 if (k >= 1) return true;
00055 else
00056 {
00057 errorOutput = "Can't parse output mask.";
00058 return false;
00059 }
00060 break;
00061 }
00062 ++_CurrChar;
00063 if (mask & (1 << maskIndex))
00064 {
00065 errorOutput = "Duplicated output mask component.";
00066 return false;
00067 }
00068 mask |= 1 << maskIndex;
00069 }
00070 return true;
00071 }
00072 }
00073
00074
00077 void CVPParser::skipSpacesAndComments()
00078 {
00079 bool stop = false;
00080 do
00081 {
00082 switch(*_CurrChar)
00083 {
00084 case '\t':
00085 case '\r':
00086 case ' ' :
00087 ++_CurrChar;
00088 break;
00089
00090 case '\n':
00091 ++_CurrChar;
00092 ++_LineIndex;
00093 _LineStart = _CurrChar;
00094 break;
00095 case '#':
00096 while (*_CurrChar != '\n' && *_CurrChar != '\0') ++_CurrChar;
00097 skipSpacesAndComments();
00098 break;
00099 default:
00100 stop = true;
00101 break;
00102 }
00103 }
00104 while (!stop);
00105 }
00106
00107
00108 uint CVPInstruction::getNumUsedSrc() const
00109 {
00110 switch(Opcode)
00111 {
00112 case CVPInstruction::ARL:
00113 case CVPInstruction::RSQ:
00114 case CVPInstruction::EXPP:
00115 case CVPInstruction::LOG:
00116 case CVPInstruction::RCP:
00117 case CVPInstruction::MOV:
00118 case CVPInstruction::LIT:
00119 return 1;
00120
00121 case CVPInstruction::MAD:
00122 return 3;
00123
00124 case CVPInstruction::MUL:
00125 case CVPInstruction::ADD:
00126 case CVPInstruction::DP3:
00127 case CVPInstruction::DP4:
00128 case CVPInstruction::DST:
00129 case CVPInstruction::MIN:
00130 case CVPInstruction::MAX:
00131 case CVPInstruction::SLT:
00132 case CVPInstruction::SGE:
00133 return 2;
00134
00135 default:
00136 nlstop;
00137 }
00138 return 0;
00139 }
00140
00141
00142 bool CVPParser::parseOperand(CVPOperand &operand, bool outputOperand, std::string &errorOutput)
00143 {
00144 skipSpacesAndComments();
00145 bool result;
00146 if (outputOperand)
00147 {
00148 operand.Negate = false;
00149 switch(*_CurrChar)
00150 {
00151 case 'o': result = parseOutputRegister(operand, errorOutput); break;
00152 case 'R':
00153 result = parseVariableRegister(operand, errorOutput);
00154 break;
00155 case 'A': result = parseAddressRegister(operand, errorOutput); break;
00156 case '-':
00157 errorOutput = "Negation not allowed on ouput register.";
00158 return false;
00159 default:
00160 errorOutput = "Output, Address, or Temporary register expected as an output operand.";
00161 return false;
00162 }
00163 if (!result) return false;
00164
00165
00166 return parseWriteMask(operand.WriteMask, errorOutput);
00167 }
00168 else
00169 {
00170 operand.Negate = false;
00171 switch(*_CurrChar)
00172 {
00173 case 'v': result = parseInputRegister(operand, errorOutput); break;
00174 case 'R': result = parseVariableRegister(operand, errorOutput); break;
00175 case 'c': result = parseConstantRegister(operand, errorOutput); break;
00176 case 'a': result = parseAddressRegister(operand, errorOutput); break;
00177 case '-':
00178 {
00179 operand.Negate = true;
00180
00181 ++ _CurrChar;
00182 skipSpacesAndComments();
00183 switch(*_CurrChar)
00184 {
00185 case 'v': result = parseInputRegister(operand, errorOutput); break;
00186 case 'R': result = parseVariableRegister(operand, errorOutput); break;
00187 case 'c': result = parseConstantRegister(operand, errorOutput); break;
00188 default:
00189 errorOutput = "Negation must be followed by an input register, a variable register, or a constant.";
00190 return false;
00191 break;
00192 }
00193 }
00194 break;
00195 default:
00196 errorOutput = "Syntax error.";
00197 return false;
00198 break;
00199 }
00200 if (!result) return false;
00201 if (operand.Type != CVPOperand::AddressRegister)
00202 {
00203 if (!parseSwizzle(operand.Swizzle, errorOutput)) return false;
00204 if (operand.Type == CVPOperand::Variable)
00205 {
00206 for(uint k = 0; k < 4; ++k)
00207 {
00208 if (!(_RegisterMask[operand.Value.VariableValue] & (1 << operand.Swizzle.Comp[k])))
00209 {
00210 errorOutput = "Can't read a register component before writing to it.";
00211 return false;
00212 }
00213 }
00214 }
00215 }
00216 return true;
00217 }
00218
00219
00220 }
00221
00222
00223
00224 bool CVPParser::parseInputRegister(CVPOperand &operand, std::string &errorOutput)
00225 {
00226 ++_CurrChar;
00227 operand.Type = CVPOperand::InputRegister;
00228 if (*_CurrChar != '[')
00229 {
00230 errorOutput = "'[' expected when parsing an input register.";
00231 return false;
00232 }
00233 ++_CurrChar;
00234 skipSpacesAndComments();
00235 if (isdigit(*_CurrChar))
00236 {
00237
00238 uint index = *_CurrChar - '0';
00239 ++_CurrChar;
00240 if (isdigit(*_CurrChar))
00241 {
00242 index = 10 * index + (*_CurrChar - '0');
00243 ++_CurrChar;
00244 }
00245 if (index > 15)
00246 {
00247 errorOutput = "Invalid index for input register, must be in [0, 15].";
00248 return false;
00249 }
00250 operand.Value.InputRegisterValue = (CVPOperand::EInputRegister) index;
00251 }
00252 else
00253 {
00254
00255 uint32 strValue = 0;
00256
00257 for(uint k = 0; k < 4; ++k)
00258 {
00259 if (!isalnum(*_CurrChar))
00260 {
00261 errorOutput = "Can't parse index for input register.";
00262 return false;
00263 }
00264 strValue |= ((uint32) *_CurrChar) << (8 * (3 - k));
00265 ++_CurrChar;
00266 }
00267 switch (strValue)
00268 {
00269 case 'OPOS': operand.Value.InputRegisterValue = CVPOperand::IPosition; break;
00270 case 'WGHT': operand.Value.InputRegisterValue = CVPOperand::IWeight; break;
00271 case 'NRML': operand.Value.InputRegisterValue = CVPOperand::INormal; break;
00272 case 'COL0': operand.Value.InputRegisterValue = CVPOperand::IPrimaryColor; break;
00273 case 'COL1': operand.Value.InputRegisterValue = CVPOperand::ISecondaryColor; break;
00274 case 'FOGC': operand.Value.InputRegisterValue = CVPOperand::IFogCoord; break;
00275
00276 case 'TEX0':
00277 case 'TEX1':
00278 case 'TEX2':
00279 case 'TEX3':
00280 case 'TEX4':
00281 case 'TEX5':
00282 case 'TEX6':
00283 case 'TEX7':
00284 operand.Value.InputRegisterValue = (CVPOperand::EInputRegister) (CVPOperand::ITex0 + strValue & 0xff - '0');
00285 break;
00286 default:
00287 errorOutput = "Can't parse index for input register.";
00288 return false;
00289 }
00290 }
00291 skipSpacesAndComments();
00292 if (*_CurrChar != ']')
00293 {
00294 errorOutput = "']' expected when parsing an input register.";
00295 return false;
00296 }
00297 ++ _CurrChar;
00298 return true;
00299 }
00300
00301
00302 static inline bool letterToSwizzleComp(char letter, CVPSwizzle::EComp &comp)
00303 {
00304 switch (letter)
00305 {
00306 case 'x': comp = CVPSwizzle::X; return true;
00307 case 'y': comp = CVPSwizzle::Y; return true;
00308 case 'z': comp = CVPSwizzle::Z; return true;
00309 case 'w': comp = CVPSwizzle::W; return true;
00310 }
00311 return false;
00312 }
00313
00314
00315 bool CVPParser::parseSwizzle(CVPSwizzle &swizzle,std::string &errorOutput)
00316 {
00317 if (*_CurrChar != '.')
00318 {
00319
00320 swizzle.Comp[0] = CVPSwizzle::X;
00321 swizzle.Comp[1] = CVPSwizzle::Y;
00322 swizzle.Comp[2] = CVPSwizzle::Z;
00323 swizzle.Comp[3] = CVPSwizzle::W;
00324 return true;
00325 }
00326 ++_CurrChar;
00327
00328 for(uint k = 0; k < 4; ++k)
00329 {
00330 if (!isalpha(*_CurrChar))
00331 {
00332 if (k == 1)
00333 {
00334 switch(*_CurrChar)
00335 {
00336 case ',':
00337 case ';':
00338 case ' ':
00339 case '\t':
00340 case '\r':
00341 case '\n':
00342 case '#':
00343 swizzle.Comp[1] = swizzle.Comp[2] = swizzle.Comp[3] = swizzle.Comp[0];
00344 return true;
00345 break;
00346 default:
00347 errorOutput = "Can't parse swizzle.";
00348
00349 }
00350 }
00351 else
00352 {
00353 errorOutput = "Invalid swizzle value.";
00354 return false;
00355 }
00356 }
00357
00358 if (!letterToSwizzleComp(*_CurrChar, swizzle.Comp[k]))
00359 {
00360 errorOutput = "Invalid swizzle value.";
00361 return false;
00362 }
00363 ++ _CurrChar;
00364 }
00365
00366 return true;
00367 }
00368
00369
00370 bool CVPParser::parseOutputRegister(CVPOperand &operand, std::string &errorOutput)
00371 {
00372 ++_CurrChar;
00373 operand.Type = CVPOperand::OutputRegister;
00374 if (*_CurrChar != '[')
00375 {
00376 errorOutput = "'[' expected when parsing an ouput register.";
00377 return false;
00378 }
00379 ++_CurrChar;
00380 skipSpacesAndComments();
00381
00382 uint32 strValue = 0;
00383
00384 for(uint k = 0; k < 4; ++k)
00385 {
00386 if (!isalnum(*_CurrChar))
00387 {
00388 errorOutput = "Can't parse index for output register.";
00389 return false;
00390 }
00391 strValue |= ((uint32) *_CurrChar) << (8 * (3 - k));
00392 ++_CurrChar;
00393 }
00394
00395 switch(strValue)
00396 {
00397 case 'HPOS': operand.Value.OutputRegisterValue = CVPOperand::OHPosition; break;
00398 case 'COL0': operand.Value.OutputRegisterValue = CVPOperand::OPrimaryColor; break;
00399 case 'COL1': operand.Value.OutputRegisterValue = CVPOperand::OSecondaryColor; break;
00400 case 'BFC0': operand.Value.OutputRegisterValue = CVPOperand::OBackFacePrimaryColor; break;
00401 case 'BFC1': operand.Value.OutputRegisterValue = CVPOperand::OBackFaceSecondaryColor; break;
00402 case 'FOGC': operand.Value.OutputRegisterValue = CVPOperand::OFogCoord; break;
00403 case 'PSIZ': operand.Value.OutputRegisterValue = CVPOperand::OPointSize; break;
00404 case 'TEX0': operand.Value.OutputRegisterValue = CVPOperand::OTex0; break;
00405 case 'TEX1': operand.Value.OutputRegisterValue = CVPOperand::OTex1; break;
00406 case 'TEX2': operand.Value.OutputRegisterValue = CVPOperand::OTex2; break;
00407 case 'TEX3': operand.Value.OutputRegisterValue = CVPOperand::OTex3; break;
00408 case 'TEX4': operand.Value.OutputRegisterValue = CVPOperand::OTex4; break;
00409 case 'TEX5': operand.Value.OutputRegisterValue = CVPOperand::OTex5; break;
00410 case 'TEX6': operand.Value.OutputRegisterValue = CVPOperand::OTex6; break;
00411 case 'TEX7': operand.Value.OutputRegisterValue = CVPOperand::OTex7; break;
00412 default:
00413 errorOutput = "Can't read index for output register.";
00414 return false;
00415 break;
00416 }
00417 skipSpacesAndComments();
00418 if (*_CurrChar != ']')
00419 {
00420 errorOutput = "']' expected when parsing an output register.";
00421 return false;
00422 }
00423 ++_CurrChar;
00424 return true;
00425 }
00426
00427
00428 static inline const char *parseUInt(const char *src, uint &dest)
00429 {
00430 uint index = 0;
00431 while (isdigit(*src))
00432 {
00433 index = 10 * index + *src - '0';
00434 ++ src;
00435 }
00436 dest = index;
00437 return src;
00438 }
00439
00440
00441
00442 bool CVPParser::parseConstantRegister(CVPOperand &operand, std::string &errorOutput)
00443 {
00444 ++_CurrChar;
00445 operand.Type = CVPOperand::Constant;
00446 if (*_CurrChar != '[')
00447 {
00448 errorOutput = "'[' expected when parsing a constant register.";
00449 return false;
00450 }
00451 ++_CurrChar;
00452 skipSpacesAndComments();
00453 uint &index = operand.Value.ConstantValue;
00454 if (isdigit(*_CurrChar))
00455 {
00456
00457 _CurrChar = parseUInt(_CurrChar, index);
00458 if (index > 95)
00459 {
00460 errorOutput = "Constant register index must range from 0 to 95.";
00461 return false;
00462 }
00463 operand.Indexed = false;
00464 }
00465 else if (*_CurrChar == 'A')
00466 {
00467
00468 operand.Indexed = true;
00469 index = 0;
00470 if (_CurrChar[1] == '0'
00471 && _CurrChar[2] == '.'
00472 && _CurrChar[3] == 'x')
00473 {
00474 _CurrChar += 4;
00475 skipSpacesAndComments();
00476 if (*_CurrChar == '+')
00477 {
00478 ++ _CurrChar;
00479 skipSpacesAndComments();
00480 if (isdigit(*_CurrChar))
00481 {
00482 _CurrChar = parseUInt(_CurrChar, index);
00483 if (index > 95)
00484 {
00485 errorOutput = "Constant register index must range from 0 to 95.";
00486 return false;
00487 }
00488 }
00489 else
00490 {
00491 errorOutput = "Can't parse offset for constant register.";
00492 return false;
00493 }
00494 }
00495 }
00496 else
00497 {
00498 errorOutput = "Can't parse constant register index.";
00499 return false;
00500 }
00501 }
00502 skipSpacesAndComments();
00503 if (*_CurrChar != ']')
00504 {
00505 errorOutput = "']' expected when parsing an input register.";
00506 return false;
00507 }
00508 ++_CurrChar;
00509 return true;
00510 }
00511
00512
00513 bool CVPParser::parseVariableRegister(CVPOperand &operand, std::string &errorOutput)
00514 {
00515 ++_CurrChar;
00516 operand.Type = CVPOperand::Variable;
00517 if (!isdigit(*_CurrChar))
00518 {
00519 errorOutput = "Can't parse variable register.";
00520 return false;
00521 }
00522 uint &index = operand.Value.VariableValue;
00523 _CurrChar = parseUInt(_CurrChar, index);
00524 if (index > 11)
00525 {
00526 errorOutput = "Variable register index must range from 0 to 11.";
00527 return false;
00528 }
00529 return true;
00530 }
00531
00532
00533 bool CVPParser::parseAddressRegister(CVPOperand &operand, std::string &errorOutput)
00534 {
00535 ++_CurrChar;
00536 operand.Type = CVPOperand::AddressRegister;
00537 if (_CurrChar[0] != '0' || _CurrChar[1] != '.' || _CurrChar[2] != 'x')
00538 {
00539 errorOutput = "Can't parse address register.";
00540 return false;
00541 }
00542 _CurrChar += 3;
00543 return true;
00544 }
00545
00546
00547 bool CVPParser::parseOp2(CVPInstruction &instr,std::string &errorOutput)
00548 {
00549 skipSpacesAndComments();
00550
00551 if (!parseOperand(instr.Dest, true, errorOutput)) return false;
00552
00553 if (instr.Dest.Type == CVPOperand::Constant || instr.Dest.Type == CVPOperand::InputRegister)
00554 {
00555 errorOutput = "Can't write to a constant or input register";
00556 return false;
00557 }
00558
00559 skipSpacesAndComments();
00560 if (*_CurrChar != ',')
00561 {
00562 errorOutput = "',' expected.";
00563 return false;
00564 }
00565 ++_CurrChar;
00566 skipSpacesAndComments();
00567
00568 if (!parseOperand(instr.Src1, false, errorOutput)) return false;
00569 if (instr.Src1.Type == CVPOperand::AddressRegister
00570 || instr.Src1.Type == CVPOperand::OutputRegister)
00571 {
00572 errorOutput = "Src1 must be constant, variable, or input register.";
00573 return false;
00574 }
00575 return true;
00576 }
00577
00578
00579 bool CVPParser::parseOp3(CVPInstruction &instr, std::string &errorOutput)
00580 {
00581 if (!parseOp2(instr, errorOutput)) return false;
00582 skipSpacesAndComments();
00583 if (*_CurrChar != ',')
00584 {
00585 errorOutput = "',' expected.";
00586 return false;
00587 }
00588 ++_CurrChar;
00589 skipSpacesAndComments();
00590
00591 if (!parseOperand(instr.Src2, false, errorOutput)) return false;
00592 if (instr.Src2.Type == CVPOperand::AddressRegister
00593 || instr.Src2.Type == CVPOperand::OutputRegister)
00594 {
00595 errorOutput = "Src2 must be constant, variable, or input register.";
00596 return false;
00597 }
00598
00599
00600
00601 if (instr.Src1.Type == CVPOperand::Constant
00602 && instr.Src2.Type == CVPOperand::Constant)
00603 {
00604
00605 if (!
00606 (
00607 instr.Src1.Indexed == instr.Src2.Indexed
00608 && instr.Src1.Value.ConstantValue == instr.Src2.Value.ConstantValue
00609 )
00610 )
00611 {
00612 errorOutput = "Can't read 2 different constant registers in a single instruction.";
00613 return false;
00614 }
00615 }
00616
00617
00618 if (instr.Src1.Type == CVPOperand::InputRegister
00619 && instr.Src2.Type == CVPOperand::InputRegister)
00620 {
00621
00622 if (instr.Src1.Value.InputRegisterValue != instr.Src2.Value.InputRegisterValue)
00623 {
00624 errorOutput = "Can't read 2 different input registers in a single instruction.";
00625 return false;
00626 }
00627 }
00628 return true;
00629 }
00630
00631
00632 bool CVPParser::parseOp4(CVPInstruction &instr, std::string &errorOutput)
00633 {
00634 if (!parseOp3(instr, errorOutput)) return false;
00635
00636 skipSpacesAndComments();
00637 if (*_CurrChar != ',')
00638 {
00639 errorOutput = "',' expected.";
00640 return false;
00641 }
00642 ++_CurrChar;
00643 skipSpacesAndComments();
00644
00645 if (!parseOperand(instr.Src3, false, errorOutput)) return false;
00646 if (instr.Src3.Type == CVPOperand::AddressRegister
00647 || instr.Src3.Type == CVPOperand::OutputRegister)
00648 {
00649 errorOutput = "Src3 must be constant, variable, or input register.";
00650 return false;
00651 }
00652
00654
00656
00657
00658 if (instr.Src3.Type == CVPOperand::Constant)
00659 {
00660 if (instr.Src1.Type == CVPOperand::Constant)
00661 {
00662 if (!
00663 (
00664 instr.Src1.Indexed == instr.Src3.Indexed
00665 && instr.Src1.Value.ConstantValue == instr.Src3.Value.ConstantValue
00666 )
00667 )
00668 {
00669 errorOutput = "Can't read 2 different constant registers in a single instruction.";
00670 return false;
00671 }
00672 }
00673 if (instr.Src2.Type == CVPOperand::Constant)
00674 {
00675 if (!
00676 (
00677 instr.Src2.Indexed == instr.Src3.Indexed
00678 && instr.Src2.Value.ConstantValue == instr.Src3.Value.ConstantValue
00679 )
00680 )
00681 {
00682 errorOutput = "Can't read 2 different constant registers in a single instruction.";
00683 return false;
00684 }
00685 }
00686 }
00687
00688
00689 if (instr.Src3.Type == CVPOperand::InputRegister)
00690 {
00691 if (instr.Src1.Type == CVPOperand::InputRegister)
00692 {
00693 if (instr.Src1.Value.InputRegisterValue != instr.Src3.Value.InputRegisterValue)
00694 {
00695 errorOutput = "Can't read 2 different input registers in a single instruction.";
00696 return false;
00697 }
00698 }
00699 if (instr.Src2.Type == CVPOperand::InputRegister)
00700 {
00701 if (instr.Src2.Value.InputRegisterValue != instr.Src3.Value.InputRegisterValue)
00702 {
00703 errorOutput = "Can't read 2 different input registers in a single instruction.";
00704 return false;
00705 }
00706 }
00707 }
00708
00709
00710 return true;
00711 }
00712
00713
00714 bool CVPParser::parseInstruction(CVPInstruction &instr, std::string &errorOutput, bool &endEncountered)
00715 {
00716 skipSpacesAndComments();
00717 endEncountered = false;
00718 uint32 instrStr = 0;
00719 uint k;
00720 for(k = 0; k < 4; ++k)
00721 {
00722 if (!isalnum(*_CurrChar))
00723 {
00724 if (k < 3)
00725 {
00726 errorOutput = "Syntax error : can't read opcode.";
00727 return false;
00728 }
00729 else break;
00730 }
00731 instrStr |= ((uint) *_CurrChar) << (8 * (3 - k));
00732 ++ _CurrChar;
00733 }
00734 if (k != 4)
00735 {
00736 instrStr |= (uint32) ' ';
00737 }
00738 switch (instrStr)
00739 {
00740 case 'ARL ':
00741 instr.Opcode = CVPInstruction::ARL;
00742 if (!parseOp2(instr, errorOutput)) return false;
00743 if (!instr.Src1.Swizzle.isScalar())
00744 {
00745 errorOutput = "ARL need a scalar src value.";
00746 return false;
00747 }
00748 break;
00749 case 'RSQ ':
00750 instr.Opcode = CVPInstruction::RSQ;
00751 if (!parseOp2(instr, errorOutput)) return false;
00752 if (!instr.Src1.Swizzle.isScalar())
00753 {
00754 errorOutput = "RSQ need a scalar src value.";
00755 return false;
00756 }
00757 break;
00758 case 'EXP ':
00759 case 'EXPP':
00760 instr.Opcode = CVPInstruction::EXPP;
00761 if (!parseOp2(instr, errorOutput)) return false;
00762 if (!instr.Src1.Swizzle.isScalar())
00763 {
00764 errorOutput = "EXP need a scalar src value.";
00765 return false;
00766 }
00767
00768
00769
00770
00771
00772
00773 break;
00774 case 'LOG ':
00775 instr.Opcode = CVPInstruction::LOG;
00776 if (!parseOp2(instr, errorOutput)) return false;
00777 if (!instr.Src1.Swizzle.isScalar())
00778 {
00779 errorOutput = "LOG need a scalar src value.";
00780 return false;
00781 }
00782
00783
00784
00785
00786
00787
00788
00789 break;
00790 case 'RCP ':
00791 instr.Opcode = CVPInstruction::RCP;
00792 if (!parseOp2(instr, errorOutput)) return false;
00793 if (!instr.Src1.Swizzle.isScalar())
00794 {
00795 errorOutput = "RCP need a scalar src value.";
00796 return false;
00797 }
00798 break;
00800 case 'MOV ':
00801 instr.Opcode = CVPInstruction::MOV;
00802 if (!parseOp2(instr, errorOutput)) return false;
00803
00804 break;
00805 case 'LIT ':
00806 instr.Opcode = CVPInstruction::LIT;
00807 if (!parseOp2(instr, errorOutput)) return false;
00808 break;
00810 case 'MAD ':
00811 instr.Opcode = CVPInstruction::MAD;
00812 if (!parseOp4(instr, errorOutput)) return false;
00813 break;
00815 case 'ADD ':
00816 instr.Opcode = CVPInstruction::ADD;
00817 if (!parseOp3(instr, errorOutput)) return false;
00818 break;
00820 case 'MUL ':
00821 instr.Opcode = CVPInstruction::MUL;
00822 if (!parseOp3(instr, errorOutput)) return false;
00823 break;
00824 case 'DP3 ':
00825 instr.Opcode = CVPInstruction::DP3;
00826 if (!parseOp3(instr, errorOutput)) return false;
00827 break;
00828 case 'DP4 ':
00829 instr.Opcode = CVPInstruction::DP4;
00830 if (!parseOp3(instr, errorOutput)) return false;
00831 break;
00832 case 'DST ':
00833 instr.Opcode = CVPInstruction::DST;
00834 if (!parseOp3(instr, errorOutput)) return false;
00835 break;
00836 case 'MIN ':
00837 instr.Opcode = CVPInstruction::MIN;
00838 if (!parseOp3(instr, errorOutput)) return false;
00839 break;
00840 case 'MAX ':
00841 instr.Opcode = CVPInstruction::MAX;
00842 if (!parseOp3(instr, errorOutput)) return false;
00843 break;
00844 case 'SLT ':
00845 instr.Opcode = CVPInstruction::SLT;
00846 if (!parseOp3(instr, errorOutput)) return false;
00847 break;
00848 case 'SGE ':
00849 instr.Opcode = CVPInstruction::SGE;
00850 if (!parseOp3(instr, errorOutput)) return false;
00851 break;
00853 case 'END ':
00854 endEncountered = true;
00855 return true;
00856 break;
00857 default:
00858 errorOutput = "Syntax error : unknow opcode.";
00859 return false;
00860 break;
00861 }
00862
00863
00864 if (instr.Dest.Type == CVPOperand::Variable)
00865 {
00866 _RegisterMask[instr.Dest.Value.VariableValue] |= instr.Dest.WriteMask;
00867 }
00868
00869
00870 if (instrStr != 'ARL ')
00871 {
00872 if (instr.Dest.Type == CVPOperand::AddressRegister)
00873 {
00874 errorOutput = "Can't write to address register.";
00875 return false;
00876 }
00877 }
00878
00879
00880 skipSpacesAndComments();
00881
00882 if (*_CurrChar != ';')
00883 {
00884 errorOutput = "';' expected.";
00885 return false;
00886 }
00887 ++_CurrChar;
00888 return true;
00889 }
00890
00891
00892
00893 static std::string getStringUntilCR(const char *src)
00894 {
00895 nlassert(src);
00896 std::string result;
00897 while (*src != '\n' && *src != '\r' && *src != '\0')
00898 {
00899 result += *src;
00900 ++src;
00901 }
00902 return result;
00903 }
00904
00905
00906 bool CVPParser::parse(const char *src, CVPParser::TProgram &result, std::string &errorOutput)
00907 {
00908 if (!src) return false;
00909
00910 std::fill(_RegisterMask, _RegisterMask + 96, 0);
00911
00912
00913 _CurrChar = src;
00914 _LineStart = src;
00915 _LineIndex = 1;
00916
00917 skipSpacesAndComments();
00918
00919
00920 if ( _CurrChar[0] != '!'
00921 || _CurrChar[1] != '!'
00922 || _CurrChar[2] != 'V'
00923 || _CurrChar[3] != 'P'
00924 || _CurrChar[4] != '1'
00925 || _CurrChar[5] != '.'
00926 || (_CurrChar[6] != '0' && _CurrChar[6] != '1'))
00927 {
00928 errorOutput = "Can't parse version.";
00929 return false;
00930 }
00931 _CurrChar += 7;
00932
00933 errorOutput.clear();
00934
00935 bool endEncoutered = false;
00936
00937 std::string errorMess;
00938 for(;;)
00939 {
00940 CVPInstruction instr;
00941 if (!parseInstruction(instr, errorMess, endEncoutered))
00942 {
00943 errorOutput = std::string("CVPParser::parse : Error encountered at line ") + NLMISC::toString(_LineIndex) + std::string(" : ") + errorMess + std::string(" Text : ") + getStringUntilCR(_LineStart);
00944 return false;
00945 }
00946 if (endEncoutered) break;
00947 result.push_back(instr);
00948 }
00949 return true;
00950 }
00951
00952
00953
00954 static const char *instrToName[] =
00955 {
00956 "MOV ",
00957 "ARL ",
00958 "MUL ",
00959 "ADD ",
00960 "MAD ",
00961 "RSQ ",
00962 "DP3 ",
00963 "DP4 ",
00964 "DST ",
00965 "LIT ",
00966 "MIN ",
00967 "MAX ",
00968 "SLT ",
00969 "SGE ",
00970 "EXPP ",
00971 "LOG ",
00972 "RCP "
00973 };
00974
00975
00976 static const char *outputRegisterToName[] =
00977 {
00978 "HPOS",
00979 "COL0",
00980 "COL1",
00981 "BFC0",
00982 "BFC1",
00983 "FOGC",
00984 "PSIZ",
00985 "TEX0",
00986 "TEX1",
00987 "TEX2",
00988 "TEX3",
00989 "TEX4",
00990 "TEX5",
00991 "TEX6",
00992 "TEX7"
00993 };
00994
00995
00996
00997 static void dumpWriteMask(uint mask, std::string &out)
00998 {
00999 if (mask == 0xf)
01000 {
01001 out = "";
01002 return;
01003 }
01004 out = ".";
01005 if (mask & 1) out +="x";
01006 if (mask & 2) out +="y";
01007 if (mask & 4) out +="z";
01008 if (mask & 8) out +="w";
01009 }
01010
01011
01012 static void dumpSwizzle(const CVPSwizzle &swz, std::string &out)
01013 {
01014 if (swz.isIdentity())
01015 {
01016 out = "";
01017 return;
01018 }
01019 out = ".";
01020 for(uint k = 0; k < 4; ++k)
01021 {
01022 switch(swz.Comp[k])
01023 {
01024 case CVPSwizzle::X: out += "x"; break;
01025 case CVPSwizzle::Y: out += "y"; break;
01026 case CVPSwizzle::Z: out += "z"; break;
01027 case CVPSwizzle::W: out += "w"; break;
01028 default:
01029 nlassert(0);
01030 break;
01031 }
01032 if (swz.isScalar() && k == 0) break;
01033 }
01034
01035 }
01036
01037
01038 static void dumpOperand(const CVPOperand &op, bool destOperand, std::string &out)
01039 {
01040 out = op.Negate ? " -" : " ";
01041 switch(op.Type)
01042 {
01043 case CVPOperand::Variable: out += "R" + NLMISC::toString(op.Value.VariableValue); break;
01044 case CVPOperand::Constant:
01045 out += "c[";
01046 if (op.Indexed)
01047 {
01048 out += "A0.x + ";
01049 }
01050 out += NLMISC::toString(op.Value.ConstantValue) + "]";
01051 break;
01052 case CVPOperand::InputRegister: out += "v[" + NLMISC::toString((uint) op.Value.InputRegisterValue) + "]"; break;
01053 case CVPOperand::OutputRegister:
01054 nlassert(op.Value.OutputRegisterValue < CVPOperand::OutputRegisterCount);
01055 out += "o[" + std::string(outputRegisterToName[op.Value.OutputRegisterValue]) + "]";
01056 break;
01057 case CVPOperand::AddressRegister:
01058 out += "A0.x";
01059 break;
01060 }
01061 std::string suffix;
01062 if (destOperand)
01063 {
01064 dumpWriteMask(op.WriteMask, suffix);
01065 }
01066 else
01067 {
01068 dumpSwizzle(op.Swizzle, suffix);
01069 }
01070 out += suffix;
01071 }
01072
01073
01076 static void dumpInstr(const CVPInstruction &instr, std::string &out)
01077 {
01078 nlassert(instr.Opcode < CVPInstruction::OpcodeCount)
01079 out = instrToName[instr.Opcode];
01080 uint nbOp = instr.getNumUsedSrc();
01081 std::string destOperand;
01082 dumpOperand(instr.Dest, true, destOperand);
01083 out += destOperand;
01084 for(uint k = 0; k < nbOp; ++k)
01085 {
01086 out += ", ";
01087 std::string srcOperand;
01088 dumpOperand(instr.getSrc(k), false, srcOperand);
01089 out += srcOperand;
01090 }
01091 out +="; \n";
01092 }
01093
01094
01095 void CVPParser::dump(const TProgram &prg, std::string &dest)
01096 {
01097 dest = "!!VP1.0 \n";
01098 for(uint k = 0; k < prg.size(); ++k)
01099 {
01100 std::string instr;
01101 dumpInstr(prg[k], instr);
01102 dest += instr;
01103 }
01104 dest +="END";
01105 }
01106
01107