fpPS4/vulkan/vImageManager.pas
red-prig fe489be531 +
2022-10-21 20:23:51 +03:00

706 lines
16 KiB
ObjectPascal

unit vImageManager;
{$mode objfpc}{$H+}
interface
uses
SysUtils,
RWLock,
g23tree,
//sys_types,
Vulkan,
vDevice,
vMemory,
vImage,
vCmdBuffer,
vImageTiling;
type
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;
FUsage:TVkFlags;
//
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:TVkFlags;
//
lock:TRWLock;
FViews:TvImageView2Set;
//
Barrier:TvImageBarrier;
//
//FHostImage:TvHostImage2;
//
Fdevc:TvPointer;
//
FRefs:ptruint;
FDeps:TObjectSetLock;
//
submit_id:ptruint;
hash:dword;
//
data_usage:Byte;
Constructor Create;
Destructor Destroy; override;
function GetImageInfo:TVkImageCreateInfo; override;
Function GetSubresRange:TVkImageSubresourceRange;
Function GetSubresLayer:TVkImageSubresourceLayers;
function FetchView(cmd:TvCustomCmdBuffer;var F:TvImageViewKey):TvImageView2;
function FetchView(cmd:TvCustomCmdBuffer):TvImageView2;
//function FetchHostImage(cmd:TvCustomCmdBuffer;usage:TVkFlags):TvHostImage2;
procedure PushBarrier(cmd:TvCustomCmdBuffer;
dstAccessMask:TVkAccessFlags;
newImageLayout:TVkImageLayout;
dstStageMask:TVkPipelineStageFlags);
Procedure Acquire(Sender:TObject);
procedure Release(Sender:TObject);
end;
function FetchImage(cmd:TvCustomCmdBuffer;var F:TvImageKey;usage:TVkFlags;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
type
TvImageKeyCompare=object
function c(a,b:PvImageKey):Integer; static;
end;
_TvImage2Set=specialize T23treeSet<PvImageKey,TvImageKeyCompare>;
TvImage2Set=object(_TvImage2Set)
lock:TRWLock;
Procedure Init;
Procedure Lock_wr;
Procedure Unlock;
end;
var
FImage2Set:TvImage2Set;
Procedure TvImage2Set.Init;
begin
rwlock_init(lock);
end;
Procedure TvImage2Set.Lock_wr;
begin
rwlock_wrlock(lock);
end;
Procedure TvImage2Set.Unlock;
begin
rwlock_unlock(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.cmdbuf,
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;
rwlock_init(lock);
Barrier.Init;
end;
Destructor TvImage2.Destroy;
var
i:TvImageView2Set.Iterator;
t:TvImageView2;
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;
MemManager.Free(Fdevc);
inherited;
end;
function TvImage2.GetImageInfo:TVkImageCreateInfo;
begin
Result:=Default(TVkImageCreateInfo);
Result.sType :=VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
Result.imageType :=TVkImageType(key.params.itype);
Result.format :=key.cformat;
Result.extent.Create(key.params.extend.width,key.params.extend.height,key.params.extend.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 :=FUsage;
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;var F:TvImageViewKey):TvImageView2;
var
i:TvImageView2Set.Iterator;
t:TvImageView2;
cinfo:TVkImageViewCreateInfo;
FView:TVkImageView;
r:TVkResult;
begin
Result:=nil;
if (Self=nil) then Exit;
if (FHandle=VK_NULL_HANDLE) then Exit;
rwlock_wrlock(lock);
t:=nil;
i:=FViews.find(@F);
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 :=key.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,FUsage);
FView:=VK_NULL_HANDLE;
r:=vkCreateImageView(Device.FHandle,@cinfo,nil,@FView);
if (r<>VK_SUCCESS) then
begin
rwlock_unlock(lock);
Writeln(StdErr,'vkCreateImageView:',r);
Exit;
end;
t:=TvImageView2.Create;
t.FHandle:=FView;
t.Parent :=Self;
t.key :=F;
t.Acquire;
FViews.Insert(@t.key);
end;
if (cmd<>nil) and (t<>nil) then
begin
if cmd.AddDependence(@t.Release) then
begin
t.Acquire;
end;
end;
rwlock_unlock(lock);
Result:=t;
end;
function TvImage2.FetchView(cmd:TvCustomCmdBuffer):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;
Result:=FetchView(cmd,F);
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;
rwlock_wrlock(lock);
if Barrier.Push(cmd.cmdbuf,
FHandle,
GetSubresRange,
dstAccessMask,
newImageLayout,
dstStageMask) then
begin
Inc(cmd.cmd_count);
end;
rwlock_unlock(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;
}
Procedure TvImage2.Acquire(Sender:TObject);
begin
System.InterlockedIncrement(Pointer(FRefs));
if (Sender<>nil) then
begin
FDeps.Insert(Sender);
end;
end;
procedure TvImage2.Release(Sender:TObject);
begin
if (Sender<>nil) then
begin
FDeps.delete(Sender);
end;
if System.InterlockedDecrement(Pointer(FRefs))=nil then
begin
Free;
end;
end;
function _Find(var 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(var F:TvImageKey;usage:TVkFlags):TvImage2;
var
t:TvImage2;
begin
Result:=nil;
t:=_Find(F);
if (t<>nil) then
begin
if ((t.FUsage and usage)<>usage) then
begin
Write('Current usage:');
print_img_usage(t.FUsage);
Writeln;
Write('Need usage:');
print_img_usage(usage);
Writeln;
Assert(false,'TODO');
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
t.Fdevc:=MemManager.Alloc(
t.GetRequirements,
ord(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
);
t.BindMem(t.Fdevc);
t.Acquire(nil);
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;var F:TvImageKey;usage:TVkFlags;data_usage:Byte):TvImage2;
begin
FImage2Set.Lock_wr;
Result:=_FetchImage(F,usage);
if (cmd<>nil) and (Result<>nil) then
begin
if cmd.AddDependence(@Result.Release) then
begin
Result.Acquire(cmd);
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;
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;
end;
initialization
FImage2Set.Init;
end.