unit srLayout; {$mode ObjFPC}{$H+} interface uses ps4_shader, srNodes, srParser, srCFG, srTypes, srReg, srVariable, srRefId, srDecorate; type TsrResourceType=( rtBufPtr2, rtFunPtr2, rtVSharp4, rtSSharp4, rtTSharp4, rtTSharp8 ); type PsrDataLayout=^TsrDataLayout; PsrChainExt=^TsrChainExt; TsrChainExt=object pIndex:PsrRegNode; stride:PtrUint; function c(n1,n2:PsrChainExt):Integer; static; end; PsrChain=^TsrChain; TsrChain=object pLeft,pRight:PsrChain; //---- read_count:DWORD; write_count:DWORD; parent:PsrDataLayout; key:packed record ext:TsrChainExt; size,offset:PtrUint; end; rSlot:TsrRegSlot; pField:Pointer; pLine:Pointer; ID:TsrRefId; //post id function c(n1,n2:PsrChain):Integer; static; Procedure mark_read; Procedure mark_unread; Procedure mark_write; Procedure SetRegType(rtype:TsrDataType); function GetRegType:TsrDataType; function IsUsed:Boolean; end; TsrChains=array[0..7] of PsrChain; //---- TsrDataLayout=object type TChainFetch=specialize TNodeFetch; var pLeft,pRight:PsrDataLayout; //---- key:packed record parent:PsrDataLayout; offset:PtrUint; rtype:TsrResourceType; end; pData:Pointer; FID:Integer; Alloc:TfnAlloc; FList:TChainFetch; function c(n1,n2:PsrDataLayout):Integer; static; function Fetch(o,s:PtrUint;ext:PsrChainExt):PsrChain; Function First:PsrChain; Function Last:PsrChain; Function Next(node:PsrChain):PsrChain; Function Prev(node:PsrChain):PsrChain; function GetData:Pointer; function GetStride:PtrUint; function GetTypeChar:Char; function GetString:RawByteString; function GetFuncString(LEN:DWORD):RawByteString; end; TsrDataLayoutList=object type TNodeFetch=specialize TNodeFetch; var FTop:TsrDataLayout; FNTree:TNodeFetch; procedure Init(cb:TfnAlloc); procedure SetUserData(pData:Pointer); function Fetch(p:PsrDataLayout;o:PtrUint;t:TsrResourceType):PsrDataLayout; Function First:PsrDataLayout; Function Next(node:PsrDataLayout):PsrDataLayout; function Grouping(const chain:TsrChains;rtype:TsrResourceType):PsrDataLayout; Procedure AllocID; procedure AllocSourceExtension(FDebugInfo:PsrDebugInfoList); procedure AllocFuncExt(FDebugInfo:PsrDebugInfoList;var Heap:TsrCodeHeap); end; //---- PsrDescriptor=^TsrDescriptor; TsrDescriptor=object pVar:PsrVariable; FStorage:DWORD; FBinding:Integer; end; function is_consistents(const chains:TsrChains;count:Byte):Boolean; function is_no_index_chains(const chains:TsrChains;count:Byte):Boolean; function is_userdata_chains(const chains:TsrChains;count:Byte):Boolean; function GetResourceSizeDw(r:TsrResourceType):Byte; implementation function TsrDataLayout.c(n1,n2:PsrDataLayout):Integer; begin //first parent Result:=Integer(n1^.key.parent>n2^.key.parent)-Integer(n1^.key.parent0) then Exit; //second offset Result:=Integer(n1^.key.offset>n2^.key.offset)-Integer(n1^.key.offset0) then Exit; //third rtype Result:=Integer(n1^.key.rtype>n2^.key.rtype)-Integer(n1^.key.rtypenil) then begin node.key.ext:=ext^; end; Result:=FList.Find(@node); if (Result=nil) then begin Result:=Alloc(SizeOf(TsrChain)); Result^.parent:=@Self; Result^.key.offset:=o; Result^.key.size :=s; if (ext<>nil) then begin Result^.key.ext:=ext^; end; Result^.rSlot.Init(Alloc,'CHAIN'); FList.Insert(Result); end else begin if (ext<>nil) then if (ext^.pIndex<>nil) then begin ext^.pIndex^.mark_unread; end; end; end; Function TsrDataLayout.First:PsrChain; begin Result:=FList.Min; end; Function TsrDataLayout.Last:PsrChain; begin Result:=FList.Max; end; Function TsrDataLayout.Next(node:PsrChain):PsrChain; begin Result:=FList.Next(node); end; Function TsrDataLayout.Prev(node:PsrChain):PsrChain; begin Result:=FList.Prev(node); end; function TsrDataLayout.GetData:Pointer; begin Result:=nil; if (pData<>nil) then Case key.rtype of rtBufPtr2, rtFunPtr2:Result:=pData; rtVSharp4:Result:={%H-}Pointer(PVSharpResource4(pData)^.base); rtTSharp4, rtTSharp8:Result:={%H-}Pointer(PTSharpResource4(pData)^.base shl 8); else; end; end; function TsrDataLayout.GetStride:PtrUint; begin Result:=0; if (pData<>nil) then Case key.rtype of rtBufPtr2:Result:=4; rtVSharp4:Result:=PVSharpResource4(pData)^.stride; else; end; end; function TsrDataLayout.GetTypeChar:Char; begin Result:=#0; case key.rtype of rtBufPtr2:Result:='B'; rtFunPtr2:Result:='F'; rtVSharp4:Result:='V'; rtSSharp4:Result:='S'; rtTSharp4:Result:='t'; rtTSharp8:Result:='T'; end; end; function TsrDataLayout.GetString:RawByteString; var PID:DWORD; begin PID:=0; if (key.parent<>nil) then begin PID:=key.parent^.FID; end; Result:='#'+GetTypeChar+ ';PID='+HexStr(PID,8)+ ';OFS='+HexStr(key.offset,8); end; function TsrDataLayout.GetFuncString(LEN:DWORD):RawByteString; begin Result:='FF'+ ';PID='+HexStr(FID,8)+ ';LEN='+HexStr(LEN,8); end; procedure TsrDataLayoutList.Init(cb:TfnAlloc); begin FTop.Alloc:=cb; FNTree.Insert(@FTop); end; procedure TsrDataLayoutList.SetUserData(pData:Pointer); begin FTop.pData:=pData; end; function TsrDataLayoutList.Fetch(p:PsrDataLayout;o:PtrUint;t:TsrResourceType):PsrDataLayout; var node:TsrDataLayout; pData:Pointer; begin node:=Default(TsrDataLayout); node.Alloc:=FTop.Alloc; node.key.parent:=p; node.key.offset:=o; node.key.rtype :=t; Result:=FNTree.Find(@node); if (Result=nil) then begin Result:=FTop.Alloc(SizeOf(TsrDataLayout)); Move(node,Result^,SizeOf(TsrDataLayout)); FNTree.Insert(Result); Result^.FID:=-1; if (p<>nil) then begin pData:=p^.GetData; if (pData<>nil) then case t of rtBufPtr2, rtFunPtr2:Result^.pData:={%H-}Pointer(PPtrUint(pData+o)^ and (not 3)); rtVSharp4, rtSSharp4, rtTSharp4, rtTSharp8:Result^.pData:=pData+o; end; end; end; end; Function TsrDataLayoutList.First:PsrDataLayout; begin Result:=FNTree.Min; end; Function TsrDataLayoutList.Next(node:PsrDataLayout):PsrDataLayout; begin Result:=FNTree.Next(node); end; function GetResourceSizeDw(r:TsrResourceType):Byte; begin Result:=0; Case r of rtBufPtr2:Result:=2; rtFunPtr2:Result:=2; rtVSharp4:Result:=4; rtSSharp4:Result:=4; rtTSharp4:Result:=4; rtTSharp8:Result:=8; end; end; function TsrDataLayoutList.Grouping(const chain:TsrChains;rtype:TsrResourceType):PsrDataLayout; begin Result:=nil; if not is_consistents(chain,GetResourceSizeDw(rtype)) then begin Assert(False,'inconsistent resources not supported'); end; if not is_no_index_chains(chain,GetResourceSizeDw(rtype)) then begin Assert(False,'indexed chain not support'); end; Result:=Fetch(chain[0]^.parent,chain[0]^.key.offset,rtype); end; Procedure TsrDataLayoutList.AllocID; var node:PsrDataLayout; FID:Integer; begin FID:=1; node:=First; While (node<>nil) do begin if (node^.FID=-1) then begin node^.FID:=FID; Inc(FID); end; node:=Next(node); end; end; procedure TsrDataLayoutList.AllocSourceExtension(FDebugInfo:PsrDebugInfoList); var node:PsrDataLayout; begin if (FDebugInfo=nil) then Exit; node:=First; While (node<>nil) do begin FDebugInfo^.emit_source_extension(node^.GetString); node:=Next(node); end; end; procedure TsrDataLayoutList.AllocFuncExt(FDebugInfo:PsrDebugInfoList;var Heap:TsrCodeHeap); var node:PsrDataLayout; block:PsrCodeBlock; begin node:=First; While (node<>nil) do begin if (node^.key.rtype=rtFunPtr2) then begin block:=Heap.FindByPtr(node^.pData); if (block<>nil) then begin FDebugInfo^.emit_source_extension(node^.GetFuncString(block^.Size)); end; end; node:=Next(node); end; end; function TsrChainExt.c(n1,n2:PsrChainExt):Integer; begin //first pIndex forward Result:=Integer(n1^.pIndex>n2^.pIndex)-Integer(n1^.pIndex0) then Exit; //second stride forward Result:=Integer(n1^.stride>n2^.stride)-Integer(n1^.stride0) then Exit; //second size backward Result:=Integer(n1^.key.sizen2^.key.size); if (Result<>0) then Exit; //third offset forward Result:=Integer(n1^.key.offset>n2^.key.offset)-Integer(n1^.key.offset0) then Dec(read_count); end; Procedure TsrChain.mark_write; begin Inc(write_count); end; Procedure TsrChain.SetRegType(rtype:TsrDataType); var node:PsrRegNode; begin node:=rSlot.pStory.pHead; While (node<>nil) do begin node^.dtype:=rtype; node:=node^.pNext; end; end; function TsrChain.GetRegType:TsrDataType; var pReg:PsrRegNode; begin Result:=dtUnknow; pReg:=rSlot.current; if (pReg=nil) then Exit; Result:=pReg^.dtype; end; function TsrChain.IsUsed:Boolean; begin Result:=((read_count<>0) or (write_count<>0)) and (rSlot.current<>nil); end; function is_consistents(const chains:TsrChains;count:Byte):Boolean; var parent:PsrDataLayout; offset,t:PtrUint; i:Byte; begin offset:=0; t:=0; if (count<2) then Exit(True); Result:=False; if (chains[0]=nil) then Exit; parent:=chains[0]^.parent; offset:=chains[0]^.key.offset; For i:=1 to count-1 do begin t:=chains[i-1]^.key.size; offset:=offset+t; if (chains[i]=nil) then Exit; if (chains[i]^.parent<>parent) then Exit; t:=chains[i]^.key.offset; if (offset<>t) then Exit; end; Result:=True; end; function is_no_index_chains(const chains:TsrChains;count:Byte):Boolean; var i:Byte; begin Result:=False; if (count=0) then Exit; For i:=0 to count-1 do begin if (chains[i]=nil) then Exit; if (chains[i]^.key.ext.pIndex<>nil) then Exit; end; Result:=True; end; function is_userdata_chains(const chains:TsrChains;count:Byte):Boolean; var parent:PsrDataLayout; i:Byte; begin Result:=False; if (count=0) then Exit; For i:=0 to count-1 do begin if (chains[i]=nil) then Exit; parent:=chains[i]^.parent; if (parent=nil) then Exit; if (parent^.key.parent<>nil) then Exit; end; Result:=True; end; end.