mirror of https://github.com/red-prig/fpPS4.git
1352 lines
31 KiB
Plaintext
1352 lines
31 KiB
Plaintext
unit vImageManager;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
SysUtils,
|
|
mqueue,
|
|
g23tree,
|
|
Vulkan,
|
|
vDevice,
|
|
vDependence,
|
|
vMemory,
|
|
vImage,
|
|
vCmdBuffer,
|
|
kern_proc,
|
|
vm_map,
|
|
vm_tracking_map{,
|
|
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
|
|
TvImageView2Compare=object
|
|
function c(a,b:PvImageViewKey):Integer; static;
|
|
end;
|
|
|
|
TvImage2=class;
|
|
|
|
TvImageView2=class(TvImageView)
|
|
Parent:TvImage2;
|
|
key:TvImageViewKey;
|
|
//
|
|
Barrier:TvImageBarrier;
|
|
//
|
|
procedure PushBarrier(cmd:TvCustomCmdBuffer;
|
|
dstAccessMask:TVkAccessFlags;
|
|
newImageLayout:TVkImageLayout;
|
|
dstStageMask:TVkPipelineStageFlags);
|
|
Function GetSubresRange(cformat:TVkFormat=VK_FORMAT_UNDEFINED):TVkImageSubresourceRange;
|
|
Function GetSubresLayer(cformat:TVkFormat=VK_FORMAT_UNDEFINED):TVkImageSubresourceLayers;
|
|
end;
|
|
|
|
TvImageView2Set=specialize T23treeSet<PvImageViewKey,TvImageView2Compare>;
|
|
|
|
t_change_rate=object
|
|
state :Integer;
|
|
trigger:Integer;
|
|
planned:Integer;
|
|
procedure mark_init;
|
|
function need_read:Boolean;
|
|
end;
|
|
|
|
TvCustomImage2=class(TvCustomImage)
|
|
//
|
|
key :TvImageKey;
|
|
//
|
|
entry:TAILQ_ENTRY;
|
|
//
|
|
size:Ptruint;
|
|
tobj:p_vm_track_object;
|
|
//
|
|
change_rate:t_change_rate;
|
|
//
|
|
Parent :TvCustomImage2;
|
|
DepthOnly :TvCustomImage2;
|
|
StencilOnly:TvCustomImage2;
|
|
//
|
|
lock:Pointer;
|
|
//
|
|
Destructor Destroy; override;
|
|
procedure restore_vm_track; virtual;
|
|
procedure assign_vm_track; virtual;
|
|
procedure mark_init;
|
|
function get_change_rate:t_change_rate;
|
|
procedure apply_change_rate(r:t_change_rate);
|
|
Function IsDepthAndStencil:Boolean;
|
|
Function GetSubresRange:TVkImageSubresourceRange; virtual;
|
|
Function GetSubresLayer:TVkImageSubresourceLayers; virtual;
|
|
function FetchViewRaw(cmd:TvCustomCmdBuffer;const F:TvImageViewKey;usage:TVkFlags):TvImageView2; virtual; abstract;
|
|
function FetchView(cmd:TvCustomCmdBuffer;const F:TvImageViewKey;usage:t_image_usage):TvImageView2;
|
|
function FetchView(cmd:TvCustomCmdBuffer;usage:t_image_usage):TvImageView2;
|
|
procedure PushBarrier(cmd:TvCustomCmdBuffer;
|
|
dstAccessMask:TVkAccessFlags;
|
|
newImageLayout:TVkImageLayout;
|
|
dstStageMask:TVkPipelineStageFlags); virtual; abstract;
|
|
procedure ForceBarrier(dstAccessMask:TVkAccessFlags;
|
|
newImageLayout:TVkImageLayout;
|
|
dstStageMask:TVkPipelineStageFlags); virtual; abstract;
|
|
end;
|
|
|
|
TvChildImage2=class(TvCustomImage2)
|
|
procedure FreeHandle; override;
|
|
function FetchViewRaw(cmd:TvCustomCmdBuffer;const F:TvImageViewKey;usage:TVkFlags):TvImageView2; override;
|
|
procedure PushBarrier(cmd:TvCustomCmdBuffer;
|
|
dstAccessMask:TVkAccessFlags;
|
|
newImageLayout:TVkImageLayout;
|
|
dstStageMask:TVkPipelineStageFlags); override;
|
|
procedure ForceBarrier(dstAccessMask:TVkAccessFlags;
|
|
newImageLayout:TVkImageLayout;
|
|
dstStageMask:TVkPipelineStageFlags); override;
|
|
function Acquire(Sender:TObject):Boolean; override;
|
|
function Release(Sender:TObject):Boolean; override;
|
|
function Hold (Sender:TObject):Boolean; override;
|
|
function Drop (Sender:TObject):Boolean; override;
|
|
end;
|
|
|
|
TvImage2=class(TvCustomImage2)
|
|
//
|
|
FUsage:s_image_usage;
|
|
//
|
|
FViews:TvImageView2Set;
|
|
//
|
|
Barrier:TvImageBarrier;
|
|
//
|
|
FLastCmd:TvCustomCmdBuffer;
|
|
FDeps:TObjectSetLock;
|
|
//
|
|
submit_id:ptruint;
|
|
hash:qword;
|
|
//
|
|
Constructor Create;
|
|
Destructor Destroy; override;
|
|
function GetImageInfo:TVkImageCreateInfo; override;
|
|
function FetchViewRaw(cmd:TvCustomCmdBuffer;const F:TvImageViewKey;usage:TVkFlags):TvImageView2; override;
|
|
procedure PushBarrier(cmd:TvCustomCmdBuffer;
|
|
dstAccessMask:TVkAccessFlags;
|
|
newImageLayout:TVkImageLayout;
|
|
dstStageMask:TVkPipelineStageFlags); override;
|
|
procedure ForceBarrier(dstAccessMask:TVkAccessFlags;
|
|
newImageLayout:TVkImageLayout;
|
|
dstStageMask:TVkPipelineStageFlags); override;
|
|
function Hold (Sender:TObject):Boolean; override;
|
|
function Drop (Sender:TObject):Boolean; override;
|
|
end;
|
|
|
|
TvDepthStencilImage2=class(TvImage2)
|
|
procedure FreeHandle; override;
|
|
function Compile(ext:Pointer):Boolean; override;
|
|
procedure restore_vm_track; override;
|
|
procedure assign_vm_track; override;
|
|
Destructor Destroy; override;
|
|
end;
|
|
|
|
function FetchImage(cmd:TvCustomCmdBuffer;const F:TvImageKey;usage:s_image_usage):TvImage2;
|
|
function FindImage (cmd:TvCustomCmdBuffer;Addr:Pointer;cformat:TVkFormat):TvImage2;
|
|
|
|
Function get_image_size(const key:TvImageKey):Ptruint; external name 'tiling_get_image_size';
|
|
|
|
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);
|
|
);
|
|
|
|
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;
|
|
FImageList:TAILQ_HEAD;
|
|
|
|
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
|
|
Result:=CompareNormalized(a^,b^);
|
|
end;
|
|
|
|
function TvImageView2Compare.c(a,b:PvImageViewKey):Integer;
|
|
begin
|
|
Result:=CompareByte(a^,b^,SizeOf(TvImageViewKey));
|
|
end;
|
|
|
|
//
|
|
|
|
function on_destroy(handle:Pointer):Integer; SysV_ABI_CDecl;
|
|
var
|
|
image:TvCustomImage2;
|
|
begin
|
|
image:=TvCustomImage2(handle);
|
|
image.tobj:=nil;
|
|
|
|
//
|
|
Result:=DO_DELETE;
|
|
end;
|
|
|
|
function on_trigger(handle:Pointer;mode:T_TRIGGER_MODE):Integer; SysV_ABI_CDecl;
|
|
var
|
|
image:TvCustomImage2;
|
|
i:Integer;
|
|
begin
|
|
Result:=DO_NOTHING;
|
|
|
|
image:=TvCustomImage2(handle);
|
|
|
|
//Writeln('on_trigger image');
|
|
|
|
case mode of
|
|
M_CPU_WRITE,
|
|
M_DMEM_WRITE:
|
|
//direct
|
|
begin
|
|
System.InterlockedIncrement(image.change_rate.trigger);
|
|
end;
|
|
M_GPU_PLANNED://planned
|
|
begin
|
|
System.InterlockedIncrement(image.change_rate.planned);
|
|
end;
|
|
M_GPU_APPLY://differed
|
|
begin
|
|
i:=System.InterlockedExchangeAdd(image.change_rate.planned,0);
|
|
|
|
System.InterlockedExchangeAdd(image.change_rate.trigger,+i);
|
|
System.InterlockedExchangeAdd(image.change_rate.planned,-i);
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
Result:=DO_INCREMENT;
|
|
end;
|
|
|
|
//
|
|
|
|
Destructor TvCustomImage2.Destroy;
|
|
begin
|
|
if (tobj<>nil) then
|
|
begin
|
|
vm_map_track_remove(p_proc.p_vmspace,tobj);
|
|
end;
|
|
|
|
inherited;
|
|
end;
|
|
|
|
procedure TvCustomImage2.restore_vm_track;
|
|
begin
|
|
if (tobj=nil) then Exit;
|
|
|
|
rw_wlock(lock);
|
|
|
|
vm_map_track_restore(p_proc.p_vmspace,tobj);
|
|
|
|
rw_wunlock(lock)
|
|
end;
|
|
|
|
procedure TvCustomImage2.assign_vm_track;
|
|
var
|
|
start,__end:QWORD;
|
|
begin
|
|
if (tobj<>nil) then Exit;
|
|
|
|
rw_wlock(lock);
|
|
|
|
if (tobj=nil) then
|
|
begin
|
|
size:=get_image_size(key);
|
|
|
|
start:=QWORD(key.Addr);
|
|
__end:=start+size;
|
|
|
|
tobj:=vm_track_object_allocate(Pointer(self),start,__end,H_GPU_IMAGE,PAGE_TRACK_W);
|
|
tobj^.on_destroy:=@on_destroy;
|
|
tobj^.on_trigger:=@on_trigger;
|
|
|
|
vm_map_track_insert(p_proc.p_vmspace,tobj);
|
|
|
|
vm_track_object_deallocate(tobj);
|
|
end;
|
|
|
|
rw_wunlock(lock)
|
|
end;
|
|
|
|
procedure t_change_rate.mark_init;
|
|
begin
|
|
state:=1;
|
|
end;
|
|
|
|
function t_change_rate.need_read:Boolean;
|
|
begin
|
|
Result:=(state=0) or (trigger<>0) or (planned<>0);
|
|
end;
|
|
|
|
procedure TvCustomImage2.mark_init;
|
|
begin
|
|
System.InterlockedExchange(change_rate.state,1);
|
|
end;
|
|
|
|
function TvCustomImage2.get_change_rate:t_change_rate;
|
|
begin
|
|
Result.state :=System.InterlockedExchangeAdd(change_rate.state ,0);
|
|
Result.trigger:=System.InterlockedExchangeAdd(change_rate.trigger,0);
|
|
Result.planned:=System.InterlockedExchangeAdd(change_rate.planned,0);
|
|
end;
|
|
|
|
procedure TvCustomImage2.apply_change_rate(r:t_change_rate);
|
|
begin
|
|
System.InterlockedExchange (change_rate.state , r.state);
|
|
System.InterlockedExchangeAdd(change_rate.trigger,-r.trigger);
|
|
System.InterlockedExchangeAdd(change_rate.planned,-r.planned);
|
|
end;
|
|
|
|
Function TvCustomImage2.IsDepthAndStencil:Boolean;
|
|
begin
|
|
Result:=vImage.IsDepthAndStencil(key.cformat);
|
|
end;
|
|
|
|
Function TvCustomImage2.GetSubresRange:TVkImageSubresourceRange;
|
|
begin
|
|
Result:=Default(TVkImageSubresourceRange);
|
|
Result.aspectMask:=GetAspectMaskByFormat(key.cformat);
|
|
Result.levelCount:=key.params.mipLevels;
|
|
Result.layerCount:=key.params.layerCount;
|
|
end;
|
|
|
|
Function TvCustomImage2.GetSubresLayer:TVkImageSubresourceLayers;
|
|
begin
|
|
Result:=Default(TVkImageSubresourceLayers);
|
|
Result.aspectMask :=GetAspectMaskByFormat(key.cformat);
|
|
Result.mipLevel :=0;
|
|
Result.baseArrayLayer:=0;
|
|
Result.layerCount :=key.params.layerCount;
|
|
end;
|
|
|
|
//
|
|
|
|
procedure TvChildImage2.FreeHandle;
|
|
begin
|
|
FHandle:=VK_NULL_HANDLE;
|
|
end;
|
|
|
|
function TvChildImage2.FetchViewRaw(cmd:TvCustomCmdBuffer;const F:TvImageViewKey;usage:TVkFlags):TvImageView2;
|
|
begin
|
|
Result:=Parent.FetchViewRaw(cmd,F,usage);
|
|
end;
|
|
|
|
procedure TvChildImage2.PushBarrier(cmd:TvCustomCmdBuffer;
|
|
dstAccessMask:TVkAccessFlags;
|
|
newImageLayout:TVkImageLayout;
|
|
dstStageMask:TVkPipelineStageFlags);
|
|
begin
|
|
Parent.PushBarrier(cmd,
|
|
dstAccessMask,
|
|
newImageLayout,
|
|
dstStageMask);
|
|
end;
|
|
|
|
procedure TvChildImage2.ForceBarrier(dstAccessMask:TVkAccessFlags;
|
|
newImageLayout:TVkImageLayout;
|
|
dstStageMask:TVkPipelineStageFlags);
|
|
begin
|
|
Parent.ForceBarrier(dstAccessMask,
|
|
newImageLayout,
|
|
dstStageMask);
|
|
end;
|
|
|
|
function TvChildImage2.Acquire(Sender:TObject):Boolean;
|
|
begin
|
|
Result:=Parent.Acquire(Sender);
|
|
end;
|
|
|
|
function TvChildImage2.Release(Sender:TObject):Boolean;
|
|
begin
|
|
Result:=Parent.Release(Sender);
|
|
end;
|
|
|
|
function TvChildImage2.Hold(Sender:TObject):Boolean;
|
|
begin
|
|
Result:=Parent.Hold(Sender);
|
|
end;
|
|
|
|
function TvChildImage2.Drop(Sender:TObject):Boolean;
|
|
begin
|
|
Result:=Parent.Drop(Sender);
|
|
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,
|
|
@cmd.BeforePushBarrier,
|
|
Parent.FHandle,
|
|
GetSubresRange,
|
|
dstAccessMask,
|
|
newImageLayout,
|
|
dstStageMask) then
|
|
begin
|
|
Inc(cmd.cmd_count);
|
|
end;
|
|
|
|
end;
|
|
|
|
Function TvImageView2.GetSubresRange(cformat:TVkFormat=VK_FORMAT_UNDEFINED):TVkImageSubresourceRange;
|
|
begin
|
|
if (cformat=VK_FORMAT_UNDEFINED) then cformat:=key.cformat;
|
|
|
|
Result:=Default(TVkImageSubresourceRange);
|
|
Result.aspectMask :=GetAspectMaskByFormat(cformat);
|
|
Result.baseMipLevel :=key.base_level;
|
|
Result.levelCount :=key.last_level-key.base_level+1;
|
|
Result.baseArrayLayer:=key.baseArrayLayer;
|
|
Result.layerCount :=key.layerCount;
|
|
end;
|
|
|
|
Function TvImageView2.GetSubresLayer(cformat:TVkFormat=VK_FORMAT_UNDEFINED):TVkImageSubresourceLayers;
|
|
begin
|
|
if (cformat=VK_FORMAT_UNDEFINED) then cformat:=key.cformat;
|
|
|
|
Result:=Default(TVkImageSubresourceLayers);
|
|
Result.aspectMask :=GetAspectMaskByFormat(cformat);
|
|
Result.mipLevel :=key.base_level;
|
|
Result.baseArrayLayer:=key.baseArrayLayer;
|
|
Result.layerCount :=key.layerCount;
|
|
end;
|
|
|
|
Constructor TvImage2.Create;
|
|
begin
|
|
inherited;
|
|
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(Self);
|
|
i.Next;
|
|
end;
|
|
FViews.Free;
|
|
|
|
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.layerCount;
|
|
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;
|
|
|
|
if (key.params.cube<>0) then
|
|
begin
|
|
Result.flags:=Result.flags or ord(VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT);
|
|
end;
|
|
|
|
if (Result.imageType=VK_IMAGE_TYPE_3D) then
|
|
begin
|
|
Result.flags:=Result.flags or ord(VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT);
|
|
end;
|
|
|
|
//
|
|
|
|
if (key.params.cube<>0) then
|
|
begin
|
|
Assert((Result.arrayLayers mod 6)=0,'CUBE: layerCount must be a multiple of 6');
|
|
end;
|
|
end;
|
|
|
|
const
|
|
DST_SEL_STR:PChar='I01RGBA';
|
|
|
|
function _get_dst_sel_str(dstSel:TvDstSel):RawByteString; inline;
|
|
begin
|
|
Result:=DST_SEL_STR[dstSel.x]+
|
|
DST_SEL_STR[dstSel.y]+
|
|
DST_SEL_STR[dstSel.z]+
|
|
DST_SEL_STR[dstSel.w];
|
|
end;
|
|
|
|
function TvImage2.FetchViewRaw(cmd:TvCustomCmdBuffer;const F:TvImageViewKey;usage:TVkFlags):TvImageView2;
|
|
var
|
|
key_view:TvImageViewKey;
|
|
|
|
i:TvImageView2Set.Iterator;
|
|
t:TvImageView2;
|
|
|
|
cinfo:TVkImageViewCreateInfo;
|
|
uinfo:TVkImageViewUsageCreateInfo;
|
|
minfo:TVkImageViewMinLodCreateInfoEXT;
|
|
|
|
FView:TVkImageView;
|
|
r:TVkResult;
|
|
begin
|
|
Result:=nil;
|
|
if (Self=nil) then Exit;
|
|
if (FHandle=VK_NULL_HANDLE) then Exit;
|
|
|
|
key_view:=F;
|
|
|
|
case FFormat of
|
|
VK_FORMAT_R32_UINT,
|
|
VK_FORMAT_R32_SINT,
|
|
VK_FORMAT_R32_SFLOAT:
|
|
if (key_view.cformat=VK_FORMAT_D32_SFLOAT) then
|
|
begin
|
|
//downlift to image
|
|
key_view.cformat:=FFormat;
|
|
end;
|
|
VK_FORMAT_R16_UNORM:
|
|
if (key_view.cformat=VK_FORMAT_D16_UNORM) then
|
|
begin
|
|
//downlift to image
|
|
key_view.cformat:=FFormat;
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
if (usage=0) then
|
|
begin
|
|
usage:=GET_VK_IMAGE_USAGE_DEFAULT(key_view.cformat);
|
|
end;
|
|
|
|
key_view.fusage:=usage;
|
|
|
|
rw_wlock(lock);
|
|
|
|
t:=nil;
|
|
i:=FViews.find(@key_view);
|
|
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(key_view.vtype);
|
|
cinfo.format :=key_view.cformat;
|
|
cinfo.components.r:=TVkComponentSwizzle(key_view.dstSel.x);
|
|
cinfo.components.g:=TVkComponentSwizzle(key_view.dstSel.y);
|
|
cinfo.components.b:=TVkComponentSwizzle(key_view.dstSel.z);
|
|
cinfo.components.a:=TVkComponentSwizzle(key_view.dstSel.w);
|
|
|
|
cinfo.subresourceRange.aspectMask :=GetAspectMaskByFormat(key_view.cformat);
|
|
cinfo.subresourceRange.baseMipLevel :=key_view.base_level;
|
|
cinfo.subresourceRange.levelCount :=key_view.last_level-key_view.base_level+1;
|
|
cinfo.subresourceRange.baseArrayLayer:=key_view.baseArrayLayer;
|
|
cinfo.subresourceRange.layerCount :=key_view.layerCount;
|
|
|
|
if (cinfo.subresourceRange.baseArrayLayer +
|
|
cinfo.subresourceRange.layerCount) > self.key.params.layerCount
|
|
then
|
|
begin
|
|
Writeln(stderr,'cinfo.subresourceRange.baseArrayLayer=',cinfo.subresourceRange.baseArrayLayer);
|
|
Writeln(stderr,'cinfo.subresourceRange.layerCount =',cinfo.subresourceRange.layerCount);
|
|
Writeln(stderr,'self.key.params.layerCount =',self.key.params.layerCount);
|
|
Assert(false);
|
|
end;
|
|
|
|
case cinfo.viewType of
|
|
VK_IMAGE_VIEW_TYPE_CUBE:
|
|
begin
|
|
|
|
if (usage and ord(VK_IMAGE_USAGE_STORAGE_BIT))=0 then
|
|
begin
|
|
Assert(cinfo.subresourceRange.layerCount=6,'VK_IMAGE_VIEW_TYPE_CUBE: layerCount must be 6');
|
|
end else
|
|
begin
|
|
//convert to array
|
|
cinfo.viewType:=VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
|
end;
|
|
|
|
end;
|
|
VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
|
|
begin
|
|
|
|
if (usage and ord(VK_IMAGE_USAGE_STORAGE_BIT))=0 then
|
|
begin
|
|
Assert((cinfo.subresourceRange.layerCount mod 6)=0,'VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: layerCount must be a multiple of 6');
|
|
end else
|
|
begin
|
|
//convert to array
|
|
cinfo.viewType:=VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
|
end;
|
|
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
//uplift imageview
|
|
if (FFormat=VK_FORMAT_D32_SFLOAT_S8_UINT) and
|
|
(cinfo.format=VK_FORMAT_D32_SFLOAT) then
|
|
begin
|
|
cinfo.format:=VK_FORMAT_D32_SFLOAT_S8_UINT;
|
|
end;
|
|
|
|
cinfo.format:=vkFixFormatSupport(cinfo.format,VK_IMAGE_TILING_OPTIMAL,usage);
|
|
|
|
cinfo.pNext:=@uinfo;
|
|
|
|
uinfo:=Default(TVkImageViewUsageCreateInfo);
|
|
uinfo.sType:=VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
|
|
uinfo.usage:=usage;
|
|
|
|
if limits.VK_EXT_image_view_min_lod and
|
|
(key_view.minLod<>0) then
|
|
begin
|
|
uinfo.pNext:=@minfo;
|
|
//
|
|
minfo:=Default(TVkImageViewMinLodCreateInfoEXT);
|
|
minfo.sType :=VK_STRUCTURE_TYPE_IMAGE_VIEW_MIN_LOD_CREATE_INFO_EXT;
|
|
minfo.minLod:=key_view.minLod;
|
|
end;
|
|
|
|
Writeln('vkCreateImageView:',cinfo.format);
|
|
|
|
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 :=key_view;
|
|
|
|
t.SetObjectName('V_'+_get_dst_sel_str(t.key.dstSel)+
|
|
'_L['+IntToStr(t.key.base_level)+'-'+IntToStr(t.key.last_level)+']'+
|
|
'_A['+IntToStr(t.key.base_array)+'-'+IntToStr(t.key.last_array)+']'
|
|
);
|
|
|
|
t.Acquire(Self); //map ref
|
|
FViews.Insert(@t.key);
|
|
end;
|
|
|
|
cmd.RefTo(t);
|
|
|
|
rw_wunlock(lock);
|
|
|
|
Result:=t;
|
|
end;
|
|
|
|
function TvCustomImage2.FetchView(cmd:TvCustomCmdBuffer;const F:TvImageViewKey;usage:t_image_usage):TvImageView2;
|
|
var
|
|
fkey:TvImageViewKey;
|
|
fusage:TVkFlags;
|
|
begin
|
|
fkey:=F;
|
|
//
|
|
case usage of
|
|
iu_attachment:
|
|
begin
|
|
fusage:=ord(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
|
|
end;
|
|
iu_depthstenc:
|
|
begin
|
|
fusage:=ord(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
|
end;
|
|
iu_sampled:
|
|
begin
|
|
fusage:=ord(VK_IMAGE_USAGE_SAMPLED_BIT);
|
|
end;
|
|
iu_storage:
|
|
begin
|
|
//Separate storage access for special cases?
|
|
//fkey.cformat:=GET_VK_FORMAT_STORAGE(fkey.cformat);
|
|
fusage:=ord(VK_IMAGE_USAGE_STORAGE_BIT);
|
|
end;
|
|
else
|
|
fusage:=0; //default
|
|
end;
|
|
//
|
|
Result:=FetchViewRaw(cmd,fkey,fusage);
|
|
end;
|
|
|
|
function TvCustomImage2.FetchView(cmd:TvCustomCmdBuffer;usage:t_image_usage):TvImageView2;
|
|
var
|
|
fkey:TvImageViewKey;
|
|
fusage:TVkFlags;
|
|
begin
|
|
if (Self=nil) then Exit;
|
|
|
|
fkey:=Default(TvImageViewKey);
|
|
fkey.cformat:=key.cformat;
|
|
|
|
Case TVkImageType(key.params.itype) of
|
|
VK_IMAGE_TYPE_1D:
|
|
begin
|
|
if (key.params.arrayLayers>1) then
|
|
fkey.vtype:=ord(VK_IMAGE_VIEW_TYPE_1D_ARRAY)
|
|
else
|
|
fkey.vtype:=ord(VK_IMAGE_VIEW_TYPE_1D);
|
|
end;
|
|
VK_IMAGE_TYPE_2D:
|
|
begin
|
|
if (key.params.cube<>0) then
|
|
begin
|
|
if (key.params.arrayLayers>6) then
|
|
begin
|
|
fkey.vtype:=ord(VK_IMAGE_VIEW_TYPE_CUBE_ARRAY);
|
|
end else
|
|
begin
|
|
fkey.vtype:=ord(VK_IMAGE_VIEW_TYPE_CUBE);
|
|
end;
|
|
end else
|
|
if (key.params.arrayLayers>1) then
|
|
begin
|
|
fkey.vtype:=ord(VK_IMAGE_VIEW_TYPE_2D_ARRAY);
|
|
end else
|
|
begin
|
|
fkey.vtype:=ord(VK_IMAGE_VIEW_TYPE_2D);
|
|
end;
|
|
end;
|
|
VK_IMAGE_TYPE_3D:fkey.vtype:=ord(VK_IMAGE_VIEW_TYPE_3D);
|
|
end;
|
|
|
|
fkey.last_level:=key.params.mipLevels -1;
|
|
fkey.last_array:=key.params.arrayLayers-1;
|
|
|
|
fusage:=0;
|
|
|
|
//
|
|
case usage of
|
|
iu_attachment:
|
|
begin
|
|
fusage:=ord(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
|
|
end;
|
|
iu_depthstenc:
|
|
begin
|
|
fusage:=ord(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
|
end;
|
|
iu_sampled:
|
|
begin
|
|
fusage:=ord(VK_IMAGE_USAGE_SAMPLED_BIT);
|
|
end;
|
|
iu_storage:
|
|
begin
|
|
//Separate storage access for special cases?
|
|
//fkey.cformat:=GET_VK_FORMAT_STORAGE(fkey.cformat);
|
|
fusage:=ord(VK_IMAGE_USAGE_STORAGE_BIT);
|
|
end;
|
|
else
|
|
fusage:=0; //default
|
|
end;
|
|
//
|
|
|
|
Result:=FetchViewRaw(cmd,fkey,fusage);
|
|
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,
|
|
@cmd.BeforePushBarrier,
|
|
FHandle,
|
|
GetSubresRange,
|
|
dstAccessMask,
|
|
newImageLayout,
|
|
dstStageMask) then
|
|
begin
|
|
Inc(cmd.cmd_count);
|
|
end;
|
|
|
|
rw_wunlock(lock);
|
|
end;
|
|
|
|
procedure TvImage2.ForceBarrier(dstAccessMask:TVkAccessFlags;
|
|
newImageLayout:TVkImageLayout;
|
|
dstStageMask:TVkPipelineStageFlags);
|
|
begin
|
|
rw_wlock(lock);
|
|
|
|
Barrier.AccessMask:=dstAccessMask;
|
|
Barrier.ImgLayout :=newImageLayout;
|
|
Barrier.StageMask :=dstStageMask;
|
|
|
|
rw_wunlock(lock);
|
|
end;
|
|
|
|
function TvImage2.Hold(Sender:TObject):Boolean;
|
|
begin
|
|
Result:=inherited;
|
|
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;
|
|
|
|
function TvImage2.Drop(Sender:TObject):Boolean;
|
|
begin
|
|
if (Sender<>nil) then
|
|
begin
|
|
FDeps.delete(Sender);
|
|
if (FLastCmd=Sender) then
|
|
begin
|
|
FLastCmd:=nil;
|
|
end;
|
|
end;
|
|
Result:=inherited;
|
|
end;
|
|
|
|
//
|
|
|
|
procedure TvDepthStencilImage2.FreeHandle;
|
|
begin
|
|
if (DepthOnly<>nil) then
|
|
begin
|
|
DepthOnly.FHandle:=VK_NULL_HANDLE;
|
|
end;
|
|
|
|
if (StencilOnly<>nil) then
|
|
begin
|
|
StencilOnly.FHandle:=VK_NULL_HANDLE;
|
|
end;
|
|
|
|
inherited;
|
|
end;
|
|
|
|
function TvDepthStencilImage2.Compile(ext:Pointer):Boolean;
|
|
begin
|
|
Result:=inherited Compile(ext);
|
|
//
|
|
if Result then
|
|
begin
|
|
if (DepthOnly<>nil) then
|
|
begin
|
|
DepthOnly.FHandle:=FHandle;
|
|
end;
|
|
|
|
if (StencilOnly<>nil) then
|
|
begin
|
|
StencilOnly.FHandle:=FHandle;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TvDepthStencilImage2.restore_vm_track;
|
|
begin
|
|
if (DepthOnly<>nil) then
|
|
begin
|
|
DepthOnly.restore_vm_track;
|
|
end;
|
|
|
|
if (StencilOnly<>nil) then
|
|
begin
|
|
StencilOnly.restore_vm_track;
|
|
end;
|
|
end;
|
|
|
|
procedure TvDepthStencilImage2.assign_vm_track;
|
|
begin
|
|
if (DepthOnly<>nil) then
|
|
begin
|
|
DepthOnly.assign_vm_track;
|
|
end;
|
|
|
|
if (StencilOnly<>nil) then
|
|
begin
|
|
StencilOnly.assign_vm_track;
|
|
end;
|
|
end;
|
|
|
|
Destructor TvDepthStencilImage2.Destroy;
|
|
begin
|
|
if (DepthOnly<>nil) and
|
|
(DepthOnly<>Self) then
|
|
begin
|
|
FreeAndNil(DepthOnly);
|
|
end;
|
|
|
|
if (StencilOnly<>nil) and
|
|
(StencilOnly<>Self) then
|
|
begin
|
|
FreeAndNil(StencilOnly);
|
|
end;
|
|
|
|
inherited;
|
|
end;
|
|
|
|
//
|
|
|
|
function _Find(const F:TvImageKey):TvCustomImage2;
|
|
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));
|
|
|
|
if (Result.Parent<>nil) then
|
|
begin
|
|
Result:=Result.Parent;
|
|
end;
|
|
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 _NewImage(const F:TvImageKey;usage:s_image_usage):TvImage2;
|
|
begin
|
|
Case F.cformat of
|
|
//stencil
|
|
VK_FORMAT_S8_UINT:
|
|
begin
|
|
Result:=TvDepthStencilImage2.Create;
|
|
Result.key :=F;
|
|
Result.FUsage:=usage;
|
|
//
|
|
Result.StencilOnly:=TvChildImage2.Create;
|
|
Result.StencilOnly.key :=GetStencilOnly(F);
|
|
end;
|
|
//depth
|
|
VK_FORMAT_D16_UNORM,
|
|
VK_FORMAT_X8_D24_UNORM_PACK32,
|
|
VK_FORMAT_D32_SFLOAT:
|
|
begin
|
|
Result:=TvImage2.Create;
|
|
Result.key :=F;
|
|
Result.FUsage:=usage;
|
|
//
|
|
Result.DepthOnly:=Result;
|
|
end;
|
|
//depth stencil
|
|
VK_FORMAT_D16_UNORM_S8_UINT,
|
|
VK_FORMAT_D24_UNORM_S8_UINT,
|
|
VK_FORMAT_D32_SFLOAT_S8_UINT:
|
|
begin
|
|
Result:=TvDepthStencilImage2.Create;
|
|
Result.key :=F;
|
|
Result.FUsage:=usage;
|
|
//
|
|
Result.DepthOnly:=TvChildImage2.Create;
|
|
Result.DepthOnly.key :=GetDepthOnly(F);
|
|
Result.DepthOnly.Parent:=Result;
|
|
//
|
|
Result.StencilOnly:=TvChildImage2.Create;
|
|
Result.StencilOnly.key :=GetStencilOnly(F);
|
|
Result.StencilOnly.Parent:=Result;
|
|
end;
|
|
else
|
|
begin
|
|
Result:=TvImage2.Create;
|
|
Result.key :=F;
|
|
Result.FUsage:=usage;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure _DeleteImage(t:TvCustomImage2);
|
|
begin
|
|
FImage2Set.delete(@t.key);
|
|
TAILQ_REMOVE(@FImageList,t,@t.entry);
|
|
|
|
if (t.DepthOnly<>nil) and
|
|
(t.DepthOnly<>t) then
|
|
begin
|
|
FImage2Set.delete(@t.DepthOnly.key);
|
|
TAILQ_REMOVE(@FImageList,t.DepthOnly,@t.DepthOnly.entry);
|
|
end;
|
|
|
|
if (t.StencilOnly<>nil) and
|
|
(t.StencilOnly<>t) then
|
|
begin
|
|
FImage2Set.delete(@t.StencilOnly.key);
|
|
TAILQ_REMOVE(@FImageList,t.StencilOnly,@t.StencilOnly.entry);
|
|
end;
|
|
|
|
t.Release(nil); //map ref
|
|
end;
|
|
|
|
procedure _DeleteAlias(const F:TvImageKey);
|
|
var
|
|
t:TvCustomImage2;
|
|
begin
|
|
t:=_Find(F);
|
|
if (t=nil) then Exit;
|
|
|
|
_DeleteImage(t);
|
|
end;
|
|
|
|
function _InsertImage(t:TvCustomImage2):Boolean;
|
|
begin
|
|
if FImage2Set.Insert(@t.key) then
|
|
begin
|
|
TAILQ_INSERT_HEAD(@FImageList,t,@t.entry);
|
|
t.Acquire(nil); //map ref
|
|
end else
|
|
begin
|
|
Exit(False);
|
|
end;
|
|
|
|
if (t.DepthOnly<>nil) and
|
|
(t.DepthOnly<>t) then
|
|
begin
|
|
if FImage2Set.Insert(@t.DepthOnly.key) then
|
|
begin
|
|
TAILQ_INSERT_HEAD(@FImageList,t.DepthOnly,@t.DepthOnly.entry);
|
|
end else
|
|
begin
|
|
//alias? -> delete
|
|
_DeleteAlias(t.DepthOnly.key);
|
|
//again
|
|
if not FImage2Set.Insert(@t.DepthOnly.key) then
|
|
begin
|
|
//wtf?
|
|
_DeleteImage(t);
|
|
Exit(False);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if (t.StencilOnly<>nil) and
|
|
(t.StencilOnly<>t) then
|
|
begin
|
|
if FImage2Set.Insert(@t.StencilOnly.key) then
|
|
begin
|
|
TAILQ_INSERT_HEAD(@FImageList,t.StencilOnly,@t.StencilOnly.entry);
|
|
end else
|
|
begin
|
|
//alias? -> delete
|
|
_DeleteAlias(t.StencilOnly.key);
|
|
//again
|
|
if not FImage2Set.Insert(@t.StencilOnly.key) then
|
|
begin
|
|
//wtf?
|
|
_DeleteImage(t);
|
|
Exit(False);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Result:=True;
|
|
end;
|
|
|
|
procedure _SetName(t:TvCustomImage2);
|
|
var
|
|
ch:Char;
|
|
begin
|
|
|
|
Case t.key.cformat of
|
|
//stencil
|
|
VK_FORMAT_S8_UINT:
|
|
begin
|
|
Ch:='S';
|
|
end;
|
|
//depth
|
|
VK_FORMAT_D16_UNORM,
|
|
VK_FORMAT_X8_D24_UNORM_PACK32,
|
|
VK_FORMAT_D32_SFLOAT:
|
|
begin
|
|
Ch:='D';
|
|
end;
|
|
//depth stencil
|
|
VK_FORMAT_D16_UNORM_S8_UINT,
|
|
VK_FORMAT_D24_UNORM_S8_UINT,
|
|
VK_FORMAT_D32_SFLOAT_S8_UINT:
|
|
begin
|
|
Ch:='X';
|
|
end;
|
|
else
|
|
begin
|
|
if (t.key.params.cube<>0) then
|
|
begin
|
|
Ch:='C';
|
|
end else
|
|
if (t.key.params.arrayLayers>1) then
|
|
begin
|
|
Ch:='A';
|
|
end else
|
|
begin
|
|
Ch:='I';
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
t.SetObjectName(Ch+'_0x'+HexStr(QWORD(t.key.Addr),10)+
|
|
'_'+IntToStr(t.key.params.width)+'x'+IntToStr(t.key.params.height)+'x'+IntToStr(t.key.params.depth)+
|
|
'_m'+IntToStr(t.key.params.mipLevels)+
|
|
'_a'+IntToStr(t.key.params.arrayLayers)+
|
|
'_t'+IntToStr(t.key.params.tiling.idx)+'|'+IntToStr(t.key.params.tiling.alt)
|
|
);
|
|
|
|
end;
|
|
|
|
Function _shrink_images(max:TVkDeviceSize):TVkDeviceSize;
|
|
var
|
|
node:TvCustomImage2;
|
|
i:TVkDeviceSize;
|
|
begin
|
|
Result:=0;
|
|
|
|
node:=TvCustomImage2(TAILQ_LAST(@FImageList));
|
|
|
|
while (node<>nil) do
|
|
begin
|
|
|
|
if (node.FHold=0) then //lock hold?
|
|
if (not node.is_invalid) then
|
|
begin
|
|
i:=node.GetRequirements.size;
|
|
|
|
node.FreeHandle;
|
|
node.UnBindMem(True);
|
|
|
|
Result:=Result+i;
|
|
|
|
if (Result>=max) then Break;
|
|
end;
|
|
|
|
node:=TvCustomImage2(TAILQ_PREV(node,@node.entry));
|
|
end;
|
|
|
|
end;
|
|
|
|
function _FetchImage(const F:TvImageKey;usage:s_image_usage):TvImage2;
|
|
label
|
|
_repeat;
|
|
var
|
|
t:TvImage2;
|
|
mem:TvPointer;
|
|
req:TVkMemoryRequirements;
|
|
begin
|
|
Result:=nil;
|
|
|
|
_repeat:
|
|
|
|
t:=TvImage2(_Find(F));
|
|
|
|
if (t<>nil) then
|
|
begin
|
|
if t.Hold(nil) then //result ref
|
|
begin
|
|
t.FUsage:=t.FUsage+usage;
|
|
end else
|
|
begin
|
|
//mem is deleted, free img
|
|
_DeleteImage(t);
|
|
t:=nil;
|
|
goto _repeat;
|
|
end;
|
|
end else
|
|
begin
|
|
t:=_NewImage(F,usage);
|
|
|
|
if not t.Compile(nil) then
|
|
begin
|
|
FreeAndNil(t);
|
|
end else
|
|
begin
|
|
|
|
_SetName(t);
|
|
|
|
req:=t.GetRequirements;
|
|
|
|
mem:=MemManager.FetchMemory(
|
|
req,
|
|
V_PROP_DEVICE_LOCAL or V_PROP_BEST_FIT,
|
|
t
|
|
);
|
|
|
|
if (mem.FMemory=nil) then //NOMEM
|
|
begin
|
|
if _shrink_images(req.size)>=req.size then
|
|
begin
|
|
//repeat after free?
|
|
FreeAndNil(t);
|
|
//
|
|
goto _repeat;
|
|
end;
|
|
//
|
|
vMemory.MemManager._print_devs;
|
|
vMemory.MemManager._print_host;
|
|
//NOMEM error
|
|
FreeAndNil(t);
|
|
//
|
|
Exit(nil);
|
|
end;
|
|
|
|
if (t.BindMem(mem)<>VK_SUCCESS) then
|
|
begin
|
|
//unknow error
|
|
FreeAndNil(t);
|
|
mem.Release; //release [FetchMemory]
|
|
//
|
|
Exit(nil);
|
|
end;
|
|
|
|
if not _InsertImage(t) then
|
|
begin
|
|
//collision?
|
|
|
|
FreeAndNil(t);
|
|
mem.Release; //release [FetchMemory]
|
|
|
|
//
|
|
goto _repeat;
|
|
end;
|
|
|
|
end;
|
|
|
|
if (t<>nil) then
|
|
begin
|
|
t.Hold(nil); //result ref
|
|
end;
|
|
|
|
mem.Release; //release [FetchMemory]
|
|
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:s_image_usage):TvImage2;
|
|
begin
|
|
FImage2Set.Lock_wr;
|
|
|
|
Result:=_FetchImage(F,usage); // <- Hold(nil)/FetchMemory
|
|
|
|
if (Result<>nil) then
|
|
if (Result<>TvImage2(TAILQ_FIRST(@FImageList))) then
|
|
begin
|
|
TAILQ_REMOVE (@FImageList,Result,@Result.entry);
|
|
TAILQ_INSERT_HEAD(@FImageList,Result,@Result.entry);
|
|
end;
|
|
|
|
//add dep
|
|
cmd.RefTo(Result);
|
|
|
|
FImage2Set.Unlock_wr;
|
|
|
|
if (Result<>nil) then
|
|
begin
|
|
Result.Drop(nil); //release [Drop(nil)]
|
|
end;
|
|
end;
|
|
|
|
function FindImage(cmd:TvCustomCmdBuffer;Addr:Pointer;cformat:TVkFormat):TvImage2;
|
|
begin
|
|
FImage2Set.Lock_wr;
|
|
|
|
Result:=_FindImage(Addr,cformat);
|
|
|
|
cmd.RefTo(Result);
|
|
|
|
FImage2Set.Unlock_wr;
|
|
end;
|
|
|
|
|
|
end.
|
|
|
|
|
|
|