unit srInterface; {$mode objfpc}{$H+} interface uses ps4_pssl, si_ci_vi_merged_registers, spirv, srNode, srConfig, srAllocator, srCFGCursor, srRefId, srLiteral, srCapability, srDecorate, srType, srTypes, srConst, srReg, srVariable, srInput, srOutput, srLayout, srVertLayout, srFragLayout, srBuffer, srUniform, srPrivate, srBitcast, srOp, srOpUtils, srCacheOp; type TLocalSize=packed record x,y,z:DWORD; end; TGeometryInfo=record outputVertCount:DWORD; //4 invocationCount:DWORD; //1 InputMode :DWORD; //Triangles OutputMode :DWORD; //OutputTriangleStrip end; PPSInputCntl=^TPSInputCntl; TPSInputCntl=object DATA:TSPI_PS_INPUT_CNTL_0; function OFFSET :Byte; function USE_DEFAULT:Boolean; function DEFAULT_VAL:Tvec4f; function FLAT_SHADE :Boolean; end; TExportInfo=packed record FORMAT :Byte; NUMBER_TYPE:Byte; COMP_SWAP :Byte; end; TEmitInterface=class(TCustomEmit) FExecutionModel :Word; FEarlyFragmentTests:Boolean; // VGPR_COMP_CNT :Byte; PS_NUM_INTERP :Byte; EXPORT_COUNT :Byte; // VGT_STEP_RATE_0 :DWORD; VGT_STEP_RATE_1 :DWORD; DB_SHADER_CONTROL :TDB_SHADER_CONTROL; CS_NUM_THREAD_X :DWORD; CS_NUM_THREAD_Y :DWORD; CS_NUM_THREAD_Z :DWORD; // FPSInputCntl :array[0..31] of TPSInputCntl; FExportInfo :array[0..7] of TExportInfo; // FLocalSize :TLocalSize; FLDS_SIZE :DWORD; FVGPRS :WORD; FSGPRS :WORD; FGeometryInfo :TGeometryInfo; // FThread_id :TsrRegNode; // Config:TsrConfig; // FSPI:TSPI; // Allocator:TsrAllocator; // LiteralList :TsrLiteralList; TypeList :TsrTypeList; ConstList :TsrConstList; RegsStory :TsrRegsStory; CapabilityList:TsrCapabilityList; HeaderList :TsrHeaderList; DecorateList :TsrDecorateList; DebugInfoList :TsrDebugInfoList; VariableList :TsrVariableList; // InputList :TsrInputList; OutputList :TsrOutputList; // DataLayoutList:TsrDataLayoutList; VertLayoutList:TsrVertLayoutList; FragLayoutList:TsrFragLayoutList; // BufferList :TsrBufferList; UniformList :TsrUniformList; PrivateList :TsrPrivateList; // BitcastList :TsrBitcastList; CacheOpList :TsrCacheOpList; // FuncList :TsrFuncList; // CodeHeap :TsrCodeHeap; Cursor :TsrCursor; Main :TSpirvFunc; InitBlock:TsrOpBlock; // RefIdAlloc:TsrRefIdAlloc; // function Alloc(Size:ptruint):Pointer; override; Function GetDmem(P:Pointer) :Pointer; override; Function GetExecutionModel :Word; override; Function GetConfig :Pointer; override; Function GetCodeHeap :Pointer; override; Function GetLiteralList :Pointer; override; Function GetTypeList :Pointer; override; Function GetConstList :Pointer; override; Function GetRegsStory :Pointer; override; Function GetCapabilityList :Pointer; override; Function GetHeaderList :TsrNode; override; Function GetDecorateList :TsrNode; override; Function GetDebugInfoList :TsrNode; override; Function GetVariableList :Pointer; override; Function GetInputList :Pointer; override; Function GetOutputList :Pointer; override; Function GetDataLayoutList :Pointer; override; Function GetVertLayoutList :Pointer; override; Function GetFragLayoutList :Pointer; override; Function GetBufferList :Pointer; override; Function GetUniformList :Pointer; override; Function GetBitcastList :Pointer; override; Function GetCacheOpList :Pointer; override; Function GetFuncList :Pointer; override; Function GetCursor :Pointer; override; function NewRefNode :TsrNode; override; // Function line :TspirvOp; Function curr_line :TsrNode; override; function init_line :TsrNode; override; // Procedure InitLists; // function NewVariable:Pointer; // function _get_line(ppLine:PPspirvOp):TspirvOp; // Function NewRegPair:TsrRegPair; Function NewReg(rtype:TsrDataType):TsrRegNode; Function NewImm(pConst:TsrConst;pLine:TspirvOp=nil):TsrRegNode; // Function NewImm_q(dtype:TsrDataType;value:QWORD;pLine:TspirvOp=nil):TsrRegNode; Function NewImm_b(value:Boolean;pLine:TspirvOp=nil):TsrRegNode; Function NewImm_i(dtype:TsrDataType;value:Integer;pLine:TspirvOp=nil):TsrRegNode; Function NewImm_s(dtype:TsrDataType;value:Single;pLine:TspirvOp=nil):TsrRegNode; // function NewSpirvOp(OpId:DWORD):TSpirvOp; function NewLabelOp(sdep:Boolean):TSpirvOp; function AddSpirvOp(OpId:DWORD):TSpirvOp; function AddSpirvOp(pLine:TSpirvOp;OpId:DWORD):TSpirvOp; function AddSpirvOp(pLine,pNew:TSpirvOp):TSpirvOp; function AddSGlslOp(pLine:TSpirvOp;OpId:DWORD):TSpirvOp; // Function PostLink(pLine,dst:TsrNode):TsrNode; override; procedure MakeCopy(dst:PsrRegSlot;src:TsrRegNode); // Procedure SetConst(pSlot:PsrRegSlot;pConst:TsrConst); Procedure SetConst_q(pSlot:PsrRegSlot;dtype:TsrDataType;value:QWORD); Procedure SetConst_b(pSlot:PsrRegSlot;value:Boolean); Procedure SetConst_i(pSlot:PsrRegSlot;dtype:TsrDataType;value:Integer); Procedure SetConst_s(pSlot:PsrRegSlot;dtype:TsrDataType;value:Single); // function AllocBlockOp:TsrOpBlock; function NewBlockOp(const curr:TsrRegsSnapshot):TsrOpBlock; function NewBlockOp(const curr,orig:TsrRegsSnapshot):TsrOpBlock; function InsertBlockOp(pLine:TSpirvOp;pChild:TsrOpBlock):TSpirvOp; // procedure AddCapability(ID:DWORD); // procedure PrepTypeSlot (pSlot:PsrRegSlot;rtype:TsrDataType); function MakeRead (pSlot:PsrRegSlot;rtype:TsrDataType):TsrRegNode; function PrepTypeNode (var node:TsrRegNode;rtype:TsrDataType;relax:Boolean=true):Integer; function PrepTypeDst (var node:TsrRegNode;rtype:TsrDataType;relax:Boolean=true):Integer; function PrepTypeParam(node:POpParamNode;rtype:TsrDataType;relax:Boolean=true):Integer; // function get_vcc0 :PsrRegSlot; function get_vcc1 :PsrRegSlot; function get_m0 :PsrRegSlot; function get_exec0:PsrRegSlot; function get_exec1:PsrRegSlot; function get_scc :PsrRegSlot; end; implementation // function TPSInputCntl.OFFSET:Byte; begin Result:=(DATA.OFFSET and 31); end; function TPSInputCntl.USE_DEFAULT:Boolean; begin Result:=(DATA.OFFSET shr 5)<>0; end; const C_DEFAULT_VAL:array[0..3] of Tvec4f=( (0.0, 0.0, 0.0, 0.0), (0.0, 0.0, 0.0, 1.0), (1.0, 1.0, 1.0, 0.0), (1.0, 1.0, 1.0, 1.0) ); function TPSInputCntl.DEFAULT_VAL:Tvec4f; begin Result:=C_DEFAULT_VAL[DATA.DEFAULT_VAL]; end; function TPSInputCntl.FLAT_SHADE:Boolean; begin Result:=(DATA.FLAT_SHADE)<>0 end; // function TEmitInterface.Alloc(Size:ptruint):Pointer; begin Result:=Allocator.Alloc(Size); end; Function TEmitInterface.GetDmem(P:Pointer):Pointer; begin if (Config.OnGetDmem<>nil) then begin Result:=Config.OnGetDmem(P); end else begin Result:=P; end; end; Function TEmitInterface.GetExecutionModel:Word; begin Result:=FExecutionModel; end; Function TEmitInterface.GetConfig:Pointer; begin Result:=@Config; end; Function TEmitInterface.GetCodeHeap:Pointer; begin Result:=@CodeHeap; end; Function TEmitInterface.GetLiteralList:Pointer; begin Result:=@LiteralList; end; Function TEmitInterface.GetTypeList:Pointer; begin Result:=@TypeList; end; Function TEmitInterface.GetConstList:Pointer; begin Result:=@ConstList; end; Function TEmitInterface.GetRegsStory:Pointer; begin Result:=@RegsStory; end; Function TEmitInterface.GetCapabilityList:Pointer; begin Result:=@CapabilityList; end; Function TEmitInterface.GetHeaderList:TsrNode; begin Result:=HeaderList; end; Function TEmitInterface.GetDecorateList:TsrNode; begin Result:=DecorateList; end; Function TEmitInterface.GetDebugInfoList:TsrNode; begin Result:=DebugInfoList; end; Function TEmitInterface.GetVariableList:Pointer; begin Result:=@VariableList; end; Function TEmitInterface.GetInputList:Pointer; begin Result:=@InputList; end; Function TEmitInterface.GetOutputList:Pointer; begin Result:=@OutputList; end; Function TEmitInterface.GetDataLayoutList:Pointer; begin Result:=@DataLayoutList; end; Function TEmitInterface.GetVertLayoutList:Pointer; begin Result:=@VertLayoutList; end; Function TEmitInterface.GetFragLayoutList:Pointer; begin Result:=@FragLayoutList; end; Function TEmitInterface.GetBufferList:Pointer; begin Result:=@BufferList; end; Function TEmitInterface.GetUniformList:Pointer; begin Result:=@UniformList; end; Function TEmitInterface.GetBitcastList:Pointer; begin Result:=@BitcastList; end; Function TEmitInterface.GetCacheOpList:Pointer; begin Result:=@CacheOpList; end; Function TEmitInterface.GetFuncList:Pointer; begin Result:=@FuncList; end; Function TEmitInterface.GetCursor:Pointer; begin Result:=@Cursor; end; // function TEmitInterface.NewRefNode:TsrNode; begin Result:=TsrNode(specialize New); end; Function TEmitInterface.line:TSpirvOp; begin Result:=nil; if (Main<>nil) then begin Result:=Main.line; end; end; function TEmitInterface.curr_line:TsrNode; begin Result:=line; end; function TEmitInterface.init_line:TsrNode; begin if (InitBlock=nil) then begin Exit(nil); end; if (InitBlock.dummy.Parent=nil) then //is not init? begin InitBlock.Init(); end; Result:=InitBlock.line; Assert(Result<>nil); end; Procedure TEmitInterface.InitLists; begin Config.Init; LiteralList .Init(Self); TypeList .Init(Self); ConstList .Init(Self); RegsStory .Init(Self); CapabilityList.Init(Self); // HeaderList :=specialize New; DecorateList :=specialize New; DebugInfoList :=specialize New; // VariableList .Init(Self); InputList .Init(Self); OutputList .Init(Self); DataLayoutList.Init(Self); VertLayoutList.Init(Self); FragLayoutList.Init(Self); BufferList .Init(Self); UniformList .Init(Self); PrivateList .Init(Self); BitcastList .Init(Self); CacheOpList .Init(Self); end; function TEmitInterface.NewVariable:Pointer; begin Result:=VariableList.Fetch; end; // function TEmitInterface._get_line(ppLine:PPspirvOp):TSpirvOp; begin if (ppLine=nil) then Exit(line); if (ppLine^=nil) then Exit(line); Result:=ppLine^; end; // Function TEmitInterface.NewRegPair:TsrRegPair; begin Result:=specialize New; end; Function TEmitInterface.NewReg(rtype:TsrDataType):TsrRegNode; begin Result:=RegsStory.FUnattach.New(rtype); end; Function TEmitInterface.NewImm(pConst:TsrConst;pLine:TspirvOp=nil):TsrRegNode; begin if (pConst=nil) then Exit(nil); Result:=NewReg(pConst.dtype); Result.pWriter:=pConst; // if (pLine=nil) then pLine:=line; Result.CustomLine:=pLine; end; // Function TEmitInterface.NewImm_q(dtype:TsrDataType;value:QWORD;pLine:TspirvOp=nil):TsrRegNode; begin Result:=NewImm(ConstList.Fetch(dtype,value),pLine); end; Function TEmitInterface.NewImm_b(value:Boolean;pLine:TspirvOp=nil):TsrRegNode; begin Result:=NewImm(ConstList.Fetch_b(value),pLine); end; Function TEmitInterface.NewImm_i(dtype:TsrDataType;value:Integer;pLine:TspirvOp=nil):TsrRegNode; begin Result:=NewImm(ConstList.Fetch_i(dtype,value),pLine); end; Function TEmitInterface.NewImm_s(dtype:TsrDataType;value:Single;pLine:TspirvOp=nil):TsrRegNode; begin Result:=NewImm(ConstList.Fetch_s(dtype,value),pLine); end; function TEmitInterface.NewSpirvOp(OpId:DWORD):TSpirvOp; begin Result:=specialize New; Result.Init(OpId); //Result.adr:=Cursor.Adr; end; function TEmitInterface.NewLabelOp(sdep:Boolean):TSpirvOp; Var node:TSpirvOp; begin node:=NewSpirvOp(Op.OpLabel); node.pDst:=NewRefNode; Result:=node; if sdep then node.pDst.mark_read(nil); end; function TEmitInterface.AddSpirvOp(OpId:DWORD):TSpirvOp; begin Result:=AddSpirvOp(line,OpId); end; function TEmitInterface.AddSpirvOp(pLine:TSpirvOp;OpId:DWORD):TSpirvOp; begin Result:=InsSpirvOp(pLine,NewSpirvOp(OpId)); end; function TEmitInterface.AddSpirvOp(pLine,pNew:TSpirvOp):TSpirvOp; begin Result:=InsSpirvOp(pLine,pNew); end; function TEmitInterface.AddSGlslOp(pLine:TSpirvOp;OpId:DWORD):TSpirvOp; var ext,node:TSpirvOp; begin ext:=HeaderList.GLSL_std_450; node:=AddSpirvOp(pLine,Op.OpExtInst); node.AddParam(ext.pDst); node.AddLiteral(OpId,GlslOp.GetStr(OpId)); Result:=node; end; Function TEmitInterface.PostLink(pLine,dst:TsrNode):TsrNode; var node:TSpirvOp; begin node:=pLine.specialize AsType; Assert(node<>nil); if node.IsType(ntOp) then if (node.OpId=Op.OpNop) then begin node.AddParam(dst); Exit(node); end; node:=AddSpirvOp(node,Op.OpNop); node.AddParam(dst); node.mark([soNotUsed,soPost]); Exit(node); end; procedure TEmitInterface.MakeCopy(dst:PsrRegSlot;src:TsrRegNode); var node:TsrRegNode; pLine:TspirvOp; begin if (src.pSlot^.iUnattach) and (src.CustomLine=nil) and (src.Parent=line.Parent) then begin node:=src; node.pSlot:=dst; //change slot dst^.current:=node; //bind current end else begin node:=dst^.New(src.dtype,line); node.pWriter:=src; end; pLine:=PostLink(line,node); //post processing //fixed line node.CustomLine:=pLine; end; Procedure TEmitInterface.SetConst(pSlot:PsrRegSlot;pConst:TsrConst); var dst:TsrRegNode; pLine:TspirvOp; begin dst:=pSlot^.New(pConst.dtype,line); dst.pWriter:=pConst; pLine:=PostLink(line,dst); //post processing //fixed line dst.CustomLine:=pLine; end; Procedure TEmitInterface.SetConst_q(pSlot:PsrRegSlot;dtype:TsrDataType;value:QWORD); begin SetConst(pSlot,ConstList.Fetch(dtype,value)); end; Procedure TEmitInterface.SetConst_b(pSlot:PsrRegSlot;value:Boolean); begin SetConst(pSlot,ConstList.Fetch_b(value)); end; Procedure TEmitInterface.SetConst_i(pSlot:PsrRegSlot;dtype:TsrDataType;value:Integer); begin SetConst(pSlot,ConstList.Fetch_i(dtype,value)); end; Procedure TEmitInterface.SetConst_s(pSlot:PsrRegSlot;dtype:TsrDataType;value:Single); begin SetConst(pSlot,ConstList.Fetch_s(dtype,value)); end; function TEmitInterface.AllocBlockOp:TsrOpBlock; begin Result:=specialize New; Result.Init(); end; function TEmitInterface.NewBlockOp(const curr:TsrRegsSnapshot):TsrOpBlock; begin Result:=AllocBlockOp; // Result.Regs.orig :=Alloc(SizeOf(TsrRegsSnapshot)); Result.Regs.prev :=Alloc(SizeOf(TsrRegsSnapshot)); Result.Regs.next :=Alloc(SizeOf(TsrRegsSnapshot)); // Result.Regs.orig^:=curr; Result.Regs.prev^:=curr; Result.Regs.next^:=curr; Result.Cond.FUseCont:=false; end; function TEmitInterface.NewBlockOp(const curr,orig:TsrRegsSnapshot):TsrOpBlock; begin Result:=AllocBlockOp; // Result.Regs.orig :=Alloc(SizeOf(TsrRegsSnapshot)); Result.Regs.prev :=Alloc(SizeOf(TsrRegsSnapshot)); Result.Regs.next :=Alloc(SizeOf(TsrRegsSnapshot)); // Result.Regs.orig^:=orig; Result.Regs.prev^:=curr; Result.Regs.next^:=curr; Result.Cond.FUseCont:=false; end; function TEmitInterface.InsertBlockOp(pLine:TSpirvOp;pChild:TsrOpBlock):TSpirvOp; begin pLine:=InsSpirvOp(pLine,pChild); pChild.UpdateLevel; Result:=pLine; end; // procedure TEmitInterface.AddCapability(ID:DWORD); begin CapabilityList.Add(ID); end; // procedure TEmitInterface.PrepTypeSlot(pSlot:PsrRegSlot;rtype:TsrDataType); begin if (pSlot=nil) then Exit; if (pSlot^.current=nil) then begin pSlot^.New(rtype,line); //Unresolve Exit; end; pSlot^.current.PrepType(ord(rtype)); end; function TEmitInterface.MakeRead(pSlot:PsrRegSlot;rtype:TsrDataType):TsrRegNode; var node:TsrRegNode; begin Result:=nil; if (pSlot=nil) then Exit; PrepTypeSlot(pSlot,rtype); node:=pSlot^.current; if (rtype<>dtUnknow) and (not CompareType(node.dtype,rtype)) then begin Result:=BitcastList.FetchRead(rtype,node); end else begin Result:=node; end; if (rtype<>dtUnknow) then begin Result.dweak:=False; end; end; function TEmitInterface.PrepTypeNode(var node:TsrRegNode;rtype:TsrDataType;relax:Boolean=true):Integer; begin Result:=0; if (node=nil) then Exit; if (rtype=dtUnknow) then Exit; if is_unprep_type(node.dtype,rtype,node.dweak) then begin node.PrepType(ord(rtype)); Inc(Result); end else begin Case relax of True :relax:=CompareType(node.dtype,rtype); False:relax:=(node.dtype=rtype); end; if not relax then begin node:=BitcastList.FetchRead(rtype,node); Inc(Result); end; end; end; function TEmitInterface.PrepTypeDst(var node:TsrRegNode;rtype:TsrDataType;relax:Boolean=true):Integer; begin Result:=0; if (node=nil) then Exit; if (rtype=dtUnknow) then Exit; if is_unprep_type(node.dtype,rtype,node.dweak) then begin node.PrepType(ord(rtype)); Inc(Result); end else begin Case relax of True :relax:=CompareType(node.dtype,rtype); False:relax:=(node.dtype=rtype); end; if not relax then begin node:=BitcastList.FetchDstr(rtype,node); Inc(Result); end; end; end; function TEmitInterface.PrepTypeParam(node:POpParamNode;rtype:TsrDataType;relax:Boolean=true):Integer; var pReg:TsrRegNode; begin Result:=0; if (node=nil) then Exit; if (rtype=dtUnknow) then Exit; if node.Value.IsType(ntReg) then begin pReg:=node.AsReg; Result:=PrepTypeNode(pReg,rtype,relax); node.Value:=pReg; end else begin node.Value.PrepType(ord(rtype)); end; end; // function TEmitInterface.get_vcc0:PsrRegSlot; begin Result:=@RegsStory.VCC[0]; end; function TEmitInterface.get_vcc1:PsrRegSlot; begin Result:=@RegsStory.VCC[1]; end; function TEmitInterface.get_m0:PsrRegSlot; begin Result:=@RegsStory.M0; end; function TEmitInterface.get_exec0:PsrRegSlot; begin Result:=@RegsStory.EXEC[0]; end; function TEmitInterface.get_exec1:PsrRegSlot; begin Result:=@RegsStory.EXEC[1]; end; function TEmitInterface.get_scc:PsrRegSlot; begin Result:=@RegsStory.SCC; end; // end.