mirror of https://github.com/red-prig/fpPS4.git
1751 lines
38 KiB
Plaintext
1751 lines
38 KiB
Plaintext
unit SprvEmit;
|
||
|
||
{$mode objfpc}{$H+}
|
||
|
||
interface
|
||
|
||
uses
|
||
sysutils,
|
||
si_ci_vi_merged_registers,
|
||
ps4_pssl,
|
||
srAllocator,
|
||
srNodes,
|
||
srBitcast,
|
||
srLabel,
|
||
srCFG,
|
||
srParser,
|
||
srTypes,
|
||
srConst,
|
||
srReg,
|
||
srOp,
|
||
srOpUtils,
|
||
srCap,
|
||
srRefId,
|
||
srDecorate,
|
||
srLayout,
|
||
srVertLayout,
|
||
srFragLayout,
|
||
srBuffer,
|
||
srVariable,
|
||
srInput,
|
||
srOutput,
|
||
srUniform,
|
||
spirv;
|
||
|
||
type
|
||
TLocalSize=packed record
|
||
x,y,z:DWORD;
|
||
end;
|
||
|
||
PSprvEmit=^TSprvEmit;
|
||
TSprvEmit=object
|
||
|
||
FAllocator:TsrAllocator;
|
||
|
||
FCodeHeap:TsrCodeHeap;
|
||
FCursor:TsrCursor;
|
||
|
||
FLocalSize:TLocalSize;
|
||
|
||
FExecutionModel:Word;
|
||
|
||
FRegsStory:TsrRegsStory;
|
||
FVolatileID:SizeUint;
|
||
|
||
FInputs:TsrInputList;
|
||
FDataLayouts:TsrDataLayoutList;
|
||
FVertLayouts:TsrVertLayoutList;
|
||
FFragLayouts:TsrFragLayoutList;
|
||
FBuffers:TsrBufferList;
|
||
|
||
FOutputs:TsrOutputList;
|
||
FVariables:TsrVariableList;
|
||
FUniforms:TsrUniformList;
|
||
FCacheOps:TsrCacheOpList;
|
||
|
||
FConsts:TsrConstList;
|
||
FBitcast:TsrBitcastList;
|
||
|
||
FSpirvIdAlloc:TsrRefIdAlloc;
|
||
FSpirvTypes:TsrTypeList;
|
||
FSpirvFuncs:TsrFuncList;
|
||
FSpirvCaps:TsrCapList;
|
||
|
||
FDebugInfo:TsrDebugInfoList;
|
||
FDecorates:TsrDecorateList;
|
||
|
||
FMain:PSpirvFunc;
|
||
FInitLine:PsrOpBlock;
|
||
|
||
FGLSL_std_450:PSpirvOp;
|
||
|
||
FHeader:TsrOpBlockSimple;
|
||
|
||
FSPI:TSPI;
|
||
|
||
FPrintAsm:Boolean;
|
||
FUseVertexInput:Boolean;
|
||
FUseTexelBuffer:Boolean;
|
||
FUseOutput16:Boolean;
|
||
|
||
function Alloc(Size:ptruint):Pointer;
|
||
|
||
procedure SetPtr(base:Pointer;bType:TsrBlockType);
|
||
function Parse(base:Pointer):Byte;
|
||
function NextParse:Byte;
|
||
function IsFinalize:Boolean;
|
||
function FindLabel(Adr:TSrcAdr):PsrLabel;
|
||
function CheckBlockBeg:Boolean;
|
||
function CheckBlockEnd:Boolean;
|
||
procedure Finalize;
|
||
|
||
function NewLabelOp:PSpirvOp;
|
||
function NewMain:PSpirvFunc;
|
||
|
||
procedure AddCap(ID:DWORD);
|
||
|
||
function AllocBlockOp:PsrOpBlock;
|
||
function NewBlockOp(Snap:TsrRegsSnapshot):PsrOpBlock;
|
||
function InsertBlockOp(pLine:PspirvOp;pChild:PsrOpBlock):PspirvOp;
|
||
Procedure PushBlockOp(pLine:PspirvOp;pOpBlock:PsrOpBlock;pLBlock:PsrCFGBlock);
|
||
function PopBlockOp:Boolean;
|
||
|
||
function NewSpirvOp(OpId:DWORD):PSpirvOp;
|
||
function AddSpirvOp(OpId:DWORD):PSpirvOp;
|
||
function AddSpirvOp(pLine:PspirvOp;OpId:DWORD):PSpirvOp;
|
||
function AddSpirvOp(pLine,pNew:PspirvOp):PSpirvOp;
|
||
function line:PSpirvOp;
|
||
function init_line:PSpirvOp;
|
||
procedure PostLink(ntype:TsrNodeType;Data:Pointer);
|
||
procedure PostReg(pReg:PsrRegNode);
|
||
|
||
function NewRefId:PsrRefId;
|
||
function NewVariable:PsrVariable;
|
||
|
||
function AddInput(dst:PsrRegSlot;rtype:TsrDataType;itype:TpsslInputType;id:Byte=0):PsrRegNode;
|
||
function AllocDescVar(p:Pointer;_ntype:TsrNodeType;rtype:TsrDataType):PsrVariable;
|
||
function AddVertLayout(pLayout:PsrDataLayout;rtype:TsrDataType):PsrRegNode;
|
||
function AddFragLayout(itype:TpsslInputType;rtype:TsrDataType;location:DWORD):PsrRegNode;
|
||
function FetchLoad(pChain:PsrChain;rtype:TsrDataType):PsrRegNode;
|
||
Procedure FetchStore(pChain:PsrChain;src:PsrRegNode);
|
||
procedure AddUserdata(dst:PsrRegSlot;offset_dw:Byte);
|
||
function FetchChain(grp:PsrDataLayout;offset,size:DWORD;ext:PsrChainExt):PsrRegNode;
|
||
function MakeChain(pSlot:PsrRegSlot;grp:PsrDataLayout;offset,size:PtrUint;ext:PsrChainExt):PsrRegNode;
|
||
Procedure AddVecInput(dst:PsrRegSlot;vtype,rtype:TsrDataType;itype:TpsslInputType;id:Byte);
|
||
function FetchUniform(src:PsrDataLayout;pType:PsrType):PsrRegNode;
|
||
function FetchImage(src:PsrDataLayout;dtype:TsrDataType;info:TsrTypeImageInfo):PsrRegNode;
|
||
function FetchSampler(src:PsrDataLayout):PsrRegNode;
|
||
function FetchOutput(etype:TpsslExportType;rtype:TsrDataType):PsrVariable;
|
||
|
||
Procedure Init;
|
||
procedure SetUserData(pData:Pointer);
|
||
Procedure InitVs(RSRC2:TSPI_SHADER_PGM_RSRC2_VS;instance:Byte);
|
||
Procedure InitPs(RSRC2:TSPI_SHADER_PGM_RSRC2_PS;ENA:TSPI_PS_INPUT_ENA);
|
||
Procedure InitCs(RSRC2:TCOMPUTE_PGM_RSRC2;NTX:TCOMPUTE_NUM_THREAD_X;NTY:TCOMPUTE_NUM_THREAD_Y;NTZ:TCOMPUTE_NUM_THREAD_Z);
|
||
|
||
Function NewReg(rtype:TsrDataType):PsrRegNode;
|
||
Function FetchReg(pConst:PsrConst):PsrRegNode;
|
||
Procedure SetConst(pSlot:PsrRegSlot;pConst:PsrConst);
|
||
Procedure SetConst(pSlot:PsrRegSlot;dtype:TsrDataType;value:QWORD);
|
||
|
||
function fetch_soffset(SOFFSET:Word;rtype:TsrDataType):PsrRegNode;
|
||
function fetch_ssrc9(SSRC:Word;rtype:TsrDataType):PsrRegNode;
|
||
function fetch_ssrc9_pair(src:PPsrRegNode;SSRC:Word;rtype:TsrDataType):Boolean;
|
||
function fetch_vsrc8(VSRC:Word;rtype:TsrDataType):PsrRegNode;
|
||
function fetch_vdst8(VDST:Word;rtype:TsrDataType):PsrRegNode;
|
||
procedure fetch_vsrc8_vec2h(VSRC:Word;var dst0,dst1:PsrRegNode);
|
||
|
||
procedure _MakeCopy(dst:PsrRegSlot;src:PsrRegNode);
|
||
procedure MakeCopy(dst:PsrRegSlot;src:PsrRegNode);
|
||
|
||
function GroupingSharp(src:PPsrRegSlot;rtype:TsrResourceType):PsrDataLayout;
|
||
|
||
procedure PrepTypeSlot(pSlot:PsrRegSlot;rtype:TsrDataType);
|
||
|
||
function MakeRead(pSlot:PsrRegSlot;rtype:TsrDataType):PsrRegNode;
|
||
|
||
procedure LoadPrepType(node:PsrRegNode;p:PspirvOp;rtype:TsrDataType);
|
||
procedure RegPrepType(node:PsrRegNode;rtype:TsrDataType);
|
||
|
||
procedure _emit_spi;
|
||
procedure _emit_DS;
|
||
procedure _emit_SOPK;
|
||
end;
|
||
|
||
function RegDown(node:PsrRegNode):PsrRegNode;
|
||
function RegDownSlot(node:PsrRegNode):PsrRegNode;
|
||
|
||
Procedure mark_read(const node:TOpParamSingle);
|
||
Procedure mark_write(const node:TOpParamSingle);
|
||
|
||
function GetChainRegNode(node:PsrRegNode):PsrChain;
|
||
function GetSourceRegNode(node:PsrRegNode):TOpParamSingle;
|
||
function GetInputRegNode(node:PsrRegNode):PsrInput;
|
||
|
||
implementation
|
||
|
||
uses
|
||
srVolatile,
|
||
emit_op,
|
||
emit_SOP1,
|
||
emit_SOP2,
|
||
emit_SOPC,
|
||
emit_SOPP,
|
||
emit_VOP1,
|
||
emit_VOP2,
|
||
emit_VOP3,
|
||
emit_VOPC,
|
||
emit_MUBUF,
|
||
emit_MTBUF,
|
||
emit_EXP,
|
||
emit_VINTRP,
|
||
emit_SMRD,
|
||
emit_MIMG;
|
||
|
||
function TSprvEmit.Alloc(Size:ptruint):Pointer;
|
||
begin
|
||
Result:=FAllocator.Alloc(Size);
|
||
end;
|
||
|
||
procedure TSprvEmit.SetPtr(base:Pointer;bType:TsrBlockType);
|
||
begin
|
||
if (FCursor.Adr.get_pc=base) then Exit;
|
||
FCursor:=FCodeHeap.FetchByPtr(base,bType);
|
||
end;
|
||
|
||
function TSprvEmit.Parse(base:Pointer):Byte;
|
||
begin
|
||
SetPtr(base,btMain);
|
||
FMain^.FTop.SetCFGBlock(FCursor.pBlock);
|
||
While (CheckBlockBeg) do;
|
||
repeat
|
||
Result:=NextParse;
|
||
Case Result of
|
||
0:;
|
||
1:Break;
|
||
else
|
||
Break;
|
||
end;
|
||
until false;
|
||
end;
|
||
|
||
function TSprvEmit.NextParse:Byte;
|
||
var
|
||
FLevel:DWORD;
|
||
begin
|
||
if (FCursor.pCode=nil) then Exit(2);
|
||
if (FCursor.pBlock=nil) then Exit(3);
|
||
if (FMain=nil) then Exit(4);
|
||
if (FMain^.pBlock=nil) then Exit(5);
|
||
|
||
|
||
if FPrintAsm then
|
||
begin
|
||
Write(HexStr(FCursor.OFFSET_DW*4,4));
|
||
FLevel:=0;
|
||
if (FMain<>nil) then
|
||
if (FMain^.pBlock<>nil) then
|
||
begin
|
||
FLevel:=FMain^.pBlock^.FLevel;
|
||
end;
|
||
Write(Space(FLevel+1));
|
||
end;
|
||
|
||
Result:=FCursor.Next(FSPI);
|
||
if (Result>1) then Exit;
|
||
|
||
if FPrintAsm then
|
||
begin
|
||
print_spi(FSPI);
|
||
end;
|
||
|
||
_emit_spi;
|
||
|
||
While (CheckBlockBeg) do;
|
||
While (CheckBlockEnd) do;
|
||
|
||
Result:=0;
|
||
if IsFinalize then
|
||
begin
|
||
Finalize;
|
||
Result:=1;
|
||
end;
|
||
|
||
end;
|
||
|
||
function TSprvEmit.IsFinalize:Boolean;
|
||
begin
|
||
Result:=False;
|
||
if (FMain^.pBlock^.pParent=nil) then
|
||
if FCursor.pBlock^.IsEndOf(FCursor.Adr) then
|
||
begin
|
||
Result:=True;
|
||
end;
|
||
end;
|
||
|
||
function TSprvEmit.FindLabel(Adr:TSrcAdr):PsrLabel;
|
||
begin
|
||
Result:=nil;
|
||
if (FCursor.pCode=nil) then Exit;
|
||
Result:=FCursor.pCode^.FindLabel(Adr);
|
||
end;
|
||
|
||
function TSprvEmit.CheckBlockBeg:Boolean;
|
||
var
|
||
pLBlock:PsrCFGBlock;
|
||
pOpLabel:array[0..3] of PspirvOp;
|
||
pOpBlock:PsrOpBlock;
|
||
pOpChild:PsrOpBlock;
|
||
adr:TSrcAdr;
|
||
Info:TsrBlockInfo;
|
||
begin
|
||
Result:=False;
|
||
adr:=FCursor.Adr;
|
||
if (FindLabel(adr)=nil) then Exit;
|
||
|
||
pLBlock:=FCursor.pBlock^.FindBlock(adr);
|
||
if (pLBlock<>nil) then
|
||
Case pLBlock^.bType of
|
||
btLoop:
|
||
begin
|
||
TEmitVolatile(Self).make_copy_all;
|
||
|
||
Info:=Default(TsrBlockInfo);
|
||
Info.b_adr:=pLBlock^.pBLabel^.Adr;
|
||
Info.e_adr:=pLBlock^.pELabel^.Adr;
|
||
Info.bType:=btLoop;
|
||
|
||
pOpLabel[0]:=NewLabelOp; //continue
|
||
pOpLabel[1]:=NewLabelOp; //end
|
||
pOpLabel[2]:=NewLabelOp; //cond
|
||
pOpLabel[3]:=NewLabelOp; //start
|
||
|
||
pOpLabel[0]^.Adr:=Info.b_adr;
|
||
pOpLabel[1]^.Adr:=Info.e_adr;
|
||
pOpLabel[2]^.Adr:=Info.e_adr;
|
||
pOpLabel[3]^.Adr:=Info.b_adr;
|
||
|
||
pOpBlock:=NewBlockOp(FRegsStory.get_snapshot);
|
||
pOpBlock^.SetLabels(pOpLabel[0],pOpLabel[1],pOpLabel[2]);
|
||
pOpBlock^.SetInfo(Info);
|
||
|
||
PushBlockOp(line,pOpBlock,pLBlock);
|
||
|
||
TEmitOp(Self).emit_OpBranch(line,pOpLabel[0]);
|
||
AddSpirvOp(line,pOpLabel[0]); //continue loop
|
||
|
||
TEmitOp(Self).emit_OpLoopMerge(line,pOpLabel[1],pOpLabel[2]);
|
||
TEmitOp(Self).emit_OpBranch(line,pOpLabel[3]);
|
||
AddSpirvOp(line,pOpLabel[3]);
|
||
|
||
//down group
|
||
Info.bType:=btOther;
|
||
pOpChild:=AllocBlockOp;
|
||
pOpChild^.SetInfo(Info);
|
||
PushBlockOp(line,pOpChild,nil);
|
||
end;
|
||
btAdr: //skip
|
||
begin
|
||
adr:=pLBlock^.pELabel^.Adr;
|
||
FCursor.Adr:=adr;
|
||
end;
|
||
else;
|
||
end;
|
||
|
||
end;
|
||
|
||
function TSprvEmit.CheckBlockEnd:Boolean;
|
||
begin
|
||
Result:=False;
|
||
if (FMain=nil) then Exit;
|
||
if (FMain^.pBlock=nil) then Exit;
|
||
|
||
if (FMain^.pBlock^.pParent<>nil) and
|
||
FMain^.pBlock^.IsEndOf(FCursor.Adr) then
|
||
begin
|
||
Result:=PopBlockOp;
|
||
end;
|
||
end;
|
||
|
||
procedure TSprvEmit.Finalize;
|
||
begin
|
||
if (FMain=nil) then Exit;
|
||
|
||
if (FMain^.pBlock<>nil) then
|
||
While (FMain^.pBlock^.pParent<>nil) do
|
||
begin
|
||
PopBlockOp;
|
||
end;
|
||
|
||
AddSpirvOp(Op.OpFunctionEnd);
|
||
end;
|
||
|
||
//%void = OpTypeVoid;
|
||
//%f_void = OpTypeFunction %void;
|
||
//%f_main = OpFunction %void None %f_void;
|
||
//%l_main = OpLabel;
|
||
|
||
function TSprvEmit.NewLabelOp:PSpirvOp;
|
||
Var
|
||
node:PSpirvOp;
|
||
begin
|
||
node:=NewSpirvOp(Op.OpLabel);
|
||
node^.dst.SetParam(ntRefId,NewRefId);
|
||
Result:=node;
|
||
end;
|
||
|
||
function TSprvEmit.NewMain:PSpirvFunc;
|
||
var
|
||
tvoid,tftype:PsrType;
|
||
node:PspirvOp;
|
||
|
||
begin
|
||
FMain:=Alloc(SizeOf(TSpirvFunc));
|
||
FMain^.Init('main',@Alloc);
|
||
FMain^.mark_read;
|
||
|
||
//OpTypeVoid
|
||
tvoid:=FSpirvTypes.Fetch(dtTypeVoid);
|
||
//OpTypeFunction
|
||
tftype:=FSpirvTypes.FetchFunction(tvoid);
|
||
|
||
//OpFunction
|
||
node:=@FMain^.FTop.dummy;
|
||
node^.OpId:=Op.OpFunction;
|
||
node^.dst_type:=tvoid;
|
||
node^.dst.SetParam(ntFunc,FMain); //self
|
||
node^.AddLiteral(FunctionControl.None,'None');
|
||
node^.AddParam(ntType,tftype);
|
||
|
||
//OpLabel
|
||
node:=NewLabelOp;
|
||
FMain^.AddSpirvOp(node);
|
||
|
||
Result:=FMain;
|
||
end;
|
||
|
||
procedure TSprvEmit.AddCap(ID:DWORD);
|
||
begin
|
||
FSpirvCaps.Add(ID);
|
||
end;
|
||
|
||
function TSprvEmit.AllocBlockOp:PsrOpBlock;
|
||
begin
|
||
Result:=Alloc(SizeOf(TsrOpBlock));
|
||
Result^.Alloc:=@Alloc;
|
||
Result^.dummy.pParent:=Result;
|
||
Result^.Push_head(@Result^.dummy);
|
||
end;
|
||
|
||
function TSprvEmit.NewBlockOp(Snap:TsrRegsSnapshot):PsrOpBlock;
|
||
begin
|
||
Result:=AllocBlockOp;
|
||
Result^.Regs.pSnap :=Alloc(SizeOf(TsrRegsSnapshot));
|
||
Result^.Regs.pSnap^:=Snap;
|
||
Result^.Regs.FVolMark:=vmNone;
|
||
Result^.Cond.FUseCont:=false;
|
||
end;
|
||
|
||
function TSprvEmit.InsertBlockOp(pLine:PspirvOp;pChild:PsrOpBlock):PspirvOp;
|
||
begin
|
||
pLine:=AddSpirvOp(pLine,OpBlock);
|
||
pLine^.dst.SetParam(ntBlock,pChild);
|
||
pChild^.pParent:=pLine^.pParent;
|
||
pChild^.pUpLine:=pLine;
|
||
pChild^.FLevel :=pLine^.pParent^.FLevel+1;
|
||
Result:=pLine;
|
||
end;
|
||
|
||
Procedure TSprvEmit.PushBlockOp(pLine:PspirvOp;pOpBlock:PsrOpBlock;pLBlock:PsrCFGBlock);
|
||
var
|
||
node:PSpirvOp;
|
||
begin
|
||
pOpBlock^.FCursor:=FCursor; //prev
|
||
|
||
node:=AddSpirvOp(pLine,OpBlock);
|
||
node^.dst.SetParam(ntBlock,pOpBlock);
|
||
pOpBlock^.pUpLine:=node;
|
||
FMain^.PushBlock(pOpBlock);
|
||
|
||
if (pLBlock<>nil) then
|
||
begin
|
||
FCursor.pBlock:=pLBlock; //push
|
||
end;
|
||
end;
|
||
|
||
procedure UpdateVolMark(pBlock:PsrOpBlock);
|
||
var
|
||
pLine:PspirvOp;
|
||
pChild:PsrOpBlock;
|
||
begin
|
||
if (pBlock=nil) then Exit;
|
||
if (pBlock^.Regs.FVolMark<>vmNone) then Exit;
|
||
pLine:=pBlock^.line;
|
||
if (pLine=nil) then Exit;
|
||
if (pLine^.OpId<>OpBlock) then Exit;
|
||
pChild:=pLine^.dst.AsBlock;
|
||
if (pChild=nil) then Exit;
|
||
Case pChild^.Block.bType of
|
||
btAdr,
|
||
btOther:;
|
||
else
|
||
Exit;
|
||
end;
|
||
pBlock^.Regs.FVolMark:=pChild^.Regs.FVolMark;
|
||
end;
|
||
|
||
function TSprvEmit.PopBlockOp:Boolean;
|
||
var
|
||
pOpBlock:PsrOpBlock;
|
||
pOpChild:PsrOpBlock;
|
||
pOpLabel:array[0..2] of PspirvOp;
|
||
begin
|
||
Result:=False;
|
||
if (FMain=nil) then Exit;
|
||
if (FMain^.pBlock=nil) then Exit;
|
||
|
||
pOpBlock:=FMain^.pBlock;
|
||
UpdateVolMark(pOpBlock);
|
||
|
||
pOpLabel[0]:=pOpBlock^.Labels.pBegOp;
|
||
pOpLabel[1]:=pOpBlock^.Labels.pEndOp;
|
||
pOpLabel[2]:=pOpBlock^.Labels.pMrgOp;
|
||
|
||
Case pOpBlock^.Block.bType of
|
||
btCond:
|
||
begin
|
||
|
||
Assert(pOpLabel[1]<>nil);
|
||
|
||
Case pOpBlock^.Regs.FVolMark of
|
||
vmNone:TEmitVolatile(Self).build_volatile_cur(pOpBlock^.Regs.pSnap);
|
||
vmEnd :TEmitVolatile(Self).build_volatile_dis(pOpBlock^.Regs.pSnap);
|
||
else;
|
||
end;
|
||
|
||
if not is_term_op(line) then
|
||
begin
|
||
TEmitOp(Self).emit_OpBranch(line,pOpLabel[1]);
|
||
end;
|
||
|
||
AddSpirvOp(line,pOpLabel[1]); //end
|
||
|
||
end;
|
||
btLoop:
|
||
begin
|
||
|
||
//add OpLoopMerge continue
|
||
|
||
Assert(pOpLabel[0]<>nil);
|
||
Assert(pOpLabel[1]<>nil);
|
||
Assert(pOpLabel[2]<>nil);
|
||
|
||
Case pOpBlock^.Regs.FVolMark of
|
||
vmNone:TEmitVolatile(Self).build_volatile_old(pOpBlock^.Regs.pSnap);
|
||
else;
|
||
end;
|
||
|
||
if pOpBlock^.Cond.FUseCont then //use continue
|
||
begin
|
||
|
||
if not is_term_op(line) then
|
||
begin
|
||
TEmitOp(Self).emit_OpBranch(line,pOpLabel[1]); //break
|
||
end;
|
||
|
||
AddSpirvOp(line,pOpLabel[2]); //OpLoopMerge end
|
||
|
||
pOpChild:=AllocBlockOp;
|
||
pOpChild^.SetInfo(btOther,FCursor.Adr,FCursor.Adr);
|
||
PushBlockOp(line,pOpChild,nil);
|
||
TEmitOp(Self).emit_OpBranch(line,pOpLabel[0]); //continue
|
||
FMain^.PopBlock;
|
||
|
||
AddSpirvOp(line,pOpLabel[1]); //end
|
||
|
||
end else //dont used continue
|
||
begin
|
||
|
||
if not is_term_op(line) then
|
||
begin
|
||
AddSpirvOp(line,NewLabelOp); //devide
|
||
end;
|
||
|
||
AddSpirvOp(line,pOpLabel[2]); //OpLoopMerge end
|
||
|
||
pOpChild:=AllocBlockOp;
|
||
pOpChild^.SetInfo(btOther,FCursor.Adr,FCursor.Adr);
|
||
PushBlockOp(line,pOpChild,nil);
|
||
TEmitOp(Self).emit_OpBranch(line,pOpLabel[1]); //break
|
||
FMain^.PopBlock;
|
||
|
||
AddSpirvOp(line,pOpLabel[1]); //end
|
||
|
||
end;
|
||
|
||
end;
|
||
else
|
||
if (pOpLabel[1]<>nil) then
|
||
begin
|
||
if not is_term_op(line) then
|
||
begin
|
||
TEmitOp(Self).emit_OpBranch(line,pOpLabel[1]);
|
||
end;
|
||
AddSpirvOp(line,pOpLabel[1]);
|
||
end;
|
||
end;
|
||
|
||
Case pOpBlock^.Block.bType of
|
||
btAdr:
|
||
begin
|
||
FCursor:=pOpBlock^.FCursor;
|
||
end;
|
||
btOther:; //nop
|
||
else
|
||
begin
|
||
FCursor.PopBlock;
|
||
end;
|
||
end;
|
||
|
||
Result:=FMain^.PopBlock;
|
||
end;
|
||
|
||
function TSprvEmit.NewSpirvOp(OpId:DWORD):PSpirvOp;
|
||
begin
|
||
Result:=Alloc(SizeOf(TSpirvOp));
|
||
Result^.adr :=FCursor.Adr;
|
||
Result^.OpId :=OpId;
|
||
end;
|
||
|
||
function TSprvEmit.AddSpirvOp(OpId:DWORD):PSpirvOp;
|
||
begin
|
||
Result:=AddSpirvOp(line,OpId);
|
||
end;
|
||
|
||
function TSprvEmit.AddSpirvOp(pLine:PspirvOp;OpId:DWORD):PSpirvOp;
|
||
begin
|
||
Result:=InsSpirvOp(pLine,NewSpirvOp(OpId));
|
||
end;
|
||
|
||
function TSprvEmit.AddSpirvOp(pLine,pNew:PspirvOp):PSpirvOp;
|
||
begin
|
||
Result:=InsSpirvOp(pLine,pNew);
|
||
end;
|
||
|
||
function TSprvEmit.line:PSpirvOp;
|
||
begin
|
||
Result:=nil;
|
||
if (FMain<>nil) then
|
||
begin
|
||
Result:=FMain^.line;
|
||
end;
|
||
end;
|
||
|
||
function TSprvEmit.init_line:PSpirvOp;
|
||
begin
|
||
Assert(FInitLine<>nil);
|
||
if (FInitLine^.dummy.pParent=nil) then
|
||
begin
|
||
FInitLine^.Alloc:=@Alloc;
|
||
FInitLine^.dummy.pParent:=FInitLine;
|
||
FInitLine^.Push_head(@FInitLine^.dummy);
|
||
end;
|
||
Result:=FInitLine^.line;
|
||
Assert(Result<>nil);
|
||
end;
|
||
|
||
procedure TSprvEmit.PostLink(ntype:TsrNodeType;Data:Pointer);
|
||
var
|
||
node:PspirvOp;
|
||
begin
|
||
node:=line;
|
||
if (node=nil) or (node^.OpId<>OpLinks) then
|
||
begin
|
||
node:=AddSpirvOp(OpLinks);
|
||
end;
|
||
node^.AddParam(ntype,Data);
|
||
end;
|
||
|
||
procedure TSprvEmit.PostReg(pReg:PsrRegNode);
|
||
begin
|
||
PostLink(ntReg,pReg);
|
||
end;
|
||
|
||
function TSprvEmit.NewRefId:PsrRefId;
|
||
begin
|
||
Result:=Alloc(SizeOf(TsrRefId));
|
||
end;
|
||
|
||
function TSprvEmit.NewVariable:PsrVariable;
|
||
begin
|
||
Result:=Alloc(SizeOf(TsrVariable));
|
||
FVariables.Push_tail(Result);
|
||
end;
|
||
|
||
function TSprvEmit.AddInput(dst:PsrRegSlot;rtype:TsrDataType;itype:TpsslInputType;id:Byte=0):PsrRegNode;
|
||
var
|
||
i:PsrInput;
|
||
v:PsrVariable;
|
||
r:PsrRegNode;
|
||
begin
|
||
i:=FInputs.Fetch(itype,id);
|
||
v:=i^.pVar;
|
||
r:=i^.pReg;
|
||
|
||
if (v=nil) then
|
||
begin
|
||
v:=NewVariable;
|
||
v^.dtype:=rtype;
|
||
v^.pSource.SetParam(ntInput,i);
|
||
i^.pVar:=v;
|
||
end;
|
||
|
||
if (r=nil) then
|
||
begin
|
||
r:=dst^.New(line,rtype);
|
||
i^.pReg :=r;
|
||
v^.mark_read;
|
||
TEmitOp(Self).emit_OpLoad(init_line,r,v); //one in any scope
|
||
end else
|
||
if (dst^.current<>r) then
|
||
begin
|
||
MakeCopy(dst,r);
|
||
end;
|
||
|
||
Result:=r;
|
||
end;
|
||
|
||
function TSprvEmit.AllocDescVar(p:Pointer;_ntype:TsrNodeType;rtype:TsrDataType):PsrVariable;
|
||
var
|
||
d:PsrDescriptor;
|
||
begin
|
||
Result:=nil;
|
||
if (p=nil) then Exit;
|
||
d:=p;
|
||
if (d^.pVar=nil) then
|
||
begin
|
||
d^.pVar:=NewVariable;
|
||
d^.pVar^.dtype:=rtype;
|
||
d^.pVar^.pSource.SetParam(_ntype,p);
|
||
end;
|
||
Result:=d^.pVar;
|
||
end;
|
||
|
||
function TSprvEmit.AddVertLayout(pLayout:PsrDataLayout;rtype:TsrDataType):PsrRegNode;
|
||
var
|
||
i:PsrVertLayout;
|
||
v:PsrVariable;
|
||
dst:PsrRegNode;
|
||
begin
|
||
i:=FVertLayouts.Fetch(pLayout);
|
||
v:=AllocDescVar(i,ntVertLayout,rtype);
|
||
dst:=i^.pReg;
|
||
if (dst=nil) then
|
||
begin
|
||
dst:=NewReg(rtype);
|
||
i^.pReg:=dst;
|
||
v^.mark_read;
|
||
TEmitOp(Self).emit_OpLoad(init_line,dst,v); //one in any scope
|
||
end;
|
||
Result:=dst;
|
||
end;
|
||
|
||
function TSprvEmit.AddFragLayout(itype:TpsslInputType;rtype:TsrDataType;location:DWORD):PsrRegNode;
|
||
var
|
||
i:PsrFragLayout;
|
||
v:PsrVariable;
|
||
dst:PsrRegNode;
|
||
begin
|
||
i:=FFragLayouts.Fetch(itype,location);
|
||
v:=AllocDescVar(i,ntFragLayout,rtype);
|
||
dst:=i^.pReg;
|
||
if (dst=nil) then
|
||
begin
|
||
dst:=NewReg(rtype);
|
||
i^.pReg:=dst;
|
||
v^.mark_read;
|
||
TEmitOp(Self).emit_OpLoad(init_line,dst,v); //one in any scope
|
||
end;
|
||
Result:=dst;
|
||
end;
|
||
|
||
function TSprvEmit.FetchLoad(pChain:PsrChain;rtype:TsrDataType):PsrRegNode;
|
||
var
|
||
dtype:TsrDataType;
|
||
src:TOpParamSingle;
|
||
begin
|
||
Result:=nil;
|
||
if (pChain=nil) then Exit;
|
||
|
||
dtype:=pChain^.GetRegType;
|
||
if (dtype=dtUnknow) and (rtype<>dtUnknow) then
|
||
begin
|
||
dtype:=rtype;
|
||
pChain^.SetRegType(dtype);
|
||
end;
|
||
|
||
Result:=pChain^.rSlot.New(line,dtype);
|
||
pChain^.mark_read;
|
||
|
||
src:=Default(TOpParamSingle);
|
||
src.SetParam(ntChain,pChain);
|
||
TEmitOp(Self).emit_OpLoad(line,FSpirvTypes.Fetch(dtype),Result,src);
|
||
|
||
if not CompareType(dtype,rtype) then
|
||
begin
|
||
MakeCopy(@FRegsStory.FUnattach,Result);
|
||
Result:=FRegsStory.FUnattach.current;
|
||
Result^.dtype:=rtype;
|
||
end;
|
||
end;
|
||
|
||
Procedure TSprvEmit.FetchStore(pChain:PsrChain;src:PsrRegNode);
|
||
var
|
||
dtype:TsrDataType;
|
||
dst:TOpParamSingle;
|
||
pReg:PsrRegNode;
|
||
begin
|
||
if (pChain=nil) or (src=nil) then Exit;
|
||
|
||
dtype:=pChain^.GetRegType;
|
||
if (dtype=dtUnknow) and (src^.dtype<>dtUnknow) then
|
||
begin
|
||
dtype:=src^.dtype;
|
||
pChain^.SetRegType(dtype);
|
||
end;
|
||
|
||
pReg:=pChain^.rSlot.New(line,dtype);
|
||
pReg^.mark_read;
|
||
pChain^.mark_write;
|
||
|
||
dst:=Default(TOpParamSingle);
|
||
dst.SetParam(ntChain,pChain);
|
||
TEmitOp(Self).emit_OpStore(line,dst,pReg);
|
||
pReg^.pLine:=line; //update line
|
||
|
||
pReg^.pWriter.SetParam(ntReg,src);
|
||
end;
|
||
|
||
procedure TSprvEmit.AddUserdata(dst:PsrRegSlot;offset_dw:Byte);
|
||
var
|
||
pLayout:PsrDataLayout;
|
||
pChain:PsrChain;
|
||
pReg:PsrRegNode;
|
||
begin
|
||
pLayout:=FDataLayouts.Fetch(nil,0,rtBufPtr2);
|
||
pChain:=pLayout^.Fetch(offset_dw*4,4,nil);
|
||
pReg:=FetchLoad(pChain,dtUnknow);
|
||
MakeCopy(dst,pReg);
|
||
end;
|
||
|
||
function TSprvEmit.FetchChain(grp:PsrDataLayout;offset,size:DWORD;ext:PsrChainExt):PsrRegNode;
|
||
var
|
||
pChain:PsrChain;
|
||
begin
|
||
pChain:=grp^.Fetch(offset,size,ext);
|
||
Result:=FetchLoad(pChain,dtUnknow);
|
||
end;
|
||
|
||
function TSprvEmit.MakeChain(pSlot:PsrRegSlot;grp:PsrDataLayout;offset,size:PtrUint;ext:PsrChainExt):PsrRegNode;
|
||
var
|
||
pChain:PsrChain;
|
||
pReg:PsrRegNode;
|
||
begin
|
||
pChain:=grp^.Fetch(offset,size,ext);
|
||
pReg:=FetchLoad(pChain,dtUnknow);
|
||
MakeCopy(pSlot,pReg);
|
||
Result:=pSlot^.current;
|
||
end;
|
||
|
||
Procedure TSprvEmit.AddVecInput(dst:PsrRegSlot;vtype,rtype:TsrDataType;itype:TpsslInputType;id:Byte);
|
||
var
|
||
rsl:PsrRegNode;
|
||
begin
|
||
rsl:=AddInput(@FRegsStory.FUnattach,vtype,itype,0);
|
||
rsl^.mark_read;
|
||
dst^.New(line,rtype);
|
||
TEmitOp(Self).emit_OpCompExtract(init_line,dst^.current,rsl,id);
|
||
end;
|
||
|
||
////
|
||
|
||
function TSprvEmit.FetchUniform(src:PsrDataLayout;pType:PsrType):PsrRegNode;
|
||
var
|
||
pUniform:PsrUniform;
|
||
v:PsrVariable;
|
||
dst:PsrRegNode;
|
||
p:TOpParamSingle;
|
||
begin
|
||
pUniform:=FUniforms.Fetch(src,pType);
|
||
v:=AllocDescVar(pUniform,ntUniform,pType^.dtype);
|
||
if (v^.pType=nil) then
|
||
begin
|
||
v^.pType:=FSpirvTypes.FetchPointer(pType,pUniform^.FStorage);
|
||
end;
|
||
|
||
dst:=pUniform^.pReg;
|
||
if (dst=nil) then
|
||
begin
|
||
dst:=NewReg(pType^.dtype);
|
||
pUniform^.pReg:=dst;
|
||
v^.mark_read;
|
||
pType^.mark_read;
|
||
p.SetParam(ntVar,v);
|
||
TEmitOp(Self).emit_OpLoad(init_line,pType,dst,p); //one in any scope
|
||
end;
|
||
Result:=dst;
|
||
end;
|
||
|
||
function TSprvEmit.FetchImage(src:PsrDataLayout;dtype:TsrDataType;info:TsrTypeImageInfo):PsrRegNode;
|
||
var
|
||
pType:PsrType;
|
||
begin
|
||
pType:=FSpirvTypes.FetchImage(FSpirvTypes.Fetch(dtype),info);
|
||
Result:=FetchUniform(src,pType);
|
||
end;
|
||
|
||
function TSprvEmit.FetchSampler(src:PsrDataLayout):PsrRegNode;
|
||
var
|
||
pType:PsrType;
|
||
begin
|
||
pType:=FSpirvTypes.Fetch(dtTypeSampler);
|
||
Result:=FetchUniform(src,pType);
|
||
end;
|
||
|
||
function TSprvEmit.FetchOutput(etype:TpsslExportType;rtype:TsrDataType):PsrVariable;
|
||
var
|
||
o:PsrOutput;
|
||
begin
|
||
o:=FOutputs.Fetch(etype);
|
||
if (o^.pVar=nil) then
|
||
begin
|
||
o^.pVar:=NewVariable;
|
||
o^.pVar^.dtype:=rtype;
|
||
o^.pVar^.pSource.SetParam(ntOutput,o);
|
||
end;
|
||
o^.pVar^.mark_read;
|
||
Result:=o^.pVar;
|
||
end;
|
||
|
||
Procedure TSprvEmit.Init;
|
||
begin
|
||
FillChar(Self,SizeOf(TSprvEmit),0);
|
||
|
||
FUseVertexInput:=True;
|
||
|
||
FRegsStory .Init(@Alloc);
|
||
FOutputs .Init;
|
||
FCodeHeap .Alloc:=@Alloc;
|
||
FInputs .Init(@Alloc);
|
||
FDataLayouts.Init(@Alloc);
|
||
FVertLayouts.Init(@Alloc);
|
||
FFragLayouts.Alloc:=@Alloc;
|
||
FBuffers .Init(@Alloc);
|
||
FUniforms .Alloc:=@Alloc;
|
||
FCacheOps .Alloc:=@Alloc;
|
||
FConsts .Alloc:=@Alloc;
|
||
FBitcast .pRoot:=@Self;
|
||
FSpirvTypes .Alloc:=@Alloc;
|
||
FSpirvCaps .Alloc:=@Alloc;
|
||
|
||
FDebugInfo .Init(@Alloc);
|
||
FDecorates .Init(@Alloc);
|
||
|
||
FHeader .Init(@Alloc);
|
||
|
||
FSpirvFuncs.Insert(NewMain);
|
||
|
||
SetConst(@FRegsStory.VCC[0] ,dtBool,0);
|
||
SetConst(@FRegsStory.VCC[1] ,dtBool,0);
|
||
SetConst(@FRegsStory.EXEC[0],dtBool,1);
|
||
SetConst(@FRegsStory.EXEC[1],dtBool,0);
|
||
|
||
FInitLine:=AllocBlockOp;
|
||
FInitLine^.SetInfo(btOther,FCursor.Adr,FCursor.Adr);
|
||
PushBlockOp(line,FInitLine,nil);
|
||
FMain^.PopBlock;
|
||
end;
|
||
|
||
procedure TSprvEmit.SetUserData(pData:Pointer);
|
||
begin
|
||
FDataLayouts.SetUserData(pData);
|
||
end;
|
||
|
||
Procedure TSprvEmit.InitVs(RSRC2:TSPI_SHADER_PGM_RSRC2_VS;instance:Byte);
|
||
var
|
||
p:Byte;
|
||
begin
|
||
Init;
|
||
|
||
FExecutionModel:=ExecutionModel.Vertex;
|
||
|
||
//sgrp
|
||
p:=0;
|
||
if (RSRC2.USER_SGPR<>0) then
|
||
For p:=p to RSRC2.USER_SGPR-1 do
|
||
begin
|
||
AddUserdata(@FRegsStory.SGRP[p],p);
|
||
end;
|
||
p:=RSRC2.USER_SGPR;
|
||
|
||
if (RSRC2.SO_EN<>0) or
|
||
(RSRC2.OC_LDS_EN<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.SGRP[p],dtUint32,itVsState);
|
||
p:=p+1;
|
||
//s_vs_state
|
||
// stream_id[1:0], is_offchip[2],
|
||
// streamout_vtx_count[6:0],
|
||
// streamout_enable[15:0]}
|
||
end;
|
||
|
||
if (RSRC2.SO_EN<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.SGRP[p],dtUint32,itWriteIndex);
|
||
p:=p+1;
|
||
//s_so_write_index
|
||
// streamout_write_index[31:0]
|
||
end;
|
||
|
||
if (RSRC2.SO_BASE0_EN<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.SGRP[p],dtUint32,itOffset,0);
|
||
p:=p+1;
|
||
//s_so_base_offset0
|
||
// streamout_offset0[31:0]
|
||
end;
|
||
|
||
if (RSRC2.SO_BASE1_EN<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.SGRP[p],dtUint32,itOffset,1);
|
||
p:=p+1;
|
||
//s_so_base_offset1
|
||
// streamout_offset1[31:0]
|
||
end;
|
||
|
||
if (RSRC2.SO_BASE2_EN<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.SGRP[p],dtUint32,itOffset,2);
|
||
p:=p+1;
|
||
//s_so_base_offset2
|
||
// streamout_offset2[31:0]
|
||
end;
|
||
|
||
if (RSRC2.SO_BASE3_EN<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.SGRP[p],dtUint32,itOffset,3);
|
||
p:=p+1;
|
||
//s_so_base_offset3
|
||
// streamout_offset3[31:0]
|
||
end;
|
||
|
||
Assert(RSRC2.OC_LDS_EN=0);
|
||
|
||
if (RSRC2.DISPATCH_DRAW_EN<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.SGRP[p],dtUint32,itWaveId);
|
||
p:=p+1;
|
||
//s_wave_id
|
||
// wave_id [11:0] (dispatch draw term)
|
||
end;
|
||
|
||
if (RSRC2.SCRATCH_EN<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.SGRP[p],dtUint32,itScratch);
|
||
p:=p+1;
|
||
//s_scratch
|
||
// scratch offset (in bytes)
|
||
end;
|
||
|
||
//vgrp
|
||
p:=1;
|
||
AddInput(@FRegsStory.VGRP[0],dtUint32,itVIndex);
|
||
|
||
if (instance>=1) then
|
||
begin
|
||
AddInput(@FRegsStory.VGRP[p],dtUint32,itVInstance,1);
|
||
p:=p+1;
|
||
end;
|
||
|
||
if (instance>=2) then
|
||
begin
|
||
AddInput(@FRegsStory.VGRP[p],dtUint32,itVInstance,2);
|
||
p:=p+1;
|
||
end;
|
||
|
||
if (instance>=3) then
|
||
begin
|
||
AddInput(@FRegsStory.VGRP[p],dtUint32,itVInstance,0);
|
||
end;
|
||
|
||
AddCap(Capability.Shader);
|
||
|
||
end;
|
||
|
||
Procedure TSprvEmit.InitPs(RSRC2:TSPI_SHADER_PGM_RSRC2_PS;ENA:TSPI_PS_INPUT_ENA);
|
||
var
|
||
p:Byte;
|
||
begin
|
||
Init;
|
||
|
||
FExecutionModel:=ExecutionModel.Fragment;
|
||
|
||
//sgrp
|
||
p:=0;
|
||
if (RSRC2.USER_SGPR<>0) then
|
||
For p:=p to RSRC2.USER_SGPR-1 do
|
||
begin
|
||
AddUserdata(@FRegsStory.SGRP[p],p);
|
||
end;
|
||
p:=RSRC2.USER_SGPR;
|
||
|
||
begin
|
||
AddInput(@FRegsStory.SGRP[p],dtUint32,itPsState);
|
||
p:=p+1;
|
||
//s_ps_state
|
||
// {bc_optimize, prim_mask[14:0],
|
||
// lds_offset[15:0]}
|
||
end;
|
||
|
||
if (RSRC2.WAVE_CNT_EN<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.SGRP[p],dtUint32,itWaveCnt);
|
||
p:=p+1;
|
||
//(s_wave_cnt)
|
||
// {ps_wave_id[9:0], ps_strap_id,
|
||
// ps_pkr_id}
|
||
end;
|
||
|
||
if (RSRC2.SCRATCH_EN<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.SGRP[p],dtUint32,itScratch);
|
||
p:=p+1;
|
||
//s_scratch
|
||
// scratch offset (in bytes)
|
||
end;
|
||
|
||
//vgrp
|
||
p:=0;
|
||
if (ENA.PERSP_SAMPLE_ENA<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.VGRP[p],dtFloat32,itPerspSample,0);
|
||
p:=p+1;
|
||
AddInput(@FRegsStory.VGRP[p],dtFloat32,itPerspSample,1);
|
||
p:=p+1;
|
||
end;
|
||
|
||
if (ENA.PERSP_CENTER_ENA<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.VGRP[p],dtFloat32,itPerspCenter,0);
|
||
p:=p+1;
|
||
AddInput(@FRegsStory.VGRP[p],dtFloat32,itPerspCenter,1);
|
||
p:=p+1;
|
||
end;
|
||
|
||
if (ENA.PERSP_CENTROID_ENA<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.VGRP[p],dtFloat32,itPerspCentroid,0);
|
||
p:=p+1;
|
||
AddInput(@FRegsStory.VGRP[p],dtFloat32,itPerspCentroid,1);
|
||
p:=p+1;
|
||
end;
|
||
|
||
if (ENA.PERSP_PULL_MODEL_ENA<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.VGRP[p],dtFloat32,itPerspW,0);
|
||
p:=p+1;
|
||
AddInput(@FRegsStory.VGRP[p],dtFloat32,itPerspW,1);
|
||
p:=p+1;
|
||
AddInput(@FRegsStory.VGRP[p],dtFloat32,itPerspW,2);
|
||
p:=p+1;
|
||
end;
|
||
|
||
if (ENA.LINEAR_SAMPLE_ENA<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.VGRP[p],dtFloat32,itLinearSample,0);
|
||
p:=p+1;
|
||
AddInput(@FRegsStory.VGRP[p],dtFloat32,itLinearSample,1);
|
||
p:=p+1;
|
||
end;
|
||
|
||
if (ENA.LINEAR_CENTER_ENA<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.VGRP[p],dtFloat32,itLinearCenter,0);
|
||
p:=p+1;
|
||
AddInput(@FRegsStory.VGRP[p],dtFloat32,itLinearCenter,1);
|
||
p:=p+1;
|
||
end;
|
||
|
||
if (ENA.LINEAR_CENTROID_ENA<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.VGRP[p],dtFloat32,itLinearCentroid,0);
|
||
p:=p+1;
|
||
AddInput(@FRegsStory.VGRP[p],dtFloat32,itLinearCentroid,1);
|
||
p:=p+1;
|
||
end;
|
||
|
||
if (ENA.POS_X_FLOAT_ENA<>0) then
|
||
begin
|
||
AddVecInput(@FRegsStory.VGRP[p],dtVec4f,dtFloat32,itFloatPos,0);
|
||
p:=p+1;
|
||
end;
|
||
|
||
if (ENA.POS_Y_FLOAT_ENA<>0) then
|
||
begin
|
||
AddVecInput(@FRegsStory.VGRP[p],dtVec4f,dtFloat32,itFloatPos,1);
|
||
p:=p+1;
|
||
end;
|
||
|
||
if (ENA.POS_Z_FLOAT_ENA<>0) then
|
||
begin
|
||
AddVecInput(@FRegsStory.VGRP[p],dtVec4f,dtFloat32,itFloatPos,2);
|
||
p:=p+1;
|
||
end;
|
||
|
||
if (ENA.POS_W_FLOAT_ENA<>0) then
|
||
begin
|
||
AddVecInput(@FRegsStory.VGRP[p],dtVec4f,dtFloat32,itFloatPos,3);
|
||
p:=p+1;
|
||
end;
|
||
|
||
if (ENA.FRONT_FACE_ENA<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.VGRP[p],dtUint32,itFrontFace);
|
||
p:=p+1;
|
||
end;
|
||
|
||
if (ENA.ANCILLARY_ENA<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.VGRP[p],dtUint32,itAncillary);
|
||
p:=p+1;
|
||
//Render target array index[26:16], Iterated sample number[11:8], Primitive type[1:0]
|
||
end;
|
||
|
||
if (ENA.SAMPLE_COVERAGE_ENA<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.VGRP[p],dtUint32,itSampleCoverage);
|
||
p:=p+1;
|
||
end;
|
||
|
||
if (ENA.POS_FIXED_PT_ENA<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.VGRP[p],dtUint32,itPosFixed);
|
||
p:=p+1;
|
||
//Per-pixel fixed point position Y[31:16], X[15:0]
|
||
end;
|
||
|
||
AddCap(Capability.Shader);
|
||
|
||
end;
|
||
|
||
Procedure TSprvEmit.InitCs(RSRC2:TCOMPUTE_PGM_RSRC2;NTX:TCOMPUTE_NUM_THREAD_X;NTY:TCOMPUTE_NUM_THREAD_Y;NTZ:TCOMPUTE_NUM_THREAD_Z);
|
||
var
|
||
p:Byte;
|
||
begin
|
||
Init;
|
||
|
||
FExecutionModel:=ExecutionModel.GLCompute;
|
||
|
||
p:=0;
|
||
if (RSRC2.USER_SGPR<>0) then
|
||
For p:=p to RSRC2.USER_SGPR-1 do
|
||
begin
|
||
AddUserdata(@FRegsStory.SGRP[p],p);
|
||
end;
|
||
p:=RSRC2.USER_SGPR;
|
||
|
||
if (RSRC2.TGID_X_EN<>0) then
|
||
begin
|
||
AddVecInput(@FRegsStory.SGRP[p],dtVec3u,dtUint32,itTgid,0);
|
||
p:=p+1;
|
||
//(s_tgid_x) threadgroup_id0[31:0] computePgmRsrc2.tgid_x_en;tgid_x_en(1) //gl_WorkGroupID
|
||
end;
|
||
|
||
if (RSRC2.TGID_Y_EN<>0) then
|
||
begin
|
||
AddVecInput(@FRegsStory.SGRP[p],dtVec3u,dtUint32,itTgid,1);
|
||
p:=p+1;
|
||
//(s_tgid_y) threadgroup_id1[31:0] computePgmRsrc2.tgid_y_en;tgid_y_en(1) //gl_WorkGroupID
|
||
end;
|
||
|
||
if (RSRC2.TGID_Z_EN<>0) then
|
||
begin
|
||
AddVecInput(@FRegsStory.SGRP[p],dtVec3u,dtUint32,itTgid,2);
|
||
p:=p+1;
|
||
//(s_tgid_z) threadgroup_id2[31:0] computePgmRsrc2.tgid_z_en;tgid_z_en(1) //gl_WorkGroupID
|
||
end;
|
||
|
||
if (RSRC2.TG_SIZE_EN<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.SGRP[p],dtUint32,itTgSize);
|
||
p:=p+1;
|
||
//(s_tg_size) //gl_NumWorkGroups ???
|
||
{first_wave, 14’b0,
|
||
ordered_append_term[10:0],
|
||
threadgroup_size_in_waves[5:0]} //computePgmRsrc2.tg_size_en;tg_size_en(1)
|
||
end;
|
||
|
||
if (RSRC2.SCRATCH_EN<>0) then
|
||
begin
|
||
AddInput(@FRegsStory.SGRP[p],dtUint32,itScratch);
|
||
p:=p+1;
|
||
//s_scratch
|
||
// scratch offset (in bytes)
|
||
end;
|
||
|
||
//vgrp
|
||
p:=0;
|
||
begin
|
||
AddVecInput(@FRegsStory.VGRP[p],dtVec3u,dtUint32,itThreadId,0);
|
||
p:=p+1;
|
||
//(v_thread_id_x) Thread ID in group 0 //gl_LocalInvocationID
|
||
end;
|
||
|
||
if (RSRC2.TIDIG_COMP_CNT>=1) then
|
||
begin
|
||
AddVecInput(@FRegsStory.VGRP[p],dtVec3u,dtUint32,itThreadId,1);
|
||
p:=p+1;
|
||
//(v_thread_id_y) Thread ID in group 1 //gl_LocalInvocationID
|
||
end;
|
||
|
||
if (RSRC2.TIDIG_COMP_CNT>=2) then
|
||
begin
|
||
AddVecInput(@FRegsStory.VGRP[p],dtVec3u,dtUint32,itThreadId,2);
|
||
p:=p+1;
|
||
//(v_thread_id_z) Thread ID in group 2 //gl_LocalInvocationID
|
||
end;
|
||
|
||
FLocalSize.x:=NTX.NUM_THREAD_FULL+NTX.NUM_THREAD_PARTIAL;
|
||
FLocalSize.y:=NTY.NUM_THREAD_FULL+NTY.NUM_THREAD_PARTIAL;
|
||
FLocalSize.z:=NTZ.NUM_THREAD_FULL+NTZ.NUM_THREAD_PARTIAL;
|
||
|
||
if (FLocalSize.x=0) then FLocalSize.x:=1;
|
||
if (FLocalSize.y=0) then FLocalSize.y:=1;
|
||
if (FLocalSize.z=0) then FLocalSize.z:=1;
|
||
|
||
AddCap(Capability.Shader);
|
||
end;
|
||
|
||
Function TSprvEmit.NewReg(rtype:TsrDataType):PsrRegNode;
|
||
begin
|
||
Result:=FRegsStory.FUnattach.New(line,rtype);
|
||
end;
|
||
|
||
Function TSprvEmit.FetchReg(pConst:PsrConst):PsrRegNode;
|
||
begin
|
||
if (pConst=nil) then Exit(nil);
|
||
Result:=NewReg(pConst^.key.dtype);
|
||
Result^.SetConst(pConst);
|
||
Result^.mark_read;
|
||
end;
|
||
|
||
Procedure TSprvEmit.SetConst(pSlot:PsrRegSlot;pConst:PsrConst);
|
||
var
|
||
dst:PsrRegNode;
|
||
begin
|
||
dst:=pSlot^.New(line,pConst^.key.dtype);
|
||
dst^.SetConst(pConst);
|
||
|
||
dst^.mark_read;
|
||
PostReg(dst); //post processing
|
||
end;
|
||
|
||
Procedure TSprvEmit.SetConst(pSlot:PsrRegSlot;dtype:TsrDataType;value:QWORD);
|
||
begin
|
||
SetConst(pSlot,FConsts.Fetch(dtype,value));
|
||
end;
|
||
|
||
function TSprvEmit.fetch_soffset(SOFFSET:Word;rtype:TsrDataType):PsrRegNode;
|
||
Var
|
||
src:PsrRegSlot;
|
||
pConst:PsrConst;
|
||
begin
|
||
if is_const_ssrc8(SOFFSET) then
|
||
begin
|
||
pConst:=FConsts.Fetch_ssrc8_const(SOFFSET,0,rtype);
|
||
Result:=FetchReg(pConst);
|
||
end else
|
||
begin
|
||
src:=FRegsStory.get_ssrc8(SOFFSET);
|
||
Result:=MakeRead(src,rtype);
|
||
end;
|
||
end;
|
||
|
||
|
||
function TSprvEmit.fetch_ssrc9(SSRC:Word;rtype:TsrDataType):PsrRegNode;
|
||
Var
|
||
src:PsrRegSlot;
|
||
pConst:PsrConst;
|
||
begin
|
||
if is_const_ssrc9(SSRC) then
|
||
begin
|
||
pConst:=FConsts.Fetch_ssrc9_const(SSRC,FSPI.INLINE32,rtype);
|
||
Result:=FetchReg(pConst);
|
||
end else
|
||
begin
|
||
src:=FRegsStory.get_ssrc9(SSRC);
|
||
Result:=MakeRead(src,rtype);
|
||
end;
|
||
end;
|
||
|
||
function TSprvEmit.fetch_ssrc9_pair(src:PPsrRegNode;SSRC:Word;rtype:TsrDataType):Boolean;
|
||
Var
|
||
pSlot:array[0..1] of PsrRegSlot;
|
||
begin
|
||
if is_const_ssrc9(SSRC) then
|
||
begin
|
||
src[0]:=FetchReg(FConsts.Fetch_ssrc9_const(SSRC,FSPI.INLINE32,rtype));
|
||
src[1]:=FetchReg(FConsts.Fetch(dtUnknow,0));
|
||
Result:=True;
|
||
end else
|
||
begin
|
||
pSlot[0]:=nil;
|
||
pSlot[1]:=nil;
|
||
Result:=FRegsStory.get_ssrc9_pair(SSRC,pSlot);
|
||
if not Result then Exit;
|
||
src[0]:=MakeRead(pSlot[0],rtype);
|
||
src[1]:=MakeRead(pSlot[1],rtype);
|
||
end;
|
||
end;
|
||
|
||
function TSprvEmit.fetch_vsrc8(VSRC:Word;rtype:TsrDataType):PsrRegNode;
|
||
var
|
||
src:PsrRegSlot;
|
||
begin
|
||
src:=FRegsStory.get_vsrc8(VSRC);
|
||
Result:=MakeRead(src,rtype);
|
||
end;
|
||
|
||
function TSprvEmit.fetch_vdst8(VDST:Word;rtype:TsrDataType):PsrRegNode;
|
||
var
|
||
src:PsrRegSlot;
|
||
begin
|
||
src:=FRegsStory.get_vdst8(VDST);
|
||
Result:=MakeRead(src,rtype);
|
||
end;
|
||
|
||
procedure TSprvEmit.fetch_vsrc8_vec2h(VSRC:Word;var dst0,dst1:PsrRegNode);
|
||
var
|
||
pSlot:PsrRegSlot;
|
||
dst:PsrRegNode;
|
||
begin
|
||
pSlot:=FRegsStory.get_vsrc8(VSRC);
|
||
|
||
dst:=MakeRead(pSlot,dtVec2h);
|
||
dst^.mark_read;
|
||
|
||
dst0:=NewReg(dtHalf16);
|
||
dst1:=NewReg(dtHalf16);
|
||
|
||
dst0^.mark_read;
|
||
dst1^.mark_read;
|
||
|
||
TEmitOp(Self).emit_OpCompExtract(line,dst0,dst,0);
|
||
TEmitOp(Self).emit_OpCompExtract(line,dst1,dst,1);
|
||
end;
|
||
|
||
procedure TSprvEmit._MakeCopy(dst:PsrRegSlot;src:PsrRegNode);
|
||
var
|
||
node:PsrRegNode;
|
||
begin
|
||
node:=dst^.New(line,src^.dtype);
|
||
node^.pWriter.SetParam(ntReg,src);
|
||
|
||
dst^.current^.mark_read;
|
||
PostReg(dst^.current); //post processing
|
||
end;
|
||
|
||
procedure TSprvEmit.MakeCopy(dst:PsrRegSlot;src:PsrRegNode);
|
||
begin
|
||
src^.mark_read;
|
||
_MakeCopy(dst,src);
|
||
end;
|
||
|
||
function GetChainRegNode(node:PsrRegNode):PsrChain;
|
||
var
|
||
pOp:PSpirvOp;
|
||
begin
|
||
Result:=nil;
|
||
node:=RegDown(node);
|
||
pOp:=node^.AsOp;
|
||
if (pOp=nil) then Exit;
|
||
if (pOp^.OpId<>Op.OpLoad) then Exit;
|
||
Result:=pOp^.pParam.pHead^.AsChain;
|
||
end;
|
||
|
||
function GetSourceRegNode(node:PsrRegNode):TOpParamSingle;
|
||
var
|
||
pOp:PSpirvOp;
|
||
pVar:PsrVariable;
|
||
begin
|
||
Result:=Default(TOpParamSingle);
|
||
node:=RegDown(node);
|
||
pOp:=node^.AsOp;
|
||
if (pOp=nil) then Exit;
|
||
if (pOp^.OpId<>Op.OpLoad) then Exit;
|
||
pVar:=pOp^.pParam.pHead^.AsVar;
|
||
if (pVar=nil) then Exit;
|
||
Result:=pVar^.pSource;
|
||
end;
|
||
|
||
function GetInputRegNode(node:PsrRegNode):PsrInput;
|
||
var
|
||
pSource:TOpParamSingle;
|
||
begin
|
||
pSource:=GetSourceRegNode(node);
|
||
Result:=pSource.AsInput;
|
||
end;
|
||
|
||
//
|
||
|
||
function TSprvEmit.GroupingSharp(src:PPsrRegSlot;rtype:TsrResourceType):PsrDataLayout;
|
||
var
|
||
i,n:Byte;
|
||
chain:TsrChains;
|
||
begin
|
||
Result:=nil;
|
||
chain:=Default(TsrChains);
|
||
n:=GetResourceSizeDw(rtype);
|
||
For i:=0 to n-1 do
|
||
begin
|
||
chain[i]:=GetChainRegNode(src[i]^.current);
|
||
end;
|
||
Result:=FDataLayouts.Grouping(chain,rtype);
|
||
end;
|
||
|
||
procedure TSprvEmit.PrepTypeSlot(pSlot:PsrRegSlot;rtype:TsrDataType);
|
||
var
|
||
node:PsrRegNode;
|
||
begin
|
||
if (pSlot=nil) then Exit;
|
||
if (pSlot^.current=nil) then
|
||
begin
|
||
pSlot^.New(line,rtype); //Unresolve
|
||
Exit;
|
||
end;
|
||
|
||
if (rtype=dtUnknow) then Exit;
|
||
|
||
node:=pSlot^.current;
|
||
if (node^.dtype=dtUnknow) then
|
||
begin
|
||
RegPrepType(node,rtype);
|
||
end;
|
||
end;
|
||
|
||
function TSprvEmit.MakeRead(pSlot:PsrRegSlot;rtype:TsrDataType):PsrRegNode;
|
||
var
|
||
node:PsrRegNode;
|
||
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:=FBitcast.FetchRead(rtype,node);
|
||
end else
|
||
begin
|
||
Result:=node;
|
||
Result^.mark_read;
|
||
end;
|
||
end;
|
||
|
||
procedure TSprvEmit.LoadPrepType(node:PsrRegNode;p:PspirvOp;rtype:TsrDataType);
|
||
var
|
||
pVar:PsrVariable;
|
||
pChain:PsrChain;
|
||
ctype:TsrDataType;
|
||
pReg:PsrRegNode;
|
||
begin
|
||
if (p^.pParam.pHead^.pData<>nil) then
|
||
Case p^.pParam.pHead^.ntype of
|
||
ntVar:
|
||
begin
|
||
pVar:=p^.pParam.pHead^.AsVar;
|
||
if (pVar^.dtype=dtUnknow) then
|
||
begin
|
||
pVar^.dtype:=rtype;
|
||
end;
|
||
end;
|
||
ntChain:
|
||
begin
|
||
pChain:=p^.pParam.pHead^.AsChain;
|
||
ctype:=pChain^.GetRegType;
|
||
if (ctype=dtUnknow) then
|
||
begin
|
||
pChain^.SetRegType(rtype);
|
||
end else
|
||
if (ctype<>rtype) then
|
||
begin
|
||
pChain^.SetRegType(rtype);
|
||
pReg:=NewReg(rtype);
|
||
pReg^.pLine :=node^.pLine;
|
||
pReg^.pWriter:=node^.pWriter;
|
||
pReg^.mark_read;
|
||
node^.pWriter.SetParam(ntReg,pReg);
|
||
rtype:=ctype;
|
||
end;
|
||
end;
|
||
else;
|
||
end;
|
||
if (p^.dst_type=nil) then
|
||
begin
|
||
p^.dst_type:=FSpirvTypes.Fetch(rtype);
|
||
end;
|
||
end;
|
||
|
||
procedure TSprvEmit.RegPrepType(node:PsrRegNode;rtype:TsrDataType);
|
||
var
|
||
n:PsrRegNode;
|
||
pConst:PsrConst;
|
||
pOp:PspirvOp;
|
||
begin
|
||
if (rtype<>dtUnknow) and (node^.dtype=dtUnknow) then
|
||
begin
|
||
node^.dtype:=rtype;
|
||
//backtrace
|
||
While (true) do
|
||
begin
|
||
Case node^.pWriter.ntype of
|
||
ntVolatile:Break; //ignore
|
||
ntReg:
|
||
begin
|
||
n:=node^.pWriter.pData; //next
|
||
if (n^.dtype=dtUnknow) then
|
||
begin
|
||
n^.dtype:=rtype;
|
||
end else
|
||
begin
|
||
Break;
|
||
end;
|
||
node:=n;
|
||
end;
|
||
ntConst:
|
||
begin
|
||
pConst:=node^.pWriter.pData;
|
||
pConst^.mark_unread;
|
||
pConst:=FConsts.Bitcast(rtype,pConst);
|
||
node^.pWriter.pData:=pConst;
|
||
Break;
|
||
end;
|
||
ntOp:
|
||
begin
|
||
pOp:=node^.AsOp;
|
||
if (pOp<>nil) then
|
||
Case pOp^.OpId of
|
||
Op.OpLoad:
|
||
begin
|
||
LoadPrepType(node,pOp,rtype);
|
||
end;
|
||
else;
|
||
end;
|
||
Break;
|
||
end;
|
||
else
|
||
Assert(false,'RegPrepType');
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
function RegDown(node:PsrRegNode):PsrRegNode;
|
||
var
|
||
tmp:PsrRegNode;
|
||
begin
|
||
//backtrace
|
||
Result:=node;
|
||
While (Result<>nil) do
|
||
begin
|
||
tmp:=Result^.AsReg; //next
|
||
if (tmp=nil) then Break;
|
||
Result:=tmp;
|
||
end;
|
||
end;
|
||
|
||
function RegDownSlot(node:PsrRegNode):PsrRegNode;
|
||
var
|
||
tmp:PsrRegNode;
|
||
begin
|
||
//backtrace
|
||
Result:=node;
|
||
While (Result<>nil) do
|
||
begin
|
||
tmp:=Result^.AsReg; //next
|
||
if (tmp=nil) then Break;
|
||
if (tmp^.pSlot<>Result^.pSlot) then Break;
|
||
Result:=tmp;
|
||
end;
|
||
end;
|
||
|
||
Procedure mark_read(const node:TOpParamSingle);
|
||
begin
|
||
Case node.ntype of
|
||
ntConst:PsrConst (node.pData)^.mark_read;
|
||
ntType :PsrType (node.pData)^.mark_read;
|
||
ntFunc :PSpirvFunc (node.pData)^.mark_read;
|
||
ntVar :PsrVariable(node.pData)^.mark_read;
|
||
ntReg :PsrRegNode (node.pData)^.mark_read;
|
||
ntChain:PsrChain (node.pData)^.mark_read;
|
||
else
|
||
Assert(false,'mark_read');
|
||
end;
|
||
end;
|
||
|
||
Procedure mark_write(const node:TOpParamSingle);
|
||
begin
|
||
Case node.ntype of
|
||
ntConst:PsrConst (node.pData)^.mark_read;
|
||
ntType :PsrType (node.pData)^.mark_read;
|
||
ntFunc :PSpirvFunc (node.pData)^.mark_read;
|
||
ntVar :PsrVariable(node.pData)^.mark_write;
|
||
ntReg :PsrRegNode (node.pData)^.mark_read;
|
||
ntChain:PsrChain (node.pData)^.mark_write;
|
||
else
|
||
Assert(false,'mark_write');
|
||
end;
|
||
end;
|
||
|
||
procedure TSprvEmit._emit_spi;
|
||
begin
|
||
Case FSPI.CMD.EN of
|
||
W_SOP1 :TEmit_SOP1(Self)._emit_SOP1;
|
||
W_SOPC :TEmit_SOPC(Self)._emit_SOPC;
|
||
W_SOPP :TEmit_SOPP(Self)._emit_SOPP;
|
||
W_VOP1 :TEmit_VOP1(Self)._emit_VOP1;
|
||
W_VOPC :TEmit_VOPC(Self)._emit_VOPC;
|
||
W_VOP3 :Case FSPI.VOP3a.OP of
|
||
0..255:TEmit_VOP3(Self)._emit_VOP3c;
|
||
293..298,
|
||
365..366:TEmit_VOP3(Self)._emit_VOP3b;
|
||
else
|
||
TEmit_VOP3(Self)._emit_VOP3a;
|
||
end;
|
||
W_DS :_emit_DS;
|
||
W_MUBUF :TEmit_MUBUF(Self)._emit_MUBUF;
|
||
W_MTBUF :TEmit_MTBUF(Self)._emit_MTBUF;
|
||
W_EXP :TEmit_EXP(Self)._emit_EXP;
|
||
W_VINTRP:TEmit_VINTRP(Self)._emit_VINTRP;
|
||
W_MIMG :TEmit_MIMG(Self)._emit_MIMG;
|
||
W_SMRD :TEmit_SMRD(Self)._emit_SMRD;
|
||
W_SOPK :_emit_SOPK;
|
||
W_SOP2 :TEmit_SOP2(Self)._emit_SOP2;
|
||
W_VOP2 :TEmit_VOP2(Self)._emit_VOP2;
|
||
else
|
||
Assert(false);
|
||
end;
|
||
end;
|
||
|
||
procedure TSprvEmit._emit_DS;
|
||
begin
|
||
Assert(false,'DS?'+IntToStr(FSPI.DS.OP));
|
||
end;
|
||
|
||
procedure TSprvEmit._emit_SOPK;
|
||
begin
|
||
Assert(false,'SOPK?'+IntToStr(FSPI.SOPK.OP));
|
||
end;
|
||
|
||
end.
|
||
|