From c2ea5703a2047733dcfbcd4d3d59cab0e122376d Mon Sep 17 00:00:00 2001 From: Pavel <68122101+red-prig@users.noreply.github.com> Date: Fri, 22 Mar 2024 22:00:12 +0300 Subject: [PATCH] + --- chip/pm4_ring.pas | 277 ++++++++++++++++++++++++++++++++++++++++++++ sys/dev/dev_gc.pas | 282 +++++---------------------------------------- 2 files changed, 309 insertions(+), 250 deletions(-) create mode 100644 chip/pm4_ring.pas diff --git a/chip/pm4_ring.pas b/chip/pm4_ring.pas new file mode 100644 index 00000000..24cf353d --- /dev/null +++ b/chip/pm4_ring.pas @@ -0,0 +1,277 @@ +unit pm4_ring; + +{$mode ObjFPC}{$H+} +{$CALLING SysV_ABI_CDecl} + +interface + +uses + errno, + md_map, + systm, + bittype; + +type + //IT_INDIRECT_BUFFER_CNST = $00000033; ccb 0xc0023300 + //IT_COND_INDIRECT_BUFFER = $0000003f; dcb 0xc0023f00 + + PPM4CMDINDIRECTBUFFER=^PM4CMDINDIRECTBUFFER; + PM4CMDINDIRECTBUFFER=bitpacked record + header :DWORD; // PM4_TYPE_3_HEADER + ibBase :QWORD; // Indirect buffer base address, must be 4 byte aligned + // + ibSize :bit20; // Indirect buffer size + reserved0:bit4; + vmid :bit4; // Virtual memory domain ID for command buffer + reserved1:bit4; + end; + + PPM4CMDSWITCHBUFFER=^PM4CMDSWITCHBUFFER; + PM4CMDSWITCHBUFFER=bitpacked record + header:DWORD; + data :DWORD; + end; + +const + GC_RING_SIZE=$80000; + GC_RING_PADD=64*1024; + +type + p_pm4_ring=^t_pm4_ring; + t_pm4_ring=packed record + buff:Pointer; + size:DWORD; + rptr:DWORD; + wptr:DWORD; + aptr:DWORD; + end; + +function gc_ring_create(ring:p_pm4_ring;size:ptruint):Integer; +function gc_ring_free (ring:p_pm4_ring):Integer; + +function gc_ring_pm4_alloc (ring:p_pm4_ring;size:DWORD;buff:PPointer):Boolean; +procedure gc_ring_pm4_submit (ring:p_pm4_ring); +procedure gc_ring_pm4_release(ring:p_pm4_ring); + +function gc_ring_pm4_peek (ring:p_pm4_ring;size:PDWORD;buff:PPointer):Boolean; +function gc_ring_pm4_drain(ring:p_pm4_ring;size:DWORD):Boolean; + +function gc_submit_internal (ring:p_pm4_ring;count:DWORD;cmds:Pointer):Integer; +function gc_switch_buffer_internal(ring:p_pm4_ring):Integer; + +implementation + +function gc_ring_create(ring:p_pm4_ring;size:ptruint):Integer; +var + hMem:THandle; +begin + Result:=0; + if (ring=nil) then Exit(-1); + + size:=1 shl BsfQWORD(size); + if (size0) then Exit; + + Result:=md_split(ring^.buff,size); + if (Result<>0) then Exit; + + hMem:=0; + Result:=md_memfd_create(hMem,size); + if (Result<>0) then Exit; + + Result:=md_file_mmap_ex(hMem,ring^.buff,0,size,MD_PROT_RW); + if (Result<>0) then + begin + md_memfd_close(hMem); + Exit; + end; + + Result:=md_file_mmap_ex(hMem,ring^.buff+size,size,GC_RING_PADD,MD_PROT_RW); + + md_memfd_close(hMem); +end; + +function gc_ring_free(ring:p_pm4_ring):Integer; +begin + Result:=0; + if (ring=nil) then Exit; + if (ring^.buff=nil) then Exit; + if (ring^.size=0) then Exit; + + Result:=md_unmap_ex(ring^.buff,ring^.size+GC_RING_PADD); +end; + +//need lock +function gc_ring_pm4_alloc(ring:p_pm4_ring;size:DWORD;buff:PPointer):Boolean; +var + next:DWORD; +begin + Result:=False; + if (size>ring^.size) then Exit; + + next:=ring^.aptr+size; + + if (next>=ring^.size) then + begin + next:=next and (ring^.size-1); + if (next>ring^.rptr) then Exit; + end; + + buff^:=ring^.buff+ring^.aptr; + ring^.aptr:=next; + Result:=True; +end; + +procedure gc_ring_pm4_submit(ring:p_pm4_ring); +begin + System.InterlockedExchange(ring^.wptr,ring^.aptr); +end; + +procedure gc_ring_pm4_release(ring:p_pm4_ring); +begin + ring^.aptr:=ring^.wptr; +end; + +//single consumer +function gc_ring_pm4_peek(ring:p_pm4_ring;size:PDWORD;buff:PPointer):Boolean; +var + rptr:DWORD; + wptr:DWORD; + s :DWORD; +begin + Result:=False; + + rptr:=ring^.rptr; + wptr:=ring^.wptr; + + if (rptr>wptr) then + begin + if (wptr>GC_RING_PADD) then wptr:=GC_RING_PADD; + s:=(ring^.size-rptr)+wptr; + end else + begin + s:=wptr-rptr; + end; + + if (s<>0) then + begin + size^:=s; + buff^:=ring^.buff+rptr; + Result:=True; + end; +end; + +//single consumer +function gc_ring_pm4_drain(ring:p_pm4_ring;size:DWORD):Boolean; +var + rptr:DWORD; + wptr:DWORD; + s :DWORD; +begin + Result:=False; + + rptr:=ring^.rptr; + wptr:=ring^.wptr; + + if (rptr>wptr) then + begin + s:=(ring^.size-rptr)+wptr; + end else + begin + s:=wptr-rptr; + end; + + if (size>s) then Exit; + + rptr:=rptr+size; + rptr:=rptr and (ring^.size-1); + + System.InterlockedExchange(ring^.rptr,rptr); + + Result:=True; +end; + +function gc_submit_internal(ring:p_pm4_ring;count:DWORD;cmds:Pointer):Integer; +var + size:QWORD; + buf:PPM4CMDINDIRECTBUFFER; + op:DWORD; +begin + Result:=0; + if (count=0) then Exit; + + if (count>=$1000) then Exit(-2142502897); + + size:=(count*16); + + buf:=nil; + if not gc_ring_pm4_alloc(ring,size,@buf) then + begin + Writeln(stderr,'### gc_submit_common : Cannot allocate a space in ring buffer.'); + Exit(EBUSY); + end; + + Result:=copyin(cmds,buf,size); + + if (Result<>0) then + begin + gc_ring_pm4_release(ring); + Exit(-2142502898); + end; + + while (count<>0) do + begin + op:=buf^.header; + + if ((op<>$c0023300) and (op<>$c0023f00)) then + begin + Writeln(stderr,'## gc_insert_indirect_buffer: invalid opcode = 0x',HexStr(op,8)); + gc_ring_pm4_release(ring); + Exit(-2142502896); + end; + + if (buf^.ibSize=0) then + begin + Writeln(stderr,'## gc_insert_indirect_buffer: invalid ib_size = 0x',HexStr(buf^.ibSize,5)); + gc_ring_pm4_release(ring); + Exit(-2142502895); + end; + + Inc(buf); + Dec(count); + end; + + gc_ring_pm4_submit(ring); +end; + +function gc_switch_buffer_internal(ring:p_pm4_ring):Integer; +var + buf:PPM4CMDSWITCHBUFFER; +begin + Result:=0; + + buf:=nil; + if not gc_ring_pm4_alloc(ring,sizeof(PM4CMDSWITCHBUFFER),@buf) then + begin + Writeln(stderr,'### gc_switch_buffer_internal : Cannot allocate a space in ring buffer.'); + Exit(EBUSY); + end; + + //IT_SWITCH_BUFFER = $0000008b; + + buf^.header:=$c0008b00; + buf^.data :=0; + + gc_ring_pm4_submit(ring); +end; + +end. + diff --git a/sys/dev/dev_gc.pas b/sys/dev/dev_gc.pas index 96c9c941..0f606914 100644 --- a/sys/dev/dev_gc.pas +++ b/sys/dev/dev_gc.pas @@ -24,15 +24,13 @@ uses vm_pager, vm_map, vm_mmap, - md_map, - systm, kern_rwlock, kern_proc, kern_thr, kern_thread, md_sleep, - subr_backtrace, - bittype; + pm4_ring, + subr_backtrace; var gc_page:Pointer; @@ -102,260 +100,21 @@ type wait :Integer; end; - //IT_INDIRECT_BUFFER_CNST = $00000033; ccb 0xc0023300 - //IT_COND_INDIRECT_BUFFER = $0000003f; dcb 0xc0023f00 - - PPM4CMDINDIRECTBUFFER=^PM4CMDINDIRECTBUFFER; - PM4CMDINDIRECTBUFFER=bitpacked record - header :DWORD; // PM4_TYPE_3_HEADER - ibBase :QWORD; // Indirect buffer base address, must be 4 byte aligned - // - ibSize :bit20; // Indirect buffer size - reserved0:bit4; - vmid :bit4; // Virtual memory domain ID for command buffer - reserved1:bit4; - end; - - PPM4CMDSWITCHBUFFER=^PM4CMDSWITCHBUFFER; - PM4CMDSWITCHBUFFER=bitpacked record - header:DWORD; - data :DWORD; - end; - -const - GC_RING_SIZE =$80000; - -type - p_pm4_ring=^t_pm4_ring; - t_pm4_ring=packed record - buff:Pointer; - size:DWORD; - rptr:DWORD; - wptr:DWORD; - aptr:DWORD; - end; - -function gc_ring_create(ring:p_pm4_ring;size:ptruint):Integer; -var - hMem:THandle; -begin - Result:=0; - if (ring=nil) then Exit(-1); - - size:=1 shl BsfQWORD(size); - if (size<64*1024) then size:=64*1024; - - ring^.buff:=nil; - ring^.size:=size; - ring^.rptr:=0; - ring^.wptr:=0; - ring^.aptr:=0; - - Result:=md_reserve_ex(ring^.buff,size+64*1024); - if (Result<>0) then Exit; - - Result:=md_split(ring^.buff,size); - if (Result<>0) then Exit; - - hMem:=0; - Result:=md_memfd_create(hMem,size); - if (Result<>0) then Exit; - - Result:=md_file_mmap_ex(hMem,ring^.buff,0,size,MD_PROT_RW); - if (Result<>0) then - begin - md_memfd_close(hMem); - Exit; - end; - - Result:=md_file_mmap_ex(hMem,ring^.buff+size,size,64*1024,MD_PROT_RW); - - md_memfd_close(hMem); -end; - -function gc_ring_free(ring:p_pm4_ring):Integer; -begin - Result:=0; - if (ring=nil) then Exit; - if (ring^.buff=nil) then Exit; - if (ring^.size=0) then Exit; - - Result:=md_unmap_ex(ring^.buff,ring^.size+64*1024); -end; - -//need lock -function gc_ring_pm4_alloc(ring:p_pm4_ring;size:DWORD;buff:PPointer):Boolean; -var - next:DWORD; -begin - Result:=False; - if (size>ring^.size) then Exit; - - next:=ring^.aptr+size; - - if (next>=ring^.size) then - begin - next:=next and (ring^.size-1); - if (next>ring^.rptr) then Exit; - end; - - buff^:=ring^.buff+ring^.aptr; - ring^.aptr:=next; - Result:=True; -end; - -procedure gc_ring_pm4_submit(ring:p_pm4_ring); -begin - System.InterlockedExchange(ring^.wptr,ring^.aptr); -end; - -procedure gc_ring_pm4_release(ring:p_pm4_ring); -begin - ring^.aptr:=ring^.wptr; -end; - -//single consumer -function gc_ring_pm4_peek(ring:p_pm4_ring;size:PDWORD;buff:PPointer):Boolean; -var - rptr:DWORD; - wptr:DWORD; - s :DWORD; -begin - Result:=False; - - rptr:=ring^.rptr; - wptr:=ring^.wptr; - - if (rptr>wptr) then - begin - s:=(ring^.size-rptr)+wptr; - end else - begin - s:=wptr-rptr; - end; - - if (s<>0) then - begin - size^:=s; - buff^:=ring^.buff+rptr; - Result:=True; - end; -end; - -//single consumer -function gc_ring_pm4_drain(ring:p_pm4_ring;size:DWORD):Boolean; -var - rptr:DWORD; - wptr:DWORD; - s :DWORD; -begin - Result:=False; - - rptr:=ring^.rptr; - wptr:=ring^.wptr; - - if (rptr>wptr) then - begin - s:=(ring^.size-rptr)+wptr; - end else - begin - s:=wptr-rptr; - end; - - if (size>s) then Exit; - - rptr:=rptr+size; - rptr:=rptr and (ring^.size-1); - - System.InterlockedExchange(ring^.rptr,rptr); - - Result:=True; -end; - -function gc_submit_internal(ring:p_pm4_ring;count:DWORD;cmds:Pointer):Integer; -var - size:QWORD; - buf:PPM4CMDINDIRECTBUFFER; - op:DWORD; -begin - Result:=0; - if (count=0) then Exit; - - if (count>=$1000) then Exit(-2142502897); - - size:=(count*16); - - buf:=nil; - if not gc_ring_pm4_alloc(ring,size,@buf) then - begin - Writeln(stderr,'### gc_submit_common : Cannot allocate a space in ring buffer.'); - Exit(16); - end; - - Result:=copyin(cmds,buf,size); - - if (Result<>0) then - begin - gc_ring_pm4_release(ring); - Exit(-2142502898); - end; - - while (count<>0) do - begin - op:=buf^.header; - - if ((op<>$c0023300) and (op<>$c0023f00)) then - begin - Writeln(stderr,'## gc_insert_indirect_buffer: invalid opcode = 0x',HexStr(op,8)); - gc_ring_pm4_release(ring); - Exit(-2142502896); - end; - - if (buf^.ibSize=0) then - begin - Writeln(stderr,'## gc_insert_indirect_buffer: invalid ib_size = 0x',HexStr(buf^.ibSize,5)); - gc_ring_pm4_release(ring); - Exit(-2142502895); - end; - - Inc(buf); - Dec(count); - end; - - gc_ring_pm4_submit(ring); -end; - -function gc_switch_buffer_internal(ring:p_pm4_ring):Integer; -var - buf:PPM4CMDSWITCHBUFFER; -begin - Result:=0; - - buf:=nil; - if not gc_ring_pm4_alloc(ring,sizeof(PM4CMDSWITCHBUFFER),@buf) then - begin - Writeln(stderr,'### gc_switch_buffer_internal : Cannot allocate a space in ring buffer.'); - Exit(16); - end; - - //IT_SWITCH_BUFFER = $0000008b; - - buf^.header:=$c0008b00; - buf^.data :=0; - - gc_ring_pm4_submit(ring); -end; - var ring_gfx:t_pm4_ring; ring_gfx_lock:Pointer=nil; parse_gfx_td:p_kthread; +function PM4_LENGTH(token:DWORD):DWORD; inline; +begin + Result:=((token shr 14) and $FFFC) + 8; +end; + procedure parse_gfx_ring(parameter:pointer); SysV_ABI_CDecl; var buff:Pointer; - size:DWORD; + i,size,op,len:DWORD; begin repeat @@ -364,7 +123,30 @@ begin begin Writeln('packet:0x',HexStr(buff),':',size); - gc_ring_pm4_drain(@ring_gfx,size); + i:=size; + while (i<>0) do + begin + op:=PDWORD(buff)^; + len:=PM4_LENGTH(op); + if (len>i) then Exit; + + case op of + $c0023300:Writeln('INDIRECT_BUFFER_CNST'); + $c0023f00:Writeln('COND_INDIRECT_BUFFER'); + $c0008b00:Writeln('SWITCH_BUFFER'); + else; + end; + + Inc(buff,len); + Dec(i,len); + end; + + //buf:PPM4CMDINDIRECTBUFFER; + //Writeln('opcode =0x',HexStr(buf[i].header,8)); + //Writeln('ib_base=0x',HexStr(buf[i].ibBase,16)); + //Writeln('ib_size=0x',HexStr(buf[i].ibSize,3)); + + gc_ring_pm4_drain(@ring_gfx,size-i); end; msleep_td(100);