FPPS4/spirv/emit_fetch.pas

1055 lines
24 KiB
Plaintext

unit emit_fetch;
{$mode objfpc}{$H+}
interface
uses
ps4_shader,
ps4_pssl,
spirv,
srNode,
srBitcast,
srType,
srTypes,
srConst,
srReg,
srOp,
srOpInternal,
srOpUtils,
srLayout,
srVertLayout,
srFragLayout,
srVariable,
srInput,
srOutput,
srUniform,
srFlow;
type
TEmitFetch=class(TEmitFlow)
//
function GroupingVImm (regs:PPsrRegNode;rtype:TsrResourceType):TsrDataLayout;
function TryShortVSharp(regs:PPsrRegNode;rtype:TsrResourceType):TsrDataLayout;
function GroupingSharp (src :PPsrRegSlot;rtype:TsrResourceType):TsrDataLayout;
//
function get_sdst7(SDST:Byte):PsrRegSlot;
function get_sdst7_pair(SDST:Byte;dst:PPsrRegSlot):Boolean;
function get_sdst8(SSRC:Byte):PsrRegSlot;
function get_ssrc8(SSRC:Byte):PsrRegSlot;
function get_ssrc9(SSRC:Word):PsrRegSlot;
function get_ssrc9_pair(SSRC:Word;src:PPsrRegSlot):Boolean;
function get_vsrc8(VSRC:Byte):PsrRegSlot;
function get_vdst8(VDST:Byte):PsrRegSlot;
function get_sbase(SBASE,count:Byte;src:PPsrRegSlot):Boolean;
function get_srsrc(SRSRC,count:Byte;src:PPsrRegSlot):Boolean;
//
function get_snapshot:TsrRegsSnapshot;
//
function fetch_ssrc8(SOFFSET:Word;rtype:TsrDataType):TsrRegNode;
function fetch_ssrc9(SSRC:Word;rtype:TsrDataType):TsrRegNode;
function fetch_ssrc9_pair(SSRC:Word;src:PPsrRegNode;rtype:TsrDataType):Boolean;
function fetch_ssrc9_64(SSRC:Word;rtype:TsrDataType):TsrRegNode;
function fetch_vsrc8(VSRC:Word;rtype:TsrDataType):TsrRegNode;
function fetch_vdst8(VDST:Word;rtype:TsrDataType):TsrRegNode;
function fetch_vdst8_64(VDST:Word;rtype:TsrDataType):TsrRegNode;
//
procedure OpCmpV(OpId:DWORD;dst0,dst1:PsrRegSlot;src0,src1:TsrRegNode);
procedure OpCmpClass(dst0,dst1:PsrRegSlot;src0,src1:TsrRegNode);
procedure OpCmpS(OpId:DWORD;dst:PsrRegSlot;src0,src1:TsrRegNode);
procedure OpConvFloatToHalf2(dst:PsrRegSlot;src0,src1:TsrRegNode);
//
function AddInput(dst:PsrRegSlot;rtype:TsrDataType;itype:TpsslInputType;id:Byte=0):TsrRegNode;
function AddInstance(dst:PsrRegSlot;id:Byte;step_rate:DWORD):TsrRegNode;
function AddAncillary(dst:PsrRegSlot):TsrRegNode;
function AddVertLayout(pLayout:TsrDataLayout;rtype:TsrDataType):TsrRegNode;
function AddFragLayout(itype:TpsslInputType;rtype:TsrDataType;location:DWORD):TsrRegNode;
function FetchLoad (pChain:TsrChain;rtype:TsrDataType):TsrRegNode;
Procedure FetchStore(pChain:TsrChain;src:TsrRegNode);
function FetchAtomic(pChain:TsrChain;OpId:DWORD;dtype:TsrDataType;src:TsrRegNode):TsrRegNode;
procedure AddUserdata(dst:PsrRegSlot;offset_dw:Byte);
function FetchChain(grp:TsrDataLayout;lvl_0:PsrChainLvl_0;lvl_1:PsrChainLvl_1;cflags:Byte=0):TsrRegNode;
function MakeChain(pSlot:PsrRegSlot;grp:TsrDataLayout;lvl_0:PsrChainLvl_0;lvl_1:PsrChainLvl_1;cflags:Byte=0):TsrRegNode;
Procedure AddVecInput(dst:PsrRegSlot;vtype,rtype:TsrDataType;itype:TpsslInputType;id:Byte);
function AddPositionsInput(count:Byte):TsrVariable;
function AddParametersInput(id,count:Byte):TsrVariable;
function FetchUniformSimple(src:TsrDataLayout;pType:TsrType;GLC,SLC,degam:Boolean):TsrNode;
function FetchImage(src:TsrDataLayout;info:TsrImageInfo):TsrNode;
function FetchImageArray(src:TsrDataLayout;info:TsrImageInfo;array_count:DWORD):TsrNode;
function FetchImageRuntimeArray(src:TsrDataLayout;info:TsrImageInfo):TsrNode;
function FetchSampler(src:TsrDataLayout):TsrNode;
function FetchOutput(etype:TpsslExportType;rtype:TsrDataType):TsrOutput;
end;
function GetInputRegNode(node:TsrRegNode):TsrInput;
implementation
function GetInputRegNode(node:TsrRegNode):TsrInput;
var
pSource:TsrNode;
begin
pSource:=GetSourceRegNode(node);
Result:=pSource.specialize AsType<ntInput>;
end;
//
Function GetRegPairOp(reg:TsrRegNode):TSpirvOp;
var
pair:TsrRegPair;
begin
Result:=nil;
pair:=RegDown(reg).pWriter.specialize AsType<ntRegPair>;
if (pair=nil) then Exit;
Result:=pair.pWriter.specialize AsType<ntOp>;
end;
Function GetRegConst(reg:TsrRegNode):TsrConst;
begin
Result:=RegDown(reg).pWriter.specialize AsType<ntConst>;
end;
Function GetRegPairConst(reg:TsrRegNode):TsrConst;
var
pair:TsrRegPair;
begin
Result:=nil;
pair:=RegDown(reg).pWriter.specialize AsType<ntRegPair>;
if (pair=nil) then Exit;
Result:=pair.pWriter.specialize AsType<ntConst>;
end;
function TEmitFetch.GroupingVImm(regs:PPsrRegNode;rtype:TsrResourceType):TsrDataLayout;
var
vsharp:TVSharpResource4;
pop_1:array[0..1] of TSpirvOp;
pop_2:array[0..1] of TSpirvOp;
imms_p0:array[0..1] of TsrConst;
imms_p1:array[0..1] of TsrConst;
imms_p2:TsrConst;
imms_p3:TsrConst;
begin
Result:=nil;
if (rtype<>rtVSharp4) then Exit;
imms_p2:=GetRegConst(regs[2]);
imms_p3:=GetRegConst(regs[3]);
if (imms_p2=nil) then Exit;
if (imms_p3=nil) then Exit;
pop_1[0]:=GetRegPairOp(regs[0]);
pop_1[1]:=GetRegPairOp(regs[1]);
//S_GETPC_B64 s[0:1]
//S_ADD_U32 s0, #0x0000011C, s0
//S_ADDC_U32 s1, 0, s1
//S_MOV_B32 s2, 20
//S_MOV_B32 s3, #0x2000C004
if (pop_1[0]=nil) then Exit;
if (pop_1[1]=nil) then Exit;
if (pop_1[0].OpId<>srOpInternal.OpIAddExt) then Exit;
if (pop_1[1].OpId<>srOpInternal.OpIAddExt) then Exit;
//S_ADD_U32
imms_p0[0]:=GetRegConst(pop_1[0].ParamNode(0).AsReg); //const
imms_p0[1]:=GetRegConst(pop_1[0].ParamNode(1).AsReg); //s0
//(src0+src1)+SCC
pop_2[0]:=GetRegPairOp(pop_1[1].ParamNode(0).AsReg); //(src0+src1)
pop_2[1]:=GetRegPairOp(pop_1[1].ParamNode(1).AsReg); //SCC
if (pop_1[0]<>pop_2[1]) then Exit;
//S_ADDC_U32
imms_p1[0]:=GetRegConst(pop_2[0].ParamNode(0).AsReg);
imms_p1[1]:=GetRegConst(pop_2[0].ParamNode(1).AsReg);
vsharp:=Default(TVSharpResource4);
PQWORD(@vsharp)[0]:=imms_p0[0].AsInt32 + imms_p0[1].AsInt32;
PDWORD(@vsharp)[1]:=PDWORD(@vsharp)[1] + imms_p1[0].AsInt32 + imms_p1[1].AsInt32;
PDWORD(@vsharp)[2]:=imms_p2.AsInt32;
PDWORD(@vsharp)[3]:=imms_p3.AsInt32;
//print_vsharp(@vsharp);
Result:=DataLayoutList.FetchImm(@vsharp,rtype);
end;
function TryDisableAnisoLod0(regs:PPsrRegNode;rtype:TsrResourceType):Boolean;
var
reg:TsrRegNode;
pSelect:TSpirvOp;
cond:TsrRegNode;
pCmp:TSpirvOp;
pCmp_param0:TsrRegNode;
pCmp_param1:TsrRegNode;
pImm:TsrConst;
pBitField:TSpirvOp;
pBitwiseAnd:TSpirvOp;
begin
Result:=False;
if (rtype<>rtSSharp4) then Exit;
reg:=RegDown(regs[0]);
pSelect:=reg.pWriter.specialize AsType<ntOp>;
if (pSelect=nil) then Exit;
if (pSelect.OpId<>Op.OpSelect) then Exit;
cond:=RegDown(pSelect.ParamNode(0).AsReg);
if (cond=nil) then Exit;
pCmp:=cond.pWriter.specialize AsType<ntOp>;
if (pCmp=nil) then Exit;
if (pCmp.OpId<>Op.OpIEqual) then Exit;
pCmp_param0:=RegDown(pCmp.ParamNode(0).AsReg);
pCmp_param1:=RegDown(pCmp.ParamNode(1).AsReg);
if (pCmp_param0=nil) then Exit;
if (pCmp_param1=nil) then Exit;
reg:=nil;
if pCmp_param0.pWriter.IsType(ntConst) then
begin
pImm:=pCmp_param0.pWriter.specialize AsType<ntConst>;
if (pImm.AsUint32=0) then
begin
reg:=pCmp_param1;
end;
end;
if (reg=nil) then
if pCmp_param1.pWriter.IsType(ntConst) then
begin
pImm:=pCmp_param1.pWriter.specialize AsType<ntConst>;
if (pImm.AsUint32=0) then
begin
reg:=pCmp_param0;
end;
end;
if (reg=nil) then Exit;
reg:=RegDown(reg);
pBitField:=reg.pWriter.specialize AsType<ntOp>;
if (pBitField.OpId<>Op.OpBitFieldUExtract) then Exit;
pImm:=RegDown(pBitField.ParamNode(1).AsReg).pWriter.specialize AsType<ntConst>;
if (pImm=nil) then Exit;
if (pImm.AsUint32<>12) then Exit;
pImm:=RegDown(pBitField.ParamNode(2).AsReg).pWriter.specialize AsType<ntConst>;
if (pImm=nil) then Exit;
if (pImm.AsUint32<>8) then Exit;
reg:=RegDown(pSelect.ParamNode(1).AsReg);
if (reg=nil) then Exit;
pBitwiseAnd:=reg.pWriter.specialize AsType<ntOp>;
if (pBitwiseAnd=nil) then Exit;
if (pBitwiseAnd.OpId<>Op.OpBitwiseAnd) then Exit;
pImm:=RegDown(pBitwiseAnd.ParamNode(0).AsReg).pWriter.specialize AsType<ntConst>;
if (pImm<>nil) then
begin
if (pImm.AsUint32<>$FFFFF1FF) then Exit;
end else
begin
pImm:=RegDown(pBitwiseAnd.ParamNode(1).AsReg).pWriter.specialize AsType<ntConst>;
if (pImm=nil) then Exit;
if (pImm.AsUint32<>$FFFFF1FF) then Exit;
end;
//final
reg:=RegDown(pSelect.ParamNode(2).AsReg);
if (reg=nil) then Exit;
regs[0]:=reg;
Result:=True;
end;
function TEmitFetch.TryShortVSharp(regs:PPsrRegNode;rtype:TsrResourceType):TsrDataLayout;
var
chain:TsrChains;
reg:TsrRegNode;
pImm:TsrConst;
V2,V3:DWORD;
begin
Result:=nil;
if (rtype<>rtVSharp4) then Exit;
reg:=RegDown(regs[2]);
pImm:=reg.AsConst;
if (pImm=nil) then Exit;
V2:=pImm.AsUint32;
reg:=RegDown(regs[3]);
pImm:=reg.AsConst;
if (pImm=nil) then Exit;
V3:=pImm.AsUint32;
chain:=Default(TsrChains);
chain[0]:=GetChainRegNode(regs[0]);
chain[1]:=GetChainRegNode(regs[1]);
Result:=DataLayoutList.Grouping(chain,rtVSharp2);
if (Result<>nil) then
begin
Result.FData[2]:=V2;
Result.FData[3]:=V3;
end;
end;
function TEmitFetch.GroupingSharp(src:PPsrRegSlot;rtype:TsrResourceType):TsrDataLayout;
type
TsrRegs=array[0..7] of TsrRegNode;
var
regs:TsrRegs;
chain:TsrChains;
i,n:Byte;
begin
Result:=nil;
chain:=Default(TsrChains);
regs :=Default(TsrRegs);
n:=GetResourceSizeDw(rtype);
For i:=0 to n-1 do
begin
regs[i]:=RegDown(src[i]^.current);
end;
Result:=GroupingVImm(@regs,rtype);
if (Result<>nil) then Exit;
Result:=TryShortVSharp(@regs,rtype);
if (Result<>nil) then Exit;
//TODO: mark "disable_aniso"
TryDisableAnisoLod0(@regs,rtype);
For i:=0 to n-1 do
begin
chain[i]:=GetChainRegNode(regs[i]);
end;
Result:=DataLayoutList.Grouping(chain,rtype);
end;
//
function TEmitFetch.get_sdst7(SDST:Byte):PsrRegSlot;
begin
Result:=RegsStory.get_sdst7(SDST);
end;
function TEmitFetch.get_sdst7_pair(SDST:Byte;dst:PPsrRegSlot):Boolean;
begin
Result:=RegsStory.get_sdst7_pair(SDST,dst);
end;
function TEmitFetch.get_sdst8(SSRC:Byte):PsrRegSlot;
begin
Result:=RegsStory.get_sdst8(SSRC);
end;
function TEmitFetch.get_ssrc8(SSRC:Byte):PsrRegSlot;
begin
Result:=RegsStory.get_ssrc8(SSRC);
end;
function TEmitFetch.get_ssrc9(SSRC:Word):PsrRegSlot;
begin
Result:=RegsStory.get_ssrc9(SSRC);
end;
function TEmitFetch.get_ssrc9_pair(SSRC:Word;src:PPsrRegSlot):Boolean;
begin
Result:=RegsStory.get_ssrc9_pair(SSRC,src);
end;
function TEmitFetch.get_vsrc8(VSRC:Byte):PsrRegSlot;
begin
Result:=RegsStory.get_vsrc8(VSRC);
end;
function TEmitFetch.get_vdst8(VDST:Byte):PsrRegSlot;
begin
Result:=RegsStory.get_vdst8(VDST);
end;
function TEmitFetch.get_sbase(SBASE,count:Byte;src:PPsrRegSlot):Boolean;
begin
Result:=RegsStory.get_sbase(SBASE,count,src);
end;
function TEmitFetch.get_srsrc(SRSRC,count:Byte;src:PPsrRegSlot):Boolean;
begin
Result:=RegsStory.get_srsrc(SRSRC,count,src);
end;
//
function TEmitFetch.get_snapshot:TsrRegsSnapshot;
begin
Result:=RegsStory.get_snapshot;
end;
//
function TEmitFetch.fetch_ssrc8(SOFFSET:Word;rtype:TsrDataType):TsrRegNode;
Var
src:PsrRegSlot;
pConst:TsrConst;
begin
if is_const_ssrc8(SOFFSET) then
begin
pConst:=ConstList.Fetch_ssrc8_const(SOFFSET,0,rtype);
Result:=NewImm(pConst);
end else
begin
src:=RegsStory.get_ssrc8(SOFFSET);
Assert(src^.Category<>cVectorArray,'TODO:fetch_ssrc8 cVectorArray');
Result:=MakeRead(src,rtype);
end;
Assert(Result<>nil,'fetch_ssrc8');
end;
function TEmitFetch.fetch_ssrc9(SSRC:Word;rtype:TsrDataType):TsrRegNode;
Var
src:PsrRegSlot;
pConst:TsrConst;
begin
if is_const_ssrc9(SSRC) then
begin
pConst:=ConstList.Fetch_ssrc9_const(SSRC,FSPI.INLINE32,rtype);
Result:=NewImm(pConst);
end else
begin
src:=RegsStory.get_ssrc9(SSRC);
Assert(src^.Category<>cVectorArray,'TODO:fetch_ssrc9 cVectorArray');
Result:=MakeRead(src,rtype);
end;
Assert(Result<>nil,'fetch_ssrc9');
end;
function TEmitFetch.fetch_ssrc9_pair(SSRC:Word;src:PPsrRegNode;rtype:TsrDataType):Boolean;
Var
pSlot:array[0..1] of PsrRegSlot;
begin
if is_const_ssrc9(SSRC) then
begin
src[0]:=NewImm(ConstList.Fetch_ssrc9_const(SSRC,FSPI.INLINE32,rtype));
src[1]:=NewImm(ConstList.Fetch(rtype,0));
Result:=True;
end else
begin
pSlot[0]:=nil;
pSlot[1]:=nil;
Result:=RegsStory.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 TEmitFetch.fetch_ssrc9_64(SSRC:Word;rtype:TsrDataType):TsrRegNode;
var
src:array[0..1] of TsrRegNode;
dst:TsrRegNode;
begin
if not fetch_ssrc9_pair(SSRC,@src,dtUint32) then Assert(false);
dst:=NewReg(dtVec2u);
OpMakeCon(line,dst,@src);
Result:=BitcastList.FetchRead(rtype,dst);
end;
function TEmitFetch.fetch_vsrc8(VSRC:Word;rtype:TsrDataType):TsrRegNode;
var
src:PsrRegSlot;
begin
src:=RegsStory.get_vsrc8(VSRC);
Assert(src^.Category<>cVectorArray,'TODO:fetch_vsrc8 cVectorArray');
Result:=MakeRead(src,rtype);
Assert(Result<>nil,'fetch_vsrc8');
end;
function TEmitFetch.fetch_vdst8(VDST:Word;rtype:TsrDataType):TsrRegNode;
var
src:PsrRegSlot;
begin
src:=RegsStory.get_vdst8(VDST);
Result:=MakeRead(src,rtype);
Assert(Result<>nil,'fetch_vdst8');
end;
function TEmitFetch.fetch_vdst8_64(VDST:Word;rtype:TsrDataType):TsrRegNode;
var
src:array[0..1] of TsrRegNode;
begin
src[0]:=fetch_vdst8(VDST+0,dtUint32);
src[1]:=fetch_vdst8(VDST+1,dtUint32);
if (src[0]=nil) or (src[1]=nil) then
begin
Assert(False);
end;
Result:=fetch64(@src,rtype);
end;
//
procedure TEmitFetch.OpCmpV(OpId:DWORD;dst0,dst1:PsrRegSlot;src0,src1:TsrRegNode);
Var
tmp:TsrRegNode;
exc:TsrRegNode;
begin
case OpId of
Op.OpOrdered:
begin
//Op.OpOrdered -> (!isNan(S0) && !isNan(S1)) -> !(isNan(S0) || isNan(S1))
if (src0=src1) then
begin
tmp:=OpIsNanTo(src0);
end else
begin
src0:=OpIsNanTo(src0);
src1:=OpIsNanTo(src1);
tmp:=OpOrTo(src0,src1);
end;
tmp:=OpNotTo(tmp);
end;
Op.OpUnordered:
begin
//Op.OpUnordered -> (isNan(S0) || isNan(S1))
if (src0=src1) then
begin
tmp:=OpIsNanTo(src0);
end else
begin
src0:=OpIsNanTo(src0);
src1:=OpIsNanTo(src1);
tmp:=OpOrTo(src0,src1);
end;
end;
else
begin
tmp:=NewReg(dtBool);
_Op2(line,OpId,tmp,src0,src1);
end;
end;
exc:=GetThreadBit(get_exec0,get_exec1,dtBool);
exc:=OpLogicalAndTo(tmp,exc);
SetThreadBit(dst0,dst1,exc);
end;
const
fcSignalingNan = 1 shl 0;
fcQuietNan = 1 shl 1;
fcNegativeInfinity = 1 shl 2;
fcNegativeNormal = 1 shl 3;
fcNegativeDenorm = 1 shl 4;
fcNegativeZero = 1 shl 5;
fcPositiveZero = 1 shl 6;
fcPositiveDenorm = 1 shl 7;
fcPositiveNormal = 1 shl 8;
fcPositiveInfinity = 1 shl 9;
fcAny = (1 shl 10)-1;
fcNaN = fcSignalingNan or fcQuietNan;
fcInfinity = fcPositiveInfinity or fcNegativeInfinity;
fcNegative = fcNegativeInfinity or fcNegativeNormal or fcNegativeDenorm or fcNegativeZero;
fcPositive = fcPositiveZero or fcPositiveDenorm or fcPositiveNormal or fcPositiveInfinity;
procedure TEmitFetch.OpCmpClass(dst0,dst1:PsrRegSlot;src0,src1:TsrRegNode);
var
rsl:TsrRegNode;
ror:TsrRegNode;
exc:TsrRegNode;
msk:TsrConst;
val:DWORD;
function _test_group(val,mask:DWORD):Boolean; inline;
var
i:DWORD;
begin
i:=(val and mask);
Result:=(i=0) or (i=mask);
end;
begin
msk:=src1.AsConst;
if (msk<>nil) then
begin
val:=msk.AsUint32;
if (val and fcAny)=fcAny then
begin
ror:=NewImm_b(True);
end else
if _test_group(val,fcNaN ) or
_test_group(val,fcInfinity) or
_test_group(val,fcNegative) or
_test_group(val,fcPositive) then
begin
ror:=nil;
if (val and fcNaN)=fcNaN then
begin
rsl:=NewReg(dtBool);
_Op1(line,Op.OpIsNan,rsl,src0);
ror:=rsl;
end;
if (val and fcInfinity)=fcInfinity then
begin
rsl:=NewReg(dtBool);
_Op1(line,Op.OpIsInf,rsl,src0);
//
if (ror=nil) then
begin
ror:=rsl;
end else
begin
ror:=OpLogicalOrTo(ror,rsl);
end;
//
end;
if (val and fcNegative)=fcNegative then
begin
rsl:=NewReg(dtBool);
_Op2(line,Op.OpFOrdLessThanEqual,rsl,src0,NewImm_s(dtFloat32,-0.0));
//
if (ror=nil) then
begin
ror:=rsl;
end else
begin
ror:=OpLogicalOrTo(ror,rsl);
end;
//
end;
if (val and fcPositive)=fcPositive then
begin
rsl:=NewReg(dtBool);
_Op2(line,Op.OpFOrdGreaterThanEqual,rsl,src0,NewImm_s(dtFloat32,+0.0));
//
if (ror=nil) then
begin
ror:=rsl;
end else
begin
ror:=OpLogicalOrTo(ror,rsl);
end;
//
end;
if (ror=nil) then
begin
ror:=NewImm_b(False);
end;
end else
begin
Assert(false,'TODO: Unhandled mask V_CMP_CLASS_32:0x'+HexStr(val,2));
end;
end else
begin
Assert(false,'TODO: Non const V_CMP_CLASS_32');
end;
exc:=GetThreadBit(get_exec0,get_exec1,dtBool);
exc:=OpLogicalAndTo(ror,exc);
SetThreadBit(dst0,dst1,exc);
end;
procedure TEmitFetch.OpCmpS(OpId:DWORD;dst:PsrRegSlot;src0,src1:TsrRegNode);
begin
Op2(OpId,dtBool,dst,src0,src1);
end;
procedure TEmitFetch.OpConvFloatToHalf2(dst:PsrRegSlot;src0,src1:TsrRegNode);
var
rsl:array[0..1] of TsrRegNode;
begin
rsl[0]:=OpFToF(src0,dtHalf16);
rsl[1]:=OpFToF(src1,dtHalf16);
dst^.New(dtVec2h);
OpMakeCon(line,dst^.current,@rsl);
end;
//
function TEmitFetch.AddInput(dst:PsrRegSlot;rtype:TsrDataType;itype:TpsslInputType;id:Byte=0):TsrRegNode;
var
i:TsrInput;
v:TsrVariable;
r:TsrRegNode;
begin
i:=InputList.Fetch(rtype,itype,id);
v:=i.pVar;
r:=i.pReg;
if (r=nil) then
begin
r:=dst^.New(rtype);
i.pReg :=r;
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 TEmitFetch.AddInstance(dst:PsrRegSlot;id:Byte;step_rate:DWORD):TsrRegNode;
var
src:TsrRegNode;
begin
if (step_rate>1) then
begin
src:=AddInput(@RegsStory.FUnattach,dtUInt32,itVInstance,id);
src:=OpIDivTo(src,step_rate);
MakeCopy(dst,src);
end else
begin
src:=AddInput(dst,dtUInt32,itVInstance,id);
end;
Result:=src;
end;
function TEmitFetch.AddAncillary(dst:PsrRegSlot):TsrRegNode;
var
src:array[0..2] of TsrRegNode;
begin
src[0]:=NewImm_q(dtUInt32,0); //vPrimType
src[1]:=AddInput(@RegsStory.FUnattach,dtUInt32,itSampleId);
src[2]:=AddInput(@RegsStory.FUnattach,dtUInt32,itLayer);
OpPackAnc(dst,src[0],src[1],src[2]);
//Render target array index[26:16], BuiltIn.Layer
//Iterated sample number[11:8], BuiltIn.SampleId
//Primitive type[1:0] 0..3
//IL_REGTYPE_PRIMTYPE vPrimType
//The first component has sign bit = 1, this is a point. Values in other bits are undefined.
//The second component has sign bit = 1, this is a line. Values in other bits are undefined.
//PID ISID RTAI
//01|234567|89AB|CDEF|0123456789A|
//00|000000| |0000| |
Result:=dst^.current;
end;
function TEmitFetch.AddVertLayout(pLayout:TsrDataLayout;rtype:TsrDataType):TsrRegNode;
var
i:TsrVertLayout;
v:TsrVariable;
dst:TsrRegNode;
begin
i:=VertLayoutList.Fetch(pLayout,rtype);
v:=i.pVar;
dst:=i.pReg;
if (dst=nil) then
begin
dst:=NewReg(rtype);
i.pReg:=dst;
OpLoad(init_line,dst,v); //one in any scope
end;
Result:=dst;
end;
function TEmitFetch.AddFragLayout(itype:TpsslInputType;rtype:TsrDataType;location:DWORD):TsrRegNode;
var
i:TsrFragLayout;
v:TsrVariable;
dst:TsrRegNode;
begin
i:=FragLayoutList.Fetch(itype,location,rtype);
v:=i.pVar;
dst:=i.pReg;
if (dst=nil) then
begin
dst:=NewReg(rtype);
i.pReg:=dst;
OpLoad(init_line,dst,v); //one in any scope
end;
Result:=dst;
end;
function TEmitFetch.FetchLoad(pChain:TsrChain;rtype:TsrDataType):TsrRegNode;
begin
Result:=nil;
if (pChain=nil) then Exit;
Result:=NewReg(rtype);
pChain.FetchLoad(line,Result);
end;
Procedure TEmitFetch.FetchStore(pChain:TsrChain;src:TsrRegNode);
begin
if (pChain=nil) or (src=nil) then Exit;
pChain.FetchStore(line,src);
end;
function TEmitFetch.FetchAtomic(pChain:TsrChain;OpId:DWORD;dtype:TsrDataType;src:TsrRegNode):TsrRegNode;
var
pLine:TSpirvOp;
iScope,iMemorySemantics:Integer;
begin
if pChain.Parent.IsLocalDataShare then
begin
if (FExecutionModel=ExecutionModel.GLCompute) then
begin
//Workgroup
iScope:=Scope.Workgroup;
iMemorySemantics:=MemorySemantics.AcquireRelease or MemorySemantics.WorkgroupMemory;
end else
begin
Writeln(stderr,'AtomicOP on Private memory?');
//private
iScope:=Scope.Invocation;
iMemorySemantics:=MemorySemantics.None;
end;
end else
begin
//Storage/uniform
iScope:=Scope.Invocation;
iMemorySemantics:=MemorySemantics.None;
end;
pLine:=AddSpirvOp(OpId);
pLine.pDst :=NewReg(dtype);
pLine.pType:=TypeList.Fetch(dtype);
pLine.AddParam(pChain); //<-First
pChain.AddLine(pLine); //<-back link
//scope
pLine.AddParam(NewImm_i(dtInt32,iScope));
//MemorySemantics
pLine.AddParam(NewImm_i(dtInt32,iMemorySemantics));
//val
pLine.AddParam(src);
Result:=pLine.pDst;
end;
procedure TEmitFetch.AddUserdata(dst:PsrRegSlot;offset_dw:Byte);
var
lvl_0:TsrChainLvl_0;
pLayout:TsrDataLayout;
pChain:TsrChain;
pReg:TsrRegNode;
begin
pLayout:=DataLayoutList.pRoot;
lvl_0.offset:=offset_dw*4;
lvl_0.size :=4;
pChain:=pLayout.Fetch(@lvl_0,nil);
pReg:=FetchLoad(pChain,dtUnknow);
MakeCopy(dst,pReg);
end;
function TEmitFetch.FetchChain(grp:TsrDataLayout;lvl_0:PsrChainLvl_0;lvl_1:PsrChainLvl_1;cflags:Byte=0):TsrRegNode;
var
pChain:TsrChain;
begin
pChain:=grp.Fetch(lvl_0,lvl_1,cflags);
Result:=FetchLoad(pChain,dtUnknow);
end;
function TEmitFetch.MakeChain(pSlot:PsrRegSlot;grp:TsrDataLayout;lvl_0:PsrChainLvl_0;lvl_1:PsrChainLvl_1;cflags:Byte=0):TsrRegNode;
var
pChain:TsrChain;
pReg:TsrRegNode;
begin
pChain:=grp.Fetch(lvl_0,lvl_1,cflags);
pReg:=FetchLoad(pChain,dtUnknow);
MakeCopy(pSlot,pReg);
Result:=pSlot^.current;
end;
Procedure TEmitFetch.AddVecInput(dst:PsrRegSlot;vtype,rtype:TsrDataType;itype:TpsslInputType;id:Byte);
var
rsl:TsrRegNode;
begin
rsl:=AddInput(@RegsStory.FUnattach,vtype,itype,0);
OpExtract(init_line,dst^.New(rtype),rsl,id);
end;
function TEmitFetch.AddPositionsInput(count:Byte):TsrVariable;
var
i:TsrInput;
t:TsrType;
begin
t:=TypeList.FetchArray(TypeList.Fetch(dtVec4f),count);
i:=InputList.Fetch(t,itPositions,0);
Result:=i.pVar;
end;
function TEmitFetch.AddParametersInput(id,count:Byte):TsrVariable;
var
i:TsrInput;
t:TsrType;
begin
t:=TypeList.FetchArray(TypeList.Fetch(dtVec4f),count);
i:=InputList.Fetch(t,itParameters,id);
Result:=i.pVar;
end;
////
function TEmitFetch.FetchUniformSimple(src:TsrDataLayout;pType:TsrType;GLC,SLC,degam:Boolean):TsrNode;
var
u:TsrUniform;
v:TsrVariable;
r:TsrRegUniform;
begin
u:=UniformList.Fetch(src,pType,degam);
//
if (GLC) then
begin
u.Flags.Coherent:=True;
end;
//
if (SLC) then
begin
u.Flags.Volatile:=True;
end;
//
v:=u.pVar;
r:=u.pReg;
if (r.pLine=nil) then
begin
OpLoad(init_line,pType,r,v); //one in any scope
end;
Result:=r;
end;
function TEmitFetch.FetchImage(src:TsrDataLayout;info:TsrImageInfo):TsrNode;
var
pType:TsrType;
begin
pType:=TypeList.Fetch(info.dtype);
pType:=TypeList.FetchImage(pType,info.tinfo);
Result:=FetchUniformSimple(src,pType,info.GLC,info.SLC,info.degam);
end;
function TEmitFetch.FetchImageArray(src:TsrDataLayout;info:TsrImageInfo;array_count:DWORD):TsrNode;
var
pType:TsrType;
begin
pType:=TypeList.Fetch(info.dtype);
pType:=TypeList.FetchImage(pType,info.tinfo);
pType:=TypeList.FetchArray(pType,array_count);
Result:=UniformList.Fetch(src,pType,info.degam);
//
if (info.GLC) then
begin
TsrUniform(Result).Flags.Coherent:=True;
end;
//
if (info.SLC) then
begin
TsrUniform(Result).Flags.Volatile:=True;
end;
end;
function TEmitFetch.FetchImageRuntimeArray(src:TsrDataLayout;info:TsrImageInfo):TsrNode;
var
pType:TsrType;
begin
pType:=TypeList.Fetch(info.dtype);
pType:=TypeList.FetchImage(pType,info.tinfo);
pType:=TypeList.FetchRuntimeArray(pType);
Result:=UniformList.Fetch(src,pType,info.degam);
//
if (info.GLC) then
begin
TsrUniform(Result).Flags.Coherent:=True;
end;
//
if (info.SLC) then
begin
TsrUniform(Result).Flags.Volatile:=True;
end;
end;
function TEmitFetch.FetchSampler(src:TsrDataLayout):TsrNode;
var
pType:TsrType;
begin
pType:=TypeList.Fetch(dtTypeSampler);
Result:=FetchUniformSimple(src,pType,False,False,False);
end;
function TEmitFetch.FetchOutput(etype:TpsslExportType;rtype:TsrDataType):TsrOutput;
begin
Result:=OutputList.Fetch(etype,rtype);
end;
end.