mirror of https://github.com/red-prig/fpPS4.git
290 lines
4.8 KiB
Plaintext
290 lines
4.8 KiB
Plaintext
unit vHostBufferManager;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
SysUtils,
|
|
g23tree,
|
|
Vulkan,
|
|
vMemory,
|
|
vBuffer,
|
|
vDependence;
|
|
|
|
type
|
|
TvHostBuffer=class(TvBuffer)
|
|
FAddr:QWORD;
|
|
end;
|
|
|
|
function FetchHostBuffer(cmd:TvDependenciesObject;
|
|
Addr:QWORD;
|
|
Size:TVkDeviceSize;
|
|
device_local:Boolean=False):TvHostBuffer;
|
|
|
|
implementation
|
|
|
|
uses
|
|
kern_rwlock,
|
|
kern_dmem;
|
|
|
|
type
|
|
TvHostBufferKey=packed record
|
|
FAddr :QWORD;
|
|
FBuffer:TvHostBuffer;
|
|
end;
|
|
|
|
TvAddrCompare=object
|
|
function c(const a,b:TvHostBufferKey):Integer; static;
|
|
end;
|
|
|
|
_TvHostBufferSet=specialize T23treeSet<TvHostBufferKey,TvAddrCompare>;
|
|
TvHostBufferSet=object(_TvHostBufferSet)
|
|
lock:Pointer;
|
|
Procedure Lock_wr;
|
|
Procedure Unlock_wr;
|
|
end;
|
|
|
|
var
|
|
FHostBufferSet:TvHostBufferSet;
|
|
|
|
|
|
Procedure TvHostBufferSet.Lock_wr;
|
|
begin
|
|
rw_wlock(lock);
|
|
end;
|
|
|
|
Procedure TvHostBufferSet.Unlock_wr;
|
|
begin
|
|
rw_wunlock(lock);
|
|
end;
|
|
|
|
function TvAddrCompare.c(const a,b:TvHostBufferKey):Integer;
|
|
begin
|
|
//1 FAddr
|
|
Result:=Integer(a.FAddr>b.FAddr)-Integer(a.FAddr<b.FAddr);
|
|
if (Result<>0) then Exit;
|
|
end;
|
|
|
|
var
|
|
host_alignment:TVkDeviceSize=0;
|
|
|
|
function _fix_buf_size(var Addr:QWORD;var Size:TVkDeviceSize;usage:TVkFlags):TVkDeviceSize;
|
|
var
|
|
mr:TVkMemoryRequirements;
|
|
begin
|
|
if (host_alignment=0) then
|
|
begin
|
|
mr:=GetRequirements(false,Size,usage,@buf_ext);
|
|
host_alignment:=mr.alignment;
|
|
end;
|
|
|
|
Result:=(Addr mod host_alignment);
|
|
|
|
Addr:=Addr-Result;
|
|
Size:=Size+Result;
|
|
end;
|
|
|
|
function _FindHostBuffer(Addr:QWORD;Size:TVkDeviceSize):TvHostBuffer;
|
|
label
|
|
_repeat,
|
|
_delete;
|
|
var
|
|
It:TvHostBufferSet.Iterator;
|
|
tmp:TvHostBufferKey;
|
|
buf:TvHostBuffer;
|
|
__end:QWORD;
|
|
begin
|
|
Result:=nil;
|
|
__end:=Addr+Size;
|
|
|
|
_repeat:
|
|
|
|
tmp:=Default(TvHostBufferKey);
|
|
tmp.FAddr :=Addr;
|
|
|
|
It:=FHostBufferSet.find(tmp);
|
|
|
|
if (It.Item<>nil) then
|
|
begin
|
|
buf:=It.Item^.FBuffer;
|
|
|
|
if buf.Hold(nil) then
|
|
begin
|
|
|
|
if ((buf.FAddr+buf.FSize)>=__end) then
|
|
begin
|
|
Exit(buf);
|
|
end else
|
|
begin
|
|
buf.Drop(nil);
|
|
//The search key matches but the size does not.
|
|
goto _delete;
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
_delete:
|
|
//mem is deleted, free buf
|
|
FHostBufferSet.erase(It);
|
|
buf.Release(nil); //map ref
|
|
buf:=nil;
|
|
goto _repeat;
|
|
end;
|
|
|
|
end;
|
|
|
|
tmp:=Default(TvHostBufferKey);
|
|
tmp.FAddr :=__end;
|
|
|
|
//[s|new|e] ->
|
|
// [s|old|e]
|
|
|
|
It:=FHostBufferSet.find_ls(tmp);
|
|
|
|
while (It.Item<>nil) do
|
|
begin
|
|
buf:=It.Item^.FBuffer;
|
|
|
|
if buf.Hold(nil) then
|
|
begin
|
|
|
|
if (buf.FAddr<=Addr) and
|
|
((buf.FAddr+buf.FSize)>=__end) then
|
|
begin
|
|
Exit(buf);
|
|
end;
|
|
|
|
buf.Drop(nil);
|
|
end else
|
|
begin
|
|
goto _delete;
|
|
end;
|
|
|
|
if not It.Prev then Break;
|
|
end;
|
|
|
|
end;
|
|
|
|
const
|
|
ALL_BUFFER_USAGE=
|
|
ord(VK_BUFFER_USAGE_TRANSFER_SRC_BIT) or
|
|
ord(VK_BUFFER_USAGE_TRANSFER_DST_BIT) or
|
|
ord(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) or
|
|
ord(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) or
|
|
ord(VK_BUFFER_USAGE_INDEX_BUFFER_BIT) or
|
|
ord(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) or
|
|
ord(VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
|
|
|
|
function FetchHostBuffer(cmd:TvDependenciesObject;
|
|
Addr:QWORD;
|
|
Size:TVkDeviceSize;
|
|
device_local:Boolean=False):TvHostBuffer;
|
|
label
|
|
_repeat;
|
|
var
|
|
dmem_addr:QWORD;
|
|
key:TvHostBufferKey;
|
|
mem:TvPointer;
|
|
begin
|
|
Result:=nil;
|
|
Assert(Size<>0);
|
|
|
|
dmem_addr:=QWORD(get_dmem_ptr(Pointer(Addr)));
|
|
|
|
dmem_addr:=dmem_addr-_fix_buf_size(Addr,Size,ALL_BUFFER_USAGE);
|
|
|
|
key:=Default(TvHostBufferKey);
|
|
key.FAddr:=Addr;
|
|
|
|
//
|
|
FHostBufferSet.Lock_wr;
|
|
//
|
|
|
|
_repeat:
|
|
|
|
key.FBuffer:=_FindHostBuffer(Addr,Size);
|
|
|
|
//
|
|
FHostBufferSet.Unlock_wr;
|
|
//
|
|
|
|
if (key.FBuffer=nil) then
|
|
begin
|
|
//create new
|
|
|
|
mem:=MemManager.FetchHostMap(dmem_addr,Size,device_local);
|
|
|
|
if (mem.FMemory=nil) then
|
|
begin
|
|
if device_local then
|
|
begin
|
|
mem:=MemManager.FetchHostMap(dmem_addr,Size,False);
|
|
end;
|
|
end;
|
|
|
|
if (mem.FMemory=nil) then
|
|
begin
|
|
//try shrink?
|
|
//ENOMEM
|
|
Exit(nil);
|
|
end;
|
|
|
|
key.FBuffer:=TvHostBuffer.Create(Size,ALL_BUFFER_USAGE,@buf_ext);
|
|
key.FBuffer.FAddr:=Addr;
|
|
|
|
key.FBuffer.SetObjectName('HB_0x'+HexStr(Addr,10)+'..'+HexStr(Addr+Size,10));
|
|
|
|
if (key.FBuffer.BindMem(mem)<>VK_SUCCESS) then
|
|
begin
|
|
//unknow error
|
|
FreeAndNil(key.FBuffer);
|
|
mem.Release; //release [FetchHostMap]
|
|
//
|
|
Exit(nil);
|
|
end;
|
|
|
|
//
|
|
FHostBufferSet.Lock_wr;
|
|
//
|
|
|
|
if FHostBufferSet.Insert(key) then
|
|
begin
|
|
key.FBuffer.Acquire(nil); //map ref
|
|
end else
|
|
begin
|
|
//collision?
|
|
|
|
FreeAndNil(key.FBuffer);
|
|
mem.Release; //release [FetchHostMap]
|
|
|
|
//
|
|
goto _repeat;
|
|
end;
|
|
|
|
key.FBuffer.Hold(nil); //analog ref in [_FindHostBuffer]
|
|
mem.Release; //release [FetchHostMap]
|
|
|
|
//
|
|
FHostBufferSet.Unlock_wr;
|
|
//
|
|
|
|
//create new
|
|
end;
|
|
|
|
Result:=key.FBuffer;
|
|
|
|
//add dep
|
|
cmd.RefTo(Result);
|
|
|
|
if (Result<>nil) then
|
|
begin
|
|
Result.Drop(nil); //release [_FindHostBuffer]
|
|
end;
|
|
end;
|
|
|
|
|
|
end.
|
|
|
|
|