mirror of
https://github.com/red-prig/fpPS4.git
synced 2024-11-27 00:20:36 +00:00
1106 lines
21 KiB
ObjectPascal
1106 lines
21 KiB
ObjectPascal
unit srBuffer;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
sysutils,
|
|
spirv,
|
|
ginodes,
|
|
srNode,
|
|
srType,
|
|
srTypes,
|
|
srReg,
|
|
srVariable,
|
|
srLayout,
|
|
srDecorate,
|
|
srConfig;
|
|
|
|
type
|
|
ntBuffer=class(ntDescriptor)
|
|
class Procedure add_read (node,src:PsrNode); override;
|
|
class Procedure rem_read (node,src:PsrNode); override;
|
|
//
|
|
class Function pwrite_count (node:PsrNode):PDWORD; override;
|
|
class function GetStorageName(node:PsrNode):RawByteString; override;
|
|
end;
|
|
|
|
PsrBuffer=^TsrBuffer;
|
|
|
|
PsrField=^TsrField;
|
|
|
|
TsrFieldValue=(frNotFit,frIdent,frVectorAsValue,frValueInVector,frValueInArray);
|
|
|
|
TFieldFetchValue=record
|
|
fValue:TsrFieldValue;
|
|
pField:PsrField;
|
|
end;
|
|
|
|
TFieldEnumCb=procedure(pField:PsrField) of object;
|
|
TsrField=object
|
|
type
|
|
TFieldFetch=specialize TNodeFetch<PsrField,TsrField>;
|
|
var
|
|
pLeft,pRight:PsrField;
|
|
//----
|
|
|
|
pBuffer:PsrBuffer;
|
|
pParent:PsrField;
|
|
offset:PtrUint;
|
|
size:PtrUint;
|
|
stride:PtrUint;
|
|
|
|
FCount:PtrUint;
|
|
dtype:TsrDataType;
|
|
|
|
sType,pType:PsrType;
|
|
|
|
FID:Integer; //alloc late
|
|
|
|
//
|
|
|
|
FList:TFieldFetch;
|
|
|
|
function c(n1,n2:PsrField):Integer; static;
|
|
function Cross(o,s:PtrUint):Boolean;
|
|
function Find_be(o:PtrUint):PsrField;
|
|
function Find_le(o:PtrUint):PsrField;
|
|
function First:PsrField;
|
|
function Last:PsrField;
|
|
function Next(p:PsrField):PsrField;
|
|
function Prev(p:PsrField):PsrField;
|
|
function Fetch(o:PtrUint):PsrField;
|
|
function FetchValue(_offset,_size:PtrUint;_dtype:TsrDataType):TFieldFetchValue;
|
|
function FetchRuntimeArray(_offset,_stride:PtrUint):TFieldFetchValue;
|
|
function IsStructUsedRuntimeArray:Boolean;
|
|
function IsStructNotUsed:Boolean;
|
|
function IsTop:Boolean;
|
|
function GetStructDecorate:DWORD;
|
|
procedure UpdateSize;
|
|
function GetSize:PtrUint;
|
|
procedure FillNode(o,s:PtrUint);
|
|
function FillSpace:Integer;
|
|
end;
|
|
|
|
TsrBufferType=(btStorageBuffer,btUniformBuffer,btPushConstant);
|
|
|
|
TsrBuffer=packed object(TsrDescriptor)
|
|
pLeft,pRight:PsrBuffer;
|
|
//----
|
|
fwrite_count:DWORD;
|
|
//
|
|
align_offset:DWORD;
|
|
|
|
FEmit:TCustomEmit;
|
|
FDList:TRegDNodeList;
|
|
|
|
bType:TsrBufferType;
|
|
|
|
key:packed record
|
|
pLayout:PsrDataLayout;
|
|
AliasId:PtrInt;
|
|
end;
|
|
|
|
FTop:TsrField;
|
|
|
|
function c(n1,n2:PsrBuffer):Integer; static;
|
|
Procedure Init(Emit:TCustomEmit); inline;
|
|
Procedure AddDep(t:PsrNode);
|
|
Procedure RemDep(t:PsrNode);
|
|
function chain_read :DWORD;
|
|
function chain_write:DWORD;
|
|
function GetStorageName:RawByteString;
|
|
function GetTypeChar:Char;
|
|
function GetString:RawByteString;
|
|
function GetStructName:RawByteString;
|
|
function GetSize:PtrUint;
|
|
procedure EnumAllField(cb:TFieldEnumCb);
|
|
procedure ShiftOffset(Offset:PtrUint);
|
|
end;
|
|
|
|
PsrBufferList=^TsrBufferList;
|
|
TsrBufferList=object
|
|
type
|
|
TNodeFetch=specialize TNodeFetch<PsrBuffer,TsrBuffer>;
|
|
var
|
|
FEmit:TCustomEmit;
|
|
FNTree:TNodeFetch;
|
|
FPushConstant:PsrBuffer;
|
|
procedure Init(Emit:TCustomEmit); inline;
|
|
function Fetch(s:PsrDataLayout;n:PtrInt):PsrBuffer;
|
|
function NextAlias(buf:PsrBuffer):PsrBuffer;
|
|
Function First:PsrBuffer;
|
|
Function Next(node:PsrBuffer):PsrBuffer;
|
|
procedure EnumAllField(cb:TFieldEnumCb);
|
|
procedure OnFillSpace(node:PsrField);
|
|
procedure FillSpace;
|
|
procedure OnAllocID(pField:PsrField);
|
|
procedure AllocID;
|
|
procedure AllocBinding(Var FBinding:Integer);
|
|
procedure AllocSourceExtension;
|
|
function FindUserDataBuf:PsrBuffer;
|
|
procedure ApplyBufferType;
|
|
procedure AlignOffset(node:PsrBuffer;offset:PtrUint);
|
|
procedure AlignOffset;
|
|
procedure OnAllocTypeBinding(pField:PsrField);
|
|
procedure AllocTypeBinding;
|
|
procedure AllocName;
|
|
end;
|
|
|
|
implementation
|
|
|
|
class Procedure ntBuffer.add_read(node,src:PsrNode);
|
|
begin
|
|
inherited;
|
|
if src^.IsType(ntChain) then
|
|
begin
|
|
PsrBuffer(node)^.AddDep(src);
|
|
end;
|
|
end;
|
|
|
|
class Procedure ntBuffer.rem_read(node,src:PsrNode);
|
|
begin
|
|
inherited;
|
|
if src^.IsType(ntChain) then
|
|
begin
|
|
PsrBuffer(node)^.RemDep(src);
|
|
end;
|
|
end;
|
|
|
|
//
|
|
|
|
class Function ntBuffer.pwrite_count(node:PsrNode):PDWORD;
|
|
begin
|
|
Result:=@PsrBuffer(node)^.fwrite_count;
|
|
end;
|
|
|
|
class function ntBuffer.GetStorageName(node:PsrNode):RawByteString;
|
|
begin
|
|
Result:=PsrBuffer(node)^.GetStorageName;
|
|
end;
|
|
|
|
//---
|
|
|
|
function TsrField.c(n1,n2:PsrField):Integer;
|
|
begin
|
|
Result:=Integer(n1^.offset>n2^.offset)-Integer(n1^.offset<n2^.offset);
|
|
end;
|
|
|
|
function TsrField.Cross(o,s:PtrUint):Boolean;
|
|
begin
|
|
Result:=((o>=offset) and (o<offset+size)) or
|
|
((offset>=o) and (offset<o+s));
|
|
end;
|
|
|
|
function TsrField.Find_be(o:PtrUint):PsrField;
|
|
var
|
|
node:TsrField;
|
|
begin
|
|
node:=Default(TsrField);
|
|
node.offset:=o;
|
|
Result:=FList.Find_be(@node);
|
|
end;
|
|
|
|
function TsrField.Find_le(o:PtrUint):PsrField;
|
|
var
|
|
node:TsrField;
|
|
begin
|
|
node:=Default(TsrField);
|
|
node.offset:=o;
|
|
Result:=FList.Find_le(@node);
|
|
end;
|
|
|
|
function TsrField.First:PsrField;
|
|
begin
|
|
Result:=FList.Min;
|
|
end;
|
|
|
|
function TsrField.Last:PsrField;
|
|
begin
|
|
Result:=FList.Max;
|
|
end;
|
|
|
|
function TsrField.Next(p:PsrField):PsrField;
|
|
begin
|
|
Result:=FList.Next(p);
|
|
end;
|
|
|
|
function TsrField.Prev(p:PsrField):PsrField;
|
|
begin
|
|
Result:=FList.Prev(p);
|
|
end;
|
|
|
|
function TsrField.Fetch(o:PtrUint):PsrField;
|
|
var
|
|
node:TsrField;
|
|
begin
|
|
node:=Default(TsrField);
|
|
node.offset:=o;
|
|
Result:=FList.Find(@node);
|
|
if (Result=nil) then
|
|
begin
|
|
Assert(pBuffer^.FEmit<>nil);
|
|
Result:=pBuffer^.FEmit.Alloc(SizeOf(TsrField));
|
|
Result^.pBuffer:=pBuffer;
|
|
Result^.pParent:=@Self;
|
|
Result^.offset :=o;
|
|
Result^.FID :=-1;
|
|
FList.Insert(Result);
|
|
Inc(FCount);
|
|
end;
|
|
end;
|
|
|
|
function TsrField.FetchValue(_offset,_size:PtrUint;_dtype:TsrDataType):TFieldFetchValue;
|
|
var
|
|
node:PsrField;
|
|
_stride:PtrUint;
|
|
begin
|
|
Result:=Default(TFieldFetchValue);
|
|
|
|
_stride:=0;
|
|
if _dtype.isVector then
|
|
begin
|
|
_stride:=_dtype.Child.BitSize div 8;
|
|
end;
|
|
|
|
Assert(_size=(_dtype.BitSize div 8));
|
|
|
|
node:=Find_le(_offset);
|
|
if (node<>nil) then
|
|
begin
|
|
if not node^.Cross(_offset,_size) then
|
|
begin
|
|
node:=Next(node);
|
|
if (node<>nil) then
|
|
begin
|
|
if not node^.Cross(_offset,_size) then
|
|
begin
|
|
node:=nil;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if (node=nil) then
|
|
begin
|
|
//new
|
|
node:=Fetch(_offset);
|
|
node^.size :=_size;
|
|
node^.stride:=_stride;
|
|
node^.dtype :=_dtype;
|
|
Result.fValue:=frIdent;
|
|
Result.pField:=node;
|
|
end else
|
|
Case node^.dtype of
|
|
dtTypeArray:
|
|
begin
|
|
if (node^.offset>_offset) then Exit; //ident or big than
|
|
if (node^.offset+node^.size<_offset+_size) then Exit;
|
|
if (node^.stride<_size) then Exit; //ident or min stride
|
|
Result.fValue:=frValueInArray;
|
|
Result.pField:=node;
|
|
end;
|
|
dtTypeRuntimeArray:
|
|
begin
|
|
if (node^.offset>_offset) then Exit; //ident or big than
|
|
if (node^.stride<_size) then Exit; //ident or min stride
|
|
Result.fValue:=frValueInArray;
|
|
Result.pField:=node;
|
|
|
|
Result.fValue:=frNotFit;
|
|
end;
|
|
else
|
|
begin
|
|
if node^.dtype.isVector then
|
|
begin //ftVector
|
|
if _dtype.isVector then
|
|
begin
|
|
if (node^.offset=_offset) and
|
|
(node^.size =_size) and
|
|
(node^.stride=_stride) then
|
|
begin
|
|
Result.fValue:=frIdent; //ident
|
|
Result.pField:=node;
|
|
end;
|
|
end else
|
|
begin
|
|
if (node^.offset>_offset) then Exit; //ident or big than
|
|
_offset:=_offset-node^.offset;
|
|
|
|
if (node^.stride=_size) and
|
|
(_offset mod node^.stride=0) then
|
|
begin
|
|
Result.fValue:=frValueInVector; //down to vector
|
|
Result.pField:=node;
|
|
end;
|
|
end;
|
|
end else
|
|
begin //ftValue
|
|
if _dtype.isVector then
|
|
begin
|
|
if (node^.offset=_offset) and
|
|
(node^.size =_size) then
|
|
begin
|
|
Result.fValue:=frVectorAsValue; //vector as value?
|
|
Result.pField:=node;
|
|
end;
|
|
end else
|
|
begin
|
|
if (node^.offset=_offset) and
|
|
(node^.size =_size) then
|
|
begin
|
|
Result.fValue:=frIdent; //ident
|
|
Result.pField:=node;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TsrField.FetchRuntimeArray(_offset,_stride:PtrUint):TFieldFetchValue;
|
|
var
|
|
node:PsrField;
|
|
begin
|
|
Result:=Default(TFieldFetchValue);
|
|
|
|
node:=Find_be(_offset); //RA only last item
|
|
if (node<>nil) then
|
|
begin
|
|
if (node^.offset>_offset) or
|
|
(node^.dtype<>dtTypeRuntimeArray) or
|
|
(node^.stride<>_stride) then
|
|
begin
|
|
Result.fValue:=frNotFit;
|
|
Result.pField:=nil;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
node:=Find_le(_offset);
|
|
if (node=nil) then
|
|
begin
|
|
//new
|
|
node:=Fetch(_offset);
|
|
node^.size :=High(PtrUint)-_offset;
|
|
node^.stride :=_stride;
|
|
node^.dtype :=dtTypeRuntimeArray;
|
|
Result.fValue:=frValueInArray;
|
|
Result.pField:=node;
|
|
end else
|
|
if (node^.stride=_stride) and
|
|
(node^.dtype =dtTypeRuntimeArray) and
|
|
(node^.offset<=_offset) then //ident or big than
|
|
begin
|
|
Result.fValue:=frValueInArray;
|
|
Result.pField:=node;
|
|
end;
|
|
end;
|
|
|
|
function TsrField.IsStructUsedRuntimeArray:Boolean;
|
|
var
|
|
node:PsrField;
|
|
begin
|
|
Result:=False;
|
|
if (dtype=dtTypeStruct) then
|
|
begin
|
|
node:=FList.Max;
|
|
if (node<>nil) then
|
|
begin
|
|
size:=node^.offset+node^.size;
|
|
end;
|
|
Result:=(size=High(PtrUint));
|
|
end;
|
|
end;
|
|
|
|
function TsrField.IsStructNotUsed:Boolean;
|
|
var
|
|
child:PsrField;
|
|
begin
|
|
Result:=False;
|
|
|
|
if IsTop then Exit;
|
|
if (FCount>1) then Exit;
|
|
|
|
child:=First;
|
|
if (child=nil) then Exit;
|
|
|
|
if (child^.offset<>0) then Exit;
|
|
if (child^.size<>stride) then Exit;
|
|
|
|
Result:=True;
|
|
end;
|
|
|
|
function TsrField.IsTop:Boolean;
|
|
begin
|
|
Result:=(pParent=nil);
|
|
end;
|
|
|
|
function TsrField.GetStructDecorate:DWORD;
|
|
begin
|
|
Result:=DWORD(-1); //dont use
|
|
if IsTop then
|
|
if (dtype=dtTypeStruct) then //is struct
|
|
begin
|
|
|
|
if (pBuffer^.FStorage<>StorageClass.StorageBuffer) and
|
|
(pBuffer^.bType=btStorageBuffer) then
|
|
begin
|
|
Result:=Decoration.BufferBlock;
|
|
end else
|
|
begin
|
|
Result:=Decoration.Block;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
procedure TsrField.UpdateSize;
|
|
var
|
|
node:PsrField;
|
|
begin
|
|
node:=FList.Max;
|
|
if (node<>nil) then
|
|
begin
|
|
size:=node^.offset+node^.size;
|
|
end;
|
|
end;
|
|
|
|
function TsrField.GetSize:PtrUint;
|
|
begin
|
|
UpdateSize;
|
|
Result:=size;
|
|
end;
|
|
|
|
procedure TsrField.FillNode(o,s:PtrUint);
|
|
|
|
procedure _Pad(p,v:PtrUint;_dtype:TsrDataType); //inline;
|
|
var
|
|
node:PsrField;
|
|
begin
|
|
if (o mod p<>0) and (s>=v) then
|
|
begin
|
|
node:=Fetch(o);
|
|
Assert(node^.dtype=dtUnknow,'WTF');
|
|
node^.size:=v;
|
|
node^.dtype:=_dtype;
|
|
o:=o+v;
|
|
s:=s-v;
|
|
end;
|
|
end;
|
|
|
|
procedure _Fill(v:PtrUint;_dtype:TsrDataType); //inline;
|
|
var
|
|
count:PtrUint;
|
|
node:PsrField;
|
|
begin
|
|
count:=s div v;
|
|
While (count<>0) do
|
|
begin
|
|
node:=Fetch(o);
|
|
Assert(node^.dtype=dtUnknow,'WTF');
|
|
node^.size:=v;
|
|
node^.dtype:=_dtype;
|
|
o:=o+v;
|
|
s:=s-v;
|
|
Dec(count);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if (s=0) then Exit;
|
|
|
|
_Pad ( 2,1,dtUint8);
|
|
_Pad ( 4,2,dtHalf16);
|
|
_Pad ( 8,4,dtFloat32);
|
|
_Pad (16,8,dtVec2f);
|
|
|
|
_Fill(16,dtVec4f);
|
|
_Fill(8 ,dtVec2f);
|
|
_Fill(4 ,dtFloat32);
|
|
_Fill(2 ,dtHalf16);
|
|
_Fill(1 ,dtUint8);
|
|
end;
|
|
|
|
function TsrField.FillSpace:Integer;
|
|
var
|
|
pNode:PsrField;
|
|
Foffset,Fsize:PtrUint;
|
|
begin
|
|
Result:=0;
|
|
pNode:=First;
|
|
if (pNode=nil) then Exit;
|
|
|
|
Foffset:=0;
|
|
While (pNode<>nil) do
|
|
begin
|
|
|
|
if (pNode^.dtype=dtUnknow) then
|
|
begin
|
|
Case pNode^.size of
|
|
1:pNode^.dtype:=dtUint8;
|
|
2:pNode^.dtype:=dtHalf16;
|
|
4:pNode^.dtype:=dtFloat32;
|
|
8:pNode^.dtype:=dtVec2f;
|
|
16:pNode^.dtype:=dtVec4f;
|
|
else
|
|
Assert(false);
|
|
end;
|
|
end;
|
|
|
|
if (Foffset<pNode^.offset) then
|
|
begin
|
|
Fsize:=pNode^.offset-Foffset;
|
|
FillNode(Foffset,Fsize);
|
|
Inc(Result);
|
|
end;
|
|
Foffset:=pNode^.offset+pNode^.size;
|
|
pNode:=Next(pNode);
|
|
end;
|
|
|
|
if (stride<>0) and (dtype in [dtTypeArray,dtTypeRuntimeArray]) then
|
|
begin
|
|
pNode:=FList.Max;
|
|
if (pNode<>nil) then
|
|
begin
|
|
Foffset:=pNode^.offset+pNode^.size;
|
|
Assert(Foffset<=stride);
|
|
if (Foffset<stride) then
|
|
begin
|
|
Fsize:=stride-Foffset;
|
|
FillNode(Foffset,Fsize);
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//--
|
|
|
|
function TsrBuffer.c(n1,n2:PsrBuffer):Integer;
|
|
begin
|
|
//first pLayout
|
|
Result:=Integer(n1^.key.pLayout>n2^.key.pLayout)-Integer(n1^.key.pLayout<n2^.key.pLayout);
|
|
if (Result<>0) then Exit;
|
|
//second CastNum
|
|
Result:=Integer(n1^.key.AliasId>n2^.key.AliasId)-Integer(n1^.key.AliasId<n2^.key.AliasId);
|
|
end;
|
|
|
|
Procedure TsrBuffer.Init(Emit:TCustomEmit); inline;
|
|
begin
|
|
FEmit:=Emit;
|
|
|
|
fntype :=ntBuffer;
|
|
bType :=btStorageBuffer;
|
|
FStorage:=StorageClass.Uniform;
|
|
FBinding:=-1;
|
|
|
|
FTop.FID:=-1;
|
|
FTop.dtype:=dtTypeStruct;
|
|
end;
|
|
|
|
Procedure TsrBuffer.AddDep(t:PsrNode);
|
|
var
|
|
pRegsStory:PsrRegsStory;
|
|
node:PRegDNode;
|
|
begin
|
|
if (t=nil) or (@Self=nil) then Exit;
|
|
|
|
pRegsStory:=FEmit.GetRegsStory;
|
|
node:=pRegsStory^.AllocDep;
|
|
|
|
node^.pNode:=t;
|
|
FDList.Push_head(node);
|
|
end;
|
|
|
|
Procedure TsrBuffer.RemDep(t:PsrNode);
|
|
var
|
|
pRegsStory:PsrRegsStory;
|
|
node,_prev:PRegDNode;
|
|
begin
|
|
if (t=nil) or (@Self=nil) then Exit;
|
|
node:=FDList.pHead;
|
|
_prev:=nil;
|
|
While (node<>nil) do
|
|
begin
|
|
if (node^.pNode=t) then
|
|
begin
|
|
if (_prev=nil) then
|
|
begin
|
|
FDList.pHead:=node^.pNext;
|
|
end else
|
|
begin
|
|
_prev^.pNext:=node^.pNext;
|
|
end;
|
|
|
|
pRegsStory:=FEmit.GetRegsStory;
|
|
pRegsStory^.FreeDep(node);
|
|
|
|
Exit;
|
|
end;
|
|
_prev:=node;
|
|
node:=node^.pNext;
|
|
end;
|
|
Assert(false,'not found!');
|
|
end;
|
|
|
|
function TsrBuffer.chain_read:DWORD;
|
|
var
|
|
node:PRegDNode;
|
|
begin
|
|
Result:=0;
|
|
node:=FDList.pHead;
|
|
While (node<>nil) do
|
|
begin
|
|
if node^.pNode^.IsType(ntChain) then
|
|
begin
|
|
Result:=Result+PsrChain(node^.pNode)^.read_count;
|
|
end;
|
|
node:=node^.pNext;
|
|
end;
|
|
end;
|
|
|
|
function TsrBuffer.chain_write:DWORD;
|
|
var
|
|
node:PRegDNode;
|
|
begin
|
|
Result:=0;
|
|
node:=FDList.pHead;
|
|
While (node<>nil) do
|
|
begin
|
|
if node^.pNode^.IsType(ntChain) then
|
|
begin
|
|
Result:=Result+PsrChain(node^.pNode)^.write_count;
|
|
end;
|
|
node:=node^.pNext;
|
|
end;
|
|
end;
|
|
|
|
function TsrBuffer.GetStorageName:RawByteString;
|
|
begin
|
|
Result:='';
|
|
Case bType of
|
|
btStorageBuffer:Result:='sBuf'+IntToStr(FBinding);
|
|
btUniformBuffer:Result:='uBuf'+IntToStr(FBinding);
|
|
btPushConstant :Result:='cBuf';
|
|
end;
|
|
end;
|
|
|
|
function TsrBuffer.GetTypeChar:Char;
|
|
begin
|
|
Result:=#0;
|
|
Case bType of
|
|
btStorageBuffer:Result:='S';
|
|
btUniformBuffer:Result:='U';
|
|
btPushConstant :Result:='P';
|
|
end;
|
|
end;
|
|
|
|
function TsrBuffer.GetString:RawByteString;
|
|
var
|
|
PID:DWORD;
|
|
begin
|
|
PID:=0;
|
|
if (key.pLayout<>nil) then
|
|
begin
|
|
PID:=key.pLayout^.FID;
|
|
end;
|
|
Result:='B'+GetTypeChar+
|
|
';PID='+HexStr(PID,8)+
|
|
';BND='+HexStr(FBinding,8)+
|
|
';LEN='+HexStr(GetSize,8)+
|
|
';OFS='+HexStr(align_offset,8);
|
|
end;
|
|
|
|
function TsrBuffer.GetStructName:RawByteString;
|
|
begin
|
|
Result:='TD'+HexStr(FBinding,8);
|
|
end;
|
|
|
|
function TsrBuffer.GetSize:PtrUint;
|
|
begin
|
|
Result:=FTop.GetSize;
|
|
end;
|
|
|
|
procedure TsrBuffer.EnumAllField(cb:TFieldEnumCb);
|
|
var
|
|
curr,node:PsrField;
|
|
begin
|
|
if (cb=nil) then Exit;
|
|
curr:=@FTop;
|
|
node:=curr^.First;
|
|
repeat
|
|
While (node<>nil) do
|
|
begin
|
|
if (node^.First<>nil) then //child exist
|
|
begin
|
|
curr:=node;
|
|
node:=curr^.First; //down
|
|
end else
|
|
begin
|
|
cb(node);
|
|
node:=curr^.Next(node);
|
|
end;
|
|
end;
|
|
cb(curr);
|
|
node:=curr;
|
|
curr:=curr^.pParent; //up
|
|
if (curr=nil) then Break;
|
|
node:=curr^.Next(node);
|
|
until false;
|
|
end;
|
|
|
|
procedure TsrBuffer.ShiftOffset(Offset:PtrUint);
|
|
var
|
|
node:PsrField;
|
|
begin
|
|
if (Offset=0) then Exit;
|
|
node:=FTop.Last;
|
|
While (node<>nil) do
|
|
begin
|
|
if (node^.offset+node^.size=High(PtrUint)) then
|
|
begin
|
|
node^.size:=node^.size-Offset;
|
|
end;
|
|
node^.offset:=node^.offset+Offset;
|
|
node:=FTop.Prev(node);
|
|
end;
|
|
end;
|
|
|
|
procedure TsrBufferList.Init(Emit:TCustomEmit); inline;
|
|
begin
|
|
FEmit:=Emit;
|
|
end;
|
|
|
|
function TsrBufferList.Fetch(s:PsrDataLayout;n:PtrInt):PsrBuffer;
|
|
var
|
|
node:TsrBuffer;
|
|
begin
|
|
node:=Default(TsrBuffer);
|
|
node.Init(FEmit);
|
|
node.key.pLayout:=s;
|
|
node.key.AliasId:=n;
|
|
Result:=FNTree.Find(@node);
|
|
if (Result=nil) then
|
|
begin
|
|
Result:=FEmit.Alloc(SizeOf(TsrBuffer));
|
|
Move(node,Result^,SizeOf(TsrBuffer));
|
|
Result^.FTop.pBuffer:=Result;
|
|
//
|
|
Result^.InitVar(FEmit);
|
|
//
|
|
FNTree.Insert(Result);
|
|
end;
|
|
end;
|
|
|
|
function TsrBufferList.NextAlias(buf:PsrBuffer):PsrBuffer;
|
|
begin
|
|
Result:=nil;
|
|
if (buf=nil) then Exit;
|
|
Result:=Fetch(buf^.key.pLayout,buf^.key.AliasId+1);
|
|
end;
|
|
|
|
Function TsrBufferList.First:PsrBuffer;
|
|
begin
|
|
Result:=FNTree.Min;
|
|
end;
|
|
|
|
Function TsrBufferList.Next(node:PsrBuffer):PsrBuffer;
|
|
begin
|
|
Result:=FNTree.Next(node);
|
|
end;
|
|
|
|
procedure TsrBufferList.EnumAllField(cb:TFieldEnumCb);
|
|
var
|
|
node:PsrBuffer;
|
|
begin
|
|
if (cb=nil) then Exit;
|
|
node:=First;
|
|
While (node<>nil) do
|
|
begin
|
|
if node^.IsUsed then
|
|
begin
|
|
node^.EnumAllField(cb);
|
|
end;
|
|
node:=Next(node);
|
|
end;
|
|
end;
|
|
|
|
procedure TsrBufferList.OnFillSpace(node:PsrField);
|
|
begin
|
|
node^.FillSpace;
|
|
end;
|
|
|
|
procedure TsrBufferList.FillSpace;
|
|
begin
|
|
EnumAllField(@OnFillSpace);
|
|
end;
|
|
|
|
procedure TsrBufferList.OnAllocID(pField:PsrField);
|
|
var
|
|
node:PsrField;
|
|
ID:Integer;
|
|
begin
|
|
ID:=0;
|
|
node:=pField^.First;
|
|
While (node<>nil) do
|
|
begin
|
|
if pField^.dtype.IsVector then
|
|
begin
|
|
ID:=node^.offset div pField^.stride;
|
|
node^.FID:=ID;
|
|
end else
|
|
begin
|
|
node^.FID:=ID;
|
|
Inc(ID);
|
|
end;
|
|
node:=pField^.Next(node);
|
|
end;
|
|
end;
|
|
|
|
procedure TsrBufferList.AllocID;
|
|
begin
|
|
EnumAllField(@OnAllocID);
|
|
end;
|
|
|
|
procedure TsrBufferList.AllocBinding(Var FBinding:Integer);
|
|
var
|
|
pConfig:PsrConfig;
|
|
pDecorateList:PsrDecorateList;
|
|
node:PsrBuffer;
|
|
pVar:PsrVariable;
|
|
begin
|
|
pConfig:=FEmit.GetConfig;
|
|
pDecorateList:=FEmit.GetDecorateList;
|
|
node:=First;
|
|
While (node<>nil) do
|
|
begin
|
|
pVar:=node^.pVar;
|
|
if (pVar<>nil) and node^.IsUsed then
|
|
if (node^.bType<>btPushConstant) then
|
|
if (node^.FBinding=-1) then //alloc
|
|
begin
|
|
pDecorateList^.OpDecorate(pVar,Decoration.Binding,FBinding);
|
|
pDecorateList^.OpDecorate(pVar,Decoration.DescriptorSet,pConfig^.DescriptorSet);
|
|
node^.FBinding:=FBinding;
|
|
Inc(FBinding);
|
|
end;
|
|
node:=Next(node);
|
|
end;
|
|
end;
|
|
|
|
procedure TsrBufferList.AllocSourceExtension;
|
|
var
|
|
pDebugInfoList:PsrDebugInfoList;
|
|
node:PsrBuffer;
|
|
pVar:PsrVariable;
|
|
begin
|
|
pDebugInfoList:=FEmit.GetDebugInfoList;
|
|
node:=First;
|
|
While (node<>nil) do
|
|
begin
|
|
pVar:=node^.pVar;
|
|
if (pVar<>nil) and node^.IsUsed then
|
|
begin
|
|
pDebugInfoList^.OpSource(node^.GetString);
|
|
end;
|
|
node:=Next(node);
|
|
end;
|
|
end;
|
|
|
|
function TsrBufferList.FindUserDataBuf:PsrBuffer;
|
|
var
|
|
node:PsrBuffer;
|
|
begin
|
|
Result:=nil;
|
|
node:=First;
|
|
While (node<>nil) do
|
|
begin
|
|
if node^.IsUsed then
|
|
begin
|
|
if node^.key.pLayout^.IsUserData then
|
|
begin
|
|
Exit(node);
|
|
end;
|
|
end;
|
|
node:=Next(node);
|
|
end;
|
|
end;
|
|
|
|
procedure TsrBufferList.ApplyBufferType;
|
|
var
|
|
pConfig:PsrConfig;
|
|
node:PsrBuffer;
|
|
fchain_write:DWORD;
|
|
begin
|
|
pConfig:=FEmit.GetConfig;
|
|
|
|
node:=FindUserDataBuf;
|
|
if (node<>nil) and (FPushConstant=nil) then
|
|
if (node^.write_count=0) and
|
|
(node^.GetSize<=pConfig^.maxPushConstantsSize) then
|
|
begin
|
|
node^.bType :=btPushConstant;
|
|
node^.FStorage:=StorageClass.PushConstant;
|
|
FPushConstant :=node;
|
|
end;
|
|
|
|
node:=First;
|
|
While (node<>nil) do
|
|
begin
|
|
if node^.IsUsed and (node^.bType=btStorageBuffer) then
|
|
begin
|
|
|
|
fchain_write:=node^.chain_write;
|
|
|
|
if (FPushConstant=nil) and
|
|
(fchain_write=0) and
|
|
(node^.GetSize<=pConfig^.maxPushConstantsSize) then
|
|
begin
|
|
node^.bType :=btPushConstant;
|
|
node^.FStorage:=StorageClass.PushConstant;
|
|
FPushConstant :=node;
|
|
end else
|
|
if (fchain_write=0) and
|
|
(node^.GetSize<=pConfig^.maxUniformBufferRange) then
|
|
begin
|
|
node^.bType :=btUniformBuffer;
|
|
node^.FStorage:=StorageClass.Uniform;
|
|
end else
|
|
if pConfig^.CanUseStorageBufferClass then
|
|
begin
|
|
node^.FStorage:=StorageClass.StorageBuffer;
|
|
end else
|
|
begin
|
|
node^.FStorage:=StorageClass.Uniform;
|
|
end;
|
|
|
|
end;
|
|
node:=Next(node);
|
|
end;
|
|
end;
|
|
|
|
function AlignShift(addr:Pointer;alignment:PtrUInt):PtrUInt; inline;
|
|
begin
|
|
if (alignment>1) then
|
|
begin
|
|
Result:=(PtrUInt(addr) mod alignment);
|
|
end else
|
|
begin
|
|
Result:=0;
|
|
end;
|
|
end;
|
|
|
|
procedure TsrBufferList.AlignOffset(node:PsrBuffer;offset:PtrUint);
|
|
var
|
|
P:Pointer;
|
|
begin
|
|
P:=node^.key.pLayout^.GetData;
|
|
offset:=AlignShift(P,offset);
|
|
node^.align_offset:=offset;
|
|
node^.ShiftOffset(offset);
|
|
end;
|
|
|
|
procedure TsrBufferList.AlignOffset;
|
|
var
|
|
pConfig:PsrConfig;
|
|
node:PsrBuffer;
|
|
begin
|
|
pConfig:=FEmit.GetConfig;
|
|
node:=First;
|
|
While (node<>nil) do
|
|
begin
|
|
if node^.IsUsed then
|
|
begin
|
|
Case node^.bType of
|
|
btStorageBuffer:
|
|
begin
|
|
AlignOffset(node,pConfig^.minStorageBufferOffsetAlignment);
|
|
end;
|
|
btUniformBuffer:
|
|
begin
|
|
AlignOffset(node,pConfig^.minUniformBufferOffsetAlignment);
|
|
end;
|
|
btPushConstant:
|
|
begin
|
|
node^.align_offset:=pConfig^.PushConstantsOffset;
|
|
node^.ShiftOffset(pConfig^.PushConstantsOffset);
|
|
end;
|
|
end;
|
|
end;
|
|
node:=Next(node);
|
|
end;
|
|
end;
|
|
|
|
procedure TsrBufferList.OnAllocTypeBinding(pField:PsrField);
|
|
var
|
|
pDecorateList:PsrDecorateList;
|
|
node:PsrField;
|
|
SD:DWORD;
|
|
begin
|
|
if (pField^.sType=nil) then Exit;
|
|
if (pField^.sType^.dtype<>dtTypeStruct) then Exit;
|
|
|
|
pDecorateList:=FEmit.GetDecorateList;
|
|
SD:=pField^.GetStructDecorate;
|
|
if (SD<>DWORD(-1)) then
|
|
begin
|
|
pDecorateList^.OpDecorate(pField^.sType,SD,0);
|
|
end;
|
|
node:=pField^.First;
|
|
While (node<>nil) do
|
|
begin
|
|
pDecorateList^.OpMember(pField^.sType,node^.FID,node^.offset);
|
|
node:=pField^.Next(node);
|
|
end;
|
|
end;
|
|
|
|
procedure TsrBufferList.AllocTypeBinding;
|
|
var
|
|
pDecorateList:PsrDecorateList;
|
|
node:PsrBuffer;
|
|
begin
|
|
EnumAllField(@OnAllocTypeBinding);
|
|
//
|
|
pDecorateList:=FEmit.GetDecorateList;
|
|
//
|
|
node:=First;
|
|
While (node<>nil) do
|
|
begin
|
|
if node^.IsUsed and (node^.pVar<>nil) then
|
|
if (node^.bType=btStorageBuffer) then
|
|
begin
|
|
if (node^.chain_read=0) then
|
|
begin
|
|
pDecorateList^.OpDecorate(node^.pVar,Decoration.NonReadable,0);
|
|
end;
|
|
if (node^.chain_write=0) then
|
|
begin
|
|
pDecorateList^.OpDecorate(node^.pVar,Decoration.NonWritable,0);
|
|
end;
|
|
end;
|
|
node:=Next(node);
|
|
end;
|
|
end;
|
|
|
|
procedure TsrBufferList.AllocName;
|
|
var
|
|
FDebugInfo:PsrDebugInfoList;
|
|
node:PsrBuffer;
|
|
begin
|
|
FDebugInfo:=FEmit.GetDebugInfoList;
|
|
node:=First;
|
|
While (node<>nil) do
|
|
begin
|
|
if node^.IsUsed and (node^.FTop.pType<>nil) then
|
|
begin
|
|
FDebugInfo^.OpName(node^.FTop.pType,node^.GetStructName);
|
|
end;
|
|
node:=Next(node);
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|