fpPS4/spirv/emit_exp.pas
2022-06-29 11:57:53 +03:00

198 lines
3.7 KiB
ObjectPascal

unit emit_EXP;
{$mode objfpc}{$H+}
interface
uses
sysutils,
spirv,
ps4_pssl,
srNodes,
srLabel,
srTypes,
srReg,
srVariable,
srOutput,
srOp,
srOpUtils,
SprvEmit,
emit_op;
type
TEmit_EXP=object(TEmitOp)
procedure _emit_EXP;
end;
implementation
procedure TEmit_EXP._emit_EXP;
Var
exc:PsrRegNode;
node:PSpirvOp;
pOpBlock:PsrOpBlock;
dout:PsrVariable;
dst:PsrRegNode;
src:array[0..3] of PsrRegNode;
rsl:array[0..3] of PsrRegNode;
rtype:TsrDataType;
f,i,p:Byte;
begin
//if (VM<>0) and (EXEC<>0) = set pixel else (if DONE=1) discard pixel /(PS only)
pOpBlock:=nil;
if (FSPI.EXP.VM<>0) and (FSPI.EXP.DONE<>0) then
begin
pOpBlock:=AllocBlockOp;
pOpBlock^.SetInfo(btOther,FCursor.Adr,FCursor.Adr);
PushBlockOp(line,pOpBlock,nil);
exc:=MakeRead(@FRegsStory.EXEC[0],dtBool);
node:=AddSpirvOp(OpMakeExp);
node^.AddParam(ntReg,exc); //<-fetch read
end;
//before
if (TpsslExportType(FSPI.EXP.TGT)=etNull) //only set kill mask
or (FSPI.EXP.EN=0) then //nop
begin
if (pOpBlock<>nil) then //is pushed
begin
FMain^.PopBlock;
end;
Exit;
end;
pOpBlock:=AllocBlockOp; //down
pOpBlock^.SetInfo(btOther,FCursor.Adr,FCursor.Adr);
PushBlockOp(line,pOpBlock,nil);
//output
src[0]:=nil;
src[1]:=nil;
src[2]:=nil;
src[3]:=nil;
f:=FSPI.EXP.EN;
if (FSPI.EXP.COMPR=0) then //float32
begin
p:=PopCnt(f);
if (p=1) then
begin
Case f of
$1:src[0]:=fetch_vsrc8(FSPI.EXP.VSRC0,dtFloat32);
$2:src[0]:=fetch_vsrc8(FSPI.EXP.VSRC1,dtFloat32);
$4:src[0]:=fetch_vsrc8(FSPI.EXP.VSRC2,dtFloat32);
$8:src[0]:=fetch_vsrc8(FSPI.EXP.VSRC3,dtFloat32);
else
Assert(false);
end;
dout:=FetchOutput(TpsslExportType(FSPI.EXP.TGT),dtFloat32); //output in FSPI.EXP.TGT
emit_OpStore(line,dout,src[0]);
end else
begin
Case p of
2:rtype:=dtVec2f;
3:rtype:=dtVec3f;
4:rtype:=dtVec4f;
else
Assert(false,IntToStr(p));
end;
i:=0;
if (f and $1<>0) then
begin
src[i]:=fetch_vsrc8(FSPI.EXP.VSRC0,dtFloat32);
Inc(i);
end;
if (f and $2<>0) then
begin
src[i]:=fetch_vsrc8(FSPI.EXP.VSRC1,dtFloat32);
Inc(i);
end;
if (f and $4<>0) then
begin
src[i]:=fetch_vsrc8(FSPI.EXP.VSRC2,dtFloat32);
Inc(i);
end;
if (f and $8<>0) then
begin
src[i]:=fetch_vsrc8(FSPI.EXP.VSRC3,dtFloat32);
Inc(i);
end;
dst:=emit_OpMakeVec(line,rtype,p,@src);
dst^.mark_read;
dout:=FetchOutput(TpsslExportType(FSPI.EXP.TGT),rtype); //output in FSPI.EXP.TGT
emit_OpStore(line,dout,dst);
end;
end else
begin //half16
Case f of
3,
$F:
begin
fetch_vsrc8_vec2h(FSPI.EXP.VSRC0,src[0],src[1]);
fetch_vsrc8_vec2h(FSPI.EXP.VSRC1,src[2],src[3]);
end;
$C:
begin
fetch_vsrc8_vec2h(FSPI.EXP.VSRC2,src[0],src[1]);
fetch_vsrc8_vec2h(FSPI.EXP.VSRC3,src[2],src[3]);
end;
else
Assert(false);
end;
if FUseOutput16 then
begin
dst:=emit_OpMakeVec(line,dtVec4h,4,@src);
dst^.mark_read;
rtype:=dtVec4h;
end else
begin
rsl[0]:=NewReg(dtFloat32);
rsl[1]:=NewReg(dtFloat32);
rsl[2]:=NewReg(dtFloat32);
rsl[3]:=NewReg(dtFloat32);
_emit_Op1(line,Op.OpFConvert,rsl[0],src[0]);
_emit_Op1(line,Op.OpFConvert,rsl[1],src[1]);
_emit_Op1(line,Op.OpFConvert,rsl[2],src[2]);
_emit_Op1(line,Op.OpFConvert,rsl[3],src[3]);
rsl[0]^.mark_read;
rsl[1]^.mark_read;
rsl[2]^.mark_read;
rsl[3]^.mark_read;
dst:=emit_OpMakeVec(line,dtVec4f,4,@rsl);
dst^.mark_read;
rtype:=dtVec4f;
end;
dout:=FetchOutput(TpsslExportType(FSPI.EXP.TGT),rtype); //output in FSPI.EXP.TGT
emit_OpStore(line,dout,dst);
end;
if (pOpBlock<>nil) then //is pushed
begin
FMain^.PopBlock;
FMain^.PopBlock;
end;
end;
end.