mirror of https://github.com/red-prig/fpPS4.git
714 lines
14 KiB
Plaintext
714 lines
14 KiB
Plaintext
unit dev_gc;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
{$CALLING SysV_ABI_CDecl}
|
|
|
|
interface
|
|
|
|
uses
|
|
sys_conf;
|
|
|
|
procedure gc_initialize();
|
|
|
|
implementation
|
|
|
|
uses
|
|
errno,
|
|
kern_mtx,
|
|
sys_event,
|
|
kern_authinfo,
|
|
vm,
|
|
vmparam,
|
|
vm_pmap,
|
|
sys_vm_object,
|
|
vm_pager,
|
|
vm_map,
|
|
vm_mmap,
|
|
kern_rwlock,
|
|
kern_proc,
|
|
kern_thr,
|
|
md_sleep,
|
|
pm4defs,
|
|
pm4_ring,
|
|
pm4_stream,
|
|
pm4_pfp,
|
|
pm4_me,
|
|
|
|
dev_dce,
|
|
|
|
vDevice,
|
|
vMemory,
|
|
|
|
sys_bootparam,
|
|
|
|
subr_backtrace;
|
|
|
|
var
|
|
gc_page:Pointer;
|
|
|
|
gc_submits_allowed_vaddr:PInteger=nil; //0=true,1=false (0xfe0100000)
|
|
gc_submits_allowed_vmirr:PInteger=nil;
|
|
|
|
gc_knl_lock:mtx;
|
|
gc_knlist:t_knlist;
|
|
|
|
procedure unmap_dmem_gc(start,__end:DWORD); public;
|
|
begin
|
|
if (MemManager<>nil) then
|
|
begin
|
|
MemManager.unmap_host(start,__end);
|
|
end;
|
|
end;
|
|
|
|
function mmap_addr(paddr,psize:QWORD;
|
|
prot:Integer;
|
|
pout_addr:PQWORD):Integer;
|
|
var
|
|
map:vm_map_t;
|
|
begin
|
|
if ((psize and $3fff)=0) and ((prot and $33)=prot) then
|
|
begin
|
|
map:=@p_vmspace(p_proc.p_vmspace)^.vm_map;
|
|
|
|
if (paddr=0) and ((g_appinfo.mmap_flags and 2)<>0) then
|
|
begin
|
|
paddr:=QWORD($fc0000000);
|
|
end;
|
|
|
|
Result:=vm_mmap2(map,
|
|
@paddr,psize,
|
|
prot,prot,
|
|
MAP_ANON or MAP_SYSTEM or MAP_SHARED,OBJT_DEFAULT,
|
|
nil,0);
|
|
|
|
if (Result=0) then
|
|
begin
|
|
vm_map_set_name(map,paddr,paddr+psize,'SceAppCommArea');
|
|
|
|
pout_addr^:=paddr;
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
Result:=EINVAL;
|
|
end;
|
|
end;
|
|
|
|
type
|
|
p_SetGsRingSizes=^t_SetGsRingSizes;
|
|
t_SetGsRingSizes=packed record
|
|
esgsRingSize:DWORD;
|
|
gsvsRingSize:DWORD;
|
|
zero :DWORD;
|
|
end;
|
|
|
|
p_SetMipStatsReport=^t_SetMipStatsReport;
|
|
t_SetMipStatsReport=packed record
|
|
p_type:DWORD;
|
|
param1:DWORD;
|
|
param2:DWORD;
|
|
param3:DWORD;
|
|
end;
|
|
|
|
p_submit_args=^t_submit_args;
|
|
t_submit_args=packed record
|
|
pid :DWORD;
|
|
count:DWORD;
|
|
cmds :PQWORD;
|
|
eop_v:QWORD;
|
|
wait :Integer;
|
|
end;
|
|
|
|
var
|
|
ring_gfx :t_pm4_ring;
|
|
ring_gfx_lock :Pointer=nil;
|
|
ring_gfx_event:PRTLEvent=nil;
|
|
|
|
GC_SRI_event:PRTLEvent=nil;
|
|
GC_SRI_label:QWORD=0;
|
|
|
|
parse_gfx_started:Pointer=nil;
|
|
parse_gfx_td:p_kthread;
|
|
|
|
pfp_ctx:t_pfp_ctx;
|
|
|
|
pm4_me_gfx:t_pm4_me;
|
|
|
|
procedure onEventWriteEop(pctx:p_pfp_ctx;Body:PPM4CMDEVENTWRITEEOP);
|
|
var
|
|
submit_id:DWORD;
|
|
begin
|
|
submit_id:=Body^.DATA;
|
|
|
|
if p_print_gpu_ops then
|
|
begin
|
|
Writeln('submit_eop_flip=0x',HexStr(submit_id,8));
|
|
end;
|
|
|
|
pctx^.stream[stGfxDcb].SubmitFlipEop(Body^.DATA,Body^.intSel);
|
|
end;
|
|
|
|
function pm4_parse_ring(pctx:p_pfp_ctx;token:DWORD;buff:Pointer):Integer;
|
|
var
|
|
ibuf:t_pm4_ibuffer;
|
|
i:Integer;
|
|
begin
|
|
Result:=0;
|
|
|
|
case token of
|
|
$c0023300:
|
|
begin
|
|
if p_print_gpu_ops then
|
|
begin
|
|
Writeln('INDIRECT_BUFFER (ccb) 0x',HexStr(PPM4CMDINDIRECTBUFFER(buff)^.ibBase,10));
|
|
end;
|
|
if pm4_ibuf_init(@ibuf,buff,@pm4_parse_ccb,stGfxCcb) then
|
|
begin
|
|
i:=pm4_ibuf_parse(pctx,@ibuf);
|
|
if (i<>0) then
|
|
begin
|
|
pctx^.add_stall(@ibuf);
|
|
end;
|
|
|
|
//pm4_me_gfx.Push(pfp_ctx.stream[stGfxCcb]);
|
|
end;
|
|
end;
|
|
$c0023f00:
|
|
begin
|
|
if p_print_gpu_ops then
|
|
begin
|
|
Writeln('INDIRECT_BUFFER (dcb) 0x',HexStr(PPM4CMDINDIRECTBUFFER(buff)^.ibBase,10));
|
|
end;
|
|
if pm4_ibuf_init(@ibuf,buff,@pm4_parse_dcb,stGfxDcb) then
|
|
begin
|
|
i:=pm4_ibuf_parse(pctx,@ibuf);
|
|
if (i<>0) then
|
|
begin
|
|
pctx^.add_stall(@ibuf);
|
|
end;
|
|
|
|
//pm4_me_gfx.Push(pfp_ctx.stream[stGfxDcb]);
|
|
end;
|
|
end;
|
|
$c0008b00:
|
|
begin
|
|
if p_print_gpu_ops then
|
|
begin
|
|
Writeln('SWITCH_BUFFER');
|
|
end;
|
|
end;
|
|
$C0044700: //IT_EVENT_WRITE_EOP
|
|
begin
|
|
onEventWriteEop(pctx,buff);
|
|
end
|
|
else;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure parse_gfx_ring(parameter:pointer); SysV_ABI_CDecl;
|
|
var
|
|
buff:Pointer;
|
|
i,size:DWORD;
|
|
|
|
ibuf:t_pm4_ibuffer;
|
|
buft:t_pm4_stream_type;
|
|
begin
|
|
|
|
if LoadVulkan then
|
|
begin
|
|
InitVulkan;
|
|
end;
|
|
|
|
repeat
|
|
|
|
if gc_ring_pm4_peek(@ring_gfx,@size,@buff) then
|
|
begin
|
|
//Writeln('packet:0x',HexStr(buff),':',size);
|
|
|
|
if pm4_ibuf_init(@ibuf,buff,size,@pm4_parse_ring,stGfxRing) then
|
|
begin
|
|
i:=pm4_ibuf_parse(@pfp_ctx,@ibuf);
|
|
|
|
if (i<>0) then
|
|
begin
|
|
//pm4_me_gfx.Push(pfp_ctx.stream_dcb);
|
|
//pm4_me_gfx.Push(pfp_ctx.stream_ccb);
|
|
|
|
pfp_ctx.add_stall(@ibuf);
|
|
end;
|
|
|
|
end;
|
|
|
|
gc_ring_pm4_drain(@ring_gfx,size);
|
|
|
|
//
|
|
for buft:=Low(t_pm4_stream_type) to High(t_pm4_stream_type) do
|
|
begin
|
|
pfp_ctx.Flush_stream(buft);;
|
|
end;
|
|
//
|
|
Continue;
|
|
end;
|
|
|
|
pm4_me_gfx.on_idle();
|
|
|
|
RTLEventWaitFor(ring_gfx_event);
|
|
until false;
|
|
|
|
|
|
end;
|
|
|
|
procedure start_gfx_ring;
|
|
begin
|
|
if (System.InterlockedExchange(parse_gfx_started,Pointer(1))=nil) then
|
|
begin
|
|
pfp_ctx.init;
|
|
pfp_ctx.on_flush_stream:=@pm4_me_gfx.Push;
|
|
|
|
ring_gfx_event:=RTLEventCreate;
|
|
GC_SRI_event :=RTLEventCreate;
|
|
|
|
kthread_add(@parse_gfx_ring,nil,@parse_gfx_td,(8*1024*1024) div (16*1024),'[GFX_PFP]');
|
|
end;
|
|
end;
|
|
|
|
procedure trigger_gfx_ring;
|
|
begin
|
|
if (ring_gfx_event<>nil) then
|
|
begin
|
|
RTLEventSetEvent(ring_gfx_event);
|
|
end;
|
|
end;
|
|
|
|
procedure gc_wait_GC_SRI;
|
|
begin
|
|
if (GC_SRI_label=0) then Exit;
|
|
|
|
if (GC_SRI_event<>nil) then
|
|
begin
|
|
RTLEventWaitFor(GC_SRI_event);
|
|
end;
|
|
end;
|
|
|
|
procedure gc_idle; register;
|
|
begin
|
|
if (GC_SRI_event<>nil) then
|
|
begin
|
|
RTLEventSetEvent(GC_SRI_event);
|
|
end;
|
|
GC_SRI_label:=0;
|
|
|
|
if (gc_submits_allowed_vmirr<>nil) then
|
|
begin
|
|
gc_submits_allowed_vmirr^:=0; //true
|
|
end;
|
|
end;
|
|
|
|
procedure gc_imdone;
|
|
var
|
|
prev:QWORD;
|
|
begin
|
|
if (GC_SRI_event=nil) then Exit;
|
|
if (pm4_me_gfx.started=nil) then Exit;
|
|
|
|
gc_wait_GC_SRI;
|
|
|
|
prev:=System.InterlockedExchange64(GC_SRI_label,1);
|
|
|
|
if (prev=0) then
|
|
begin
|
|
|
|
if (gc_submits_allowed_vmirr<>nil) then
|
|
begin
|
|
gc_submits_allowed_vmirr^:=1; //false
|
|
end;
|
|
|
|
pm4_me_gfx.imdone;
|
|
end;
|
|
|
|
end;
|
|
|
|
Function gc_ioctl(dev:p_cdev;cmd:QWORD;data:Pointer;fflag:Integer):Integer;
|
|
var
|
|
vaddr:QWORD;
|
|
begin
|
|
Result:=0;
|
|
|
|
Writeln('gc_ioctl(0x',HexStr(cmd,8),')');
|
|
|
|
case cmd of
|
|
$C0108120: //call in neo mode (Tca)
|
|
begin
|
|
Exit(19);
|
|
end;
|
|
|
|
$C004811F: //sceGnmGetNumTcaUnits -> 0x01
|
|
//ext_gpu_timer -> 0x08
|
|
begin
|
|
PInteger(data)^:=0;
|
|
end;
|
|
|
|
$C00C8110: //sceGnmSetGsRingSizes
|
|
begin
|
|
Writeln('SetGsRingSizes(0x',HexStr(p_SetGsRingSizes(data)^.esgsRingSize,8),',0x'
|
|
,HexStr(p_SetGsRingSizes(data)^.gsvsRingSize,8),')');
|
|
pfp_ctx.set_esgs_gsvs_ring_size(p_SetGsRingSizes(data)^.esgsRingSize,
|
|
p_SetGsRingSizes(data)^.gsvsRingSize);
|
|
end;
|
|
|
|
$C0848119: //*MipStatsReport
|
|
begin
|
|
case PInteger(data)^ of
|
|
$10001:
|
|
begin
|
|
Writeln('MipStatsReport(0x',HexStr(p_SetMipStatsReport(data)^.param1,8),',0x'
|
|
,HexStr(p_SetMipStatsReport(data)^.param2,8),',0x'
|
|
,HexStr(p_SetMipStatsReport(data)^.param3,8),')');
|
|
end;
|
|
|
|
$18001:; //diag?
|
|
|
|
else
|
|
Exit(EINVAL);
|
|
end;
|
|
end;
|
|
$C008811B: //sceGnmAreSubmitsAllowed
|
|
begin
|
|
if (gc_submits_allowed_vaddr=nil) then
|
|
begin
|
|
vaddr:=0;
|
|
Result:=mmap_addr($fe0100000,$4000,1,@vaddr);
|
|
|
|
if (Result<>0) then
|
|
begin
|
|
Result:=ENOMEM;
|
|
Exit;
|
|
end;
|
|
|
|
gc_submits_allowed_vaddr:=Pointer(vaddr);
|
|
gc_submits_allowed_vmirr:=mirror_map(vaddr,$4000);
|
|
end;
|
|
|
|
PPointer(data)^:=gc_submits_allowed_vaddr;
|
|
|
|
gc_submits_allowed_vmirr^:=0; //init true
|
|
end;
|
|
|
|
$C010810B: //get cu mask
|
|
begin
|
|
PInteger(data)[0]:=$10; //& 0x3ff GC SE0 Redundant CU: 0x10
|
|
PInteger(data)[1]:=$10; //& 0x3ff GC SE1 Redundant CU: 0x10
|
|
PInteger(data)[2]:=$00; //& 0x3ff GC SE2 Redundant CU: 0x00
|
|
PInteger(data)[3]:=$00; //& 0x3ff GC SE3 Redundant CU: 0x00
|
|
end;
|
|
|
|
$C0048116: //sceGnmSubmitDone
|
|
begin
|
|
Writeln('sceGnmSubmitDone');
|
|
|
|
gc_imdone;
|
|
end;
|
|
|
|
$C0048117: //wait idle
|
|
begin
|
|
Writeln('gc_wait_idle');
|
|
|
|
gc_wait_GC_SRI;
|
|
end;
|
|
|
|
$C0048114: //sceGnmFlushGarlic
|
|
begin
|
|
Writeln('sceGnmFlushGarlic');
|
|
|
|
MemManager.Flush;
|
|
end;
|
|
|
|
$C0108102: //submit
|
|
begin
|
|
start_gfx_ring;
|
|
|
|
rw_wlock(ring_gfx_lock);
|
|
|
|
Result:=gc_submit_internal(@ring_gfx,
|
|
p_submit_args(data)^.count,
|
|
p_submit_args(data)^.cmds);
|
|
|
|
rw_wunlock(ring_gfx_lock);
|
|
|
|
trigger_gfx_ring;
|
|
end;
|
|
|
|
$C020810C: //submit eop
|
|
begin
|
|
start_gfx_ring;
|
|
|
|
rw_wlock(ring_gfx_lock);
|
|
|
|
Result:=gc_submit_internal(@ring_gfx,
|
|
p_submit_args(data)^.count,
|
|
p_submit_args(data)^.cmds);
|
|
|
|
if (Result=0) then
|
|
begin
|
|
{
|
|
The original data is an incremental "submit_id | (vmid << 32)",
|
|
now this is directly sended "eop_v"
|
|
}
|
|
|
|
Result:=gc_pm4_event_write_eop(@ring_gfx,
|
|
nil,
|
|
p_submit_args(data)^.eop_v,
|
|
1,
|
|
p_submit_args(data)^.wait
|
|
);
|
|
end;
|
|
|
|
rw_wunlock(ring_gfx_lock);
|
|
|
|
trigger_gfx_ring;
|
|
end;
|
|
|
|
$C0088101: //switch_buffer
|
|
begin
|
|
start_gfx_ring;
|
|
|
|
rw_wlock(ring_gfx_lock);
|
|
|
|
Result:=gc_switch_buffer_internal(@ring_gfx);
|
|
|
|
rw_wunlock(ring_gfx_lock);
|
|
|
|
trigger_gfx_ring;
|
|
end;
|
|
|
|
|
|
else
|
|
begin
|
|
print_error_td('gc_ioctl(0x'+HexStr(cmd,8)+')');
|
|
Assert(False);
|
|
Result:=EINVAL;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
Function gc_mmap_single(cdev:p_cdev;offset:p_vm_ooffset_t;size:vm_size_t;objp:p_vm_object_t;nprot:Integer):Integer;
|
|
var
|
|
obj:vm_object_t;
|
|
begin
|
|
if sceSblACMgrHasUseHp3dPipeCapability(@g_authinfo) then
|
|
begin
|
|
Exit(EINVAL);
|
|
end;
|
|
|
|
if (offset^>=PAGE_SIZE) then
|
|
begin
|
|
Exit(EPERM);
|
|
end;
|
|
|
|
if (size<>PAGE_SIZE) then
|
|
begin
|
|
Exit(EINVAL);
|
|
end;
|
|
|
|
obj:=vm_pager_allocate(OBJT_DEVICE,cdev,PAGE_SIZE,nprot,offset^);
|
|
obj^.flags:=obj^.flags or OBJ_DMEM_EXT;
|
|
obj^.un_pager.map_base:=gc_page;
|
|
|
|
if (obj=nil) then
|
|
begin
|
|
Exit(EINVAL);
|
|
end;
|
|
|
|
objp^:=obj;
|
|
|
|
Result:=0;
|
|
end;
|
|
|
|
Function gc_mmap(dev:p_cdev;offset:vm_ooffset_t;paddr:p_vm_paddr_t;nprot:Integer;memattr:p_vm_memattr_t):Integer;
|
|
begin
|
|
if sceSblACMgrHasUseHp3dPipeCapability(@g_authinfo) then
|
|
begin
|
|
Exit(EINVAL);
|
|
end;
|
|
|
|
if (offset>=PAGE_SIZE) then
|
|
begin
|
|
Exit(EPERM);
|
|
end;
|
|
|
|
paddr^:=offset + (QWORD(gc_page)-VM_MIN_GPU_ADDRESS);
|
|
memattr^:=0;
|
|
|
|
Result:=0;
|
|
end;
|
|
|
|
const
|
|
gc_cdevsw:t_cdevsw=(
|
|
d_version :D_VERSION;
|
|
d_flags :0;
|
|
d_name :'gc';
|
|
d_open :nil;
|
|
d_fdopen :nil;
|
|
d_close :nil;
|
|
d_read :nil;
|
|
d_write :nil;
|
|
d_ioctl :@gc_ioctl;
|
|
d_poll :nil;
|
|
d_mmap :@gc_mmap;
|
|
d_strategy :nil;
|
|
d_dump :nil;
|
|
d_kqfilter :nil;
|
|
d_purge :nil;
|
|
d_mmap_single :@gc_mmap_single;
|
|
d_mmap_single2:nil;
|
|
);
|
|
|
|
{
|
|
event_id
|
|
(SourceID == 0xb5)
|
|
0x00 -> Compute0
|
|
0x01 -> Compute1
|
|
0x02 -> Compute2
|
|
0x03 -> Compute3
|
|
0x04 -> Compute4
|
|
0x05 -> Compute5
|
|
0x06 -> Compute6
|
|
0x40 -> GfxEop
|
|
0x41 -> GfxEop (meid ????)
|
|
|
|
0x84 -> set timer hz
|
|
|
|
(SourceID == 0xef)
|
|
0x83,
|
|
0x85,
|
|
0x86 -> (dbggc)
|
|
}
|
|
|
|
function filterops_graphics_core_attach(kn:p_knote):Integer;
|
|
var
|
|
kn_sdata:QWORD;
|
|
event_id:Byte;
|
|
cap:Boolean;
|
|
me_id:Byte;
|
|
begin
|
|
Result:=0;
|
|
|
|
event_id:=Byte(kn^.kn_sdata); //kev.ident = kev.data
|
|
|
|
cap:=sceSblACMgrHasUseHp3dPipeCapability(@g_authinfo);
|
|
|
|
me_id:=0;
|
|
|
|
case event_id of
|
|
$00..$41,
|
|
$80..$86:
|
|
begin
|
|
|
|
if (not cap) then
|
|
begin
|
|
if (event_id=$84) or (event_id=$41) then Exit(EPERM);
|
|
end else
|
|
begin
|
|
if (event_id=$40) then Exit(EPERM);
|
|
end;
|
|
|
|
kn_sdata:=kn^.kn_sdata;
|
|
|
|
case event_id of
|
|
$82..$86:kn_sdata:=(kn_sdata and QWORD($ffffffffffff0000)) or
|
|
QWORD(event_id);
|
|
else
|
|
kn_sdata:=(kn_sdata and QWORD($ffffffffffff0000)) or
|
|
QWORD(event_id) or
|
|
QWORD((me_id and $ff) shl 8);
|
|
end;
|
|
|
|
kn^.kn_sdata:=kn_sdata;
|
|
|
|
kn^.kn_flags:=kn^.kn_flags or EV_CLEAR; { automatically set }
|
|
|
|
knlist_add(@gc_knlist,kn,0);
|
|
end;
|
|
else
|
|
Result:=EINVAL;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure filterops_graphics_core_detach(kn:p_knote);
|
|
begin
|
|
knlist_remove(@gc_knlist,kn,0);
|
|
end;
|
|
|
|
function filterops_graphics_core_event(kn:p_knote;hint:QWORD):Integer;
|
|
var
|
|
me_id:Byte;
|
|
begin
|
|
//hint:[event_id:8|meid:8|timestamp:48]
|
|
if (hint=0) then
|
|
begin
|
|
Result:=ord(kn^.kn_kevent.data<>0);
|
|
end else
|
|
begin
|
|
Result:=0;
|
|
if (Byte(kn^.kn_sdata)=Byte(hint)) then //kn^.kn_sdata.event_id = hint.event_id
|
|
begin
|
|
me_id:=(hint shr 8);
|
|
|
|
if (me_id=$80) or
|
|
(me_id=Byte(kn^.kn_sdata shr 8)) then
|
|
begin
|
|
Result:=1;
|
|
|
|
me_id:=Byte(kn^.kn_kevent.data shr 8);
|
|
|
|
kn^.kn_kevent.data:=(hint and QWORD($ffffffffffff00ff)) or
|
|
(QWORD(me_id) shl 8);
|
|
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure filterops_graphics_core_touch(kn:p_knote;kev:p_kevent;_type:QWORD);
|
|
begin
|
|
if (_type=EVENT_PROCESS) then
|
|
begin
|
|
kev^:=kn^.kn_kevent;
|
|
end;
|
|
end;
|
|
|
|
const
|
|
filterops_graphics_core:t_filterops=(
|
|
f_isfd :0;
|
|
_align :0;
|
|
f_attach:@filterops_graphics_core_attach;
|
|
f_detach:@filterops_graphics_core_detach;
|
|
f_event :@filterops_graphics_core_event;
|
|
f_touch :@filterops_graphics_core_touch
|
|
);
|
|
|
|
procedure gc_initialize();
|
|
begin
|
|
gc_page:=dev_mem_alloc(1);
|
|
|
|
make_dev(@gc_cdevsw,0,0,0,&666,'gc',[]);
|
|
|
|
mtx_init(gc_knl_lock,'gc knl lock');
|
|
knlist_init_mtx(@gc_knlist,@gc_knl_lock);
|
|
|
|
kqueue_add_filteropts(EVFILT_GRAPHICS_CORE,@filterops_graphics_core);
|
|
|
|
gc_ring_create(@ring_gfx,GC_RING_SIZE);
|
|
|
|
pm4_me_gfx.Init(@gc_knlist);
|
|
pm4_me_gfx.on_idle:=@gc_idle;
|
|
pm4_me_gfx.on_submit_flip_eop:=@dev_dce.TriggerFlipEop;
|
|
end;
|
|
|
|
|
|
end.
|
|
|