FPPS4/spirv/srBuffer.pas

1435 lines
27 KiB
Plaintext

unit srBuffer;
{$mode ObjFPC}{$H+}
interface
uses
sysutils,
spirv,
ginodes,
srNode,
srType,
srTypes,
srLayout,
srDecorate,
srConfig;
type
String2=String[2];
TsrBuffer=class;
TsrField=class;
TsrFieldValue=(frNotFit,frIdent,frVectorAsValue,frValueInVector,frValueInArray);
TFieldFetchValue=record
fValue:TsrFieldValue;
pField:TsrField;
end;
TFieldEnumCb=procedure(pField:TsrField) of object;
TsrField=class
type
TFieldTree=specialize TNodeTreeClass<TsrField>;
var
pLeft,pRight:TsrField;
//----
pBuffer:TsrBuffer;
pParent:TsrField;
//
key:PtrUint; //offset
//
FFSize :PtrUint; //full size of struct/array (cached)
stride :PtrUint; //value size/stride in array
count :PtrUint; //count in array
FCount:PtrUint; //field count
Fdtype:TsrDataType; //field type
sType,vType:TsrType;
FID:Integer; //alloc late
//
FList:TFieldTree;
class function c(n1,n2:PPtrUint):Integer; static;
property offset:PtrUint read key write key;
function Cross(o,s:PtrUint):Boolean;
function Find_be(o:PtrUint):TsrField;
function Find_le(o:PtrUint):TsrField;
function Find_ls(o:PtrUint):TsrField;
function First:TsrField;
function Last:TsrField;
function Next(p:TsrField):TsrField;
function Prev(p:TsrField):TsrField;
function Fetch(o:PtrUint):TsrField;
Procedure ClearSize;
function FindIntersect(_offset,_size:PtrUint):TsrField;
function FetchValue(_offset,_size:PtrUint;_dtype:TsrDataType;_weak:Boolean):TFieldFetchValue;
function FetchArray(_offset,_size,_stride:PtrUint):TFieldFetchValue;
function FetchRuntimeArray(_offset,_stride:PtrUint):TFieldFetchValue;
function IsStructUsedRuntimeArray:Boolean;
function IsStructNotUsed:Boolean;
function IsTop:Boolean;
function GetStructDecorate:DWORD;
procedure UpdateSize;
function Size:PtrUint;
procedure FillNode(o,s:PtrUint);
function FillSpace:Integer;
end;
TsrBufferType=(btStorageBuffer,btUniformBuffer,btPushConstant,btWorkgroup,btPrivate);
PsrBufferKey=^TsrBufferKey;
TsrBufferKey=packed record
pLayout:TsrDataLayout;
AliasId:PtrInt;
end;
TsrBuffer=class(TsrDescriptor)
pLeft,pRight:TsrBuffer;
//----
//
align_offset:DWORD;
FDList:TDependenceNodeList;
bType:TsrBufferType;
key:TsrBufferKey;
FTop:TsrField;
pNextAlias:TsrBuffer; // alias cache
tRef:TsrNode; //bitcast cache
//
Procedure add_read(src:TsrNode); override;
Procedure rem_read(src:TsrNode); override;
//
function _GetStorageName:RawByteString; override;
//
class function c(n1,n2:PsrBufferKey):Integer; static;
//
property pLayout:TsrDataLayout read key.pLayout;
property AliasId:PtrInt read key.AliasId;
//
Function is_export_used:Boolean;
Procedure Init(); inline;
Procedure AddDep(t:TsrNode);
Procedure RemDep(t:TsrNode);
function _chain_read:DWORD;
function chain_read :DWORD;
function _chain_write:DWORD;
function chain_write:DWORD;
function GetStorageName:RawByteString;
function GetTypeStr:PChar;
function GetFlagsStr:String2;
function GetStructName:RawByteString;
function GetSize:PtrUint;
procedure EnumAllField(cb:TFieldEnumCb);
procedure ShiftOffset(Offset:PtrUint);
//
procedure AllocSourceExtension2(var Writer:TseWriter); override;
end;
ntBuffer=TsrBuffer;
PsrBufferList=^TsrBufferList;
TsrBufferList=object
type
TNodeTree=specialize TNodeTreeClass<TsrBuffer>;
var
FEmit:TCustomEmit;
FTree:TNodeTree;
FPushConstant:TsrBuffer;
procedure Init(Emit:TCustomEmit); inline;
function Fetch(s:TsrDataLayout;n:PtrInt;GLC,SLC:Boolean):TsrBuffer;
function NextAlias(buf:TsrBuffer;GLC,SLC:Boolean):TsrBuffer;
Function First:TsrBuffer;
Function Next(node:TsrBuffer):TsrBuffer;
procedure EnumAllField(cb:TFieldEnumCb);
procedure OnFillSpace(node:TsrField);
procedure FillSpace;
procedure OnAllocID(pField:TsrField);
procedure AllocID;
procedure AllocBinding(Var FBinding:Integer);
function FindUserDataBuf:TsrBuffer;
procedure ApplyBufferType;
procedure AlignOffset(node:TsrBuffer;offset:PtrUint);
procedure AlignOffset;
procedure OnAllocTypeBinding(pField:TsrField);
procedure AllocTypeBinding;
procedure AllocName;
end;
Const
MAX_BUF_SIZE=QWORD(High(DWORD)+1);
operator := (i:TObject):TsrField; inline;
implementation
operator := (i:TObject):TsrField; inline;
begin
Result:=TsrField(Pointer(i)); //typecast hack
end;
Procedure TsrBuffer.add_read(src:TsrNode);
begin
inherited;
if src.IsType(ntChain) then
begin
AddDep(src);
end;
end;
Procedure TsrBuffer.rem_read(src:TsrNode);
begin
inherited;
if src.IsType(ntChain) then
begin
RemDep(src);
end;
end;
function TsrBuffer._GetStorageName:RawByteString;
begin
Result:=GetStorageName;
end;
//---
class function TsrField.c(n1,n2:PPtrUint):Integer;
begin
Result:=ord(n1^>n2^)-ord(n1^<n2^);
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):TsrField;
begin
Result:=FList.Find_be(@o);
end;
function TsrField.Find_le(o:PtrUint):TsrField;
begin
Result:=FList.Find_le(@o);
end;
function TsrField.Find_ls(o:PtrUint):TsrField;
begin
Result:=FList.Find_ls(@o);
end;
function TsrField.First:TsrField;
begin
Result:=FList.Min;
end;
function TsrField.Last:TsrField;
begin
Result:=FList.Max;
end;
function TsrField.Next(p:TsrField):TsrField;
begin
Result:=FList.Next(p);
end;
function TsrField.Prev(p:TsrField):TsrField;
begin
Result:=FList.Prev(p);
end;
function TsrField.Fetch(o:PtrUint):TsrField;
begin
Result:=FList.Find(@o);
if (Result=nil) then
begin
Assert(pBuffer.Emit<>nil);
Result:=pBuffer.Emit.specialize New<TsrField>;
Result.pBuffer:=pBuffer;
Result.pParent:=Self;
Result.offset :=o;
Result.FID :=-1;
FList.Insert(Result);
//inc field count
Inc(FCount);
//clear parent size
ClearSize;
end;
end;
Procedure TsrField.ClearSize;
var
node:TsrField;
begin
node:=Self;
while (node<>nil) do
begin
//update only struct
if (node.Fdtype<>dtTypeStruct) then Exit;
//dont clear max size
if (node.FFSize=MAX_BUF_SIZE) then Exit;
//
node.FFSize:=0;
//
node:=node.pParent;
end;
end;
function TsrField.FindIntersect(_offset,_size:PtrUint):TsrField;
var
node:TsrField;
begin
Result:=nil;
node:=Find_ls(_offset+_size);
//
while (node<>nil) do
begin
if node.Cross(_offset,_size) then
begin
Exit(node);
end;
//
node:=Prev(node);
end;
end;
function TsrField.FetchValue(_offset,_size:PtrUint;_dtype:TsrDataType;_weak:Boolean):TFieldFetchValue;
var
node:TsrField;
_stride:PtrUint;
begin
Result:=Default(TFieldFetchValue);
if _dtype.isVector then
begin
_stride:=_dtype.Child.BitSize div 8;
end else
begin
_stride:=_dtype.BitSize div 8;
end;
Assert(_size=(_dtype.BitSize div 8));
//find intersec
node:=FindIntersect(_offset,_size);
if (node=nil) then
begin
//new
node:=Fetch(_offset);
node.FFSize:=_size; //fixed size
node.stride:=_stride;
node.count :=1;
node.Fdtype:=_dtype;
//
Result.fValue:=frIdent;
Result.pField:=node;
end else
Case node.Fdtype 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;
end;
else
begin
if node.Fdtype.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;
if not _weak then
begin
case Result.fValue of
frIdent:
begin
if (node.Fdtype<>_dtype) then
begin
Result:=Default(TFieldFetchValue);
end;
end;
frValueInVector:
begin
if (node.Fdtype.Child<>_dtype) then
begin
Result:=Default(TFieldFetchValue);
end;
end;
else;
end;
end;
//
end;
function TsrField.FetchArray(_offset,_size,_stride:PtrUint):TFieldFetchValue;
var
node:TsrField;
_count:PtrUint;
max_old:PtrUint;
max_new:PtrUint;
begin
Result:=Default(TFieldFetchValue);
Assert(_stride<>0);
Assert(_size <>0);
_count:=_size div _stride;
_size :=_count*_stride; //align
Assert(_count<>0);
//find intersec
node:=FindIntersect(_offset,_size);
if (node=nil) then
begin
//new
node:=Fetch(_offset);
node.FFSize:=_size; //fixed size
node.stride:=_stride;
node.count :=_count;
node.Fdtype:=dtTypeArray;
//
Result.fValue:=frValueInArray;
Result.pField:=node;
end else
Case node.Fdtype of
dtTypeArray:
begin
if (node.offset>_offset) then Exit; //ident or big than
if (node.stride<>_stride) then Exit; //ident stride
//
max_old:=node.offset+node.size;
max_new:=_offset+_size;
//
if (max_old<max_new) then
begin
//expand?
if FindIntersect(max_old,max_new-max_old)<>nil then
begin
//dont expand
//not fit
Exit;
end;
//
_size:=max_new-node.offset;
_size:=Align(_size,_stride); //align up
_count:=_size div _stride;
//
node.FFSize:=_size; //fixed size
node.count :=_count;
end;
//
Result.fValue:=frValueInArray;
Result.pField:=node;
end;
dtTypeRuntimeArray:
begin
if (node.offset>_offset) then Exit; //ident or big than
if (node.stride<>_stride) then Exit; //ident stride
//
Result.fValue:=frValueInArray;
Result.pField:=node;
end;
else;
end;
end;
function TsrField.FetchRuntimeArray(_offset,_stride:PtrUint):TFieldFetchValue;
var
node:TsrField;
begin
Result:=Default(TFieldFetchValue);
node:=Find_be(_offset); //RA only last item
if (node<>nil) then
begin
if (node.offset>_offset) or
(node.Fdtype<>dtTypeRuntimeArray) or
(node.stride<>_stride) then
begin
//not fit
Exit;
end;
end;
//find intersec
node:=FindIntersect(_offset,MAX_BUF_SIZE-offset);
if (node=nil) then
begin
//new
node:=Fetch(_offset);
node.FFSize:=MAX_BUF_SIZE; //fixed size
node.stride:=_stride;
node.count :=node.FFSize div _stride;
node.Fdtype :=dtTypeRuntimeArray;
//
Result.fValue:=frValueInArray;
Result.pField:=node;
end else
if (node.stride=_stride) and //ident stride
(node.Fdtype=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:TsrField;
begin
Result:=False;
if (Fdtype=dtTypeStruct) then
begin
node:=FList.Max;
if (node<>nil) then
begin
Result:=(node.Fdtype=dtTypeRuntimeArray);
end;
end;
end;
function TsrField.IsStructNotUsed:Boolean;
var
child:TsrField;
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 (Fdtype=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:TsrField;
begin
if (FFSize<>0) then Exit;
//
if Fdtype.isVector then
begin
FFSize:=Fdtype.BitSize div 8
end else
if (Fdtype=dtTypeArray) then
begin
//array
FFSize:=count*stride;
end else
if (Fdtype=dtTypeRuntimeArray) then
begin
//runtame array
FFSize:=MAX_BUF_SIZE;
end else
begin
//struct
node:=FList.Max;
if (node<>nil) then
begin
FFSize:=node.size;
//check max
if (FFSize=MAX_BUF_SIZE) then Exit;
FFSize:=node.offset+FFSize;
end;
end;
end;
function TsrField.Size:PtrUint;
begin
UpdateSize;
Result:=FFSize;
end;
procedure TsrField.FillNode(o,s:PtrUint);
procedure _Pad(p,v:PtrUint;_dtype:TsrDataType); //inline;
var
node:TsrField;
begin
if (o mod p<>0) and (s>=v) then
begin
node:=Fetch(o);
Assert(node.Fdtype=dtUnknow,'WTF');
node.FFSize:=v; //fixed size
node.stride:=v;
if _dtype.isVector then
begin
node.stride:=_dtype.Child.BitSize div 8;
end;
node.Fdtype:=_dtype;
o:=o+v;
s:=s-v;
end;
end;
procedure _Fill(v:PtrUint;_dtype:TsrDataType); //inline;
var
count:PtrUint;
node:TsrField;
begin
count:=s div v;
While (count<>0) do
begin
node:=Fetch(o);
Assert(node.Fdtype=dtUnknow,'WTF');
node.FFSize:=v; //fixed size
node.stride:=v;
if _dtype.isVector then
begin
node.stride:=_dtype.Child.BitSize div 8;
end;
node.Fdtype:=_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:TsrField;
Foffset,Fsize:PtrUint;
begin
Result:=0;
pNode:=First;
if (pNode=nil) then Exit;
Foffset:=0;
While (pNode<>nil) do
begin
if (pNode.Fdtype=dtUnknow) then
begin
Case pNode.size of
1:pNode.Fdtype:=dtUint8;
2:pNode.Fdtype:=dtHalf16;
4:pNode.Fdtype:=dtFloat32;
8:pNode.Fdtype:=dtVec2f;
16:pNode.Fdtype:=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 (Fdtype 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;
//--
class function TsrBuffer.c(n1,n2:PsrBufferKey):Integer;
begin
//first pLayout
Result:=ord(n1^.pLayout.Order>n2^.pLayout.Order)-ord(n1^.pLayout.Order<n2^.pLayout.Order);
if (Result<>0) then Exit;
//second AliasId
Result:=ord(n1^.AliasId>n2^.AliasId)-ord(n1^.AliasId<n2^.AliasId);
end;
Function TsrBuffer.is_export_used:Boolean;
begin
Result:=IsUsed;
if Result then
begin
if (pVar=nil) then Exit(false);
Result:=pVar.IsUsed;
end;
end;
Procedure TsrBuffer.Init(); inline;
begin
bType :=btStorageBuffer;
FStorage:=StorageClass.Uniform;
FBinding:=-1;
FTop:=Emit.specialize New<TsrField>;
FTop.FID :=-1;
FTop.Fdtype :=dtTypeStruct;
FTop.pBuffer:=Self;
end;
Procedure TsrBuffer.AddDep(t:TsrNode);
var
node:TDependenceNode;
begin
if (t=nil) or (Self=nil) then Exit;
node:=NewDependence;
node.pNode:=t;
FDList.Push_head(node);
end;
Procedure TsrBuffer.RemDep(t:TsrNode);
var
node:TDependenceNode;
begin
if (t=nil) or (Self=nil) then Exit;
node:=FDList.pHead;
While (node<>nil) do
begin
if (node.pNode=t) then
begin
FDList.Remove(node);
FreeDependence(node);
Exit;
end;
node:=node.pNext;
end;
Assert(false,'not found!');
end;
function TsrBuffer._chain_read:DWORD;
var
node:TDependenceNode;
begin
Result:=0;
node:=FDList.pHead;
While (node<>nil) do
begin
if node.pNode.IsType(ntChain) then
begin
Result:=Result+node.pNode.read_count;
end;
node:=node.pNext;
end;
end;
function TsrBuffer.chain_read:DWORD;
var
node:TsrBuffer;
begin
Result:=0;
if Flags.Bitcast then
begin
node:=Self;
while (node<>nil) do
begin
Result:=Result+node._chain_read;
node:=node.pNextAlias;
end;
end else
begin
Result:=_chain_read;
end;
end;
function TsrBuffer._chain_write:DWORD;
var
node:TDependenceNode;
begin
Result:=0;
node:=FDList.pHead;
While (node<>nil) do
begin
if node.pNode.IsType(ntChain) then
begin
Result:=Result+node.pNode.write_count;
end;
node:=node.pNext;
end;
end;
function TsrBuffer.chain_write:DWORD;
var
node:TsrBuffer;
begin
Result:=0;
if Flags.Bitcast then
begin
node:=Self;
while (node<>nil) do
begin
Result:=Result+node._chain_write;
node:=node.pNextAlias;
end;
end else
begin
Result:=_chain_write;
end;
end;
function TsrBuffer.GetStorageName:RawByteString;
begin
Result:='';
if (pLayout<>nil) then
begin
case pLayout.key.rtype of
rtLDS:
begin
Result:='sLds'+IntToStr(FBinding);
Exit;
end;
rtGDS:
begin
Result:='sGds'+IntToStr(FBinding);
Exit;
end;
else;
end;
end;
Case bType of
btStorageBuffer:Result:='sBuf'+IntToStr(FBinding);
btUniformBuffer:Result:='uBuf'+IntToStr(FBinding);
btPushConstant :Result:='cBuf';
end;
end;
function TsrBuffer.GetTypeStr:PChar;
begin
Result:=nil;
Case bType of
btStorageBuffer:Result:='+STR_BUF';
btUniformBuffer:Result:='+UNF_BUF';
btPushConstant :Result:='+PSH_CST';
end;
end;
function TsrBuffer.GetFlagsStr:String2;
const
_R:array[0..1] of AnsiChar='_R';
_W:array[0..1] of AnsiChar='_W';
begin
Result:=_R[ord(chain_read <>0)]+
_W[ord(chain_write<>0)];
end;
function TsrBuffer.GetStructName:RawByteString;
begin
Result:='TD'+HexStr(FBinding,8);
end;
function TsrBuffer.GetSize:PtrUint;
begin
Result:=FTop.size;
end;
procedure TsrBuffer.EnumAllField(cb:TFieldEnumCb);
var
curr,node:TsrField;
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:TsrField;
begin
if (Offset=0) then Exit;
node:=FTop.Last;
While (node<>nil) do
begin
node.offset:=node.offset+Offset;
node:=FTop.Prev(node);
end;
//
FTop.ClearSize;
FTop.UpdateSize;
end;
procedure TsrBufferList.Init(Emit:TCustomEmit); inline;
begin
FEmit:=Emit;
end;
function TsrBufferList.Fetch(s:TsrDataLayout;n:PtrInt;GLC,SLC:Boolean):TsrBuffer;
var
key:TsrBufferKey;
begin
key:=Default(TsrBufferKey);
key.pLayout:=s;
key.AliasId:=n;
//
Result:=FTree.Find(@key);
if (Result=nil) then
begin
Result:=FEmit.specialize New<TsrBuffer>;
Result.Init();
Result.key:=key;
//
Result.InitVar();
//
FTree.Insert(Result);
//
s.FDescList.Push_tail(Result);
end;
//
if GLC then
begin
Result.Flags.Coherent:=True;
end;
//
if SLC then
begin
Result.Flags.Volatile:=True;
end;
end;
function TsrBufferList.NextAlias(buf:TsrBuffer;GLC,SLC:Boolean):TsrBuffer;
begin
Result:=nil;
if (buf=nil) then Exit;
Result:=buf.pNextAlias;
if (Result=nil) then
begin
Result:=Fetch(buf.pLayout,buf.AliasId+1,GLC,SLC);
//cache
buf.pNextAlias:=Result;
end;
//mark
buf.Flags.Aliased:=True;
Result.Flags.Aliased:=True;
end;
Function TsrBufferList.First:TsrBuffer;
begin
Result:=FTree.Min;
end;
Function TsrBufferList.Next(node:TsrBuffer):TsrBuffer;
begin
Result:=FTree.Next(node);
end;
procedure TsrBufferList.EnumAllField(cb:TFieldEnumCb);
var
node:TsrBuffer;
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:TsrField);
begin
node.FillSpace;
end;
procedure TsrBufferList.FillSpace;
begin
EnumAllField(@OnFillSpace);
end;
procedure TsrBufferList.OnAllocID(pField:TsrField);
var
node:TsrField;
ID:Integer;
begin
ID:=0;
node:=pField.First;
While (node<>nil) do
begin
if pField.Fdtype.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:TsrDecorateList;
node:TsrBuffer;
FHide:Integer;
begin
pConfig:=FEmit.GetConfig;
pDecorateList:=FEmit.GetDecorateList;
//
node:=First;
While (node<>nil) do
begin
if node.is_export_used then
if not (node.bType in [btPushConstant]) then
if (node.FBinding=-1) then //alloc
begin
//
if not (node.bType in [btWorkgroup,btPrivate]) then
begin
pDecorateList.OpDecorate(node.pVar,Decoration.Binding ,FBinding);
pDecorateList.OpDecorate(node.pVar,Decoration.DescriptorSet,pConfig^.DescriptorSet);
//
if (node.Flags.Coherent) then
begin
pDecorateList.OpDecorate(node.pVar,Decoration.Coherent,0);
end;
//
if (node.Flags.Volatile) then
begin
pDecorateList.OpDecorate(node.pVar,Decoration.Volatile,0);
end;
//next bind id
node.FBinding:=FBinding;
Inc(FBinding);
end; //
//Aliased need for uniform/storage/workgroup
if (node.Flags.Aliased) and (not node.Flags.Bitcast) then
begin
pDecorateList.OpDecorate(node.pVar,Decoration.Aliased,0);
end;
end;
//
node:=Next(node);
end;
//Alloc hide id
FHide:=FBinding;
node:=First;
While (node<>nil) do
begin
if (node.FBinding=-1) then //alloc
begin
node.FBinding:=FHide;
Inc(FHide);
end;
node:=Next(node);
end;
end;
procedure TsrBuffer.AllocSourceExtension2(var Writer:TseWriter);
begin
if is_export_used then
if not (bType in [btWorkgroup,btPrivate]) then
begin
//start block
Writer.Header(GetTypeStr);
//
Writer.IntOpt('BND',FBinding);
if (GetSize<>MAX_BUF_SIZE) then
begin
Writer.HexOpt('LEN',GetSize);
end;
if (align_offset<>0) then
begin
Writer.HexOpt('OFS',align_offset);
end;
Writer.StrOpt('FLG',GetFlagsStr);
end;
end;
function TsrBufferList.FindUserDataBuf:TsrBuffer;
var
node:TsrBuffer;
begin
Result:=nil;
node:=First;
While (node<>nil) do
begin
if node.IsUsed then
begin
if node.pLayout.IsUserData then
begin
Exit(node);
end;
end;
node:=Next(node);
end;
end;
procedure TsrBufferList.ApplyBufferType;
label
_storage;
var
pConfig:PsrConfig;
node:TsrBuffer;
fchain_write:DWORD;
begin
pConfig:=FEmit.GetConfig;
node:=FindUserDataBuf;
if (node<>nil) and
(FPushConstant=nil) then
if (node.bType=btStorageBuffer) and
(node.chain_write=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 node.pLayout.IsGlobalDataShare then
begin
//global buffer
goto _storage;
//
end else
if node.pLayout.IsLocalDataShare then
begin
//Workgroup? (btWorkgroup) (btPrivate)
if (FEmit.GetExecutionModel=ExecutionModel.GLCompute) then
begin
node.bType :=btWorkgroup;
node.FStorage:=StorageClass.Workgroup;
end else
begin
node.bType :=btPrivate;
node.FStorage:=StorageClass.Private_;
end;
//
end else
if (not pConfig^.UseOnlyUserdataPushConst) and
(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
begin
_storage: //
if pConfig^.CanUseStorageBufferClass then
begin
node.FStorage:=StorageClass.StorageBuffer;
end else
begin
node.FStorage:=StorageClass.Uniform;
end;
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:TsrBuffer;offset:PtrUint);
var
P:Pointer;
begin
P:=node.pLayout.GetData;
offset:=AlignShift(P,offset);
node.align_offset:=offset;
node.ShiftOffset(offset);
end;
procedure TsrBufferList.AlignOffset;
var
pConfig:PsrConfig;
node:TsrBuffer;
begin
pConfig:=FEmit.GetConfig;
node:=First;
While (node<>nil) do
begin
if node.IsUsed then //Dont use is_export_used in this stage
if not node.pLayout.IsLocalDataShare then
if not node.pLayout.IsGlobalDataShare 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:TsrField);
var
pDecorateList:TsrDecorateList;
node:TsrField;
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:TsrDecorateList;
pHeaderList :TsrHeaderList;
Config :PsrConfig;
node:TsrBuffer;
begin
EnumAllField(@OnAllocTypeBinding);
//
pDecorateList:=FEmit.GetDecorateList;
pHeaderList :=FEmit.GetHeaderList;
Config :=FEmit.GetConfig;
//
node:=First;
While (node<>nil) do
begin
if node.is_export_used then
begin
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;
//
if (node.bType=btWorkgroup) then
begin
if Config^.IsSpv14 then
begin
pHeaderList.SPV_KHR_workgroup_memory_explicit_layout;
end;
end;
end; //is_export_used
//
node:=Next(node);
end;
end;
procedure TsrBufferList.AllocName;
var
FDebugInfo:TsrDebugInfoList;
node:TsrBuffer;
begin
FDebugInfo:=FEmit.GetDebugInfoList;
node:=First;
While (node<>nil) do
begin
if node.IsUsed and (node.FTop.vType<>nil) then
begin
FDebugInfo.OpName(node.FTop.vType,node.GetStructName);
end;
node:=Next(node);
end;
end;
end.