FPPS4/vulkan/vRenderPassManager.pas

393 lines
8.4 KiB
Plaintext

unit vRenderPassManager;
{$mode ObjFPC}{$H+}
interface
uses
SysUtils,
g23tree,
Vulkan,
vDevice,
vDependence,
vPipeline,
vImage{,
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(id:TVkUInt32;aformat:TVkFormat;IMAGE_USAGE,asamples:Byte);
Procedure AddDepthAt(id:TVkUInt32;aformat:TVkFormat;DEPTH_USAGE,STENCIL_USAGE,asamples:Byte);
end;
TvRenderPass2=class(TvRenderPass)
Key:TvRenderPassKey;
//
Function Compile:Boolean;
end;
function FetchRenderPass(cmd:TvDependenciesObject;P:PvRenderPassKey):TvRenderPass2;
implementation
uses
kern_rwlock;
type
TvRenderPassKey2Compare=object
function c(a,b:PvRenderPassKey):Integer; static;
end;
_TvRenderPass2Set=specialize T23treeSet<PvRenderPassKey,TvRenderPassKey2Compare>;
TvRenderPass2Set=object(_TvRenderPass2Set)
lock:Pointer;
Procedure Lock_wr;
Procedure Unlock_wr;
end;
var
FRenderPass2Set:TvRenderPass2Set;
function TvRenderPassKey2Compare.c(a,b:PvRenderPassKey):Integer;
begin
Result:=CompareByte(a^,b^,SizeOf(TvRenderPassKey));
end;
Procedure TvRenderPass2Set.Lock_wr;
begin
rw_wlock(lock);
end;
Procedure TvRenderPass2Set.Unlock_wr;
begin
rw_wunlock(lock);
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;
if (id<>VK_ATTACHMENT_UNUSED) then
begin
with ColorRef[RefCount] do
begin
attachment:=id;
layout:=GetColorSendLayout(IMAGE_USAGE);
end;
end else
begin
with ColorRef[RefCount] do
begin
attachment:=VK_ATTACHMENT_UNUSED;
layout:=VK_IMAGE_LAYOUT_GENERAL;
end;
end;
Inc(RefCount);
//add on unused also
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);
if (id<>VK_ATTACHMENT_UNUSED) then
begin
am:=GetColorAccessAttachMask(IMAGE_USAGE);
Dependency.srcAccessMask:=Dependency.srcAccessMask or am;
Dependency.dstAccessMask:=Dependency.dstAccessMask or am;
end;
end;
Procedure TvRenderPassKey._SetDepthRef(id:TVkUInt32;DEPTH_USAGE,STENCIL_USAGE:Byte);
var
am:TVkAccessFlags;
begin
DepCount:=1;
DepthRef.attachment:=id;
DepthRef.layout :=GetDepthStencilSendLayout(DEPTH_USAGE,STENCIL_USAGE);
am:=GetDepthStencilAccessAttachMask(DEPTH_USAGE,STENCIL_USAGE);
Dependency.srcAccessMask:=Dependency.srcAccessMask or am;
Dependency.dstAccessMask:=Dependency.dstAccessMask or am;
end;
Procedure TvRenderPassKey.AddColorAt(id:TVkUInt32;aformat:TVkFormat;IMAGE_USAGE,asamples:Byte);
begin
if (AtdCount>8) then Exit;
ColorAtd[AtdCount]:=Default(TVkAttachmentDescription);
With ColorAtd[AtdCount] do
begin
format :=aformat;
samples:=TVkSampleCountFlagBits(asamples);
stencilLoadOp :=VK_ATTACHMENT_LOAD_OP_DONT_CARE;
stencilStoreOp:=VK_ATTACHMENT_STORE_OP_DONT_CARE;
end;
if (id<>VK_ATTACHMENT_UNUSED) then
begin
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;
With ColorAtd[AtdCount] do
if ((IMAGE_USAGE and TM_READ)<>0) then
begin
initialLayout:=GetColorSendLayout(IMAGE_USAGE);
end else
begin
initialLayout:=VK_IMAGE_LAYOUT_UNDEFINED;
end;
With ColorAtd[AtdCount] do
begin
finalLayout:=GetColorSendLayout(IMAGE_USAGE);
end;
end else
begin
With ColorAtd[AtdCount] do
begin
loadOp :=VK_ATTACHMENT_LOAD_OP_DONT_CARE;
storeOp:=VK_ATTACHMENT_STORE_OP_DONT_CARE;
initialLayout:=VK_IMAGE_LAYOUT_UNDEFINED;
finalLayout :=VK_IMAGE_LAYOUT_GENERAL;
end;
end;
Inc(AtdCount);
_AddColorRef(id,IMAGE_USAGE);
end;
Procedure TvRenderPassKey.AddDepthAt(id:TVkUInt32;aformat:TVkFormat;DEPTH_USAGE,STENCIL_USAGE,asamples:Byte);
begin
if (AtdCount>8) then Exit;
ColorAtd[AtdCount]:=Default(TVkAttachmentDescription);
With ColorAtd[AtdCount] do
begin
format :=aformat;
samples:=TVkSampleCountFlagBits(asamples);
end;
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
begin
initialLayout:=GetDepthStencilInitLayout(DEPTH_USAGE,STENCIL_USAGE);
end;
With ColorAtd[AtdCount] do
begin
finalLayout:=GetDepthStencilSendLayout(DEPTH_USAGE,STENCIL_USAGE);
end;
Inc(AtdCount);
_SetDepthRef(id,DEPTH_USAGE,STENCIL_USAGE);
end;
///
Function TvRenderPass2.Compile:Boolean;
var
r:TVkResult;
subpass:TVkSubpassDescription;
info:TVkRenderPassCreateInfo;
begin
Result:=False;
if (Key.AtdCount=0) and (Key.DepCount=0) then Exit;
if (FHandle<>VK_NULL_HANDLE) then Exit(True);
subpass:=Default(TVkSubpassDescription);
subpass.pipelineBindPoint:=VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.inputAttachmentCount :=0;
subpass.pInputAttachments :=nil;
subpass.colorAttachmentCount :=Key.RefCount;
subpass.pColorAttachments :=@Key.ColorRef;
subpass.pResolveAttachments :=nil; //colorAttachmentCount VK_ATTACHMENT_UNUSED
if (Key.DepCount<>0) then
begin
subpass.pDepthStencilAttachment:=@Key.DepthRef; //1
end;
subpass.preserveAttachmentCount:=0;
subpass.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 :=@subpass;
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;
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(nil); //map ref
FRenderPass2Set.Insert(@t.key);
end;
end;
Result:=t;
end;
function FetchRenderPass(cmd:TvDependenciesObject;P:PvRenderPassKey):TvRenderPass2;
begin
Result:=nil;
if (P=nil) then Exit;
FRenderPass2Set.Lock_wr;
Result:=_FetchRenderPass(P);
cmd.RefTo(Result);
FRenderPass2Set.Unlock_wr;
end;
end.