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;
                }
            }
        }
Beispiel #2
0
        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);
            }
        }