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.