FPPS4/vulkan/vImageManager.pas

772 lines
17 KiB
Plaintext

unit vImageManager;
{$mode objfpc}{$H+}
interface
uses
SysUtils,
g23tree,
//sys_types,
Vulkan,
vDevice,
vDependence,
vMemory,
vImage,
vCmdBuffer{,
vImageTiling};
{
image_usage -> attachment,sampled,storage
read_mode -> not_need,started,keep,changed
write_back -> not_need,keep,started,finished
cmd R/W -> cmd RO
|
v
cmd R/W -> cmd RO
|
v
}
type
t_image_usage=(iu_attachment,iu_sampled,iu_storage);
s_image_usage=set of t_image_usage;
TvImageView2Compare=object
function c(a,b:PvImageViewKey):Integer; static;
end;
TvImage2=class;
TvImageView2=class(TvImageView)
Parent:TvImage2;
key:TvImageViewKey;
//
Barrier:TvImageBarrier;
//
//Constructor Create;
procedure PushBarrier(cmd:TvCustomCmdBuffer;
dstAccessMask:TVkAccessFlags;
newImageLayout:TVkImageLayout;
dstStageMask:TVkPipelineStageFlags);
procedure Release(Sender:TObject);
Function GetSubresRange:TVkImageSubresourceRange;
Function GetSubresLayer:TVkImageSubresourceLayers;
end;
TvImageView2Set=specialize T23treeSet<PvImageViewKey,TvImageView2Compare>;
{
TvHostImage2=class(TvCustomImage)
Parent:TvImage2;
//
Barrier:TvImageBarrier;
//
Constructor Create;
function GetImageInfo:TVkImageCreateInfo; override;
procedure PushBarrier(cmd:TvCustomCmdBuffer;
dstAccessMask:TVkAccessFlags;
newImageLayout:TVkImageLayout;
dstStageMask:TVkPipelineStageFlags);
end;
}
TvImage2=class(TvCustomImage)
key:TvImageKey;
//
FUsage:s_image_usage;
//
lock:Pointer;
FViews:TvImageView2Set;
//
Barrier:TvImageBarrier;
//
FLastCmd:TvCustomCmdBuffer;
FDeps:TObjectSetLock;
//
submit_id:ptruint;
hash:qword;
//
data_usage:Byte;
Constructor Create;
Destructor Destroy; override;
function GetImageInfo:TVkImageCreateInfo; override;
Function GetSubresRange:TVkImageSubresourceRange;
Function GetSubresLayer:TVkImageSubresourceLayers;
function FetchView(cmd:TvCustomCmdBuffer;const F:TvImageViewKey;usage:TVkFlags):TvImageView2;
function FetchView(cmd:TvCustomCmdBuffer;const F:TvImageViewKey;usage:t_image_usage):TvImageView2;
function FetchView(cmd:TvCustomCmdBuffer;usage:t_image_usage):TvImageView2;
//function FetchHostImage(cmd:TvCustomCmdBuffer;usage:TVkFlags):TvHostImage2;
procedure PushBarrier(cmd:TvCustomCmdBuffer;
dstAccessMask:TVkAccessFlags;
newImageLayout:TVkImageLayout;
dstStageMask:TVkPipelineStageFlags);
function Acquire(Sender:TObject):Boolean;
procedure Release(Sender:TObject);
end;
function FetchImage(cmd:TvCustomCmdBuffer;const F:TvImageKey;usage:t_image_usage;data_usage:Byte):TvImage2;
function FindImage(cmd:TvCustomCmdBuffer;Addr:Pointer;cformat:TVkFormat):TvImage2;
const
img_ext:TVkExternalMemoryImageCreateInfo=(
sType:VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
pNext:nil;
handleTypes:ord(VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT);
);
var
IMAGE_TEST_HACK:Boolean=False;
IMAGE_LOAD_HACK:Boolean=False;
implementation
uses
kern_rwlock;
type
TvImageKeyCompare=object
function c(a,b:PvImageKey):Integer; static;
end;
_TvImage2Set=specialize T23treeSet<PvImageKey,TvImageKeyCompare>;
TvImage2Set=object(_TvImage2Set)
lock:Pointer;
Procedure Lock_wr;
Procedure Unlock_wr;
end;
var
FImage2Set:TvImage2Set;
Procedure TvImage2Set.Lock_wr;
begin
rw_wlock(lock);
end;
Procedure TvImage2Set.Unlock_wr;
begin
rw_wunlock(lock);
end;
function TvImageKeyCompare.c(a,b:PvImageKey):Integer;
begin
//1 Addr
Result:=Integer(a^.Addr>b^.Addr)-Integer(a^.Addr<b^.Addr);
if (Result<>0) then Exit;
//2 cformat
Result:=Integer(a^.cformat>b^.cformat)-Integer(a^.cformat<b^.cformat);
if (Result<>0) then Exit;
//3 params
Result:=CompareByte(a^.params,b^.params,SizeOf(TvImageKey.params));
end;
function TvImageView2Compare.c(a,b:PvImageViewKey):Integer;
begin
Result:=CompareByte(a^,b^,SizeOf(TvImageViewKey));
end;
{
Constructor TvImageView2.Create;
begin
inherited;
Barrier.Init;
end;
}
procedure TvImageView2.PushBarrier(cmd:TvCustomCmdBuffer;
dstAccessMask:TVkAccessFlags;
newImageLayout:TVkImageLayout;
dstStageMask:TVkPipelineStageFlags);
begin
if (Parent=nil) then Exit;
Parent.PushBarrier(cmd,dstAccessMask,newImageLayout,dstStageMask);
if (cmd=nil) then Exit;
if (not cmd.BeginCmdBuffer) then Exit;
if Barrier.Push(cmd.FCmdbuf,
Parent.FHandle,
GetSubresRange,
dstAccessMask,
newImageLayout,
dstStageMask) then
begin
Inc(cmd.cmd_count);
end;
end;
procedure TvImageView2.Release(Sender:TObject);
begin
inherited Release;
end;
Function TvImageView2.GetSubresRange:TVkImageSubresourceRange;
begin
Result:=Default(TVkImageSubresourceRange);
Result.aspectMask :=GetAspectMaskByFormat(key.cformat);
Result.baseMipLevel :=key.base_level;
Result.levelCount :=key.last_level-key.base_level+1;
Result.baseArrayLayer:=key.base_array;
Result.layerCount :=key.last_array-key.base_array+1;
end;
Function TvImageView2.GetSubresLayer:TVkImageSubresourceLayers;
begin
Result:=Default(TVkImageSubresourceLayers);
Result.aspectMask :=GetAspectMaskByFormat(key.cformat);
Result.mipLevel :=key.base_level;
Result.baseArrayLayer:=key.base_array;
Result.layerCount :=key.last_array-key.base_array+1;
end;
Constructor TvImage2.Create;
begin
inherited;
Barrier.Init;
end;
Destructor TvImage2.Destroy;
var
i:TvImageView2Set.Iterator;
t:TvImageView2;
Fdevc:TvPointer;
begin
i:=FViews.cbegin;
While (i.Item<>nil) do
begin
t:=TvImageView2(ptruint(i.Item^)-ptruint(@TvImageView2(nil).key));
t.Release(nil);
i.Next;
end;
FViews.Free;
Fdevc:=FBind;
FBind:=Default(TvPointer);
MemManager.Free(Fdevc);
inherited;
end;
function TvImage2.GetImageInfo:TVkImageCreateInfo;
begin
Result:=Default(TVkImageCreateInfo);
Result.sType :=VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
Result.flags :=GET_VK_IMAGE_CREATE_DEFAULT(key.cformat);
Result.imageType :=TVkImageType(key.params.itype);
Result.format :=key.cformat;
Result.extent.Create(key.params.width,key.params.height,key.params.depth);
Result.mipLevels :=key.params.mipLevels;
Result.arrayLayers :=key.params.arrayLayers;
Result.samples :=TVkSampleCountFlagBits(key.params.samples);
Result.tiling :=VK_IMAGE_TILING_OPTIMAL;
Result.usage :=GET_VK_IMAGE_USAGE_DEFAULT(key.cformat);
Result.initialLayout:=VK_IMAGE_LAYOUT_UNDEFINED;
end;
{
Constructor TvHostImage2.Create;
begin
inherited;
Barrier.Init;
end;
function TvHostImage2.GetImageInfo:TVkImageCreateInfo;
var
bpp,size:qword;
begin
Result:=Parent.GetImageInfo;
Result.tiling:=VK_IMAGE_TILING_LINEAR;
Result.usage :=FUsage;
Result.flags :=ord(VK_IMAGE_CREATE_ALIAS_BIT);
if (Parent.key.params.tiling_idx=8) then
begin
size:=Result.extent.width;
bpp:=getFormatSize(Result.format);
if IsTexelFormat(Result.format) then
begin
size:=(size+3) div 4;
end;
size:=size*bpp;
size:=AlignUp(size,128);
size:=size div bpp;
if IsTexelFormat(Result.format) then
begin
size:=size*4;
end;
Result.extent.width:=size;
end;
end;
}
Function TvImage2.GetSubresRange:TVkImageSubresourceRange;
begin
Result:=Default(TVkImageSubresourceRange);
Result.aspectMask:=GetAspectMaskByFormat(key.cformat);
Result.levelCount:=key.params.mipLevels;
Result.layerCount:=key.params.arrayLayers;
end;
Function TvImage2.GetSubresLayer:TVkImageSubresourceLayers;
begin
Result:=Default(TVkImageSubresourceLayers);
Result.aspectMask :=GetAspectMaskByFormat(key.cformat);
Result.mipLevel :=0;
Result.baseArrayLayer:=0;
Result.layerCount :=key.params.arrayLayers;
end;
function TvImage2.FetchView(cmd:TvCustomCmdBuffer;const F:TvImageViewKey;usage:TVkFlags):TvImageView2;
var
key2:TvImageViewKey;
i:TvImageView2Set.Iterator;
t:TvImageView2;
cinfo:TVkImageViewCreateInfo;
uinfo:TVkImageViewUsageCreateInfo;
FView:TVkImageView;
r:TVkResult;
begin
Result:=nil;
if (Self=nil) then Exit;
if (FHandle=VK_NULL_HANDLE) then Exit;
if (usage=0) then
begin
usage:=GET_VK_IMAGE_USAGE_DEFAULT(F.cformat);
end;
key2:=F;
key2.fusage:=usage;
rw_wlock(lock);
t:=nil;
i:=FViews.find(@key2);
if (i.Item<>nil) then
begin
t:=TvImageView2(ptruint(i.Item^)-ptruint(@TvImageView2(nil).key));
end else
begin
cinfo:=Default(TVkImageViewCreateInfo);
cinfo.sType :=VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
cinfo.image :=FHandle;
cinfo.viewType :=TVkImageViewType(F.vtype);
cinfo.format :=F.cformat;
cinfo.components.r:=TVkComponentSwizzle(F.dstSel.r);
cinfo.components.g:=TVkComponentSwizzle(F.dstSel.g);
cinfo.components.b:=TVkComponentSwizzle(F.dstSel.b);
cinfo.components.a:=TVkComponentSwizzle(F.dstSel.a);
cinfo.subresourceRange.aspectMask :=GetAspectMaskByFormat(F.cformat);
cinfo.subresourceRange.baseMipLevel :=F.base_level;
cinfo.subresourceRange.levelCount :=F.last_level-F.base_level+1;
cinfo.subresourceRange.baseArrayLayer:=F.base_array;
cinfo.subresourceRange.layerCount :=F.last_array-F.base_array+1;
cinfo.format:=vkFixFormatSupport(cinfo.format,VK_IMAGE_TILING_OPTIMAL,usage);
uinfo:=Default(TVkImageViewUsageCreateInfo);
uinfo.sType:=VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
uinfo.usage:=usage;
cinfo.pNext:=@uinfo;
FView:=VK_NULL_HANDLE;
r:=vkCreateImageView(Device.FHandle,@cinfo,nil,@FView);
if (r<>VK_SUCCESS) then
begin
rw_wunlock(lock);
Writeln(StdErr,'vkCreateImageView:',r);
Exit;
end;
t:=TvImageView2.Create;
t.FHandle:=FView;
t.Parent :=Self;
t.key :=key2;
t.Acquire; //map ref
FViews.Insert(@t.key);
end;
if (cmd<>nil) and (t<>nil) then
begin
if cmd.AddDependence(@t.Release) then
begin
t.Acquire;
end;
end;
rw_wunlock(lock);
Result:=t;
end;
function TvImage2.FetchView(cmd:TvCustomCmdBuffer;const F:TvImageViewKey;usage:t_image_usage):TvImageView2;
var
tmp:TvImageViewKey;
begin
case usage of
iu_storage:
begin
tmp:=F;
tmp.cformat:=GET_VK_FORMAT_STORAGE(F.cformat);
Result:=FetchView(cmd,tmp,ord(VK_IMAGE_USAGE_STORAGE_BIT));
end;
else
Result:=FetchView(cmd,F,0);
end;
end;
function TvImage2.FetchView(cmd:TvCustomCmdBuffer;usage:t_image_usage):TvImageView2;
var
F:TvImageViewKey;
begin
if (Self=nil) then Exit;
F:=Default(TvImageViewKey);
F.cformat:=key.cformat;
Case TVkImageType(key.params.itype) of
VK_IMAGE_TYPE_1D:
begin
if (key.params.arrayLayers>1) then
F.vtype:=ord(VK_IMAGE_VIEW_TYPE_1D_ARRAY)
else
F.vtype:=ord(VK_IMAGE_VIEW_TYPE_1D);
end;
VK_IMAGE_TYPE_2D:
begin
if (key.params.arrayLayers>1) then
F.vtype:=ord(VK_IMAGE_VIEW_TYPE_2D_ARRAY)
else
F.vtype:=ord(VK_IMAGE_VIEW_TYPE_2D);
//VK_IMAGE_VIEW_TYPE_CUBE
//VK_IMAGE_VIEW_TYPE_CUBE_ARRAY
end;
VK_IMAGE_TYPE_3D:F.vtype:=ord(VK_IMAGE_VIEW_TYPE_3D);
end;
F.last_level:=key.params.mipLevels -1;
F.last_array:=key.params.arrayLayers-1;
case usage of
iu_storage:
begin
F.cformat:=GET_VK_FORMAT_STORAGE(F.cformat);
Result:=FetchView(cmd,F,ord(VK_IMAGE_USAGE_STORAGE_BIT));
end;
else
Result:=FetchView(cmd,F,0);
end;
end;
{
function TvImage2.FetchHostImage(cmd:TvCustomCmdBuffer;usage:TVkFlags):TvHostImage2;
var
t:TvHostImage2;
Fhost:TvPointer;
begin
Result:=nil;
t:=FHostImage;
if (t<>nil) then
begin
if ((t.FUsage and usage)<>usage) then
begin
Assert(false,'TODO');
end;
Exit(t);
end;
t:=TvHostImage2.Create;
t.Parent:=Self;
t.FUsage:=usage;
if not t.Compile(@img_ext) then
begin
t.Free;
Exit;
end;
if TryGetHostPointerByAddr(key.Addr,Fhost) then
begin
if (t.BindMem(Fhost)<>VK_SUCCESS) then
begin
t.Free;
Exit;
end;
end else
begin
t.Free;
Exit;
end;
FHostImage:=t;
Result:=t;
if (cmd<>nil) and (Self<>nil) then
begin
if cmd.AddDependence(@Self.Release) then
begin
Self.Acquire(cmd);
end;
end;
end;
}
procedure TvImage2.PushBarrier(cmd:TvCustomCmdBuffer;
dstAccessMask:TVkAccessFlags;
newImageLayout:TVkImageLayout;
dstStageMask:TVkPipelineStageFlags);
begin
if (cmd=nil) then Exit;
if (not cmd.BeginCmdBuffer) then Exit;
rw_wlock(lock);
if Barrier.Push(cmd.FCmdbuf,
FHandle,
GetSubresRange,
dstAccessMask,
newImageLayout,
dstStageMask) then
begin
Inc(cmd.cmd_count);
end;
rw_wunlock(lock);
end;
{
procedure TvHostImage2.PushBarrier(cmd:TvCustomCmdBuffer;
dstAccessMask:TVkAccessFlags;
newImageLayout:TVkImageLayout;
dstStageMask:TVkPipelineStageFlags);
begin
if (cmd=nil) then Exit;
if (not cmd.BeginCmdBuffer) then Exit;
if Barrier.Push(cmd.cmdbuf,
FHandle,
Parent.GetSubresRange,
dstAccessMask,
newImageLayout,
dstStageMask) then
begin
Inc(cmd.cmd_count);
end;
end;
}
function TvImage2.Acquire(Sender:TObject):Boolean;
begin
Result:=inherited Acquire;
if Result and (Sender<>nil) then
begin
if FDeps.Insert(Sender) then
begin
if Sender.InheritsFrom(TvCustomCmdBuffer) then
begin
FLastCmd:=TvCustomCmdBuffer(Sender);
end;
end;
end;
end;
procedure TvImage2.Release(Sender:TObject);
begin
if (Sender<>nil) then
begin
FDeps.delete(Sender);
if (FLastCmd=Sender) then
begin
FLastCmd:=nil;
end;
end;
inherited Release;
end;
function _Find(const F:TvImageKey):TvImage2;
var
i:TvImage2Set.Iterator;
begin
Result:=nil;
i:=FImage2Set.find(@F);
if (i.Item<>nil) then
begin
Result:=TvImage2(ptruint(i.Item^)-ptruint(@TvImage2(nil).key));
end;
end;
procedure print_img_usage(usage:TVkFlags);
begin
if (usage and ord(VK_IMAGE_USAGE_TRANSFER_SRC_BIT ))<>0 then Write(' TRANSFER_SRC');
if (usage and ord(VK_IMAGE_USAGE_TRANSFER_DST_BIT ))<>0 then Write(' TRANSFER_DST');
if (usage and ord(VK_IMAGE_USAGE_SAMPLED_BIT ))<>0 then Write(' SAMPLED');
if (usage and ord(VK_IMAGE_USAGE_STORAGE_BIT ))<>0 then Write(' STORAGE');
if (usage and ord(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ))<>0 then Write(' COLOR_ATTACHMENT');
if (usage and ord(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT))<>0 then Write(' DEPTH_STENCIL_ATTACHMENT');
if (usage and ord(VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT ))<>0 then Write(' TRANSIENT_ATTACHMENT');
if (usage and ord(VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT ))<>0 then Write(' INPUT_ATTACHMENT');
end;
function _FetchImage(const F:TvImageKey;usage:t_image_usage):TvImage2;
label
_repeat;
var
t:TvImage2;
Fdevc:TvPointer;
begin
Result:=nil;
_repeat:
t:=_Find(F);
if (t<>nil) then
begin
if t.Acquire(nil) then
begin
t.FUsage:=t.FUsage+[usage];
end else
begin
//mem is deleted, free img
FImage2Set.delete(@t.key);
FreeAndNil(t);
goto _repeat;
end;
end else
begin
t:=TvImage2.Create;
t.key :=F;
t.FUsage:=[usage];
if not t.Compile(nil) then
begin
FreeAndNil(t);
end else
begin
Fdevc:=MemManager.Alloc(
t.GetRequirements,
ord(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
);
t.BindMem(Fdevc); // <-Acquire
FImage2Set.Insert(@t.key);
end;
end;
Result:=t;
end;
function _FindImage(Addr:Pointer;cformat:TVkFormat):TvImage2;
var
i:TvImage2Set.Iterator;
t:TvImage2;
F:TvImageKey;
begin
F:=Default(TvImageKey);
F.Addr:=Addr;
F.cformat:=cformat;
t:=nil;
i:=FImage2Set.find_be(@F);
if (i.Item<>nil) then
begin
t:=TvImage2(ptruint(i.Item^)-ptruint(@TvImage2(nil).key));
if (t.key.Addr<>Addr) then t:=nil;
end;
Result:=t;
end;
function FetchImage(cmd:TvCustomCmdBuffer;const F:TvImageKey;usage:t_image_usage;data_usage:Byte):TvImage2;
begin
FImage2Set.Lock_wr;
Result:=_FetchImage(F,usage); // <-Acquire
if (cmd<>nil) and (Result<>nil) then
begin
if cmd.AddDependence(@Result.Release) then
begin
Result.Acquire(cmd);
Result.Release(nil); // <-_FetchImage
end;
if not cmd.IsRenderPass then
begin
if ((Result.data_usage and TM_READ)<>0) and (Result.submit_id<>cmd.submit_id) then
begin
//hash test
{
if not IMAGE_LOAD_HACK then
begin
if IMAGE_TEST_HACK then
begin
Result.data_usage:=Result.data_usage and (not TM_READ);
end else
if CheckFromBuffer(Result) then
begin
Result.data_usage:=Result.data_usage and (not TM_READ);
end;
end;
}
end;
if ((Result.data_usage and TM_READ)=0) and ((data_usage and TM_READ)<>0) then
begin
Result.submit_id:=cmd.submit_id;
Result.data_usage:=Result.data_usage or TM_READ;
//LoadFromBuffer(cmd,Result);
end;
end;
Result.data_usage:=Result.data_usage or (data_usage and TM_WRITE);
end;
FImage2Set.Unlock_wr;
end;
function FindImage(cmd:TvCustomCmdBuffer;Addr:Pointer;cformat:TVkFormat):TvImage2;
begin
FImage2Set.Lock_wr;
Result:=_FindImage(Addr,cformat);
if (cmd<>nil) and (Result<>nil) then
begin
if cmd.AddDependence(@Result.Release) then
begin
Result.Acquire(cmd);
end;
end;
FImage2Set.Unlock_wr;
end;
end.