mirror of https://github.com/red-prig/fpPS4.git
273 lines
6.2 KiB
Plaintext
273 lines
6.2 KiB
Plaintext
unit vRectGS;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes,
|
|
|
|
Vulkan,
|
|
|
|
vRegs2Vulkan,
|
|
|
|
spirv,
|
|
srNode,
|
|
srType,
|
|
srTypes,
|
|
srReg,
|
|
srVariable,
|
|
srOutput,
|
|
|
|
SprvEmit;
|
|
|
|
function CompileRectangleGeometryShader(var GPU_REGS:TGPU_REGS):TMemoryStream;
|
|
|
|
implementation
|
|
|
|
function interpolate(SprvEmit:TSprvEmit;
|
|
rtype :TsrDataType;
|
|
barycentric,inputs:PPsrRegNode):TsrRegNode;
|
|
var
|
|
tmp:array[0..2] of TsrRegNode;
|
|
//
|
|
i:Byte;
|
|
begin
|
|
For i:=0 to 2 do
|
|
begin
|
|
tmp[i]:=SprvEmit.NewReg(rtype);
|
|
//
|
|
SprvEmit._Op2(SprvEmit.line,Op.OpVectorTimesScalar,tmp[i],inputs[i],barycentric[i]);
|
|
end;
|
|
//
|
|
Result:=SprvEmit.OpFAddTo(tmp[0],tmp[1]);
|
|
Result:=SprvEmit.OpFAddTo(Result,tmp[2]);
|
|
end;
|
|
|
|
type
|
|
TINPUT_INFO=packed record
|
|
LAYOUT_ID :Byte;
|
|
FLAT_SHADE :Boolean;
|
|
end;
|
|
|
|
//source: [amdilc_rect_gs_compiler.c]
|
|
function CompileRectangleGeometryShader(var GPU_REGS:TGPU_REGS):TMemoryStream;
|
|
var
|
|
INPUT_INFO :array[0..31] of TINPUT_INFO;
|
|
INPUT_COUNT:Byte;
|
|
//
|
|
SprvEmit:TSprvEmit;
|
|
//
|
|
pVec4f :TsrType;
|
|
InputPos :TsrVariable;
|
|
OutputPos :TsrVariable;
|
|
InputParams :array[0..31] of TsrVariable;
|
|
OutputParams:array[0..31] of TsrVariable;
|
|
//
|
|
pChain :TsrNode;
|
|
UintId :array[0..3] of TsrRegNode;
|
|
Positions :array[0..3] of TsrRegNode;
|
|
positionsX :array[0..2] of TsrRegNode;
|
|
positionsY :array[0..2] of TsrRegNode;
|
|
CoordEqualX :array[0..2] of TsrRegNode;
|
|
CoordEqualY :array[0..2] of TsrRegNode;
|
|
EdgeVertex :array[0..2] of TsrRegNode;
|
|
barycentric :array[0..2] of TsrRegNode;
|
|
Parameters :array[0..2] of TsrRegNode;
|
|
xyEqual :TsrRegNode;
|
|
yxEqual :TsrRegNode;
|
|
pOneId :TsrRegNode;
|
|
pMinusOne :TsrRegNode;
|
|
pIndex :TsrRegNode;
|
|
pLoaded :TsrRegNode;
|
|
//
|
|
i,a:Byte;
|
|
begin
|
|
Result:=nil;
|
|
|
|
INPUT_COUNT:=GPU_REGS.CX_REG^.SPI_PS_IN_CONTROL.NUM_INTERP;
|
|
if (INPUT_COUNT<>0) then
|
|
begin
|
|
a:=0;
|
|
for i:=0 to INPUT_COUNT-1 do
|
|
//if not default
|
|
if ((GPU_REGS.CX_REG^.SPI_PS_INPUT_CNTL[i].OFFSET shr 5)=0) then
|
|
begin
|
|
INPUT_INFO[a].LAYOUT_ID :=(GPU_REGS.CX_REG^.SPI_PS_INPUT_CNTL[i].OFFSET and 31);
|
|
INPUT_INFO[a].FLAT_SHADE:=(GPU_REGS.CX_REG^.SPI_PS_INPUT_CNTL[i].FLAT_SHADE)<>0;
|
|
//
|
|
Inc(a);
|
|
end;
|
|
//update count
|
|
INPUT_COUNT:=a;
|
|
end;
|
|
|
|
SprvEmit:=TSprvEmit.Create;
|
|
|
|
SprvEmit.InitCustomGs();
|
|
|
|
pVec4f :=SprvEmit.TypeList.Fetch(dtVec4f);
|
|
|
|
//postion i/o
|
|
InputPos :=SprvEmit.AddPositionsInput(3);
|
|
OutputPos:=SprvEmit.FetchOutput(etPos0,dtVec4f).pVar;
|
|
|
|
//input param i/o
|
|
if (INPUT_COUNT<>0) then
|
|
begin
|
|
for a:=0 to INPUT_COUNT-1 do
|
|
begin
|
|
InputParams [a]:=SprvEmit.AddParametersInput(INPUT_INFO[a].LAYOUT_ID,3);
|
|
OutputParams[a]:=SprvEmit.FetchOutput(TpsslExportType(ord(etParam0)+INPUT_INFO[a].LAYOUT_ID),dtVec4f).pVar;
|
|
end;
|
|
end;
|
|
|
|
//gen const id
|
|
For i:=0 to 3 do
|
|
begin
|
|
UintId[i]:=SprvEmit.NewImm_i(dtUint32,i);
|
|
end;
|
|
|
|
//load positions
|
|
For i:=0 to 2 do
|
|
begin
|
|
pChain:=SprvEmit.OpAccessChainTo(pVec4f,InputPos,UintId[i]);
|
|
//
|
|
Positions[i]:=SprvEmit.OpLoadTo(pVec4f,pChain);
|
|
end;
|
|
|
|
//extract
|
|
For i:=0 to 2 do
|
|
begin
|
|
positionsX[i]:=SprvEmit.NewReg(dtFloat32);
|
|
positionsY[i]:=SprvEmit.NewReg(dtFloat32);
|
|
//
|
|
SprvEmit.OpExtract(SprvEmit.line,positionsX[i],Positions[i],0);
|
|
SprvEmit.OpExtract(SprvEmit.line,positionsY[i],Positions[i],1);
|
|
end;
|
|
|
|
//compare
|
|
For i:=0 to 2 do
|
|
begin
|
|
CoordEqualX[i]:=SprvEmit.NewReg(dtBool);
|
|
CoordEqualY[i]:=SprvEmit.NewReg(dtBool);
|
|
//
|
|
SprvEmit._Op2(SprvEmit.line,Op.OpFOrdEqual,CoordEqualX[i],positionsX[i],positionsX[(i + 1) mod 3]);
|
|
SprvEmit._Op2(SprvEmit.line,Op.OpFOrdEqual,CoordEqualY[i],positionsY[i],positionsY[(i + 1) mod 3]);
|
|
end;
|
|
|
|
pOneId :=SprvEmit.NewImm_s(dtFloat32, 1);
|
|
pMinusOne:=SprvEmit.NewImm_s(dtFloat32,-1);
|
|
|
|
//calc barycentric
|
|
For i:=0 to 2 do
|
|
begin
|
|
xyEqual:=SprvEmit.OpAndTo(CoordEqualX[i], CoordEqualY[(i + 2) mod 3]);
|
|
yxEqual:=SprvEmit.OpAndTo(CoordEqualY[i], CoordEqualX[(i + 2) mod 3]);
|
|
//
|
|
EdgeVertex[i]:=SprvEmit.OpOrTo(xyEqual,yxEqual);
|
|
//cond,src_true,src_false
|
|
barycentric[i]:=SprvEmit.OpSelectTo(EdgeVertex[i],pMinusOne,pOneId);
|
|
end;
|
|
|
|
//calc last pos
|
|
Positions[3]:=interpolate(SprvEmit,dtVec4f,@barycentric,@Positions);
|
|
|
|
//select first index
|
|
//cond,src_true,src_false
|
|
pIndex:=SprvEmit.OpSelectTo(EdgeVertex[1], UintId[1], UintId[0]);
|
|
pIndex:=SprvEmit.OpSelectTo(EdgeVertex[2], UintId[2], pIndex );
|
|
|
|
//Send vertex by index
|
|
For i:=0 to 2 do
|
|
begin
|
|
pChain :=SprvEmit.OpAccessChainTo(pVec4f,InputPos,pIndex);
|
|
pLoaded:=SprvEmit.OpLoadTo(pVec4f,pChain);
|
|
SprvEmit.OpStore(SprvEmit.line,OutputPos,pLoaded);
|
|
|
|
//emit input attr
|
|
if (INPUT_COUNT<>0) then
|
|
begin
|
|
for a:=0 to INPUT_COUNT-1 do
|
|
begin
|
|
if INPUT_INFO[a].FLAT_SHADE then
|
|
begin
|
|
//get first
|
|
pChain:=SprvEmit.OpAccessChainTo(pVec4f,InputParams[a],UintId[0]);
|
|
end else
|
|
begin
|
|
pChain:=SprvEmit.OpAccessChainTo(pVec4f,InputParams[a],pIndex);
|
|
end;
|
|
|
|
pLoaded:=SprvEmit.OpLoadTo(pVec4f,pChain);
|
|
SprvEmit.OpStore(SprvEmit.line,OutputParams[a],pLoaded);
|
|
end;
|
|
end;
|
|
|
|
//end vertex
|
|
SprvEmit.OpEmitVertex(SprvEmit.line);
|
|
|
|
if (i<>2) then
|
|
begin
|
|
//next index
|
|
pIndex:=SprvEmit.OpIAddTo(pIndex,UintId[1]);
|
|
pIndex:=SprvEmit.OpIModTo(pIndex,UintId[3]);
|
|
end;
|
|
end; //for
|
|
|
|
//send last vertex
|
|
SprvEmit.OpStore(SprvEmit.line,OutputPos,Positions[3]);
|
|
|
|
//emit input attr
|
|
if (INPUT_COUNT<>0) then
|
|
begin
|
|
for a:=0 to INPUT_COUNT-1 do
|
|
begin
|
|
if INPUT_INFO[a].FLAT_SHADE then
|
|
begin
|
|
//get first
|
|
pChain :=SprvEmit.OpAccessChainTo(pVec4f,InputParams[a],UintId[0]);
|
|
pLoaded:=SprvEmit.OpLoadTo(pVec4f,pChain);
|
|
end else
|
|
begin
|
|
//load parameters
|
|
For i:=0 to 2 do
|
|
begin
|
|
pChain:=SprvEmit.OpAccessChainTo(pVec4f,InputParams[a],UintId[i]);
|
|
//
|
|
Parameters[i]:=SprvEmit.OpLoadTo(pVec4f,pChain);
|
|
end;
|
|
|
|
//calc last parameter
|
|
pLoaded:=interpolate(SprvEmit,dtVec4f,@barycentric,@Parameters);
|
|
end;
|
|
|
|
SprvEmit.OpStore(SprvEmit.line,OutputParams[a],pLoaded);
|
|
end;
|
|
end;
|
|
|
|
//end vertex
|
|
SprvEmit.OpEmitVertex(SprvEmit.line);
|
|
|
|
//end prim
|
|
SprvEmit.OpEndPrimitive(SprvEmit.line);
|
|
|
|
//end function
|
|
SprvEmit.OpReturn(SprvEmit.line);
|
|
SprvEmit.OpFunctionEnd(SprvEmit.line);
|
|
|
|
//ending stage
|
|
SprvEmit.PostStage;
|
|
SprvEmit.AllocStage;
|
|
|
|
//SprvEmit.Print;
|
|
|
|
Result:=TMemoryStream.Create;
|
|
SprvEmit.SaveToStream(Result);
|
|
|
|
SprvEmit.Free;
|
|
end;
|
|
|
|
end.
|
|
|