unit vDescriptorSet; {$mode ObjFPC}{$H+} interface uses sysutils, g_node_splay, Vulkan, vDevice, vPipeline, vDependence; type PvDescriptorCache=^TvDescriptorCache; TvDescriptorCache=packed object // layout:TvPipelineLayout; //Must be the first element in memory // p_write:PVkWriteDescriptorSet; // p_count_all:Byte; // set bind p_count:array[0..6] of Byte; p_binds:array[0..6] of PVkWriteDescriptorSet; P_bmaxd:array[0..6] of PByte; // p_change_any:Boolean; p_change:array[0..6] of Boolean; // pLeft :PvDescriptorCache; pRight:PvDescriptorCache; // function c(a,b:PvDescriptorCache):Integer; static; procedure ClearAllChange; procedure SetAllChange; procedure BindBuffer (aSet,aBind:TVkUInt32;dtype:TVkDescriptorType;buffer:TVkBuffer;offset,range:TVkDeviceSize); procedure BindImage (aSet,aBind:TVkUInt32;dtype:TVkDescriptorType;img:TVkImageView;aLayout:TVkImageLayout); procedure BindImages (aSet,aBind,aElem,aCount:TVkUInt32;dtype:TVkDescriptorType;img:PVkImageView;aLayout:TVkImageLayout); procedure BindSampler(aSet,aBind:TVkUInt32;smp:TVkSampler); end; TvDescriptorCacheSet=specialize TNodeSplay; TvDescriptorInterface=object FHandle:PvDescriptorCache; Procedure BindBuffer (aSet,aBind:TVkUInt32;buffer:TVkBuffer;offset,range:TVkDeviceSize); Procedure BindUniform (aSet,aBind:TVkUInt32;buffer:TVkBuffer;offset,range:TVkDeviceSize); Procedure BindStorage (aSet,aBind:TVkUInt32;img:TVkImageView;Layout:TVkImageLayout); Procedure BindStorages(aSet,aBind,aElem,aCount:TVkUInt32;img:PVkImageView;Layout:TVkImageLayout); Procedure BindImage (aSet,aBind:TVkUInt32;img:TVkImageView;Layout:TVkImageLayout); Procedure BindSampler (aSet,aBind:TVkUInt32;smp:TVkSampler); end; TvDescriptorSet2=object FHandle:TVkDescriptorSet; Function IsValid:Boolean; Procedure FillHandle (dwrite:PVkWriteDescriptorSet;count:Integer); Procedure BindBuffer (aBind,aElem:TVkUInt32;buffer:TVkBuffer;offset,range:TVkDeviceSize); Procedure BindUniform(aBind,aElem:TVkUInt32;buffer:TVkBuffer;offset,range:TVkDeviceSize); Procedure BindStorage(aBind,aElem:TVkUInt32;img:TVkImageView;Layout:TVkImageLayout); Procedure BindImage (aBind,aElem:TVkUInt32;img:TVkImageView;Layout:TVkImageLayout); Procedure BindSampler(aBind,aElem:TVkUInt32;smp:TVkSampler); end; AvDescriptorSet2=Array of TvDescriptorSet2; TvDescriptorGroup=class(TvRefsObject) FLayout:TvPipelineLayout; FSets :AvDescriptorSet2; Procedure Bind(Cache:PvDescriptorCache); end; function AllocDescriptorCache(obj:TvDependenciesObject;layout:TvPipelineLayout):PvDescriptorCache; implementation Procedure TvDescriptorGroup.Bind(Cache:PvDescriptorCache); var i:Integer; begin if (Cache=nil) then Exit; Assert(FLayout=Cache^.layout,'bind on wrong layout'); if (Length(FSets)<>0) then For i:=0 to High(FSets) do begin FSets[i].FillHandle(Cache^.p_binds[i],Cache^.p_count[i]); end; if (Cache^.p_count_all<>0) then begin vkUpdateDescriptorSets(Device.FHandle,Cache^.p_count_all,Cache^.p_write,0,nil); end; end; // Function TvDescriptorSet2.IsValid:Boolean; begin Result:=FHandle<>VK_NULL_HANDLE; end; Procedure TvDescriptorSet2.FillHandle(dwrite:PVkWriteDescriptorSet;count:Integer); var i:Integer; begin if (dwrite=nil) or (count=0) then Exit; For i:=0 to count-1 do begin dwrite[i].dstSet:=FHandle; end; end; Procedure TvDescriptorSet2.BindBuffer(aBind,aElem:TVkUInt32;buffer:TVkBuffer;offset,range:TVkDeviceSize); var dwrite:TVkWriteDescriptorSet; buf:TVkDescriptorBufferInfo; begin buf:=Default(TVkDescriptorBufferInfo); buf.buffer:=buffer; buf.offset:=offset; buf.range :=range ; dwrite:=Default(TVkWriteDescriptorSet); dwrite.sType :=VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; dwrite.dstSet :=FHandle; dwrite.dstBinding :=aBind; dwrite.dstArrayElement:=aElem; dwrite.descriptorType :=VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; dwrite.descriptorCount:=1; dwrite.pBufferInfo :=@buf; vkUpdateDescriptorSets(Device.FHandle,1,@dwrite,0,nil); end; Procedure TvDescriptorSet2.BindUniform(aBind,aElem:TVkUInt32;buffer:TVkBuffer;offset,range:TVkDeviceSize); var dwrite:TVkWriteDescriptorSet; buf:TVkDescriptorBufferInfo; begin buf:=Default(TVkDescriptorBufferInfo); buf.buffer:=buffer; buf.offset:=offset; buf.range :=range ; dwrite:=Default(TVkWriteDescriptorSet); dwrite.sType :=VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; dwrite.dstSet :=FHandle; dwrite.dstBinding :=aBind; dwrite.dstArrayElement:=aElem; dwrite.descriptorType :=VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; dwrite.descriptorCount:=1; dwrite.pBufferInfo :=@buf; vkUpdateDescriptorSets(Device.FHandle,1,@dwrite,0,nil); end; Procedure TvDescriptorSet2.BindStorage(aBind,aElem:TVkUInt32;img:TVkImageView;Layout:TVkImageLayout); var dwrite:TVkWriteDescriptorSet; dimg:TVkDescriptorImageInfo; begin dimg:=Default(TVkDescriptorImageInfo); dimg.imageView :=img; dimg.imageLayout:=Layout; dwrite:=Default(TVkWriteDescriptorSet); dwrite.sType :=VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; dwrite.dstSet :=FHandle; dwrite.dstBinding :=aBind; dwrite.dstArrayElement:=aElem; dwrite.descriptorType :=VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; dwrite.descriptorCount:=1; dwrite.pImageInfo :=@dimg; vkUpdateDescriptorSets(Device.FHandle,1,@dwrite,0,nil); end; Procedure TvDescriptorSet2.BindImage(aBind,aElem:TVkUInt32;img:TVkImageView;Layout:TVkImageLayout); var dwrite:TVkWriteDescriptorSet; dimg:TVkDescriptorImageInfo; begin dimg:=Default(TVkDescriptorImageInfo); dimg.imageView :=img; dimg.imageLayout:=Layout; dwrite:=Default(TVkWriteDescriptorSet); dwrite.sType :=VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; dwrite.dstSet :=FHandle; dwrite.dstBinding :=aBind; dwrite.dstArrayElement:=aElem; dwrite.descriptorType :=VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; dwrite.descriptorCount:=1; dwrite.pImageInfo :=@dimg; vkUpdateDescriptorSets(Device.FHandle,1,@dwrite,0,nil); end; Procedure TvDescriptorSet2.BindSampler(aBind,aElem:TVkUInt32;smp:TVkSampler); var dwrite:TVkWriteDescriptorSet; dimg:TVkDescriptorImageInfo; begin dimg:=Default(TVkDescriptorImageInfo); dimg.sampler:=smp; dwrite:=Default(TVkWriteDescriptorSet); dwrite.sType :=VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; dwrite.dstSet :=FHandle; dwrite.dstBinding :=aBind; dwrite.dstArrayElement:=aElem; dwrite.descriptorType :=VK_DESCRIPTOR_TYPE_SAMPLER; dwrite.descriptorCount:=1; dwrite.pImageInfo :=@dimg; vkUpdateDescriptorSets(Device.FHandle,1,@dwrite,0,nil); end; // Procedure TvDescriptorInterface.BindBuffer(aSet,aBind:TVkUInt32;buffer:TVkBuffer;offset,range:TVkDeviceSize); begin if (FHandle=nil) then Exit; FHandle^.BindBuffer(aSet,aBind,VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,buffer,offset,range); end; Procedure TvDescriptorInterface.BindUniform(aSet,aBind:TVkUInt32;buffer:TVkBuffer;offset,range:TVkDeviceSize); begin if (FHandle=nil) then Exit; FHandle^.BindBuffer(aSet,aBind,VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,buffer,offset,range); end; Procedure TvDescriptorInterface.BindStorage(aSet,aBind:TVkUInt32;img:TVkImageView;Layout:TVkImageLayout); begin if (FHandle=nil) then Exit; FHandle^.BindImage(aSet,aBind,VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,img,Layout); end; Procedure TvDescriptorInterface.BindStorages(aSet,aBind,aElem,aCount:TVkUInt32;img:PVkImageView;Layout:TVkImageLayout); begin if (FHandle=nil) then Exit; FHandle^.BindImages(aSet,aBind,aElem,aCount,VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,img,Layout); end; Procedure TvDescriptorInterface.BindImage(aSet,aBind:TVkUInt32;img:TVkImageView;Layout:TVkImageLayout); begin if (FHandle=nil) then Exit; FHandle^.BindImage(aSet,aBind,VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,img,Layout); end; Procedure TvDescriptorInterface.BindSampler(aSet,aBind:TVkUInt32;smp:TVkSampler); begin if (FHandle=nil) then Exit; FHandle^.BindSampler(aSet,aBind,smp); end; // function AllocDescriptorCache(obj:TvDependenciesObject;layout:TvPipelineLayout):PvDescriptorCache; var i,b :Integer; dwrite_count:Integer; dimg_count :Integer; dbuf_count :Integer; dmax_count :Integer; size :Integer; base :Pointer; ends :Pointer; p_write_base:PVkWriteDescriptorSet; p_write_ends:PVkWriteDescriptorSet; function AllocBase(size:Integer):Pointer; inline; begin Assert((base+size)<=ends,'AllocBase'); Result:=base; base:=base+size; end; function AllocWrite(count:Integer):PVkWriteDescriptorSet; inline; begin Assert((p_write_base+count)<=p_write_ends,'AllocWrite'); Result:=p_write_base; p_write_base:=p_write_base+count; end; begin Assert(layout<>nil,'layout not binded'); Assert(layout.FCounts[ord(VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER )]=0,'TODO'); Assert(layout.FCounts[ord(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER )]=0,'TODO'); Assert(layout.FCounts[ord(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC)]=0,'TODO'); Assert(layout.FCounts[ord(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)]=0,'TODO'); Assert(layout.FCounts[ord(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT )]=0,'TODO'); dwrite_count:=layout.FBinds; Assert(dwrite_count<=255,'dwrite_count limit'); dimg_count:= layout.FCounts[ord(VK_DESCRIPTOR_TYPE_SAMPLER)]+ layout.FCounts[ord(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)]+ layout.FCounts[ord(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)]+ layout.FCounts[ord(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)]; dbuf_count:= layout.FCounts[ord(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)]+ layout.FCounts[ord(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)]; dmax_count:=dwrite_count; size:=SizeOf(TvDescriptorCache)+ dwrite_count*SizeOf(TVkWriteDescriptorSet)+ dmax_count *SizeOf(Byte)+ dimg_count *SizeOf(TVkDescriptorImageInfo)+ dbuf_count *SizeOf(TVkDescriptorBufferInfo); base:=obj.OnAlloc(size); ends:=base+size; Result:=AllocBase(SizeOf(TvDescriptorCache)); Result^.layout:=layout; p_write_base:=AllocBase(dwrite_count*SizeOf(TVkWriteDescriptorSet)); p_write_ends:=base; Result^.p_write:=p_write_base; Result^.p_count_all:=dwrite_count; if Length(layout.key.FLayouts)<>0 then begin For i:=0 to High(layout.key.FLayouts) do With layout.key.FLayouts[i] do if (Length(key.FBinds)<>0) then begin Result^.p_count[i]:=Length(key.FBinds); Result^.p_binds[i]:=AllocWrite(Length(key.FBinds)); Result^.P_bmaxd[i]:=AllocBase (Length(key.FBinds)*SizeOf(Byte)); For b:=0 to High(key.FBinds) do with key.FBinds[b] do begin Result^.p_binds[i][binding].sType :=VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; Result^.p_binds[i][binding].dstBinding :=binding; Result^.p_binds[i][binding].descriptorCount:=1; //initial Result^.p_binds[i][binding].descriptorType :=descriptorType; Result^.P_bmaxd[i][binding]:=descriptorCount; //max case descriptorType of VK_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: begin Result^.p_binds[i][binding].pImageInfo:=AllocBase(SizeOf(TVkDescriptorImageInfo)*descriptorCount); end; VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: begin Result^.p_binds[i][binding].pBufferInfo:=AllocBase(SizeOf(TVkDescriptorBufferInfo)*descriptorCount); end; else; end; end; end; end; end; /// function TvDescriptorCache.c(a,b:PvDescriptorCache):Integer; begin Result:=Integer(Pointer(a^.layout)>Pointer(b^.layout))-Integer(Pointer(a^.layout)nil,'0x'+HexStr(p_binds[aSet])+'<>nil'); dwrite:=@p_binds[aSet][aBind]; Assert(dwrite^.descriptorType=dtype); dbuf:=dwrite^.pBufferInfo; Assert(dbuf<>nil); change:=False; change:=change or (dbuf^.buffer<>buffer); change:=change or (dbuf^.offset<>offset); change:=change or (dbuf^.range <>range ); dbuf^.buffer:=buffer; dbuf^.offset:=offset; dbuf^.range :=range ; if change then begin p_change_any:=True; p_change[aSet]:=True; end; end; procedure TvDescriptorCache.BindImage(aSet,aBind:TVkUInt32;dtype:TVkDescriptorType;img:TVkImageView;aLayout:TVkImageLayout); var dwrite:PVkWriteDescriptorSet; dimg :PVkDescriptorImageInfo; change:Boolean; begin Assert(aSet<7,IntToStr(aSet)+'<7'); Assert(aBindnil,'0x'+HexStr(p_binds[aSet])+'<>nil'); dwrite:=@p_binds[aSet][aBind]; Assert(dwrite^.descriptorType=dtype); dimg:=dwrite^.pImageInfo; Assert(dimg<>nil); change:=False; change:=change or (dimg^.imageView <>img ); change:=change or (dimg^.imageLayout<>aLayout); dimg^.imageView :=img; dimg^.imageLayout:=aLayout; if change then begin p_change_any:=True; p_change[aSet]:=True; end; end; procedure TvDescriptorCache.BindImages(aSet,aBind,aElem,aCount:TVkUInt32;dtype:TVkDescriptorType;img:PVkImageView;aLayout:TVkImageLayout); var dwrite:PVkWriteDescriptorSet; dimg :PVkDescriptorImageInfo; i :TVkUInt32; change:Boolean; begin Assert(aSet<7,IntToStr(aSet)+'<7'); Assert(aBind0,IntToStr(aCount)+'>0'); Assert(p_binds[aSet]<>nil,'0x'+HexStr(p_binds[aSet])+'<>nil'); dwrite:=@p_binds[aSet][aBind]; Assert(dwrite^.descriptorType=dtype); Assert((aElem+aCount)<=P_bmaxd[aSet][aBind]); dimg:=dwrite^.pImageInfo; Assert(dimg<>nil); change:=False; change:=change or (dwrite^.dstArrayElement<>aElem ); change:=change or (dwrite^.descriptorCount<>aCount); dwrite^.dstArrayElement:=aElem; dwrite^.descriptorCount:=aCount; For i:=0 to aCount-1 do begin change:=change or (dimg[i].imageView <>img[i] ); change:=change or (dimg[i].imageLayout<>aLayout); dimg[i].imageView :=img[i]; dimg[i].imageLayout:=aLayout; end; if change then begin p_change_any:=True; p_change[aSet]:=True; end; end; procedure TvDescriptorCache.BindSampler(aSet,aBind:TVkUInt32;smp:TVkSampler); var dwrite:PVkWriteDescriptorSet; dimg :PVkDescriptorImageInfo; change:Boolean; begin Assert(aSet<7,IntToStr(aSet)+'<7'); Assert(aBindnil,'0x'+HexStr(p_binds[aSet])+'<>nil'); dwrite:=@p_binds[aSet][aBind]; Assert(dwrite^.descriptorType=VK_DESCRIPTOR_TYPE_SAMPLER); dimg:=dwrite^.pImageInfo; Assert(dimg<>nil); change:=False; change:=change or (dimg^.sampler<>smp); dimg^.sampler:=smp; if change then begin p_change_any:=True; p_change[aSet]:=True; end; end; end.