mirror of
https://github.com/red-prig/fpPS4.git
synced 2024-11-23 06:19:57 +00:00
2e04d5d3fa
* Unit names should match with file names to avoid case sensitive issue on Unix system * Explicit state the build is for win64 target
1040 lines
25 KiB
ObjectPascal
1040 lines
25 KiB
ObjectPascal
unit vFlip;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes,
|
|
SysUtils,
|
|
ps4_libSceVideoOut,
|
|
Vulkan,
|
|
vDevice,
|
|
vMemory,
|
|
vShader,
|
|
vPipeline,
|
|
vBuffer,
|
|
vImage,
|
|
vImageManager,
|
|
vCmdBuffer;
|
|
|
|
type
|
|
TFlipCfg=packed object
|
|
gamma:array[0..3] of Single;
|
|
Width:array[0..1] of Integer;
|
|
end;
|
|
|
|
Tgamma=array[0..2] of Single;
|
|
|
|
TvFlip=class;
|
|
|
|
PvFlipBufferCursor=^TvFlipBufferCursor;
|
|
TvFlipBufferCursor=object
|
|
FSet:TvDescriptorSet;
|
|
PtrBuf :TvPointer;
|
|
HostBuf :TvBuffer;
|
|
pending:PDWORD;
|
|
procedure SetBuffer(hbuf:TvPointer);
|
|
Procedure Init(Flip:TvFlip);
|
|
Procedure Free;
|
|
function IsPrepare:Boolean;
|
|
Procedure SetPending(f:PDWORD);
|
|
end;
|
|
|
|
PvFlipBuffer=^TvFlipBuffer;
|
|
TvFlipBuffer=object
|
|
|
|
FSet:TvDescriptorSet;
|
|
|
|
cmdbuf:TvCustomCmdBuffer;
|
|
|
|
Extent:TVkExtent3D;
|
|
|
|
PITCH,SIZE:DWORD;
|
|
|
|
DstImgNORM:TvImage; //
|
|
DstImgSRGB:TvImage; //
|
|
|
|
DevcMem:TvPointer; //
|
|
ImgViewDst:TvImageView; //
|
|
|
|
Addr:Pointer;
|
|
PtrBuf:TvPointer; //
|
|
HostBuf:TvBuffer; //
|
|
|
|
Cursors:array[0..SCE_VIDEO_OUT_CURSOR_NUM_MAX-1] of TvFlipBufferCursor;
|
|
|
|
Procedure Init(Flip:TvFlip);
|
|
Procedure Free(Flip:TvFlip);
|
|
function IsPrepare:Boolean;
|
|
end;
|
|
|
|
TVCursorPos=packed record
|
|
X,Y:DWORD;
|
|
end;
|
|
|
|
TvFlipCursor=object
|
|
enable:boolean;
|
|
pos:TVCursorPos;
|
|
PtrBuf:TvPointer;
|
|
pending:PDWORD;
|
|
Procedure Free;
|
|
end;
|
|
|
|
TvFlip=class
|
|
FSurface:TVSurface;
|
|
FSwapChain:TvSwapChain;
|
|
FSetLayout:TvSetLayout;
|
|
FLayout:TvPipelineLayout;
|
|
FPipelineFlip:TvComputePipeline;
|
|
FPipelineCursor:TvComputePipeline;
|
|
|
|
FSetsPool:TvSetsPool;
|
|
|
|
FCmdPool:TvCmdPool;
|
|
Fcfg:TFlipCfg;
|
|
|
|
Fformat,Ftmode:DWORD;
|
|
|
|
cformat:TVkFormat;
|
|
sformat:TVkFormat;
|
|
|
|
Ffilp_shader:TvShaderCompute;
|
|
|
|
Fcursor_shader:TvShaderCompute;
|
|
|
|
FimageAvailableSemaphore:array[0..2] of TvSemaphore; //
|
|
FrenderFinishedSemaphore:array[0..2] of TvSemaphore; //
|
|
|
|
FNeoMode:Boolean;
|
|
|
|
FcurrentFrame:Byte;
|
|
FcurrentBuffer:Byte;
|
|
FBuffers:array[0..15] of TvFlipBuffer;
|
|
|
|
FCursors:array[0..SCE_VIDEO_OUT_CURSOR_NUM_MAX-1] of TvFlipCursor;
|
|
|
|
Constructor Create(Handle:THandle);
|
|
Destructor Destroy; override;
|
|
|
|
Procedure SetCurrentBuffer(Buffer:Byte);
|
|
|
|
Procedure SetImageFormat(format,tmode:DWORD);
|
|
Procedure SetImageSize(width,height:DWORD);
|
|
Procedure SetHostBuffer(Addr:Pointer);
|
|
Procedure SetGamma(gamma:Tgamma);
|
|
|
|
Procedure SetCursor(index:Integer;enable:Boolean;addr:Pointer;pending:PDWORD;pos:TVCursorPos);
|
|
|
|
procedure recreateSwapChain;
|
|
Procedure FixCurrentFrame;
|
|
function IsComplite(currentBuffer:Byte):Boolean;
|
|
Procedure Flip;
|
|
end;
|
|
|
|
var
|
|
SRGB_HACK:Boolean=True;
|
|
|
|
implementation
|
|
|
|
Procedure TvFlipCursor.Free;
|
|
begin
|
|
enable:=False;
|
|
pos:=Default(TVCursorPos);
|
|
pending:=nil;
|
|
PtrBuf:=Default(TvPointer);
|
|
end;
|
|
|
|
Constructor TvFlip.Create(Handle:THandle);
|
|
var
|
|
i:Byte;
|
|
begin
|
|
InitVulkan;
|
|
|
|
Fcfg.gamma[0]:=1;
|
|
Fcfg.gamma[1]:=1;
|
|
Fcfg.gamma[2]:=1;
|
|
Fcfg.gamma[3]:=1;
|
|
Fcfg.Width[0]:=1;
|
|
Fcfg.Width[1]:=1;
|
|
|
|
FSurface:=TVSurface.Create(Handle);
|
|
|
|
FSetLayout:=TvSetLayout.Create;
|
|
FSetLayout.Add(0,VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,ord(VK_SHADER_STAGE_COMPUTE_BIT));
|
|
FSetLayout.Add(1,VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ,ord(VK_SHADER_STAGE_COMPUTE_BIT));
|
|
|
|
FLayout:=TvPipelineLayout.Create;
|
|
FLayout.AddLayout(FSetLayout);
|
|
FLayout.AddPushConst(0,SizeOf(TFlipCfg),ord(VK_SHADER_STAGE_COMPUTE_BIT));
|
|
|
|
FPipelineFlip:=TvComputePipeline.Create;
|
|
FPipelineFlip.SetLayout(FLayout);
|
|
|
|
FSetsPool:=TvSetsPool.Create;
|
|
FSetsPool.AddLayout(FSetLayout,16+16*2);
|
|
|
|
FCmdPool:=TvCmdPool.Create(VulkanApp.FGFamily);
|
|
|
|
For i:=0 to 2 do
|
|
begin
|
|
FimageAvailableSemaphore[i]:=TvSemaphore.Create;
|
|
FrenderFinishedSemaphore[i]:=TvSemaphore.Create;
|
|
end;
|
|
|
|
end;
|
|
|
|
Destructor TvFlip.Destroy;
|
|
var
|
|
i:Byte;
|
|
begin
|
|
FlipQueue.WaitIdle;
|
|
FreeAndNil(Ffilp_shader);
|
|
|
|
For i:=0 to 15 do
|
|
begin
|
|
FBuffers[i].Free(Self);
|
|
end;
|
|
|
|
For i:=0 to 2 do
|
|
begin
|
|
FreeAndNil(FimageAvailableSemaphore[i]);
|
|
FreeAndNil(FrenderFinishedSemaphore[i]);
|
|
end;
|
|
|
|
FreeAndNil(FCmdPool);
|
|
FreeAndNil(FSetsPool);
|
|
FreeAndNil(FPipelineFlip);
|
|
FreeAndNil(FLayout);
|
|
FreeAndNil(FSetLayout);
|
|
FreeAndNil(FSwapChain);
|
|
FreeAndNil(FSurface);
|
|
inherited;
|
|
end;
|
|
|
|
Procedure TvFlipBuffer.Init(Flip:TvFlip);
|
|
begin
|
|
if (FSet=nil) then
|
|
begin
|
|
FSet:=Flip.FSetsPool.Alloc(Flip.FSetLayout);
|
|
end;
|
|
|
|
if (cmdbuf=nil) then
|
|
begin
|
|
cmdbuf:=TvCustomCmdBuffer.Create(Flip.FCmdPool,FlipQueue);
|
|
end;
|
|
end;
|
|
|
|
Procedure TvFlipBuffer.Free(Flip:TvFlip);
|
|
begin
|
|
FreeAndNil(ImgViewDst);
|
|
FreeAndNil(DstImgNORM);
|
|
FreeAndNil(DstImgSRGB);
|
|
FreeAndNil(HostBuf);
|
|
|
|
FreeAndNil(cmdbuf);
|
|
|
|
MemManager.Free(DevcMem);
|
|
DevcMem:=Default(TvPointer);
|
|
Cursors[0].Free;
|
|
Cursors[1].Free;
|
|
end;
|
|
|
|
function TvFlipBuffer.IsPrepare:Boolean;
|
|
begin
|
|
Result:=False;
|
|
if (FSet=nil) then Exit;
|
|
if (cmdbuf=nil) then Exit;
|
|
if (DstImgNORM=nil) then Exit;
|
|
if (ImgViewDst=nil) then Exit;
|
|
if (DevcMem.FHandle=VK_NULL_HANDLE) then Exit;
|
|
if (Extent.width=0) or (Extent.height=0) then Exit;
|
|
if (HostBuf=nil) then Exit;
|
|
Result:=True;
|
|
end;
|
|
|
|
procedure TvFlipBufferCursor.SetBuffer(hbuf:TvPointer);
|
|
const
|
|
buf_ext:TVkExternalMemoryBufferCreateInfo=(
|
|
sType:VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
|
|
pNext:nil;
|
|
handleTypes:ord(VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT);
|
|
);
|
|
begin
|
|
if (PtrBuf.FHandle=hbuf.FHandle) and (PtrBuf.FOffset=hbuf.FOffset) and (HostBuf<>nil) then Exit;
|
|
|
|
PtrBuf:=hbuf;
|
|
FreeAndNil(HostBuf);
|
|
|
|
HostBuf:=TvBuffer.Create(16384,
|
|
ord(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT),
|
|
@buf_ext);
|
|
|
|
HostBuf.BindMem(hbuf);
|
|
end;
|
|
|
|
Procedure TvFlipBufferCursor.Init(Flip:TvFlip);
|
|
begin
|
|
if (FSet=nil) then
|
|
begin
|
|
FSet:=Flip.FSetsPool.Alloc(Flip.FSetLayout);
|
|
end;
|
|
end;
|
|
|
|
Procedure TvFlipBufferCursor.Free;
|
|
begin
|
|
FreeAndNil(FSet);
|
|
FreeAndNil(HostBuf);
|
|
PtrBuf:=Default(TvPointer);
|
|
pending:=nil;
|
|
end;
|
|
|
|
function TvFlipBufferCursor.IsPrepare:Boolean;
|
|
begin
|
|
Result:=False;
|
|
if (FSet=nil) then Exit;
|
|
if (HostBuf=nil) then Exit;
|
|
Result:=True;
|
|
end;
|
|
|
|
Procedure TvFlipBufferCursor.SetPending(f:PDWORD);
|
|
begin
|
|
if (pending<>f) then
|
|
begin
|
|
if (pending<>nil) then System.InterlockedDecrement(pending^);
|
|
pending:=f;
|
|
if (pending<>nil) then System.InterlockedIncrement(pending^);
|
|
end;
|
|
end;
|
|
|
|
Procedure TvFlip.SetCurrentBuffer(Buffer:Byte);
|
|
var
|
|
buf:PvFlipBuffer;
|
|
begin
|
|
if (Buffer>15) then Buffer:=15;
|
|
FcurrentBuffer:=Buffer;
|
|
buf:=@FBuffers[FcurrentBuffer];
|
|
buf^.Init(Self);
|
|
end;
|
|
|
|
Procedure TvFlip.SetImageFormat(format,tmode:DWORD);
|
|
begin
|
|
if (Fformat=format) and (Ftmode=tmode) and (Ffilp_shader<>nil) then Exit;
|
|
|
|
Case format of
|
|
SCE_VIDEO_OUT_PIXEL_FORMAT_A8R8G8B8_SRGB,
|
|
SCE_VIDEO_OUT_PIXEL_FORMAT_A8B8G8R8_SRGB:
|
|
begin
|
|
cformat:=VK_FORMAT_R8G8B8A8_UNORM;
|
|
if SRGB_HACK then
|
|
sformat:=VK_FORMAT_R8G8B8A8_SRGB;
|
|
end;
|
|
end;
|
|
|
|
Case tmode of
|
|
SCE_VIDEO_OUT_TILING_MODE_LINEAR:
|
|
Case format of
|
|
SCE_VIDEO_OUT_PIXEL_FORMAT_A8R8G8B8_SRGB:
|
|
begin
|
|
Fformat:=format;
|
|
Ftmode:=tmode;
|
|
FlipQueue.WaitIdle;
|
|
FreeAndNil(Ffilp_shader);
|
|
Ffilp_shader:=TvShaderCompute.Create;
|
|
|
|
Ffilp_shader.LoadFromResource('FLIP_LINE_A8R8G8B8_SRGB');
|
|
FPipelineFlip.SetShader(Ffilp_shader);
|
|
end;
|
|
else
|
|
Assert(false,HexStr(format,8));
|
|
end;
|
|
SCE_VIDEO_OUT_TILING_MODE_TILE:
|
|
Case format of
|
|
SCE_VIDEO_OUT_PIXEL_FORMAT_A8R8G8B8_SRGB:
|
|
begin
|
|
Fformat:=format;
|
|
Ftmode:=tmode;
|
|
FlipQueue.WaitIdle;
|
|
FreeAndNil(Ffilp_shader);
|
|
Ffilp_shader:=TvShaderCompute.Create;
|
|
|
|
if FNeoMode then
|
|
begin
|
|
Ffilp_shader.LoadFromResource('FLIP_TILE_A8R8G8B8_SRGB_NEO');
|
|
end else
|
|
begin
|
|
Ffilp_shader.LoadFromResource('FLIP_TILE_A8R8G8B8_SRGB');
|
|
end;
|
|
|
|
FPipelineFlip.SetShader(Ffilp_shader);
|
|
end;
|
|
SCE_VIDEO_OUT_PIXEL_FORMAT_A8B8G8R8_SRGB:
|
|
begin
|
|
Fformat:=format;
|
|
Ftmode:=tmode;
|
|
FlipQueue.WaitIdle;
|
|
FreeAndNil(Ffilp_shader);
|
|
Ffilp_shader:=TvShaderCompute.Create;
|
|
|
|
if FNeoMode then
|
|
begin
|
|
Assert(false,'TODO');
|
|
end else
|
|
begin
|
|
Ffilp_shader.LoadFromResource('FLIP_TILE_A8B8G8R8_SRGB');
|
|
end;
|
|
|
|
FPipelineFlip.SetShader(Ffilp_shader);
|
|
end
|
|
else
|
|
Assert(false,HexStr(format,8));
|
|
end;
|
|
else
|
|
Assert(false);
|
|
end;
|
|
|
|
end;
|
|
|
|
function Max(a,b:TVkDeviceSize):TVkDeviceSize; inline;
|
|
begin
|
|
if (a>b) then Result:=a else Result:=b;
|
|
end;
|
|
|
|
Procedure TvFlip.SetImageSize(width,height:DWORD);
|
|
var
|
|
buf:PvFlipBuffer;
|
|
memr:TVkMemoryRequirements;
|
|
memr2:TVkMemoryRequirements;
|
|
begin
|
|
buf:=@FBuffers[FcurrentBuffer];
|
|
|
|
if (buf^.Extent.width=width) and (buf^.Extent.height=height) and (buf^.DstImgNORM<>nil) then Exit;
|
|
buf^.Extent.width :=width;
|
|
buf^.Extent.height:=height;
|
|
buf^.Extent.depth :=1;
|
|
|
|
Case Ftmode of
|
|
SCE_VIDEO_OUT_TILING_MODE_LINEAR:
|
|
Case Fformat of
|
|
SCE_VIDEO_OUT_PIXEL_FORMAT_A8R8G8B8_SRGB,
|
|
SCE_VIDEO_OUT_PIXEL_FORMAT_A8B8G8R8_SRGB:
|
|
begin
|
|
buf^.PITCH:=width;
|
|
buf^.SIZE :=width*height*4;
|
|
end;
|
|
end;
|
|
SCE_VIDEO_OUT_TILING_MODE_TILE:
|
|
Case Fformat of
|
|
SCE_VIDEO_OUT_PIXEL_FORMAT_A8R8G8B8_SRGB,
|
|
SCE_VIDEO_OUT_PIXEL_FORMAT_A8B8G8R8_SRGB:
|
|
begin
|
|
if FNeoMode then
|
|
begin
|
|
buf^.PITCH:=(width+127) div 128;
|
|
buf^.SIZE :=buf^.PITCH*128*((height+127) and (not 127))*4;
|
|
end else
|
|
begin
|
|
buf^.PITCH:=(width+127) div 128;
|
|
buf^.SIZE :=buf^.PITCH*128*((height+63) and (not 63))*4;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
FreeAndNil(buf^.ImgViewDst);
|
|
FreeAndNil(buf^.DstImgNORM);
|
|
FreeAndNil(buf^.DstImgSRGB);
|
|
|
|
MemManager.Free(buf^.DevcMem);
|
|
buf^.DevcMem:=Default(TvPointer);
|
|
|
|
//
|
|
|
|
buf^.DstImgNORM:=TvDeviceImage2D.Create(
|
|
cformat,
|
|
buf^.Extent,
|
|
ord(VK_IMAGE_USAGE_STORAGE_BIT) or
|
|
ord(VK_IMAGE_USAGE_TRANSFER_SRC_BIT) or
|
|
ord(VK_IMAGE_USAGE_TRANSFER_DST_BIT),
|
|
ord(VK_IMAGE_CREATE_ALIAS_BIT)
|
|
);
|
|
|
|
memr:=buf^.DstImgNORM.GetRequirements;
|
|
|
|
if (sformat<>VK_FORMAT_UNDEFINED) then
|
|
begin
|
|
buf^.DstImgSRGB:=TvDeviceImage2D.Create(
|
|
sformat,
|
|
buf^.Extent,
|
|
ord(VK_IMAGE_USAGE_TRANSFER_SRC_BIT) or
|
|
ord(VK_IMAGE_USAGE_TRANSFER_DST_BIT),
|
|
ord(VK_IMAGE_CREATE_ALIAS_BIT)
|
|
);
|
|
|
|
memr2:=buf^.DstImgSRGB.GetRequirements;
|
|
|
|
memr.size :=Max(memr.size ,memr2.size);
|
|
memr.alignment :=Max(memr.alignment,memr2.alignment);
|
|
memr.memoryTypeBits:=memr.memoryTypeBits and memr2.memoryTypeBits;
|
|
end;
|
|
|
|
//Writeln(buf^.DstImg.GetDedicatedAllocation);
|
|
|
|
buf^.DevcMem:=MemManager.Alloc(memr,ord(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
|
|
|
|
buf^.DstImgNORM.BindMem(buf^.DevcMem);
|
|
|
|
if (sformat<>VK_FORMAT_UNDEFINED) then
|
|
buf^.DstImgSRGB.BindMem(buf^.DevcMem);
|
|
|
|
buf^.ImgViewDst:=buf^.DstImgNORM.NewView;
|
|
end;
|
|
|
|
Procedure TvFlip.SetHostBuffer(Addr:Pointer);
|
|
const
|
|
buf_ext:TVkExternalMemoryBufferCreateInfo=(
|
|
sType:VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
|
|
pNext:nil;
|
|
handleTypes:ord(VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT);
|
|
);
|
|
var
|
|
hbuf:TvPointer;
|
|
buf:PvFlipBuffer;
|
|
begin
|
|
buf:=@FBuffers[FcurrentBuffer];
|
|
|
|
hbuf:=Default(TvPointer);
|
|
if not TryGetHostPointerByAddr(addr,hbuf) then Exit;
|
|
|
|
if (buf^.PtrBuf.FHandle=hbuf.FHandle) and (buf^.PtrBuf.FOffset=hbuf.FOffset) and (buf^.HostBuf<>nil) then Exit;
|
|
buf^.PtrBuf:=hbuf;
|
|
FreeAndNil(buf^.HostBuf);
|
|
|
|
buf^.HostBuf:=TvBuffer.Create(buf^.SIZE,
|
|
ord(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT),
|
|
@buf_ext);
|
|
buf^.HostBuf.BindMem(hbuf);
|
|
|
|
buf^.Addr:=Addr;
|
|
end;
|
|
|
|
Procedure TvFlip.SetGamma(gamma:Tgamma);
|
|
begin
|
|
Fcfg.gamma[0]:=gamma[0];
|
|
Fcfg.gamma[1]:=gamma[1];
|
|
Fcfg.gamma[2]:=gamma[2];
|
|
end;
|
|
|
|
Procedure TvFlip.SetCursor(index:Integer;enable:Boolean;addr:Pointer;pending:PDWORD;pos:TVCursorPos);
|
|
var
|
|
hbuf:TvPointer;
|
|
begin
|
|
If (index<0) or (index>=Length(FCursors)) then Exit;
|
|
Case enable of
|
|
True:
|
|
if TryGetHostPointerByAddr(addr,hbuf) then
|
|
begin
|
|
if (FPipelineCursor=nil) then
|
|
begin
|
|
FPipelineCursor:=TvComputePipeline.Create;
|
|
FPipelineCursor.SetLayout(FLayout);
|
|
end;
|
|
|
|
if (Fcursor_shader=nil) then
|
|
begin
|
|
Fcursor_shader:=TvShaderCompute.Create;
|
|
Fcursor_shader.LoadFromResource('FLIP_CURSOR');
|
|
FPipelineCursor.SetShader(Fcursor_shader);
|
|
end;
|
|
|
|
FCursors[index].enable :=true;
|
|
FCursors[index].pos :=pos;
|
|
FCursors[index].pending:=pending;
|
|
FCursors[index].PtrBuf :=hbuf;
|
|
end else
|
|
begin
|
|
FCursors[index].Free;
|
|
end;
|
|
False:FCursors[index].Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TvFlip.recreateSwapChain;
|
|
begin
|
|
Device.WaitIdle;
|
|
FreeAndNil(FSwapChain);
|
|
FSwapChain:=TvSwapChain.Create(FSurface,0{1},ord(VK_IMAGE_USAGE_TRANSFER_DST_BIT));
|
|
end;
|
|
|
|
Procedure TvFlip.FixCurrentFrame;
|
|
begin
|
|
if (FSwapChain=nil) then Exit;
|
|
if (Length(FSwapChain.FImages)=0) then Exit;
|
|
FcurrentFrame:=FcurrentFrame mod Length(FSwapChain.FImages);
|
|
end;
|
|
|
|
function TvFlip.IsComplite(currentBuffer:Byte):Boolean;
|
|
var
|
|
buf:PvFlipBuffer;
|
|
r:TVkResult;
|
|
begin
|
|
Result:=True;
|
|
if (Device=nil) then Exit;
|
|
|
|
buf:=@FBuffers[FcurrentBuffer];
|
|
|
|
if (buf^.cmdbuf=nil) then Exit;
|
|
if (buf^.cmdbuf.Fence=nil) then Exit;
|
|
|
|
if (buf^.cmdbuf.ret=0) then
|
|
begin
|
|
r:=buf^.cmdbuf.Fence.Status;
|
|
Case r of
|
|
VK_SUCCESS :;
|
|
VK_NOT_READY:Exit(False);
|
|
else
|
|
begin
|
|
Writeln(StdErr,'vkGetEventStatus:',r);
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
buf^.cmdbuf.ReleaseResource;
|
|
|
|
buf^.Cursors[0].SetPending(nil);
|
|
buf^.Cursors[1].SetPending(nil);
|
|
end;
|
|
|
|
Procedure TvFlip.Flip;
|
|
var
|
|
r:TVkResult;
|
|
imageIndex:TVkUInt32;
|
|
SwapImage:TvSwapChainImage;
|
|
|
|
imageAvailableSemaphore:TvSemaphore;
|
|
renderFinishedSemaphore:TvSemaphore;
|
|
|
|
buf:PvFlipBuffer;
|
|
|
|
bufcur:PvFlipBufferCursor;
|
|
|
|
FCurSet:TvDescriptorSet;
|
|
|
|
imgBlitRegion:TVkImageBlit;
|
|
FLocalSize:TVkOffset3D;
|
|
|
|
prInfo:TVkPresentInfoKHR;
|
|
|
|
img_reg:TVkImageCopy;
|
|
|
|
ur:TvImage2;
|
|
begin
|
|
if (Device=nil) then Exit;
|
|
|
|
buf:=@FBuffers[FcurrentBuffer];
|
|
|
|
if (Ffilp_shader=nil) then
|
|
begin
|
|
buf^.cmdbuf.ret:=1;
|
|
Exit;
|
|
end;
|
|
|
|
if (not buf^.IsPrepare) or
|
|
(not FSetLayout.Compile) or
|
|
(not FLayout.Compile) or
|
|
(not FPipelineFlip.Compile) or
|
|
(not FSetsPool.Compile) then
|
|
begin
|
|
buf^.cmdbuf.ret:=2;
|
|
Exit;
|
|
end;
|
|
|
|
repeat
|
|
|
|
if (FSwapChain=nil) then recreateSwapChain;
|
|
if (FSwapChain.FHandle=VK_NULL_HANDLE) then
|
|
begin
|
|
recreateSwapChain;
|
|
if (FSwapChain.FHandle=VK_NULL_HANDLE) then
|
|
begin
|
|
buf^.cmdbuf.ret:=3;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
FixCurrentFrame;
|
|
imageAvailableSemaphore:=FimageAvailableSemaphore[FcurrentFrame];
|
|
renderFinishedSemaphore:=FrenderFinishedSemaphore[FcurrentFrame];
|
|
|
|
R:=vkAcquireNextImageKHR(Device.FHandle,
|
|
FSwapChain.FHandle,
|
|
High(uInt64),
|
|
imageAvailableSemaphore.FHandle,
|
|
VK_NULL_HANDLE,
|
|
@imageIndex);
|
|
Case R of
|
|
VK_SUCCESS:Break;
|
|
VK_ERROR_OUT_OF_DATE_KHR,
|
|
VK_SUBOPTIMAL_KHR:recreateSwapChain;
|
|
else
|
|
begin
|
|
Writeln(StdErr,'vkAcquireNextImageKHR:',R);
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
until false;
|
|
SwapImage:=FSwapChain.FImages[imageIndex];
|
|
|
|
//Writeln('>Flip.Fence.Wait');
|
|
if (buf^.cmdbuf.ret=0) then
|
|
begin
|
|
buf^.cmdbuf.Fence.Wait(High(uint64));
|
|
end;
|
|
//Writeln('<Flip.Fence.Wait');
|
|
|
|
buf^.cmdbuf.Fence.Reset;
|
|
buf^.cmdbuf.ReleaseResource;
|
|
|
|
buf^.Cursors[0].SetPending(nil);
|
|
buf^.Cursors[1].SetPending(nil);
|
|
|
|
if not buf^.cmdbuf.BeginCmdBuffer then Exit;
|
|
|
|
ur:=FindImage(buf^.cmdbuf,buf^.Addr,cformat);
|
|
|
|
if (ur=nil) then
|
|
begin
|
|
FCurSet:=buf^.FSet;
|
|
|
|
FCurSet.BindBuf(0,0,
|
|
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
|
buf^.HostBuf.FHandle,
|
|
0,
|
|
buf^.SIZE);
|
|
|
|
FCurSet.BindSTI(1,0,buf^.ImgViewDst.FHandle,VK_IMAGE_LAYOUT_GENERAL);
|
|
|
|
buf^.DstImgNORM.PushBarrier(buf^.cmdbuf.cmdbuf,
|
|
SubresColor,
|
|
ord(VK_ACCESS_SHADER_WRITE_BIT),
|
|
VK_IMAGE_LAYOUT_GENERAL,
|
|
ord(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT));
|
|
|
|
if (buf^.DstImgSRGB<>nil) then
|
|
begin
|
|
buf^.DstImgSRGB.PushBarrier(buf^.cmdbuf.cmdbuf,
|
|
SubresColor,
|
|
ord(VK_ACCESS_SHADER_WRITE_BIT),
|
|
VK_IMAGE_LAYOUT_GENERAL,
|
|
ord(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT));
|
|
end;
|
|
|
|
buf^.cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE,FPipelineFlip.FHandle);
|
|
buf^.cmdbuf.BindLayout(VK_PIPELINE_BIND_POINT_COMPUTE,FLayout);
|
|
|
|
Fcfg.Width[0]:=1;
|
|
Fcfg.Width[1]:=buf^.PITCH;
|
|
|
|
buf^.cmdbuf.PushConstant(VK_PIPELINE_BIND_POINT_COMPUTE,
|
|
ord(VK_SHADER_STAGE_COMPUTE_BIT),
|
|
0,SizeOf(TFlipCfg),@Fcfg);
|
|
|
|
buf^.cmdbuf.BindSet(VK_PIPELINE_BIND_POINT_COMPUTE,0,FCurSet.FHandle);
|
|
|
|
FLocalSize:=TvShaderCompute(FPipelineFlip.FComputeShader).FLocalSize;
|
|
|
|
FLocalSize.x:=(buf^.DstImgNORM.FExtent.width +(FLocalSize.x-1)) div FLocalSize.x;
|
|
FLocalSize.y:=(buf^.DstImgNORM.FExtent.height+(FLocalSize.y-1)) div FLocalSize.y;
|
|
|
|
buf^.cmdbuf.DispatchDirect(FLocalSize.x,FLocalSize.y,1);
|
|
end else
|
|
begin
|
|
|
|
ur.data_usage:=ur.data_usage and (not TM_READ); //reset read
|
|
|
|
ur.PushBarrier(buf^.cmdbuf,
|
|
ord(VK_ACCESS_TRANSFER_READ_BIT),
|
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
|
ord(VK_PIPELINE_STAGE_TRANSFER_BIT));
|
|
|
|
if (buf^.DstImgSRGB<>nil) and (ur.key.cformat=VK_FORMAT_R8G8B8A8_SRGB) then
|
|
begin
|
|
buf^.DstImgSRGB.PushBarrier(buf^.cmdbuf.cmdbuf,
|
|
SubresColor,
|
|
ord(VK_ACCESS_TRANSFER_WRITE_BIT),
|
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
ord(VK_PIPELINE_STAGE_TRANSFER_BIT));
|
|
end else
|
|
begin
|
|
buf^.DstImgNORM.PushBarrier(buf^.cmdbuf.cmdbuf,
|
|
SubresColor,
|
|
ord(VK_ACCESS_TRANSFER_WRITE_BIT),
|
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
ord(VK_PIPELINE_STAGE_TRANSFER_BIT));
|
|
end;
|
|
|
|
|
|
img_reg:=Default(TVkImageCopy);
|
|
img_reg.srcSubresource.aspectMask:=ord(VK_IMAGE_ASPECT_COLOR_BIT);
|
|
img_reg.srcSubresource.layerCount:=1;
|
|
img_reg.dstSubresource.aspectMask:=ord(VK_IMAGE_ASPECT_COLOR_BIT);
|
|
img_reg.dstSubresource.layerCount:=1;
|
|
|
|
img_reg.extent.Create(
|
|
ur.key.params.extend.width,
|
|
ur.key.params.extend.height,
|
|
1);
|
|
|
|
if (buf^.DstImgSRGB<>nil) and (ur.key.cformat=VK_FORMAT_R8G8B8A8_SRGB) then
|
|
begin
|
|
|
|
vkCmdCopyImage(buf^.cmdbuf.cmdbuf,
|
|
ur.FHandle,
|
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
|
buf^.DstImgSRGB.FHandle,
|
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
1,@img_reg);
|
|
|
|
end else
|
|
begin
|
|
|
|
vkCmdCopyImage(buf^.cmdbuf.cmdbuf,
|
|
ur.FHandle,
|
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
|
buf^.DstImgNORM.FHandle,
|
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
1,@img_reg);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
if (FCursors[0].enable or FCursors[1].enable) then
|
|
begin
|
|
buf^.cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE,FPipelineCursor.FHandle);
|
|
|
|
FLocalSize:=TvShaderCompute(FPipelineCursor.FComputeShader).FLocalSize;
|
|
|
|
bufcur:=@buf^.Cursors[0];
|
|
|
|
if FCursors[0].enable then
|
|
begin
|
|
bufcur^.Init(Self);
|
|
bufcur^.SetBuffer(FCursors[0].PtrBuf);
|
|
|
|
if bufcur^.IsPrepare then
|
|
begin
|
|
FCurSet:=bufcur^.FSet;
|
|
|
|
Fcfg.Width[0]:=FCursors[0].pos.x;
|
|
Fcfg.Width[1]:=FCursors[0].pos.y;
|
|
|
|
bufcur^.SetPending(FCursors[0].pending);
|
|
|
|
FCurSet.BindBuf(0,0,
|
|
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
|
bufcur^.HostBuf.FHandle,
|
|
0,
|
|
16384);
|
|
|
|
FCurSet.BindSTI(1,0,buf^.ImgViewDst.FHandle,VK_IMAGE_LAYOUT_GENERAL);
|
|
|
|
if (buf^.DstImgSRGB<>nil) then
|
|
begin
|
|
buf^.DstImgSRGB.PushBarrier(buf^.cmdbuf.cmdbuf,
|
|
SubresColor,
|
|
ord(VK_ACCESS_SHADER_WRITE_BIT),
|
|
VK_IMAGE_LAYOUT_GENERAL,
|
|
ord(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT));
|
|
end else
|
|
begin
|
|
buf^.DstImgNORM.PushBarrier(buf^.cmdbuf.cmdbuf,
|
|
SubresColor,
|
|
ord(VK_ACCESS_SHADER_WRITE_BIT),
|
|
VK_IMAGE_LAYOUT_GENERAL,
|
|
ord(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT));
|
|
end;
|
|
|
|
buf^.cmdbuf.PushConstant(VK_PIPELINE_BIND_POINT_COMPUTE,
|
|
ord(VK_SHADER_STAGE_COMPUTE_BIT),
|
|
0,SizeOf(TFlipCfg),@Fcfg);
|
|
|
|
buf^.cmdbuf.BindSet(VK_PIPELINE_BIND_POINT_COMPUTE,0,FCurSet.FHandle);
|
|
|
|
buf^.cmdbuf.DispatchDirect(64 div FLocalSize.x,64 div FLocalSize.y,1);
|
|
end else
|
|
begin
|
|
bufcur^.Free;
|
|
end;
|
|
end else
|
|
begin
|
|
bufcur^.Free;
|
|
end;
|
|
|
|
bufcur:=@buf^.Cursors[1];
|
|
|
|
if FCursors[1].enable then
|
|
begin
|
|
bufcur^.Init(Self);
|
|
bufcur^.SetBuffer(FCursors[1].PtrBuf);
|
|
|
|
if bufcur^.IsPrepare then
|
|
begin
|
|
FCurSet:=bufcur^.FSet;
|
|
|
|
Fcfg.Width[0]:=FCursors[1].pos.x;
|
|
Fcfg.Width[1]:=FCursors[1].pos.y;
|
|
|
|
bufcur^.SetPending(FCursors[1].pending);
|
|
|
|
FCurSet.BindBuf(0,0,
|
|
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
|
bufcur^.HostBuf.FHandle,
|
|
0,
|
|
16384);
|
|
|
|
FCurSet.BindSTI(1,0,buf^.ImgViewDst.FHandle,VK_IMAGE_LAYOUT_GENERAL);
|
|
|
|
if (buf^.DstImgSRGB<>nil) then
|
|
begin
|
|
buf^.DstImgSRGB.PushBarrier(buf^.cmdbuf.cmdbuf,
|
|
SubresColor,
|
|
ord(VK_ACCESS_SHADER_WRITE_BIT),
|
|
VK_IMAGE_LAYOUT_GENERAL,
|
|
ord(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT));
|
|
end else
|
|
begin
|
|
buf^.DstImgNORM.PushBarrier(buf^.cmdbuf.cmdbuf,
|
|
SubresColor,
|
|
ord(VK_ACCESS_SHADER_WRITE_BIT),
|
|
VK_IMAGE_LAYOUT_GENERAL,
|
|
ord(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT));
|
|
end;
|
|
|
|
buf^.cmdbuf.PushConstant(VK_PIPELINE_BIND_POINT_COMPUTE,
|
|
ord(VK_SHADER_STAGE_COMPUTE_BIT),
|
|
0,SizeOf(TFlipCfg),@Fcfg);
|
|
|
|
buf^.cmdbuf.BindSet(VK_PIPELINE_BIND_POINT_COMPUTE,0,FCurSet.FHandle);
|
|
|
|
buf^.cmdbuf.DispatchDirect(64 div FLocalSize.x,64 div FLocalSize.y,1);
|
|
end else
|
|
begin
|
|
bufcur^.Free;
|
|
end;
|
|
end else
|
|
begin
|
|
bufcur^.Free;
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
buf^.Cursors[0].Free;
|
|
buf^.Cursors[1].Free;
|
|
end;
|
|
|
|
if (buf^.DstImgSRGB<>nil) then
|
|
begin
|
|
buf^.DstImgSRGB.PushBarrier(buf^.cmdbuf.cmdbuf,
|
|
SubresColor,
|
|
ord(VK_ACCESS_TRANSFER_READ_BIT),
|
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
|
ord(VK_PIPELINE_STAGE_TRANSFER_BIT));
|
|
end else
|
|
begin
|
|
buf^.DstImgNORM.PushBarrier(buf^.cmdbuf.cmdbuf,
|
|
SubresColor,
|
|
ord(VK_ACCESS_TRANSFER_READ_BIT),
|
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
|
ord(VK_PIPELINE_STAGE_TRANSFER_BIT));
|
|
end;
|
|
|
|
SwapImage.PushBarrier(buf^.cmdbuf.cmdbuf,
|
|
SubresColor,
|
|
ord(VK_ACCESS_TRANSFER_WRITE_BIT),
|
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
ord(VK_PIPELINE_STAGE_TRANSFER_BIT));
|
|
|
|
imgBlitRegion:=Default(TVkImageBlit);
|
|
imgBlitRegion.srcSubresource.aspectMask:=ord(VK_IMAGE_ASPECT_COLOR_BIT);
|
|
imgBlitRegion.srcSubresource.layerCount:=1;
|
|
imgBlitRegion.dstSubresource.aspectMask:=ord(VK_IMAGE_ASPECT_COLOR_BIT);
|
|
imgBlitRegion.dstSubresource.layerCount:=1;
|
|
imgBlitRegion.srcOffsets[1].x:=buf^.DstImgNORM.FExtent.width;
|
|
imgBlitRegion.srcOffsets[1].y:=buf^.DstImgNORM.FExtent.height;
|
|
imgBlitRegion.srcOffsets[1].z:=1;
|
|
imgBlitRegion.dstOffsets[1].x:=FSwapChain.FSize.width;
|
|
imgBlitRegion.dstOffsets[1].y:=FSwapChain.FSize.height;
|
|
imgBlitRegion.dstOffsets[1].z:=1;
|
|
|
|
if (buf^.DstImgSRGB<>nil) then
|
|
begin
|
|
vkCmdBlitImage(
|
|
buf^.cmdbuf.cmdbuf,
|
|
buf^.DstImgSRGB.FHandle,VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
|
SwapImage.FHandle ,VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
1,@imgBlitRegion,VK_FILTER_LINEAR);
|
|
end else
|
|
begin
|
|
vkCmdBlitImage(
|
|
buf^.cmdbuf.cmdbuf,
|
|
buf^.DstImgNORM.FHandle,VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
|
SwapImage.FHandle ,VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
1,@imgBlitRegion,VK_FILTER_LINEAR);
|
|
end;
|
|
|
|
|
|
SwapImage.PushBarrier(buf^.cmdbuf.cmdbuf,
|
|
SubresColor,
|
|
ord(VK_ACCESS_NONE_KHR),
|
|
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
|
ord(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT));
|
|
|
|
buf^.cmdbuf.EndCmdBuffer;
|
|
|
|
buf^.cmdbuf.AddWaitSemaphore(imageAvailableSemaphore,ord(VK_PIPELINE_STAGE_TRANSFER_BIT));
|
|
buf^.cmdbuf.SignalSemaphore:=renderFinishedSemaphore;
|
|
|
|
if not buf^.cmdbuf.QueueSubmit then
|
|
begin
|
|
//
|
|
end;
|
|
|
|
prInfo:=Default(TVkPresentInfoKHR);
|
|
prInfo.sType :=VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
|
prInfo.waitSemaphoreCount:=1;
|
|
prInfo.pWaitSemaphores :=@renderFinishedSemaphore.FHandle;
|
|
prInfo.swapchainCount :=1;
|
|
prInfo.pSwapchains :=@FSwapChain.FHandle;
|
|
prInfo.pImageIndices :=@imageIndex;
|
|
prInfo.pResults:=nil;
|
|
|
|
if (buf^.cmdbuf.ret<>0) then
|
|
begin
|
|
prInfo.waitSemaphoreCount:=0;
|
|
prInfo.pWaitSemaphores :=nil;
|
|
end;
|
|
|
|
R:=FlipQueue.PresentKHR(@prInfo);
|
|
Case R of
|
|
VK_SUCCESS:;
|
|
VK_ERROR_OUT_OF_DATE_KHR,
|
|
VK_SUBOPTIMAL_KHR:recreateSwapChain;
|
|
else
|
|
begin
|
|
Writeln(StdErr,'vkQueuePresentKHR:',R);
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
FcurrentFrame:=FcurrentFrame+1;
|
|
FixCurrentFrame;
|
|
end;
|
|
|
|
|
|
|
|
end.
|
|
|