1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "nel/3d/vertex_program_parse.h"
29 #ifdef NL_LITTLE_ENDIAN
108 //=====================================
109 bool CVPParser::parseWriteMask(uint
&mask
, std::string
&errorOutput
)
112 if (*_CurrChar
!= '.')
115 mask
= 0xf; //output 4 coordinates
122 for(uint k
= 0; k
< 4; ++k
)
127 case 'x': maskIndex
= 0; break;
128 case 'y': maskIndex
= 1; break;
129 case 'z': maskIndex
= 2; break;
130 case 'w': maskIndex
= 3; break;
132 if (k
>= 1) return true;
135 errorOutput
= "Can't parse output mask.";
141 if (mask
& (1 << maskIndex
))
143 errorOutput
= "Duplicated output mask component.";
146 mask
|= 1 << maskIndex
;
152 //=====================================
153 /** Skip tabulation and space in a source code
155 void CVPParser::skipSpacesAndComments()
171 _LineStart
= _CurrChar
;
173 case '#': // comment go till end of line
174 while (*_CurrChar
!= '\n' && *_CurrChar
!= '\0') ++_CurrChar
;
175 skipSpacesAndComments();
185 //=================================================================================================
186 uint
CVPInstruction::getNumUsedSrc() const
190 case CVPInstruction::ARL
:
191 case CVPInstruction::RSQ
:
192 case CVPInstruction::EXPP
:
193 case CVPInstruction::LOG
:
194 case CVPInstruction::RCP
:
195 case CVPInstruction::MOV
:
196 case CVPInstruction::LIT
:
199 case CVPInstruction::MAD
:
202 case CVPInstruction::MUL
:
203 case CVPInstruction::ADD
:
204 case CVPInstruction::DP3
:
205 case CVPInstruction::DP4
:
206 case CVPInstruction::DST
:
207 case CVPInstruction::MIN
:
208 case CVPInstruction::MAX
:
209 case CVPInstruction::SLT
:
210 case CVPInstruction::SGE
:
219 //=================================================================================================
220 bool CVPParser::parseOperand(CVPOperand
&operand
, bool outputOperand
, std::string
&errorOutput
)
222 skipSpacesAndComments();
226 operand
.Negate
= false;
229 case 'o': result
= parseOutputRegister(operand
, errorOutput
); break;
231 result
= parseVariableRegister(operand
, errorOutput
);
233 case 'A': result
= parseAddressRegister(operand
, errorOutput
); break;
235 errorOutput
= "Negation not allowed on output register.";
238 errorOutput
= "Output, Address, or Temporary register expected as an output operand.";
241 if (!result
) return false;
243 // parse the write mask
244 return parseWriteMask(operand
.WriteMask
, errorOutput
);
248 operand
.Negate
= false;
251 case 'v': result
= parseInputRegister(operand
, errorOutput
); break;
252 case 'R': result
= parseVariableRegister(operand
, errorOutput
); break;
253 case 'c': result
= parseConstantRegister(operand
, errorOutput
); break;
254 case 'a': result
= parseAddressRegister(operand
, errorOutput
); break;
257 operand
.Negate
= true;
260 skipSpacesAndComments();
263 case 'v': result
= parseInputRegister(operand
, errorOutput
); break;
264 case 'R': result
= parseVariableRegister(operand
, errorOutput
); break;
265 case 'c': result
= parseConstantRegister(operand
, errorOutput
); break;
267 errorOutput
= "Negation must be followed by an input register, a variable register, or a constant.";
274 errorOutput
= "Syntax error.";
278 if (!result
) return false;
279 if (operand
.Type
!= CVPOperand::AddressRegister
)
281 if (!parseSwizzle(operand
.Swizzle
, errorOutput
)) return false;
282 if (operand
.Type
== CVPOperand::Variable
)
284 for(uint k
= 0; k
< 4; ++k
)
286 if (!(_RegisterMask
[operand
.Value
.VariableValue
] & (1 << operand
.Swizzle
.Comp
[k
])))
288 errorOutput
= "Can't read a register component before writing to it.";
301 //=================================================================================================
302 bool CVPParser::parseInputRegister(CVPOperand
&operand
, std::string
&errorOutput
)
305 operand
.Type
= CVPOperand::InputRegister
;
306 if (*_CurrChar
!= '[')
308 errorOutput
= "'[' expected when parsing an input register.";
312 skipSpacesAndComments();
313 if (isdigit(*_CurrChar
))
315 // The input register is expressed as an index
316 uint index
= *_CurrChar
- '0';
318 if (isdigit(*_CurrChar
))
320 index
= 10 * index
+ (*_CurrChar
- '0');
325 errorOutput
= "Invalid index for input register, must be in [0, 15].";
328 operand
.Value
.InputRegisterValue
= (CVPOperand::EInputRegister
) index
;
332 // The input register is expressed as a string
334 // read the 4 letters
335 for(uint k
= 0; k
< 4; ++k
)
337 if (!isalnum(*_CurrChar
))
339 errorOutput
= "Can't parse index for input register.";
342 strValue
|= ((uint32
) *_CurrChar
) << (8 * (3 - k
));
345 switch ((TArguments
)strValue
)
347 case OPOS
: operand
.Value
.InputRegisterValue
= CVPOperand::IPosition
; break;
348 case WGHT
: operand
.Value
.InputRegisterValue
= CVPOperand::IWeight
; break;
349 case NRML
: operand
.Value
.InputRegisterValue
= CVPOperand::INormal
; break;
350 case COL0
: operand
.Value
.InputRegisterValue
= CVPOperand::IPrimaryColor
; break;
351 case COL1
: operand
.Value
.InputRegisterValue
= CVPOperand::ISecondaryColor
; break;
352 case FOGC
: operand
.Value
.InputRegisterValue
= CVPOperand::IFogCoord
; break;
362 operand
.Value
.InputRegisterValue
= (CVPOperand::EInputRegister
) (((CVPOperand::ITex0
+ strValue
) & 0xff) - '0');
365 errorOutput
= "Can't parse index for input register.";
369 skipSpacesAndComments();
370 if (*_CurrChar
!= ']')
372 errorOutput
= "']' expected when parsing an input register.";
379 //=================================================================================================
380 static inline bool letterToSwizzleComp(char letter
, CVPSwizzle::EComp
&comp
)
384 case 'x': comp
= CVPSwizzle::X
; return true;
385 case 'y': comp
= CVPSwizzle::Y
; return true;
386 case 'z': comp
= CVPSwizzle::Z
; return true;
387 case 'w': comp
= CVPSwizzle::W
; return true;
392 //=================================================================================================
393 bool CVPParser::parseSwizzle(CVPSwizzle
&swizzle
,std::string
&errorOutput
)
395 if (*_CurrChar
!= '.')
398 swizzle
.Comp
[0] = CVPSwizzle::X
;
399 swizzle
.Comp
[1] = CVPSwizzle::Y
;
400 swizzle
.Comp
[2] = CVPSwizzle::Z
;
401 swizzle
.Comp
[3] = CVPSwizzle::W
;
406 for(uint k
= 0; k
< 4; ++k
)
408 if (!isalpha(*_CurrChar
))
410 if (k
== 1) // 1 letter case
421 swizzle
.Comp
[1] = swizzle
.Comp
[2] = swizzle
.Comp
[3] = swizzle
.Comp
[0];
425 errorOutput
= "Can't parse swizzle.";
431 errorOutput
= "Invalid swizzle value.";
436 if (!letterToSwizzleComp(*_CurrChar
, swizzle
.Comp
[k
]))
438 errorOutput
= "Invalid swizzle value.";
447 //=================================================================================================
448 bool CVPParser::parseOutputRegister(CVPOperand
&operand
, std::string
&errorOutput
)
451 operand
.Type
= CVPOperand::OutputRegister
;
452 if (*_CurrChar
!= '[')
454 errorOutput
= "'[' expected when parsing an output register.";
458 skipSpacesAndComments();
459 // The input register is expressed as a string
461 // read the 4 letters
462 for(uint k
= 0; k
< 4; ++k
)
464 if (!isalnum(*_CurrChar
))
466 errorOutput
= "Can't parse index for output register.";
469 strValue
|= ((uint32
) *_CurrChar
) << (8 * (3 - k
));
473 switch((TArguments
)strValue
)
475 case HPOS
: operand
.Value
.OutputRegisterValue
= CVPOperand::OHPosition
; break;
476 case COL0
: operand
.Value
.OutputRegisterValue
= CVPOperand::OPrimaryColor
; break;
477 case COL1
: operand
.Value
.OutputRegisterValue
= CVPOperand::OSecondaryColor
; break;
478 case BFC0
: operand
.Value
.OutputRegisterValue
= CVPOperand::OBackFacePrimaryColor
; break;
479 case BFC1
: operand
.Value
.OutputRegisterValue
= CVPOperand::OBackFaceSecondaryColor
; break;
480 case FOGC
: operand
.Value
.OutputRegisterValue
= CVPOperand::OFogCoord
; break;
481 case PSIZ
: operand
.Value
.OutputRegisterValue
= CVPOperand::OPointSize
; break;
482 case TEX0
: operand
.Value
.OutputRegisterValue
= CVPOperand::OTex0
; break;
483 case TEX1
: operand
.Value
.OutputRegisterValue
= CVPOperand::OTex1
; break;
484 case TEX2
: operand
.Value
.OutputRegisterValue
= CVPOperand::OTex2
; break;
485 case TEX3
: operand
.Value
.OutputRegisterValue
= CVPOperand::OTex3
; break;
486 case TEX4
: operand
.Value
.OutputRegisterValue
= CVPOperand::OTex4
; break;
487 case TEX5
: operand
.Value
.OutputRegisterValue
= CVPOperand::OTex5
; break;
488 case TEX6
: operand
.Value
.OutputRegisterValue
= CVPOperand::OTex6
; break;
489 case TEX7
: operand
.Value
.OutputRegisterValue
= CVPOperand::OTex7
; break;
491 errorOutput
= "Can't read index for output register.";
495 skipSpacesAndComments();
496 if (*_CurrChar
!= ']')
498 errorOutput
= "']' expected when parsing an output register.";
505 //=================================================================================================
506 static inline const char *parseUInt(const char *src
, uint
&dest
)
509 while (isdigit(*src
))
511 index
= 10 * index
+ *src
- '0';
519 //=================================================================================================
520 bool CVPParser::parseConstantRegister(CVPOperand
&operand
, std::string
&errorOutput
)
523 operand
.Type
= CVPOperand::Constant
;
524 if (*_CurrChar
!= '[')
526 errorOutput
= "'[' expected when parsing a constant register.";
530 skipSpacesAndComments();
531 sint
&index
= operand
.Value
.ConstantValue
;
532 if (isdigit(*_CurrChar
))
534 // immediat case : c[0] to c[95]
536 _CurrChar
= parseUInt(_CurrChar
, uIndex
);
539 errorOutput
= "Constant register index must range from 0 to 95.";
542 index
= (sint
) uIndex
;
543 operand
.Indexed
= false;
545 else if (*_CurrChar
== 'A')
547 // indexed case : c[A0.x - 64] to c[A0.x + 63]
548 operand
.Indexed
= true;
550 if (_CurrChar
[1] == '0'
551 && _CurrChar
[2] == '.'
552 && _CurrChar
[3] == 'x')
555 skipSpacesAndComments();
556 if (*_CurrChar
== '+')
559 skipSpacesAndComments();
560 if (isdigit(*_CurrChar
))
563 _CurrChar
= parseUInt(_CurrChar
, uIndex
);
566 errorOutput
= "Constant register index must range from -64 to +63.";
569 index
= (sint
) uIndex
;
573 errorOutput
= "Can't parse offset for constant register.";
578 if (*_CurrChar
== '-')
581 skipSpacesAndComments();
582 if (isdigit(*_CurrChar
))
585 _CurrChar
= parseUInt(_CurrChar
, uIndex
);
588 errorOutput
= "Constant register index must range from -64 to +63.";
591 index
= - (sint
) uIndex
;
595 errorOutput
= "Can't parse offset for constant register.";
602 errorOutput
= "Can't parse constant register index.";
606 skipSpacesAndComments();
607 if (*_CurrChar
!= ']')
609 errorOutput
= "']' expected when parsing an input register.";
616 //=================================================================================================
617 bool CVPParser::parseVariableRegister(CVPOperand
&operand
, std::string
&errorOutput
)
620 operand
.Type
= CVPOperand::Variable
;
621 if (!isdigit(*_CurrChar
))
623 errorOutput
= "Can't parse variable register.";
626 uint
&index
= operand
.Value
.VariableValue
;
627 _CurrChar
= parseUInt(_CurrChar
, index
);
630 errorOutput
= "Variable register index must range from 0 to 11.";
636 //=================================================================================================
637 bool CVPParser::parseAddressRegister(CVPOperand
&operand
, std::string
&errorOutput
)
640 operand
.Type
= CVPOperand::AddressRegister
;
641 if (_CurrChar
[0] != '0' || _CurrChar
[1] != '.' || _CurrChar
[2] != 'x')
643 errorOutput
= "Can't parse address register.";
650 //=================================================================================================
651 bool CVPParser::parseOp2(CVPInstruction
&instr
,std::string
&errorOutput
)
653 skipSpacesAndComments();
655 if (!parseOperand(instr
.Dest
, true, errorOutput
)) return false;
656 // Can't write in input or consant register
657 if (instr
.Dest
.Type
== CVPOperand::Constant
|| instr
.Dest
.Type
== CVPOperand::InputRegister
)
659 errorOutput
= "Can't write to a constant or input register";
663 skipSpacesAndComments();
664 if (*_CurrChar
!= ',')
666 errorOutput
= "',' expected.";
670 skipSpacesAndComments();
672 if (!parseOperand(instr
.Src1
, false, errorOutput
)) return false;
673 if (instr
.Src1
.Type
== CVPOperand::AddressRegister
674 || instr
.Src1
.Type
== CVPOperand::OutputRegister
)
676 errorOutput
= "Src1 must be constant, variable, or input register.";
682 //=================================================================================================
683 bool CVPParser::parseOp3(CVPInstruction
&instr
, std::string
&errorOutput
)
685 if (!parseOp2(instr
, errorOutput
)) return false;
686 skipSpacesAndComments();
687 if (*_CurrChar
!= ',')
689 errorOutput
= "',' expected.";
693 skipSpacesAndComments();
695 if (!parseOperand(instr
.Src2
, false, errorOutput
)) return false;
696 if (instr
.Src2
.Type
== CVPOperand::AddressRegister
697 || instr
.Src2
.Type
== CVPOperand::OutputRegister
)
699 errorOutput
= "Src2 must be constant, variable, or input register.";
702 // make sure we do not have 2 =/= contant register as src (or in put register)
704 // 2 constant registers ?
705 if (instr
.Src1
.Type
== CVPOperand::Constant
706 && instr
.Src2
.Type
== CVPOperand::Constant
)
708 // the index must be the same
711 instr
.Src1
.Indexed
== instr
.Src2
.Indexed
712 && instr
.Src1
.Value
.ConstantValue
== instr
.Src2
.Value
.ConstantValue
716 errorOutput
= "Can't read 2 different constant registers in a single instruction.";
721 // 2 input registers ?
722 if (instr
.Src1
.Type
== CVPOperand::InputRegister
723 && instr
.Src2
.Type
== CVPOperand::InputRegister
)
725 // the index must be the same
726 if (instr
.Src1
.Value
.InputRegisterValue
!= instr
.Src2
.Value
.InputRegisterValue
)
728 errorOutput
= "Can't read 2 different input registers in a single instruction.";
735 //=================================================================================================
736 bool CVPParser::parseOp4(CVPInstruction
&instr
, std::string
&errorOutput
)
738 if (!parseOp3(instr
, errorOutput
)) return false;
740 skipSpacesAndComments();
741 if (*_CurrChar
!= ',')
743 errorOutput
= "',' expected.";
747 skipSpacesAndComments();
749 if (!parseOperand(instr
.Src3
, false, errorOutput
)) return false;
750 if (instr
.Src3
.Type
== CVPOperand::AddressRegister
751 || instr
.Src3
.Type
== CVPOperand::OutputRegister
)
753 errorOutput
= "Src3 must be constant, variable, or input register.";
757 ///////////////////////////////////////////////////
758 // check for different contant / input registers //
759 ///////////////////////////////////////////////////
761 // Duplicated constant register
762 if (instr
.Src3
.Type
== CVPOperand::Constant
)
764 if (instr
.Src1
.Type
== CVPOperand::Constant
)
768 instr
.Src1
.Indexed
== instr
.Src3
.Indexed
769 && instr
.Src1
.Value
.ConstantValue
== instr
.Src3
.Value
.ConstantValue
773 errorOutput
= "Can't read 2 different constant registers in a single instruction.";
777 if (instr
.Src2
.Type
== CVPOperand::Constant
)
781 instr
.Src2
.Indexed
== instr
.Src3
.Indexed
782 && instr
.Src2
.Value
.ConstantValue
== instr
.Src3
.Value
.ConstantValue
786 errorOutput
= "Can't read 2 different constant registers in a single instruction.";
792 // Duplicated input register
793 if (instr
.Src3
.Type
== CVPOperand::InputRegister
)
795 if (instr
.Src1
.Type
== CVPOperand::InputRegister
)
797 if (instr
.Src1
.Value
.InputRegisterValue
!= instr
.Src3
.Value
.InputRegisterValue
)
799 errorOutput
= "Can't read 2 different input registers in a single instruction.";
803 if (instr
.Src2
.Type
== CVPOperand::InputRegister
)
805 if (instr
.Src2
.Value
.InputRegisterValue
!= instr
.Src3
.Value
.InputRegisterValue
)
807 errorOutput
= "Can't read 2 different input registers in a single instruction.";
817 //=================================================================================================
818 bool CVPParser::parseInstruction(CVPInstruction
&instr
, std::string
&errorOutput
, bool &endEncountered
)
820 skipSpacesAndComments();
821 endEncountered
= false;
824 for(k
= 0; k
< 4; ++k
)
826 if (!isalnum(*_CurrChar
))
828 if (k
< 3) // at least 3 letter in an instruction
830 errorOutput
= "Syntax error : can't read opcode.";
835 instrStr
|= ((uint
) *_CurrChar
) << (8 * (3 - k
));
840 instrStr
|= (uint32
) ' ';
842 switch ((TArguments
)instrStr
)
845 instr
.Opcode
= CVPInstruction::ARL
;
846 if (!parseOp2(instr
, errorOutput
)) return false;
847 if (!instr
.Src1
.Swizzle
.isScalar())
849 errorOutput
= "ARL need a scalar src value.";
854 instr
.Opcode
= CVPInstruction::RSQ
;
855 if (!parseOp2(instr
, errorOutput
)) return false;
856 if (!instr
.Src1
.Swizzle
.isScalar())
858 errorOutput
= "RSQ need a scalar src value.";
864 instr
.Opcode
= CVPInstruction::EXPP
;
865 if (!parseOp2(instr
, errorOutput
)) return false;
866 if (!instr
.Src1
.Swizzle
.isScalar())
868 errorOutput
= "EXP need a scalar src value.";
872 if (instr.Src1.Swizzle.Comp[0] != CVPSwizzle.W)
874 errorOutput = "EXPP input scalar must be w";
879 instr
.Opcode
= CVPInstruction::LOG
;
880 if (!parseOp2(instr
, errorOutput
)) return false;
881 if (!instr
.Src1
.Swizzle
.isScalar())
883 errorOutput
= "LOG need a scalar src value.";
887 if (instr.Src1.Swizzle.Comp[0] != CVPSwizzle.W)
889 errorOutput = "LOG input scalar must be w";
895 instr
.Opcode
= CVPInstruction::RCP
;
896 if (!parseOp2(instr
, errorOutput
)) return false;
897 if (!instr
.Src1
.Swizzle
.isScalar())
899 errorOutput
= "RCP need a scalar src value.";
905 instr
.Opcode
= CVPInstruction::MOV
;
906 if (!parseOp2(instr
, errorOutput
)) return false;
910 instr
.Opcode
= CVPInstruction::LIT
;
911 if (!parseOp2(instr
, errorOutput
)) return false;
915 instr
.Opcode
= CVPInstruction::MAD
;
916 if (!parseOp4(instr
, errorOutput
)) return false;
920 instr
.Opcode
= CVPInstruction::ADD
;
921 if (!parseOp3(instr
, errorOutput
)) return false;
925 instr
.Opcode
= CVPInstruction::MUL
;
926 if (!parseOp3(instr
, errorOutput
)) return false;
929 instr
.Opcode
= CVPInstruction::DP3
;
930 if (!parseOp3(instr
, errorOutput
)) return false;
933 instr
.Opcode
= CVPInstruction::DP4
;
934 if (!parseOp3(instr
, errorOutput
)) return false;
937 instr
.Opcode
= CVPInstruction::DST
;
938 if (!parseOp3(instr
, errorOutput
)) return false;
941 instr
.Opcode
= CVPInstruction::MIN
;
942 if (!parseOp3(instr
, errorOutput
)) return false;
945 instr
.Opcode
= CVPInstruction::MAX
;
946 if (!parseOp3(instr
, errorOutput
)) return false;
949 instr
.Opcode
= CVPInstruction::SLT
;
950 if (!parseOp3(instr
, errorOutput
)) return false;
953 instr
.Opcode
= CVPInstruction::SGE
;
954 if (!parseOp3(instr
, errorOutput
)) return false;
958 endEncountered
= true;
962 errorOutput
= "Syntax error : unknow opcode.";
968 if (instr
.Dest
.Type
== CVPOperand::Variable
)
970 _RegisterMask
[instr
.Dest
.Value
.VariableValue
] |= instr
.Dest
.WriteMask
;
973 // it is not allowed to write to an adress register except for ARL
974 if (instrStr
!= NELID("ARL "))
976 if (instr
.Dest
.Type
== CVPOperand::AddressRegister
)
978 errorOutput
= "Can't write to address register.";
984 skipSpacesAndComments();
986 if (*_CurrChar
!= ';')
988 errorOutput
= "';' expected.";
996 //=================================================================================================
997 bool CVPParser::isInputUsed(const TProgram
&prg
, CVPOperand::EInputRegister input
)
999 for(uint k
= 0; k
< prg
.size(); ++k
)
1001 uint numSrc
= prg
[k
].getNumUsedSrc();
1002 for(uint l
= 0; l
< numSrc
; ++l
)
1004 const CVPOperand
&src
= prg
[k
].getSrc(l
);
1005 if (src
.Type
== CVPOperand::InputRegister
&& src
.Value
.InputRegisterValue
== input
) return true;
1011 //=================================================================================================
1012 static std::string
getStringUntilCR(const char *src
)
1016 while (*src
!= '\n' && *src
!= '\r' && *src
!= '\0')
1024 //=================================================================================================
1025 bool CVPParser::parse(const char *src
, CVPParser::TProgram
&result
, std::string
&errorOutput
)
1027 if (!src
) return false;
1029 std::fill(_RegisterMask
, _RegisterMask
+ 96, 0);
1036 //skipSpacesAndComments(); // in fact space are not allowed at the start of the vertex program
1039 if ( _CurrChar
[0] != '!'
1040 || _CurrChar
[1] != '!'
1041 || _CurrChar
[2] != 'V'
1042 || _CurrChar
[3] != 'P'
1043 || _CurrChar
[4] != '1'
1044 || _CurrChar
[5] != '.'
1045 || (_CurrChar
[6] != '0' && _CurrChar
[6] != '1'))
1047 errorOutput
= "Can't parse version.";
1052 errorOutput
.clear();
1053 // parse instructions
1054 bool endEncoutered
= false;
1056 std::string errorMess
;
1059 CVPInstruction instr
;
1060 if (!parseInstruction(instr
, errorMess
, endEncoutered
))
1062 errorOutput
= std::string("CVPParser::parse : Error encountered at line ") + NLMISC::toString(_LineIndex
) + std::string(" : ") + errorMess
+ std::string(" Text : ") + getStringUntilCR(_LineStart
);
1065 if (endEncoutered
) break;
1066 result
.push_back(instr
);
1072 //=================================================================================================
1073 static const char *instrToName
[] =
1094 //=================================================================================================
1095 static const char *outputRegisterToName
[] =
1115 //=================================================================================================
1116 static void dumpWriteMask(uint mask
, std::string
&out
)
1124 if (mask
& 1) out
+="x";
1125 if (mask
& 2) out
+="y";
1126 if (mask
& 4) out
+="z";
1127 if (mask
& 8) out
+="w";
1130 //=================================================================================================
1131 static void dumpSwizzle(const CVPSwizzle
&swz
, std::string
&out
)
1133 if (swz
.isIdentity())
1139 for(uint k
= 0; k
< 4; ++k
)
1143 case CVPSwizzle::X
: out
+= "x"; break;
1144 case CVPSwizzle::Y
: out
+= "y"; break;
1145 case CVPSwizzle::Z
: out
+= "z"; break;
1146 case CVPSwizzle::W
: out
+= "w"; break;
1151 if (swz
.isScalar() && k
== 0) break;
1156 //=================================================================================================
1157 static void dumpOperand(const CVPOperand
&op
, bool destOperand
, std::string
&out
)
1159 out
= op
.Negate
? " -" : " ";
1162 case CVPOperand::Variable
: out
+= "R" + NLMISC::toString(op
.Value
.VariableValue
); break;
1163 case CVPOperand::Constant
:
1169 out
+= NLMISC::toString(op
.Value
.ConstantValue
) + "]";
1171 case CVPOperand::InputRegister
: out
+= "v[" + NLMISC::toString((uint
) op
.Value
.InputRegisterValue
) + "]"; break;
1172 case CVPOperand::OutputRegister
:
1173 nlassert(op
.Value
.OutputRegisterValue
< CVPOperand::OutputRegisterCount
);
1174 out
+= "o[" + std::string(outputRegisterToName
[op
.Value
.OutputRegisterValue
]) + "]";
1176 case CVPOperand::AddressRegister
:
1185 dumpWriteMask(op
.WriteMask
, suffix
);
1189 dumpSwizzle(op
.Swizzle
, suffix
);
1194 //=================================================================================================
1195 /** Dump an instruction in a string
1197 static void dumpInstr(const CVPInstruction
&instr
, std::string
&out
)
1199 nlassert(instr
.Opcode
< CVPInstruction::OpcodeCount
);
1200 out
= instrToName
[instr
.Opcode
];
1201 uint nbOp
= instr
.getNumUsedSrc();
1202 std::string destOperand
;
1203 dumpOperand(instr
.Dest
, true, destOperand
);
1205 for(uint k
= 0; k
< nbOp
; ++k
)
1208 std::string srcOperand
;
1209 dumpOperand(instr
.getSrc(k
), false, srcOperand
);
1215 //=================================================================================================
1216 void CVPParser::dump(const TProgram
&prg
, std::string
&dest
)
1218 dest
= "!!VP1.0 \n";
1219 for(uint k
= 0; k
< prg
.size(); ++k
)
1222 dumpInstr(prg
[k
], instr
);