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; }
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); } } } }
private static void FillBlock(ShaderConfig config, Block block, ulong limitAddress, ulong startAddress) { IGpuAccessor gpuAccessor = config.GpuAccessor; ulong address = block.Address; do { if (address + 7 >= limitAddress) { break; } // Ignore scheduling instructions, which are written every 32 bytes. if ((address & 0x1f) == 0) { address += 8; continue; } ulong opAddress = address; address += 8; long opCode = gpuAccessor.MemoryRead <long>(startAddress + opAddress); (InstEmitter emitter, OpCodeTable.MakeOp makeOp) = OpCodeTable.GetEmitter(opCode); if (emitter == null) { // TODO: Warning, illegal encoding. block.OpCodes.Add(new OpCode(null, opAddress, opCode)); continue; } if (makeOp == null) { throw new ArgumentNullException(nameof(makeOp)); } OpCode op = makeOp(emitter, opAddress, opCode); // We check these patterns to figure out the presence of bindless access if ((op is OpCodeImage image && image.IsBindless) || (op is OpCodeTxd txd && txd.IsBindless) || (op is OpCodeTld4B) || (emitter == InstEmit.TexB) || (emitter == InstEmit.TldB) || (emitter == InstEmit.TmmlB) || (emitter == InstEmit.TxqB)) { config.SetUsedFeature(FeatureFlags.Bindless); } // Populate used attributes. if (op is IOpCodeAttribute opAttr) { SetUserAttributeUses(config, opAttr); } block.OpCodes.Add(op); }while (!IsControlFlowChange(block.GetLastOp())); block.EndAddress = address; block.UpdatePushOps(); }