FPPS4/sys/dev/dev_gc.pas

1440 lines
29 KiB
Plaintext

unit dev_gc;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
sys_conf;
procedure gc_initialize();
function gc_add_internal_ptr (kq,ptr,udata:Pointer):Integer; register;
function gc_del_internal_ptr (kq,ptr:Pointer):Integer; register;
procedure gc_wakeup_internal_ptr(ptr:Pointer); register;
var
sync_me_submit:Boolean=False; //forced wait for all tasks to complete on the GPU side after submit
implementation
uses
errno,
kern_mtx,
sys_event,
kern_event,
sched_ule,
kern_authinfo,
vm,
vmparam,
vm_pmap,
sys_vm_object,
vm_pager,
vm_map,
vm_mmap,
kern_rwlock,
kern_proc,
kern_thr,
kern_condvar,
time,
pm4defs,
pm4_ring,
pm4_stream,
pm4_pfp,
pm4_me,
dev_dce,
vDevice,
vMemory,
sys_bootparam,
subr_backtrace;
var
gc_page:PDWORD; //SceGnmDingDongArea
gc_submits_allowed_vaddr:PInteger=nil; //0=true,1=false (0xfe0100000)
gc_submits_allowed_vmirr:PInteger=nil;
gc_knlock:mtx;
gc_knlist:t_knlist;
procedure unmap_dmem_gc(start,__end:QWORD); 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 PAGE_MASK)=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:=SCE_REPLAY_EXEC_START;
end;
Result:=vm_mmap2(map,
@paddr,psize,
prot,prot,
MAP_ANON or MAP_SYSTEM or MAP_SHARED,OBJT_DEFAULT,
nil,0,nil);
if (Result=0) then
begin
Result:=vm_map_wire(map,paddr,paddr + psize,0);
end;
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;
p_map_compute_queue_args=^t_map_compute_queue_args;
t_map_compute_queue_args=packed record
pipeHi :DWORD;
pipeLo :DWORD;
queueId :DWORD;
g_queueId :DWORD;
ringBaseAddress:Pointer;
readPtrAddress :Pointer;
dingDongPtr :Pointer;
lenLog2 :DWORD;
pipePriority :DWORD;
end;
p_unmap_compute_queue_args=^t_unmap_compute_queue_args;
t_unmap_compute_queue_args=packed record
pipeHi :DWORD;
pipeLo :DWORD;
queueId:DWORD;
end;
p_ding_dong_args=^t_ding_dong_args;
t_ding_dong_args=packed record
pipeHi :DWORD;
pipeLo :DWORD;
queueId :DWORD;
nextStartOffsetInDw:DWORD;
end;
p_set_wave_limit_multipliers=^t_set_wave_limit_multipliers;
t_set_wave_limit_multipliers=packed record
bitset:Integer;
values:array[0..7] of Integer;
unk1 :Integer;
unk2 :Integer;
unk3 :Integer;
end;
var
ring_gfx :t_pm4_ring;
ring_gfx_lock :Pointer=nil;
type
t_gc_priv=object
ring_watchdog:t_cv;
GC_SRI_event :t_cv; //suspend-resume-idle event
GC_IDLE_event:t_cv;
//pfp_event :t_cv;
gc_suspend_lock:mtx;
watchdog_label:Integer;
GC_SRI_label :Integer;
pfp_label :Integer;
sync_to_imdone:Integer;
end;
var
gc_priv:t_gc_priv=(
ring_watchdog:(cv_description:nil;cv_waiters:0);
GC_SRI_event :(cv_description:nil;cv_waiters:0);
GC_IDLE_event:(cv_description:nil;cv_waiters:0);
//pfp_event :(cv_description:nil;cv_waiters:0);
watchdog_label:0;
GC_SRI_label :0;
pfp_label :0;
sync_to_imdone:0;
);
parse_gfx_started:Pointer=nil;
parse_gfx_td:p_kthread;
pfp_ctx:t_pfp_ctx;
pm4_me_gfx:t_pm4_me;
var
map_queue_valid:QWORD=0;
map_queue_hqd :array[0..63] of t_gc_hqd;
//asc_queues
//gfx ring only
procedure onEventWriteEop(pctx:p_pfp_ctx;Body:PPM4CMDEVENTWRITEEOP);
var
submit_id:QWORD;
begin
submit_id:=Body^.DATA;
if p_print_gpu_ops then
begin
Writeln('[R]IT_EVENT_WRITE_EOP=0x',HexStr(submit_id,16),' ',Body^.intSel);
end;
pctx^.stream[stGfxDcb].SubmitFlipEop(Body^.DATA,Body^.intSel);
end;
procedure onSwitchBuffer(pctx:p_pfp_ctx;Body:Pointer);
begin
//
end;
function pm4_parse_gfx_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('[R]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('[R]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('[R]SWITCH_BUFFER');
end;
onSwitchBuffer(pctx,buff);
end;
$C0044700: //IT_EVENT_WRITE_EOP
begin
onEventWriteEop(pctx,buff);
end;
else
begin
Assert(False);
end;
end;
end;
function get_compute_stream_type(c_id:DWORD):t_pm4_stream_type; inline;
begin
Result:=t_pm4_stream_type(ord(stCompute0) + (c_id div 8)); //pipe id
end;
procedure pfp_idle; forward;
procedure parse_gfx_ring(parameter:pointer); SysV_ABI_CDecl;
var
buff:Pointer;
i,size:DWORD;
ibuf:t_pm4_ibuffer;
buft:t_pm4_stream_type;
base_guest_addr:Pointer;
bits:QWORD;
c_id:DWORD;
p_id:DWORD;
send:DWORD;
begin
sched_prio(curkthread,64);
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_gfx_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:=stGfxDcb to stGfxCcb do
begin
pfp_ctx.Flush_stream(buft);
end;
//
Continue;
end;
bits:=map_queue_valid;
if (bits<>0) then
begin
//init sended bits
send:=0;
while (bits<>0) do
begin
c_id:=BsfQWord(bits);
//start
rw_wlock(ring_gfx_lock);
p_id:=2; //double check
while (p_id<>0) and gc_map_hdq_peek(@map_queue_hqd[c_id],@size,@buff) do
begin
//adjust guest addr
base_guest_addr:=map_queue_hqd[c_id].base_guest_addr + (buff - map_queue_hqd[c_id].base_dmem_addr);
//
rw_wunlock(ring_gfx_lock);
//
if pm4_ibuf_init(@ibuf,buff,size,@pm4_parse_compute_ring,get_compute_stream_type(c_id),c_id) then
begin
//adjust guest addr
ibuf.base:=base_guest_addr;
i:=pm4_ibuf_parse(@pfp_ctx,@ibuf);
if (i<>0) then
begin
pfp_ctx.add_stall(@ibuf);
end;
end;
//
rw_wlock(ring_gfx_lock);
//
gc_map_hdq_drain(@map_queue_hqd[c_id],size);
//set sended bits
send:=send or (QWORD(1) shl (c_id div 8)); //by pipe id //It is necessary to force QWORD!
Dec(p_id);
end; //while
rw_wunlock(ring_gfx_lock);
//end
//clear
bits:=bits and (not (QWORD(1) shl c_id)); //It is necessary to force QWORD!
end; //while
if (send<>0) then
begin
//
while (send<>0) do
begin
c_id:=BsfDWord(send);
pfp_ctx.Flush_stream( t_pm4_stream_type(ord(stCompute0) + c_id) );
//clear
send:=send and (not (QWORD(1) shl c_id)); //It is necessary to force QWORD!
end;
//
Continue;
end; //(send<>0)
end; //(bits<>0)
//PFP idle
pfp_idle;
if (gc_priv.watchdog_label=0) then
begin
mtx_lock(gc_priv.gc_suspend_lock);
_cv_wait_sig(@gc_priv.ring_watchdog,@gc_priv.gc_suspend_lock);
mtx_unlock(gc_priv.gc_suspend_lock);
end else
begin
mtx_lock(gc_priv.gc_suspend_lock);
_cv_timedwait_sig(@gc_priv.ring_watchdog,@gc_priv.gc_suspend_lock, hz div 10000);
mtx_unlock(gc_priv.gc_suspend_lock);
end;
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;
cv_init (@gc_priv.ring_watchdog ,'ring_watchdog');
cv_init (@gc_priv.GC_SRI_event ,'GC_SRI_event');
cv_init (@gc_priv.GC_IDLE_event ,'GC_IDLE_event');
mtx_init(gc_priv.gc_suspend_lock,'gc_suspend_lock');
kthread_add(@parse_gfx_ring,nil,@parse_gfx_td,(8*1024*1024) div (16*1024),'[GFX_PFP]');
end;
end;
procedure gc_retrigger_watchdog;
begin
if (gc_priv.ring_watchdog.cv_description<>nil) then
begin
gc_priv.watchdog_label:=1; //thread can`t wait
cv_signal(@gc_priv.ring_watchdog);
end;
end;
procedure gc_retrigger_watchdog_imdone;
begin
//if (gc_priv.sync_to_imdone=0) then
begin
gc_retrigger_watchdog;
gc_priv.sync_to_imdone:=1;
end;
end;
procedure gc_wait_GC_SRI;
begin
if (pm4_me_gfx.started=nil) then Exit;
mtx_lock(gc_priv.gc_suspend_lock);
if (gc_priv.GC_SRI_label<>0) then
begin
pm4_me_gfx.trigger; //update if wait
_cv_wait_sig(@gc_priv.GC_SRI_event,@gc_priv.gc_suspend_lock);
end;
mtx_unlock(gc_priv.gc_suspend_lock);
//pm4_me_gfx.trigger; //update if wait
end;
procedure pfp_idle;
begin
mtx_lock(gc_priv.gc_suspend_lock);
//if (gc_priv.pfp_label<>0) then
//begin
// cv_broadcastpri(@gc_priv.pfp_event,0);
//end;
gc_priv.pfp_label:=0;
mtx_unlock(gc_priv.gc_suspend_lock);
pm4_me_gfx.trigger;
end;
procedure gc_idle; register;
begin
mtx_lock(gc_priv.gc_suspend_lock);
if (gc_priv.pfp_label=0) then
begin
cv_signal(@gc_priv.GC_IDLE_event);
end;
mtx_unlock(gc_priv.gc_suspend_lock);
end;
procedure gc_imdone_tasklet;
var
ret:Integer;
begin
mtx_lock(gc_priv.gc_suspend_lock);
gc_priv.pfp_label:=1;
repeat
gc_retrigger_watchdog;
pm4_me_gfx.trigger; //update if wait
ret:=_cv_timedwait_sig(@gc_priv.GC_IDLE_event,@gc_priv.gc_suspend_lock, hz div 2);
if (ret<>0) then
begin
Writeln(stderr,'GPU failed to become idle within 500 ms after submitDone.');
end;
until (ret=0);
if (gc_priv.GC_SRI_label<>0) then
begin
cv_broadcastpri(@gc_priv.GC_SRI_event,0);
end;
gc_priv.GC_SRI_label:=0;
mtx_unlock(gc_priv.gc_suspend_lock);
if (gc_submits_allowed_vmirr<>nil) then
begin
gc_submits_allowed_vmirr^:=0; //true
end;
end;
procedure gc_imdone;
begin
//if (gc_priv.GC_SRI_event=nil) then Exit;
if (pm4_me_gfx.started=nil) then Exit;
//gc_wait_GC_SRI;
mtx_lock(gc_priv.gc_suspend_lock);
gc_priv.sync_to_imdone:=0;
{
if (gc_priv.pfp_label<>0) then
begin
gc_retrigger_watchdog;
_cv_wait_sig(@gc_priv.pfp_event,@gc_priv.GC_SRI_lock);
end;
}
if (gc_priv.GC_SRI_label<>0) then
begin
pm4_me_gfx.trigger; //update if wait
_cv_wait_sig(@gc_priv.GC_SRI_event,@gc_priv.gc_suspend_lock);
end;
//gc_priv.pfp_label :=1;
gc_priv.GC_SRI_label:=1;
mtx_unlock(gc_priv.gc_suspend_lock);
//gc_priv.GC_SRI_label:=1;
if (gc_submits_allowed_vmirr<>nil) then
begin
gc_submits_allowed_vmirr^:=1; //false
end;
gc_priv.watchdog_label:=0; //thread can wait
//-> gc_imdone_tasklet
gc_imdone_tasklet;
pm4_me_gfx.imdone;
//gc_wait_GC_SRI;
end;
Function gc_map_compute_queue(data:p_map_compute_queue_args):Integer;
var
g_queueId :DWORD;
pipeHi :DWORD;
pipeLo :DWORD;
queueId :DWORD;
pipePriority:DWORD;
id :DWORD;
begin
Result:=0;
g_queueId :=data^.g_queueId;
pipeHi :=data^.pipeHi;
pipeLo :=data^.pipeLo;
queueId :=data^.queueId;
pipePriority:=data^.pipePriority;
//if (not IsDevKit) or
if (pipeHi <> $0769c766) or (pipeLo <> $72e8e3c1) or
(queueId <> $db72af28) or (g_queueId <> $d245ed58) then
begin
//if (not IsDevKit) or (not IsDiag)
if (pipeHi <> $e13ec1f1) or (pipeLo <> $76c0801c) or
(queueId <> $75c36152) or (g_queueId <> $4be587dd) then
begin
if (pipeHi = 2) and
(pipeLo = 3) then
begin
Exit(Integer($804c000a));
end;
if (1 < (pipeHi - 1)) then
begin
Exit(Integer($804c000b));
end;
if (3 < pipeLo) then
begin
Exit(Integer($804c000b));
end;
if (7 < queueId) then
begin
Exit(Integer($804c000b));
end;
end else
begin
pipeHi :=2;
g_queueId:=19;
pipeLo :=3;
queueId :=3;
end;
end else
begin
pipeHi :=2;
g_queueId:=20;
queueId :=4;
pipeLo :=3;
end;
if (pipePriority >= 2) then
begin
Exit(EINVAL);
end;
id:=(pipeHi - 1) * 32 + pipeLo * 8 + queueId;
if ((map_queue_valid and (QWORD(1) shl id))<>0) then //It is necessary to force QWORD!
begin
Exit(Integer($804c0012));
end;
Result:=gc_map_hqd(data^.ringBaseAddress,
data^.readPtrAddress,
@gc_page[id],
data^.lenLog2,
g_queueId,
pipePriority,
@map_queue_hqd[id]);
if (Result=0) then
begin
map_queue_valid:=map_queue_valid or (QWORD(1) shl id); //It is necessary to force QWORD!
end;
end;
Function gc_unmap_compute_queue(data:p_unmap_compute_queue_args):Integer;
var
pipeHi :DWORD;
pipeLo :DWORD;
queueId :DWORD;
id :DWORD;
begin
Result:=0;
pipeHi :=data^.pipeHi;
pipeLo :=data^.pipeLo;
queueId:=data^.queueId;
//if (not IsDevKit) or (not IsDiag)
if (pipeHi <> $0769c766) or
(pipeLo <> $72e8e3c1) or
(queueId <> $db72af28) then
begin
//if (not IsDevKit) or (not IsDiag)
if (pipeHi <> $e13ec1f1) or
(pipeLo <> $76c0801c) or
(queueId <> $75c36152) then
begin
if (pipeHi = 2) and
(pipeLo = 3) then
begin
Exit(Integer($804c000a));
end;
if (1 < (pipeHi - 1)) then
begin
Exit(Integer($804c000b));
end;
if (3 < pipeLo) then
begin
Exit(Integer($804c000b));
end;
if (7 < queueId) then
begin
Exit(Integer($804c000b));
end;
end else
begin
pipeLo :=3;
pipeHi :=2;
queueId:=3;
end;
end else
begin
queueId:=4;
pipeLo :=3;
pipeHi :=2;
end;
id:=(pipeHi - 1) * 32 + pipeLo * 8 + queueId;
if ((map_queue_valid and (QWORD(1) shl id))<>0) then //It is necessary to force QWORD!
begin
gc_unmap_hqd(@map_queue_hqd[id]);
map_queue_valid:=map_queue_valid and (not (QWORD(1) shl id)); //It is necessary to force QWORD!
end;
end;
Function gc_ding_dong(data:p_ding_dong_args):Integer;
var
pipeHi :DWORD;
pipeLo :DWORD;
queueId:DWORD;
id :DWORD;
begin
Result:=0;
pipeHi :=data^.pipeHi;
pipeLo :=data^.pipeLo;
queueId:=data^.queueId;
//if (not IsDevKit) or (not IsDiag)
if (pipeHi <> $0769c766) or
(pipeLo <> $72e8e3c1) or
(queueId <> $db72af28) then
begin
if (pipeHi = 2) and
(pipeLo = 3) then
begin
Exit(Integer($804c000a));
end;
if (1 < (pipeHi - 1)) then
begin
Exit(Integer($804c000b));
end;
if (3 < pipeLo) then
begin
Exit(Integer($804c000b));
end;
if (7 < queueId) then
begin
Exit(Integer($804c000b));
end;
end else
begin
queueId:=4;
pipeLo :=3;
pipeHi :=2;
end;
id:=(pipeHi - 1) * 32 + pipeLo * 8 + queueId;
if ((map_queue_valid and (QWORD(1) shl id))=0) then //It is necessary to force QWORD!
begin
Exit(Integer($804c0001));
end;
Result:=gc_map_hdq_ding_dong(@map_queue_hqd[id],
data^.nextStartOffsetInDw);
end;
Function gc_ioctl(dev:p_cdev;cmd:QWORD;data:Pointer;fflag:Integer):Integer;
var
vaddr:Pointer;
begin
Result:=0;
//Writeln('gc_ioctl(0x',HexStr(cmd,8),')');
case cmd of
$C0088111:; //sceGnmDebugHardwareStatus
$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
with p_SetGsRingSizes(data)^ do
Writeln('SetGsRingSizes(0x',HexStr(esgsRingSize,8),',0x'
,HexStr(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
with p_SetMipStatsReport(data)^ do
Writeln('MipStatsReport(0x',HexStr(param1,8),',0x'
,HexStr(param2,8),',0x'
,HexStr(param3,8),')');
end;
$18001:; //diag?
else
Exit(EINVAL);
end;
end;
$C008811B: //sceGnmAreSubmitsAllowed
begin
if (gc_submits_allowed_vaddr=nil) then
begin
vaddr:=nil;
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
start_gfx_ring;
Writeln('sceGnmSubmitDone');
//rw_wlock(ring_gfx_lock);
gc_imdone;
//rw_wunlock(ring_gfx_lock);
end;
$C0048117: //wait idle
begin
Writeln('gc_wait_idle');
//rw_wlock(ring_gfx_lock);
gc_wait_GC_SRI;
//rw_wunlock(ring_gfx_lock);
end;
$C004811D: //????
begin
Writeln('gc_wait_free:',PInteger(data)^);
//rw_wlock(ring_gfx_lock);
gc_wait_GC_SRI;
//rw_wunlock(ring_gfx_lock);
end;
$C0048114: //sceGnmFlushGarlic
begin
Writeln('sceGnmFlushGarlic');
MemManager.Flush;
end;
$C0108102: //submit
begin
start_gfx_ring;
rw_wlock(ring_gfx_lock);
//gc_retrigger_watchdog;
Result:=gc_submit_internal(@ring_gfx,
p_submit_args(data)^.count,
p_submit_args(data)^.cmds);
if (Result=0) then
begin
gc_retrigger_watchdog;
if sync_me_submit then
begin
//force wait GPU idle
gc_wait_GC_SRI;
end;
//msleep_td(hz);
end;
rw_wunlock(ring_gfx_lock);
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"
}
Writeln('submit_eop=0x',HexStr(p_submit_args(data)^.eop_v,16),' ',p_submit_args(data)^.wait);
Result:=gc_pm4_event_write_eop(@ring_gfx,
nil,
p_submit_args(data)^.eop_v,
1,
p_submit_args(data)^.wait
);
end;
if (Result=0) then
begin
gc_retrigger_watchdog;
end;
rw_wunlock(ring_gfx_lock);
end;
$C0088101: //switch_buffer
begin
start_gfx_ring;
gc_retrigger_watchdog_imdone;
gc_wait_GC_SRI;
rw_wlock(ring_gfx_lock);
Result:=gc_switch_buffer_internal(@ring_gfx);
rw_wunlock(ring_gfx_lock);
end;
$C030810D: //sceGnmMapComputeQueue
begin
rw_wlock(ring_gfx_lock);
//reset prio
p_map_compute_queue_args(data)^.pipePriority:=0;
Result:=gc_map_compute_queue(data);
if (Result=0) then
begin
gc_retrigger_watchdog;
end;
rw_wunlock(ring_gfx_lock);
end;
$C030811A: //sceGnmMapComputeQueueWithPriority
begin
rw_wlock(ring_gfx_lock);
Result:=gc_map_compute_queue(data);
if (Result=0) then
begin
gc_retrigger_watchdog;
end;
rw_wunlock(ring_gfx_lock);
end;
$C00C810E: //sceGnmUnmapComputeQueue
begin
gc_wait_GC_SRI;
rw_wlock(ring_gfx_lock);
Result:=gc_unmap_compute_queue(data);
rw_wunlock(ring_gfx_lock);
end;
$C010811C: //sceGnmDingDong
begin
start_gfx_ring;
Writeln('sceGnmDingDong');
gc_retrigger_watchdog_imdone;
gc_wait_GC_SRI;
rw_wlock(ring_gfx_lock);
Result:=gc_ding_dong(data);
if (Result=0) then
begin
gc_retrigger_watchdog;
end;
rw_wunlock(ring_gfx_lock);
end;
$C030811E: //sceGnmSetWaveLimitMultipliers
begin
with p_set_wave_limit_multipliers(data)^ do
Writeln('SetWaveLimitMultipliers(b',BinStr(bitset,8),',',
values[0],',',
values[1],',',
values[2],',',
values[3],',',
values[4],',',
values[5],',',
values[6],',',
values[7],')'
);
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^.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);
memattr^:=0;
Result:=0;
end;
const
gc_cdevsw:t_cdevsw=(
d_version :D_VERSION;
d_flags :0;
d_name :'gc';
d_ioctl :@gc_ioctl;
d_mmap :@gc_mmap;
d_mmap_single :@gc_mmap_single;
);
{
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;
f_attach:@filterops_graphics_core_attach;
f_detach:@filterops_graphics_core_detach;
f_event :@filterops_graphics_core_event;
f_touch :@filterops_graphics_core_touch
);
////
var
gc_internal_knlock:mtx;
gc_internal_knlist:t_knlist;
function filterops_internal_attach(kn:p_knote):Integer;
begin
Result:=0;
kn^.kn_flags:=kn^.kn_flags or EV_CLEAR; { automatically set }
knlist_add(@gc_internal_knlist,kn,0);
end;
procedure filterops_internal_detach(kn:p_knote);
begin
knlist_remove(@gc_internal_knlist,kn,0);
end;
function filterops_internal_event(kn:p_knote;hint:QWORD):Integer;
begin
Result:=0;
if (hint=0) then
begin
if (kn^.kn_kevent.ident=hint) then
begin
Result:=Integer(kn^.kn_kevent.data);
end;
end else
begin
if (kn^.kn_kevent.ident=hint) then
begin
kn^.kn_kevent.data:=1;
Result:=1;
end;
end;
end;
const
filterops_internal:t_filterops=(
f_isfd :0;
f_attach:@filterops_internal_attach;
f_detach:@filterops_internal_detach;
f_event :@filterops_internal_event;
);
procedure gc_init_internal();
begin
mtx_init(gc_internal_knlock,'gc internal kn lock');
knlist_init_mtx(@gc_internal_knlist,@gc_internal_knlock);
end;
function gc_add_internal_ptr(kq,ptr,udata:Pointer):Integer; register; [public, alias:'gc_add_internal_ptr'];
var
kev:t_kevent;
fops:p_filterops;
begin
kev:=Default(t_kevent);
kev.ident:=PtrUint(ptr);
kev.flags:=EV_ADD;
kev.udata:=udata;
//
fops:=@filterops_internal;
Result:=kqueue_register2(kq,@kev,fops);
end;
function gc_del_internal_ptr(kq,ptr:Pointer):Integer; register; [public, alias:'gc_del_internal_ptr'];
var
kev:t_kevent;
fops:p_filterops;
begin
kev:=Default(t_kevent);
kev.ident:=PtrUint(ptr);
kev.flags:=EV_DELETE;
//
fops:=@filterops_internal;
Result:=kqueue_register2(kq,@kev,fops);
end;
procedure gc_wakeup_internal_ptr(ptr:Pointer); register; [public, alias:'gc_wakeup_internal_ptr'];
begin
knote(@gc_internal_knlist, PtrUint(ptr), 0);
end;
////
procedure gc_initialize();
begin
gc_page:=dev_mem_alloc(1);
make_dev(@gc_cdevsw,0,0,0,&666,'gc',[]);
mtx_init(gc_knlock,'gc kn lock');
knlist_init_mtx(@gc_knlist,@gc_knlock);
gc_init_internal();
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.