mirror of https://github.com/red-prig/fpPS4.git
260 lines
4.2 KiB
Plaintext
260 lines
4.2 KiB
Plaintext
unit vHostBufferManager;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
SysUtils,
|
|
g23tree,
|
|
Vulkan,
|
|
vDevice,
|
|
vMemory,
|
|
vBuffer,
|
|
vDependence;
|
|
|
|
type
|
|
TvHostBuffer=class(TvBuffer)
|
|
FAddr:QWORD;
|
|
end;
|
|
|
|
function FetchHostBuffer(cmd:TvDependenciesObject;
|
|
Addr:QWORD;
|
|
Size:TVkDeviceSize;
|
|
usage:TVkFlags;
|
|
device_local:Boolean=False):TvHostBuffer;
|
|
|
|
implementation
|
|
|
|
uses
|
|
kern_rwlock,
|
|
kern_dmem;
|
|
|
|
type
|
|
TvHostBufferKey=packed record
|
|
FAddr :QWORD;
|
|
FUsage :TVkFlags;
|
|
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;
|
|
//2 FUsage
|
|
Result:=Integer(a.FUsage>b.FUsage)-Integer(a.FUsage<b.FUsage);
|
|
end;
|
|
|
|
function _fix_buf_size(var Addr:QWORD;var Size:TVkDeviceSize;usage:TVkFlags):TVkDeviceSize;
|
|
var
|
|
mr:TVkMemoryRequirements;
|
|
begin
|
|
mr:=GetRequirements(false,Size,usage,@buf_ext);
|
|
|
|
Result:=(Addr mod mr.alignment);
|
|
|
|
Addr:=Addr-Result;
|
|
Size:=Size+Result;
|
|
end;
|
|
|
|
function _FindHostBuffer(Addr:QWORD;Size:TVkDeviceSize;usage:TVkFlags):TvHostBuffer;
|
|
label
|
|
_repeat;
|
|
var
|
|
It:TvHostBufferSet.Iterator;
|
|
tmp:TvHostBufferKey;
|
|
buf:TvHostBuffer;
|
|
__end:QWORD;
|
|
begin
|
|
Result:=nil;
|
|
__end:=Addr+Size;
|
|
|
|
tmp:=Default(TvHostBufferKey);
|
|
tmp.FAddr :=__end;
|
|
tmp.FUsage:=High(TVkFlags);
|
|
|
|
//[s|new|e] ->
|
|
// [s|old|e]
|
|
|
|
_repeat:
|
|
|
|
It:=FHostBufferSet.find_ls(tmp);
|
|
|
|
while (It.Item<>nil) do
|
|
begin
|
|
buf:=It.Item^.FBuffer;
|
|
|
|
if buf.Acquire(nil) then
|
|
begin
|
|
|
|
if (buf.FAddr<=Addr) and
|
|
((buf.FAddr+buf.FSize)>=__end) and
|
|
((buf.FUsage and usage)=usage) then
|
|
begin
|
|
Exit(buf);
|
|
end;
|
|
|
|
buf.Release(nil);
|
|
end else
|
|
begin
|
|
//mem is deleted, free buf
|
|
FHostBufferSet.erase(It);
|
|
buf._Release(nil); //map ref
|
|
buf:=nil;
|
|
goto _repeat;
|
|
end;
|
|
|
|
if not It.Prev then Break;
|
|
end;
|
|
|
|
end;
|
|
|
|
function FetchHostBuffer(cmd:TvDependenciesObject;
|
|
Addr:QWORD;
|
|
Size:TVkDeviceSize;
|
|
usage:TVkFlags;
|
|
device_local:Boolean=False):TvHostBuffer;
|
|
label
|
|
_repeat;
|
|
var
|
|
dmem_addr:QWORD;
|
|
key:TvHostBufferKey;
|
|
mem:TvPointer;
|
|
begin
|
|
Result:=nil;
|
|
Assert(Size<>0);
|
|
|
|
dmem_addr:=0;
|
|
if not get_dmem_ptr(Pointer(Addr),@dmem_addr,nil) then
|
|
begin
|
|
Assert(false,'addr:0x'+HexStr(Pointer(Addr))+' not in dmem!');
|
|
end;
|
|
|
|
dmem_addr:=dmem_addr-_fix_buf_size(Addr,Size,usage);
|
|
|
|
key:=Default(TvHostBufferKey);
|
|
key.FAddr :=Addr;
|
|
key.FUsage:=usage;
|
|
|
|
//
|
|
FHostBufferSet.Lock_wr;
|
|
//
|
|
|
|
_repeat:
|
|
|
|
key.FBuffer:=_FindHostBuffer(Addr,Size,usage);
|
|
|
|
//
|
|
FHostBufferSet.Unlock_wr;
|
|
//
|
|
|
|
if (key.FBuffer<>nil) then
|
|
begin
|
|
//
|
|
end else
|
|
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);
|
|
|
|
if (mem.FMemory=nil) then
|
|
begin
|
|
//ENOMEM
|
|
Exit(nil);
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
//ENOMEM
|
|
Exit(nil);
|
|
end;
|
|
|
|
end;
|
|
|
|
key.FBuffer:=TvHostBuffer.Create(Size,usage,@buf_ext);
|
|
key.FBuffer.FAddr:=Addr;
|
|
|
|
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;
|
|
|
|
//
|
|
FHostBufferSet.Unlock_wr;
|
|
//
|
|
|
|
//create new
|
|
end;
|
|
|
|
Result:=key.FBuffer;
|
|
|
|
//add dep
|
|
cmd.RefTo(Result);
|
|
|
|
if (Result<>nil) then
|
|
begin
|
|
Result.Release(nil); //release [FetchHostMap]/[_FindHostBuffer]
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
end.
|
|
|
|
|