unit emit_vbuf_chain; {$mode ObjFPC}{$H+} interface uses sysutils, ps4_shader, ps4_pssl, srType, srConst, srReg, srLayout, srConfig, emit_fetch, srVBufInfo; type TBuf_adr=packed record stride :PtrInt; aligned_size:PtrInt; format_size :PtrInt; csize :PtrInt; soffset,ioffset,voffset:PtrInt; ofs,idx:TsrRegNode; end; TvcType=(vcInvalid,vcChainVector,vcChainElement,vcUniformVector,vcUniformElement); TvarChain=record vType:TvcType; data:array[0..1] of Pointer; end; TEmit_vbuf_chain=class(TEmitFetch) procedure get_reg_adr(var adr:TBuf_adr); function get_sum_ofs(var adr:TBuf_adr):TsrRegNode; function get_idx_elm(var adr:TBuf_adr):TsrRegNode; function get_idx_fmt(var adr:TBuf_adr):TsrRegNode; function get_chain (info:TBuf_info):TvarChain; end; implementation procedure TEmit_vbuf_chain.get_reg_adr(var adr:TBuf_adr); var pSlot:PsrRegSlot; sof:TsrRegNode; ofs:TsrRegNode; begin sof:=nil; ofs:=nil; if is_const_soffset(FSPI.MUBUF.SOFFSET) then begin adr.soffset:=get_soffset_const_int(FSPI.MUBUF.SOFFSET,FSPI.INLINE32); end else begin pSlot:=get_ssrc8(FSPI.MUBUF.SOFFSET); if (pSlot<>nil) then begin sof:=pSlot^.current; if (sof<>nil) then begin if (sof.is_const) then begin adr.soffset:=sof.AsConst.AsInt32; sof:=nil; end else begin sof:=MakeRead(pSlot,dtInt32); end; end; end; end; pSlot:=nil; if (FSPI.MUBUF.IDXEN=1) then begin if (adr.stride<>0) then //ignore index when stride=0 begin adr.idx:=fetch_vsrc8(FSPI.MUBUF.VADDR+0,dtInt32); end; if (FSPI.MUBUF.OFFEN=1) then begin pSlot:=get_vsrc8(FSPI.MUBUF.VADDR+1); end; end else if (FSPI.MUBUF.OFFEN=1) then begin pSlot:=get_vsrc8(FSPI.MUBUF.VADDR+0); end; if (pSlot<>nil) then begin ofs:=pSlot^.current; if (ofs<>nil) then begin if (ofs.is_const) then begin adr.voffset:=ofs.AsConst.AsInt32; ofs:=nil; end else begin ofs:=MakeRead(pSlot,dtInt32); end; end; end; if (sof<>nil) and (ofs<>nil) then begin adr.ofs:=OpIAddTo(sof,ofs); end else if (sof<>nil) then begin adr.ofs:=sof; end else begin adr.ofs:=ofs; end; end; function TEmit_vbuf_chain.get_sum_ofs(var adr:TBuf_adr):TsrRegNode; var foffset:PtrInt; sum_d,ofs_d,idx_m:TsrRegNode; begin foffset:=adr.soffset+adr.ioffset+adr.voffset; if (foffset mod adr.aligned_size=0) and //const offset is align ((adr.idx=nil) or //no index or (adr.stride mod adr.aligned_size=0)) then //stride is align begin //(foffset is Align) //(stride is Align) //result=(foffset/Align+ofs/Align+idx*(stride/Align)) in elem ofs_d:=OpIDivTo(adr.ofs,adr.aligned_size); //ofs/Align sum_d:=OpIAddTo(ofs_d,foffset div adr.aligned_size); //foffset/Align+ofs/Align if (adr.idx<>nil) then begin idx_m:=OpIMulTo(adr.idx,adr.stride div adr.aligned_size); //idx*(stride/Align) sum_d:=OpIAddTo(sum_d,idx_m); end; end else begin //result=(foffset+ofs+idx*stride)/Align in elem sum_d:=OpIAddTo(adr.ofs,foffset); //foffset+ofs if (adr.idx<>nil) then begin idx_m:=OpIMulTo(adr.idx,adr.stride); //idx*stride sum_d:=OpIAddTo(sum_d,idx_m); end; sum_d:=OpIDivTo(sum_d,adr.aligned_size); // sum/Align end; Result:=sum_d; end; function TEmit_vbuf_chain.get_idx_elm(var adr:TBuf_adr):TsrRegNode; var foffset:PtrInt; sum_d,idx_m:TsrRegNode; begin //result=(foffset/Align+idx*(stride/Align)) in elem foffset:=adr.soffset+adr.ioffset+adr.voffset; foffset:=foffset div adr.aligned_size; if (adr.idx=nil) then begin sum_d:=NewImm_q(dtUint32,foffset); end else begin idx_m:=OpIMulTo(adr.idx,adr.stride div adr.aligned_size); //idx*(stride/Align) sum_d:=OpIAddTo(idx_m,foffset); end; Result:=sum_d; end; function TEmit_vbuf_chain.get_idx_fmt(var adr:TBuf_adr):TsrRegNode; var foffset:PtrInt; sum_d,idx_m:TsrRegNode; begin //result=(foffset/size+idx*(stride/size)) in format foffset:=adr.soffset+adr.ioffset+adr.voffset; foffset:=foffset div adr.format_size; if (adr.idx=nil) then begin sum_d:=NewImm_q(dtUint32,foffset); end else begin idx_m:=OpIMulTo(adr.idx,adr.stride div adr.format_size); //idx*(stride/size) sum_d:=OpIAddTo(idx_m,foffset); end; Result:=sum_d; end; function Min(a,b:PtrInt):PtrInt; inline; begin if (a=0,'WTF'); if (adr.ofs=nil) and (adr.idx=nil) then //simple begin lvl_0.offset:=foffset; lvl_0.size :=adr.csize; Result.data[0]:=info.grp.Fetch(@lvl_0,nil,cflags(dtUnknow,info.GLC,info.SLC)); Result.vType :=vcChainVector; Exit; end; //result=Align(foffset+ofs+idx*stride) in byte if (adr.ofs<>nil) then begin sum_d:=get_sum_ofs(adr); //minTexelBufferOffsetAlignment if Config.UseTexelBuffer then if (info.IsComp) and (adr.stride div adr.aligned_size=0) then begin //is uniform buffer per element img:=info.GetImageInfoElement; Result.vType :=vcUniformElement; Result.data[0]:=FetchImage(info.grp,img); Result.data[1]:=sum_d; Exit; end; lvl_0.offset:=0; lvl_0.size :=adr.aligned_size; lvl_1.pIndex:=sum_d; lvl_1.stride:=adr.aligned_size; Result.data[0]:=info.grp.Fetch(@lvl_0,@lvl_1,cflags(dtUnknow,info.GLC,info.SLC)); Result.vType :=vcChainElement; Exit; end else begin //idx<>nil //minTexelBufferOffsetAlignment if Config.UseTexelBuffer then if (info.IsComp) and (adr.stride mod adr.format_size=0) and (foffset mod adr.format_size=0) then begin //is uniform buffer per format sum_d:=get_idx_fmt(adr); img:=info.GetImageInfo; Result.vType :=vcUniformVector; Result.data[0]:=FetchImage(info.grp,img); Result.data[1]:=sum_d; Exit; end; //minTexelBufferOffsetAlignment if Config.UseTexelBuffer then if (info.IsComp) and (adr.stride div adr.aligned_size=0) then begin //is uniform buffer per element sum_d:=get_idx_elm(adr); img:=info.GetImageInfoElement; Result.vType :=vcUniformElement; Result.data[0]:=FetchImage(info.grp,img); Result.data[1]:=sum_d; Exit; end; lvl_0.offset:=foffset; lvl_0.size :=adr.csize; lvl_1.pIndex:=adr.idx; lvl_1.stride:=adr.stride; Result.data[0]:=info.grp.Fetch(@lvl_0,@lvl_1,cflags(dtUnknow,info.GLC,info.SLC)); Result.vType :=vcChainVector; Exit; end; end; end.