private void ParseAssignmentInstruction(D3D9Instruction instruction) { var newOutputs = new Dictionary <RegisterComponentKey, HlslTreeNode>(); RegisterComponentKey[] destinationKeys = GetDestinationKeys(instruction).ToArray(); foreach (RegisterComponentKey destinationKey in destinationKeys) { HlslTreeNode instructionTree = CreateInstructionTree(instruction, destinationKey); newOutputs[destinationKey] = instructionTree; } foreach (var output in newOutputs) { if (instruction.Opcode == Opcode.TexKill) { _noOutputInstructions[output.Key.RegisterKey] = output.Value; } else { _activeOutputs[output.Key] = output.Value; } } }
private void WriteInstruction(D3D9Instruction instruction) { switch (instruction.Opcode) { case Opcode.Abs: WriteLine("{0} = abs({1});", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Add: WriteLine("{0} = {1} + {2};", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Cmp: // TODO: should be per-component WriteLine("{0} = ({1} >= 0) ? {2} : {3};", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3)); break; case Opcode.DP2Add: WriteLine("{0} = dot({1}, {2}) + {3};", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3)); break; case Opcode.Dp3: WriteLine("{0} = dot({1}, {2});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Dp4: WriteLine("{0} = dot({1}, {2});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Else: indent = indent.Substring(0, indent.Length - 1); WriteLine("} else {"); indent += "\t"; break; case Opcode.Endif: indent = indent.Substring(0, indent.Length - 1); WriteLine("}"); break; case Opcode.EndLoop: case Opcode.EndRep: indent = indent.Substring(0, indent.Length - 1); WriteLine("}"); _loopVariableIndex--; break; case Opcode.Exp: WriteLine("{0} = exp2({1});", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Frc: WriteLine("{0} = frac({1});", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.If: WriteLine("if ({0}) {{", GetSourceName(instruction, 0)); indent += "\t"; break; case Opcode.IfC: if ((IfComparison)instruction.Modifier == IfComparison.GE && instruction.GetSourceModifier(0) == SourceModifier.AbsAndNegate && instruction.GetSourceModifier(1) == SourceModifier.Abs && instruction.GetParamRegisterName(0) + instruction.GetSourceSwizzleName(0) == instruction.GetParamRegisterName(1) + instruction.GetSourceSwizzleName(1)) { WriteLine("if ({0} == 0) {{", instruction.GetParamRegisterName(0) + instruction.GetSourceSwizzleName(0)); } else if ((IfComparison)instruction.Modifier == IfComparison.LT && instruction.GetSourceModifier(0) == SourceModifier.AbsAndNegate && instruction.GetSourceModifier(1) == SourceModifier.Abs && instruction.GetParamRegisterName(0) + instruction.GetSourceSwizzleName(0) == instruction.GetParamRegisterName(1) + instruction.GetSourceSwizzleName(1)) { WriteLine("if ({0} != 0) {{", instruction.GetParamRegisterName(0) + instruction.GetSourceSwizzleName(0)); } else { string ifComparison; switch ((IfComparison)instruction.Modifier) { case IfComparison.GT: ifComparison = ">"; break; case IfComparison.EQ: ifComparison = "=="; break; case IfComparison.GE: ifComparison = ">="; break; case IfComparison.LE: ifComparison = "<="; break; case IfComparison.NE: ifComparison = "!="; break; case IfComparison.LT: ifComparison = "<"; break; default: throw new InvalidOperationException(); } WriteLine("if ({0} {2} {1}) {{", GetSourceName(instruction, 0), GetSourceName(instruction, 1), ifComparison); } indent += "\t"; break; case Opcode.Log: WriteLine("{0} = log2({1});", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Loop: ConstantIntRegister intRegister = _registers.FindConstantIntRegister(instruction.GetParamRegisterNumber(1)); uint end = intRegister.Value[0]; uint start = intRegister.Value[1]; uint stride = intRegister.Value[2]; _loopVariableIndex++; string loopVariable = "i" + _loopVariableIndex; if (stride == 1) { WriteLine("for (int {2} = {0}; {2} < {1}; {2}++) {{", start, end, loopVariable); } else { WriteLine("for (int {3} = {0}; {3} < {1}; {3} += {2}) {{", start, end, stride, loopVariable); } indent += "\t"; break; case Opcode.Lrp: WriteLine("{0} = lerp({2}, {3}, {1});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3)); break; case Opcode.Mad: WriteLine("{0} = {1} * {2} + {3};", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3)); break; case Opcode.Max: WriteLine("{0} = max({1}, {2});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Min: WriteLine("{0} = min({1}, {2});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Mov: WriteLine("{0} = {1};", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.MovA: WriteLine("{0} = {1};", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Mul: WriteLine("{0} = {1} * {2};", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Nrm: WriteLine("{0} = normalize({1});", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Pow: WriteLine("{0} = pow({1}, {2});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Rcp: WriteLine("{0} = 1 / {1};", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Rep: ConstantIntRegister loopRegister = _registers.FindConstantIntRegister(instruction.GetParamRegisterNumber(0)); _loopVariableIndex++; WriteLine("for (int {1} = 0; {1} < {0}; {1}++) {{", loopRegister[0], "i" + _loopVariableIndex); indent += "\t"; break; case Opcode.Rsq: WriteLine("{0} = 1 / sqrt({1});", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Sge: if (instruction.GetSourceModifier(1) == SourceModifier.AbsAndNegate && instruction.GetSourceModifier(2) == SourceModifier.Abs && instruction.GetParamRegisterName(1) + instruction.GetSourceSwizzleName(1) == instruction.GetParamRegisterName(2) + instruction.GetSourceSwizzleName(2)) { WriteLine("{0} = ({1} == 0) ? 1 : 0;", GetDestinationName(instruction), instruction.GetParamRegisterName(1) + instruction.GetSourceSwizzleName(1)); } else { WriteLine("{0} = ({1} >= {2}) ? 1 : 0;", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); } break; case Opcode.Slt: WriteLine("{0} = ({1} < {2}) ? 1 : 0;", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.SinCos: WriteLine("sincos({1}, {0}, {0});", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Sub: WriteLine("{0} = {1} - {2};", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Tex: if ((_shader.MajorVersion == 1 && _shader.MinorVersion >= 4) || (_shader.MajorVersion > 1)) { WriteLine("{0} = tex2D({2}, {1});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); } else { WriteLine("{0} = tex2D();", GetDestinationName(instruction)); } break; case Opcode.TexLDL: WriteLine("{0} = tex2Dlod({2}, {1});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.TexKill: WriteLine("clip({0});", GetDestinationName(instruction)); break; case Opcode.Def: case Opcode.DefB: case Opcode.DefI: case Opcode.Dcl: case Opcode.Comment: case Opcode.End: break; default: break; } }
private HlslTreeNode CreateInstructionTree(D3D9Instruction instruction, RegisterComponentKey destinationKey) { int componentIndex = destinationKey.ComponentIndex; switch (instruction.Opcode) { case Opcode.Dcl: { var shaderInput = new RegisterInputNode(destinationKey); return(shaderInput); } case Opcode.Def: { var constant = new ConstantNode(instruction.GetParamSingle(componentIndex + 1)); return(constant); } case Opcode.DefI: { var constant = new ConstantNode(instruction.GetParamInt(componentIndex + 1)); return(constant); } case Opcode.DefB: { throw new NotImplementedException(); } case Opcode.Abs: case Opcode.Add: case Opcode.Cmp: case Opcode.Frc: case Opcode.Lrp: case Opcode.Mad: case Opcode.Max: case Opcode.Min: case Opcode.Mov: case Opcode.Mul: case Opcode.Pow: case Opcode.Rcp: case Opcode.Rsq: case Opcode.SinCos: case Opcode.Sge: case Opcode.Slt: case Opcode.TexKill: { HlslTreeNode[] inputs = GetInputs(instruction, componentIndex); switch (instruction.Opcode) { case Opcode.Abs: return(new AbsoluteOperation(inputs[0])); case Opcode.Cmp: return(new CompareOperation(inputs[0], inputs[1], inputs[2])); case Opcode.Frc: return(new FractionalOperation(inputs[0])); case Opcode.Lrp: return(new LinearInterpolateOperation(inputs[0], inputs[1], inputs[2])); case Opcode.Max: return(new MaximumOperation(inputs[0], inputs[1])); case Opcode.Min: return(new MinimumOperation(inputs[0], inputs[1])); case Opcode.Mov: return(new MoveOperation(inputs[0])); case Opcode.Add: return(new AddOperation(inputs[0], inputs[1])); case Opcode.Mul: return(new MultiplyOperation(inputs[0], inputs[1])); case Opcode.Mad: return(new MultiplyAddOperation(inputs[0], inputs[1], inputs[2])); case Opcode.Pow: return(new PowerOperation(inputs[0], inputs[1])); case Opcode.Rcp: return(new ReciprocalOperation(inputs[0])); case Opcode.Rsq: return(new ReciprocalSquareRootOperation(inputs[0])); case Opcode.SinCos: if (componentIndex == 0) { return(new CosineOperation(inputs[0])); } return(new SineOperation(inputs[0])); case Opcode.Sge: return(new SignGreaterOrEqualOperation(inputs[0], inputs[1])); case Opcode.Slt: return(new SignLessOperation(inputs[0], inputs[1])); case Opcode.TexKill: return(new ClipOperation(inputs[0])); default: throw new NotImplementedException(); } } case Opcode.Tex: case Opcode.TexLDL: return(CreateTextureLoadOutputNode(instruction, componentIndex)); case Opcode.DP2Add: return(CreateDotProduct2AddNode(instruction)); case Opcode.Dp3: case Opcode.Dp4: return(CreateDotProductNode(instruction)); case Opcode.Nrm: return(CreateNormalizeOutputNode(instruction, componentIndex)); default: throw new NotImplementedException($"{instruction.Opcode} not implemented"); } }
public static void Verify(D3D9Instruction instruction) { //Assert(currentInstruction.Modifier == 0); Assert(!instruction.Predicated); switch (instruction.Opcode) { case Opcode.Dcl: // https://msdn.microsoft.com/en-us/library/windows/hardware/ff549176(v=vs.85).aspx Assert(instruction.Params.Count == 2); uint param0 = instruction.Params[0]; switch (instruction.GetParamRegisterType(1)) { case RegisterType.Sampler: Assert((param0 & 0x07FFFFFF) == 0); break; case RegisterType.Input: case RegisterType.Output: case RegisterType.Texture: Assert((param0 & 0x0000FFF0) == 0); Assert((param0 & 0x7FF00000) == 0); break; } Assert((param0 & 0x80000000) != 0); break; case Opcode.Def: { Assert(instruction.Params.Count == 5); var registerType = instruction.GetParamRegisterType(0); Assert( registerType == RegisterType.Const || registerType == RegisterType.Const2 || registerType == RegisterType.Const3 || registerType == RegisterType.Const4); } break; case Opcode.DefI: { Assert(instruction.Params.Count == 5); var registerType = instruction.GetParamRegisterType(0); Assert(registerType == RegisterType.ConstInt); } break; case Opcode.IfC: IfComparison comp = (IfComparison)instruction.Modifier; Assert( comp == IfComparison.GT || comp == IfComparison.EQ || comp == IfComparison.GE || comp == IfComparison.LT || comp == IfComparison.NE || comp == IfComparison.LE); break; default: //throw new NotImplementedException(); break; } }
public string GetSourceName(D3D9Instruction instruction, int srcIndex) { string sourceRegisterName; var registerType = instruction.GetParamRegisterType(srcIndex); switch (registerType) { case RegisterType.Const: case RegisterType.Const2: case RegisterType.Const3: case RegisterType.Const4: case RegisterType.ConstBool: case RegisterType.ConstInt: sourceRegisterName = GetSourceConstantName(instruction, srcIndex); if (sourceRegisterName != null) { return(sourceRegisterName); } ParameterType parameterType; switch (registerType) { case RegisterType.Const: case RegisterType.Const2: case RegisterType.Const3: case RegisterType.Const4: parameterType = ParameterType.Float; break; case RegisterType.ConstBool: parameterType = ParameterType.Bool; break; case RegisterType.ConstInt: parameterType = ParameterType.Int; break; default: throw new NotImplementedException(); } int registerNumber = instruction.GetParamRegisterNumber(srcIndex); ConstantDeclaration decl = FindConstant(parameterType, registerNumber); if (decl == null) { // Constant register not found in def statements nor the constant table throw new NotImplementedException(); } if ((decl.ParameterClass == ParameterClass.MatrixRows && ColumnMajorOrder) || (decl.ParameterClass == ParameterClass.MatrixColumns && !ColumnMajorOrder)) { int row = registerNumber - decl.RegisterIndex; sourceRegisterName = $"{decl.Name}[{row}]"; } else if ((decl.ParameterClass == ParameterClass.MatrixColumns && ColumnMajorOrder) || (decl.ParameterClass == ParameterClass.MatrixRows && !ColumnMajorOrder)) { int column = registerNumber - decl.RegisterIndex; sourceRegisterName = $"transpose({decl.Name})[{column}]"; } else { sourceRegisterName = decl.Name; } break; default: RegisterKey registerKey = instruction.GetParamRegisterKey(srcIndex); sourceRegisterName = GetRegisterName(registerKey); break; } sourceRegisterName = sourceRegisterName ?? instruction.GetParamRegisterName(srcIndex); sourceRegisterName += GetRelativeAddressingName(instruction, srcIndex); sourceRegisterName += instruction.GetSourceSwizzleName(srcIndex); return(ApplyModifier(instruction.GetSourceModifier(srcIndex), sourceRegisterName)); }
private string GetSourceConstantName(D3D9Instruction instruction, int srcIndex) { var registerType = instruction.GetParamRegisterType(srcIndex); int registerNumber = instruction.GetParamRegisterNumber(srcIndex); switch (registerType) { case RegisterType.ConstBool: //throw new NotImplementedException(); return(null); case RegisterType.ConstInt: { var constantInt = _constantIntDefinitions.FirstOrDefault(x => x.RegisterIndex == registerNumber); if (constantInt == null) { return(null); } byte[] swizzle = instruction.GetSourceSwizzleComponents(srcIndex); uint[] constant = { constantInt[swizzle[0]], constantInt[swizzle[1]], constantInt[swizzle[2]], constantInt[swizzle[3]] }; switch (instruction.GetSourceModifier(srcIndex)) { case SourceModifier.None: break; case SourceModifier.Negate: throw new NotImplementedException(); /* * for (int i = 0; i < 4; i++) * { * constant[i] = -constant[i]; * }*/ break; default: throw new NotImplementedException(); } int destLength = instruction.GetDestinationMaskLength(); switch (destLength) { case 1: return(constant[0].ToString()); case 2: if (constant[0] == constant[1]) { return(constant[0].ToString()); } return($"int2({constant[0]}, {constant[1]})"); case 3: if (constant[0] == constant[1] && constant[0] == constant[2]) { return(constant[0].ToString()); } return($"int3({constant[0]}, {constant[1]}, {constant[2]})"); case 4: if (constant[0] == constant[1] && constant[0] == constant[2] && constant[0] == constant[3]) { return(constant[0].ToString()); } return($"int4({constant[0]}, {constant[1]}, {constant[2]}, {constant[3]})"); default: throw new InvalidOperationException(); } } case RegisterType.Const: case RegisterType.Const2: case RegisterType.Const3: case RegisterType.Const4: { var constantRegister = _constantDefinitions.FirstOrDefault(x => x.RegisterIndex == registerNumber); if (constantRegister == null) { return(null); } byte[] swizzle = instruction.GetSourceSwizzleComponents(srcIndex); float[] constant = { constantRegister[swizzle[0]], constantRegister[swizzle[1]], constantRegister[swizzle[2]], constantRegister[swizzle[3]] }; switch (instruction.GetSourceModifier(srcIndex)) { case SourceModifier.None: break; case SourceModifier.Negate: for (int i = 0; i < 4; i++) { constant[i] = -constant[i]; } break; default: throw new NotImplementedException(); } int destLength; if (instruction.HasDestination) { destLength = instruction.GetDestinationMaskLength(); } else { if (instruction is D3D9Instruction d3D9Instruction && (d3D9Instruction.Opcode == Opcode.If || d3D9Instruction.Opcode == Opcode.IfC)) { // TODO } destLength = 4; } switch (destLength) { case 1: return(constant[0].ToString(_culture)); case 2: if (constant[0] == constant[1]) { return(constant[0].ToString(_culture)); } return(string.Format("float2({0}, {1})", constant[0].ToString(_culture), constant[1].ToString(_culture))); case 3: if (constant[0] == constant[1] && constant[0] == constant[2]) { return(constant[0].ToString(_culture)); } return(string.Format("float3({0}, {1}, {2})", constant[0].ToString(_culture), constant[1].ToString(_culture), constant[2].ToString(_culture))); case 4: if (constant[0] == constant[1] && constant[0] == constant[2] && constant[0] == constant[3]) { return(constant[0].ToString(_culture)); } return(string.Format("float4({0}, {1}, {2}, {3})", constant[0].ToString(_culture), constant[1].ToString(_culture), constant[2].ToString(_culture), constant[3].ToString(_culture))); default: throw new InvalidOperationException(); } } default: return(null); } }