Exemplo n.º 1
0
        private static bool FindBrxTargets(ShaderConfig config, IEnumerable <Block> blocks, Func <ulong, Block> getBlock)
        {
            bool hasNewTarget = false;

            foreach (Block block in blocks)
            {
                InstOp lastOp  = block.GetLastOp();
                bool   hasNext = block.HasNext();

                if (lastOp.Name == InstName.Brx && block.Successors.Count == (hasNext ? 1 : 0))
                {
                    InstBrx opBrx      = new InstBrx(lastOp.RawOpCode);
                    ulong   baseOffset = lastOp.GetAbsoluteAddress();

                    // An indirect branch could go anywhere,
                    // try to get the possible target offsets from the constant buffer.
                    (int cbBaseOffset, int cbOffsetsCount) = FindBrxTargetRange(block, opBrx.SrcA);

                    if (cbOffsetsCount != 0)
                    {
                        hasNewTarget = true;
                    }

                    for (int i = 0; i < cbOffsetsCount; i++)
                    {
                        uint  targetOffset = config.GpuAccessor.ConstantBuffer1Read(cbBaseOffset + i * 4);
                        Block target       = getBlock(baseOffset + targetOffset);
                        target.Predecessors.Add(block);
                        block.Successors.Add(target);
                    }
                }
            }

            return(hasNewTarget);
        }
Exemplo n.º 2
0
        public static void RunPass(BasicBlock block, ShaderConfig config)
        {
            int sbStart = GetStorageBaseCbOffset(config.Stage);

            int sbEnd = sbStart + StorageDescsSize;

            for (LinkedListNode <INode> node = block.Operations.First; node != null; node = node.Next)
            {
                if (!(node.Value is Operation operation))
                {
                    continue;
                }

                if (UsesGlobalMemory(operation.Inst))
                {
                    Operand source = operation.GetSource(0);

                    if (source.AsgOp is Operation asgOperation)
                    {
                        int storageIndex = SearchForStorageBase(asgOperation, sbStart, sbEnd);

                        if (storageIndex >= 0)
                        {
                            node = ReplaceGlobalWithStorage(node, config, storageIndex);
                        }
                    }
                }
            }
        }
Exemplo n.º 3
0
        static void Main(string[] args)
        {
            if (args.Length == 2)
            {
                GalShaderType type = GalShaderType.Vertex;

                switch (args[0].ToLower())
                {
                case "v":  type = GalShaderType.Vertex;         break;

                case "tc": type = GalShaderType.TessControl;    break;

                case "te": type = GalShaderType.TessEvaluation; break;

                case "g":  type = GalShaderType.Geometry;       break;

                case "f":  type = GalShaderType.Fragment;       break;
                }

                using (FileStream fs = new FileStream(args[1], FileMode.Open, FileAccess.Read))
                {
                    Memory mem = new Memory(fs);

                    ShaderConfig config = new ShaderConfig(type, 65536);

                    string code = Translator.Translate(mem, 0, config).Code;

                    Console.WriteLine(code);
                }
            }
            else
            {
                Console.WriteLine("Usage: Ryujinx.ShaderTools [v|tc|te|g|f] shader.bin");
            }
        }
Exemplo n.º 4
0
        public static GlslProgram Generate(StructuredProgramInfo info, ShaderConfig config)
        {
            CodeGenContext context = new CodeGenContext(info, config);

            Declarations.Declare(context, info);

            if (info.Functions.Count != 0)
            {
                for (int i = 1; i < info.Functions.Count; i++)
                {
                    context.AppendLine($"{GetFunctionSignature(info.Functions[i])};");
                }

                context.AppendLine();

                for (int i = 1; i < info.Functions.Count; i++)
                {
                    PrintFunction(context, info, info.Functions[i]);

                    context.AppendLine();
                }
            }

            PrintFunction(context, info, info.Functions[0], MainFunctionName);

            return(new GlslProgram(
                       context.CBufferDescriptors.ToArray(),
                       context.SBufferDescriptors.ToArray(),
                       context.TextureDescriptors.ToArray(),
                       context.ImageDescriptors.ToArray(),
                       context.GetCode()));
        }
Exemplo n.º 5
0
        public string GetExpression(AstOperand operand, ShaderConfig config, bool cbIndexable)
        {
            switch (operand.Type)
            {
            case OperandType.Argument:
                return(GetArgumentName(operand.Value));

            case OperandType.Attribute:
                return(GetAttributeName(operand, config));

            case OperandType.Constant:
                return(NumberFormatter.FormatInt(operand.Value));

            case OperandType.ConstantBuffer:
                return(GetConstantBufferName(operand.CbufSlot, operand.CbufOffset, config.Stage, cbIndexable));

            case OperandType.LocalVariable:
                return(_locals[operand]);

            case OperandType.Undefined:
                return(DefaultNames.UndefinedName);
            }

            throw new ArgumentException($"Invalid operand type \"{operand.Type}\".");
        }
Exemplo n.º 6
0
        public static string Generate(StructuredProgramInfo info, ShaderConfig config)
        {
            CodeGenContext context = new CodeGenContext(info, config);

            Declarations.Declare(context, info);

            if (info.Functions.Count != 0)
            {
                for (int i = 1; i < info.Functions.Count; i++)
                {
                    context.AppendLine($"{GetFunctionSignature(info.Functions[i])};");
                }

                context.AppendLine();

                for (int i = 1; i < info.Functions.Count; i++)
                {
                    PrintFunction(context, info, info.Functions[i]);

                    context.AppendLine();
                }
            }

            PrintFunction(context, info, info.Functions[0], MainFunctionName);

            return(context.GetCode());
        }
Exemplo n.º 7
0
        private static void SetUserAttributeUses(ShaderConfig config, IOpCodeAttribute opAttr)
        {
            if (opAttr.Indexed)
            {
                if (opAttr.Emitter == InstEmit.Ast)
                {
                    config.SetAllOutputUserAttributes();
                }
                else
                {
                    config.SetAllInputUserAttributes();
                }
            }
            else
            {
                for (int elemIndex = 0; elemIndex < opAttr.Count; elemIndex++)
                {
                    int attr = opAttr.AttributeOffset + elemIndex * 4;
                    if (attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd)
                    {
                        int index = (attr - AttributeConsts.UserAttributeBase) / 16;

                        if (opAttr.Emitter == InstEmit.Ast)
                        {
                            config.SetOutputUserAttribute(index);
                        }
                        else
                        {
                            config.SetInputUserAttribute(index);
                        }
                    }
                }
            }
        }
Exemplo n.º 8
0
        public CodeGenContext(StructuredProgramInfo info, ShaderConfig config)
        {
            _info  = info;
            Config = config;

            OperandManager = new OperandManager();

            _sb = new StringBuilder();
        }
Exemplo n.º 9
0
        private static void FillBlock(ShaderConfig config, Block block, ulong limitAddress, ulong startAddress)
        {
            IGpuAccessor gpuAccessor = config.GpuAccessor;

            ulong address               = block.Address;
            int   bufferOffset          = 0;
            ReadOnlySpan <ulong> buffer = ReadOnlySpan <ulong> .Empty;

            InstOp op = default;

            do
            {
                if (address + 7 >= limitAddress)
                {
                    break;
                }

                // Ignore scheduling instructions, which are written every 32 bytes.
                if ((address & 0x1f) == 0)
                {
                    address += 8;
                    bufferOffset++;
                    continue;
                }

                if (bufferOffset >= buffer.Length)
                {
                    buffer       = gpuAccessor.GetCode(startAddress + address, 8);
                    bufferOffset = 0;
                }

                ulong opCode = buffer[bufferOffset++];

                op = InstTable.GetOp(address, opCode);

                if (op.Props.HasFlag(InstProps.TexB))
                {
                    config.SetUsedFeature(FeatureFlags.Bindless);
                }

                if (op.Name == InstName.Ald || op.Name == InstName.Ast || op.Name == InstName.Ipa)
                {
                    SetUserAttributeUses(config, op.Name, opCode);
                }
                else if (op.Name == InstName.Ssy || op.Name == InstName.Pbk)
                {
                    block.AddPushOp(op);
                }

                block.OpCodes.Add(op);

                address += 8;
            }while (!op.Props.HasFlag(InstProps.Bra));

            block.EndAddress = address;
        }
Exemplo n.º 10
0
        public static void RunPass(BasicBlock block, ShaderConfig config)
        {
            // We can turn a bindless into regular access by recognizing the pattern
            // produced by the compiler for separate texture and sampler.
            // We check for the following conditions:
            // - The handle is the result of a bitwise OR logical operation.
            // - Both sources of the OR operation comes from CB2 (used by NVN to hold texture handles).
            for (LinkedListNode <INode> node = block.Operations.First; node != null; node = node.Next)
            {
                if (!(node.Value is TextureOperation texOp))
                {
                    continue;
                }

                if ((texOp.Flags & TextureFlags.Bindless) == 0)
                {
                    continue;
                }

                if (texOp.Inst == Instruction.TextureSample)
                {
                    if (!(texOp.GetSource(0).AsgOp is Operation handleCombineOp))
                    {
                        continue;
                    }

                    if (handleCombineOp.Inst != Instruction.BitwiseOr)
                    {
                        continue;
                    }

                    Operand src0 = handleCombineOp.GetSource(0);
                    Operand src1 = handleCombineOp.GetSource(1);

                    if (src0.Type != OperandType.ConstantBuffer || src0.GetCbufSlot() != NvnTextureBufferSlot ||
                        src1.Type != OperandType.ConstantBuffer || src1.GetCbufSlot() != NvnTextureBufferSlot)
                    {
                        continue;
                    }

                    texOp.SetHandle(src0.GetCbufOffset() | (src1.GetCbufOffset() << 16));
                }
                else if (texOp.Inst == Instruction.ImageLoad || texOp.Inst == Instruction.ImageStore)
                {
                    Operand src0 = texOp.GetSource(0);

                    if (src0.Type == OperandType.ConstantBuffer && src0.GetCbufSlot() == NvnTextureBufferSlot)
                    {
                        texOp.SetHandle(src0.GetCbufOffset());
                        texOp.Format = config.GetTextureFormat(texOp.Handle);
                    }
                }
            }
        }
Exemplo n.º 11
0
        public CodeGenContext(ShaderConfig config)
        {
            Config = config;

            CBufferDescriptors = new List <CBufferDescriptor>();
            TextureDescriptors = new List <TextureDescriptor>();

            OperandManager = new OperandManager();

            _sb = new StringBuilder();
        }
Exemplo n.º 12
0
        private static void SetHandle(ShaderConfig config, TextureOperation texOp, int cbufOffset, int cbufSlot, bool rewriteSamplerType)
        {
            texOp.SetHandle(cbufOffset, cbufSlot);

            if (rewriteSamplerType)
            {
                texOp.Type = config.GpuAccessor.QuerySamplerType(cbufOffset, cbufSlot);
            }

            config.SetUsedTexture(texOp.Inst, texOp.Type, texOp.Format, texOp.Flags, cbufSlot, cbufOffset);
        }
Exemplo n.º 13
0
        private static int FixedFuncToUserAttribute(ShaderConfig config, int attr, bool isOutput)
        {
            if (attr >= AttributeConsts.FrontColorDiffuseR && attr < AttributeConsts.ClipDistance0)
            {
                attr = FixedFuncToUserAttribute(config, attr, AttributeConsts.FrontColorDiffuseR, 0, isOutput);
            }
            else if (attr >= AttributeConsts.TexCoordBase && attr < AttributeConsts.TexCoordEnd)
            {
                attr = FixedFuncToUserAttribute(config, attr, AttributeConsts.TexCoordBase, 4, isOutput);
            }

            return(attr);
        }
Exemplo n.º 14
0
        public static GlslProgram Generate(StructuredProgramInfo info, ShaderConfig config)
        {
            CodeGenContext context = new CodeGenContext(config);

            Declarations.Declare(context, info);

            PrintMainBlock(context, info);

            return(new GlslProgram(
                       context.CBufferDescriptors.ToArray(),
                       context.TextureDescriptors.ToArray(),
                       context.GetCode()));
        }
Exemplo n.º 15
0
 public string GetExpression(AstOperand operand, ShaderConfig config)
 {
     return(operand.Type switch
     {
         OperandType.Argument => GetArgumentName(operand.Value),
         OperandType.Attribute => GetAttributeName(operand.Value, config, perPatch: false),
         OperandType.AttributePerPatch => GetAttributeName(operand.Value, config, perPatch: true),
         OperandType.Constant => NumberFormatter.FormatInt(operand.Value),
         OperandType.ConstantBuffer => GetConstantBufferName(operand, config),
         OperandType.LocalVariable => _locals[operand],
         OperandType.Undefined => DefaultNames.UndefinedName,
         _ => throw new ArgumentException($"Invalid operand type \"{operand.Type}\".")
     });
Exemplo n.º 16
0
        public CodeGenContext(ShaderConfig config, bool cbIndexable)
        {
            Config      = config;
            CbIndexable = cbIndexable;

            CBufferDescriptors = new List <BufferDescriptor>();
            SBufferDescriptors = new List <BufferDescriptor>();
            TextureDescriptors = new List <TextureDescriptor>();
            ImageDescriptors   = new List <TextureDescriptor>();

            OperandManager = new OperandManager();

            _sb = new StringBuilder();
        }
Exemplo n.º 17
0
        public CodeGenContext(StructuredProgramInfo info, ShaderConfig config)
        {
            _info  = info;
            Config = config;

            CBufferDescriptors = new List <BufferDescriptor>();
            SBufferDescriptors = new List <BufferDescriptor>();
            TextureDescriptors = new List <TextureDescriptor>();
            ImageDescriptors   = new List <TextureDescriptor>();

            OperandManager = new OperandManager();

            _sb = new StringBuilder();
        }
Exemplo n.º 18
0
        public static void RunPass(BasicBlock[] blocks, ShaderConfig config)
        {
            RunOptimizationPasses(blocks);

            // Those passes are looking for specific patterns and only needs to run once.
            for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
            {
                GlobalToStorage.RunPass(blocks[blkIndex], config);
                BindlessToIndexed.RunPass(blocks[blkIndex]);
                BindlessElimination.RunPass(blocks[blkIndex], config);
            }

            // Run optimizations one last time to remove any code that is now optimizable after above passes.
            RunOptimizationPasses(blocks);
        }
Exemplo n.º 19
0
        public static void RunPass(BasicBlock block, ShaderConfig config)
        {
            int sbStart = GetStorageBaseCbOffset(config.Stage);

            int sbEnd = sbStart + StorageDescsSize;

            for (LinkedListNode <INode> node = block.Operations.First; node != null; node = node.Next)
            {
                if (!(node.Value is Operation operation))
                {
                    continue;
                }

                if (UsesGlobalMemory(operation.Inst))
                {
                    Operand source = operation.GetSource(0);

                    if (source.AsgOp is Operation asgOperation)
                    {
                        int storageIndex = SearchForStorageBase(asgOperation, sbStart, sbEnd);

                        if (storageIndex >= 0)
                        {
                            // Storage buffers are implemented using global memory access.
                            // If we know from where the base address of the access is loaded,
                            // we can guess which storage buffer it is accessing.
                            // We can then replace the global memory access with a storage
                            // buffer access.
                            node = ReplaceGlobalWithStorage(node, config, storageIndex);
                        }
                        else if (config.Stage == ShaderStage.Compute && operation.Inst == Instruction.LoadGlobal)
                        {
                            // Here we effectively try to replace a LDG instruction with LDC.
                            // The hardware only supports a limited amount of constant buffers
                            // so NVN "emulates" more constant buffers using global memory access.
                            // Here we try to replace the global access back to a constant buffer
                            // load.
                            storageIndex = SearchForStorageBase(asgOperation, UbeBaseOffset, UbeBaseOffset + UbeDescsSize);

                            if (storageIndex >= 0)
                            {
                                node = ReplaceLdgWithLdc(node, config, storageIndex);
                            }
                        }
                    }
                }
            }
        }
Exemplo n.º 20
0
 public string GetExpression(AstOperand operand, ShaderConfig config)
 {
     return(operand.Type switch
     {
         OperandType.Argument => GetArgumentName(operand.Value),
         OperandType.Attribute => GetAttributeName(operand, config),
         OperandType.Constant => NumberFormatter.FormatInt(operand.Value),
         OperandType.ConstantBuffer => GetConstantBufferName(
             operand.CbufSlot,
             operand.CbufOffset,
             config.Stage,
             config.UsedFeatures.HasFlag(FeatureFlags.CbIndexing)),
         OperandType.LocalVariable => _locals[operand],
         OperandType.Undefined => DefaultNames.UndefinedName,
         _ => throw new ArgumentException($"Invalid operand type \"{operand.Type}\".")
     });
Exemplo n.º 21
0
        public static byte[] Generate(StructuredProgramInfo info, ShaderConfig config)
        {
            CodeGenContext context = new CodeGenContext(config);

            context.AddCapability(Capability.GroupNonUniformBallot);
            context.AddCapability(Capability.ImageBuffer);
            context.AddCapability(Capability.SampledBuffer);
            context.AddCapability(Capability.SubgroupBallotKHR);
            context.AddCapability(Capability.SubgroupVoteKHR);
            context.AddExtension("SPV_KHR_shader_ballot");
            context.AddExtension("SPV_KHR_subgroup_vote");

            Declarations.DeclareAll(context, info);

            if ((info.HelperFunctionsMask & NeedsInvocationIdMask) != 0)
            {
                Declarations.DeclareInvocationId(context);
            }

            for (int funcIndex = 0; funcIndex < info.Functions.Count; funcIndex++)
            {
                var function = info.Functions[funcIndex];
                var retType  = context.GetType(function.ReturnType.Convert());

                var funcArgs = new SpvInstruction[function.InArguments.Length + function.OutArguments.Length];

                for (int argIndex = 0; argIndex < funcArgs.Length; argIndex++)
                {
                    var argType        = context.GetType(function.GetArgumentType(argIndex).Convert());
                    var argPointerType = context.TypePointer(StorageClass.Function, argType);
                    funcArgs[argIndex] = argPointerType;
                }

                var funcType = context.TypeFunction(retType, false, funcArgs);
                var spvFunc  = context.Function(retType, FunctionControlMask.MaskNone, funcType);

                context.DeclareFunction(funcIndex, function, spvFunc);
            }

            for (int funcIndex = 0; funcIndex < info.Functions.Count; funcIndex++)
            {
                Generate(context, info, funcIndex);
            }

            return(context.Generate());
        }
Exemplo n.º 22
0
        private static int FixedFuncToUserAttribute(ShaderConfig config, int attr, int baseAttr, int baseIndex, bool isOutput)
        {
            int index         = (attr - baseAttr) >> 4;
            int userAttrIndex = config.GetFreeUserAttribute(isOutput, index);

            if ((uint)userAttrIndex < Constants.MaxAttributes)
            {
                userAttrIndex += baseIndex;
                attr           = AttributeConsts.UserAttributeBase + userAttrIndex * 16 + (attr & 0xf);

                if (isOutput)
                {
                    config.SetOutputUserAttributeFixedFunc(userAttrIndex);
                }
                else
                {
                    config.SetInputUserAttributeFixedFunc(userAttrIndex);
                }
            }

            return(attr);
        }
Exemplo n.º 23
0
        private OglShaderStage ShaderStageFactory(
            IGalMemory memory,
            long position,
            long positionB,
            bool isDualVp,
            GalShaderType type)
        {
            ShaderConfig config = new ShaderConfig(type, OglLimit.MaxUboSize);

            ShaderProgram program;

            if (isDualVp)
            {
                ShaderDumper.Dump(memory, position, type, "a");
                ShaderDumper.Dump(memory, positionB, type, "b");

                program = Translator.Translate(memory, (ulong)position, (ulong)positionB, config);
            }
            else
            {
                ShaderDumper.Dump(memory, position, type);

                program = Translator.Translate(memory, (ulong)position, config);
            }

            string code = program.Code;

            if (ShaderDumper.IsDumpEnabled())
            {
                int shaderDumpIndex = ShaderDumper.DumpIndex;

                code = "//Shader " + shaderDumpIndex + Environment.NewLine + code;
            }

            return(new OglShaderStage(type, code, program.Info.CBuffers, program.Info.Textures));
        }
Exemplo n.º 24
0
        public static void RunPass(BasicBlock[] blocks, ShaderConfig config)
        {
            for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
            {
                GlobalToStorage.RunPass(blocks[blkIndex], config);
            }

            bool modified;

            do
            {
                modified = false;

                for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
                {
                    BasicBlock block = blocks[blkIndex];

                    LinkedListNode <INode> node = block.Operations.First;

                    while (node != null)
                    {
                        LinkedListNode <INode> nextNode = node.Next;

                        bool isUnused = IsUnused(node.Value);

                        if (!(node.Value is Operation operation) || isUnused)
                        {
                            if (isUnused)
                            {
                                RemoveNode(block, node);

                                modified = true;
                            }

                            node = nextNode;

                            continue;
                        }

                        ConstantFolding.RunPass(operation);

                        Simplification.RunPass(operation);

                        if (DestIsLocalVar(operation))
                        {
                            if (operation.Inst == Instruction.Copy)
                            {
                                PropagateCopy(operation);

                                RemoveNode(block, node);

                                modified = true;
                            }
                            else if ((operation.Inst == Instruction.PackHalf2x16 && PropagatePack(operation)) ||
                                     (operation.Inst == Instruction.ShuffleXor && MatchDdxOrDdy(operation)))
                            {
                                if (operation.Dest.UseOps.Count == 0)
                                {
                                    RemoveNode(block, node);
                                }

                                modified = true;
                            }
                        }

                        node = nextNode;
                    }

                    if (BranchElimination.RunPass(block))
                    {
                        RemoveNode(block, block.Operations.Last);

                        modified = true;
                    }
                }
            }while (modified);

            for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
            {
                BindlessToIndexed.RunPass(blocks[blkIndex]);
                BindlessElimination.RunPass(blocks[blkIndex]);

                // Try to eliminate any operations that are now unused.
                LinkedListNode <INode> node = blocks[blkIndex].Operations.First;

                while (node != null)
                {
                    LinkedListNode <INode> nextNode = node.Next;

                    if (IsUnused(node.Value))
                    {
                        RemoveNode(blocks[blkIndex], node);
                    }

                    node = nextNode;
                }
            }
        }
Exemplo n.º 25
0
        public static string GetAttributeName(AstOperand attr, ShaderConfig config, bool isOutAttr = false, string indexExpr = "0")
        {
            int value = attr.Value;

            char swzMask = GetSwizzleMask((value >> 2) & 3);

            if (value >= AttributeConsts.UserAttributeBase && value < AttributeConsts.UserAttributeEnd)
            {
                value -= AttributeConsts.UserAttributeBase;

                string prefix = isOutAttr
                    ? DefaultNames.OAttributePrefix
                    : DefaultNames.IAttributePrefix;

                if ((config.Flags & TranslationFlags.Feedback) != 0)
                {
                    string name = $"{prefix}{(value >> 4)}_{swzMask}";

                    if (config.Stage == ShaderStage.Geometry && !isOutAttr)
                    {
                        name += $"[{indexExpr}]";
                    }

                    return(name);
                }
                else
                {
                    string name = $"{prefix}{(value >> 4)}";

                    if (config.Stage == ShaderStage.Geometry && !isOutAttr)
                    {
                        name += $"[{indexExpr}]";
                    }

                    return(name + '.' + swzMask);
                }
            }
            else
            {
                if (value >= AttributeConsts.FragmentOutputColorBase && value < AttributeConsts.FragmentOutputColorEnd)
                {
                    value -= AttributeConsts.FragmentOutputColorBase;

                    return($"{DefaultNames.OAttributePrefix}{(value >> 4)}.{swzMask}");
                }
                else if (_builtInAttributes.TryGetValue(value & ~3, out BuiltInAttribute builtInAttr))
                {
                    // TODO: There must be a better way to handle this...
                    if (config.Stage == ShaderStage.Fragment)
                    {
                        switch (value & ~3)
                        {
                        case AttributeConsts.PositionX: return("(gl_FragCoord.x / fp_renderScale[0])");

                        case AttributeConsts.PositionY: return("(gl_FragCoord.y / fp_renderScale[0])");

                        case AttributeConsts.PositionZ: return("gl_FragCoord.z");

                        case AttributeConsts.PositionW: return("gl_FragCoord.w");
                        }
                    }

                    string name = builtInAttr.Name;

                    if (config.Stage == ShaderStage.Geometry && (value & AttributeConsts.SpecialMask) == 0 && !isOutAttr)
                    {
                        name = $"gl_in[{indexExpr}].{name}";
                    }

                    return(name);
                }
            }

            // TODO: Warn about unknown built-in attribute.

            return(isOutAttr ? "// bad_attr0x" + value.ToString("X") : "0.0");
        }
Exemplo n.º 26
0
 public static string GetOutAttributeName(AstOperand attr, ShaderConfig config)
 {
     return(GetAttributeName(attr, config, isOutAttr: true));
 }
Exemplo n.º 27
0
        private static void SetUserAttributeUses(ShaderConfig config, InstName name, ulong opCode)
        {
            int  offset;
            int  count    = 1;
            bool isStore  = false;
            bool indexed  = false;
            bool perPatch = false;

            if (name == InstName.Ast)
            {
                InstAst opAst = new InstAst(opCode);
                count    = (int)opAst.AlSize + 1;
                offset   = opAst.Imm11;
                indexed  = opAst.Phys;
                perPatch = opAst.P;
                isStore  = true;
            }
            else if (name == InstName.Ald)
            {
                InstAld opAld = new InstAld(opCode);
                count    = (int)opAld.AlSize + 1;
                offset   = opAld.Imm11;
                indexed  = opAld.Phys;
                perPatch = opAld.P;
                isStore  = opAld.O;
            }
            else /* if (name == InstName.Ipa) */
            {
                InstIpa opIpa = new InstIpa(opCode);
                offset  = opIpa.Imm10;
                indexed = opIpa.Idx;
            }

            if (indexed)
            {
                if (isStore)
                {
                    config.SetAllOutputUserAttributes();
                }
                else
                {
                    config.SetAllInputUserAttributes();
                }
            }
            else
            {
                for (int elemIndex = 0; elemIndex < count; elemIndex++)
                {
                    int attr = offset + elemIndex * 4;
                    if (attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd)
                    {
                        int index = (attr - AttributeConsts.UserAttributeBase) / 16;

                        if (isStore)
                        {
                            config.SetOutputUserAttribute(index, perPatch);
                        }
                        else
                        {
                            config.SetInputUserAttribute(index, perPatch);
                        }
                    }

                    if (!isStore &&
                        ((attr >= AttributeConsts.FrontColorDiffuseR && attr < AttributeConsts.ClipDistance0) ||
                         (attr >= AttributeConsts.TexCoordBase && attr < AttributeConsts.TexCoordEnd)))
                    {
                        config.SetUsedFeature(FeatureFlags.FixedFuncAttr);
                    }
                }
            }
        }
Exemplo n.º 28
0
        private static LinkedListNode <INode> ReplaceLdgWithLdc(LinkedListNode <INode> node, ShaderConfig config, int storageIndex)
        {
            Operation operation = (Operation)node.Value;

            Operand GetCbufOffset()
            {
                Operand addrLow = operation.GetSource(0);

                Operand baseAddrLow = Cbuf(0, UbeBaseOffset + storageIndex * StorageDescSize);

                Operand baseAddrTrunc = Local();

                Operand alignMask = Const(-config.QueryInfo(QueryInfoName.StorageBufferOffsetAlignment));

                Operation andOp = new Operation(Instruction.BitwiseAnd, baseAddrTrunc, baseAddrLow, alignMask);

                node.List.AddBefore(node, andOp);

                Operand byteOffset = Local();
                Operand wordOffset = Local();

                Operation subOp = new Operation(Instruction.Subtract, byteOffset, addrLow, baseAddrTrunc);
                Operation shrOp = new Operation(Instruction.ShiftRightU32, wordOffset, byteOffset, Const(2));

                node.List.AddBefore(node, subOp);
                node.List.AddBefore(node, shrOp);

                return(wordOffset);
            }

            Operand[] sources = new Operand[operation.SourcesCount];

            sources[0] = Const(UbeFirstCbuf + storageIndex);
            sources[1] = GetCbufOffset();

            for (int index = 2; index < operation.SourcesCount; index++)
            {
                sources[index] = operation.GetSource(index);
            }

            Operation ldcOp = new Operation(Instruction.LoadConstant, operation.Dest, sources);

            for (int index = 0; index < operation.SourcesCount; index++)
            {
                operation.SetSource(index, null);
            }

            LinkedListNode <INode> oldNode = node;

            node = node.List.AddBefore(node, ldcOp);

            node.List.Remove(oldNode);

            return(node);
        }
Exemplo n.º 29
0
        private static LinkedListNode <INode> ReplaceGlobalWithStorage(LinkedListNode <INode> node, ShaderConfig config, int storageIndex)
        {
            Operation operation = (Operation)node.Value;

            Operand GetStorageOffset()
            {
                Operand addrLow = operation.GetSource(0);

                Operand baseAddrLow = Cbuf(0, GetStorageCbOffset(config.Stage, storageIndex));

                Operand baseAddrTrunc = Local();

                Operand alignMask = Const(-config.QueryInfo(QueryInfoName.StorageBufferOffsetAlignment));

                Operation andOp = new Operation(Instruction.BitwiseAnd, baseAddrTrunc, baseAddrLow, alignMask);

                node.List.AddBefore(node, andOp);

                Operand byteOffset = Local();
                Operand wordOffset = Local();

                Operation subOp = new Operation(Instruction.Subtract, byteOffset, addrLow, baseAddrTrunc);
                Operation shrOp = new Operation(Instruction.ShiftRightU32, wordOffset, byteOffset, Const(2));

                node.List.AddBefore(node, subOp);
                node.List.AddBefore(node, shrOp);

                return(wordOffset);
            }

            Operand[] sources = new Operand[operation.SourcesCount];

            sources[0] = Const(storageIndex);
            sources[1] = GetStorageOffset();

            for (int index = 2; index < operation.SourcesCount; index++)
            {
                sources[index] = operation.GetSource(index);
            }

            Operation storageOp;

            if (operation.Inst.IsAtomic())
            {
                Instruction inst = (operation.Inst & ~Instruction.MrMask) | Instruction.MrStorage;

                storageOp = new Operation(inst, operation.Dest, sources);
            }
            else if (operation.Inst == Instruction.LoadGlobal)
            {
                storageOp = new Operation(Instruction.LoadStorage, operation.Dest, sources);
            }
            else
            {
                storageOp = new Operation(Instruction.StoreStorage, null, sources);
            }

            for (int index = 0; index < operation.SourcesCount; index++)
            {
                operation.SetSource(index, null);
            }

            LinkedListNode <INode> oldNode = node;

            node = node.List.AddBefore(node, storageOp);

            node.List.Remove(oldNode);

            return(node);
        }
Exemplo n.º 30
0
        public static void RunPass(BasicBlock block, ShaderConfig config)
        {
            // We can turn a bindless into regular access by recognizing the pattern
            // produced by the compiler for separate texture and sampler.
            // We check for the following conditions:
            // - The handle is a constant buffer value.
            // - The handle is the result of a bitwise OR logical operation.
            // - Both sources of the OR operation comes from a constant buffer.
            for (LinkedListNode <INode> node = block.Operations.First; node != null; node = node.Next)
            {
                if (!(node.Value is TextureOperation texOp))
                {
                    continue;
                }

                if ((texOp.Flags & TextureFlags.Bindless) == 0)
                {
                    continue;
                }

                if (texOp.Inst == Instruction.Lod ||
                    texOp.Inst == Instruction.TextureSample ||
                    texOp.Inst == Instruction.TextureSize)
                {
                    Operand bindlessHandle     = Utils.FindLastOperation(texOp.GetSource(0), block);
                    bool    rewriteSamplerType = texOp.Inst == Instruction.TextureSize;

                    if (bindlessHandle.Type == OperandType.ConstantBuffer)
                    {
                        SetHandle(config, texOp, bindlessHandle.GetCbufOffset(), bindlessHandle.GetCbufSlot(), rewriteSamplerType);
                        continue;
                    }

                    if (!(bindlessHandle.AsgOp is Operation handleCombineOp))
                    {
                        continue;
                    }

                    if (handleCombineOp.Inst != Instruction.BitwiseOr)
                    {
                        continue;
                    }

                    Operand src0 = Utils.FindLastOperation(handleCombineOp.GetSource(0), block);
                    Operand src1 = Utils.FindLastOperation(handleCombineOp.GetSource(1), block);

                    if (src0.Type != OperandType.ConstantBuffer || src1.Type != OperandType.ConstantBuffer)
                    {
                        continue;
                    }

                    SetHandle(
                        config,
                        texOp,
                        src0.GetCbufOffset() | ((src1.GetCbufOffset() + 1) << 16),
                        src0.GetCbufSlot() | ((src1.GetCbufSlot() + 1) << 16),
                        rewriteSamplerType);
                }
                else if (texOp.Inst == Instruction.ImageLoad ||
                         texOp.Inst == Instruction.ImageStore ||
                         texOp.Inst == Instruction.ImageAtomic)
                {
                    Operand src0 = Utils.FindLastOperation(texOp.GetSource(0), block);

                    if (src0.Type == OperandType.ConstantBuffer)
                    {
                        int cbufOffset = src0.GetCbufOffset();
                        int cbufSlot   = src0.GetCbufSlot();

                        if (texOp.Inst == Instruction.ImageAtomic)
                        {
                            texOp.Format = config.GetTextureFormatAtomic(cbufOffset, cbufSlot);
                        }
                        else
                        {
                            texOp.Format = config.GetTextureFormat(cbufOffset, cbufSlot);
                        }

                        SetHandle(config, texOp, cbufOffset, cbufSlot, false);
                    }
                }
            }
        }