fpPS4/spirv/emit_fetch.pas
2023-03-07 20:15:36 +03:00

619 lines
14 KiB
ObjectPascal

unit emit_fetch;
{$mode objfpc}{$H+}
interface
uses
ps4_pssl,
srNode,
srBitcast,
srType,
srTypes,
srConst,
srReg,
srOp,
srOpUtils,
srLayout,
srVertLayout,
srFragLayout,
srVariable,
srInput,
srOutput,
srUniform,
srFlow;
type
TEmitFetch=class(TEmitFlow)
//
function GroupingSharp(src:PPsrRegSlot;rtype:TsrResourceType):PsrDataLayout;
//
procedure PrepTypeSlot(pSlot:PsrRegSlot;rtype:TsrDataType);
function MakeRead(pSlot:PsrRegSlot;rtype:TsrDataType):PsrRegNode;
//
function PrepTypeNode(var node:PsrRegNode;rtype:TsrDataType;relax:Boolean=true):Integer;
function PrepTypeDst(var node:PsrRegNode;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;
//
function get_sdst7(SDST:Byte):PsrRegSlot;
function get_sdst7_pair(SDST:Byte;dst:PPsrRegSlot):Boolean;
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):PsrRegNode;
function fetch_ssrc9(SSRC:Word;rtype:TsrDataType):PsrRegNode;
function fetch_ssrc9_pair(SSRC:Word;src:PPsrRegNode;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 OpCmpV(OpId:DWORD;dst:PsrRegSlot;src0,src1:PsrRegNode);
procedure OpCmpS(OpId:DWORD;dst:PsrRegSlot;src0,src1:PsrRegNode);
procedure OpConvFloatToHalf2(dst:PsrRegSlot;src0,src1:PsrRegNode);
//
function AddInput(dst:PsrRegSlot;rtype:TsrDataType;itype:TpsslInputType;id:Byte=0):PsrRegNode;
function AddAncillary(dst:PsrRegSlot):PsrRegNode;
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;lvl_0:PsrChainLvl_0;lvl_1:PsrChainLvl_1):PsrRegNode;
function MakeChain(pSlot:PsrRegSlot;grp:PsrDataLayout;lvl_0:PsrChainLvl_0;lvl_1:PsrChainLvl_1):PsrRegNode;
Procedure AddVecInput(dst:PsrRegSlot;vtype,rtype:TsrDataType;itype:TpsslInputType;id:Byte);
function FetchUniform(src:PsrDataLayout;pType:PsrType):PsrNode;
function FetchImage(src:PsrDataLayout;dtype:TsrDataType;info:TsrTypeImageInfo):PsrNode;
function FetchSampler(src:PsrDataLayout):PsrNode;
function FetchOutput(etype:TpsslExportType;rtype:TsrDataType):PsrVariable;
end;
function GetInputRegNode(node:PsrRegNode):PsrInput;
implementation
function GetInputRegNode(node:PsrRegNode):PsrInput;
var
pSource:PsrNode;
begin
pSource:=GetSourceRegNode(node);
Result:=pSource^.AsType(ntInput);
end;
//
function TEmitFetch.GroupingSharp(src:PPsrRegSlot;rtype:TsrResourceType):PsrDataLayout;
var
chain:TsrChains;
i,n:Byte;
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:=DataLayoutList.Grouping(chain,rtype);
end;
//
procedure TEmitFetch.PrepTypeSlot(pSlot:PsrRegSlot;rtype:TsrDataType);
begin
if (pSlot=nil) then Exit;
if (pSlot^.current=nil) then
begin
pSlot^.New(line,rtype); //Unresolve
Exit;
end;
pSlot^.current^.PrepType(ord(rtype));
end;
function TEmitFetch.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:=BitcastList.FetchRead(rtype,node);
end else
begin
Result:=node;
end;
if (rtype<>dtUnknow) then
begin
Result^.Weak:=False;
end;
end;
//
function TEmitFetch.PrepTypeNode(var node:PsrRegNode;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^.Weak) 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 TEmitFetch.PrepTypeDst(var node:PsrRegNode;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^.Weak) 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 TEmitFetch.PrepTypeParam(node:POpParamNode;rtype:TsrDataType;relax:Boolean=true):Integer;
var
pReg:PsrRegNode;
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 TEmitFetch.get_vcc0:PsrRegSlot;
begin
Result:=@RegsStory.VCC[0];
end;
function TEmitFetch.get_vcc1:PsrRegSlot;
begin
Result:=@RegsStory.VCC[1];
end;
function TEmitFetch.get_m0:PsrRegSlot;
begin
Result:=@RegsStory.M0;
end;
function TEmitFetch.get_exec0:PsrRegSlot;
begin
Result:=@RegsStory.EXEC[0];
end;
function TEmitFetch.get_exec1:PsrRegSlot;
begin
Result:=@RegsStory.EXEC[1];
end;
function TEmitFetch.get_scc:PsrRegSlot;
begin
Result:=@RegsStory.SCC;
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_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):PsrRegNode;
Var
src:PsrRegSlot;
pConst:PsrConst;
begin
if is_const_ssrc8(SOFFSET) then
begin
pConst:=ConstList.Fetch_ssrc8_const(SOFFSET,0,rtype);
Result:=NewReg(pConst);
end else
begin
src:=RegsStory.get_ssrc8(SOFFSET);
Result:=MakeRead(src,rtype);
end;
Assert(Result<>nil,'fetch_ssrc8');
end;
function TEmitFetch.fetch_ssrc9(SSRC:Word;rtype:TsrDataType):PsrRegNode;
Var
src:PsrRegSlot;
pConst:PsrConst;
begin
if is_const_ssrc9(SSRC) then
begin
pConst:=ConstList.Fetch_ssrc9_const(SSRC,FSPI.INLINE32,rtype);
Result:=NewReg(pConst);
end else
begin
src:=RegsStory.get_ssrc9(SSRC);
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]:=NewReg(ConstList.Fetch_ssrc9_const(SSRC,FSPI.INLINE32,rtype));
src[1]:=NewReg(ConstList.Fetch(dtUnknow,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_vsrc8(VSRC:Word;rtype:TsrDataType):PsrRegNode;
var
src:PsrRegSlot;
begin
src:=RegsStory.get_vsrc8(VSRC);
Result:=MakeRead(src,rtype);
Assert(Result<>nil,'fetch_vsrc8');
end;
function TEmitFetch.fetch_vdst8(VDST:Word;rtype:TsrDataType):PsrRegNode;
var
src:PsrRegSlot;
begin
src:=RegsStory.get_vdst8(VDST);
Result:=MakeRead(src,rtype);
Assert(Result<>nil,'fetch_vdst8');
end;
procedure TEmitFetch.fetch_vsrc8_vec2h(VSRC:Word;var dst0,dst1:PsrRegNode);
var
pSlot:PsrRegSlot;
dst:PsrRegNode;
begin
pSlot:=RegsStory.get_vsrc8(VSRC);
dst:=MakeRead(pSlot,dtVec2h);
Assert(dst<>nil,'fetch_vsrc8_vec2h');
dst0:=NewReg(dtHalf16);
dst1:=NewReg(dtHalf16);;
OpExtract(line,dst0,dst,0);
OpExtract(line,dst1,dst,1);
end;
//
procedure TEmitFetch.OpCmpV(OpId:DWORD;dst:PsrRegSlot;src0,src1:PsrRegNode);
Var
tmp:PsrRegNode;
exc:PsrRegNode;
begin
tmp:=NewReg(dtBool);
_Op2(line,OpId,tmp,src0,src1);
exc:=MakeRead(get_exec0,dtBool);
OpLogicalAnd(dst,tmp,exc);
end;
procedure TEmitFetch.OpCmpS(OpId:DWORD;dst:PsrRegSlot;src0,src1:PsrRegNode);
begin
Op2(OpId,dtBool,dst,src0,src1);
end;
procedure TEmitFetch.OpConvFloatToHalf2(dst:PsrRegSlot;src0,src1:PsrRegNode);
var
rsl:array[0..1] of PsrRegNode;
begin
rsl[0]:=OpFToF(src0,dtHalf16);
rsl[1]:=OpFToF(src1,dtHalf16);
dst^.New(line,dtVec2h);
OpMakeCon(line,dst^.current,@rsl);
end;
//
function TEmitFetch.AddInput(dst:PsrRegSlot;rtype:TsrDataType;itype:TpsslInputType;id:Byte=0):PsrRegNode;
var
i:PsrInput;
v:PsrVariable;
r:PsrRegNode;
begin
i:=InputList.Fetch(rtype,itype,id);
v:=i^.pVar;
r:=i^.pReg;
if (r=nil) then
begin
r:=dst^.New(line,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.AddAncillary(dst:PsrRegSlot):PsrRegNode;
var
src:array[0..2] of PsrRegNode;
begin
src[0]:=NewReg_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:PsrDataLayout;rtype:TsrDataType):PsrRegNode;
var
i:PsrVertLayout;
v:PsrVariable;
dst:PsrRegNode;
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):PsrRegNode;
var
i:PsrFragLayout;
v:PsrVariable;
dst:PsrRegNode;
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:PsrChain;rtype:TsrDataType):PsrRegNode;
begin
Result:=nil;
if (pChain=nil) then Exit;
Result:=NewReg(rtype);
pChain^.FetchLoad(line,Result);
end;
Procedure TEmitFetch.FetchStore(pChain:PsrChain;src:PsrRegNode);
begin
if (pChain=nil) or (src=nil) then Exit;
pChain^.FetchStore(line,src);
end;
procedure TEmitFetch.AddUserdata(dst:PsrRegSlot;offset_dw:Byte);
var
lvl_0:TsrChainLvl_0;
pLayout:PsrDataLayout;
pChain:PsrChain;
pReg:PsrRegNode;
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:PsrDataLayout;lvl_0:PsrChainLvl_0;lvl_1:PsrChainLvl_1):PsrRegNode;
var
pChain:PsrChain;
begin
pChain:=grp^.Fetch(lvl_0,lvl_1);
Result:=FetchLoad(pChain,dtUnknow);
end;
function TEmitFetch.MakeChain(pSlot:PsrRegSlot;grp:PsrDataLayout;lvl_0:PsrChainLvl_0;lvl_1:PsrChainLvl_1):PsrRegNode;
var
pChain:PsrChain;
pReg:PsrRegNode;
begin
pChain:=grp^.Fetch(lvl_0,lvl_1);
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:PsrRegNode;
begin
rsl:=AddInput(@RegsStory.FUnattach,vtype,itype,0);
OpExtract(init_line,dst^.New(line,rtype),rsl,id);
end;
////
function TEmitFetch.FetchUniform(src:PsrDataLayout;pType:PsrType):PsrNode;
var
u:PsrUniform;
v:PsrVariable;
r:PsrRegUniform;
begin
u:=UniformList.Fetch(src,pType);
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:PsrDataLayout;dtype:TsrDataType;info:TsrTypeImageInfo):PsrNode;
var
pType:PsrType;
begin
pType:=TypeList.Fetch(dtype);
pType:=TypeList.FetchImage(pType,info);
Result:=FetchUniform(src,pType);
end;
function TEmitFetch.FetchSampler(src:PsrDataLayout):PsrNode;
var
pType:PsrType;
begin
pType:=TypeList.Fetch(dtTypeSampler);
Result:=FetchUniform(src,pType);
end;
function TEmitFetch.FetchOutput(etype:TpsslExportType;rtype:TsrDataType):PsrVariable;
var
o:PsrOutput;
begin
o:=OutputList.Fetch(etype,rtype);
Result:=o^.pVar;
end;
end.