private static ShaderProgram Translate(Operation[] ops, ShaderConfig config, int size) { BasicBlock[] blocks = ControlFlowGraph.MakeCfg(ops); if (blocks.Length > 0) { Dominance.FindDominators(blocks[0], blocks.Length); Dominance.FindDominanceFrontiers(blocks); Ssa.Rename(blocks); Optimizer.RunPass(blocks, config); Lowering.RunPass(blocks, config); } StructuredProgramInfo sInfo = StructuredProgram.MakeStructuredProgram(blocks, config); GlslProgram program = GlslGenerator.Generate(sInfo, config); ShaderProgramInfo spInfo = new ShaderProgramInfo( program.CBufferDescriptors, program.SBufferDescriptors, program.TextureDescriptors, program.ImageDescriptors, sInfo.UsesInstanceId); string glslCode = program.Code; return(new ShaderProgram(spInfo, config.Stage, glslCode, size)); }
public void MergeFromtNextStage(ShaderConfig config) { NextInputAttributesComponents = config.ThisInputAttributesComponents; NextInputAttributesPerPatchComponents = config.ThisInputAttributesPerPatchComponents; NextUsesFixedFuncAttributes = config.UsedFeatures.HasFlag(FeatureFlags.FixedFuncAttr); MergeOutputUserAttributes(config.UsedInputAttributes, config.UsedInputAttributesPerPatch); }
public static AttributeInfo From(ShaderConfig config, int value) { value &= ~3; if (value >= AttributeConsts.UserAttributeBase && value < AttributeConsts.UserAttributeEnd) { int location = (value - AttributeConsts.UserAttributeBase) / 16; var elemType = config.GpuAccessor.QueryAttributeType(location) switch { AttributeType.Sint => AggregateType.S32, AttributeType.Uint => AggregateType.U32, _ => AggregateType.FP32 }; return(new AttributeInfo(value, 4, AggregateType.Vector | elemType, false)); } else if (value >= AttributeConsts.FragmentOutputColorBase && value < AttributeConsts.FragmentOutputColorEnd) { return(new AttributeInfo(value, 4, AggregateType.Vector | AggregateType.FP32, false)); } else if (BuiltInAttributes.TryGetValue(value, out AttributeInfo info)) { return(info); } return(new AttributeInfo(value, 0, AggregateType.Invalid)); }
public EmitterContext(DecodedProgram program, ShaderConfig config, bool isNonMain) { Program = program; Config = config; IsNonMain = isNonMain; _operations = new List <Operation>(); _labels = new Dictionary <ulong, Operand>(); }
private static Block[][] DecodeShader( ulong address, IGpuAccessor gpuAccessor, TranslationOptions options, TranslationCounts counts, out ShaderConfig config) { Block[][] cfg; ulong maxEndAddress = 0; bool hasBindless; if ((options.Flags & TranslationFlags.Compute) != 0) { config = new ShaderConfig(gpuAccessor, options, counts); cfg = Decoder.Decode(gpuAccessor, address, out hasBindless); } else { config = new ShaderConfig(new ShaderHeader(gpuAccessor, address), gpuAccessor, options, counts); cfg = Decoder.Decode(gpuAccessor, address + HeaderSize, out hasBindless); } if (hasBindless) { config.SetUsedFeature(FeatureFlags.Bindless); } for (int funcIndex = 0; funcIndex < cfg.Length; funcIndex++) { for (int blkIndex = 0; blkIndex < cfg[funcIndex].Length; blkIndex++) { Block block = cfg[funcIndex][blkIndex]; if (maxEndAddress < block.EndAddress) { maxEndAddress = block.EndAddress; } if (!hasBindless) { for (int index = 0; index < block.OpCodes.Count; index++) { if (block.OpCodes[index] is OpCodeTextureBase texture) { config.TextureHandlesForCache.Add(texture.HandleOffset); } } } } } config.SizeAdd((int)maxEndAddress + (options.Flags.HasFlag(TranslationFlags.Compute) ? 0 : HeaderSize)); return(cfg); }
internal TranslatorContext(ulong addressA, ulong addressB, Block[][] cfgA, Block[][] cfgB, ShaderConfig configA, ShaderConfig configB) { Address = addressB; AddressA = addressA; _config = configB; _configA = configA; _cfg = cfgB; _cfgA = cfgA; }
internal TranslatorContext(ulong address, Block[][] cfg, ShaderConfig config) { Address = address; AddressA = 0; _config = config; _configA = null; _cfg = cfg; _cfgA = null; }
public void MergeFromtNextStage(ShaderConfig config) { NextInputAttributesComponents = config.ThisInputAttributesComponents; NextInputAttributesPerPatchComponents = config.ThisInputAttributesPerPatchComponents; NextUsesFixedFuncAttributes = config.UsedFeatures.HasFlag(FeatureFlags.FixedFuncAttr); MergeOutputUserAttributes(config.UsedInputAttributes, config.UsedInputAttributesPerPatch); if (config.Stage != ShaderStage.Fragment) { LastInVertexPipeline = false; } }
private static void ScanForBindless(BasicBlock[] blocks, ShaderConfig config) { for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++) { // Right now the guest shader cache cannot handle bindless textures correctly. for (LinkedListNode <INode> node = blocks[blkIndex].Operations.First; node != null; node = node.Next) { if (node.Value is TextureOperation texOp && (texOp.Flags & TextureFlags.Bindless) != 0) { config.SetUsedFeature(FeatureFlags.Bindless); break; } } } }
private static Operation[] DecodeShader( ReadOnlySpan <byte> code, TranslatorCallbacks callbacks, TranslationFlags flags, out ShaderConfig config, out int size) { Block[] cfg; if ((flags & TranslationFlags.Compute) != 0) { config = new ShaderConfig(flags, callbacks); cfg = Decoder.Decode(code, 0); } else { config = new ShaderConfig(new ShaderHeader(code), flags, callbacks); cfg = Decoder.Decode(code, HeaderSize); } if (cfg == null) { config.PrintLog("Invalid branch detected, failed to build CFG."); size = 0; return(Array.Empty <Operation>()); } EmitterContext context = new EmitterContext(config); ulong maxEndAddress = 0; for (int blkIndex = 0; blkIndex < cfg.Length; blkIndex++) { Block block = cfg[blkIndex]; if (maxEndAddress < block.EndAddress) { maxEndAddress = block.EndAddress; } context.CurrBlock = block; context.MarkLabel(context.GetLabel(block.Address)); for (int opIndex = 0; opIndex < block.OpCodes.Count; opIndex++) { OpCode op = block.OpCodes[opIndex]; if ((flags & TranslationFlags.DebugMode) != 0) { string instName; if (op.Emitter != null) { instName = op.Emitter.Method.Name; } else { instName = "???"; config.PrintLog($"Invalid instruction at 0x{op.Address:X6} (0x{op.RawOpCode:X16})."); } string dbgComment = $"0x{op.Address:X6}: 0x{op.RawOpCode:X16} {instName}"; context.Add(new CommentNode(dbgComment)); } if (op.NeverExecute) { continue; } Operand predSkipLbl = null; bool skipPredicateCheck = op is OpCodeBranch opBranch && !opBranch.PushTarget; if (op is OpCodeBranchPop opBranchPop) { // If the instruction is a SYNC or BRK instruction with only one // possible target address, then the instruction is basically // just a simple branch, we can generate code similar to branch // instructions, with the condition check on the branch itself. skipPredicateCheck = opBranchPop.Targets.Count < 2; } if (!(op.Predicate.IsPT || skipPredicateCheck)) { Operand label; if (opIndex == block.OpCodes.Count - 1 && block.Next != null) { label = context.GetLabel(block.Next.Address); } else { label = Label(); predSkipLbl = label; } Operand pred = Register(op.Predicate); if (op.InvertPredicate) { context.BranchIfTrue(label, pred); } else { context.BranchIfFalse(label, pred); } } context.CurrOp = op; op.Emitter?.Invoke(context); if (predSkipLbl != null) { context.MarkLabel(predSkipLbl); } } } size = (int)maxEndAddress + (((flags & TranslationFlags.Compute) != 0) ? 0 : HeaderSize); return(context.GetOperations()); }
internal TranslatorContext(ulong address, DecodedProgram program, ShaderConfig config) { Address = address; _program = program; _config = config; }