fpPS4/vulkan/vRenderPassManager.pas
2022-07-13 17:01:22 +03:00

397 lines
9.2 KiB
ObjectPascal

unit vRenderPassManager;
{$mode ObjFPC}{$H+}
interface
uses
SysUtils,
RWLock,
g23tree,
Vulkan,
vDevice,
vImage,
vPipeline,
vCmdBuffer;
type
PvRenderPassKey=^TvRenderPassKey;
TvRenderPassKey=packed object
AtdCount:Byte;
RefCount:Byte; //VkSubpassDescription.colorAttachmentCount
DepCount:Byte; //DepthRef
_align:Byte;
ColorAtd:array[0..8] of TVkAttachmentDescription;
ColorRef:array[0..7] of TVkAttachmentReference;
DepthRef:TVkAttachmentReference;
Dependency:TVkSubpassDependency;
Procedure Clear;
Procedure SetZorderStage(s:TVkPipelineStageFlags);
Procedure AddColorRef(id:TVkUInt32;IMAGE_USAGE:Byte);
Procedure SetDepthRef(id:TVkUInt32;DEPTH_USAGE,STENCIL_USAGE:Byte);
Procedure AddColorAt(format:TVkFormat;IMAGE_USAGE:Byte;samples:TVkSampleCountFlagBits);
Procedure AddDepthAt(format:TVkFormat;DEPTH_USAGE,STENCIL_USAGE:Byte);
end;
TvRenderPass2=class(TvRenderPass)
Key:TvRenderPassKey;
//
FRefs:ptruint;
Function Compile:Boolean;
Procedure Acquire;
procedure Release(Sender:TObject);
end;
function FetchRenderPass(cmd:TvCustomCmdBuffer;P:PvRenderPassKey):TvRenderPass2;
implementation
type
TvRenderPassKey2Compare=object
function c(a,b:PvRenderPassKey):Integer; static;
end;
_TvRenderPass2Set=specialize T23treeSet<PvRenderPassKey,TvRenderPassKey2Compare>;
TvRenderPass2Set=object(_TvRenderPass2Set)
lock:TRWLock;
Procedure Init;
Procedure Lock_wr;
Procedure Unlock;
end;
var
FRenderPass2Set:TvRenderPass2Set;
Function GetDepthStencilLayout(DEPTH_USAGE,STENCIL_USAGE:Byte):TVkImageLayout;
begin
if ((DEPTH_USAGE or STENCIL_USAGE) and (TM_WRITE or TM_CLEAR)<>0) then
begin
Result:=VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
end else
begin
Result:=VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
end;
end;
Function GetDepthStencilAccessMask(DEPTH_USAGE,STENCIL_USAGE:Byte):TVkAccessFlags;
begin
Result:=(ord(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT) *ord((DEPTH_USAGE or STENCIL_USAGE) and TM_READ <>0) ) or
(ord(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT)*ord((DEPTH_USAGE or STENCIL_USAGE) and (TM_WRITE or TM_CLEAR)<>0) );
end;
Function GetColorAccessMask(IMAGE_USAGE:Byte):TVkAccessFlags;
begin
Result:=(ord(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT) *ord(IMAGE_USAGE and TM_READ<>0) ) or
(ord(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT)*ord(IMAGE_USAGE and (TM_WRITE or TM_CLEAR)<>0) );
end;
Procedure TvRenderPassKey.Clear;
begin
Self:=Default(TvRenderPassKey);
Dependency.srcSubpass:=VK_SUBPASS_EXTERNAL;
end;
Procedure TvRenderPassKey.SetZorderStage(s:TVkPipelineStageFlags);
begin
Dependency.srcStageMask:=Dependency.srcStageMask or s;
Dependency.dstStageMask:=Dependency.dstStageMask or s;
end;
Procedure TvRenderPassKey.AddColorRef(id:TVkUInt32;IMAGE_USAGE:Byte);
var
am:TVkAccessFlags;
begin
if (RefCount>7) then Exit;
ColorRef[RefCount].attachment:=id;
ColorRef[RefCount].layout :=VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL{VK_IMAGE_LAYOUT_GENERAL};
Inc(RefCount);
Dependency.srcStageMask :=Dependency.srcStageMask or ord(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
Dependency.dstStageMask :=Dependency.dstStageMask or ord(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
am:=GetColorAccessMask(IMAGE_USAGE);
Dependency.srcAccessMask:=Dependency.srcAccessMask or am;
Dependency.dstAccessMask:=Dependency.dstAccessMask or am;
end;
Procedure TvRenderPassKey.SetDepthRef(id:TVkUInt32;DEPTH_USAGE,STENCIL_USAGE:Byte);
var
am:TVkAccessFlags;
begin
DepCount:=1;
DepthRef.attachment :=id;
DepthRef.layout :=GetDepthStencilLayout(DEPTH_USAGE,STENCIL_USAGE);
am:=GetDepthStencilAccessMask(DEPTH_USAGE,STENCIL_USAGE);
Dependency.srcAccessMask:=Dependency.srcAccessMask or am;
Dependency.dstAccessMask:=Dependency.dstAccessMask or am;
end;
Procedure TvRenderPassKey.AddColorAt(format:TVkFormat;IMAGE_USAGE:Byte;samples:TVkSampleCountFlagBits);
begin
if (AtdCount>8) then Exit;
ColorAtd[AtdCount]:=Default(TVkAttachmentDescription);
ColorAtd[AtdCount].format :=format;
ColorAtd[AtdCount].samples :=samples;
With ColorAtd[AtdCount] do
if (IMAGE_USAGE and TM_CLEAR<>0) then
begin
loadOp:=VK_ATTACHMENT_LOAD_OP_CLEAR;
end else
if (IMAGE_USAGE and TM_READ<>0) then
begin
loadOp:=VK_ATTACHMENT_LOAD_OP_LOAD;
end else
begin
loadOp:=VK_ATTACHMENT_LOAD_OP_DONT_CARE;
end;
With ColorAtd[AtdCount] do
if (IMAGE_USAGE and TM_WRITE<>0) then
begin
storeOp:=VK_ATTACHMENT_STORE_OP_STORE;
end else
begin
storeOp:=VK_ATTACHMENT_STORE_OP_DONT_CARE;
end;
ColorAtd[AtdCount].stencilLoadOp :=VK_ATTACHMENT_LOAD_OP_DONT_CARE;
ColorAtd[AtdCount].stencilStoreOp:=VK_ATTACHMENT_STORE_OP_DONT_CARE;
With ColorAtd[AtdCount] do
if (IMAGE_USAGE and TM_READ<>0) then
begin
initialLayout :=VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
end else
begin
initialLayout :=VK_IMAGE_LAYOUT_UNDEFINED;
end;
With ColorAtd[AtdCount] do
finalLayout:=VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
Inc(AtdCount);
end;
Procedure TvRenderPassKey.AddDepthAt(format:TVkFormat;DEPTH_USAGE,STENCIL_USAGE:Byte);
begin
if (AtdCount>8) then Exit;
ColorAtd[AtdCount]:=Default(TVkAttachmentDescription);
ColorAtd[AtdCount].format :=format;
ColorAtd[AtdCount].samples :=VK_SAMPLE_COUNT_1_BIT;
With ColorAtd[AtdCount] do
if (DEPTH_USAGE and TM_CLEAR<>0) then
begin
loadOp:=VK_ATTACHMENT_LOAD_OP_CLEAR;
end else
if (DEPTH_USAGE and TM_READ<>0) then
begin
loadOp:=VK_ATTACHMENT_LOAD_OP_LOAD;
end else
begin
loadOp:=VK_ATTACHMENT_LOAD_OP_DONT_CARE;
end;
With ColorAtd[AtdCount] do
if (DEPTH_USAGE and TM_WRITE<>0) then
begin
storeOp:=VK_ATTACHMENT_STORE_OP_STORE;
end else
begin
storeOp:=VK_ATTACHMENT_STORE_OP_DONT_CARE;
end;
With ColorAtd[AtdCount] do
if (STENCIL_USAGE and TM_CLEAR<>0) then
begin
stencilLoadOp:=VK_ATTACHMENT_LOAD_OP_CLEAR;
end else
if (STENCIL_USAGE and TM_READ<>0) then
begin
stencilLoadOp:=VK_ATTACHMENT_LOAD_OP_LOAD;
end else
begin
stencilLoadOp:=VK_ATTACHMENT_LOAD_OP_DONT_CARE;
end;
With ColorAtd[AtdCount] do
if (STENCIL_USAGE and TM_WRITE<>0) then
begin
stencilStoreOp:=VK_ATTACHMENT_STORE_OP_STORE;
end else
begin
stencilStoreOp:=VK_ATTACHMENT_STORE_OP_DONT_CARE;
end;
With ColorAtd[AtdCount] do
if ((DEPTH_USAGE or STENCIL_USAGE) and TM_READ<>0) then
begin
initialLayout :=GetDepthStencilLayout(DEPTH_USAGE,STENCIL_USAGE);
end else
begin
initialLayout :=VK_IMAGE_LAYOUT_UNDEFINED;
end;
With ColorAtd[AtdCount] do
finalLayout:=GetDepthStencilLayout(DEPTH_USAGE,STENCIL_USAGE);
Inc(AtdCount);
end;
///
Function TvRenderPass2.Compile:Boolean;
var
r:TVkResult;
sub:TVkSubpassDescription;
info:TVkRenderPassCreateInfo;
begin
Result:=False;
if (Key.AtdCount=0) then Exit;
if (FHandle<>VK_NULL_HANDLE) then Exit(True);
sub:=Default(TVkSubpassDescription);
sub.pipelineBindPoint:=VK_PIPELINE_BIND_POINT_GRAPHICS;
sub.inputAttachmentCount :=0;
sub.pInputAttachments :=nil;
sub.colorAttachmentCount :=Key.RefCount;
sub.pColorAttachments :=@Key.ColorRef;
sub.pResolveAttachments :=nil; //colorAttachmentCount VK_ATTACHMENT_UNUSED
if (Key.DepCount<>0) then
begin
sub.pDepthStencilAttachment:=@Key.DepthRef; //1
end;
sub.preserveAttachmentCount:=0;
sub.pPreserveAttachments :=nil;
info:=Default(TVkRenderPassCreateInfo);
info.sType :=VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
info.attachmentCount:=Key.AtdCount;
info.pAttachments :=@Key.ColorAtd;
info.subpassCount :=1;
info.pSubpasses :=@sub;
info.dependencyCount:=1;
info.pDependencies :=@Key.Dependency;
r:=vkCreateRenderPass(Device.FHandle,@info,nil,@FHandle);
if (r<>VK_SUCCESS) then
begin
Writeln(StdErr,'vkCreateRenderPass:',r);
Exit;
end;
Result:=True;
end;
Procedure TvRenderPass2Set.Init;
begin
rwlock_init(lock);
end;
Procedure TvRenderPass2Set.Lock_wr;
begin
rwlock_wrlock(lock);
end;
Procedure TvRenderPass2Set.Unlock;
begin
rwlock_unlock(lock);
end;
Procedure TvRenderPass2.Acquire;
begin
System.InterlockedIncrement(Pointer(FRefs));
end;
procedure TvRenderPass2.Release(Sender:TObject);
begin
if System.InterlockedDecrement(Pointer(FRefs))=nil then
begin
Free;
end;
end;
function TvRenderPassKey2Compare.c(a,b:PvRenderPassKey):Integer;
begin
Result:=CompareByte(a^,b^,SizeOf(TvRenderPassKey));
end;
function _Find(P:PvRenderPassKey):TvRenderPass2;
var
i:TvRenderPass2Set.Iterator;
begin
Result:=nil;
i:=FRenderPass2Set.find(P);
if (i.Item<>nil) then
begin
Result:=TvRenderPass2(ptruint(i.Item^)-ptruint(@TvRenderPass2(nil).key));
end;
end;
function _FetchRenderPass(P:PvRenderPassKey):TvRenderPass2;
var
t:TvRenderPass2;
begin
Result:=nil;
t:=_Find(P);
if (t=nil) then
begin
t:=TvRenderPass2.Create;
t.key:=P^;
if not t.Compile then
begin
FreeAndNil(t);
end else
begin
t.Acquire;
FRenderPass2Set.Insert(@t.key);
end;
end;
Result:=t;
end;
function FetchRenderPass(cmd:TvCustomCmdBuffer;P:PvRenderPassKey):TvRenderPass2;
begin
Result:=nil;
if (P=nil) then Exit;
FRenderPass2Set.Lock_wr;
Result:=_FetchRenderPass(P);
if (cmd<>nil) and (Result<>nil) then
begin
if cmd.AddDependence(@TvRenderPass2(Result).Release) then
begin
TvRenderPass2(Result).Acquire;
end;
end;
FRenderPass2Set.Unlock;
end;
initialization
FRenderPass2Set.Init;
end.