Initial commit

This commit is contained in:
red-prig 2021-12-08 23:04:07 +03:00
commit 49e069874b
74 changed files with 155915 additions and 0 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

19
.gitignore vendored Normal file
View File

@ -0,0 +1,19 @@
*.exe
*.dll
*.lps
*.ppu
*.bak
*.o
*.ini
*.db
*.txt
*.rar
*.bat
*.prx
*.sprx
link.res
lib/
backup/
shader_dump/
spirv/
savedata/

461
LFQueue.pas Normal file
View File

@ -0,0 +1,461 @@
{ Implimentation of Dmitry Vyukov Intrusive MPSC node-based queue on free pascal
Copyright (C) 2018-2020 Red_prig
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version with the following modification:
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent modules,and
to copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the terms
and conditions of the license of that module. An independent module is a
module which is not derived from or based on this library. If you modify
this library, you may extend this exception to your version of the library,
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
for more details.
}
unit LFQueue;
{$mode objfpc}{$H+}
interface
Const
CacheLineSize=64;
Type
TIntrusiveMPSCQueue=object
protected
type
PQNode=^TQNode;
TQNode=record
next_:PQNode;
//some data
end;
Var
tail_:PQNode;
stub_:TQNode;
head_:PQNode;
public
Procedure Create;
Function Push(Node:Pointer):Boolean;
Function Pop(Var Node:Pointer):Boolean;
Function IsEmpty:Boolean; inline;
end;
TIntrusiveMPSCQueueA=object
protected
type
PQNode=^TQNode;
TQNode=record
next_:PQNode;
//some data
end;
Var
tail_:record
Case Byte of
0:(Pad:Array[0..CacheLineSize-1] of Byte);
1:(VAL:PQNode;stub:TQNode);
end;
head_:record
Case Byte of
0:(Pad:Array[0..CacheLineSize-1] of Byte);
1:(VAL:PQNode);
end;
public
Procedure Create;
Function Push(Node:Pointer):Boolean;
Function Pop(Var Node:Pointer):Boolean;
Function IsEmpty:Boolean; inline;
end;
generic TLFQueue<TItem,Allocator,back_off>=object(TIntrusiveMPSCQueue)
type
PNode=^TNode;
TNode=record
next_:PNode;
Item:TItem;
end;
Function push_front(Const val:TItem):Boolean;
Function pop_back(Var val:TItem):Boolean;
end;
generic TLFQueueA<TItem,Allocator,back_off>=object(TIntrusiveMPSCQueueA)
type
PNode=^TNode;
TNode=record
next_:PNode;
Item:TItem;
end;
Function push_front(Const val:TItem):Boolean;
Function pop_back(Var val:TItem):Boolean;
end;
function load_consume(Var addr:Pointer):Pointer; inline;
function load_consume(Var addr:PtrUInt):PtrUInt; inline;
Procedure store_release(Var addr:Pointer;v:Pointer); inline;
function XCHG(Var addr:Pointer;New:Pointer):Pointer; inline;
implementation
function load_consume(Var addr:Pointer):Pointer; inline;
begin
ReadDependencyBarrier;
Result:=addr;
end;
function load_consume(Var addr:PtrUInt):PtrUInt; inline;
begin
ReadDependencyBarrier;
Result:=addr;
end;
Procedure store_release(Var addr:Pointer;v:Pointer); inline;
begin
WriteBarrier;
addr:=v;
end;
function XCHG(Var addr:Pointer;New:Pointer):Pointer; inline;
begin
Result:=System.InterLockedExchange(addr,New);
end;
//
Procedure TIntrusiveMPSCQueue.Create;
begin
FillChar(Self,SizeOf(Self),0);
head_:=@stub_;
tail_:=@stub_;
ReadWriteBarrier;
end;
Function TIntrusiveMPSCQueue.Push(Node:Pointer):Boolean;
Var
prev:PQNode;
begin
if not Assigned(Node) then Exit(False);
store_release(PQNode(Node)^.next_,nil);
prev:=XCHG(head_,Node);
store_release(prev^.next_,Node);
Result:=True;
end;
Function TIntrusiveMPSCQueue.Pop(Var Node:Pointer):Boolean;
Var
tail,n,head:PQNode;
begin
Node:=nil;
Result:=False;
tail:=tail_;
n:=load_consume(tail^.next_);
if tail=@stub_ then
begin
if n=nil then Exit;
store_release(tail_,n);
tail:=n;
n:=load_consume(n^.next_);
end;
if n<>nil then
begin
store_release(tail_,n);
Node:=tail;
store_release(tail^.next_,nil);
Exit(True);
end;
head:=head_;
if tail<>head then Exit;
stub_.next_:=nil;
n:=XCHG(head_,@stub_);
store_release(n^.next_,@stub_);
n:=load_consume(tail^.next_);
if n<>nil then
begin
store_release(tail_,n);
Node:=tail;
store_release(tail^.next_,nil);
Exit(True);
end;
end;
Function TIntrusiveMPSCQueue.IsEmpty:Boolean; inline;
begin
Result:=head_=@stub_;
end;
//
Procedure TIntrusiveMPSCQueueA.Create;
begin
FillChar(Self,SizeOf(Self),0);
head_.VAL:=@tail_.stub;
tail_.VAL:=@tail_.stub;
ReadWriteBarrier;
end;
Function TIntrusiveMPSCQueueA.Push(Node:Pointer):Boolean;
Var
prev:PQNode;
begin
if not Assigned(Node) then Exit(False);
store_release(PQNode(Node)^.next_,nil);
prev:=XCHG(head_.VAL,Node);
store_release(prev^.next_,Node);
Result:=True;
end;
Function TIntrusiveMPSCQueueA.Pop(Var Node:Pointer):Boolean;
Var
tail,n,head:PQNode;
begin
Node:=nil;
Result:=False;
tail:=tail_.VAL;
n:=load_consume(tail^.next_);
if tail=@tail_.stub then
begin
if n=nil then Exit;
store_release(tail_.VAL,n);
tail:=n;
n:=load_consume(n^.next_);
end;
if n<>nil then
begin
store_release(tail_.VAL,n);
Node:=tail;
store_release(tail^.next_,nil);
Exit(True);
end;
head:=head_.VAL;
if tail<>head then Exit;
tail_.stub.next_:=nil;
n:=XCHG(head_.VAL,@tail_.stub);
store_release(n^.next_,@tail_.stub);
n:=load_consume(tail^.next_);
if n<>nil then
begin
store_release(tail_.VAL,n);
Node:=tail;
store_release(tail^.next_,nil);
Exit(True);
end;
end;
Function TIntrusiveMPSCQueueA.IsEmpty:Boolean; inline;
begin
Result:=head_.VAL=@tail_.stub;
end;
//
Function TLFQueue.push_front(Const val:TItem):Boolean;
Var
Node:PNode;
begin
Node:=Allocator.AllocMem(SizeOf(TNode));
Result:=Push(Node);
end;
Function TLFQueue.pop_back(Var val:TItem):Boolean;
Var
tail,n,head:PQNode;
bkoff:back_off;
begin
Result:=False;
bkoff.Reset;
repeat
tail:=XCHG(tail_,nil);
if (tail<>nil) then
begin
Break;
end else
begin
bkoff.Wait;
end;
until false;
n:=load_consume(tail^.next_);
if tail=@stub_ then
begin
if n=nil then
begin
if tail=nil then tail:=@stub_;
store_release(tail_,tail); //unlock
Exit;
end;
tail:=n;
n:=load_consume(n^.next_);
end;
if n<>nil then
begin
val:=PNode(tail)^.Item;
FreeMem(tail);
if n=nil then n:=@stub_;
store_release(tail_,n); //unlock
Exit(True);
end;
head:=head_;
if tail<>head then
begin
if tail=nil then tail:=@stub_;
store_release(tail_,tail); //unlock
Exit;
end;
stub_.next_:=nil;
n:=XCHG(head_,@stub_);
store_release(n^.next_,@stub_);
n:=load_consume(tail^.next_);
if n<>nil then
begin
val:=PNode(tail)^.Item;
FreeMem(tail);
if n=nil then n:=@stub_;
store_release(tail_,n); //unlock
Exit(True);
end;
if tail=nil then tail:=@stub_;
store_release(tail_,tail); //unlock
end;
//
Function TLFQueueA.push_front(Const val:TItem):Boolean;
Var
Node:PNode;
begin
Node:=Allocator.AllocMem(SizeOf(TNode));
Result:=Push(Node);
end;
Function TLFQueueA.pop_back(Var val:TItem):Boolean;
Var
tail,n,head:PQNode;
bkoff:back_off;
begin
Result:=False;
bkoff.Reset;
repeat
tail:=XCHG(tail_.VAL,nil);
if (tail<>nil) then
begin
Break;
end else
begin
bkoff.Wait;
end;
until false;
n:=load_consume(tail^.next_);
if tail=@tail_.stub then
begin
if n=nil then
begin
if tail=nil then tail:=@tail_.stub;
store_release(tail_.VAL,tail); //unlock
Exit;
end;
tail:=n;
n:=load_consume(n^.next_);
end;
if n<>nil then
begin
val:=PNode(tail)^.Item;
FreeMem(tail);
if n=nil then n:=@tail_.stub;
store_release(tail_.VAL,n); //unlock
Exit(True);
end;
head:=head_.VAL;
if tail<>head then
begin
if tail=nil then tail:=@tail_.stub;
store_release(tail_.VAL,tail); //unlock
Exit;
end;
tail_.stub.next_:=nil;
n:=XCHG(head_.VAL,@tail_.stub);
store_release(n^.next_,@tail_.stub);
n:=load_consume(tail^.next_);
if n<>nil then
begin
val:=PNode(tail)^.Item;
FreeMem(tail);
if n=nil then n:=@tail_.stub;
store_release(tail_.VAL,n); //unlock
Exit(True);
end;
if tail=nil then tail:=@tail_.stub;
store_release(tail_.VAL,tail); //unlock
end;
end.

504
LICENSE Normal file
View File

@ -0,0 +1,504 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random
Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

14
README.md Normal file
View File

@ -0,0 +1,14 @@
# fpPS4
** PS4 compatibility layer (emulator) on Free Pascal**
This project is at the beginning and started for fun.
### Building
- Free pascal compiler: 3.0.0 and higher
- Lazarus: 2.0.0 and higher
### Minimum system requirements
- OS: Windows 7 x64 and higher
- CPU: x64, AVX1 support
- GPU: Vulkan API support

420
RWLock.pas Normal file
View File

@ -0,0 +1,420 @@
{ Implementation of Slim read-write lock based on https://github.com/neosmart/RWLock
Copyright (C) 2018-2020 Red_prig
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version with the following modification:
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent modules,and
to copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the terms
and conditions of the license of that module. An independent module is a
module which is not derived from or based on this library. If you modify
this library, you may extend this exception to your version of the library,
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
for more details.
}
unit RWLock;
{$mode objfpc}{$H+}
interface
{$IFDEF UNIX}
{$DEFINE SMART} //Force NeoSmart algoritm
{$ENDIF}
{/$DEFINE SMART}
{$IF DEFINED(UNIX)) and (not DEFINED(SMART))}
uses
UnixType,pthreads;
type
TRWLock=pthread_rwlock_t;
{$ELSE}
{$IF DEFINED(WINDOWS) and (not DEFINED(SMART))}
uses
Windows;
{$ENDIF}
type
TRWLock=packed record
Case Byte of
0:(SRWLock:Pointer;Mode:SizeInt);
1:(Event:PRTLEvent;vLock:DWORD);
end;
{$ENDIF}
Procedure rwlock_init(Var L:TRWLock);
Procedure rwlock_destroy(Var L:TRWLock);
Procedure rwlock_rdlock(Var L:TRWLock);
Procedure rwlock_wrlock(Var L:TRWLock);
function rwlock_tryrdlock(Var L:TRWLock):Boolean;
function rwlock_trywrlock(Var L:TRWLock):Boolean;
Procedure rwlock_unlock(Var L:TRWLock);
implementation
{$IF DEFINED(WINDOWS) and (not DEFINED(SMART))}
type
TSRWLockProc=procedure(Var SRWLock:Pointer); stdcall;
TSRWLockTryFunc=Function(Var SRWLock:Pointer):Boolean; stdcall;
Var
InitializeSRWLock,
AcquireSRWLockShared,
ReleaseSRWLockShared,
AcquireSRWLockExclusive,
ReleaseSRWLockExclusive:TSRWLockProc;
TryAcquireSRWLockShared,
TryAcquireSRWLockExclusive:TSRWLockTryFunc;
Procedure LoadSRW;
Var
Handle:THandle;
begin
InitializeSRWLock :=nil;
AcquireSRWLockShared :=nil;
ReleaseSRWLockShared :=nil;
AcquireSRWLockExclusive :=nil;
ReleaseSRWLockExclusive :=nil;
TryAcquireSRWLockShared :=nil;
TryAcquireSRWLockExclusive:=nil;
Handle:=GetModuleHandle('kernel32.dll');
if Handle<>INVALID_HANDLE_VALUE then
begin
Pointer(InitializeSRWLock ):=GetProcAddress(Handle,'InitializeSRWLock');
if InitializeSRWLock<>nil then
begin
Pointer(AcquireSRWLockShared ):=GetProcAddress(Handle,'AcquireSRWLockShared');
Pointer(ReleaseSRWLockShared ):=GetProcAddress(Handle,'ReleaseSRWLockShared');
Pointer(AcquireSRWLockExclusive ):=GetProcAddress(Handle,'AcquireSRWLockExclusive');
Pointer(ReleaseSRWLockExclusive ):=GetProcAddress(Handle,'ReleaseSRWLockExclusive');
Pointer(TryAcquireSRWLockShared ):=GetProcAddress(Handle,'TryAcquireSRWLockShared');
Pointer(TryAcquireSRWLockExclusive):=GetProcAddress(Handle,'TryAcquireSRWLockExclusive');
end;
end;
end;
{$ENDIF}
{$IF (not DEFINED(UNIX)) or DEFINED(SMART)}
Const
MAX_SPIN=50000;
function ReaderCount(lock:DWORD):WORD; inline;
begin
Result:=WORD(lock and $00007FFF);
end;
function SetReaders(lock:DWORD;readers:WORD):DWORD; inline;
begin
Result:=(lock and (not $00007FFF)) or readers;
end;
function WaitingCount(lock:DWORD):WORD; inline;
begin
Result:=WORD((lock and $3FFF8000) shr 15);
end;
function SetWaiting(lock:DWORD;waiting:WORD):DWORD; inline;
begin
Result:=(lock and (not $3FFF8000)) or (waiting shl 15);
end;
function Writer(lock:DWORD):Boolean; inline;
begin
Result:=(lock and $40000000)<>0;
end;
function SetWriter(lock:DWORD;writer:Boolean):DWORD; inline;
begin
if writer then
Result:=lock or $40000000
else
Result:=lock and (not $40000000);
end;
function AllClear(lock:DWORD):Boolean; inline;
begin
Result:=(lock and $40007FFF)=0;
end;
function Initialized(lock:DWORD):Boolean; inline;
begin
Result:=(lock and $80000000)<>0;
end;
function SetInitialized(lock:DWORD;init:Boolean):DWORD; inline;
begin
if init then
Result:=lock or $80000000
else
Result:=lock and (not $80000000);
end;
Procedure _rdlock(Var vLock:DWORD;Event:PRTLEvent); inline;
Var
i:SizeUInt;
temp:DWORD;
begin
i:=0;
repeat
temp:=vLock;
if not Writer(temp) then
begin
if System.InterlockedCompareExchange(vLock,SetReaders(temp,ReaderCount(temp)+1),temp)=temp then
Break
else
Continue;
end else
begin
if (i<MAX_SPIN) then
begin
ThreadSwitch;
Continue;
end;
if System.InterlockedCompareExchange(vLock,SetWaiting(temp,WaitingCount(temp)+1),temp)<>temp then
Continue;
RTLeventWaitFor(Event);
i:=0;
repeat
temp:=vLock;
if (i>MAX_SPIN) then
begin
ThreadSwitch;
Continue;
end;
Inc(i);
until System.InterlockedCompareExchange(vLock,SetWaiting(temp,WaitingCount(temp)-1),temp)=temp;
i:=0;
end;
Inc(i);
until False;
end;
Procedure _wrlock(Var vLock:DWORD;Event:PRTLEvent); inline;
Var
i:SizeUInt;
temp:DWORD;
begin
i:=0;
repeat
temp:=vLock;
if AllClear(temp) then
begin
if System.InterlockedCompareExchange(vLock,SetWriter(temp,true),temp)=temp then
Break
else
Continue;
end else
begin
if (i<MAX_SPIN) then
begin
ThreadSwitch;
Continue;
end;
if System.InterlockedCompareExchange(vLock,SetWaiting(temp,WaitingCount(temp)+1),temp)<>temp then
Continue;
RTLeventWaitFor(Event);
i:=0;
repeat
temp:=vLock;
if (i>MAX_SPIN) then
begin
ThreadSwitch;
Continue;
end;
Inc(i);
until System.InterlockedCompareExchange(vLock,SetWaiting(temp,WaitingCount(temp)-1),temp)=temp;
i:=0;
end;
Inc(i);
until False;
end;
Procedure _unlock(Var vLock:DWORD;Event:PRTLEvent); inline;
Var
temp:DWORD;
begin
if ReaderCount(vLock)=0 then
begin
repeat
repeat
temp:=vLock;
if (WaitingCount(temp)=0) then break;
RTLeventSetEvent(Event);
until False;
until System.InterlockedCompareExchange(vLock,SetWriter(temp,false),temp)=temp;
end else
begin
repeat
temp:=vLock;
if (ReaderCount(temp)=1) and (WaitingCount(temp)<>0) then
RTLeventSetEvent(Event);
until System.InterlockedCompareExchange(vLock,SetReaders(temp,ReaderCount(temp)-1),temp)=temp;
end;
end;
function _tryrdlock(Var vLock:DWORD):Boolean; inline;
Var
temp:DWORD;
begin
Result:=False;
temp:=vLock;
if not Writer(temp) then
begin
if System.InterlockedCompareExchange(vLock,SetReaders(temp,ReaderCount(temp)+1),temp)=temp then
Result:=True;
end;
end;
function _trywrlock(Var vLock:DWORD):Boolean; inline;
Var
temp:DWORD;
begin
Result:=False;
temp:=vLock;
if AllClear(temp) then
begin
if System.InterlockedCompareExchange(vLock,SetWriter(temp,true),temp)=temp then
Result:=True;
end;
end;
{$ENDIF}
Procedure rwlock_init(Var L:TRWLock);
begin
{$IF DEFINED(UNIX)) and (not DEFINED(SMART))}
pthread_rwlock_init(@L,nil);
{$ELSE}
L:=Default(TRWLock);
{$IF DEFINED(WINDOWS) and (not DEFINED(SMART))}
if InitializeSRWLock<>nil then
begin
InitializeSRWLock(L.SRWLock);
L.Mode:=0;
end else
{$ENDIF}
begin
L.vLock:=SetInitialized(0,true);
L.Event:=RTLEventCreate;
end;
{$ENDIF}
end;
Procedure rwlock_destroy(Var L:TRWLock);
begin
{$IF DEFINED(UNIX)) and (not DEFINED(SMART))}
pthread_rwlock_destroy(@L);
{$ELSE}
{$IF DEFINED(WINDOWS) and (not defined(SMART))}
if InitializeSRWLock=nil then
{$ENDIF}
RTLEventDestroy(L.Event);
{$ENDIF}
end;
Procedure rwlock_rdlock(Var L:TRWLock);
begin
{$IF DEFINED(UNIX)) and (not DEFINED(SMART))}
pthread_rwlock_rdlock(@L);
{$ELSE}
{$IF DEFINED(WINDOWS) and (not DEFINED(SMART))}
if InitializeSRWLock<>nil then
begin
AcquireSRWLockShared(L.SRWLock);
L.Mode:=1;
end else
{$ENDIF}
_rdlock(L.vLock,L.Event);
{$ENDIF}
end;
Procedure rwlock_wrlock(Var L:TRWLock);
begin
{$IF DEFINED(UNIX)) and (not DEFINED(SMART))}
pthread_rwlock_wrlock(@L);
{$ELSE}
{$IF DEFINED(WINDOWS) and (not DEFINED(SMART))}
if InitializeSRWLock<>nil then
begin
AcquireSRWLockExclusive(L.SRWLock);
L.Mode:=2;
end else
{$ENDIF}
_wrlock(L.vLock,L.Event);
{$ENDIF}
end;
function rwlock_tryrdlock(Var L:TRWLock):Boolean;
begin
{$IF DEFINED(UNIX)) and (not DEFINED(SMART))}
Result:=pthread_rwlock_tryrdlock(@L)=0;
{$ELSE}
{$IF DEFINED(WINDOWS) and (not DEFINED(SMART))}
if InitializeSRWLock<>nil then
begin
Result:=TryAcquireSRWLockShared(L.SRWLock);
if Result then
L.Mode:=1;
end else
{$ENDIF}
Result:=_tryrdlock(L.vLock);
{$ENDIF}
end;
function rwlock_trywrlock(Var L:TRWLock):Boolean;
begin
{$IF DEFINED(UNIX)) and (not DEFINED(SMART))}
Result:=pthread_rwlock_trywrlock(@L)=0;
{$ELSE}
{$IF DEFINED(WINDOWS) and (not DEFINED(SMART))}
if InitializeSRWLock<>nil then
begin
Result:=TryAcquireSRWLockExclusive(L.SRWLock);
if Result then
L.Mode:=2;
end else
{$ENDIF}
Result:=_trywrlock(L.vLock);
{$ENDIF}
end;
Procedure rwlock_unlock(Var L:TRWLock);
begin
{$IF DEFINED(UNIX)) and (not DEFINED(SMART))}
pthread_rwlock_unlock(@L);
{$ELSE}
{$IF DEFINED(WINDOWS) and (not DEFINED(SMART))}
if InitializeSRWLock<>nil then
begin
if L.SRWLock<>nil then
Case L.Mode of
1:ReleaseSRWLockShared(L.SRWLock);
2:ReleaseSRWLockExclusive(L.SRWLock);
end;
end else
{$ENDIF}
_unlock(L.vLock,L.Event);
{$ENDIF}
end;
{$IF DEFINED(WINDOWS) and (not DEFINED(SMART))}
initialization
begin
LoadSRW;
end;
{$ENDIF}
end.

48
bittype.pas Normal file
View File

@ -0,0 +1,48 @@
unit bittype;
{$mode objfpc}{$H+}
interface
type
bit1=0..1;
bit2=0..3;
bit3=0..7;
bit4=0..15;
bit5=0..31;
bit6=0..63;
bit7=0..127;
bit8=Byte;
bit9=0..511;
bit10=0..1023;
bit11=0..2047;
bit12=0..4095;
bit13=0..8191;
bit14=0..16383;
bit15=0..32767;
bit16=Word;
bit17=0..131071;
bit18=0..262143;
bit19=0..524287;
bit20=0..1048575;
bit21=0..2097151;
bit22=0..4194303;
bit23=0..8388607;
bit24=0..16777215;
bit25=0..33554431;
bit26=0..67108863;
bit27=0..134217727;
bit28=0..268435455;
bit29=0..536870911;
bit30=0..1073741823;
bit31=0..2147483647;
bit32=DWORD;
bit38=0..274877906943;
bit44=0..17592186044415;
bit48=0..281474976710655;
bit64=QWORD;
implementation
end.

501
chip/pm4defs.pas Normal file
View File

@ -0,0 +1,501 @@
unit pm4defs;
{$mode objfpc}{$H+}
interface
uses
bittype,
si_ci_vi_merged_registers;
const
IT_NOP = $00000010;
IT_SET_BASE = $00000011;
IT_CLEAR_STATE = $00000012;
IT_INDEX_BUFFER_SIZE = $00000013;
IT_DISPATCH_DIRECT = $00000015;
IT_DISPATCH_INDIRECT = $00000016;
IT_INDIRECT_BUFFER_END = $00000017;
IT_INDIRECT_BUFFER_CNST_END = $00000019;
IT_ATOMIC_GDS = $0000001d;
IT_ATOMIC_MEM = $0000001e;
IT_OCCLUSION_QUERY = $0000001f;
IT_SET_PREDICATION = $00000020;
IT_REG_RMW = $00000021;
IT_COND_EXEC = $00000022;
IT_PRED_EXEC = $00000023;
IT_DRAW_INDIRECT = $00000024;
IT_DRAW_INDEX_INDIRECT = $00000025;
IT_INDEX_BASE = $00000026;
IT_DRAW_INDEX_2 = $00000027;
IT_CONTEXT_CONTROL = $00000028;
IT_INDEX_TYPE = $0000002a;
IT_DRAW_INDIRECT_MULTI = $0000002c;
IT_DRAW_INDEX_AUTO = $0000002d;
IT_NUM_INSTANCES = $0000002f;
IT_DRAW_INDEX_MULTI_AUTO = $00000030;
IT_INDIRECT_BUFFER_PRIV = $00000032;
IT_INDIRECT_BUFFER_CNST = $00000033;
IT_COND_INDIRECT_BUFFER_CNST = $00000033;
IT_STRMOUT_BUFFER_UPDATE = $00000034;
IT_DRAW_INDEX_OFFSET_2 = $00000035;
IT_DRAW_PREAMBLE = $00000036;
IT_WRITE_DATA = $00000037;
IT_DRAW_INDEX_INDIRECT_MULTI = $00000038;
IT_MEM_SEMAPHORE = $00000039;
IT_DRAW_INDEX_MULTI_INST = $0000003a;
IT_COPY_DW = $0000003b;
IT_WAIT_REG_MEM = $0000003c;
IT_INDIRECT_BUFFER = $0000003f;
IT_COND_INDIRECT_BUFFER = $0000003f;
IT_COPY_DATA = $00000040;
IT_CP_DMA = $00000041;
IT_PFP_SYNC_ME = $00000042;
IT_SURFACE_SYNC = $00000043;
IT_ME_INITIALIZE = $00000044;
IT_COND_WRITE = $00000045;
IT_EVENT_WRITE = $00000046;
IT_EVENT_WRITE_EOP = $00000047;
IT_EVENT_WRITE_EOS = $00000048;
IT_RELEASE_MEM = $00000049;
IT_PREAMBLE_CNTL = $0000004a;
IT_DRAW_RESERVED0 = $0000004c;
IT_DRAW_RESERVED1 = $0000004d;
IT_DRAW_RESERVED2 = $0000004e;
IT_DRAW_RESERVED3 = $0000004f;
IT_DMA_DATA = $00000050;
IT_CONTEXT_REG_RMW = $00000051;
IT_GFX_CNTX_UPDATE = $00000052;
IT_BLK_CNTX_UPDATE = $00000053;
IT_INCR_UPDT_STATE = $00000055;
IT_ACQUIRE_MEM = $00000058;
IT_REWIND = $00000059;
IT_INTERRUPT = $0000005a;
IT_GEN_PDEPTE = $0000005b;
IT_INDIRECT_BUFFER_PASID = $0000005c;
IT_PRIME_UTCL2 = $0000005d;
IT_LOAD_UCONFIG_REG = $0000005e;
IT_LOAD_SH_REG = $0000005f;
IT_LOAD_CONFIG_REG = $00000060;
IT_LOAD_CONTEXT_REG = $00000061;
IT_LOAD_COMPUTE_STATE = $00000062;
IT_LOAD_SH_REG_INDEX = $00000063;
IT_SET_CONFIG_REG = $00000068;
IT_SET_CONTEXT_REG = $00000069;
IT_SET_CONTEXT_REG_INDEX = $0000006a;
IT_SET_VGPR_REG_DI_MULTI = $00000071;
IT_SET_SH_REG_DI = $00000072;
IT_SET_CONTEXT_REG_INDIRECT = $00000073;
IT_SET_SH_REG_DI_MULTI = $00000074;
IT_GFX_PIPE_LOCK = $00000075;
IT_SET_SH_REG = $00000076;
IT_SET_SH_REG_OFFSET = $00000077;
IT_SET_QUEUE_REG = $00000078;
IT_SET_UCONFIG_REG = $00000079;
IT_SET_UCONFIG_REG_INDEX = $0000007a;
IT_FORWARD_HEADER = $0000007c;
IT_SCRATCH_RAM_WRITE = $0000007d;
IT_SCRATCH_RAM_READ = $0000007e;
IT_LOAD_CONST_RAM = $00000080;
IT_WRITE_CONST_RAM = $00000081;
IT_DUMP_CONST_RAM = $00000083;
IT_INCREMENT_CE_COUNTER = $00000084;
IT_INCREMENT_DE_COUNTER = $00000085;
IT_WAIT_ON_CE_COUNTER = $00000086;
IT_WAIT_ON_DE_COUNTER_DIFF = $00000088;
IT_SWITCH_BUFFER = $0000008b;
IT_FRAME_CONTROL = $00000090;
IT_INDEX_ATTRIBUTES_INDIRECT = $00000091;
IT_WAIT_REG_MEM64 = $00000093;
IT_COND_PREEMPT = $00000094;
IT_HDP_FLUSH = $00000095;
IT_INVALIDATE_TLBS = $00000098;
IT_DMA_DATA_FILL_MULTI = $0000009a;
IT_SET_SH_REG_INDEX = $0000009b;
IT_DRAW_INDIRECT_COUNT_MULTI = $0000009c;
IT_DRAW_INDEX_INDIRECT_COUNT_MULTI = $0000009d;
IT_DUMP_CONST_RAM_OFFSET = $0000009e;
IT_LOAD_CONTEXT_REG_INDEX = $0000009f;
IT_SET_RESOURCES = $000000a0;
IT_MAP_PROCESS = $000000a1;
IT_MAP_QUEUES = $000000a2;
IT_UNMAP_QUEUES = $000000a3;
IT_QUERY_STATUS = $000000a4;
IT_RUN_LIST = $000000a5;
IT_MAP_PROCESS_VM = $000000a6;
//OP_HINT_NOP=0;
OP_HINT_1920_1080=$04380780;
OP_HINT_1860_1080=$04380744;
OP_HINT_320_240 =$00F00140;
OP_HINT_WRITE_GPU_PREFETCH_INTO_L2 =$60000000;
OP_HINT_BASE_ALLOCATE_FROM_COMMAND_BUFFER =$68750000;
OP_HINT_PUSH_MARKER =$68750001;
OP_HINT_POP_MARKER =$68750002;
OP_HINT_SET_VSHARP_IN_USER_DATA =$68750004;
OP_HINT_SET_TSHARP_IN_USER_DATA =$68750005;
OP_HINT_SET_SSHARP_IN_USER_DATA =$68750006;
OP_HINT_SET_USER_DATA_REGION =$6875000D;
OP_HINT_BASE_MARK_DISPATCH_DRAW_ACB_ADDRESS =$68750012;
OP_HINT_PREPARE_FLIP_VOID =$68750777;
OP_HINT_PREPARE_FLIP_LABEL =$68750778;
OP_HINT_PREPARE_FLIP_WITH_EOP_INTERRUPT_VOID =$68750780;
OP_HINT_PREPARE_FLIP_WITH_EOP_INTERRUPT_LABEL =$68750781;
OP_HINT_INLINE_DATA1 =$68752000;
OP_HINT_INLINE_DATA2 =$68753000;
OP_HINT_SET_DB_RENDER_CONTROL =$00000000;
OP_HINT_SET_DB_COUNT_CONTROL =$00000001;
OP_HINT_SET_RENDER_OVERRIDE_CONTROL =$00000003;
OP_HINT_SET_RENDER_OVERRIDE2CONTROL =$00000004;
OP_HINT_SET_PS_SHADER_SAMPLE_EXCLUSION_MASK =$00000006;
OP_HINT_SET_DEPTH_BOUNDS_RANGE =$00000008;
OP_HINT_SET_STENCIL_CLEAR_VALUE =$0000000A;
OP_HINT_SET_DEPTH_CLEAR_VALUE =$0000000B;
OP_HINT_SET_SCREEN_SCISSOR =$0000000C;
OP_HINT_SET_DEPTH_RENDER_TARGET =$00000010;
OP_HINT_SET_BORDER_COLOR_TABLE_ADDR =$00000020;
OP_HINT_SET_WINDOW_OFFSET =$00000080;
OP_HINT_SET_WINDOW_SCISSOR =$00000081;
OP_HINT_SET_CLIP_RECTANGLE_RULE =$00000083;
OP_HINT_SET_HARDWARE_SCREEN_OFFSET =$0000008D;
OP_HINT_SET_RENDER_TARGET_MASK =$0000008E;
OP_HINT_SET_GENERIC_SCISSOR =$00000090;
OP_HINT_SET_PERFMON_ENABLE =$000000D8;
OP_HINT_SET_SCALED_RESOLUTION_GRID =$000000E8;
OP_HINT_SET_FOVEATED_WINDOW =$000000EB;
OP_HINT_SET_RESET_FOVEATED_WINDOW =$000000EB;
OP_HINT_SET_INDEX_OFFSET =$00000102;
OP_HINT_SET_PRIMITIVE_RESET_INDEX =$00000103;
OP_HINT_SET_STENCIL_OP_CONTROL =$0000010B;
OP_HINT_SET_STENCIL =$0000010C;
OP_HINT_SET_STENCIL_SEPARATE =$0000010C;
OP_HINT_SET_PS_SHADER_USAGE =$00000191;
OP_HINT_SET_GRAPHICS_SCRATCH_SIZE =$000001BA;
OP_HINT_SET_DEPTH_STENCIL_CONTROL =$00000200;
OP_HINT_SET_DEPTH_STENCIL_DISABLE =$00000200;
OP_HINT_SET_DEPTH_EQAA_CONTROL =$00000201;
OP_HINT_SET_CB_CONTROL =$00000202;
OP_HINT_SET_CLIP_CONTROL =$00000204;
OP_HINT_SET_PRIMITIVE_SETUP =$00000205;
OP_HINT_SET_VIEWPORT_TRANSFORM_CONTROL =$00000206;
OP_HINT_SET_OBJECT_ID_MODE =$0000020D;
OP_HINT_SET_COMPUTE_SHADER_CONTROL =$00000215;
OP_HINT_SET_COMPUTE_SCRATCH_SIZE =$00000218;
OP_HINT_SET_PRIMITIVE_TYPE_BASE =$00000242;
OP_HINT_SET_POINT_SIZE =$00000280;
OP_HINT_SET_POINT_MIN_MAX =$00000281;
OP_HINT_SET_LINE_WIDTH =$00000282;
OP_HINT_GS_MODE_ENABLE =$00000290;
OP_HINT_SET_GS_MODE =$00000290;
OP_HINT_GS_MODE_ENABLE_ON_CHIP =$00000291;
OP_HINT_SET_GS_ON_CHIP_CONTROL =$00000291;
OP_HINT_SET_SCAN_MODE_CONTROL =$00000292;
OP_HINT_SET_PS_SHADER_RATE =$00000293;
OP_HINT_SET_PRIMITIVE_ID_ENABLE =$000002A1;
OP_HINT_SET_PRIMITIVE_RESET_INDEX_ENABLE =$000002A5;
OP_HINT_SET_DRAW_PAYLOAD_CONTROL =$000002A6;
OP_HINT_SET_INSTANCE_STEP_RATE =$000002A8;
OP_HINT_SETUP_ES_GS_RING_REGISTERS =$000002AB;
OP_HINT_SET_VERTEX_REUSE_ENABLE =$000002AD;
OP_HINT_SET_HTILE_STENCIL0 =$000002B0;
OP_HINT_SET_HTILE_STENCIL1 =$000002B1;
OP_HINT_SETUP_DRAW_OPAQUE_PARAMETERS_1 =$000002CA;
OP_HINT_SETUP_DRAW_OPAQUE_PARAMETERS_0 =$000002CC;
OP_HINT_SET_TESSELLATION_DISTRIBUTION_THRESHOLDS =$000002D4;
OP_HINT_SET_ACTIVE_SHADER_STAGES =$000002D5;
OP_HINT_SETUP_GS_VS_RING_REGISTERS =$000002D7;
OP_HINT_SET_ALPHA_TO_MASK_CONTROL =$000002DC;
OP_HINT_SET_DISPATCH_DRAW_INDEX_DEALLOCATION_MASK=$000002DD;
OP_HINT_SET_POLYGON_OFFSET_Z_FORMAT =$000002DE;
OP_HINT_SET_POLYGON_OFFSET_CLAMP =$000002DF;
OP_HINT_SET_POLYGON_OFFSET_FRONT =$000002E0;
OP_HINT_SET_POLYGON_OFFSET_BACK =$000002E2;
OP_HINT_GS_MODE_DISABLE =$000002E5;
OP_HINT_SET_GS_MODE_DISABLE =$000002E5;
OP_HINT_SET_VS_SHADER_STREAMOUT_ENABLE =$000002E5;
OP_HINT_SET_STREAMOUT_MAPPING =$000002E6;
OP_HINT_SET_AA_SAMPLE_COUNT =$000002F8;
OP_HINT_SET_VERTEX_QUANTIZATION =$000002F9;
OP_HINT_SET_GUARD_BANDS =$000002FA;
OP_HINT_SET_AA_SAMPLE_MASK1 =$0000030E;
OP_HINT_SET_AA_SAMPLE_MASK2 =$0000030F;
OP_HINT_SET_TEXTURE_GRADIENT_FACTORS =$00000382;
OP_HINT_SET_PERF_COUNTER_CONTROL_PA =$00001808;
OP_HINT_SET_PRIMITIVE_TYPE_NEO =$10000242;
type
PPM4_HEADER=^PM4_HEADER;
PM4_HEADER=bitpacked record
reserved:Word; //16
count:bit14; //14
_type:bit2; //2
end;
PPM4_TYPE_0_HEADER=^PM4_TYPE_0_HEADER;
PM4_TYPE_0_HEADER=bitpacked record
baseIndex:Word; //16
count:bit14; //14
_type:bit2; //2
end;
PPM4_TYPE_3_HEADER=^PM4_TYPE_3_HEADER;
PM4_TYPE_3_HEADER=bitpacked record
predicate:bit1; //1
shaderType:bit1; //1
reserved:bit6; //6
opcode:Byte; //8
count:bit14; //14
_type:bit2; //2
end;
PPM4PrepareFlip=^TPM4PrepareFlip;
TPM4PrepareFlip=packed record
ADDRES_LO:DWORD;
ADDRES_HI:DWORD;
DATA:DWORD;
end;
PPM4PrepareFlipWithEopInterrupt=^TPM4PrepareFlipWithEopInterrupt;
TPM4PrepareFlipWithEopInterrupt=packed record
ADDRES_LO:DWORD;
ADDRES_HI:DWORD;
DATA:DWORD;
eventType:DWORD;
cacheAction:DWORD;
end;
PTPM4CMDWRITEDATA=^TPM4CMDWRITEDATA;
TPM4CMDWRITEDATA=packed record
CONTROL:bitpacked record
reserved1 :bit8;
dstSel :bit4; ///< destination select
reserved2 :bit4;
wrOneAddr :bit1; ///< Increment or not increment address
reserved3 :bit3;
wrConfirm :bit1; ///< Wait or not wait for confirmation
reserved4 :bit3;
atc :bit1;
cachePolicy:bit2; ///< Cache olicy settings for write requests to the TCL2
volatile :bit1; ///< Volatile setting for write requests to the TCL2
reserved5 :bit2;
engineSel :bit2; ///< engine select
end;
dstAddrLo:DWORD;
dstAddrHi:DWORD;
data:packed record end;
end;
PEVENTWRITEEOP=^TEVENTWRITEEOP;
TEVENTWRITEEOP=packed record
EVENT_CNTL:bitpacked record
EVENT_TYPE:bit6; //6 ///< event type written to VGT_EVENT_INITIATOR
Reserved1:bit2; //2
EVENT_INDEX:bit4; //4 ///< event index
tcl1VolActionEna__CI:bit1; //1
tcVolActionEna__CI :bit1; //1
reserved2:bit1; //1
tcWbActionEna__CI:bit1; //1
tcl1ActionEna__CI:bit1; //1
tcActionEna__CI:bit1; //1
reserved3:bit2; //2
invalidateL2__SI:bit1; //1
reserved4:bit3; //3
atc__CI:bit1; //1
cachePolicy__CI:bit2; //2 ///< Cache Policy setting used for writing fences and timestamps to the TCL2
volatile__CI:bit1; //1 ///< Volatile setting used for writing fences and timestamps to the TCL2.
reserved5:bit4; //4
end;
ADDRESS_LO:DWORD; ///< low bits of address
DATA_CNTL:bitpacked record
ADDRESS_HI:bit24;//24 ///< high bits of address
INT_SEL:bit2; //2 ///< selects interrupt action for end-of-pipe
Reserved:bit3; //3 ///< reserved
DATA_SEL:bit3; //3 ///< selects source of data
end;
DATA_LO:DWORD; ///< value that will be written to memory when event occurs
DATA_HI:DWORD; ///< value that will be written to memory when event occurs
end;
PTPM4CMDEVENTWRITEEOS=^TPM4CMDEVENTWRITEEOS;
TPM4CMDEVENTWRITEEOS=bitpacked record
eventType :bit6; ///< event type written to VGT_EVENT_INITIATOR
reserved1 :bit2; ///< reserved
eventIndex :bit4; ///< event index
reserved2 :bit20; ///< reserved
addressLo:DWORD; ///< low bits of address, must be 4 byte aligned
addressHi :bit29; ///< high bits of address
command :bit3; ///< command
Case byte of
0:(
gdsIndex:Word; ///< indexed offset into GDS partition
size :Word; ///< number of DWs to read from the GDS
);
1:(
data:DWORD; ///< fence value that will be written to memory when event occurs
);
end;
PTPM4CMDEVENTWRITE=^TPM4CMDEVENTWRITE;
TPM4CMDEVENTWRITE=bitpacked record
eventType :bit6; ///< event type written to VGT_EVENT_INITIATOR
reserved1 :bit2; ///< reserved
eventIndex :bit4; ///< event index
///< 0000: Any non-Time Stamp/non-Fence/non-Trap EVENT_TYPE not listed.
///< 0001: ZPASS_DONE
///< 0010: SAMPLE_PIPELINESTATS
///< 0011: SAMPLE_STREAMOUTSTAT[S|S1|S2|S3]
///< 0100: [CS|VS|PS]_PARTIAL_FLUSH
///< 0101: Reserved for EVENT_WRITE_EOP time stamp/fence event types
///< 0110: Reserved for EVENT_WRITE_EOS packet
///< 0111: CACHE_FLUSH, CACHE_FLUSH_AND_INV_EVENT
///< 1000 - 1111: Reserved for future use.
reserved2 :bit8; ///< reserved
invalidateL2 :bit1; ///< Send WBINVL2 op to the TC L2 cache when eventIndex = 0111.
reserved3 :bit3;
ATC :bit1; ///< needed by Sample_PipelineStats (compute engine)
reserved4 :bit6; ///< reserved
offload_enable :bit1; ///< Offload queue until EOP queue goes empty, only works for MEC. ///< Setting this bit on graphics/ME will do nothing/be masked out.
end;
PTPM4DMADATA=^TPM4DMADATA;
TPM4DMADATA=packed record
Flags1:bitpacked record
engine :bit1;
reserved1 :bit11;
srcATC :bit1;
srcCachePolicy :bit2;
srcVolatile :bit1;
reserved2 :bit4;
dstSel :bit2;
reserved3 :bit2;
dstATC :bit1;
dstCachePolicy :bit2;
dstVolatile :bit1;
reserved4 :bit1;
srcSel :bit2;
cpSync :bit1;
end;
srcAddrLo:DWORD;
srcAddrHi:DWORD;
dstAddrLo:DWORD;
dstAddrHi:DWORD;
Flags2:bitpacked record
byteCount :bit21;
disWC :bit1;
srcSwap :bit2;
dstSwap :bit2;
sas :bit1;
das :bit1;
saic :bit1;
daic :bit1;
rawWait :bit1;
reserved5 :bit1;
end;
end;
PPM4ACQUIREMEM=^TPM4ACQUIREMEM;
TPM4ACQUIREMEM=bitpacked record
coherCntl :bit31;
engine :bit1;
coherSize :DWORD;
coherSizeHi :bit8;
coherSizeHiRsvd:bit16;
reserved1 :bit8;
coherBaseLo :DWORD;
coherBaseHi :bit24;
reserved2 :bit8;
pollInterval :bit16;
reserved3 :bit16;
end;
TCONTEXTCONTROLENABLE=bitpacked record
enableSingleCntxConfigReg:bit1; ///< single context config reg
enableMultiCntxRenderReg :bit1; ///< multi context render state reg
reserved1 :bit13; ///< reserved
enableUserConfigReg :bit1; ///< User Config Reg on CI(reserved for SI)
enableGfxSHReg :bit1; ///< Gfx SH Registers
reserved2 :bit7; ///< reserved
enableCSSHReg :bit1; ///< CS SH Registers
reserved3 :bit6; ///< reserved
enableDw :bit1; ///< DW enable
end;
PPM4CMDCONTEXTCONTROL=^TPM4CMDCONTEXTCONTROL;
TPM4CMDCONTEXTCONTROL=bitpacked record
loadControl :TCONTEXTCONTROLENABLE; ///< enable bits for loading
shadowEnable:TCONTEXTCONTROLENABLE; ///< enable bits for shadowing
end;
PPM4CMDCLEARSTATE=^DWORD;
PPM4CMDSETDATA=^TPM4CMDSETDATA;
TPM4CMDSETDATA=packed record
REG_OFFSET:WORD;
RESERVED:WORD;
REG_DATA:packed record end;
end;
PPM4CMDDRAWINDEX2=^TPM4CMDDRAWINDEX2;
TPM4CMDDRAWINDEX2=packed record
maxSize:DWORD; // VGT_DMA_MAX_SIZE
indexBaseLo:DWORD; // VGT_DMA_BASE
indexBaseHi:DWORD; // VGT_DMA_BASE_HI
indexCount:DWORD; // VGT_DMA_SIZE ,VGT_NUM_INDICES
drawInitiator:TVGT_DRAW_INITIATOR;
end;
PPM4CMDDRAWINDEXAUTO=^TPM4CMDDRAWINDEXAUTO;
TPM4CMDDRAWINDEXAUTO=packed record
indexCount:DWORD; ///< max index count
drawInitiator:TVGT_DRAW_INITIATOR;
end;
PPM4CMDDISPATCHDIRECT=^TPM4CMDDISPATCHDIRECT;
TPM4CMDDISPATCHDIRECT=packed record
dimX:DWORD; ///< X dimensions of the array of thread groups to be dispatched
dimY:DWORD; ///< Y dimensions of the array of thread groups to be dispatched
dimZ:DWORD; ///< Z dimensions of the array of thread groups to be dispatched
dispatchInitiator:TCOMPUTE_DISPATCH_INITIATOR; ///< Dispatch Initiator Register
end;
function PM4_HEADER_BUILD(lenDw:WORD;op,priv:Byte):DWORD; inline;
function PM4_PRIV(token:DWORD):Byte; inline;
function PM4_TYPE(token:DWORD):Byte; inline;
function PM4_LENGTH_DW(token:DWORD):WORD; inline;
implementation
function PM4_HEADER_BUILD(lenDw:WORD;op,priv:Byte):DWORD; inline;
begin
Result:=((lenDw shl 16)+$3FFE0000) or $C0000000 or
(op shl 8) or priv;
end;
function PM4_PRIV(token:DWORD):Byte; inline;
begin
Result:=Byte(token);
end;
function PM4_TYPE(token:DWORD):Byte; inline;
begin
Result:=(token shr 30) and 3;
end;
function PM4_LENGTH_DW(token:DWORD):WORD; inline;
begin
Result:=((token shr 16) and $3FFF) + 2;
end;
end.

928
chip/ps4_gpu_regs.pas Normal file
View File

@ -0,0 +1,928 @@
unit ps4_gpu_regs;
{$mode objfpc}{$H+}
interface
uses
Classes,
SysUtils,
vulkan,
bittype,
pm4defs,
si_ci_vi_merged_offset,
si_ci_vi_merged_enum,
si_ci_vi_merged_registers;
type
TRENDER_TARGET=packed record
BASE :TCB_COLOR0_BASE ; //mmCB_COLOR0_BASE_DEFAULT
PITCH :TCB_COLOR0_PITCH ; //mmCB_COLOR0_PITCH_DEFAULT
SLICE :TCB_COLOR0_SLICE ; //mmCB_COLOR0_SLICE_DEFAULT
VIEW :TCB_COLOR0_VIEW ; //mmCB_COLOR0_VIEW_DEFAULT
INFO :TCB_COLOR0_INFO ; //mmCB_COLOR0_INFO_DEFAULT
ATTRIB :TCB_COLOR0_ATTRIB ; //mmCB_COLOR0_ATTRIB_DEFAULT
DCC_CONTROL:TCB_COLOR0_DCC_CONTROL; //mmCB_COLOR0_DCC_CONTROL_DEFAULT
CMASK :TCB_COLOR0_CMASK ; //mmCB_COLOR0_CMASK_DEFAULT
CMASK_SLICE:TCB_COLOR0_CMASK_SLICE; //mmCB_COLOR0_CMASK_SLICE_DEFAULT
FMASK :TCB_COLOR0_FMASK ; //mmCB_COLOR0_FMASK_DEFAULT
FMASK_SLICE:TCB_COLOR0_FMASK_SLICE; //mmCB_COLOR0_FMASK_SLICE_DEFAULT
CLEAR_WORD :QWORD; //mmCB_COLOR0_CLEAR_WORD0_DEFAULT
//mmCB_COLOR0_CLEAR_WORD1_DEFAULT
DCC_BASE :TCB_COLOR0_DCC_BASE ; //mmCB_COLOR0_DCC_BASE_DEFAULT
align:DWORD;
end;
TGB_CLIP=packed record
VERT_CLIP_ADJ:Single;
VERT_DISC_ADJ:Single;
HORZ_CLIP_ADJ:Single;
HORZ_DISC_ADJ:Single;
end;
TVPORT_SCISSOR=packed record
TL:TPA_SC_VPORT_SCISSOR_0_TL;
BR:TPA_SC_VPORT_SCISSOR_0_BR;
end;
TVPORT_ZMIN_MAX=packed record
ZMIN:Single;
ZMAX:Single;
end;
TVPORT_SCALE_OFFSET=packed record
XSCALE :Single;
XOFFSET:Single;
YSCALE :Single;
YOFFSET:Single;
ZSCALE :Single;
ZOFFSET:Single;
end;
TSPI_USER_DATA=array[0..15] of DWORD;
TRT_INFO=record
Addr:Pointer;
extend:TVkExtent2D;
padded:TVkExtent2D;
cformat:TVkFormat;
TILE_MODE_INDEX:DWORD;
COMP_SWAP :Byte;
FAST_CLEAR:Boolean;
CLEAR_COLOR:TVkClearColorValue;
blend:TVkPipelineColorBlendAttachmentState;
end;
TDB_INFO=record
Z_READ_ADDR:Pointer;
Z_WRITE_ADDR:Pointer;
STENCIL_READ_ADDR:Pointer;
STENCIL_WRITE_ADDR:Pointer;
extend:TVkExtent2D;
padded:TVkExtent2D;
DEPTH_CLEAR :Boolean;
STENCIL_CLEAR :Boolean;
Z_READ_ONLY :Boolean;
STENCIL_READ_ONLY:Boolean;
CLEAR_VALUE:TVkClearValue;
depthTestEnable :TVkBool32;
depthWriteEnable :TVkBool32;
depthCompareOp :TVkCompareOp;
depthBoundsTestEnable:TVkBool32;
stencilTestEnable :TVkBool32;
front:TVkStencilOpState;
back:TVkStencilOpState;
minDepthBounds:TVkFloat;
maxDepthBounds:TVkFloat;
dformat:TVkFormat;
zorder_stage:TVkPipelineStageFlagBits;
end;
TGPU_REGS=packed object
RENDER_TARGET:array[0..7] of TRENDER_TARGET;
TARGET_MASK:TCB_TARGET_MASK;
VTE_CNTL:TPA_CL_VTE_CNTL;
SC_MODE_CNTL_0:TPA_SC_MODE_CNTL_0;
SC_MODE_CNTL_1:TPA_SC_MODE_CNTL_1;
VPORT_SCISSOR:array[0..15] of TVPORT_SCISSOR;
VPORT_ZMIN_MAX:array[0..15] of TVPORT_ZMIN_MAX;
VPORT_SCALE_OFFSET:array[0..15] of TVPORT_SCALE_OFFSET;
SCREEN_SCISSOR_BR:TPA_SC_SCREEN_SCISSOR_BR;
SCREEN_SCISSOR_TL:TPA_SC_SCREEN_SCISSOR_TL;
SC_AA_CONFIG:TPA_SC_AA_CONFIG;
SC_AA_MASK_X0Y0_X1Y0:TPA_SC_AA_MASK_X0Y0_X1Y0;
SC_AA_MASK_X0Y1_X1Y1:TPA_SC_AA_MASK_X0Y1_X1Y1;
HARDWARE_SCREEN_OFFSET:TPA_SU_HARDWARE_SCREEN_OFFSET;
SU_LINE_CNTL:TPA_SU_LINE_CNTL;
SU_POINT_SIZE:TPA_SU_POINT_SIZE;
SU_POINT_MINMAX:TPA_SU_POINT_MINMAX;
VTX_CNTL:TPA_SU_VTX_CNTL;
GB_CLIP:TGB_CLIP;
CL_CLIP_CNTL:TPA_CL_CLIP_CNTL;
SC_CLIPRECT_RULE:TPA_SC_CLIPRECT_RULE;
VGT_SHADER_STAGES_EN:TVGT_SHADER_STAGES_EN;
VGT_OUT_DEALLOC_CNTL:TVGT_OUT_DEALLOC_CNTL;
VGT_VTX_INDX:packed record
CNT_EN:TVGT_VTX_CNT_EN;
INDX_OFFSET:DWORD;
MIN_INDX:DWORD;
MAX_INDX:DWORD;
end;
VGT_MULTI_PRIM_IB_RESET_INDX:TVGT_MULTI_PRIM_IB_RESET_INDX;
VGT_OUTPUT_PATH_CNTL:TVGT_OUTPUT_PATH_CNTL;
VGT_PRIMITIVE_TYPE:TVGT_PRIMITIVE_TYPE;
VGT_INDEX_TYPE :TVGT_INDEX_TYPE ;
VGT_NUM_INSTANCES :TVGT_NUM_INSTANCES ;
VGT_DMA:packed record
INDEX_TYPE:TVGT_DMA_INDEX_TYPE;
NUM_INSTANCES:TVGT_DMA_NUM_INSTANCES;
MAX_SIZE:DWORD;
BASE_LO:DWORD;
BASE_HI:DWORD;
SIZE:DWORD;
INDICES:DWORD;
end;
SPI:packed record
PS:packed record
INPUT_CNTL_0:TSPI_PS_INPUT_CNTL_0;
INPUT_CNTL_1:TSPI_PS_INPUT_CNTL_1;
LO,HI:DWORD;
RSRC1:TSPI_SHADER_PGM_RSRC1_PS;
RSRC2:TSPI_SHADER_PGM_RSRC2_PS;
RSRC3:TSPI_SHADER_PGM_RSRC3_PS;
Z_FORMAT :TSPI_SHADER_Z_FORMAT;
COL_FORMAT:TSPI_SHADER_COL_FORMAT;
INPUT_ENA :TSPI_PS_INPUT_ENA;
INPUT_ADDR:TSPI_PS_INPUT_ADDR;
IN_CONTROL:TSPI_PS_IN_CONTROL;
BARYC_CNTL:TSPI_BARYC_CNTL;
SHADER_CONTROL:TDB_SHADER_CONTROL;
SHADER_MASK:TCB_SHADER_MASK;
USER_DATA:TSPI_USER_DATA;
end;
VS:packed record
LO,HI:DWORD;
RSRC1:TSPI_SHADER_PGM_RSRC1_VS;
RSRC2:TSPI_SHADER_PGM_RSRC2_VS;
RSRC3:TSPI_SHADER_PGM_RSRC3_VS;
OUT_CONFIG:TSPI_VS_OUT_CONFIG;
POS_FORMAT:TSPI_SHADER_POS_FORMAT;
OUT_CNTL :TPA_CL_VS_OUT_CNTL;
USER_DATA:TSPI_USER_DATA;
LATE_ALLOC:TSPI_SHADER_LATE_ALLOC_VS;
end;
CS:packed record
LO,HI:DWORD;
RSRC1:TCOMPUTE_PGM_RSRC1;
RSRC2:TCOMPUTE_PGM_RSRC2;
STATIC_THREAD_MGMT_SE0:TCOMPUTE_STATIC_THREAD_MGMT_SE0;
STATIC_THREAD_MGMT_SE1:TCOMPUTE_STATIC_THREAD_MGMT_SE1;
RESOURCE_LIMITS:TCOMPUTE_RESOURCE_LIMITS;
NUM_THREAD_X:TCOMPUTE_NUM_THREAD_X;
NUM_THREAD_Y:TCOMPUTE_NUM_THREAD_Y;
NUM_THREAD_Z:TCOMPUTE_NUM_THREAD_Z;
USER_DATA:TSPI_USER_DATA;
end;
end;
DEPTH:packed record
RENDER_CONTROL :TDB_RENDER_CONTROL;
DEPTH_CONTROL :TDB_DEPTH_CONTROL;
DEPTH_VIEW :TDB_DEPTH_VIEW ;
HTILE_DATA_BASE :TDB_HTILE_DATA_BASE ;
DEPTH_BOUNDS_MIN :Single;
DEPTH_BOUNDS_MAX :Single;
STENCIL_CLEAR :TDB_STENCIL_CLEAR ;
DEPTH_CLEAR :Single;
DEPTH_INFO :TDB_DEPTH_INFO ;
Z_INFO :TDB_Z_INFO ;
STENCIL_INFO :TDB_STENCIL_INFO ;
Z_READ_BASE :TDB_Z_READ_BASE ;
STENCIL_READ_BASE :TDB_STENCIL_READ_BASE ;
Z_WRITE_BASE :TDB_Z_WRITE_BASE ;
STENCIL_WRITE_BASE:TDB_STENCIL_WRITE_BASE;
DEPTH_SIZE :TDB_DEPTH_SIZE ;
DEPTH_SLICE :TDB_DEPTH_SLICE ;
HTILE_SURFACE :TDB_HTILE_SURFACE ;
end;
CB_COLOR_CONTROL:TCB_COLOR_CONTROL;
CB_BLEND_CONTROL:array[0..7] of TCB_BLEND0_CONTROL;
PA_SU_POLY_OFFSET_DB_FMT_CNTL:TPA_SU_POLY_OFFSET_DB_FMT_CNTL;
Function _SHADER_MASK(i:Byte):Byte; inline; //0..7
Function _TARGET_MASK(i:Byte):Byte; inline; //0..7
Function _COMP_MASK(i:Byte):Byte; inline; //0..7
Function COMP_ENABLE:Boolean; inline;
Function RT_ENABLE(i:Byte):Boolean; //0..7
Function VP_ENABLE(i:Byte):Boolean; //0..15
Function GET_VPORT(i:Byte):TVkViewport; //0..15
Function GET_SCISSOR(i:Byte):TVkRect2D; //0..15
Function GET_SCREEN:TVkRect2D;
Function GET_SCREEN_SIZE:TVkExtent2D;
Function GET_RT_BLEND(i:Byte):TVkPipelineColorBlendAttachmentState; //0..7
Function GET_RT_INFO(i:Byte):TRT_INFO; //0..7
Function DB_ENABLE:Boolean;
Function GET_DB_INFO:TDB_INFO;
function GET_PRIM_TYPE:TVkPrimitiveTopology;
function GET_INDEX_TYPE:TVkIndexType;
function GET_INDEX_TYPE_SIZE:Byte;
Procedure Clear;
Procedure ClearDMA;
end;
implementation
Function TGPU_REGS._SHADER_MASK(i:Byte):Byte; inline; //0..7
begin
Result:=(DWORD(SPI.PS.SHADER_MASK) shr i) and 15;
end;
Function TGPU_REGS._TARGET_MASK(i:Byte):Byte; inline; //0..7
begin
Result:=(DWORD(TARGET_MASK) shr i) and 15;
end;
Function TGPU_REGS._COMP_MASK(i:Byte):Byte; inline; //0..7
begin
Result:=((DWORD(SPI.PS.SHADER_MASK) and DWORD(TARGET_MASK)) shr i) and 15;
end;
Function TGPU_REGS.COMP_ENABLE:Boolean; inline;
begin
Result:=(DWORD(SPI.PS.SHADER_MASK) and DWORD(TARGET_MASK))<>0;
end;
Function TGPU_REGS.RT_ENABLE(i:Byte):Boolean; //0..7
begin
Result:=(RENDER_TARGET[i].BASE<>0) and
(RENDER_TARGET[i].INFO.FORMAT<>0) and
(_COMP_MASK(i)<>0);
end;
Function TGPU_REGS.VP_ENABLE(i:Byte):Boolean; //0..15
begin
Result:=(PQWORD(@VPORT_SCALE_OFFSET[i])[0]<>0) or
(PQWORD(@VPORT_SCALE_OFFSET[i])[1]<>0) or
(PQWORD(@VPORT_SCALE_OFFSET[i])[2]<>0);
end;
Function TGPU_REGS.GET_VPORT(i:Byte):TVkViewport; //0..15
var
V:TVPORT_SCALE_OFFSET;
begin
Result:=Default(TVkViewport);
V:=VPORT_SCALE_OFFSET[i];
if (VTE_CNTL.VPORT_X_SCALE_ENA =0) then V.XSCALE :=1;
if (VTE_CNTL.VPORT_X_OFFSET_ENA=0) then V.XOFFSET:=0;
if (VTE_CNTL.VPORT_Y_SCALE_ENA =0) then V.YSCALE :=1;
if (VTE_CNTL.VPORT_Y_OFFSET_ENA=0) then V.YOFFSET:=0;
if (VTE_CNTL.VPORT_Z_SCALE_ENA =0) then V.ZSCALE :=1;
if (VTE_CNTL.VPORT_Z_OFFSET_ENA=0) then V.ZOFFSET:=0;
Assert(VTE_CNTL.VTX_XY_FMT=0);
Assert(VTE_CNTL.VTX_Z_FMT =0);
Assert(VTE_CNTL.VTX_W0_FMT=1);
Result.x :=V.XOFFSET-V.XSCALE;
Result.y :=V.YOFFSET-V.YSCALE;
Result.width :=V.XSCALE*2;
Result.height :=V.YSCALE*2;
Result.minDepth:=V.ZOFFSET;
Result.maxDepth:=V.ZOFFSET+V.ZSCALE;
end;
Function _fix_scissor_range(i:Word):Word;
begin
Result:=i;
if SmallInt(Result)<0 then Result:=0;
if SmallInt(Result)>16384 then Result:=16384;
end;
Function TGPU_REGS.GET_SCISSOR(i:Byte):TVkRect2D; //0..15
begin
if (SC_MODE_CNTL_0.VPORT_SCISSOR_ENABLE=1) then
begin
Result.offset.x :=_fix_scissor_range(VPORT_SCISSOR[i].TL.TL_X);
Result.offset.y :=_fix_scissor_range(VPORT_SCISSOR[i].TL.TL_Y);
Result.extent.width :=_fix_scissor_range(VPORT_SCISSOR[i].BR.BR_X);
Result.extent.height:=_fix_scissor_range(VPORT_SCISSOR[i].BR.BR_Y);
Result.extent.width :=Result.extent.width -Result.offset.x;
Result.extent.height:=Result.extent.height-Result.offset.y;
end else
begin
Result.offset.x :=_fix_scissor_range(SCREEN_SCISSOR_TL.TL_X);
Result.offset.y :=_fix_scissor_range(SCREEN_SCISSOR_TL.TL_Y);
Result.extent.width :=_fix_scissor_range(SCREEN_SCISSOR_BR.BR_X);
Result.extent.height:=_fix_scissor_range(SCREEN_SCISSOR_BR.BR_Y);
Result.extent.width :=Result.extent.width -Result.offset.x;
Result.extent.height:=Result.extent.height-Result.offset.y;
end;
end;
Function TGPU_REGS.GET_SCREEN:TVkRect2D;
{var
i:Byte;
x,y:Word;}
begin
Result.offset.x :=_fix_scissor_range(SCREEN_SCISSOR_TL.TL_X);
Result.offset.y :=_fix_scissor_range(SCREEN_SCISSOR_TL.TL_Y);
Result.extent.width :=_fix_scissor_range(SCREEN_SCISSOR_BR.BR_X);
Result.extent.height:=_fix_scissor_range(SCREEN_SCISSOR_BR.BR_Y);
Result.extent.width :=Result.extent.width -Result.offset.x;
Result.extent.height:=Result.extent.height-Result.offset.y;
{if (SC_MODE_CNTL_0.VPORT_SCISSOR_ENABLE=1) then
begin
Result:=Default(TPA_SC_SCREEN_SCISSOR_BR);
For i:=0 to 15 do //SCISSOR WINDOW TODO
begin
x:=_fix_scissor_range(VPORT_SCISSOR[i].BR.BR_X);
y:=_fix_scissor_range(VPORT_SCISSOR[i].BR.BR_Y);
if (Result.BR_X<x) then Result.BR_X:=x;
if (Result.BR_Y<y) then Result.BR_Y:=y;
end;
end else
begin
Result.BR_X:=_fix_scissor_range(SCREEN_SCISSOR_BR.BR_X);
Result.BR_Y:=_fix_scissor_range(SCREEN_SCISSOR_BR.BR_Y);
end;}
end;
Function TGPU_REGS.GET_SCREEN_SIZE:TVkExtent2D;
begin
Result.width :=_fix_scissor_range(SCREEN_SCISSOR_BR.BR_X);
Result.height:=_fix_scissor_range(SCREEN_SCISSOR_BR.BR_Y);
end;
Function GetBlendFactor(i:Byte):TVkBlendFactor;
begin
Case i of
BLEND_ZERO :Result:=VK_BLEND_FACTOR_ZERO;
BLEND_ONE :Result:=VK_BLEND_FACTOR_ONE;
BLEND_SRC_COLOR :Result:=VK_BLEND_FACTOR_SRC_COLOR;
BLEND_ONE_MINUS_SRC_COLOR :Result:=VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
BLEND_SRC_ALPHA :Result:=VK_BLEND_FACTOR_SRC_ALPHA;
BLEND_ONE_MINUS_SRC_ALPHA :Result:=VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
BLEND_DST_ALPHA :Result:=VK_BLEND_FACTOR_DST_ALPHA;
BLEND_ONE_MINUS_DST_ALPHA :Result:=VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
BLEND_DST_COLOR :Result:=VK_BLEND_FACTOR_DST_COLOR;
BLEND_ONE_MINUS_DST_COLOR :Result:=VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
BLEND_SRC_ALPHA_SATURATE :Result:=VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
BLEND_BOTH_SRC_ALPHA :Result:=VK_BLEND_FACTOR_SRC1_ALPHA;
BLEND_BOTH_INV_SRC_ALPHA :Result:=VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
BLEND_CONSTANT_COLOR :Result:=VK_BLEND_FACTOR_CONSTANT_COLOR;
BLEND_ONE_MINUS_CONSTANT_COLOR:Result:=VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
BLEND_SRC1_COLOR :Result:=VK_BLEND_FACTOR_SRC1_COLOR;
BLEND_INV_SRC1_COLOR :Result:=VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
BLEND_SRC1_ALPHA :Result:=VK_BLEND_FACTOR_SRC1_ALPHA;
BLEND_INV_SRC1_ALPHA :Result:=VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
BLEND_CONSTANT_ALPHA :Result:=VK_BLEND_FACTOR_CONSTANT_ALPHA;
BLEND_ONE_MINUS_CONSTANT_ALPHA:Result:=VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
else
Assert(false);
end;
end;
Function GetBlendOp(i:Byte):TVkBlendOp;
begin
Case i of
COMB_DST_PLUS_SRC :Result:=VK_BLEND_OP_ADD;
COMB_SRC_MINUS_DST:Result:=VK_BLEND_OP_SUBTRACT;
COMB_MIN_DST_SRC :Result:=VK_BLEND_OP_MIN;
COMB_MAX_DST_SRC :Result:=VK_BLEND_OP_MAX;
COMB_DST_MINUS_SRC:Result:=VK_BLEND_OP_REVERSE_SUBTRACT;
else
Assert(false);
end;
end;
function GetRTCompCount(FORMAT:Byte):Byte;
begin
Result:=0;
Case FORMAT of
COLOR_8 :Result:=1;
COLOR_16 :Result:=1;
COLOR_8_8 :Result:=2;
COLOR_32 :Result:=1;
COLOR_16_16 :Result:=2;
COLOR_10_11_11 :Result:=3;
COLOR_11_11_10 :Result:=3;
COLOR_10_10_10_2 :Result:=4;
COLOR_2_10_10_10 :Result:=4;
COLOR_8_8_8_8 :Result:=4;
COLOR_32_32 :Result:=2;
COLOR_16_16_16_16 :Result:=4;
COLOR_RESERVED_13 :Result:=3; //32_32_32
COLOR_32_32_32_32 :Result:=4;
COLOR_5_6_5 :Result:=3;
COLOR_1_5_5_5 :Result:=4;
COLOR_5_5_5_1 :Result:=4;
COLOR_4_4_4_4 :Result:=4;
COLOR_8_24 :Result:=2;
COLOR_24_8 :Result:=2;
COLOR_X24_8_32_FLOAT:Result:=3;
end;
end;
type
TCOMP_MAP=array[0..3] of Byte;
function GetCompMap(COMP_SWAP,COUNT:Byte):TCOMP_MAP;
begin
Result:=Default(TCOMP_MAP);
Case COUNT of
1:
Case COMP_SWAP of
SWAP_STD :Result[0]:=ord(VK_COLOR_COMPONENT_R_BIT);
SWAP_ALT :Result[0]:=ord(VK_COLOR_COMPONENT_G_BIT);
SWAP_STD_REV:Result[0]:=ord(VK_COLOR_COMPONENT_B_BIT);
SWAP_ALT_REV:Result[0]:=ord(VK_COLOR_COMPONENT_A_BIT);
end;
2:
Case COMP_SWAP of
SWAP_STD :begin
Result[0]:=ord(VK_COLOR_COMPONENT_R_BIT);
Result[1]:=ord(VK_COLOR_COMPONENT_G_BIT);
end;
SWAP_ALT :begin
Result[0]:=ord(VK_COLOR_COMPONENT_R_BIT);
Result[1]:=ord(VK_COLOR_COMPONENT_A_BIT);
end;
SWAP_STD_REV:begin
Result[0]:=ord(VK_COLOR_COMPONENT_A_BIT);
Result[1]:=ord(VK_COLOR_COMPONENT_B_BIT);
end;
SWAP_ALT_REV:begin
Result[0]:=ord(VK_COLOR_COMPONENT_A_BIT);
Result[1]:=ord(VK_COLOR_COMPONENT_R_BIT);
end;
end;
3:
Case COMP_SWAP of
SWAP_STD :begin
Result[0]:=ord(VK_COLOR_COMPONENT_R_BIT);
Result[1]:=ord(VK_COLOR_COMPONENT_G_BIT);
Result[2]:=ord(VK_COLOR_COMPONENT_B_BIT);
end;
SWAP_ALT :begin
Result[0]:=ord(VK_COLOR_COMPONENT_R_BIT);
Result[1]:=ord(VK_COLOR_COMPONENT_G_BIT);
Result[2]:=ord(VK_COLOR_COMPONENT_A_BIT);
end;
SWAP_STD_REV:begin
Result[0]:=ord(VK_COLOR_COMPONENT_A_BIT);
Result[1]:=ord(VK_COLOR_COMPONENT_B_BIT);
Result[2]:=ord(VK_COLOR_COMPONENT_G_BIT);
end;
SWAP_ALT_REV:begin
Result[0]:=ord(VK_COLOR_COMPONENT_A_BIT);
Result[1]:=ord(VK_COLOR_COMPONENT_R_BIT);
Result[2]:=ord(VK_COLOR_COMPONENT_G_BIT);
end;
end;
4:
Case COMP_SWAP of
SWAP_STD :begin
Result[0]:=ord(VK_COLOR_COMPONENT_R_BIT);
Result[1]:=ord(VK_COLOR_COMPONENT_G_BIT);
Result[2]:=ord(VK_COLOR_COMPONENT_B_BIT);
Result[3]:=ord(VK_COLOR_COMPONENT_A_BIT);
end;
SWAP_ALT :begin
Result[0]:=ord(VK_COLOR_COMPONENT_B_BIT);
Result[1]:=ord(VK_COLOR_COMPONENT_G_BIT);
Result[2]:=ord(VK_COLOR_COMPONENT_R_BIT);
Result[3]:=ord(VK_COLOR_COMPONENT_A_BIT);
end;
SWAP_STD_REV:begin
Result[0]:=ord(VK_COLOR_COMPONENT_A_BIT);
Result[1]:=ord(VK_COLOR_COMPONENT_B_BIT);
Result[2]:=ord(VK_COLOR_COMPONENT_G_BIT);
Result[3]:=ord(VK_COLOR_COMPONENT_R_BIT);
end;
SWAP_ALT_REV:begin
Result[0]:=ord(VK_COLOR_COMPONENT_A_BIT);
Result[1]:=ord(VK_COLOR_COMPONENT_R_BIT);
Result[2]:=ord(VK_COLOR_COMPONENT_G_BIT);
Result[3]:=ord(VK_COLOR_COMPONENT_B_BIT);
end;
end;
end;
//SWAP_STD (R=>0)
//SWAP_ALT (G=>0)
//SWAP_STD_REV (B=>0)
//SWAP_ALT_REV (A=>0)
//SWAP_ALT (R=>0, A=>1)
//SWAP_ALT (R=>0, G=>1, A=>2)
//SWAP_STD (R=>0, G=>1, B=>2, A=>3)
//SWAP_ALT (B=>0, G=>1, R=>2, A=>3).
//SWAP_STD_REV (A=>0, B=>1, G=>2, R=>3)
//SWAP_ALT_REV (A=>0, R=>1, G=>2, B=>3)
end;
Function TGPU_REGS.GET_RT_BLEND(i:Byte):TVkPipelineColorBlendAttachmentState; //0..7
var
m:Byte;
COMP_MAP:TCOMP_MAP;
begin
Result:=Default(TVkPipelineColorBlendAttachmentState);
m:=GetRTCompCount(RENDER_TARGET[i].INFO.FORMAT);
COMP_MAP:=GetCompMap(RENDER_TARGET[i].INFO.COMP_SWAP,m);
//COMP_SWAP depend (B=>0, G=>1, R=>2, A=>3)
m:=_COMP_MASK(i);
if m.TestBit(0) then Result.colorWriteMask:=Result.colorWriteMask or COMP_MAP[0];
if m.TestBit(1) then Result.colorWriteMask:=Result.colorWriteMask or COMP_MAP[1];
if m.TestBit(2) then Result.colorWriteMask:=Result.colorWriteMask or COMP_MAP[2];
if m.TestBit(3) then Result.colorWriteMask:=Result.colorWriteMask or COMP_MAP[3];
//BLEND_CLAMP
if (RENDER_TARGET[i].INFO.BLEND_BYPASS=1) then
begin
Result.blendEnable:=VK_FALSE;
end else
if (CB_BLEND_CONTROL[i].ENABLE=0) then
begin
Result.blendEnable:=VK_FALSE;
end else
begin
Result.blendEnable:=VK_TRUE;
Result.srcColorBlendFactor:=GetBlendFactor(CB_BLEND_CONTROL[i].COLOR_SRCBLEND);
Result.dstColorBlendFactor:=GetBlendFactor(CB_BLEND_CONTROL[i].COLOR_DESTBLEND);
Result.srcAlphaBlendFactor:=GetBlendFactor(CB_BLEND_CONTROL[i].ALPHA_SRCBLEND);
Result.dstAlphaBlendFactor:=GetBlendFactor(CB_BLEND_CONTROL[i].ALPHA_DESTBLEND);
Result.colorBlendOp:=GetBlendOp(CB_BLEND_CONTROL[i].COLOR_COMB_FCN);
Result.alphaBlendOp:=GetBlendOp(CB_BLEND_CONTROL[i].ALPHA_COMB_FCN);
Assert(CB_BLEND_CONTROL[i].SEPARATE_ALPHA_BLEND=0);
Assert(CB_BLEND_CONTROL[i].DISABLE_ROP3 =0);
end;
//Assert(CB_COLOR_CONTROL.ROP3 = 204);
end;
Function TGPU_REGS.GET_RT_INFO(i:Byte):TRT_INFO; //0..7
var
COMP_MAP:TCOMP_MAP;
W:QWORD;
begin
Result:=Default(TRT_INFO);
Result.Addr:=Pointer(QWORD(RENDER_TARGET[i].BASE) shl 8);
if (RENDER_TARGET[i].INFO.LINEAR_GENERAL=1) then
begin
Result.Addr:=Pointer(QWORD(Result.Addr) or Byte(RENDER_TARGET[i].VIEW.SLICE_START));
end;
Result.extend:=GET_SCREEN_SIZE;
Result.padded.Width :=(RENDER_TARGET[i].PITCH.TILE_MAX+1)*8;
Result.padded.Height:=(RENDER_TARGET[i].SLICE.TILE_MAX+1)*8 div (RENDER_TARGET[i].PITCH.TILE_MAX+1);
Assert(RENDER_TARGET[i].INFO.ENDIAN=ENDIAN_NONE);
Assert(RENDER_TARGET[i].INFO.COMPRESSION=0);
Case RENDER_TARGET[i].INFO.FORMAT of
COLOR_8_8_8_8:
Case RENDER_TARGET[i].INFO.NUMBER_TYPE of
NUMBER_UNORM:Result.cformat:=VK_FORMAT_R8G8B8A8_UNORM;
NUMBER_SRGB :Result.cformat:=VK_FORMAT_R8G8B8A8_SRGB;
else
Assert(false);
end;
else
Assert(false);
end;
Result.TILE_MODE_INDEX:=RENDER_TARGET[i].ATTRIB.TILE_MODE_INDEX;
if (RENDER_TARGET[i].INFO.LINEAR_GENERAL=1) then Result.TILE_MODE_INDEX:=8;
Result.COMP_SWAP:=RENDER_TARGET[i].INFO.COMP_SWAP;
if (RENDER_TARGET[i].INFO.FAST_CLEAR=1) then
begin
Result.FAST_CLEAR:=True;
Case RENDER_TARGET[i].INFO.FORMAT of
COLOR_8_8_8_8:
Case RENDER_TARGET[i].INFO.NUMBER_TYPE of
NUMBER_UNORM,
NUMBER_SRGB :
begin
COMP_MAP:=GetCompMap(RENDER_TARGET[i].INFO.COMP_SWAP,4);
//VK_COLOR_COMPONENT_R_BIT=$00000001, 0001
//VK_COLOR_COMPONENT_G_BIT=$00000002, 0010
//VK_COLOR_COMPONENT_B_BIT=$00000004, 0100
//VK_COLOR_COMPONENT_A_BIT=$00000008 1000
W:=RENDER_TARGET[i].CLEAR_WORD;
//Writeln((W shr (BsrDWord(COMP_MAP[0]) shl 3)) and 255);
//Writeln((W shr (BsrDWord(COMP_MAP[1]) shl 3)) and 255);
//Writeln((W shr (BsrDWord(COMP_MAP[2]) shl 3)) and 255);
//Writeln((W shr (BsrDWord(COMP_MAP[3]) shl 3)) and 255);
Result.CLEAR_COLOR.float32[0]:=((W shr (BsrDWord(COMP_MAP[0]) shl 3)) and 255)/255;
Result.CLEAR_COLOR.float32[1]:=((W shr (BsrDWord(COMP_MAP[1]) shl 3)) and 255)/255;
Result.CLEAR_COLOR.float32[2]:=((W shr (BsrDWord(COMP_MAP[2]) shl 3)) and 255)/255;
Result.CLEAR_COLOR.float32[3]:=((W shr (BsrDWord(COMP_MAP[3]) shl 3)) and 255)/255;
end;
else
Assert(false);
end;
else
Assert(false);
end;
end;
Result.blend:=GET_RT_BLEND(i);
end;
Function TGPU_REGS.DB_ENABLE:Boolean;
begin
Result:=(
(DEPTH.DEPTH_CONTROL.STENCIL_ENABLE<>0) and
(DEPTH.STENCIL_INFO.FORMAT<>0)
) or
(
(DEPTH.DEPTH_CONTROL.Z_ENABLE<>0) and
(DEPTH.Z_INFO.FORMAT<>0)
);
end;
Function TGPU_REGS.GET_DB_INFO:TDB_INFO;
begin
Result:=Default(TDB_INFO);
Result.extend:=GET_SCREEN_SIZE;
Result.padded.width :=(DEPTH.DEPTH_SIZE.PITCH_TILE_MAX +1)*8;
Result.padded.height:=(DEPTH.DEPTH_SIZE.HEIGHT_TILE_MAX+1)*8;
Result.DEPTH_CLEAR :=DEPTH.RENDER_CONTROL.DEPTH_CLEAR_ENABLE<>0;
Result.STENCIL_CLEAR:=DEPTH.RENDER_CONTROL.STENCIL_CLEAR_ENABLE<>0;
Result.Z_READ_ONLY :=DEPTH.DEPTH_VIEW.Z_READ_ONLY<>0;
Result.STENCIL_READ_ONLY:=DEPTH.DEPTH_VIEW.STENCIL_READ_ONLY<>0;
Assert(DEPTH.RENDER_CONTROL.DEPTH_COPY=0);
Assert(DEPTH.RENDER_CONTROL.STENCIL_COPY=0);
Assert(DEPTH.RENDER_CONTROL.COPY_CENTROID=0);
Assert(DEPTH.RENDER_CONTROL.COPY_SAMPLE=0);
Result.CLEAR_VALUE.depthStencil.depth :=DEPTH.DEPTH_CLEAR;
Result.CLEAR_VALUE.depthStencil.stencil:=DEPTH.STENCIL_CLEAR.CLEAR;
/////
Result.depthTestEnable :=DEPTH.DEPTH_CONTROL.Z_ENABLE; //1:1
Result.depthWriteEnable :=DEPTH.DEPTH_CONTROL.Z_WRITE_ENABLE; //1:1
Result.depthBoundsTestEnable:=DEPTH.DEPTH_CONTROL.DEPTH_BOUNDS_ENABLE; //1:1
Result.stencilTestEnable :=DEPTH.DEPTH_CONTROL.STENCIL_ENABLE; //1:1
Result.depthCompareOp:=TVkCompareOp(DEPTH.DEPTH_CONTROL.ZFUNC); //1:1
Result.minDepthBounds:=DEPTH.DEPTH_BOUNDS_MIN;
Result.maxDepthBounds:=DEPTH.DEPTH_BOUNDS_MAX;
//compareMask:TVkUInt32; //DB_STENCILREFMASK DB_STENCILREFMASK_BF
//writeMask:TVkUInt32; //DB_STENCILREFMASK DB_STENCILREFMASK_BF
//reference:TVkUInt32; //DB_STENCILREFMASK DB_STENCILREFMASK_BF
if (DEPTH.DEPTH_CONTROL.DISABLE_COLOR_WRITES_ON_DEPTH_PASS<>0) then
begin
Result.front.failOp:=VK_STENCIL_OP_REPLACE;
Result.front.depthFailOp:=VK_STENCIL_OP_REPLACE;
//Result.front.reference:=; ???
end;
if (DEPTH.DEPTH_CONTROL.ENABLE_COLOR_WRITES_ON_DEPTH_FAIL<>0) then
begin
Result.front.passOp:=VK_STENCIL_OP_REPLACE;
//Result.front.reference:=; ???
end;
Result.front.compareOp:=TVkCompareOp(DEPTH.DEPTH_CONTROL.STENCILFUNC); //1:1
if (DEPTH.DEPTH_CONTROL.BACKFACE_ENABLE<>0) then
begin
Result.back:=Result.front;
Result.back.compareOp:=TVkCompareOp(DEPTH.DEPTH_CONTROL.STENCILFUNC_BF); //1:1
end;
////
Assert(DEPTH.DEPTH_VIEW.SLICE_START=0);
Case DEPTH.Z_INFO.FORMAT of
Z_INVALID :
if (DEPTH.STENCIL_INFO.FORMAT=STENCIL_8) then
begin
Result.dformat:=VK_FORMAT_S8_UINT;
end;
Z_16 :
if (DEPTH.STENCIL_INFO.FORMAT=STENCIL_8) then
begin
Result.dformat:=VK_FORMAT_D16_UNORM_S8_UINT;
end else
begin
Result.dformat:=VK_FORMAT_D16_UNORM;
end;
Z_24 :
if (DEPTH.STENCIL_INFO.FORMAT=STENCIL_8) then
begin
Result.dformat:=VK_FORMAT_D24_UNORM_S8_UINT;
end else
begin
Result.dformat:=VK_FORMAT_X8_D24_UNORM_PACK32;
end;
Z_32_FLOAT:
if (DEPTH.STENCIL_INFO.FORMAT=STENCIL_8) then
begin
Result.dformat:=VK_FORMAT_D32_SFLOAT_S8_UINT;
end else
begin
Result.dformat:=VK_FORMAT_D32_SFLOAT;
end;
end;
Result.Z_READ_ADDR :=Pointer(QWORD(DEPTH.Z_READ_BASE) shl 8);
Result.Z_WRITE_ADDR:=Pointer(QWORD(DEPTH.Z_WRITE_BASE) shl 8);
Result.STENCIL_READ_ADDR :=Pointer(QWORD(DEPTH.STENCIL_READ_BASE) shl 8);
Result.STENCIL_WRITE_ADDR:=Pointer(QWORD(DEPTH.STENCIL_WRITE_BASE) shl 8);
Assert(SPI.PS.SHADER_CONTROL.Z_EXPORT_ENABLE=0);
Assert(SPI.PS.SHADER_CONTROL.STENCIL_TEST_VAL_EXPORT_ENABLE=0);
Case SPI.PS.SHADER_CONTROL.Z_ORDER of
LATE_Z :Result.zorder_stage:=VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
EARLY_Z_THEN_LATE_Z:Result.zorder_stage:=TVkPipelineStageFlagBits(
ord(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT) or
ord(VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT));
RE_Z :Result.zorder_stage:=VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
EARLY_Z_THEN_RE_Z :Result.zorder_stage:=VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
end;
end;
function TGPU_REGS.GET_PRIM_TYPE:TVkPrimitiveTopology;
begin
case VGT_PRIMITIVE_TYPE.PRIM_TYPE of
DI_PT_POINTLIST :Result:=VK_PRIMITIVE_TOPOLOGY_POINT_LIST ;
DI_PT_LINELIST :Result:=VK_PRIMITIVE_TOPOLOGY_LINE_LIST ;
DI_PT_LINESTRIP :Result:=VK_PRIMITIVE_TOPOLOGY_LINE_STRIP ;
DI_PT_TRILIST :Result:=VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST ;
DI_PT_TRIFAN :Result:=VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN ;
DI_PT_TRISTRIP :Result:=VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP ;
DI_PT_PATCH :Result:=VK_PRIMITIVE_TOPOLOGY_PATCH_LIST ;
DI_PT_LINELIST_ADJ :Result:=VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY ;
DI_PT_LINESTRIP_ADJ:Result:=VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY ;
DI_PT_TRILIST_ADJ :Result:=VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY ;
DI_PT_TRISTRIP_ADJ :Result:=VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY;
DI_PT_RECTLIST ,
DI_PT_LINELOOP ,
DI_PT_QUADLIST ,
DI_PT_QUADSTRIP ,
DI_PT_POLYGON :Result:=TVkPrimitiveTopology(VGT_PRIMITIVE_TYPE.PRIM_TYPE); //need to emulate
else
Assert(False);
end;
end;
// VGT_DI_PRIM_TYPE
//DI_PT_NONE | kPrimitiveTypeNone |
//DI_PT_POINTLIST | kPrimitiveTypePointList | VK_PRIMITIVE_TOPOLOGY_POINT_LIST
//DI_PT_LINELIST | kPrimitiveTypeLineList | VK_PRIMITIVE_TOPOLOGY_LINE_LIST
//DI_PT_LINESTRIP | kPrimitiveTypeLineStrip | VK_PRIMITIVE_TOPOLOGY_LINE_STRIP
//DI_PT_TRILIST | kPrimitiveTypeTriList | VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
//DI_PT_TRIFAN | kPrimitiveTypeTriFan | VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN
//DI_PT_TRISTRIP | kPrimitiveTypeTriStrip | VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP
//DI_PT_PATCH | kPrimitiveTypePatch | VK_PRIMITIVE_TOPOLOGY_PATCH_LIST
//DI_PT_LINELIST_ADJ | kPrimitiveTypeLineListAdjacency | VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY
//DI_PT_LINESTRIP_ADJ | kPrimitiveTypeLineStripAdjacency | VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY
//DI_PT_TRILIST_ADJ | kPrimitiveTypeTriListAdjacency | VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY
//DI_PT_TRISTRIP_ADJ | kPrimitiveTypeTriStripAdjacency | VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY
//DI_PT_RECTLIST | kPrimitiveTypeRectList |
//DI_PT_LINELOOP | kPrimitiveTypeLineLoop |
//DI_PT_QUADLIST | kPrimitiveTypeQuadList |
//DI_PT_QUADSTRIP | kPrimitiveTypeQuadStrip |
//DI_PT_POLYGON | kPrimitiveTypePolygon |
function TGPU_REGS.GET_INDEX_TYPE:TVkIndexType;
begin
Case VGT_DMA.INDEX_TYPE.INDEX_TYPE of
VGT_INDEX_16:Result:=VK_INDEX_TYPE_UINT16;
VGT_INDEX_32:Result:=VK_INDEX_TYPE_UINT32;
VGT_INDEX_8 :Result:=VK_INDEX_TYPE_UINT8_EXT;
else Result:=VK_INDEX_TYPE_NONE_KHR;
end;
end;
function TGPU_REGS.GET_INDEX_TYPE_SIZE:Byte;
begin
Case VGT_DMA.INDEX_TYPE.INDEX_TYPE of
VGT_INDEX_16:Result:=16;
VGT_INDEX_32:Result:=32;
VGT_INDEX_8 :Result:=8;
else Result:=0;
end;
end;
Procedure TGPU_REGS.Clear;
begin
FillChar(Self,SizeOf(Self),0);
DWORD(SPI.CS.STATIC_THREAD_MGMT_SE0):=$FFFFFFFF;
DWORD(SPI.CS.STATIC_THREAD_MGMT_SE1):=$FFFFFFFF;
end;
Procedure TGPU_REGS.ClearDMA;
begin
FillChar(VGT_DMA,SizeOf(VGT_DMA),0);
end;
end.

1783
chip/ps4_pssl.pas Normal file

File diff suppressed because it is too large Load Diff

284
chip/ps4_shader.pas Normal file
View File

@ -0,0 +1,284 @@
unit ps4_shader;
{$mode objfpc}{$H+}
interface
uses
Classes,SysUtils,
bittype,
ps4_pssl;
const
SHADER_BINARY_INFO_SIG:array[0..6] of Char='OrbShdr';
SHADER_END_SEARCH_MAX_DW=256+7;
type
PShaderBinaryInfo=^TShaderBinaryInfo;
TShaderBinaryInfo=bitpacked record
signature:array[0..6] of AnsiChar; // 'OrbShdr'
version:Byte; // ShaderBinaryInfoVersion
pssl_or_cg :bit1; // 1 = PSSL / Cg, 0 = IL / shtb
cached :bit1; // 1 = when compile, debugging source was cached. May only make sense for PSSL=1
m_type :bit4; // See enum ShaderBinaryType
source_type :bit2; // See enum ShaderSourceType
length :bit24; // Binary code length (does not include this structure or any of its preceding associated tables)
chunkUsageBaseOffsetInDW:Byte; // in DW, which starts at ((uint32_t*)&ShaderBinaryInfo) - m_chunkUsageBaseOffsetInDW; max is currently 7 dwords (128 T# + 32 V# + 20 CB V# + 16 UAV T#/V#)
numInputUsageSlots:Byte; // Up to 16 user data reg slots + 128 extended user data dwords supported by CUE; up to 16 user data reg slots + 240 extended user data dwords supported by Gnm::InputUsageSlot
isSrt :bit1; // 1 if this shader uses shader resource tables and has an SrtDef table embedded below the input usage table and any extended usage info
isSrtUsedInfoValid :bit1; // 1 if SrtDef::m_isUsed=0 indicates an element is definitely unused; 0 if SrtDef::m_isUsed=0 indicates only that the element is not known to be used (m_isUsed=1 always indicates a resource is known to be used)
isExtendedUsageInfo:bit1; // 1 if this shader has extended usage info for the InputUsage table embedded below the input usage table
reserved2:bit5; //1;
reserved3:Byte; //5
shaderHash0:DWORD; // Association hash first 4 bytes
shaderHash1:DWORD; // Association hash second 4 bytes
crc32 :DWORD; // crc32 of shader + this struct, just up till this field
end;
PInputUsageSlot=^TInputUsageSlot;
TInputUsageSlot=packed record
m_usageType :Byte; ///< From Gnm::ShaderInputUsageType.
m_apiSlot :Byte; ///< API slot or chunk ID.
m_startRegister:Byte; ///< User data slot.
Case byte of
0:(
b:bitpacked record
m_registerCount:bit1; ///< If 0, count is 4DW; if 1, count is 8DW. Other sizes are defined by the usage type.
m_resourceType:bit1; ///< If 0, resource type <c>V#</c>; if 1, resource type <c>T#</c>, in case of a Gnm::kShaderInputUsageImmResource.
m_reserved:bit2; ///< Unused; must be set to zero.
m_chunkMask:bit4; ///< Internal usage data.
end;
);
1:(m_srtSizeInDWordMinusOne:Byte); ///< Size of the SRT data; used for Gnm::kShaderInputUsageImmShaderResourceTable.
end;
const
//ShaderBinaryType
kShaderTypePs = 0;
kShaderTypeVsVs = 1;
kShaderTypeVsEs = 2;
kShaderTypeVsLs = 3;
kShaderTypeCs = 4;
kShaderTypeGs = 5;
kShaderTypeHs = 7;
kShaderTypeDsVs = 8;
//ShaderType
kShaderTypeGraphics = $00000000; ///< Configures command buffer for graphics commands.
kShaderTypeCompute = $00000001; ///< Configures command buffer for compute commands.
//ShaderStage
kShaderStageCs = $00000000; ///< Compute shader stage.
kShaderStagePs = $00000001; ///< Pixel shader stage.
kShaderStageVs = $00000002; ///< Vertex shader stage.
kShaderStageGs = $00000003; ///< Geometry shader stage.
kShaderStageEs = $00000004; ///< Export shader stage.
kShaderStageHs = $00000005; ///< Hull shader stage.
kShaderStageLs = $00000006; ///< LDS shader stage.
kShaderStageCount = 7; //< The number of shader stages.
//Specifies which stages should be activated in the graphics shader pipeline.
//ActiveShaderStages
kActiveShaderStagesVsPs = $00000000; ///< VS/PS only.
kActiveShaderStagesEsGsVsPs = $000000B0; ///< Geometry shader followed by VS/PS.
kActiveShaderStagesLsHsVsPs = $00000045; ///< Tessellation followed by VS/PS.
kActiveShaderStagesOffChipLsHsVsPs = $00000145; ///< Off-chip tessellation followed by VS/PS
kActiveShaderStagesLsHsEsGsVsPs = $000000AD; ///< Tessellation followed by the geometry shader followed by VS/PS.
kActiveShaderStagesOffChipLsHsEsGsVsPs = $000001AD; ///< Off-chip tessellation followed by the geometry shader followed by VS/PS.
kActiveShaderStagesDispatchDrawVsPs = $00000200; ///< Dispatch Draw VS/PS only.
//Describes a data resource expected by a shader.
//Each input must be bound by the application before the shader runs.
//ShaderInputUsageType
kShaderInputUsageImmResource = $00; ///< Immediate read-only buffer/texture descriptor.
kShaderInputUsageImmSampler = $01; ///< Immediate sampler descriptor.
kShaderInputUsageImmConstBuffer = $02; ///< Immediate constant buffer descriptor.
kShaderInputUsageImmVertexBuffer = $03; ///< Immediate vertex buffer descriptor.
kShaderInputUsageImmRwResource = $04; ///< Immediate read/write buffer/texture descriptor.
kShaderInputUsageImmAluFloatConst = $05; ///< Immediate float const (scalar or vector).
kShaderInputUsageImmAluBool32Const = $06; ///< 32 immediate Booleans packed into one UINT.
kShaderInputUsageImmGdsCounterRange = $07; ///< Immediate UINT with GDS address range for counters (used for append/consume buffers).
kShaderInputUsageImmGdsMemoryRange = $08; ///< Immediate UINT with GDS address range for storage.
kShaderInputUsageImmGwsBase = $09; ///< Immediate UINT with GWS resource base offset.
kShaderInputUsageImmShaderResourceTable = $0A; ///< Pointer to read/write resource indirection table.
kShaderInputUsageImmLdsEsGsSize = $0D; ///< Immediate LDS ESGS size used in on-chip GS
// Skipped several items here...
kShaderInputUsageSubPtrFetchShader = $12; ///< Immediate fetch shader subroutine pointer.
kShaderInputUsagePtrResourceTable = $13; ///< Flat resource table pointer.
kShaderInputUsagePtrInternalResourceTable = $14; ///< Flat internal resource table pointer.
kShaderInputUsagePtrSamplerTable = $15; ///< Flat sampler table pointer.
kShaderInputUsagePtrConstBufferTable = $16; ///< Flat const buffer table pointer.
kShaderInputUsagePtrVertexBufferTable = $17; ///< Flat vertex buffer table pointer.
kShaderInputUsagePtrSoBufferTable = $18; ///< Flat stream-out buffer table pointer.
kShaderInputUsagePtrRwResourceTable = $19; ///< Flat read/write resource table pointer.
kShaderInputUsagePtrInternalGlobalTable = $1A; ///< Internal driver table pointer.
kShaderInputUsagePtrExtendedUserData = $1B; ///< Extended user data pointer.
kShaderInputUsagePtrIndirectResourceTable = $1C; ///< Pointer to resource indirection table.
kShaderInputUsagePtrIndirectInternalResourceTable = $1D; ///< Pointer to internal resource indirection table.
kShaderInputUsagePtrIndirectRwResourceTable = $1E; ///< Pointer to read/write resource indirection table.
// Skipped several items here...
kShaderInputUsageImmGdsKickRingBufferOffse = $22; ///< Immediate UINT offset into GDS kick ring buffer for DispatchDraw. This must not be in extended user data.
kShaderInputUsageImmVertexRingBufferOffse = $23; ///< Immediate UINT offset into vertex ring buffer for DispatchDraw. This must not be in extended user data.
kShaderInputUsagePtrDispatchDraw = $24; ///< Pointer to DispatchDraw data. This must not be in extended user data.
kShaderInputUsageImmDispatchDrawInstances = $25; ///< Immediate UINT ((firstInstance<<16)|(numInstances-1)). This must not be in extended user data.
//ShaderProgramType
kShaderProgramTypeLs = 1 shl 0;
kShaderProgramTypeHs = 1 shl 1;
kShaderProgramTypeEs = 1 shl 2;
kShaderProgramTypeGs = 1 shl 3;
kShaderProgramTypeVs = 1 shl 4;
kShaderProgramTypePs = 1 shl 5;
kShaderProgramTypeCsG = 1 shl 10;
kShaderProgramTypeCs0 = 1 shl 15;
kShaderProgramTypeCs1 = 1 shl 16;
kShaderProgramTypeCs2 = 1 shl 17;
kShaderProgramTypeCs3 = 1 shl 18;
kShaderProgramTypeCs4 = 1 shl 19;
kShaderProgramTypeCs5 = 1 shl 20;
kShaderProgramTypeCs6 = 1 shl 21;
kShaderProgramTypeCs7 = 1 shl 22;
type
TShaderType=(
kInvalidShader, ///< Invalid or unrecognized shader.
kVertexShader, ///< VS stage shader
kPixelShader, ///< PS stage shader.
kGeometryShader, ///< GS stage shader.
kComputeShader, ///< CS stage shader.
kExportShader, ///< ES stage shader.
kLocalShader, ///< LS stage shader.
kHullShader, ///< HS stage shader.
kComputeVertexShader); ///< VS stage shader with embedded CS stage frontend shader.
TPsslShaderType=(
kShaderTypeVsShader,
kShaderTypeFsShader,
kShaderTypeCsShader,
kShaderTypeGsShader,
kShaderTypeHsShader,
kShaderTypeDsShader,
kShaderTypeShaderTypeLast
);
TPsslCodeType=(
kCodeTypeIl,
kCodeTypeIsa,
kCodeTypeScu,
kCodeTypeCodeTypeLast
);
type
PVSharpResource=^TVSharpResource;
TVSharpResource=bitpacked record
base:bit44;
mtype_L1s:bit2;
mtype_L2:bit2;
stride:bit14;
cache_swizzle:bit1;
swizzle_en:bit1; //swizzle AOS according to stride, index_stride, and element_size, else linear (stride * index + offset)
//64
num_records:bit32; //n units of 'stride'
dst_sel_x:bit3; //Destination channel select:
dst_sel_y:bit3; //0=0, 1=1, 4=R, 5=G, 6=B, 7=A
dst_sel_z:bit3;
dst_sel_w:bit3;
nfmt:bit3; //numeric data type (float, int, ...)
dfmt:bit4; //data format
element_size:bit2; //2, 4, 8, or 16 bytes. Used for swizzled buffer addressing
index_stride:bit2; //8, 16, 32, or 64. Used for swizzled buffer addressing
addtid_en:bit1; //addtid_en add thread id to the index for addr calc
reserved:bit1;
hash_en:bit1;
mtype:bit3;
_type:bit2; //value == 0 for buf. Overlaps upper 2 bits of 4-bit TYPE field in 128-bit T# resource
end;
PTSharpResource=^TTSharpResource;
TTSharpResource=bitpacked record
base:bit38;
mtype_L2:bit2;
min_lod:bit12;
dfmt:bit6;
nfmt:bit4;
mtype_L1L:bit2;
//64
width:bit14;
height:bit14;
perf_mod:bit3;
interlaced:bit1;
dst_sel_x:bit3;
dst_sel_y:bit3;
dst_sel_z:bit3;
dst_sel_w:bit3;
base_level:bit4;
last_level:bit4;
tiling_idx:bit5;
pow2pad:bit1;
mtype_L1M:bit1;
reserved:bit1;
_type:bit4;
//
end;
PVBufResource=^TVBufResource;
TVBufResource=Pointer;
function _calc_shader_size(base:Pointer;size_dw:DWORD=0;setpc:Boolean=false):DWORD;
function _calc_shader_info(base:Pointer;size_dw:DWORD=0;setpc:Boolean=false):PShaderBinaryInfo;
function _calc_shader_slot(info:PShaderBinaryInfo):PInputUsageSlot;
implementation
function _calc_shader_size(base:Pointer;size_dw:DWORD=0;setpc:Boolean=false):DWORD;
var
i:Integer;
_end:Pointer;
begin
if (base=nil) then Exit(0);
_end:=ps4_pssl._parse_size(base,size_dw,setpc);
Result:=(_end-base);
i:=System.IndexDword(_end^,SHADER_END_SEARCH_MAX_DW,PDWORD(@SHADER_BINARY_INFO_SIG)^);
If (i<>-1) then
begin
Result:=Result+i*SizeOf(DWORD)+SizeOf(TShaderBinaryInfo);
end;
end;
function _calc_shader_info(base:Pointer;size_dw:DWORD=0;setpc:Boolean=false):PShaderBinaryInfo;
var
i:Integer;
_end:Pointer;
begin
Result:=nil;
if (base=nil) then Exit;
_end:=ps4_pssl._parse_size(base,size_dw,setpc);
i:=System.IndexDword(_end^,SHADER_END_SEARCH_MAX_DW,PDWORD(@SHADER_BINARY_INFO_SIG)^);
If (i<>-1) then
begin
Result:=_end+i*SizeOf(DWORD);
end;
end;
function _calc_shader_slot(info:PShaderBinaryInfo):PInputUsageSlot;
var
usageMasks:Pointer;
begin
Result:=nil;
if (info=nil) then Exit;
if (info^.numInputUsageSlots<>0) then
begin
usageMasks:=Pointer(info)-(info^.chunkUsageBaseOffsetInDW*4);
Result:=PInputUsageSlot(usageMasks)-info^.numInputUsageSlots;
end;
end;
end.

3450
chip/ps4_tiling.pas Normal file

File diff suppressed because it is too large Load Diff

1154
chip/ps4_videodrv.pas Normal file

File diff suppressed because it is too large Load Diff

309
chip/shader_dump.pas Normal file
View File

@ -0,0 +1,309 @@
unit shader_dump;
{$mode objfpc}{$H+}
interface
uses
Classes,
SysUtils,
ps4_program,
si_ci_vi_merged_offset,
ps4_shader,
ps4_gpu_regs;
type
TDUMP_WORD=packed record
REG,COUNT:WORD;
end;
Function FastHash(data:PByte;len:DWORD):DWORD;
Procedure DUMP_BLOCK(F:THandle;REG:WORD;P:Pointer;Size:DWORD);
Procedure DumpCS(var GPU_REGS:TGPU_REGS);
Procedure DumpPS(var GPU_REGS:TGPU_REGS);
Procedure DumpVS(var GPU_REGS:TGPU_REGS);
implementation
Function FastHash(data:PByte;len:DWORD):DWORD;
var
hash,tmp,rem:DWORD;
begin
if (len=0) or (data=nil) then Exit(0);
hash:=len;
rem:=len and 3;
len:=len shr 2;
While (len>0) do
begin
tmp :=PDWORD(data)[0];
hash:=hash+PWORD(@tmp)[0];
tmp :=(PWORD(@tmp)[1] shl 11) xor hash;
hash:=(hash shl 16) xor tmp;
data:=@PWORD(data)[2];
hash:=hash+(hash shr 11);
Dec(len);
end;
Case rem of
3:
begin
hash:=hash+PWORD(data)[0];
hash:=hash xor (hash shl 16);
hash:=hash xor (PShortint(data)[2] shl 18);
hash:=hash+(hash shr 11);
end;
2:
begin
hash:=hash+PWORD(data)[0];
hash:=hash xor (hash shl 11);
hash:=hash+(hash shr 17);
end;
1:
begin
hash:=hash+PShortint(data)[0];
hash:=hash xor (hash shl 10);
hash:=hash+(hash shr 1);
end;
end;
hash:=hash xor (hash shl 3);
hash:=hash+(hash shr 5);
hash:=hash xor (hash shl 4);
hash:=hash+(hash shr 17);
hash:=hash xor (hash shl 25);
hash:=hash+(hash shr 6);
Result:=hash;
end;
Procedure DUMP_BLOCK(F:THandle;REG:WORD;P:Pointer;Size:DWORD);
const
MAX_SIZE=($FFFF+1)*4;
var
W:TDUMP_WORD;
begin
if (F=feInvalidHandle) then Exit;
if (Size=0) or (P=nil) then Exit;
if (Size>MAX_SIZE) then Size:=MAX_SIZE;
W.REG :=REG;
W.COUNT:=((Size+3) div 4)-1;
FileWrite(F,W,SizeOf(W));
FileWrite(F,P^,System.Align(Size,4));
end;
function getCodeAddress(lo,hi:DWORD):Pointer;
begin
Result:=Pointer(((QWORD(hi) shl 40) or (QWORD(lo) shl 8)));
end;
function getFetchAddress(P:PDWORD):Pointer;
begin
Result:=Pointer(((QWORD(P[1]) shl 32) or (QWORD(P[0]) and (not 3))));
end;
type
TUSER_DATA_USEAGE=array[0..15] of Byte;
Procedure _calc_usage(info:PShaderBinaryInfo;var USER_DATA:TSPI_USER_DATA;var USEAGE_DATA:TUSER_DATA_USEAGE);
var
i:Integer;
Slots:PInputUsageSlot;
r:Byte;
begin
USEAGE_DATA:=Default(TUSER_DATA_USEAGE);
if (info<>nil) then
begin
Slots:=_calc_shader_slot(info);
if (Slots<>nil) then
For i:=0 to info^.numInputUsageSlots-1 do
if (Slots[i].m_usageType=kShaderInputUsageSubPtrFetchShader) then
begin
r:=Slots[i].m_startRegister;
Assert(r<15);
USEAGE_DATA[r]:=2;
USEAGE_DATA[r+1]:=1;
end;
end;
For i:=0 to 15 do
if (USEAGE_DATA[i]=0) and (USER_DATA[i]=0) then
begin
USEAGE_DATA[i]:=1;
end;
end;
Procedure DumpCS(var GPU_REGS:TGPU_REGS);
var
i:Integer;
size,hash:DWORD;
base,Fetch:Pointer;
F:THandle;
fname:RawByteString;
USEAGE_DATA:TUSER_DATA_USEAGE;
begin
base:=getCodeAddress(GPU_REGS.SPI.CS.LO,GPU_REGS.SPI.CS.HI);
if (base<>nil) then
begin
size:=_calc_shader_size(base);
_calc_usage(_calc_shader_info(base),GPU_REGS.SPI.CS.USER_DATA,USEAGE_DATA);
hash:=FastHash(base,size);
fname:='shader_dump\'+get_dev_progname+'_cs_'+HexStr(hash,8)+'.dump';
CreateDir('shader_dump');
F:=FileCreate(fname);
DUMP_BLOCK(F,mmCOMPUTE_PGM_LO,base,size);
DUMP_BLOCK(F,mmCOMPUTE_PGM_RSRC1 ,@GPU_REGS.SPI.CS.RSRC1 ,SizeOf(DWORD));
DUMP_BLOCK(F,mmCOMPUTE_PGM_RSRC2 ,@GPU_REGS.SPI.CS.RSRC2 ,SizeOf(DWORD));
DUMP_BLOCK(F,mmCOMPUTE_NUM_THREAD_X,@GPU_REGS.SPI.CS.NUM_THREAD_X,SizeOf(DWORD));
DUMP_BLOCK(F,mmCOMPUTE_NUM_THREAD_Y,@GPU_REGS.SPI.CS.NUM_THREAD_Y,SizeOf(DWORD));
DUMP_BLOCK(F,mmCOMPUTE_NUM_THREAD_Z,@GPU_REGS.SPI.CS.NUM_THREAD_Z,SizeOf(DWORD));
For i:=0 to 15 do
begin
Case USEAGE_DATA[i] of
0:DUMP_BLOCK(F,mmCOMPUTE_USER_DATA_0+i,@GPU_REGS.SPI.CS.USER_DATA[i],SizeOf(DWORD));
2:
begin
Fetch:=getFetchAddress(@GPU_REGS.SPI.CS.USER_DATA[i]);
if (Fetch<>nil) then
begin
size:=_calc_shader_size(Fetch,0,True);
DUMP_BLOCK(F,mmCOMPUTE_USER_DATA_0+i,Fetch,size);
end;
end;
end;
end;
DUMP_BLOCK(F,mmCOMPUTE_STATIC_THREAD_MGMT_SE0,@GPU_REGS.SPI.CS.STATIC_THREAD_MGMT_SE0,SizeOf(DWORD));
DUMP_BLOCK(F,mmCOMPUTE_STATIC_THREAD_MGMT_SE1,@GPU_REGS.SPI.CS.STATIC_THREAD_MGMT_SE1,SizeOf(DWORD));
DUMP_BLOCK(F,mmCOMPUTE_RESOURCE_LIMITS ,@GPU_REGS.SPI.CS.RESOURCE_LIMITS ,SizeOf(DWORD));
FileClose(F);
end;
end;
Procedure DumpPS(var GPU_REGS:TGPU_REGS);
var
i:Integer;
size,hash:DWORD;
base,Fetch:Pointer;
F:THandle;
fname:RawByteString;
USEAGE_DATA:TUSER_DATA_USEAGE;
begin
base:=getCodeAddress(GPU_REGS.SPI.PS.LO,GPU_REGS.SPI.PS.HI);
if (base<>nil) then
begin
size:=_calc_shader_size(base);
_calc_usage(_calc_shader_info(base),GPU_REGS.SPI.PS.USER_DATA,USEAGE_DATA);
hash:=FastHash(base,size);
fname:='shader_dump\'+get_dev_progname+'_ps_'+HexStr(hash,8)+'.dump';
CreateDir('shader_dump');
F:=FileCreate(fname);
DUMP_BLOCK(F,mmSPI_SHADER_PGM_LO_PS,base,size);
DUMP_BLOCK(F,mmSPI_SHADER_PGM_RSRC1_PS,@GPU_REGS.SPI.PS.RSRC1,SizeOf(DWORD));
DUMP_BLOCK(F,mmSPI_SHADER_PGM_RSRC2_PS,@GPU_REGS.SPI.PS.RSRC2,SizeOf(DWORD));
DUMP_BLOCK(F,mmSPI_SHADER_PGM_RSRC3_PS,@GPU_REGS.SPI.PS.RSRC3,SizeOf(DWORD));
DUMP_BLOCK(F,mmSPI_SHADER_Z_FORMAT ,@GPU_REGS.SPI.PS.Z_FORMAT ,SizeOf(DWORD));
DUMP_BLOCK(F,mmSPI_SHADER_COL_FORMAT ,@GPU_REGS.SPI.PS.COL_FORMAT,SizeOf(DWORD));
DUMP_BLOCK(F,mmSPI_PS_INPUT_ENA ,@GPU_REGS.SPI.PS.INPUT_ENA ,SizeOf(DWORD));
DUMP_BLOCK(F,mmSPI_PS_INPUT_ADDR ,@GPU_REGS.SPI.PS.INPUT_ADDR,SizeOf(DWORD));
DUMP_BLOCK(F,mmSPI_PS_IN_CONTROL ,@GPU_REGS.SPI.PS.IN_CONTROL,SizeOf(DWORD));
DUMP_BLOCK(F,mmSPI_BARYC_CNTL ,@GPU_REGS.SPI.PS.BARYC_CNTL,SizeOf(DWORD));
DUMP_BLOCK(F,mmDB_SHADER_CONTROL ,@GPU_REGS.SPI.PS.SHADER_CONTROL,SizeOf(DWORD));
DUMP_BLOCK(F,mmCB_SHADER_MASK ,@GPU_REGS.SPI.PS.SHADER_MASK ,SizeOf(DWORD));
For i:=0 to 15 do
begin
Case USEAGE_DATA[i] of
0:DUMP_BLOCK(F,mmSPI_SHADER_USER_DATA_PS_0+i,@GPU_REGS.SPI.PS.USER_DATA[i],SizeOf(DWORD));
2:
begin
Fetch:=getFetchAddress(@GPU_REGS.SPI.PS.USER_DATA[i]);
if (Fetch<>nil) then
begin
size:=_calc_shader_size(Fetch,0,True);
DUMP_BLOCK(F,mmSPI_SHADER_USER_DATA_PS_0+i,Fetch,size);
end;
end;
end;
end;
DUMP_BLOCK(F,mmSPI_PS_INPUT_CNTL_0,@GPU_REGS.SPI.PS.INPUT_CNTL_0,SizeOf(DWORD));
DUMP_BLOCK(F,mmSPI_PS_INPUT_CNTL_1,@GPU_REGS.SPI.PS.INPUT_CNTL_1,SizeOf(DWORD));
FileClose(F);
end;
end;
Procedure DumpVS(var GPU_REGS:TGPU_REGS);
var
i:Integer;
size,hash:DWORD;
base,Fetch:Pointer;
F:THandle;
fname:RawByteString;
USEAGE_DATA:TUSER_DATA_USEAGE;
begin
base:=getCodeAddress(GPU_REGS.SPI.VS.LO,GPU_REGS.SPI.VS.HI);
if (base<>nil) then
begin
size:=_calc_shader_size(base);
_calc_usage(_calc_shader_info(base),GPU_REGS.SPI.VS.USER_DATA,USEAGE_DATA);
hash:=FastHash(base,size);
fname:='shader_dump\'+get_dev_progname+'_vs_'+HexStr(hash,8)+'.dump';
CreateDir('shader_dump');
F:=FileCreate(fname);
DUMP_BLOCK(F,mmSPI_SHADER_PGM_LO_VS,base,size);
DUMP_BLOCK(F,mmSPI_SHADER_PGM_RSRC1_VS,@GPU_REGS.SPI.VS.RSRC1,SizeOf(DWORD));
DUMP_BLOCK(F,mmSPI_SHADER_PGM_RSRC2_VS,@GPU_REGS.SPI.VS.RSRC2,SizeOf(DWORD));
DUMP_BLOCK(F,mmSPI_SHADER_PGM_RSRC3_VS,@GPU_REGS.SPI.VS.RSRC3,SizeOf(DWORD));
DUMP_BLOCK(F,mmSPI_VS_OUT_CONFIG ,@GPU_REGS.SPI.VS.OUT_CONFIG,SizeOf(DWORD));
DUMP_BLOCK(F,mmSPI_SHADER_POS_FORMAT,@GPU_REGS.SPI.VS.POS_FORMAT,SizeOf(DWORD));
DUMP_BLOCK(F,mmPA_CL_VS_OUT_CNTL ,@GPU_REGS.SPI.VS.OUT_CNTL ,SizeOf(DWORD));
For i:=0 to 15 do
begin
Case USEAGE_DATA[i] of
0:DUMP_BLOCK(F,mmSPI_SHADER_USER_DATA_VS_0+i,@GPU_REGS.SPI.VS.USER_DATA[i],SizeOf(DWORD));
2:
begin
Fetch:=getFetchAddress(@GPU_REGS.SPI.VS.USER_DATA[i]);
if (Fetch<>nil) then
begin
size:=_calc_shader_size(Fetch,0,True);
DUMP_BLOCK(F,mmSPI_SHADER_USER_DATA_VS_0+i,Fetch,size);
end;
end;
end;
end;
DUMP_BLOCK(F,mmVGT_NUM_INSTANCES ,@GPU_REGS.VGT_NUM_INSTANCES,SizeOf(DWORD));
FileClose(F);
end;
end;
end.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

142
fpPS4.lpi Normal file
View File

@ -0,0 +1,142 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<General>
<Flags>
<MainUnitHasCreateFormStatements Value="False"/>
<MainUnitHasTitleStatement Value="False"/>
<MainUnitHasScaledStatement Value="False"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
<Title Value="fpPS4"/>
<UseAppBundle Value="False"/>
<ResourceType Value="res"/>
</General>
<BuildModes Count="1">
<Item1 Name="Default" Default="True"/>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
<UseFileFilters Value="True"/>
</PublishOptions>
<RunParams>
<FormatVersion Value="2"/>
<Modes Count="0"/>
</RunParams>
<RequiredPackages Count="1">
<Item1>
<PackageName Value="LCL"/>
</Item1>
</RequiredPackages>
<Units Count="15">
<Unit0>
<Filename Value="fpPS4.lpr"/>
<IsPartOfProject Value="True"/>
</Unit0>
<Unit1>
<Filename Value="ps4_elf_tls.pas"/>
<IsPartOfProject Value="True"/>
</Unit1>
<Unit2>
<Filename Value="ps4_libkerenel\ps4_rwlock.pas"/>
<IsPartOfProject Value="True"/>
</Unit2>
<Unit3>
<Filename Value="ps4_libkerenel\ps4_time.pas"/>
<IsPartOfProject Value="True"/>
</Unit3>
<Unit4>
<Filename Value="ps4_libkerenel\ps4_pthread.pas"/>
<IsPartOfProject Value="True"/>
</Unit4>
<Unit5>
<Filename Value="ps4_libsceuserservice.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="ps4_libSceUserService"/>
</Unit5>
<Unit6>
<Filename Value="ps4_libkerenel\ps4_kernel_file.pas"/>
<IsPartOfProject Value="True"/>
</Unit6>
<Unit7>
<Filename Value="ps4_libscesavedata.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="ps4_libSceSaveData"/>
</Unit7>
<Unit8>
<Filename Value="ps4_libscenptrophy.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="ps4_libSceNpTrophy"/>
</Unit8>
<Unit9>
<Filename Value="ps4_libkerenel\ps4_queue.pas"/>
<IsPartOfProject Value="True"/>
</Unit9>
<Unit10>
<Filename Value="chip\ps4_gpu_regs.pas"/>
<IsPartOfProject Value="True"/>
</Unit10>
<Unit11>
<Filename Value="chip\shader_dump.pas"/>
<IsPartOfProject Value="True"/>
</Unit11>
<Unit12>
<Filename Value="ps4_libscehttp.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="ps4_libSceHttp"/>
</Unit12>
<Unit13>
<Filename Value="ps4_libscenet.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="ps4_libSceNet"/>
</Unit13>
<Unit14>
<Filename Value="vulkan\vRender.pas"/>
<IsPartOfProject Value="True"/>
</Unit14>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="fpPS4"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value="ps4_libkerenel;vulkan;chip"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>
<IncludeAssertionCode Value="True"/>
</SyntaxOptions>
</Parsing>
<CodeGeneration>
<SmartLinkUnit Value="True"/>
<RelocatableUnit Value="True"/>
<Optimizations>
<OptimizationLevel Value="3"/>
</Optimizations>
</CodeGeneration>
<Linking>
<LinkSmart Value="True"/>
</Linking>
</CompilerOptions>
<Debugging>
<Exceptions Count="3">
<Item1>
<Name Value="EAbort"/>
</Item1>
<Item2>
<Name Value="ECodetoolError"/>
</Item2>
<Item3>
<Name Value="EFOpenError"/>
</Item3>
</Exceptions>
</Debugging>
</CONFIG>

290
fpPS4.lpr Normal file
View File

@ -0,0 +1,290 @@
uses
{$IFDEF Linux}
cmem,
cthreads,
{$ENDIF}
seh64,
Classes,sysutils,
stub_manager,
ps4libdoc,
ps4_libSceNet,
ps4_libSceHttp,
ps4_libSceGnmDriver,
ps4_libSceNpScore,
ps4_libSceNpTrophy,
ps4_libSceSystemService,
ps4_libSceNpManager,
ps4_libSceSaveData,
ps4_libSceDialogs,
ps4_libSceUserService,
ps4_libsceaudioout,
ps4_libSceVideoOut,
ps4_libScePad,
ps4_libkernel,
ps4_types,
ps4_elf,
ps4_pthread,
ps4_program,
ps4_elf_tls;
function ParseCmd:Boolean;
var
i,n:Integer;
label
promo;
begin
if (ParamCount=0) then
begin
promo:
Writeln('PS4 compatibility layer (emulator) on Free Pascal '+{$I %FPCVERSION%});
Writeln(' Parameters:');
Writeln(' -e <name> //decrypted elf or self file name');
Writeln(' -f <name> //folder of app');
Writeln(' -s <name> //savedata path');
Exit(False);
end;
n:=-1;
For i:=1 to ParamCount do
begin
case LowerCase(ParamStr(i)) of
'-e':n:=0;
'-f':n:=1;
'-s':n:=2;
else
if (n<>-1) then
begin
Case n of
0:begin
if (ps4_app.app_file<>'') then Goto promo;
ps4_app.app_file:=Trim(ParamStr(i));
if (ps4_app.app_path='') then
begin
ps4_app.app_path:=ExtractFileDir(ps4_app.app_file);
if (ExcludeLeadingPathDelimiter(ps4_app.app_path)='') then ps4_app.app_path:=GetCurrentDir;
end;
end;
1:begin
ps4_app.app_path:=Trim(ParamStr(i));
if (ExcludeLeadingPathDelimiter(ps4_app.app_path)='') then ps4_app.app_path:=GetCurrentDir;
end;
2:begin
ps4_app.save_path:=Trim(ParamStr(i));
end;
end;
n:=-1;
end;
end;
end;
if (ps4_app.app_file='') or (ps4_app.app_path='') or (ps4_app.save_path='') then Goto promo;
if not FileExists(ps4_app.app_file) then
begin
Writeln('File not found:',ps4_app.app_file);
Writeln;
Goto promo;
end;
if not DirectoryExists(ps4_app.app_path) then
begin
Writeln('Path not found:',ps4_app.app_path);
Writeln;
Goto promo;
end;
if not DirectoryExists(ps4_app.save_path) then
begin
Writeln('Path not found:',ps4_app.save_path);
Writeln;
Goto promo;
end;
Result:=True;
end;
{
type
_TElf_node=class(TElf_node)
end;
procedure Print_libs(node:TElf_node);
var
i,l:SizeInt;
lib:PLIBRARY;
begin
l:=Length(_TElf_node(node).aLibs);
if (l<>0) then
begin
For i:=0 to l-1 do
begin
lib:=_TElf_node(node).aLibs[i];
Writeln(hexStr(lib));
if lib<>nil then
Writeln(lib^.Import,' ',lib^.strName);
end;
end;
end;
}
var
Stub:TStubMemoryProc;
procedure _nop_stub; assembler; nostackframe;
asm
xor %rax,%rax
end;
procedure print_stub(nid:QWORD;lib:PLIBRARY);
begin
Writeln('nop nid:',lib^.strName,':',HexStr(nid,16),':',ps4libdoc.GetFunctName(nid));
writeln;
//readln;
//Print_libs(ps4_app.GetFile('libc.prx'));
end;
function ps4_sceSslInit(poolSize:size_t):Integer; SysV_ABI_CDecl;
begin
Writeln('sceSslInit:',poolSize);
Result:=3;
end;
function ResolveImport(elf:Telf_file;Info:PResolveImportInfo;data:Pointer):Pointer;
var
lib:PLIBRARY;
begin
Result:=nil;
//cache
Result:=Info^.lib^.get_proc(Info^.nid);
if (Result<>nil) then
begin
//Writeln('Cache^:',Info^.lib^.strName,':',ps4libdoc.GetFunctName(Info^.Nid));
Exit;
end;
lib:=ps4_app.GetLib(Info^.lib^.strName);
if (lib<>nil) then
begin
Result:=lib^.get_proc(Info^.Nid);
end;
if (Result=nil) then
begin
Case Info^.lib^.strName of
'libSceSsl':
Case Info^.nid of
$85DA551140C55B7B:Result:=@ps4_sceSslInit;
end;
end;
end;
if (Result=nil) then
begin
if (Info^.sType=STT_FUN) then
begin
Result:=Stub.NewNopStub(Info^.Nid,Info^.lib,@print_stub);
//Writeln('Warn^:',Info^.lib^.strName,':',ps4libdoc.GetFunctName(Info^.Nid),':',HexStr(Info^.Nid,16));
end else
begin
//PNAME = 'module_stop',
//_MD = $11af200,
//LIB = $114e110,
//NID = 0,
//OFFSET = 311584,
//RTYPE = 7, //R_X86_64_JUMP_SLOT
//SBIND = 2, //STB_WEAK
//STYPE = 0} //STT_NOTYPE
Writeln('Warn^:',Info^.lib^.strName,':',ps4libdoc.GetFunctName(Info^.Nid),':',HexStr(Info^.Nid,16));
end;
end;
if (Result<>nil) then //cache
begin
Info^.lib^.set_proc(Info^.nid,Result);
end;
end;
var
elf:Telf_file;
//i:Integer;
//F:THandle;
main:pthread;
begin
DefaultSystemCodePage:=CP_UTF8;
DefaultUnicodeCodePage:=CP_UTF8;
DefaultFileSystemCodePage:=CP_UTF8;
DefaultRTLFileSystemCodePage:=CP_UTF8;
UTF8CompareLocale:=CP_UTF8;
ps4_app.save_path:=IncludeTrailingPathDelimiter(GetCurrentDir)+'savedata';
if not ParseCmd then Exit;
//ps4_app.app_path:='..\samples\api_gnm\simplet-single-triangle';
//ps4_app.app_file:='..\samples\api_gnm\simplet-single-triangle\simplet-single-triangle_debug.elf';
//ps4_app.app_file:='..\samples\api_gnm\simplet-cmask\simplet-cmask_debug.elf';
//ps4_app.app_path:='..\samples\api_gnm\simplet-simple-fs\';
//ps4_app.app_file:='..\samples\api_gnm\simplet-simple-fs\simplet-simple-fs_debug.elf';
//ps4_app.app_path:='..\samples\tutorial_graphics_programming\basic_quad\';
//ps4_app.app_file:='..\samples\tutorial_graphics_programming\basic_quad\basic_quad_debug.elf';
//ps4_app.app_file:='..\samples\api_video_out\videoout_cursor.elf';
//ps4_app.app_file:='..\samples\api_video_out\videoout_flip.elf';
//ps4_app.app_file:='..\samples\api_video_out\videoout_basic2.elf';
//ps4_app.app_file:='..\samples\api_video_out\videoout_basic3.elf';
//ps4_app.app_file:='..\samples\api_video_out\videoout_basic5.elf';
//ps4_app.app_path:='G:\Games\MOMODORA\CUSA05694\';
//ps4_app.app_file:='G:\Games\MOMODORA\CUSA05694\eboot.bin';
//ps4_app.app_path:='G:\Games\We.Are.Doomed.PS4-PRELUDE\CUSA02394\';
//ps4_app.app_file:='G:\Games\We.Are.Doomed.PS4-PRELUDE\CUSA02394\eboot.elf';
//Writeln(_parse_filename('/app0/data/system_ps4/flatShader_vv.sb'));
//Writeln(_parse_filename('savedata0/11/../app.prf'));
//elf:=Telf_file(LoadPs4ElfFromFile('libSceLibcInternal.sprx'));
//elf.Prepare;
//elf.SavePs4ElfToFile('libSceLibcInternal.prx');
//F:=FileCreate('libSceLibcInternal.txt');
//elf.DympSymbol(F);
//FileClose(F);
//FreeAndNil(elf);
elf:=Telf_file(LoadPs4ElfFromFile(ps4_app.app_file));
elf.Prepare;
ps4_app.prog:=elf;
ps4_app.RegistredElf(elf);
ps4_app.ResolveDepended(elf);
ps4_app.LoadSymbolImport(@ResolveImport,nil);
Stub.FinStub;
ps4_app.InitProt;
ps4_app.InitThread;
_pthread_run_entry(@main);
//ps4_app.InitCode;
//elf.mapCodeEntry;
ps4_libSceVideoOut.App_Run;
//KillALLThreads TODO
//readln;
end.

1007
g23tree.pas Normal file

File diff suppressed because it is too large Load Diff

989
hamt.pas Normal file
View File

@ -0,0 +1,989 @@
{ Simplified implementation of HAMT (Hash Array Mapped Trie) with 32bit/64bit hash key.
Specific hash functions and collision resolution are outside the scope of
this implementation and can be implemented on top of it.
Copyright (C) 2021 Red_prig
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version with the following modification:
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent modules,and
to copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the terms
and conditions of the license of that module. An independent module is a
module which is not derived from or based on this library. If you modify
this library, you may extend this exception to your version of the library,
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
for more details.
}
unit hamt;
{$mode objfpc}{$H+}
interface
type
THAMT=type Pointer;
Tfree_data_cb=procedure(data,userdata:Pointer);
function HAMT_create32:THAMT;
function HAMT_clear32(hamt:THAMT;cb:Tfree_data_cb;userdata:Pointer):Boolean;
function HAMT_destroy32(hamt:THAMT;cb:Tfree_data_cb;userdata:Pointer):Boolean;
function HAMT_search32(hamt:THAMT;key:DWORD):PPointer; //mutable link to data
function HAMT_insert32(hamt:THAMT;key:DWORD;data:Pointer):PPointer; //mutable link to data
function HAMT_delete32(hamt:THAMT;key:DWORD):Pointer; //data
function HAMT_traverse32(hamt:THAMT;cb:Tfree_data_cb;userdata:Pointer):Boolean;
function HAMT_create64:THAMT;
function HAMT_clear64(hamt:THAMT;cb:Tfree_data_cb;userdata:Pointer):Boolean;
function HAMT_destroy64(hamt:THAMT;cb:Tfree_data_cb;userdata:Pointer):Boolean;
function HAMT_search64(hamt:THAMT;key:QWORD):PPointer; //mutable link to data
function HAMT_insert64(hamt:THAMT;key:QWORD;data:Pointer):PPointer; //mutable link to data
function HAMT_delete64(hamt:THAMT;key:QWORD):Pointer; //data
function HAMT_traverse64(hamt:THAMT;cb:Tfree_data_cb;userdata:Pointer):Boolean;
type
// [7] [5]*5 =32
HAMT32=object
type
TBitKey=DWORD;
const
node_size=SizeOf(TBitKey)*TBitKey(8);
node_mask=TBitKey(node_size)-TBitKey(1);
node_bits=PopCnt(TBitKey(node_mask));
root_bits=(TBitKey(node_size) mod TBitKey(node_bits))+TBitKey(node_bits);
root_size=TBitKey(1) shl TBitKey(root_bits);
root_mask=TBitKey(root_size)-TBitKey(1);
const_one=TBitKey(1);
const_max=not TBitKey(0);
stack_max=(TBitKey(node_size) div TBitKey(node_bits));
end;
//[10] [6]*9 =64
HAMT64=object
type
TBitKey=QWORD;
const
node_size=SizeOf(TBitKey)*TBitKey(8);
node_mask=TBitKey(node_size)-TBitKey(1);
node_bits=PopCnt(TBitKey(node_mask));
root_bits=(TBitKey(node_size) mod TBitKey(node_bits))+TBitKey(node_bits);
root_size=TBitKey(1) shl TBitKey(root_bits);
root_mask=TBitKey(root_size)-TBitKey(1);
const_one=TBitKey(1);
const_max=not TBitKey(0);
stack_max=(TBitKey(node_size) div TBitKey(node_bits));
end;
type
PHAMTNode32=^THAMTNode32;
THAMTNode32=packed record
BitMapKey:DWORD;
BaseValue:Pointer;
end;
PHAMTNode64=^THAMTNode64;
THAMTNode64=packed record
BitMapKey:QWORD;
BaseValue:Pointer;
end;
TSTUB_HAMT32=array[0..HAMT32.root_size-1] of THAMTNode32;
TSTUB_HAMT64=array[0..HAMT64.root_size-1] of THAMTNode64;
implementation
function IsSubTrie32(n:PHAMTNode32):Boolean; inline;
begin
Result:=(PtrUint(n^.BaseValue) and 1)<>0;
end;
function IsSubTrie64(n:PHAMTNode64):Boolean; inline;
begin
Result:=(PtrUint(n^.BaseValue) and 1)<>0;
end;
procedure SetSubTrie32(n:PHAMTNode32;v:PHAMTNode32); inline;
begin
Assert((PtrUint(v) and 1)=0);
PtrUint(n^.BaseValue):=PtrUint(v) or 1;
end;
procedure SetSubTrie64(n:PHAMTNode64;v:PHAMTNode64); inline;
begin
Assert((PtrUint(v) and 1)=0);
PtrUint(n^.BaseValue):=PtrUint(v) or 1;
end;
procedure SetValue32(n:PHAMTNode32;v:Pointer); inline;
begin
Assert((PtrUint(v) and 1)=0);
n^.BaseValue:=v;
end;
procedure SetValue64(n:PHAMTNode64;v:Pointer); inline;
begin
Assert((PtrUint(v) and 1)=0);
n^.BaseValue:=v;
end;
function GetSubTrie32(n:PHAMTNode32):PHAMTNode32; inline;
begin
PtrUint(Result):=(PtrUint(n^.BaseValue) or 1) xor 1;
end;
function GetSubTrie64(n:PHAMTNode64):PHAMTNode64; inline;
begin
PtrUint(Result):=(PtrUint(n^.BaseValue) or 1) xor 1;
end;
function GetValue32(n:PHAMTNode32):Pointer; inline;
begin
Result:=n^.BaseValue;
end;
function GetValue64(n:PHAMTNode64):Pointer; inline;
begin
Result:=n^.BaseValue;
end;
function GetMutableValue32(n:PHAMTNode32):PPointer; inline;
begin
Result:=@n^.BaseValue;
end;
function GetMutableValue64(n:PHAMTNode64):PPointer; inline;
begin
Result:=@n^.BaseValue;
end;
function GetBitMapSize32(BitKey:DWORD):DWORD; inline;
begin
Result:=PopCnt(BitKey);
Result:=Result and HAMT32.node_mask;
if (Result=0) then Result:=HAMT32.node_size;
end;
function GetBitMapSize64(BitKey:QWORD):QWORD; inline;
begin
Result:=PopCnt(BitKey);
Result:=Result and HAMT64.node_mask;
if (Result=0) then Result:=HAMT64.node_size;
end;
function BitIsNotSet32(BitKey,keypart:DWORD):Boolean; inline;
begin
Result:=(BitKey and (HAMT32.const_one shl keypart))=0;
end;
function BitIsNotSet64(BitKey,keypart:QWORD):Boolean; inline;
begin
Result:=(BitKey and (HAMT64.const_one shl keypart))=0;
end;
function SetBitInSet32(BitKey,keypart:DWORD):DWORD; inline;
begin
Result:=BitKey or (HAMT32.const_one shl keypart);
end;
function SetBitInSet64(BitKey,keypart:QWORD):QWORD; inline;
begin
Result:=BitKey or (HAMT64.const_one shl keypart);
end;
function UnSetBitInSet32(BitKey,keypart:DWORD):DWORD; inline;
begin
Result:=BitKey and (not (HAMT32.const_one shl keypart));
end;
function UnSetBitInSet64(BitKey,keypart:QWORD):QWORD; inline;
begin
Result:=BitKey and (not (HAMT64.const_one shl keypart));
end;
function GetMapPos32(BitKey,keypart:DWORD):DWORD; inline;
begin
Result:=PopCnt(BitKey and (not DWORD(HAMT32.const_max shl keypart)));
Result:=Result and HAMT32.node_mask; //Clamp
end;
function GetMapPos64(BitKey,keypart:QWORD):QWORD; inline;
begin
Result:=PopCnt(BitKey and (not QWORD(HAMT64.const_max shl keypart)));
Result:=Result and HAMT64.node_mask; //Clamp
end;
function HAMT_create32:THAMT;
begin
Result:=AllocMem(HAMT32.root_size*SizeOf(THAMTNode32));
end;
function HAMT_create64:THAMT;
begin
Result:=AllocMem(HAMT64.root_size*SizeOf(THAMTNode64));
end;
procedure HAMT_delete_trie32(node:PHAMTNode32;cb:Tfree_data_cb;userdata:Pointer); inline;
type
PStackNode=^TStackNode;
TStackNode=packed record
bnode,cnode,enode:PHAMTNode32;
end;
var
curr:PStackNode;
data:array[0..HAMT32.stack_max] of TStackNode;
Size:DWORD;
begin
if IsSubTrie32(node) then
begin
curr:=@data;
Size:=GetBitMapSize32(node^.BitMapKey);
With curr^ do
begin
bnode:=GetSubTrie32(node);
cnode:=bnode;
enode:=@bnode[Size];
end;
repeat
if (curr^.cnode>=curr^.enode) then
begin
FreeMem(curr^.bnode);
if (curr=@data) then Break;
Dec(curr);
Inc(curr^.cnode);
Continue;
end;
if IsSubTrie32(curr^.cnode) then
begin
node:=curr^.cnode;
Inc(curr);
Size:=GetBitMapSize32(node^.BitMapKey);
With curr^ do
begin
bnode:=GetSubTrie32(node);
cnode:=bnode;
enode:=@bnode[Size];
end;
end else
begin
if (cb<>nil) then
cb(GetValue32(curr^.cnode),userdata);
Inc(curr^.cnode);
end;
until false;
end else
begin
if (cb<>nil) then
cb(GetValue32(node),userdata);
end;
end;
procedure HAMT_delete_trie64(node:PHAMTNode64;cb:Tfree_data_cb;userdata:Pointer); inline;
type
PStackNode=^TStackNode;
TStackNode=packed record
bnode,cnode,enode:PHAMTNode64;
end;
var
curr:PStackNode;
data:array[0..HAMT64.stack_max] of TStackNode;
Size:QWORD;
begin
if IsSubTrie64(node) then
begin
curr:=@data;
Size:=GetBitMapSize64(node^.BitMapKey);
With curr^ do
begin
bnode:=GetSubTrie64(node);
cnode:=bnode;
enode:=@bnode[Size];
end;
repeat
if (curr^.cnode>=curr^.enode) then
begin
FreeMem(curr^.bnode);
if (curr=@data) then Break;
Dec(curr);
Inc(curr^.cnode);
Continue;
end;
if IsSubTrie64(curr^.cnode) then
begin
node:=curr^.cnode;
Inc(curr);
Size:=GetBitMapSize64(node^.BitMapKey);
With curr^ do
begin
bnode:=GetSubTrie64(node);
cnode:=bnode;
enode:=@bnode[Size];
end;
end else
begin
if (cb<>nil) then
cb(GetValue64(curr^.cnode),userdata);
Inc(curr^.cnode);
end;
until false;
end else
begin
if (cb<>nil) then
cb(GetValue64(node),userdata);
end;
end;
function HAMT_clear32(hamt:THAMT;cb:Tfree_data_cb;userdata:Pointer):Boolean;
var
i:Integer;
begin
if (hamt=nil) then Exit(False);
For i:=0 to HAMT32.root_mask do
begin
HAMT_delete_trie32(@PHAMTNode32(hamt)[i],cb,userdata);
end;
FillChar(hamt^,HAMT32.root_size*SizeOf(THAMTNode32),0);
Result:=True;
end;
function HAMT_clear64(hamt:THAMT;cb:Tfree_data_cb;userdata:Pointer):Boolean;
var
i:Integer;
begin
if (hamt=nil) then Exit(False);
For i:=0 to HAMT64.root_mask do
begin
HAMT_delete_trie64(@PHAMTNode64(hamt)[i],cb,userdata);
end;
FillChar(hamt^,HAMT64.root_size*SizeOf(THAMTNode64),0);
Result:=True;
end;
procedure HAMT_traverse_trie32(node:PHAMTNode32;cb:Tfree_data_cb;userdata:Pointer); inline;
type
PStackNode=^TStackNode;
TStackNode=packed record
cnode,enode:PHAMTNode32;
end;
var
curr:PStackNode;
data:array[0..HAMT32.stack_max] of TStackNode;
Size:QWORD;
begin
if IsSubTrie32(node) then
begin
curr:=@data;
Size:=GetBitMapSize32(node^.BitMapKey);
With curr^ do
begin
cnode:=GetSubTrie32(node);
enode:=@cnode[Size];
end;
repeat
if (curr^.cnode>=curr^.enode) then
begin
if (curr=@data) then Break;
Dec(curr);
Inc(curr^.cnode);
Continue;
end;
if IsSubTrie32(curr^.cnode) then
begin
node:=curr^.cnode;
Inc(curr);
Size:=GetBitMapSize32(node^.BitMapKey);
With curr^ do
begin
cnode:=GetSubTrie32(node);
enode:=@cnode[Size];
end;
end else
begin
if (cb<>nil) then
cb(GetValue32(curr^.cnode),userdata);
Inc(curr^.cnode);
end;
until false;
end else
begin
if (cb<>nil) then
cb(GetValue32(node),userdata);
end;
end;
procedure HAMT_traverse_trie64(node:PHAMTNode64;cb:Tfree_data_cb;userdata:Pointer); inline;
type
PStackNode=^TStackNode;
TStackNode=packed record
cnode,enode:PHAMTNode64;
end;
var
curr:PStackNode;
data:array[0..HAMT64.stack_max] of TStackNode;
Size:QWORD;
begin
if IsSubTrie64(node) then
begin
curr:=@data;
Size:=GetBitMapSize64(node^.BitMapKey);
With curr^ do
begin
cnode:=GetSubTrie64(node);
enode:=@cnode[Size];
end;
repeat
if (curr^.cnode>=curr^.enode) then
begin
if (curr=@data) then Break;
Dec(curr);
Inc(curr^.cnode);
Continue;
end;
if IsSubTrie64(curr^.cnode) then
begin
node:=curr^.cnode;
Inc(curr);
Size:=GetBitMapSize64(node^.BitMapKey);
With curr^ do
begin
cnode:=GetSubTrie64(node);
enode:=@cnode[Size];
end;
end else
begin
if (cb<>nil) then
cb(GetValue64(curr^.cnode),userdata);
Inc(curr^.cnode);
end;
until false;
end else
begin
if (cb<>nil) then
cb(GetValue64(node),userdata);
end;
end;
function HAMT_traverse32(hamt:THAMT;cb:Tfree_data_cb;userdata:Pointer):Boolean;
var
i:Integer;
begin
if (hamt=nil) then Exit(False);
For i:=0 to HAMT32.root_mask do
begin
HAMT_traverse_trie32(@PHAMTNode32(hamt)[i],cb,userdata);
end;
Result:=True;
end;
function HAMT_traverse64(hamt:THAMT;cb:Tfree_data_cb;userdata:Pointer):Boolean;
var
i:Integer;
begin
if (hamt=nil) then Exit(False);
For i:=0 to HAMT64.root_mask do
begin
HAMT_traverse_trie64(@PHAMTNode64(hamt)[i],cb,userdata);
end;
Result:=True;
end;
function HAMT_destroy32(hamt:THAMT;cb:Tfree_data_cb;userdata:Pointer):Boolean;
begin
Result:=HAMT_clear32(hamt,cb,userdata);
FreeMem(hamt);
end;
function HAMT_destroy64(hamt:THAMT;cb:Tfree_data_cb;userdata:Pointer):Boolean;
begin
Result:=HAMT_clear64(hamt,cb,userdata);
FreeMem(hamt);
end;
function HAMT_search32(hamt:THAMT;key:DWORD):PPointer;
var
node:PHAMTNode32;
keypart,Map:DWORD;
keypartbits:DWORD;
begin
if (hamt=nil) then Exit(nil);
keypartbits:=HAMT32.root_bits;
keypart:=key and HAMT32.root_mask;
node:=@PHAMTNode32(hamt)[keypart];
if (node^.BaseValue=nil) then Exit(nil);
repeat
if not IsSubTrie32(node) then
begin
if (node^.BitMapKey=key) then
begin
Exit(GetMutableValue32(node));
end else
Exit(nil);
end;
//Subtree: look up in bitmap
Assert(keypartbits<HAMT32.node_size);
keypart:=(key shr keypartbits) and HAMT32.node_mask;
if BitIsNotSet32(node^.BitMapKey,keypart) then
Exit(nil); // bit is 0 in bitmap -> no match
Map:=GetMapPos32(node^.BitMapKey,keypart);
// Go down a level */
node:=@GetSubTrie32(node)[Map];
keypartbits:=keypartbits+HAMT32.node_bits;
until false;
end;
function HAMT_search64(hamt:THAMT;key:QWORD):PPointer;
var
node:PHAMTNode64;
keypart,Map:QWORD;
keypartbits:QWORD;
begin
if (hamt=nil) then Exit(nil);
keypartbits:=HAMT64.root_bits;
keypart:=key and HAMT64.root_mask;
node:=@PHAMTNode64(hamt)[keypart];
if (node^.BaseValue=nil) then Exit(nil);
repeat
if not IsSubTrie64(node) then
begin
if (node^.BitMapKey=key) then
begin
Exit(GetMutableValue64(node));
end else
Exit(nil);
end;
//Subtree: look up in bitmap
Assert(keypartbits<HAMT64.node_size);
keypart:=(key shr keypartbits) and HAMT64.node_mask;
if BitIsNotSet64(node^.BitMapKey,keypart) then
Exit(nil); // bit is 0 in bitmap -> no match
Map:=GetMapPos64(node^.BitMapKey,keypart);
// Go down a level */
node:=@GetSubTrie64(node)[Map];
keypartbits:=keypartbits+HAMT64.node_bits;
until false;
end;
function HAMT_insert32(hamt:THAMT;key:DWORD;data:Pointer):PPointer;
var
node,oldnodes,newnodes:PHAMTNode32;
key2,keypart,keypart2,Map,Size:DWORD;
keypartbits:DWORD;
begin
if (hamt=nil) then Exit(nil);
keypartbits:=HAMT32.root_bits;
keypart:=key and HAMT32.root_mask;
node:=@PHAMTNode32(hamt)[keypart];
if (node^.BaseValue=nil) then
begin
node^.BitMapKey:=key;
SetValue32(node,data);
Assert(not IsSubTrie32(node));
Exit(GetMutableValue32(node));
end;
repeat
if not IsSubTrie32(node) then
begin
if (node^.BitMapKey=key) then
begin
Exit(GetMutableValue32(node));
end else
begin
key2:=node^.BitMapKey;
//build tree downward until keys differ
repeat
Assert(keypartbits<HAMT32.node_size);
keypart :=(key shr keypartbits) and HAMT32.node_mask;
keypart2:=(key2 shr keypartbits) and HAMT32.node_mask;
if (keypart=keypart2) then
begin
newnodes:=AllocMem(SizeOf(THAMTNode32));
Assert((PtrUint(newnodes) and 1)=0);
newnodes[0].BitMapKey:=key2;
newnodes[0].BaseValue:=node^.BaseValue;
node^.BitMapKey:=SetBitInSet32(0,keypart);
SetSubTrie32(node,newnodes);
node:=@newnodes[0];
end else
begin
newnodes:=AllocMem(2*SizeOf(THAMTNode32));
Assert((PtrUint(newnodes) and 1)=0);
if (keypart2<keypart) then
begin
newnodes[0].BitMapKey:=key2;
newnodes[0].BaseValue:=node^.BaseValue;
newnodes[1].BitMapKey:=key;
SetValue32(@newnodes[1],data);
Result:=GetMutableValue32(@newnodes[1]);
end else
begin
newnodes[0].BitMapKey:=key;
SetValue32(@newnodes[0],data);
Result:=GetMutableValue32(@newnodes[0]);
newnodes[1].BitMapKey:=key2;
newnodes[1].BaseValue:=node^.BaseValue;
end;
node^.BitMapKey:=(HAMT32.const_one shl keypart) or (HAMT32.const_one shl keypart2);
SetSubTrie32(node,newnodes);
Exit;
end;
keypartbits:=keypartbits+HAMT32.node_bits;
until false;
end;
end; //if not IsSubTrie(node) then
Assert(keypartbits<HAMT32.node_size);
keypart:=(key shr keypartbits) and HAMT32.node_mask;
if BitIsNotSet32(node^.BitMapKey,keypart) then
begin
// bit is 0 in bitmap -> add node to table
node^.BitMapKey:=SetBitInSet32(node^.BitMapKey,keypart);
Size:=GetBitMapSize32(node^.BitMapKey);
Map:=GetMapPos32(node^.BitMapKey,keypart);
oldnodes:=GetSubTrie32(node);
if (MemSize(oldnodes)>=(Size*SizeOf(THAMTNode32))) then
begin
newnodes:=oldnodes;
Move(oldnodes[Map],newnodes[Map+1],(Size-Map-1)*SizeOf(THAMTNode32));
end else
begin
newnodes:=AllocMem(Size*SizeOf(THAMTNode32));
Assert((PtrUint(newnodes) and 1)=0);
Move(oldnodes[0] ,newnodes[0] , Map*SizeOf(THAMTNode32));
Move(oldnodes[Map],newnodes[Map+1],(Size-Map-1)*SizeOf(THAMTNode32));
FreeMem(oldnodes);
SetSubTrie32(node,newnodes);
end;
// Set up new node
newnodes[Map].BitMapKey:=key;
SetValue32(@newnodes[Map],data);
Exit(GetMutableValue32(@newnodes[Map]));
end;
Map:=GetMapPos32(node^.BitMapKey,keypart);
// Go down a level */
node:=@GetSubTrie32(node)[Map];
keypartbits:=keypartbits+HAMT32.node_bits;
until false;
end;
function HAMT_insert64(hamt:THAMT;key:QWORD;data:Pointer):PPointer;
var
node,oldnodes,newnodes:PHAMTNode64;
key2,keypart,keypart2,Map,Size:QWORD;
keypartbits:QWORD;
begin
if (hamt=nil) then Exit(nil);
keypartbits:=HAMT64.root_bits;
keypart:=key and HAMT64.root_mask;
node:=@PHAMTNode64(hamt)[keypart];
if (node^.BaseValue=nil) then
begin
node^.BitMapKey:=key;
SetValue64(node,data);
Assert(not IsSubTrie64(node));
Exit(GetMutableValue64(node));
end;
repeat
if not IsSubTrie64(node) then
begin
if (node^.BitMapKey=key) then
begin
Exit(GetMutableValue64(node));
end else
begin
key2:=node^.BitMapKey;
//build tree downward until keys differ
repeat
Assert(keypartbits<HAMT64.node_size);
keypart :=(key shr keypartbits) and HAMT64.node_mask;
keypart2:=(key2 shr keypartbits) and HAMT64.node_mask;
if (keypart=keypart2) then
begin
newnodes:=AllocMem(SizeOf(THAMTNode64));
Assert((PtrUint(newnodes) and 1)=0);
newnodes[0].BitMapKey:=key2;
newnodes[0].BaseValue:=node^.BaseValue;
node^.BitMapKey:=SetBitInSet64(0,keypart);
SetSubTrie64(node,newnodes);
node:=@newnodes[0];
end else
begin
newnodes:=AllocMem(2*SizeOf(THAMTNode64));
Assert((PtrUint(newnodes) and 1)=0);
if (keypart2<keypart) then
begin
newnodes[0].BitMapKey:=key2;
newnodes[0].BaseValue:=node^.BaseValue;
newnodes[1].BitMapKey:=key;
SetValue64(@newnodes[1],data);
Result:=GetMutableValue64(@newnodes[1]);
end else
begin
newnodes[0].BitMapKey:=key;
SetValue64(@newnodes[0],data);
Result:=GetMutableValue64(@newnodes[0]);
newnodes[1].BitMapKey:=key2;
newnodes[1].BaseValue:=node^.BaseValue;
end;
node^.BitMapKey:=(HAMT64.const_one shl keypart) or (HAMT64.const_one shl keypart2);
SetSubTrie64(node,newnodes);
Exit;
end;
keypartbits:=keypartbits+HAMT64.node_bits;
until false;
end;
end; //if not IsSubTrie(node) then
Assert(keypartbits<HAMT64.node_size);
keypart:=(key shr keypartbits) and HAMT64.node_mask;
if BitIsNotSet64(node^.BitMapKey,keypart) then
begin
// bit is 0 in bitmap -> add node to table
node^.BitMapKey:=SetBitInSet64(node^.BitMapKey,keypart);
Size:=GetBitMapSize64(node^.BitMapKey);
Map:=GetMapPos64(node^.BitMapKey,keypart);
oldnodes:=GetSubTrie64(node);
if (MemSize(oldnodes)>=(Size*SizeOf(THAMTNode64))) then
begin
newnodes:=oldnodes;
Move(oldnodes[Map],newnodes[Map+1],(Size-Map-1)*SizeOf(THAMTNode64));
end else
begin
newnodes:=AllocMem(Size*SizeOf(THAMTNode64));
Assert((PtrUint(newnodes) and 1)=0);
Move(oldnodes[0] ,newnodes[0] , Map*SizeOf(THAMTNode64));
Move(oldnodes[Map],newnodes[Map+1],(Size-Map-1)*SizeOf(THAMTNode64));
FreeMem(oldnodes);
SetSubTrie64(node,newnodes);
end;
// Set up new node
newnodes[Map].BitMapKey:=key;
SetValue64(@newnodes[Map],data);
Exit(GetMutableValue64(@newnodes[Map]));
end;
Map:=GetMapPos64(node^.BitMapKey,keypart);
// Go down a level */
node:=@GetSubTrie64(node)[Map];
keypartbits:=keypartbits+HAMT64.node_bits;
until false;
end;
function HAMT_delete32(hamt:THAMT;key:DWORD):Pointer;
var
prev,node,oldnodes,newnodes:PHAMTNode32;
keypart,Map,Size:DWORD;
keypartbits:DWORD;
begin
if (hamt=nil) then Exit(nil);
keypartbits:=HAMT32.root_bits;
prev:=nil;
Map:=0;
keypart:=key and HAMT32.root_mask;
node:=@PHAMTNode32(hamt)[keypart];
if (node^.BaseValue=nil) then Exit(nil);
repeat
if not IsSubTrie32(node) then
begin
if (node^.BitMapKey=key) then
begin
Result:=GetValue32(node);
node^:=Default(THAMTNode32);
if (prev=nil) then Exit;
node:=prev;
node^.BitMapKey:=UnSetBitInSet32(node^.BitMapKey,keypart);
Size:=GetBitMapSize32(node^.BitMapKey);
oldnodes:=GetSubTrie32(node);
if (Size=1) then
begin
if (Map=0) then
begin
node^:=oldnodes[1];
end else
begin
node^:=oldnodes[0];
end;
FreeMem(oldnodes);
end else
if ((2*Size*SizeOf(THAMTNode32))<=MemSize(oldnodes)) then
begin
newnodes:=AllocMem(Size*SizeOf(THAMTNode32));
Assert((PtrUint(newnodes) and 1)=0);
Move(oldnodes[0] ,newnodes[0] ,Map*SizeOf(THAMTNode32));
Move(oldnodes[Map+1],newnodes[Map],(Size-Map)*SizeOf(THAMTNode32));
FreeMem(oldnodes);
SetSubTrie32(node,newnodes);
end else
begin
Move(oldnodes[Map+1],oldnodes[Map],(Size-Map)*SizeOf(THAMTNode32));
end;
Exit;
end else
Exit(nil);
end;
//Subtree: look up in bitmap
Assert(keypartbits<HAMT32.node_size);
keypart:=(key shr keypartbits) and HAMT32.node_mask;
if BitIsNotSet32(node^.BitMapKey,keypart) then
Exit(nil); // bit is 0 in bitmap -> no match
Map:=GetMapPos32(node^.BitMapKey,keypart);
// Go down a level */
prev:=node;
node:=@GetSubTrie32(node)[Map];
keypartbits:=keypartbits+HAMT32.node_bits;
until false;
end;
function HAMT_delete64(hamt:THAMT;key:QWORD):Pointer;
var
prev,node,oldnodes,newnodes:PHAMTNode64;
keypart,Map,Size:QWORD;
keypartbits:QWORD;
begin
if (hamt=nil) then Exit(nil);
keypartbits:=HAMT64.root_bits;
prev:=nil;
Map:=0;
keypart:=key and HAMT64.root_mask;
node:=@PHAMTNode64(hamt)[keypart];
if (node^.BaseValue=nil) then Exit(nil);
repeat
if not IsSubTrie64(node) then
begin
if (node^.BitMapKey=key) then
begin
Result:=GetValue64(node);
node^:=Default(THAMTNode64);
if (prev=nil) then Exit;
node:=prev;
node^.BitMapKey:=UnSetBitInSet64(node^.BitMapKey,keypart);
Size:=GetBitMapSize64(node^.BitMapKey);
oldnodes:=GetSubTrie64(node);
if (Size=1) then
begin
if (Map=0) then
begin
node^:=oldnodes[1];
end else
begin
node^:=oldnodes[0];
end;
FreeMem(oldnodes);
end else
if ((2*Size*SizeOf(THAMTNode64))<=MemSize(oldnodes)) then
begin
newnodes:=AllocMem(Size*SizeOf(THAMTNode64));
Assert((PtrUint(newnodes) and 1)=0);
Move(oldnodes[0] ,newnodes[0] ,Map*SizeOf(THAMTNode64));
Move(oldnodes[Map+1],newnodes[Map],(Size-Map)*SizeOf(THAMTNode64));
FreeMem(oldnodes);
SetSubTrie64(node,newnodes);
end else
begin
Move(oldnodes[Map+1],oldnodes[Map],(Size-Map)*SizeOf(THAMTNode64));
end;
Exit;
end else
Exit(nil);
end;
//Subtree: look up in bitmap
Assert(keypartbits<HAMT64.node_size);
keypart:=(key shr keypartbits) and HAMT64.node_mask;
if BitIsNotSet64(node^.BitMapKey,keypart) then
Exit(nil); // bit is 0 in bitmap -> no match
Map:=GetMapPos64(node^.BitMapKey,keypart);
// Go down a level */
prev:=node;
node:=@GetSubTrie64(node)[Map];
keypartbits:=keypartbits+HAMT64.node_bits;
until false;
end;
end.

278
libportaudio.pas Normal file
View File

@ -0,0 +1,278 @@
{ Header for libportaudio
Copyright (C) 2021 Red_prig
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version with the following modification:
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent modules,and
to copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the terms
and conditions of the license of that module. An independent module is a
module which is not derived from or based on this library. If you modify
this library, you may extend this exception to your version of the library,
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
for more details.
}
unit libportaudio;
{$mode objfpc}{$H+}
{$PACKRECORDS C}
interface
uses
{$if defined(USE_STATIC_PORTAUDIO) and defined(WINDOWS)}
libaudio_static,
{$ENDIF}
CTypes;
{$ifdef USE_STATIC_PORTAUDIO}
{$Linklib libportaudio.a, static}
{$IFDEF unix}
{$Linklib libasound}
{$Linklib libpthread}
{$Linklib libm}
{$Linklib libc}
{$ENDIF}
{$endif}
Const
{$IFDEF unix}
{$IFDEF darwin}
libname='libportaudio.2.dylib';
{$ELSE}
libname='libportaudio.so.2';
{$ENDIF}
{$ELSE}
libname='libportaudio-2.dll';
{$ENDIF}
type
PaError = CInt32;
PaErrorCode =(
paNotInitialized := -10000,
paUnanticipatedHostError,
paInvalidChannelCount,
paInvalidSampleRate,
paInvalidDevice,
paInvalidFlag,
paSampleFormatNotSupported,
paBadIODeviceCombination,
paInsufficientMemory,
paBufferTooBig,
paBufferTooSmall,
paNullCallback,
paBadStreamPtr,
paTimedOut,
paInternalError,
paDeviceUnavailable,
paIncompatibleHostApiSpecificStreamInfo,
paStreamIsStopped,
paStreamIsNotStopped,
paInputOverflowed,
paOutputUnderflowed,
paHostApiNotFound,
paInvalidHostApi,
paCanNotReadFromACallbackStream,
paCanNotWriteToACallbackStream,
paCanNotReadFromAnOutputOnlyStream,
paCanNotWriteToAnInputOnlyStream,
paIncompatibleStreamHostApi,
paBadBufferPtr,
paNoError := 0
);
PaDeviceIndex = CInt32;
PaHostApiIndex = CInt32;
PaHostApiTypeId =(paInDevelopment := 0,
paDirectSound := 1,
paMME := 2,
paASIO := 3,
paSoundManager := 4,
paCoreAudio := 5,
paOSS := 7,
paALSA := 8,
paAL := 9,
paBeOS := 10,
paWDMKS := 11,
paJACK := 12,
paWASAPI := 13,
paAudioScienceHPI := 14
);
PaHostApiInfo = record
structVersion : CInt32;
_type : PaHostApiTypeId ;
_name : Pchar;
deviceCount : CInt32;
defaultInputDevice : PaDeviceIndex;
defaultOutputDevice : PaDeviceIndex;
end;
PPaHostApiInfo = ^PaHostApiInfo;
PaHostErrorInfo = record
hostApiType : PaHostApiTypeId;
errorCode : CLong;
errorText : PChar;
end;
PPaHostErrorInfo = ^PaHostErrorInfo;
PaTime = CDouble;
PaSampleFormat = pCULongLong;
PaDeviceInfo = record
structVersion : CInt32;
_name : PChar;
hostApi : PaHostApiIndex;
maxInputChannels : CInt32;
maxOutputChannels : CInt32;
defaultLowInputLatency : PaTime;
defaultLowOutputLatency : PaTime;
defaultHighInputLatency : PaTime;
defaultHighOutputLatency : PaTime;
defaultSampleRate : CDouble;
end;
PPaDeviceInfo = ^PaDeviceInfo;
PaStreamParameters = record
device : PaDeviceIndex;
channelCount : CInt32;
sampleFormat : PaSampleFormat;
suggestedLatency : PaTime;
hostApiSpecificStreamInfo : Pointer;
end;
PPaStreamParameters = ^PaStreamParameters;
PaStream = Pointer;
PPaStream = ^PaStream;
PPPaStream = ^PPaStream;
PaStreamFlags = CULong;
PaStreamCallbackTimeInfo = record
inputBufferAdcTime : PaTime;
currentTime : PaTime;
outputBufferDacTime : PaTime;
end;
PaStreamCallbackFlags = CULong;
PaStreamCallbackResult =(
paContinue := 0,
paComplete := 1,
paAbort := 2);
PaStreamCallback = function(
input : Pointer;
output : Pointer;
frameCount : CULong;
timeInfo : PaStreamCallbackTimeInfo;
statusFlags : PaStreamCallbackFlags;
userData : Pointer) : CInt32;
PaStreamFinishedCallback = procedure(userData : Pointer);
PaStreamInfo = record
structVersion : CInt32;
inputLatency : PaTime;
outputLatency : PaTime;
sampleRate : CDouble;
end;
PPaStreamInfo = ^PaStreamInfo;
const
paFormatIsSupported = 0;
paFramesPerBufferUnspecified = 0;
paNoDevice = PaDeviceIndex(-1);
paUseHostApiSpecificDeviceSpecification = PaDeviceIndex(-2);
paFloat32 = PaSampleFormat($00000001);
paInt32 = PaSampleFormat($00000002);
paInt24 = PaSampleFormat($00000004);
paInt16 = PaSampleFormat($00000008);
paInt8 = PaSampleFormat($00000010);
paUInt8 = PaSampleFormat($00000020);
paCustomFormat = PaSampleFormat($00010000);
paNonInterleaved = PaSampleFormat($80000000);
paNoFlag = PaStreamFlags(0);
paClipOff = PaStreamFlags($00000001);
paDitherOff = PaStreamFlags($00000002);
paNeverDropInput = PaStreamFlags($00000004);
paPrimeOutputBuffersUsingStreamCallback = PaStreamFlags($00000008);
paPlatformSpecificFlags = PaStreamFlags($FFFF0000);
paInputUnderflow = PaStreamCallbackFlags($00000001);
paInputOverflow = PaStreamCallbackFlags($00000002);
paOutputUnderflow = PaStreamCallbackFlags($00000004);
paOutputOverflow = PaStreamCallbackFlags($00000008);
paPrimingOutput = PaStreamCallbackFlags($00000010);
function Pa_GetVersion():CInt32 ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_GetVersionText():PChar ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_GetErrorText(errorCode : PaError):PChar ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_Initialize():PaError ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_Terminate():PaError ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_GetHostApiCount():PaHostApiIndex ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_GetDefaultHostApi():PaHostApiIndex ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_GetHostApiInfo(hostApi : PaHostApiIndex):PPaHostApiInfo ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_HostApiTypeIdToHostApiIndex(_type : PaHostApiTypeId):PaHostApiIndex ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_HostApiDeviceIndexToDeviceIndex(hostApi : PaHostApiIndex;hostApiDeviceIndex : CInt32):PaDeviceIndex ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_GetLastHostErrorInfo():PPaHostErrorInfo ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_GetDeviceCount:PaDeviceIndex ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_GetDefaultInputDevice:PaDeviceIndex ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_GetDefaultOutputDevice:PaDeviceIndex ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_GetDeviceInfo(device : PaDeviceIndex):PPaDeviceInfo ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_IsFormatSupported(inputParameters,outputParameters : PPaStreamParameters; sampleRate : CDouble):PaError ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_OpenStream(stream : PPPaStream;
inputParameters : PPaStreamParameters;
outputParameters : PPaStreamParameters;
sampleRate : CDouble;
framesPerBuffer : CULong;
streamFlags : PaStreamFlags;
streamCallback : PaStreamCallback;
userData : Pointer):PaError ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_OpenDefaultStream(stream : PPPaStream;
numInputChannels : CInt32;
numOutputChannels : CInt32;
sampleFormat : PaSampleFormat;
sampleRate : CDouble;
framesPerBuffer : CULong;
streamCallback : PaStreamCallback;
userData : Pointer):PaError ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_CloseStream(stream : PPaStream):PaError ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_SetStreamFinishedCallback(stream : PPaStream;
streamFinishedCallback : PaStreamFinishedCallback):PaError ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_StartStream(stream : PPaStream):PaError ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_StopStream(stream : PPaStream):PaError ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_AbortStream(stream : PPaStream):PaError ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_IsStreamStopped(stream : PPaStream):PaError ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_IsStreamActive(stream : PPaStream):PaError ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_GetStreamInfo(stream : PPaStream):PPaStreamInfo ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_GetStreamTime(stream : PPaStream):Patime ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_GetStreamCpuLoad(stream : PPaStream):CDouble ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_ReadStream(stream : PPaStream; buffer : pcfloat ;frames : CULong):PaError ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_WriteStream(stream : PPaStream; buffer : pcfloat ;frames : CULong):PaError ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_GetStreamReadAvailable(stream : PPaStream):CSLong ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_GetStreamWriteAvailable(stream : PPaStream):CSLong ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_GetSampleSize(format : PaSampleFormat):PaError ; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
function Pa_Sleep(msec : CLong) : integer; cdecl; external {$ifndef USE_STATIC_PORTAUDIO} libname {$endif};
implementation
end.

2407
ps4_elf.pas Normal file

File diff suppressed because it is too large Load Diff

83
ps4_elf_tls.pas Normal file
View File

@ -0,0 +1,83 @@
unit ps4_elf_tls;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils,
Hamt;
type
Pdtv=^Tdtv;
Tdtv=packed record
value:Pointer;
is_static:QWORD;
gen:QWORD;
end;
Ptls_tcb=^Ttls_tcb;
Ttls_tcb=packed record
seg_adr:Pointer;
dtv:Pdtv;
_dtv:Tdtv;
end;
function _init_tls_tcb(Size,is_static,gen:QWORD):Ptls_tcb;
function _get_tls_tcb(gen:QWORD):Ptls_tcb;
procedure _free_tls_tcb_all;
implementation
threadvar
tls_local:THAMT;
function _init_tls_tcb(Size,is_static,gen:QWORD):Ptls_tcb;
var
full_size:QWORD;
base:Pointer;
tcb:Ptls_tcb;
PP:PPointer;
begin
full_size:=Size+SizeOf(Ttls_tcb);
base:=AllocMem(full_size);
tcb:=Pointer(base+Size);
tcb^.seg_adr:=tcb;
tcb^.dtv:=@tcb^._dtv;
tcb^._dtv.value:=base;
tcb^._dtv.is_static:=is_static;
tcb^._dtv.gen:=gen;
if (tls_local=nil) then tls_local:=HAMT_create64;
PP:=HAMT_insert64(tls_local,gen,tcb);
Assert(PP<>nil);
Assert(PP^=tcb);
Result:=tcb;
end;
function _get_tls_tcb(gen:QWORD):Ptls_tcb;
var
PP:PPointer;
begin
Result:=nil;
PP:=HAMT_search64(tls_local,gen);
if (PP<>nil) then Result:=PP^;
end;
procedure _free_tls_tcb(data,userdata:Pointer);
Var
tcb:Ptls_tcb;
base:Pointer;
begin
tcb:=data;
if (tcb=nil) then Exit;
base:=tcb^._dtv.value;
FreeMem(base);
end;
procedure _free_tls_tcb_all;
begin
HAMT_destroy64(tls_local,@_free_tls_tcb,nil);
tls_local:=nil;
end;
end.

190
ps4_handles.pas Normal file
View File

@ -0,0 +1,190 @@
unit ps4_handles;
{$mode objfpc}{$H+}
interface
uses
hamt,
RWLock,
Classes, SysUtils;
type
TClassHandle=class
private
FRef:Pointer;
public
Procedure Acqure;
Procedure Release;
end;
AClassHandle=Array of TClassHandle;
TClassHandleLock=class(TClassHandle)
private
FLock:TRWLock;
public
constructor Create;
destructor Destroy; override;
Procedure Lock;
Procedure UnLock;
end;
TIntegerHandles=class
private
Const
def_min_key=1;
def_max_key=$7FFFFFFF;
var
FStub:TSTUB_HAMT32;
FHAMT:THAMT;
FCount,FPos:Integer;
FLock:TRWLock;
public
min_key,max_key:Integer;
constructor Create;
destructor Destroy; override;
function New(H:TClassHandle;var OutKey:Integer):Boolean;
function Acqure(const Key:Integer):TClassHandle;
function Delete(const Key:Integer):Boolean;
end;
implementation
Procedure TClassHandle.Acqure;
begin
System.InterlockedIncrement(FRef);
end;
Procedure TClassHandle.Release;
begin
if System.InterlockedDecrement(FRef)=nil then
begin
Free;
end;
end;
constructor TClassHandleLock.Create;
begin
inherited;
rwlock_init(FLock);
end;
destructor TClassHandleLock.Destroy;
begin
rwlock_destroy(FLock);
inherited;
end;
Procedure TClassHandleLock.Lock;
begin
rwlock_wrlock(FLock);
end;
Procedure TClassHandleLock.UnLock;
begin
rwlock_unlock(FLock);
end;
constructor TIntegerHandles.Create;
begin
min_key:=def_min_key;
max_key:=def_max_key;
FPos:=def_min_key;
FHAMT:=@FStub;
rwlock_init(FLock);
end;
procedure _free_data_cb(data,userdata:Pointer);
begin
if (data<>nil) then
TClassHandle(data).Release;
end;
destructor TIntegerHandles.Destroy;
begin
HAMT_clear32(FHAMT,@_free_data_cb,nil);
rwlock_destroy(FLock);
inherited;
end;
function TIntegerHandles.New(H:TClassHandle;var OutKey:Integer):Boolean;
Var
i,m:Integer;
data:PPointer;
Label
_data,_exit;
begin
Result:=False;
if (H=nil) then Exit;
rwlock_wrlock(FLock);
m:=(max_key-min_key);
if (FCount>=m+1) then Goto _exit;
if (FPos<min_key) or (FPos>max_key) then FPos:=min_key;
if (FCount=0) then
begin
OutKey:=FPos;
Inc(FPos);
data:=HAMT_insert32(FHAMT,OutKey,Pointer(H));
if (data=nil) then Goto _exit;
if (data^<>Pointer(H)) then Goto _exit;
end else
begin
For i:=0 to m do
begin
OutKey:=FPos;
Inc(FPos);
if (FPos>max_key) then FPos:=min_key;
data:=HAMT_insert32(FHAMT,OutKey,Pointer(H));
if (data=nil) then Goto _exit;
if (data^=Pointer(H)) then Goto _data;
end;
Goto _exit;
end;
_data:
Inc(FCount);
H.Acqure;
H.Acqure;
Result:=True;
_exit:
rwlock_unlock(FLock);
end;
function TIntegerHandles.Acqure(const Key:Integer):TClassHandle;
Var
data:PPointer;
Label
_exit;
begin
Result:=nil;
if (Key<min_key) or (Key>max_key) then Exit;
rwlock_rdlock(FLock);
data:=HAMT_search32(FHAMT,Key);
if (data=nil) then Goto _exit;
Pointer(Result):=data^;
if Assigned(Result) then
begin
Result.Acqure;
end;
_exit:
rwlock_unlock(FLock);
end;
function TIntegerHandles.Delete(const Key:Integer):Boolean;
Var
data:TClassHandle;
begin
Result:=False;
if (Key<min_key) or (Key>max_key) then Exit;
rwlock_wrlock(FLock);
Pointer(data):=HAMT_delete32(FHAMT,Key);
if Assigned(data) then
begin
data.Release;
Dec(FCount);
Result:=True;
end;
rwlock_unlock(FLock);
end;
end.

View File

@ -0,0 +1,259 @@
const
STOP_REASON_SIGHUP =$00000001; //Stop caused by SIGHUP signal.
STOP_REASON_SIGINT =$00000002; //Stop caused by SIGINT signal.
STOP_REASON_SIGQUIT =$00000003; //Stop caused by SIGQUIT signal.
STOP_REASON_SIGILL =$00000004; //Stop caused by SIGILL signal.
STOP_REASON_SIGTRAP =$00000005; //Stop caused by SIGTRAP signal.
STOP_REASON_SIGABRT =$00000006; //Stop caused by SIGABRT signal.
STOP_REASON_SIGEMT =$00000007; //Stop caused by SIGEMT (emulator trap) signal.
STOP_REASON_SIGFPE =$00000008; //Stop caused by SIGFPE signal.
STOP_REASON_SIGKILL =$00000009; //Stop caused by SIGKILL signal.
STOP_REASON_SIGBUS =$0000000A; //Stop caused by SIGBUS signal.
STOP_REASON_SIGSEGV =$0000000B; //Stop caused by SIGSEGV signal.
STOP_REASON_SIGSYS =$0000000C; //Stop caused by SIGSYS signal.
STOP_REASON_SIGPIPE =$0000000D; //Stop caused by SIGPIPE signal.
STOP_REASON_SIGALRM =$0000000E; //Stop caused by SIGALRM signal.
STOP_REASON_SIGTERM =$0000000F; //Stop caused by SIGTERM signal.
STOP_REASON_SIGURG =$00000010; //Stop caused by SIGURG signal.
STOP_REASON_SIGSTOP =$00000011; //Stop caused by SIGSTOP signal.
STOP_REASON_SIGTSTP =$00000012; //Stop caused by SIGTSTP signal.
STOP_REASON_SIGCONT =$00000013; //Stop caused by SIGCONT signal.
STOP_REASON_SIGCHLD =$00000014; //Stop caused by SIGCHLD signal.
STOP_REASON_SIGTTIN =$00000015; //Stop caused by SIGTTIN signal.
STOP_REASON_SIGTTOU =$00000016; //Stop caused by SIGTTOU signal.
STOP_REASON_SIGIO =$00000017; //Stop caused by SIGIO (SIGPOLL) signal.
STOP_REASON_SIGXCPU =$00000018; //Stop caused by SIGXCPU signal.
STOP_REASON_SIGXFSZ =$00000019; //Stop caused by SIGXFSZ signal.
STOP_REASON_SIGVTALRM =$0000001A; //Stop caused by SIGVTALRM signal.
STOP_REASON_SIGPROF =$0000001B; //Stop caused by SIGPROF signal.
STOP_REASON_SIGWINCH =$0000001C; //Stop caused by SIGWINCH signal.
STOP_REASON_SIGINFO =$0000001D; //Stop caused by SIGINFO signal.
STOP_REASON_SIGUSR1 =$0000001E; //Stop caused by SIGUSR1 signal.
STOP_REASON_SIGUSR2 =$0000001F; //Stop caused by SIGUSR2 signal.
STOP_REASON_SIGTHR =$00000020; //Reserved by thread library.
STOP_REASON_SIGNONE =$00000080; //When this reason is used in SceDbgpProcInfo, it means the process is running. When this reason is used in SceDbgpThrInfo, it means the thread is running no matter what the process state is.
STOP_REASON_SIGSUSPEND_PROCESS =$00000081; //Stopped because SCE_DBGP_TYPE_SUSPEND_PROCESS_CMD was received, or the process was spawned with SceDbgpLoadFlags.loadSuspended = 1 and has not been resumed.
STOP_REASON_SIGSUSPEND_THREAD =$00000082; //Stopped because SCE_DBGP_TYPE_SUSPEND_THREAD_CMD was received.
STOP_REASON_SIGSWBRKPT =$00000083; //Stopped due to hitting software breakpoint inserted with SET_SWBRKPT_CMD.
STOP_REASON_DL_STOP_INIT =$00000084; //Stopped due to loading dynamic module for the process when dlStop bit is set.
STOP_REASON_DL_START_UP_FAILED =$00000085; //Error was encountered when preparing to start or on starting a dynamic library.
STOP_REASON_SIGHWBRKPT =$00000086; //Stopped due to hitting hardware breakpoint inserted with SET_HWBRKPT_CMD. Even though hardware breakpoints are not thread specific, only the thread that hit the breakpoint should have this reason.
STOP_REASON_GPU_FAULT_ASYNC =$a0d0c001; //GPU exception was detected.
STOP_REASON_GPU_HP3D_TIMEOUT_ASYNC =$a0d04002; //System software forcibly shutdown the process because of GPU timeout.
STOP_REASON_GPU_SUBMITDONE_TIMEOUT_ASYNC =$a0d04003; //System software forcibly shutdown the process because of submitDone timeout.
STOP_REASON_GPU_BREAK_ASYNC =$a0d0c004; //GPU breakpoint detected.
STOP_REASON_GPU_FAULT_PAGE_FAULT_ASYNC =$a0d0c005; //GPU page fault detected.
STOP_REASON_GPU_FAULT_BAD_OP_CODE_ASYNC =$a0d0c006; //GPU encountered illegal instruction.
STOP_REASON_GPU_FAULT_SUBMITDONE_TIMEOUT_IN_RUN_ASYNC =$a0d0c007; //System software forcibly shutdown the process because of submitDone timeout. GPU was in busy state.
STOP_REASON_GPU_FAULT_SUBMITDONE_TIMEOUT_IN_SUSPEND_ASYNC =$a0d0c008; //System software failed to suspend the process because of submitDone timeout. GPU was in busy state.
STOP_REASON_CPU_FAULT_SUBMITDONE_TIMEOUT_IN_RUN_ASYNC =$a0d0c009; //System software forcibly shutdown the process because of submitDone timeout. GPU was in idle state.
STOP_REASON_CPU_FAULT_SUBMITDONE_TIMEOUT_IN_SUSPEND_ASYNC =$a0d0c00a; //System software failed to suspend the process because of submitDone timeout. GPU was in idle state.
STOP_REASON_GPU_FAULT_IDLE_TIMEOUT_AFTER_SUBMITDONE_ASYNC =$a0d0c00b; //GPU idle timeout after submitDone.
STOP_REASON_LIBC_RETURN_MAIN_SUCCESS =$a0020001; //Returned from main with zero.
STOP_REASON_LIBC_RETURN_MAIN_FAIL =$a0020002; //Returned from main with non-zero.
STOP_REASON_LIBC_EXIT_SUCCESS =$a0020003; //exit is called with zero.
STOP_REASON_LIBC_EXIT_FAIL =$a0020004; //exit is called with non-zero.
STOP_REASON_LIBC__EXIT_SUCCESS =$a0020005; //_Exit is called with zero.
STOP_REASON_LIBC__EXIT_FAIL =$a0020006; //_Exit is called with non-zero.
STOP_REASON_LIBC_ASSERT =$a0020007; //assert is called.
STOP_REASON_LIBC_TERMINATE =$a0020008; //terminate is called.
STOP_REASON_LIBC_UNEXPECTED =$a0020009; //unexpected is called.
STOP_REASON_LIBC_PURE_VIRTUAL =$a002000a; //pure virtual function is called.
STOP_REASON_LIBC_ABORT =$a002000b; //abort is called.
STOP_REASON_LIBC_QUICK_EXIT_SUCCESS =$a002000c; //quick_exit is called with zero.
STOP_REASON_LIBC_QUICK_EXIT_FAIL =$a002000d; //quick_exit is called with non-zero.
STOP_REASON_LIBC_FAILED_TO_CREATE_HEAP =$a002000e; //Failed to create the heap. Please check the value of sceLibcHeapSize.
STOP_REASON_LIBC_FAILED_TO_REPLACE_MALLOC =$a0020010; //Failed to replace malloc. Please check that you defined all necessary functions.
STOP_REASON_LIBC_FAILED_TO_REPLACE_NEW =$a0020011; //Failed to replace new. Please check that you defined all necessary functions.
STOP_REASON_LIBC_FAILED_TO_REPLACE_TLS_MALLOC =$a0020012; //Failed to replace malloc for TLS. Please check that you defined all necessary functions.
STOP_REASON_LIBC_FAILED_TO_MALLOC_INIT =$a0020013; //Failed to initialize malloc.
STOP_REASON_LIBC_FAILED_TO_TLS_MALLOC_INIT =$a0020014; //Failed to initialize malloc for TLS.
STOP_REASON_LIBC_INTERNAL_RETURN_MAIN_SUCCESS =$a0020081; //Returned from main with zero(system).
STOP_REASON_LIBC_INTERNAL_RETURN_MAIN_FAIL =$a0020082; //Returned from main with non-zero(system).
STOP_REASON_LIBC_INTERNAL_EXIT_SUCCESS =$a0020083; //exit is called with zero(system).
STOP_REASON_LIBC_INTERNAL_EXIT_FAIL =$a0020084; //exit is called with non-zero(system).
STOP_REASON_LIBC_INTERNAL__EXIT_SUCCESS =$a0020085; //_Exit is called with zero(system).
STOP_REASON_LIBC_INTERNAL__EXIT_FAIL =$a0020086; //_Exit is called with non-zero(system).
STOP_REASON_LIBC_INTERNAL_ASSERT =$a0020087; //assert is called(system).
STOP_REASON_LIBC_INTERNAL_TERMINATE =$a0020088; //terminate is called(system).
STOP_REASON_LIBC_INTERNAL_UNEXPECTED =$a0020089; //unexpected is called(system).
STOP_REASON_LIBC_INTERNAL_PURE_VIRTUAL =$a002008a; //pure virtual function is called(system).
STOP_REASON_LIBC_INTERNAL_ABORT =$a002008b; //abort is called(system).
STOP_REASON_LIBC_INTERNAL_QUICK_EXIT_SUCCESS =$a002008c; //quick_exit is called with zero(system).
STOP_REASON_LIBC_INTERNAL_QUICK_EXIT_FAIL =$a002008d; //quick_exit is called with non-zero(system).
STOP_REASON_LIBC_INTERNAL_FAILED_TO_CREATE_SYSTEM_MEMORY =$a002008f; //Failed to create the system memory (please report it in devnet).
STOP_REASON_PRX_NOT_RESOLVED_FUNCTION =$a0020101; //Called PRX function was not resolved.
STOP_REASON_PRX_SCE_MODULE_LOAD_ERROR =$a0020102; //Cannot load necessary modules from sce_module.
STOP_REASON_PRX_RUNTIME_ERROR =$a0020103; //An error occured in dynamic library (PRX) runtime.
STOP_REASON_PRX_PROCESS_STARTUP_FAILURE =$a0020104; //System software failed to initialize process environment.
STOP_REASON_SYSTEM_FATAL_LOAD_ERROR =$a0020302; //System software could not start the program.
STOP_REASON_SYSTEM_PTHREAD_RUNTIME_ERROR =$a0020305; //ScePthread runtime detected a fatal runtime error.
STOP_REASON_SYSTEM_INTERNAL_PTHREAD_RUNTIME_ERROR =$a0020306; //ScePthread runtime detected a fatal runtime error(internal).
STOP_REASON_SYSTEM_STACK_CHECK_FAILURE =$a0020307; //System software detected user stack is corrupted.
STOP_REASON_SYSTEM_INTERNAL_STACK_CHECK_FAILURE =$a0020308; //System software detected user stack is corrupted(internal).
STOP_REASON_SYSTEM_UNKNOWN_FATAL_ERROR =$a0020309; //The process was forcibly terminated due to unknown fatal error.
STOP_REASON_SYSTEM_ILLEGAL_FUNCTION_CALL =$a002030a; //The process was terminated with illegal function call.
STOP_REASON_SYSTEM_SCE_BREAK =$a002030b; //The process was terminated with unhandled SCE_BREAK.
STOP_REASON_SYSTEM_SCE_STOP =$a002030c; //The process was terminated with unhandled SCE_STOP.
STOP_REASON_SYSTEM_UNKNOWN_KERNEL_ERROR =$a002030d; //System software forcibly shutdown the process(driver).
STOP_REASON_SYSTEM_EXECUTABLE_ACCESS_ERROR =$a0020311; //Failed to verify executable.
STOP_REASON_KERNEL_ABORT_SYSTEM_ABNORMAL_TERMINATION_REQUEST =$a0020318; //The process terminated with sceSystemServiceReportAbnormalTermination.
STOP_REASON_SYSTEM_INTERNAL_DATA_ACCESS_ERROR =$a0020319; //System software is corrupted.
STOP_REASON_SYSTEM_ILLEGAL_EXCEPTION_CODE =$a002031a; //The process misused a library and was terminated.
STOP_REASON_SYSTEM_INTERNAL_SERVICE_RUNTIME_ERROR =$a002031c; //Failed to request system software service.
STOP_REASON_SYSTEM_DEBUG_RUNTIME_ERROR =$a002031d; //Cannot continue process instrumentation.
STOP_REASON_SYSTEM_INTERNAL_SERVICE_RUNTIME_FATAL =$a002031e; //Failed to request system software service.
STOP_REASON_SYSTEM_INTERNAL_SERVICE_CALL_ERROR =$a002031f; //Failed to request system software service.
STOP_REASON_SYSTEM_INTERNAL_SERVICE_CALL_FATAL =$a0020320; //Failed to request system software service.
STOP_REASON_SYSTEM_PTHREAD_MUTEX_ERROR =$a0020321; //Critical error on pthread mutex.
STOP_REASON_SYSTEM_WRITE_ADDRESS_WRAPAROUND =$a0020323; //System software detected wraparound of write address.
STOP_REASON_SYSTEM_ASAN_FATAL_ASSERT =$a0020325; //The process encountered a fatal ASan error.
STOP_REASON_SYSTEM_BAILOUT_REQUEST =$a0020404; //Terminating system service(s) without crash reporting. (Internal)
STOP_REASON_SYSTEM_BAILOUT_LOW_MEMORY =$a0020405; //Terminating system service(s) without crash reporting. (Internal)
STOP_REASON_SYSTEM_SUSPEND_BLOCK_TIMEOUT_ASYNC =$a0024301; //System software forcibly shutdown the process because of suspend blocker timeout.
STOP_REASON_SYSTEM_UNKNOWN_FATAL_ERROR_ASYNC =$a0024303; //System software forcibly shutdown the process.
STOP_REASON_SYSTEM_USER_DEBUG_REQUEST_ASYNC =$a0024304; //The process received debug termination request.
STOP_REASON_SYSTEM_INTERNAL_SERVICE_TIMEOUT_ASYNC =$a002431b; //Terminating system service(s). (Internal)
STOP_REASON_SYSTEM_SOFTWARE_TIMEOUT_ASYNC =$a0024402; //The process was forcibly terminated with operation timeout.
STOP_REASON_SYSTEM_BAILOUT_GENERIC_ASYNC =$a0024403; //Terminating system service(s) without crash reporting. (Internal)
STOP_REASON_SYSTEM_DEBUGHANDLER_TIMEOUT =$a0028310; //The core dump handler timed out.
STOP_REASON_SYSTEM_DEBUGHANDLER_REJECTED =$a0028316; //Core dump handler was skipped due to application suspend.
STOP_REASON_SYSTEM_TRIGGER_COREDUMP_REQUEST =$a0028322; //The process requested core dump generation.
STOP_REASON_SYSTEM_ASAN_ASSERT =$a0028324; //The process encountered an ASan error.
STOP_REASON_SYSTEM_VM_RUNTIME =$a0028401; //The process was terminated with VM runtime exception.
STOP_REASON_SYSTEM_DUMP_AND_CONTINUE_REQUEST_ASYNC =$a002c315; //The process received core dump request.
STOP_REASON_KERNEL_EXCEPTION_SYSTEM_DEBUG_REQUEST_TIMEOUT_ASYNC=$a002c317; //Debug suspend request was timed out.
function GetStopReasonInfo(dwStopReason:DWORD):RawByteString;
begin
Case dwStopReason of
STOP_REASON_SIGHUP :Result:='Stop caused by SIGHUP signal.';
STOP_REASON_SIGINT :Result:='Stop caused by SIGINT signal.';
STOP_REASON_SIGQUIT :Result:='Stop caused by SIGQUIT signal.';
STOP_REASON_SIGILL :Result:='Stop caused by SIGILL signal.';
STOP_REASON_SIGTRAP :Result:='Stop caused by SIGTRAP signal.';
STOP_REASON_SIGABRT :Result:='Stop caused by SIGABRT signal.';
STOP_REASON_SIGEMT :Result:='Stop caused by SIGEMT (emulator trap) signal.';
STOP_REASON_SIGFPE :Result:='Stop caused by SIGFPE signal.';
STOP_REASON_SIGKILL :Result:='Stop caused by SIGKILL signal.';
STOP_REASON_SIGBUS :Result:='Stop caused by SIGBUS signal.';
STOP_REASON_SIGSEGV :Result:='Stop caused by SIGSEGV signal.';
STOP_REASON_SIGSYS :Result:='Stop caused by SIGSYS signal.';
STOP_REASON_SIGPIPE :Result:='Stop caused by SIGPIPE signal.';
STOP_REASON_SIGALRM :Result:='Stop caused by SIGALRM signal.';
STOP_REASON_SIGTERM :Result:='Stop caused by SIGTERM signal.';
STOP_REASON_SIGURG :Result:='Stop caused by SIGURG signal.';
STOP_REASON_SIGSTOP :Result:='Stop caused by SIGSTOP signal.';
STOP_REASON_SIGTSTP :Result:='Stop caused by SIGTSTP signal.';
STOP_REASON_SIGCONT :Result:='Stop caused by SIGCONT signal.';
STOP_REASON_SIGCHLD :Result:='Stop caused by SIGCHLD signal.';
STOP_REASON_SIGTTIN :Result:='Stop caused by SIGTTIN signal.';
STOP_REASON_SIGTTOU :Result:='Stop caused by SIGTTOU signal.';
STOP_REASON_SIGIO :Result:='Stop caused by SIGIO (SIGPOLL) signal.';
STOP_REASON_SIGXCPU :Result:='Stop caused by SIGXCPU signal.';
STOP_REASON_SIGXFSZ :Result:='Stop caused by SIGXFSZ signal.';
STOP_REASON_SIGVTALRM :Result:='Stop caused by SIGVTALRM signal.';
STOP_REASON_SIGPROF :Result:='Stop caused by SIGPROF signal.';
STOP_REASON_SIGWINCH :Result:='Stop caused by SIGWINCH signal.';
STOP_REASON_SIGINFO :Result:='Stop caused by SIGINFO signal.';
STOP_REASON_SIGUSR1 :Result:='Stop caused by SIGUSR1 signal.';
STOP_REASON_SIGUSR2 :Result:='Stop caused by SIGUSR2 signal.';
STOP_REASON_SIGTHR :Result:='Reserved by thread library.';
STOP_REASON_SIGNONE :Result:='When this reason is used in SceDbgpProcInfo, it means the process is running. When this reason is used in SceDbgpThrInfo, it means the thread is running no matter what the process state is.';
STOP_REASON_SIGSUSPEND_PROCESS :Result:='Stopped because SCE_DBGP_TYPE_SUSPEND_PROCESS_CMD was received, or the process was spawned with SceDbgpLoadFlags.loadSuspended = 1 and has not been resumed.';
STOP_REASON_SIGSUSPEND_THREAD :Result:='Stopped because SCE_DBGP_TYPE_SUSPEND_THREAD_CMD was received.';
STOP_REASON_SIGSWBRKPT :Result:='Stopped due to hitting software breakpoint inserted with SET_SWBRKPT_CMD.';
STOP_REASON_DL_STOP_INIT :Result:='Stopped due to loading dynamic module for the process when dlStop bit is set.';
STOP_REASON_DL_START_UP_FAILED :Result:='Error was encountered when preparing to start or on starting a dynamic library.';
STOP_REASON_SIGHWBRKPT :Result:='Stopped due to hitting hardware breakpoint inserted with SET_HWBRKPT_CMD. Even though hardware breakpoints are not thread specific, only the thread that hit the breakpoint should have this reason.';
STOP_REASON_GPU_FAULT_ASYNC :Result:='GPU exception was detected.';
STOP_REASON_GPU_HP3D_TIMEOUT_ASYNC :Result:='System software forcibly shutdown the process because of GPU timeout.';
STOP_REASON_GPU_SUBMITDONE_TIMEOUT_ASYNC :Result:='System software forcibly shutdown the process because of submitDone timeout.';
STOP_REASON_GPU_BREAK_ASYNC :Result:='GPU breakpoint detected.';
STOP_REASON_GPU_FAULT_PAGE_FAULT_ASYNC :Result:='GPU page fault detected.';
STOP_REASON_GPU_FAULT_BAD_OP_CODE_ASYNC :Result:='GPU encountered illegal instruction.';
STOP_REASON_GPU_FAULT_SUBMITDONE_TIMEOUT_IN_RUN_ASYNC :Result:='System software forcibly shutdown the process because of submitDone timeout. GPU was in busy state.';
STOP_REASON_GPU_FAULT_SUBMITDONE_TIMEOUT_IN_SUSPEND_ASYNC :Result:='System software failed to suspend the process because of submitDone timeout. GPU was in busy state.';
STOP_REASON_CPU_FAULT_SUBMITDONE_TIMEOUT_IN_RUN_ASYNC :Result:='System software forcibly shutdown the process because of submitDone timeout. GPU was in idle state.';
STOP_REASON_CPU_FAULT_SUBMITDONE_TIMEOUT_IN_SUSPEND_ASYNC :Result:='System software failed to suspend the process because of submitDone timeout. GPU was in idle state.';
STOP_REASON_GPU_FAULT_IDLE_TIMEOUT_AFTER_SUBMITDONE_ASYNC :Result:='GPU idle timeout after submitDone.';
STOP_REASON_LIBC_RETURN_MAIN_SUCCESS :Result:='Returned from main with zero.';
STOP_REASON_LIBC_RETURN_MAIN_FAIL :Result:='Returned from main with non-zero.';
STOP_REASON_LIBC_EXIT_SUCCESS :Result:='exit is called with zero.';
STOP_REASON_LIBC_EXIT_FAIL :Result:='exit is called with non-zero.';
STOP_REASON_LIBC__EXIT_SUCCESS :Result:='_Exit is called with zero.';
STOP_REASON_LIBC__EXIT_FAIL :Result:='_Exit is called with non-zero.';
STOP_REASON_LIBC_ASSERT :Result:='assert is called.';
STOP_REASON_LIBC_TERMINATE :Result:='terminate is called.';
STOP_REASON_LIBC_UNEXPECTED :Result:='unexpected is called.';
STOP_REASON_LIBC_PURE_VIRTUAL :Result:='pure virtual function is called.';
STOP_REASON_LIBC_ABORT :Result:='abort is called.';
STOP_REASON_LIBC_QUICK_EXIT_SUCCESS :Result:='quick_exit is called with zero.';
STOP_REASON_LIBC_QUICK_EXIT_FAIL :Result:='quick_exit is called with non-zero.';
STOP_REASON_LIBC_FAILED_TO_CREATE_HEAP :Result:='Failed to create the heap. Please check the value of sceLibcHeapSize.';
STOP_REASON_LIBC_FAILED_TO_REPLACE_MALLOC :Result:='Failed to replace malloc. Please check that you defined all necessary functions.';
STOP_REASON_LIBC_FAILED_TO_REPLACE_NEW :Result:='Failed to replace new. Please check that you defined all necessary functions.';
STOP_REASON_LIBC_FAILED_TO_REPLACE_TLS_MALLOC :Result:='Failed to replace malloc for TLS. Please check that you defined all necessary functions.';
STOP_REASON_LIBC_FAILED_TO_MALLOC_INIT :Result:='Failed to initialize malloc.';
STOP_REASON_LIBC_FAILED_TO_TLS_MALLOC_INIT :Result:='Failed to initialize malloc for TLS.';
STOP_REASON_LIBC_INTERNAL_RETURN_MAIN_SUCCESS :Result:='Returned from main with zero(system).';
STOP_REASON_LIBC_INTERNAL_RETURN_MAIN_FAIL :Result:='Returned from main with non-zero(system).';
STOP_REASON_LIBC_INTERNAL_EXIT_SUCCESS :Result:='exit is called with zero(system).';
STOP_REASON_LIBC_INTERNAL_EXIT_FAIL :Result:='exit is called with non-zero(system).';
STOP_REASON_LIBC_INTERNAL__EXIT_SUCCESS :Result:='_Exit is called with zero(system).';
STOP_REASON_LIBC_INTERNAL__EXIT_FAIL :Result:='_Exit is called with non-zero(system).';
STOP_REASON_LIBC_INTERNAL_ASSERT :Result:='assert is called(system).';
STOP_REASON_LIBC_INTERNAL_TERMINATE :Result:='terminate is called(system).';
STOP_REASON_LIBC_INTERNAL_UNEXPECTED :Result:='unexpected is called(system).';
STOP_REASON_LIBC_INTERNAL_PURE_VIRTUAL :Result:='pure virtual function is called(system).';
STOP_REASON_LIBC_INTERNAL_ABORT :Result:='abort is called(system).';
STOP_REASON_LIBC_INTERNAL_QUICK_EXIT_SUCCESS :Result:='quick_exit is called with zero(system).';
STOP_REASON_LIBC_INTERNAL_QUICK_EXIT_FAIL :Result:='quick_exit is called with non-zero(system).';
STOP_REASON_LIBC_INTERNAL_FAILED_TO_CREATE_SYSTEM_MEMORY :Result:='Failed to create the system memory (please report it in devnet).';
STOP_REASON_PRX_NOT_RESOLVED_FUNCTION :Result:='Called PRX function was not resolved.';
STOP_REASON_PRX_SCE_MODULE_LOAD_ERROR :Result:='Cannot load necessary modules from sce_module.';
STOP_REASON_PRX_RUNTIME_ERROR :Result:='An error occured in dynamic library (PRX) runtime.';
STOP_REASON_PRX_PROCESS_STARTUP_FAILURE :Result:='System software failed to initialize process environment.';
STOP_REASON_SYSTEM_FATAL_LOAD_ERROR :Result:='System software could not start the program.';
STOP_REASON_SYSTEM_PTHREAD_RUNTIME_ERROR :Result:='ScePthread runtime detected a fatal runtime error.';
STOP_REASON_SYSTEM_INTERNAL_PTHREAD_RUNTIME_ERROR :Result:='ScePthread runtime detected a fatal runtime error(internal).';
STOP_REASON_SYSTEM_STACK_CHECK_FAILURE :Result:='System software detected user stack is corrupted.';
STOP_REASON_SYSTEM_INTERNAL_STACK_CHECK_FAILURE :Result:='System software detected user stack is corrupted(internal).';
STOP_REASON_SYSTEM_UNKNOWN_FATAL_ERROR :Result:='The process was forcibly terminated due to unknown fatal error.';
STOP_REASON_SYSTEM_ILLEGAL_FUNCTION_CALL :Result:='The process was terminated with illegal function call.';
STOP_REASON_SYSTEM_SCE_BREAK :Result:='The process was terminated with unhandled SCE_BREAK.';
STOP_REASON_SYSTEM_SCE_STOP :Result:='The process was terminated with unhandled SCE_STOP.';
STOP_REASON_SYSTEM_UNKNOWN_KERNEL_ERROR :Result:='System software forcibly shutdown the process(driver).';
STOP_REASON_SYSTEM_EXECUTABLE_ACCESS_ERROR :Result:='Failed to verify executable.';
STOP_REASON_KERNEL_ABORT_SYSTEM_ABNORMAL_TERMINATION_REQUEST :Result:='The process terminated with sceSystemServiceReportAbnormalTermination.';
STOP_REASON_SYSTEM_INTERNAL_DATA_ACCESS_ERROR :Result:='System software is corrupted.';
STOP_REASON_SYSTEM_ILLEGAL_EXCEPTION_CODE :Result:='The process misused a library and was terminated.';
STOP_REASON_SYSTEM_INTERNAL_SERVICE_RUNTIME_ERROR :Result:='Failed to request system software service.';
STOP_REASON_SYSTEM_DEBUG_RUNTIME_ERROR :Result:='Cannot continue process instrumentation.';
STOP_REASON_SYSTEM_INTERNAL_SERVICE_RUNTIME_FATAL :Result:='Failed to request system software service.';
STOP_REASON_SYSTEM_INTERNAL_SERVICE_CALL_ERROR :Result:='Failed to request system software service.';
STOP_REASON_SYSTEM_INTERNAL_SERVICE_CALL_FATAL :Result:='Failed to request system software service.';
STOP_REASON_SYSTEM_PTHREAD_MUTEX_ERROR :Result:='Critical error on pthread mutex.';
STOP_REASON_SYSTEM_WRITE_ADDRESS_WRAPAROUND :Result:='System software detected wraparound of write address.';
STOP_REASON_SYSTEM_ASAN_FATAL_ASSERT :Result:='The process encountered a fatal ASan error.';
STOP_REASON_SYSTEM_BAILOUT_REQUEST :Result:='Terminating system service(s) without crash reporting. (Internal)';
STOP_REASON_SYSTEM_BAILOUT_LOW_MEMORY :Result:='Terminating system service(s) without crash reporting. (Internal)';
STOP_REASON_SYSTEM_SUSPEND_BLOCK_TIMEOUT_ASYNC :Result:='System software forcibly shutdown the process because of suspend blocker timeout.';
STOP_REASON_SYSTEM_UNKNOWN_FATAL_ERROR_ASYNC :Result:='System software forcibly shutdown the process.';
STOP_REASON_SYSTEM_USER_DEBUG_REQUEST_ASYNC :Result:='The process received debug termination request.';
STOP_REASON_SYSTEM_INTERNAL_SERVICE_TIMEOUT_ASYNC :Result:='Terminating system service(s). (Internal)';
STOP_REASON_SYSTEM_SOFTWARE_TIMEOUT_ASYNC :Result:='The process was forcibly terminated with operation timeout.';
STOP_REASON_SYSTEM_BAILOUT_GENERIC_ASYNC :Result:='Terminating system service(s) without crash reporting. (Internal)';
STOP_REASON_SYSTEM_DEBUGHANDLER_TIMEOUT :Result:='The core dump handler timed out.';
STOP_REASON_SYSTEM_DEBUGHANDLER_REJECTED :Result:='Core dump handler was skipped due to application suspend.';
STOP_REASON_SYSTEM_TRIGGER_COREDUMP_REQUEST :Result:='The process requested core dump generation.';
STOP_REASON_SYSTEM_ASAN_ASSERT :Result:='The process encountered an ASan error.';
STOP_REASON_SYSTEM_VM_RUNTIME :Result:='The process was terminated with VM runtime exception.';
STOP_REASON_SYSTEM_DUMP_AND_CONTINUE_REQUEST_ASYNC :Result:='The process received core dump request.';
STOP_REASON_KERNEL_EXCEPTION_SYSTEM_DEBUG_REQUEST_TIMEOUT_ASYNC:Result:='Debug suspend request was timed out.';
else
Result:='';
end;
end;

183
ps4_libkerenel/errno.inc Normal file
View File

@ -0,0 +1,183 @@
const
EPERM =1 ;// Operation not permitted */
ENOENT =2 ;// No such file or directory */
ESRCH =3 ;// No such process */
EINTR =4 ;// Interrupted system call */
EIO =5 ;// Input/output error */
ENXIO =6 ;// Device not configured */
E2BIG =7 ;// Argument list too long */
ENOEXEC =8 ;// Exec format error */
EBADF =9 ;// Bad file descriptor */
ECHILD =10 ;// No child processes */
EDEADLK =11 ;// Resource deadlock avoided */
// 11 was EAGAIN */
ENOMEM =12 ;// Cannot allocate memory */
EACCES =13 ;// Permission denied */
EFAULT =14 ;// Bad address */
ENOTBLK =15 ;// Block device required */
EBUSY =16 ;// Device busy */
EEXIST =17 ;// File exists */
EXDEV =18 ;// Cross-device link */
ENODEV =19 ;// Operation not supported by device */
ENOTDIR =20 ;// Not a directory */
EISDIR =21 ;// Is a directory */
EINVAL =22 ;// Invalid argument */
ENFILE =23 ;// Too many open files in system */
EMFILE =24 ;// Too many open files */
ENOTTY =25 ;// Inappropriate ioctl for device */
ETXTBSY =26 ;// Text file busy */
EFBIG =27 ;// File too large */
ENOSPC =28 ;// No space left on device */
ESPIPE =29 ;// Illegal seek */
EROFS =30 ;// Read-only filesystem */
EMLINK =31 ;// Too many links */
EPIPE =32 ;// Broken pipe */
// math software
EDOM =33 ;// Numerical argument out of domain */
ERANGE =34 ;// Result too large */
// non-blocking and interrupt i/o
EAGAIN =35 ;// Resource temporarily unavailable */
EWOULDBLOCK =EAGAIN ;// Operation would block */
EINPROGRESS =36 ;// Operation now in progress */
EALREADY =37 ;// Operation already in progress */
// ipc/network software -- argument errors
ENOTSOCK =38 ;// Socket operation on non-socket */
EDESTADDRREQ =39 ;// Destination address required */
EMSGSIZE =40 ;// Message too long */
EPROTOTYPE =41 ;// Protocol wrong type for socket */
ENOPROTOOPT =42 ;// Protocol not available */
EPROTONOSUPPORT =43 ;// Protocol not supported */
ESOCKTNOSUPPORT =44 ;// Socket type not supported */
EOPNOTSUPP =45 ;// Operation not supported */
ENOTSUP =EOPNOTSUPP ;// Operation not supported */
EPFNOSUPPORT =46 ;// Protocol family not supported */
EAFNOSUPPORT =47 ;// Address family not supported by protocol family */
EADDRINUSE =48 ;// Address already in use */
EADDRNOTAVAIL =49 ;// Can't assign requested address */
// ipc/network software -- operational errors
ENETDOWN =50 ;// Network is down */
ENETUNREACH =51 ;// Network is unreachable */
ENETRESET =52 ;// Network dropped connection on reset */
ECONNABORTED =53 ;// Software caused connection abort */
ECONNRESET =54 ;// Connection reset by peer */
ENOBUFS =55 ;// No buffer space available */
EISCONN =56 ;// Socket is already connected */
ENOTCONN =57 ;// Socket is not connected */
ESHUTDOWN =58 ;// Can't send after socket shutdown */
ETOOMANYREFS =59 ;// Too many references: can't splice */
ETIMEDOUT =60 ;// Operation timed out */
ECONNREFUSED =61 ;// Connection refused */
ELOOP =62 ;// Too many levels of symbolic links */
ENAMETOOLONG =63 ;// File name too long */
// should be rearranged
EHOSTDOWN =64 ;// Host is down */
EHOSTUNREACH =65 ;// No route to host */
ENOTEMPTY =66 ;// Directory not empty */
// quotas & mush */
EPROCLIM =67 ;// Too many processes */
EUSERS =68 ;// Too many users */
EDQUOT =69 ;// Disc quota exceeded */
// Network File System */
ESTALE =70 ;// Stale NFS file handle */
EREMOTE =71 ;// Too many levels of remote in path */
EBADRPC =72 ;// RPC struct is bad */
ERPCMISMATCH =73 ;// RPC version wrong */
EPROGUNAVAIL =74 ;// RPC prog. not avail */
EPROGMISMATCH =75 ;// Program version wrong */
EPROCUNAVAIL =76 ;// Bad procedure for program */
ENOLCK =77 ;// No locks available */
ENOSYS =78 ;// Function not implemented */
EFTYPE =79 ;// Inappropriate file type or format */
EAUTH =80 ;// Authentication error */
ENEEDAUTH =81 ;// Need authenticator */
EIDRM =82 ;// Identifier removed */
ENOMSG =83 ;// No message of desired type */
EOVERFLOW =84 ;// Value too large to be stored in data type */
ECANCELED =85 ;// Operation canceled */
EILSEQ =86 ;// Illegal byte sequence */
ENOATTR =87 ;// Attribute not found */
EDOOFUS =88 ;// Programming error */
EBADMSG =89 ;// Bad message */
EMULTIHOP =90 ;// Multihop attempted */
ENOLINK =91 ;// Link has been severed */
EPROTO =92 ;// Protocol error */
ENOTCAPABLE =93 ;// Capabilities insufficient */
ECAPMODE =94 ;// Not permitted in capability mode */
ENOBLK =95;
EICV =96;
ENOPLAYGOENT =97;
EREVOKE =98;
ESDKVERSION =99;
ESTART =100 ;// module_start() fails */
ESTOP =101 ;// module_stop() fails */
ELAST =101 ;// Must be equal largest errno */
EADHOC =160 ;// adhoc mode */
// 161 reserved */
// 162 reserved */
EINACTIVEDISABLED =163 ;// IP address was changed */
ENETNODATA =164 ;// internal code */
ENETDESC =165 ;// internal code */
ENETDESCTIMEDOUT =166 ;// internal code */
ENETINTR =167 ;// network abort */
// 168 reserved */
// 169 reserved */
ERETURN =205 ;// libnetctl error */
// Dinkumware */
// ERROR CODES */
EFPOS =$0098;
// POSIX SUPPLEMENT */
ENODATA=1040;
ENOSR=1050;
ENOSTR=1051; // ENOSTR */
ENOTRECOVERABLE=1056; // ENOTRECOVERABLE */
EOTHER=1062;// EOTHER */
EOWNERDEAD=1064;// EOWNERDEAD */
ETIME=1074;// ETIME */
// pseudo-errors returned inside kernel to modify return to process */
ERESTART =(-1) ;// restart syscall */
EJUSTRETURN =(-2) ;// don't modify regs, just return */
ENOIOCTL =(-3) ;// ioctl not handled by this layer */
EDIRIOCTL =(-4) ;// do direct ioctl in GEOM */

588
ps4_libkerenel/ps4_cond.pas Normal file
View File

@ -0,0 +1,588 @@
unit ps4_cond;
{$mode objfpc}{$H+}
interface
uses
Windows,
ps4_mutex,
ps4_types;
type
Ppthread_condattr=^pthread_condattr_t;
pthread_condattr_t=bitpacked record
_shared:0..1; //1
_clock:0..31; //5
_align:0..67108863; //26
_align2:Integer; //32
end;
Ppthread_cond=^pthread_cond;
pthread_cond=^pthread_cond_t;
pthread_cond_t=record
valid:DWORD;
busy :DWORD;
waiters_count_:DWORD;
waiters_count_unblock_:DWORD;
waiters_count_gone_:DWORD;
value_q:Integer;
value_b:Integer;
waiters_count_lock_:TRTLCriticalSection;
waiters_q_lock_:TRTLCriticalSection;
waiters_b_lock_:TRTLCriticalSection;
sema_q:THandle;
sema_b:THandle;
name:array[0..31] of AnsiChar;
end;
PScePthreadCond=Ppthread_cond;
Const
PTHREAD_COND_INITIALIZER=nil;
function ps4_pthread_condattr_init(pAttr:Ppthread_condattr):Integer; SysV_ABI_CDecl;
function ps4_pthread_condattr_destroy(pAttr:Ppthread_condattr):Integer; SysV_ABI_CDecl;
function ps4_pthread_condattr_getclock(pAttr:Ppthread_condattr;t:PInteger):Integer; SysV_ABI_CDecl;
function ps4_pthread_condattr_setclock(pAttr:Ppthread_condattr;t:Integer):Integer; SysV_ABI_CDecl;
function ps4_pthread_condattr_getpshared(pAttr:Ppthread_condattr;t:PInteger):Integer; SysV_ABI_CDecl;
function ps4_pthread_condattr_setpshared(pAttr:Ppthread_condattr;t:Integer):Integer; SysV_ABI_CDecl;
function ps4_pthread_cond_init(pCond:Ppthread_cond;pAttr:Ppthread_condattr):Integer; SysV_ABI_CDecl;
function ps4_pthread_cond_destroy(pCond:Ppthread_cond):Integer; SysV_ABI_CDecl;
function ps4_pthread_cond_signal(pCond:Ppthread_cond):Integer; SysV_ABI_CDecl;
function ps4_pthread_cond_broadcast(pCond:Ppthread_cond):Integer; SysV_ABI_CDecl;
function ps4_pthread_cond_wait(pCond:Ppthread_cond;pMutex:Ppthread_mutex):Integer; SysV_ABI_CDecl;
function ps4_pthread_cond_timedwait(pCond:Ppthread_cond;pMutex:Ppthread_mutex;ptime:Ptimespec):Integer; SysV_ABI_CDecl;
function ps4_scePthreadCondattrInit(pAttr:Ppthread_condattr):Integer; SysV_ABI_CDecl;
function ps4_scePthreadCondattrDestroy(pAttr:Ppthread_condattr):Integer; SysV_ABI_CDecl;
function ps4_scePthreadCondInit(pCond:PScePthreadCond;pAttr:Ppthread_condattr;name:Pchar):Integer; SysV_ABI_CDecl;
function ps4_scePthreadCondDestroy(pCond:PScePthreadCond):Integer; SysV_ABI_CDecl;
function ps4_scePthreadCondSignal(pCond:PScePthreadCond):Integer; SysV_ABI_CDecl;
function ps4_scePthreadCondWait(pCond:PScePthreadCond;pMutex:PScePthreadMutex):Integer; SysV_ABI_CDecl;
function ps4_scePthreadCondTimedwait(pCond:PScePthreadCond;pMutex:PScePthreadMutex;usec:DWORD):Integer; SysV_ABI_CDecl;
function ps4_scePthreadCondBroadcast(pCond:PScePthreadCond):Integer; SysV_ABI_CDecl;
implementation
Uses
spinlock,
ps4_sema,
ps4_libkernel,
ps4_time;
function ps4_pthread_condattr_init(pAttr:Ppthread_condattr):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(EINVAL);
pAttr^:=Default(pthread_condattr_t);
Result:=0;
end;
function ps4_pthread_condattr_destroy(pAttr:Ppthread_condattr):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(EINVAL);
pAttr^:=Default(pthread_condattr_t);
Result:=0;
end;
function ps4_pthread_condattr_getclock(pAttr:Ppthread_condattr;t:PInteger):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) or (t=nil) then Exit(EINVAL);
t^:=pAttr^._clock;
Result:=0;
end;
function ps4_pthread_condattr_setclock(pAttr:Ppthread_condattr;t:Integer):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(EINVAL);
Case t of
CLOCK_REALTIME :;
CLOCK_VIRTUAL :;
CLOCK_PROF :;
CLOCK_MONOTONIC :;
CLOCK_UPTIME :;
CLOCK_UPTIME_PRECISE :;
CLOCK_UPTIME_FAST :;
CLOCK_REALTIME_PRECISE :;
CLOCK_REALTIME_FAST :;
CLOCK_MONOTONIC_PRECISE:;
CLOCK_MONOTONIC_FAST :;
CLOCK_SECOND :;
CLOCK_THREAD_CPUTIME_ID:;
CLOCK_PROCTIME :;
CLOCK_EXT_NETWORK :;
CLOCK_EXT_DEBUG_NETWORK:;
CLOCK_EXT_AD_NETWORK :;
CLOCK_EXT_RAW_NETWORK :;
else
Exit(EINVAL);
end;
pAttr^._clock:=t;
Result:=0;
end;
function ps4_pthread_condattr_getpshared(pAttr:Ppthread_condattr;t:PInteger):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) or (t=nil) then Exit(EINVAL);
t^:=pAttr^._shared;
Result:=0;
end;
function ps4_pthread_condattr_setpshared(pAttr:Ppthread_condattr;t:Integer):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(EINVAL);
Case t of
PTHREAD_PROCESS_PRIVATE:;
PTHREAD_PROCESS_SHARED :;
else
Exit(EINVAL);
end;
pAttr^._shared:=t;
Result:=0;
end;
Const
LIFE_COND=$C0BAB1FD;
DEAD_COND=$C0DEADBF;
{type
sCondWaitHelper=record
c:pthread_cond;
external_mutex:pthread_mutex;
r:Pinteger;
end;}
var
cond_locked:Pointer=nil;
function STATIC_COND_INITIALIZER(x:Ppthread_cond):Boolean; inline;
begin
Result:=(x^=PTHREAD_COND_INITIALIZER);
end;
function pthread_cond_init(c:Ppthread_cond;a:Ppthread_condattr;str:PChar):Integer;
var
_c:pthread_cond;
begin
if (c=nil) then Exit(EINVAL);
_c:=AllocMem(SizeOf(pthread_cond_t));
if (_c=nil) then Exit(ENOMEM);
_c^.valid:=DEAD_COND;
_c^.sema_q:=CreateSemaphore(nil,0,$7fffffff,nil);
if (_c^.sema_q=0) then
begin
FreeMem(_c);
c^:=nil;
Exit(EAGAIN);
end;
_c^.sema_b:=CreateSemaphore(nil,0,$7fffffff,nil);
if (_c^.sema_b=0) then
begin
CloseHandle(_c^.sema_q);
FreeMem(_c);
c^:=nil;
Exit(EAGAIN);
end;
System.InitCriticalSection(_c^.waiters_count_lock_);
System.InitCriticalSection(_c^.waiters_b_lock_);
System.InitCriticalSection(_c^.waiters_q_lock_);
_c^.value_q:=0;
_c^.value_b:=1;
_c^.valid:=LIFE_COND;
if (str<>nil) then MoveChar0(str^,_c^.name,32);
c^:=_c;
Result:=0;
end;
function cond_static_init(c:Ppthread_cond):Integer;
var
r:Integer;
begin
r:=0;
spin_lock(cond_locked);
if (c=nil) then Exit(EINVAL);
if STATIC_COND_INITIALIZER(c) then
begin
r:=pthread_cond_init(c,nil,nil);
end;
spin_unlock(cond_locked);
Result:=r;
end;
function ps4_pthread_cond_init(pCond:Ppthread_cond;pAttr:Ppthread_condattr):Integer; SysV_ABI_CDecl;
begin
Result:=pthread_cond_init(pCond,pAttr,nil);
end;
function ps4_pthread_cond_destroy(pCond:Ppthread_cond):Integer; SysV_ABI_CDecl;
var
r:Integer;
_c:pthread_cond;
begin
if (pCond=nil) then Exit(EINVAL);
if STATIC_COND_INITIALIZER(pCond) then
begin
spin_lock(cond_locked);
if STATIC_COND_INITIALIZER(pCond) then
begin
r:=0;
end else
begin
r:=EBUSY;
end;
spin_unlock(cond_locked);
Exit(r);
end;
_c:=pCond^;
r:=do_sema_b_wait(_c^.sema_b,INFINITE,_c^.waiters_b_lock_,_c^.value_b);
if (r<>0) then Exit(r);
if (System.TryEnterCriticalSection(_c^.waiters_count_lock_)=0) then
begin
do_sema_b_release(_c^.sema_b,1,_c^.waiters_b_lock_,_c^.value_b);
Exit(EBUSY);
end;
if (_c^.waiters_count_ > _c^.waiters_count_gone_) then
begin
r:=do_sema_b_release(_c^.sema_b, 1,_c^.waiters_b_lock_,_c^.value_b);
if (r=0) then r:=EBUSY;
System.LeaveCriticalSection(_c^.waiters_count_lock_);
Exit(r);
end;
pCond^:=nil;
do_sema_b_release(_c^.sema_b,1,_c^.waiters_b_lock_,_c^.value_b);
if (not CloseHandle(_c^.sema_q)) and (r=0) then r:=EINVAL;
if (not CloseHandle(_c^.sema_b)) and (r=0) then r:=EINVAL;
System.LeaveCriticalSection (_c^.waiters_count_lock_);
System.DoneCriticalSection(_c^.waiters_count_lock_);
System.DoneCriticalSection(_c^.waiters_b_lock_);
System.DoneCriticalSection(_c^.waiters_q_lock_);
_c^.valid:=DEAD_COND;
FreeMem(_c);
Result:=0;
end;
function ps4_pthread_cond_signal(pCond:Ppthread_cond):Integer; SysV_ABI_CDecl;
var
r:Integer;
_c:pthread_cond;
begin
if (pCond=nil) then Exit(EINVAL);
_c:=pCond^;
if (_c=PTHREAD_COND_INITIALIZER) then
Exit(0)
else
if (_c^.valid<>LIFE_COND) then
Exit(EINVAL);
System.EnterCriticalSection(_c^.waiters_count_lock_);
//mingw implement is wrong
if true {(_c^.waiters_count_unblock_<>0)} then
begin
if (_c^.waiters_count_=0) then
begin
System.LeaveCriticalSection(_c^.waiters_count_lock_);
Exit(0);
end;
Dec(_c^.waiters_count_);
Inc(_c^.waiters_count_unblock_);
end else
if false {(_c^.waiters_count_>_c^.waiters_count_gone_)} then
begin
r:=do_sema_b_wait(_c^.sema_b,INFINITE,_c^.waiters_b_lock_,_c^.value_b);
if (r<>0) then
begin
//r:=do_sema_b_release (_c^.sema_b,1,_c^.waiters_b_lock_,_c^.value_b);
System.LeaveCriticalSection (_c^.waiters_count_lock_);
Exit(r);
end;
if (_c^.waiters_count_gone_<>0) then
begin
Dec(_c^.waiters_count_,_c^.waiters_count_gone_);
_c^.waiters_count_gone_:=0;
end;
Dec(_c^.waiters_count_);
_c^.waiters_count_unblock_:=1;
//System.LeaveCriticalSection(_c^.waiters_count_lock_);
//r:=do_sema_b_release (_c^.sema_b,1,_c^.waiters_b_lock_,_c^.value_b);
end else
begin
System.LeaveCriticalSection(_c^.waiters_count_lock_);
Exit(0);
end;
System.LeaveCriticalSection(_c^.waiters_count_lock_);
Result:=do_sema_b_release(_c^.sema_q,1,_c^.waiters_q_lock_,_c^.value_q);
end;
function ps4_pthread_cond_broadcast(pCond:Ppthread_cond):Integer; SysV_ABI_CDecl;
var
r,relCnt:Integer;
_c:pthread_cond;
begin
if (pCond=nil) then Exit(EINVAL);
relCnt:=0;
_c:=pCond^;
if (_c=PTHREAD_COND_INITIALIZER) then
Exit(0)
else
if (_c^.valid<>LIFE_COND) then
Exit(EINVAL);
System.EnterCriticalSection(_c^.waiters_count_lock_);
//mingw implement is wrong
if true {(_c^.waiters_count_unblock_<>0)} then
begin
if (_c^.waiters_count_=0) then
begin
System.LeaveCriticalSection (_c^.waiters_count_lock_);
Exit(0);
end;
relCnt:=_c^.waiters_count_;
_c^.waiters_count_:=0;
Inc(_c^.waiters_count_unblock_,relCnt);
end else
if false {(_c^.waiters_count_>_c^.waiters_count_gone_)} then
begin
r:=do_sema_b_wait(_c^.sema_b,INFINITE,_c^.waiters_b_lock_,_c^.value_b);
if (r<>0) then
begin
//r:=do_sema_b_release (_c^.sema_b,1,_c^.waiters_b_lock_,_c^.value_b);
System.LeaveCriticalSection(_c^.waiters_count_lock_);
Exit(r);
end;
if (_c^.waiters_count_gone_<>0) then
begin
Dec(_c^.waiters_count_,_c^.waiters_count_gone_);
_c^.waiters_count_gone_:=0;
end;
relCnt:=_c^.waiters_count_;
_c^.waiters_count_:=0;
_c^.waiters_count_unblock_:=relCnt;
//System.LeaveCriticalSection(_c^.waiters_count_lock_);
//r:=do_sema_b_release (_c^.sema_b,1,_c^.waiters_b_lock_,_c^.value_b);
end else
begin
System.LeaveCriticalSection(_c^.waiters_count_lock_);
Exit(0);
end;
LeaveCriticalSection(_c^.waiters_count_lock_);
Result:=do_sema_b_release(_c^.sema_q,relCnt,_c^.waiters_q_lock_,_c^.value_q);
end;
function ps4_pthread_cond_wait(pCond:Ppthread_cond;pMutex:Ppthread_mutex):Integer; SysV_ABI_CDecl;
var
//ch:sCondWaitHelper;
r:Integer;
_c:pthread_cond;
Label
tryagain;
begin
if (pCond=nil) then Exit(EINVAL);
_c:=pCond^;
if (_c=PTHREAD_COND_INITIALIZER) then
begin
r:=cond_static_init(pCond);
if (r<>0) and (r<>EBUSY) then Exit(r);
_c:=pCond^;
end else
if (_c^.valid<>LIFE_COND) then
Exit(EINVAL);
tryagain:
r:=do_sema_b_wait(_c^.sema_b,INFINITE,_c^.waiters_b_lock_,_c^.value_b);
if (r<>0) then Exit(r);
if (System.TryEnterCriticalSection(_c^.waiters_count_lock_)=0) then
begin
r:=do_sema_b_release(_c^.sema_b,1,_c^.waiters_b_lock_,_c^.value_b);
if (r<>0) then Exit(r);
System.ThreadSwitch;
goto tryagain;
end;
Inc(_c^.waiters_count_);
LeaveCriticalSection(_c^.waiters_count_lock_);
r:=do_sema_b_release (_c^.sema_b,1,_c^.waiters_b_lock_,_c^.value_b);
if (r<>0) then Exit(r);
//ch.c = _c;
//ch.r = &r;
//ch.external_mutex = external_mutex;
//pthread_cleanup_push(cleanup_wait, (void *) &ch);
r:=ps4_pthread_mutex_unlock(pMutex);
//Writeln('ps4_pthread_mutex_unlock:',HexStr(pMutex),':',HexStr(r,8));
if (r=0) then
begin
r:=do_sema_b_wait(_c^.sema_q,INFINITE,_c^.waiters_q_lock_,_c^.value_q);
end;
ps4_pthread_mutex_lock(pMutex); //WHY IT NO IN MINGW
//pthread_cleanup_pop(1);
Result:=r;
end;
function pthread_cond_timedwait_impl(c:Ppthread_cond;m:Ppthread_mutex;t:DWORD):Integer;
var
//ch:sCondWaitHelper;
r:Integer;
_c:pthread_cond;
Label
tryagain;
begin
if (c=nil) then Exit(EINVAL);
_c:=c^;
if (_c=PTHREAD_COND_INITIALIZER) then
begin
r:=cond_static_init(c);
if (r<>0) and (r<>EBUSY) then Exit(r);
_c:=c^;
end else
if (_c^.valid<>LIFE_COND) then
Exit(EINVAL);
tryagain:
r:=do_sema_b_wait(_c^.sema_b,INFINITE,_c^.waiters_b_lock_,_c^.value_b);
if (r<>0) then Exit(r);
if (System.TryEnterCriticalSection(_c^.waiters_count_lock_)=0) then
begin
r:=do_sema_b_release(_c^.sema_b,1,_c^.waiters_b_lock_,_c^.value_b);
if (r<>0) then Exit(r);
System.ThreadSwitch;
goto tryagain;
end;
Inc(_c^.waiters_count_);
System.LeaveCriticalSection(_c^.waiters_count_lock_);
r:=do_sema_b_release(_c^.sema_b,1,_c^.waiters_b_lock_,_c^.value_b);
if (r<>0) then Exit(r);
//ch.c = _c;
//ch.r = &r;
//ch.external_mutex = external_mutex;
//pthread_cleanup_push(cleanup_wait, (void *) &ch);
r:=ps4_pthread_mutex_unlock(m);
//Writeln('ps4_pthread_mutex_unlock:',HexStr(m),':',HexStr(r,8));
if (r=0) then
begin
r:=do_sema_b_wait(_c^.sema_q,t,_c^.waiters_q_lock_,_c^.value_q);
end;
ps4_pthread_mutex_lock(m); //WHY IT NO IN MINGW
//pthread_cleanup_pop(1);
Result:=r;
end;
function ps4_pthread_cond_timedwait(pCond:Ppthread_cond;pMutex:Ppthread_mutex;ptime:Ptimespec):Integer; SysV_ABI_CDecl;
var
t:DWORD;
begin
if (ptime=nil) then
begin
Result:=ps4_pthread_cond_wait(pCond,pMutex);
end else
begin
t:=dwMilliSecs(_pthread_rel_time_in_ms(ptime^));
Result:=pthread_cond_timedwait_impl(pCond,pMutex,t);
end;
end;
///////////////////////
function ps4_scePthreadCondattrInit(pAttr:Ppthread_condattr):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
pAttr^:=Default(pthread_condattr_t);
Result:=0;
end;
function ps4_scePthreadCondattrDestroy(pAttr:Ppthread_condattr):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
pAttr^:=Default(pthread_condattr_t);
Result:=0;
end;
function ps4_scePthreadCondInit(pCond:PScePthreadCond;pAttr:Ppthread_condattr;name:Pchar):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(pthread_cond_init(pCond,pAttr,name));
end;
function ps4_scePthreadCondDestroy(pCond:PScePthreadCond):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(ps4_pthread_cond_destroy(pCond));
end;
function ps4_scePthreadCondSignal(pCond:PScePthreadCond):Integer; SysV_ABI_CDecl;
begin
//Writeln('>scePthreadCondSignal:',HexStr(pCond));
Result:=px2sce(ps4_pthread_cond_signal(pCond));
//Writeln('<scePthreadCondSignal:',HexStr(pCond),':',HexStr(Result,8));
end;
function ps4_scePthreadCondWait(pCond:PScePthreadCond;pMutex:PScePthreadMutex):Integer; SysV_ABI_CDecl;
begin
//Writeln('>scePthreadCondWait:',HexStr(pCond),':',HexStr(pMutex));
Result:=px2sce(ps4_pthread_cond_wait(pCond,pMutex));
//Writeln('<scePthreadCondWait:',HexStr(pCond),':',HexStr(pMutex),':',HexStr(Result,8));
//Result:=0;
end;
//Time to wait (microseconds)
function ps4_scePthreadCondTimedwait(pCond:PScePthreadCond;pMutex:PScePthreadMutex;usec:DWORD):Integer; SysV_ABI_CDecl;
begin
//Writeln('>scePthreadCondTimedwait:',HexStr(pCond),':',HexStr(pMutex));
Result:=px2sce(pthread_cond_timedwait_impl(pCond,pMutex,_usec2msec(usec)));
//if Result=SCE_KERNEL_ERROR_ETIMEDOUT then Writeln('SCE_KERNEL_ERROR_ETIMEDOUT');
end;
function ps4_scePthreadCondBroadcast(pCond:PScePthreadCond):Integer; SysV_ABI_CDecl;
begin
//Writeln('>scePthreadCondBroadcast:',HexStr(pCond));
Result:=px2sce(ps4_pthread_cond_broadcast(pCond));
//Writeln('<scePthreadCondBroadcast:',HexStr(pCond),':',HexStr(Result,8));
end;
end.

View File

@ -0,0 +1,539 @@
unit ps4_kernel_file;
{$mode objfpc}{$H+}
interface
uses
windows,
ps4_types,
ps4_program,
Classes, SysUtils;
const
NAME_MAX =255; // max bytes in a file name
PATH_MAX =1024; // max bytes in pathname
IOV_MAX =1024; // max elements in i/o vector
MAXNAMLEN =255;
O_RDONLY =$0000; // open for reading only
O_WRONLY =$0001; // open for writing only
O_RDWR =$0002; // open for reading and writing
O_ACCMODE =$0003; // mask for above modes
O_NONBLOCK =$0004; // no delay
O_APPEND =$0008; // set append mode
O_SYNC =$0080; // POSIX synonym for O_FSYNC
O_CREAT =$0200; // create if nonexistent
O_TRUNC =$0400; // truncate to zero length
O_EXCL =$0800; // error if already exists
O_DSYNC =$1000; // synchronous data writes(omit inode writes)
O_DIRECT =$00010000;
O_FSYNC =$0080; // synchronous writes
O_DIRECTORY =$00020000; // Fail if not directory
O_EXEC =$00040000; // Open for execute only
S_IRWXU =0000700; // RWX mask for owner
S_IRUSR =0000400; // R for owner
S_IWUSR =0000200; // W for owner
S_IXUSR =0000100; // X for owner
S_IRWXG =0000070; // RWX mask for group
S_IRGRP =0000040; // R for group
S_IWGRP =0000020; // W for group
S_IXGRP =0000010; // X for group
S_IRWXO =0000007; // RWX mask for other
S_IROTH =0000004; // R for other
S_IWOTH =0000002; // W for other
S_IXOTH =0000001; // X for other
S_IFMT =0170000; // type of file mask
S_IFDIR =0040000; // directory
S_IFREG =0100000; // regular
F_GETFL =3; // get file status flags
F_SETFL =4; // set file status flags
SEEK_SET =0; // set file offset to offset
SEEK_CUR =1; // set file offset to current plus offset
SEEK_END =2; // set file offset to EOF plus offset
MAP_SHARED =$0001; // share changes
MAP_PRIVATE =$0002; // changes are private
MAP_FILE =$0000; // map from file (default)
MAP_ANON =$1000; // allocated from memory, swap space
MAP_SYSTEM =$2000;
MAP_NOCORE =$00020000; // dont include these pages in a coredump
MAP_NOSYNC =$0800; // page to but do not sync underlying file
MAP_PREFAULT_READ =$00040000; // prefault mapping for reading
DT_UNKNOWN =0;
DT_DIR =4;
DT_REG =8;
SCE_KERNEL_NAME_MAX =NAME_MAX;
SCE_KERNEL_PATH_MAX =PATH_MAX;
SCE_KERNEL_IOV_MAX =IOV_MAX;
SCE_KERNEL_MAXNAMLEN =MAXNAMLEN;
SCE_KERNEL_O_RDONLY =O_RDONLY;
SCE_KERNEL_O_WRONLY =O_WRONLY;
SCE_KERNEL_O_RDWR =O_RDWR ;
SCE_KERNEL_O_NONBLOCK =O_NONBLOCK;
SCE_KERNEL_O_APPEND =O_APPEND;
SCE_KERNEL_O_CREAT =O_CREAT;
SCE_KERNEL_O_TRUNC =O_TRUNC;
SCE_KERNEL_O_EXCL =O_EXCL;
SCE_KERNEL_O_DIRECT =O_DIRECT;
SCE_KERNEL_O_FSYNC =O_FSYNC;
SCE_KERNEL_O_SYNC =O_SYNC;
SCE_KERNEL_O_DSYNC =O_DSYNC;
SCE_KERNEL_O_DIRECTORY =O_DIRECTORY;
SCE_KERNEL_S_IFMT =S_IFMT;
SCE_KERNEL_S_IFDIR =S_IFDIR;
SCE_KERNEL_S_IFREG =S_IFREG;
SCE_KERNEL_S_IRUSR =(S_IRUSR or S_IRGRP or S_IROTH or S_IXUSR or S_IXGRP or S_IXOTH);
SCE_KERNEL_S_IWUSR =(S_IWUSR or S_IWGRP or S_IWOTH or S_IXUSR or S_IXGRP or S_IXOTH);
SCE_KERNEL_S_IXUSR =(S_IXUSR or S_IXGRP or S_IXOTH);
SCE_KERNEL_S_IRWXU =(SCE_KERNEL_S_IRUSR or SCE_KERNEL_S_IWUSR);
SCE_KERNEL_S_IRWU =(SCE_KERNEL_S_IRUSR or SCE_KERNEL_S_IWUSR);
// 00777, R/W
SCE_KERNEL_S_IRU =(SCE_KERNEL_S_IRUSR);
// 00555, R
SCE_KERNEL_S_INONE =0000000;
//SCE_KERNEL_S_ISDIR(m) =S_ISDIR(m);
//SCE_KERNEL_S_ISREG(m) =S_ISREG(m);
// for sceKernelFcntl()
SCE_KERNEL_F_GETFL =F_GETFL;
SCE_KERNEL_F_SETFL =F_SETFL;
// for sceKernelLseek()
SCE_KERNEL_SEEK_SET =SEEK_SET;
SCE_KERNEL_SEEK_CUR =SEEK_CUR;
SCE_KERNEL_SEEK_END =SEEK_END;
// for sceKernelMmap()
SCE_KERNEL_MAP_NOCORE =MAP_NOCORE;
SCE_KERNEL_MAP_NOSYNC =MAP_NOSYNC;
SCE_KERNEL_MAP_PREFAULT_READ=MAP_PREFAULT_READ;
SCE_KERNEL_MAP_PRIVATE =MAP_PRIVATE;
SCE_KERNEL_MAP_SHARED =MAP_SHARED;
// for SceKernelDirent
SCE_KERNEL_DT_UNKNOWN =DT_UNKNOWN;
SCE_KERNEL_DT_DIR =DT_DIR;
SCE_KERNEL_DT_REG =DT_REG;
// for sceKernelSetCompress
SCE_KERNEL_COMPRESS_FILE_MAGIC =($43534650);
SCE_KERNEL_SET_COMPRESS_FILE =(1);
SCE_KERNEL_SET_REGULAR_FILE =(0);
// for sceKernelLwfsSetAttribute
SCE_KERNEL_LWFS_DISABLE =(0);
SCE_KERNEL_LWFS_ENABLE =(1);
type
P_ps4_stat=^T_ps4_stat;
T_ps4_stat=packed object
type
__dev_t=DWORD;
ino_t =DWORD;
mode_t =Word;
nlink_t=Word;
uid_t =DWORD;
gid_t =DWORD;
off_t =Int64;
blkcnt_t=Int64;
blksize_t=DWORD;
fflags_t =DWORD;
var
st_dev :__dev_t ; // inode's device
st_ino :ino_t ; // inode's number
st_mode :mode_t ; // inode protection mode
st_nlink :nlink_t ; // number of hard links
st_uid :uid_t ; // user ID of the file's owner
st_gid :gid_t ; // group ID of the file's group
st_rdev :__dev_t ; // device type
st_atim :timespec ; // time of last access
st_mtim :timespec ; // time of last data modification
st_ctim :timespec ; // time of last file status change
st_size :off_t ; // file size, in bytes
st_blocks :blkcnt_t ; // blocks allocated for file
st_blksize :blksize_t ; // optimal blocksize for I/O
st_flags :fflags_t ; // user defined flags for file
st_gen :DWORD ; // file generation number
st_lspare :DWORD ;
st_birthtim:timespec ; // time of file creation
end;
function ps4_sceKernelOpen(path:PChar;flags,mode:Integer):Integer; SysV_ABI_CDecl;
function ps4_sceKernelLseek(fd:Integer;offset:Int64;whence:Integer):Int64; SysV_ABI_CDecl;
function ps4_sceKernelWrite(fd:Integer;buf:Pointer;nbytes:Int64):Int64; SysV_ABI_CDecl;
function ps4_sceKernelRead(fd:Integer;buf:Pointer;nbytes:Int64):Int64; SysV_ABI_CDecl;
function ps4_sceKernelPread(fd:Integer;buf:Pointer;nbytes,offset:Int64):Int64; SysV_ABI_CDecl;
function ps4_sceKernelClose(fd:Integer):Integer; SysV_ABI_CDecl;
function ps4_stat(path:PChar;stat:P_ps4_stat):Integer; SysV_ABI_CDecl;
function ps4_sceKernelStat(path:PChar;stat:P_ps4_stat):Integer; SysV_ABI_CDecl;
function ps4_write(fd:Integer;data:Pointer;size:DWORD):Integer; SysV_ABI_CDecl;
function ps4_read(fd:Integer;data:Pointer;size:DWORD):Integer; SysV_ABI_CDecl;
function ps4_sceKernelMkdir(path:PChar;mode:Integer):Integer; SysV_ABI_CDecl;
function ps4_mkdir(path:PChar):Integer; SysV_ABI_CDecl;
implementation
uses
ps4_libkernel;
function _open_osfhandle(h:THandle;flags:Integer):Integer; cdecl; external 'msvcrt';
function _get_osfhandle(fd:Integer):THandle; cdecl; external 'msvcrt';
function _close(fd:Integer):Integer; cdecl; external 'msvcrt';
function ps4_sceKernelOpen(path:PChar;flags,mode:Integer):Integer; SysV_ABI_CDecl;
const
WR_RDWR=SCE_KERNEL_O_WRONLY or SCE_KERNEL_O_RDWR;
CREAT_EXCL=SCE_KERNEL_O_CREAT or SCE_KERNEL_O_EXCL;
O_OFS=O_RDONLY or O_WRONLY or O_RDWR or O_APPEND;
var
h:THandle;
dwDesiredAccess:DWORD;
dwCreationDisposition:DWORD;
rp:RawByteString;
wp:WideString;
begin
if (path=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
Assert((flags and SCE_KERNEL_O_DIRECTORY)=0,'folder open TODO');
if (flags and WR_RDWR)=WR_RDWR then
begin
Exit(SCE_KERNEL_ERROR_EINVAL);
end;
if (path[0]=#0) then Exit(SCE_KERNEL_ERROR_ENOENT);
rp:=_parse_filename(path);
if (rp='') then Exit(SCE_KERNEL_ERROR_EACCES);
wp:=UTF8Decode(rp);
if (flags and SCE_KERNEL_O_RDWR)<>0 then
begin
dwDesiredAccess:=GENERIC_READ or GENERIC_WRITE;
end else
if (flags and SCE_KERNEL_O_WRONLY)<>0 then
begin
dwDesiredAccess:=GENERIC_WRITE;
end else
begin
dwDesiredAccess:=GENERIC_READ;
end;
if (flags and SCE_KERNEL_O_APPEND)<>0 then
begin
dwDesiredAccess:=dwDesiredAccess or FILE_APPEND_DATA;
end;
if (flags and CREAT_EXCL)=CREAT_EXCL then
begin
dwCreationDisposition:=CREATE_NEW;
end else
if (flags and SCE_KERNEL_O_CREAT)<>0 then
begin
dwCreationDisposition:=CREATE_ALWAYS;
end else
if (flags and SCE_KERNEL_O_TRUNC)<>0 then
begin
dwCreationDisposition:=TRUNCATE_EXISTING;
end else
begin
dwCreationDisposition:=OPEN_EXISTING;
end;
h:=CreateFileW(
PWideChar(wp),
dwDesiredAccess,
FILE_SHARE_READ,
nil,
dwCreationDisposition,
FILE_ATTRIBUTE_NORMAL,
0
);
if (h=INVALID_HANDLE_VALUE) then
begin
Writeln(GetLastError);
Case GetLastError of
ERROR_INVALID_DRIVE,
ERROR_PATH_NOT_FOUND,
ERROR_FILE_NOT_FOUND:Exit(SCE_KERNEL_ERROR_ENOENT);
ERROR_ACCESS_DENIED :Exit(SCE_KERNEL_ERROR_EACCES);
ERROR_FILE_EXISTS :Exit(SCE_KERNEL_ERROR_EEXIST);
else
Exit(SCE_KERNEL_ERROR_EIO);
end;
end;
Result:=_open_osfhandle(h,flags and O_OFS);
if (Result=-1) then
begin
Exit(SCE_KERNEL_ERROR_EMFILE);
end;
end;
function ps4_sceKernelLseek(fd:Integer;offset:Int64;whence:Integer):Int64; SysV_ABI_CDecl;
var
h:THandle;
begin
h:=_get_osfhandle(fd);
if (h=INVALID_HANDLE_VALUE) then Exit(SCE_KERNEL_ERROR_EBADF);
case whence of
SCE_KERNEL_SEEK_SET:Result:=FileSeek(h,offset,fsFromBeginning);
SCE_KERNEL_SEEK_CUR:Result:=FileSeek(h,offset,fsFromCurrent);
SCE_KERNEL_SEEK_END:Result:=FileSeek(h,offset,fsFromEnd);
else
Exit(SCE_KERNEL_ERROR_EINVAL);
end;
if (Result=-1) then Result:=SCE_KERNEL_ERROR_EOVERFLOW;
end;
function ps4_sceKernelWrite(fd:Integer;buf:Pointer;nbytes:Int64):Int64; SysV_ABI_CDecl;
var
h:THandle;
N:DWORD;
begin
h:=_get_osfhandle(fd);
if (h=INVALID_HANDLE_VALUE) then Exit(SCE_KERNEL_ERROR_EBADF);
if (buf=nil) then Exit(SCE_KERNEL_ERROR_EFAULT);
if (nbytes<0) or (nbytes>High(Integer)) then Exit(SCE_KERNEL_ERROR_EINVAL);
N:=0;
if WriteFile(h,buf^,nbytes,N,nil) then
begin
Result:=N;
end else
begin
Exit(SCE_KERNEL_ERROR_EIO);
end;
end;
function ps4_sceKernelRead(fd:Integer;buf:Pointer;nbytes:Int64):Int64; SysV_ABI_CDecl;
var
h:THandle;
N:DWORD;
begin
h:=_get_osfhandle(fd);
if (h=INVALID_HANDLE_VALUE) then Exit(SCE_KERNEL_ERROR_EBADF);
if (buf=nil) then Exit(SCE_KERNEL_ERROR_EFAULT);
if (nbytes<0) or (nbytes>High(Integer)) then Exit(SCE_KERNEL_ERROR_EINVAL);
N:=0;
if ReadFile(h,buf^,nbytes,N,nil) then
begin
Result:=N;
end else
begin
Exit(SCE_KERNEL_ERROR_EIO);
end;
end;
function ps4_sceKernelPread(fd:Integer;buf:Pointer;nbytes,offset:Int64):Int64; SysV_ABI_CDecl;
var
h:THandle;
N:DWORD;
O:TOVERLAPPED;
begin
if (buf=nil) then Exit(SCE_KERNEL_ERROR_EFAULT);
if (nbytes<0) or (nbytes>High(Integer)) or (offset<0) then Exit(SCE_KERNEL_ERROR_EINVAL);
h:=_get_osfhandle(fd);
if (h=INVALID_HANDLE_VALUE) then Exit(SCE_KERNEL_ERROR_EBADF);
O:=Default(TOVERLAPPED);
PInt64(@O.Offset)^:=offset;
N:=0;
if ReadFile(h,buf^,nbytes,N,@O) then
begin
Result:=N;
end else
begin
Exit(SCE_KERNEL_ERROR_EIO);
end;
end;
function ps4_sceKernelClose(fd:Integer):Integer; SysV_ABI_CDecl;
begin
Result:=_close(fd);
if (Result<>0) then Result:=SCE_KERNEL_ERROR_EBADF;
end;
type
P_ms_stat64=^T_ms_stat64;
T_ms_stat64=packed object
type
_dev_t=DWORD;
_ino_t=WORD;
__time64_t=QWORD;
var
st_dev:_dev_t; //4
st_ino:_ino_t; //2
st_mode:WORD; //2 4
st_nlink:WORD; //2
st_uid:WORD; //2 4
st_gid:WORD; //2
a1:Word; //2 4
st_rdev:_dev_t; //4
a2:DWORD; //4
st_size:Int64; //8
st_atime:__time64_t;
st_mtime:__time64_t;
st_ctime:__time64_t;
end;
function _wstat64(path:PWideChar;stat:P_ms_stat64):Integer; cdecl; external 'msvcrt';
function ps4_stat(path:PChar;stat:P_ps4_stat):Integer; SysV_ABI_CDecl;
var
stat_os:T_ms_stat64;
rp:RawByteString;
wp:WideString;
begin
//_wstat64(path:PWideChar;stat:P_ms_stat64)
writeln('stat:',path);
if (path=nil) then Exit(EINVAL);
if (path[0]=#0) then Exit(ENOENT);
rp:=_parse_filename(path);
if (rp='') then Exit(EACCES);
wp:=UTF8Decode(rp);
stat_os:=Default(T_ms_stat64);
Result:=_wstat64(PWideChar(wp),@stat_os);
if (Result<>0) then
begin
Writeln(GetLastError);
Case GetLastError of
ERROR_FILE_NOT_FOUND:Exit(SCE_KERNEL_ERROR_ENOENT);
ERROR_PATH_NOT_FOUND:Exit(SCE_KERNEL_ERROR_ENOTDIR);
else
Exit(SCE_KERNEL_ERROR_EIO);
end;
end;
if (stat<>nil) then
begin
stat^:=Default(T_ps4_stat);
stat^.st_dev :=stat_os.st_dev;
stat^.st_ino :=stat_os.st_ino;
stat^.st_mode :=stat_os.st_mode;
stat^.st_nlink :=stat_os.st_nlink;
stat^.st_uid :=stat_os.st_uid;
stat^.st_gid :=stat_os.st_gid;
stat^.st_rdev :=stat_os.st_rdev;
stat^.st_atim.tv_sec:=stat_os.st_atime;
stat^.st_mtim.tv_sec:=stat_os.st_mtime;
stat^.st_ctim.tv_sec:=stat_os.st_ctime;
stat^.st_size :=stat_os.st_size;
end;
end;
function ps4_sceKernelStat(path:PChar;stat:P_ps4_stat):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(ps4_stat(path,stat));
end;
function GetStr(p:Pointer;L:SizeUint):RawByteString;
begin
SetString(Result,P,L);
end;
function ps4_write(fd:Integer;data:Pointer;size:DWORD):Integer; SysV_ABI_CDecl;
var
h:THandle;
N:DWORD;
begin
if (data=nil) then Exit(lc_set_errno(EFAULT));
if (size>High(Integer)) then Exit(lc_set_errno(EINVAL));
h:=_get_osfhandle(fd);
if (h=INVALID_HANDLE_VALUE) then Exit(lc_set_errno(EBADF));
N:=0;
if WriteFile(h,data^,size,N,nil) then
begin
Result:=N;
end else
begin
Exit(lc_set_errno(EIO));
end;
end;
function ps4_read(fd:Integer;data:Pointer;size:DWORD):Integer; SysV_ABI_CDecl;
var
h:THandle;
N:DWORD;
begin
if (data=nil) then Exit(lc_set_errno(EFAULT));
if (size>High(Integer)) then Exit(lc_set_errno(EINVAL));
h:=_get_osfhandle(fd);
if (h=INVALID_HANDLE_VALUE) then Exit(lc_set_errno(EBADF));
N:=0;
if ReadFile(h,data^,size,N,nil) then
begin
Result:=N;
end else
begin
Exit(lc_set_errno(EIO));
end;
end;
// nop nid:libkernel:0D1B81B76A6F2029:_read ps4_write
function ps4_sceKernelMkdir(path:PChar;mode:Integer):Integer; SysV_ABI_CDecl;
var
fn:RawByteString;
begin
Result:=0;
Writeln('sceKernelMkdir:',path,'(',OctStr(mode,3),')');
fn:=_parse_filename(path);
if not CreateDir(fn) then Result:=-1;
end;
function ps4_mkdir(path:PChar):Integer; SysV_ABI_CDecl;
var
fn:RawByteString;
begin
Result:=0;
Writeln('mkdir:',path);
fn:=_parse_filename(path);
if not CreateDir(fn) then Result:=-1;
end;
end.

View File

@ -0,0 +1,866 @@
unit ps4_libkernel;
{$mode objfpc}{$H+}
interface
uses
Windows,
ps4_map_mm,
RWLock,
ps4_types,
ps4_pthread,
ps4_mutex,
ps4_cond,
ps4_sema,
ps4_rwlock,
ps4_time,
ps4_kernel_file,
ps4_queue,
ps4_elf,
ps4_program,
Classes, SysUtils;
{$I sce_errno.inc}
{$I errno.inc}
function px2sce(e:Integer):Integer;
function lc_set_errno(r:Integer):Integer;
function ps4_sceKernelIsNeoMode:Integer; SysV_ABI_CDecl;
implementation
function px2sce(e:Integer):Integer;
begin
case e of
0:Result:=0;
EPERM :Result:=SCE_KERNEL_ERROR_EPERM ;
ENOENT :Result:=SCE_KERNEL_ERROR_ENOENT ;
ESRCH :Result:=SCE_KERNEL_ERROR_ESRCH ;
EINTR :Result:=SCE_KERNEL_ERROR_EINTR ;
EIO :Result:=SCE_KERNEL_ERROR_EIO ;
ENXIO :Result:=SCE_KERNEL_ERROR_ENXIO ;
E2BIG :Result:=SCE_KERNEL_ERROR_E2BIG ;
ENOEXEC :Result:=SCE_KERNEL_ERROR_ENOEXEC ;
EBADF :Result:=SCE_KERNEL_ERROR_EBADF ;
ECHILD :Result:=SCE_KERNEL_ERROR_ECHILD ;
EDEADLK :Result:=SCE_KERNEL_ERROR_EDEADLK ;
ENOMEM :Result:=SCE_KERNEL_ERROR_ENOMEM ;
EACCES :Result:=SCE_KERNEL_ERROR_EACCES ;
EFAULT :Result:=SCE_KERNEL_ERROR_EFAULT ;
ENOTBLK :Result:=SCE_KERNEL_ERROR_ENOTBLK ;
EBUSY :Result:=SCE_KERNEL_ERROR_EBUSY ;
EEXIST :Result:=SCE_KERNEL_ERROR_EEXIST ;
EXDEV :Result:=SCE_KERNEL_ERROR_EXDEV ;
ENODEV :Result:=SCE_KERNEL_ERROR_ENODEV ;
ENOTDIR :Result:=SCE_KERNEL_ERROR_ENOTDIR ;
EISDIR :Result:=SCE_KERNEL_ERROR_EISDIR ;
EINVAL :Result:=SCE_KERNEL_ERROR_EINVAL ;
ENFILE :Result:=SCE_KERNEL_ERROR_ENFILE ;
EMFILE :Result:=SCE_KERNEL_ERROR_EMFILE ;
ENOTTY :Result:=SCE_KERNEL_ERROR_ENOTTY ;
ETXTBSY :Result:=SCE_KERNEL_ERROR_ETXTBSY ;
EFBIG :Result:=SCE_KERNEL_ERROR_EFBIG ;
ENOSPC :Result:=SCE_KERNEL_ERROR_ENOSPC ;
ESPIPE :Result:=SCE_KERNEL_ERROR_ESPIPE ;
EROFS :Result:=SCE_KERNEL_ERROR_EROFS ;
EMLINK :Result:=SCE_KERNEL_ERROR_EMLINK ;
EPIPE :Result:=SCE_KERNEL_ERROR_EPIPE ;
EDOM :Result:=SCE_KERNEL_ERROR_EDOM ;
ERANGE :Result:=SCE_KERNEL_ERROR_ERANGE ;
EAGAIN :Result:=SCE_KERNEL_ERROR_EAGAIN ;
EINPROGRESS :Result:=SCE_KERNEL_ERROR_EINPROGRESS ;
EALREADY :Result:=SCE_KERNEL_ERROR_EALREADY ;
ENOTSOCK :Result:=SCE_KERNEL_ERROR_ENOTSOCK ;
EDESTADDRREQ :Result:=SCE_KERNEL_ERROR_EDESTADDRREQ ;
EMSGSIZE :Result:=SCE_KERNEL_ERROR_EMSGSIZE ;
EPROTOTYPE :Result:=SCE_KERNEL_ERROR_EPROTOTYPE ;
ENOPROTOOPT :Result:=SCE_KERNEL_ERROR_ENOPROTOOPT ;
EPROTONOSUPPORT:Result:=SCE_KERNEL_ERROR_EPROTONOSUPPORT;
ESOCKTNOSUPPORT:Result:=SCE_KERNEL_ERROR_ESOCKTNOSUPPORT;
EOPNOTSUPP :Result:=SCE_KERNEL_ERROR_EOPNOTSUPP ;
EPFNOSUPPORT :Result:=SCE_KERNEL_ERROR_EPFNOSUPPORT ;
EAFNOSUPPORT :Result:=SCE_KERNEL_ERROR_EAFNOSUPPORT ;
EADDRINUSE :Result:=SCE_KERNEL_ERROR_EADDRINUSE ;
EADDRNOTAVAIL :Result:=SCE_KERNEL_ERROR_EADDRNOTAVAIL ;
ENETDOWN :Result:=SCE_KERNEL_ERROR_ENETDOWN ;
ENETUNREACH :Result:=SCE_KERNEL_ERROR_ENETUNREACH ;
ENETRESET :Result:=SCE_KERNEL_ERROR_ENETRESET ;
ECONNABORTED :Result:=SCE_KERNEL_ERROR_ECONNABORTED ;
ECONNRESET :Result:=SCE_KERNEL_ERROR_ECONNRESET ;
ENOBUFS :Result:=SCE_KERNEL_ERROR_ENOBUFS ;
EISCONN :Result:=SCE_KERNEL_ERROR_EISCONN ;
ENOTCONN :Result:=SCE_KERNEL_ERROR_ENOTCONN ;
ESHUTDOWN :Result:=SCE_KERNEL_ERROR_ESHUTDOWN ;
ETOOMANYREFS :Result:=SCE_KERNEL_ERROR_ETOOMANYREFS ;
ETIMEDOUT :Result:=SCE_KERNEL_ERROR_ETIMEDOUT ;
ECONNREFUSED :Result:=SCE_KERNEL_ERROR_ECONNREFUSED ;
ELOOP :Result:=SCE_KERNEL_ERROR_ELOOP ;
ENAMETOOLONG :Result:=SCE_KERNEL_ERROR_ENAMETOOLONG ;
EHOSTDOWN :Result:=SCE_KERNEL_ERROR_EHOSTDOWN ;
EHOSTUNREACH :Result:=SCE_KERNEL_ERROR_EHOSTUNREACH ;
ENOTEMPTY :Result:=SCE_KERNEL_ERROR_ENOTEMPTY ;
EPROCLIM :Result:=SCE_KERNEL_ERROR_EPROCLIM ;
EUSERS :Result:=SCE_KERNEL_ERROR_EUSERS ;
EDQUOT :Result:=SCE_KERNEL_ERROR_EDQUOT ;
ESTALE :Result:=SCE_KERNEL_ERROR_ESTALE ;
EREMOTE :Result:=SCE_KERNEL_ERROR_EREMOTE ;
EBADRPC :Result:=SCE_KERNEL_ERROR_EBADRPC ;
ERPCMISMATCH :Result:=SCE_KERNEL_ERROR_ERPCMISMATCH ;
EPROGUNAVAIL :Result:=SCE_KERNEL_ERROR_EPROGUNAVAIL ;
EPROGMISMATCH :Result:=SCE_KERNEL_ERROR_EPROGMISMATCH ;
EPROCUNAVAIL :Result:=SCE_KERNEL_ERROR_EPROCUNAVAIL ;
ENOLCK :Result:=SCE_KERNEL_ERROR_ENOLCK ;
ENOSYS :Result:=SCE_KERNEL_ERROR_ENOSYS ;
EFTYPE :Result:=SCE_KERNEL_ERROR_EFTYPE ;
EAUTH :Result:=SCE_KERNEL_ERROR_EAUTH ;
ENEEDAUTH :Result:=SCE_KERNEL_ERROR_ENEEDAUTH ;
EIDRM :Result:=SCE_KERNEL_ERROR_EIDRM ;
ENOMSG :Result:=SCE_KERNEL_ERROR_ENOMSG ;
EOVERFLOW :Result:=SCE_KERNEL_ERROR_EOVERFLOW ;
ECANCELED :Result:=SCE_KERNEL_ERROR_ECANCELED ;
EILSEQ :Result:=SCE_KERNEL_ERROR_EILSEQ ;
ENOATTR :Result:=SCE_KERNEL_ERROR_ENOATTR ;
EDOOFUS :Result:=SCE_KERNEL_ERROR_EDOOFUS ;
EBADMSG :Result:=SCE_KERNEL_ERROR_EBADMSG ;
EMULTIHOP :Result:=SCE_KERNEL_ERROR_EMULTIHOP ;
ENOLINK :Result:=SCE_KERNEL_ERROR_ENOLINK ;
EPROTO :Result:=SCE_KERNEL_ERROR_EPROTO ;
ENOTCAPABLE :Result:=SCE_KERNEL_ERROR_ENOTCAPABLE ;
ECAPMODE :Result:=SCE_KERNEL_ERROR_ECAPMODE ;
ENOBLK :Result:=SCE_KERNEL_ERROR_ENOBLK ;
EICV :Result:=SCE_KERNEL_ERROR_EICV ;
ENOPLAYGOENT :Result:=SCE_KERNEL_ERROR_ENOPLAYGOENT ;
EREVOKE :Result:=SCE_KERNEL_ERROR_EREVOKE ;
ESDKVERSION :Result:=SCE_KERNEL_ERROR_ESDKVERSION ;
ESTART :Result:=SCE_KERNEL_ERROR_ESTART ;
ESTOP :Result:=SCE_KERNEL_ERROR_ESTOP ;
else
Result:=SCE_KERNEL_ERROR_UNKNOWN;
end;
end;
var
_error:QWORD;
function lc_set_errno(r:Integer):Integer;
begin
if (r<>0) then
begin
_error:=r;
Exit(-1);
end;
Result:=r;
end;
function ps4___error:Pointer; SysV_ABI_CDecl;
begin
//Writeln('___error');
Result:=@_error;
end;
Const
_stack_chk_guard:QWORD=$deadbeefa55a857;
ps4_stack_chk_guard:Pointer=@_stack_chk_guard;
procedure ps4_stack_chk_fail; SysV_ABI_CDecl;
begin
Writeln('Stack overflow detected! Aborting program.');
end;
{$I StopNotificationReason.inc}
// eStopNotificationReason
procedure ps4_sceKernelDebugRaiseException(dwStopReason,dwStopId:DWORD); SysV_ABI_CDecl;
begin
Writeln(StdErr,'RaiseException:',HexStr(dwStopReason,8),':',HexStr(dwStopId,8),':',GetStopReasonInfo(dwStopReason));
end;
procedure ps4_sceKernelDebugRaiseExceptionOnReleaseMode; assembler;
asm
xor %rax,%rax
end;
//ps4 neo mode is support? (Ps4 Pro)
function ps4_sceKernelIsNeoMode:Integer; SysV_ABI_CDecl;
begin
Result:=0; //no
//Result:=1; //yes
end;
//void * _aligned_malloc(
// size_t size,
// size_t alignment
//);
//void _aligned_free (
// void *memblock
//);
const
_SIG_WORDS =4;
_SIG_MAXSIG =128;
//_SIG_IDX(sig) ((sig) - 1)
//_SIG_WORD(sig) (_SIG_IDX(sig) >> 5)
//_SIG_BIT(sig) (1U << (_SIG_IDX(sig) & 31))
//_SIG_VALID(sig) ((sig) <= _SIG_MAXSIG && (sig) > 0)
SIG_BLOCK =1;
SIG_UNBLOCK =2;
SIG_SETMASK =3;
SIGPROCMASK_OLD =$0001;
SIGPROCMASK_PROC_LOCKED =$0002;
SIGPROCMASK_PS_LOCKED =$0004;
SIGPROCMASK_FASTBLK =$0008;
type
P__sigset_t=^__sigset_t;
__sigset_t=packed record
__bits:array[0.._SIG_WORDS-1] of DWORD;
end;
//function sigfillset(_set:P__sigset_t):Integer;
procedure ps4_sigfillset; assembler; nostackframe;
label
_end;
asm
xor %eax, %eax
dec %eax
test %rdi,%rdi
je _end
xor %rax, %rax
mov %rax, (%rdi) //0+1
mov %rax, 0x8(%rdi) //2+3
_end:
end;
function ps4_sigprocmask(how:Integer;_set,oldset:P__sigset_t):Integer; SysV_ABI_CDecl;
begin
//Writeln('sigprocmask:',how);
//if (_set<>nil) and (oldset<>nil) then oldset^:=_set^;
Result:=0;
end;
function ps4__sigprocmask(how:QWORD;_set,oldset:P__sigset_t):Integer; cdecl; SysV_ABI_CDecl;
begin
//Writeln('_sigprocmask:',how);
if (_set<>nil) and (oldset<>nil) then oldset^:=_set^;
Result:=0;
end;
function ps4_is_signal_return(P:Pointer):Integer; SysV_ABI_CDecl;
begin
Writeln('_is_signal_return:',HexStr(P));
Result:=1;
end;
function ps4_sceKernelGetModuleInfoFromAddr(Addr:Pointer;P2:Integer;pOut:PKernelModuleInfo):Integer; SysV_ABI_CDecl;
var
node:TElf_node;
begin
Writeln('GetModuleInfoFromAddr:',HexStr(Addr),':',P2,':',HexStr(pOut));
node:=ps4_app.FindFileByCodeAdr(Addr);
if (node=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
if pOut<>nil then
begin
pOut^:=Telf_file(node).ModuleInfo;
end;
Result:=0;
end;
type
PInternalSegmentInfo=^TInternalSegmentInfo;
TInternalSegmentInfo=packed record
address:Pointer;
size:DWORD;
end;
function ps4_sceKernelInternalMemoryGetModuleSegmentInfo(pOut:PInternalSegmentInfo):Integer; SysV_ABI_CDecl;
begin
pOut^.address:=nil;
pOut^.size:=0;
Result:=0;
//sceKernelGetLibkernelTextLocation(pOut^.address,pOut^.size)
end;
function ps4_sceKernelGetProcParam:Pointer; SysV_ABI_CDecl;
var
elf:Telf_file;
Param:PSceProcParam;
begin
Result:=nil;
Writeln('KernelGetProcParam');
elf:=Telf_file(ps4_program.ps4_app.prog);
if (elf=nil) then Exit;
if (elf.pProcParam=0) then Exit;
Param:=elf.mMap.pAddr+elf.pProcParam;
Result:=Param;
end;
type
PAppHeapAPI=^TAppHeapAPI;
TAppHeapAPI=packed record
_malloc,_free:Pointer;
end;
procedure ps4_sceKernelRtldSetApplicationHeapAPI(heap_api:PAppHeapAPI); SysV_ABI_CDecl;
begin
Writeln('SetApplicationHeapAPI:',HexStr(heap_api));
Writeln(HexStr(heap_api^._malloc)); //__malloc
Writeln(HexStr(heap_api^._free)); //__free
end;
//registred destroy proc?
function ps4_sceKernelSetThreadDtors(Proc:TProcedure):Integer; SysV_ABI_CDecl;
begin
Writeln('sceKernelSetThreadDtors:',HexStr(proc));
Result:=0;
end;
type
TKernelAtexitFunc=function(param:Integer):Integer;
//registred thread atexit proc?
function ps4_sceKernelSetThreadAtexitCount(proc:TKernelAtexitFunc):Integer; SysV_ABI_CDecl;
begin
Writeln('sceKernelSetThreadAtexitCount:',HexStr(proc));
Result:=0;
end;
type
TKernelAtexitReportFunc=procedure(param:Integer);
function ps4_sceKernelSetThreadAtexitReport(proc:TKernelAtexitReportFunc):Integer; SysV_ABI_CDecl;
begin
Writeln('sceKernelSetThreadAtexitReport:',HexStr(proc));
Result:=0;
end;
//extern "C" {
//int user_malloc_init(void);
//int user_malloc_finalize(void);
//void *user_malloc(size_t size);
//void user_free(void *ptr);
//void *user_calloc(size_t nelem, size_t size);
//void *user_realloc(void *ptr, size_t size);
//void *user_memalign(size_t boundary, size_t size);
//int user_posix_memalign(void **ptr, size_t boundary, size_t size);
//void *user_reallocalign(void *ptr, size_t size, size_t boundary);
//int user_malloc_stats(SceLibcMallocManagedSize *mmsize);
//int user_malloc_stats_fast(SceLibcMallocManagedSize *mmsize);
//size_t user_malloc_usable_size(void *ptr);
//}
//PlayStation®4 Clang: UndefinedBehaviorSanitizer (UBSan)
function ps4_sceKernelGetSanitizerNewReplaceExternal():Pointer; SysV_ABI_CDecl;
begin
//list mem of proc????
Result:=nil;
end;
function ps4_sceKernelIsAddressSanitizerEnabled({name:Pchar}):Integer; SysV_ABI_CDecl;
begin
Writeln('sceKernelIsAddressSanitizerEnabled:'{,name});
Result:=0;
end;
type
SceKernelModule=Integer;
PSceKernelLoadModuleOpt=^SceKernelLoadModuleOpt;
SceKernelLoadModuleOpt=packed record
size:size_t;
end;
//dynamic load????
function ps4_sceKernelLoadStartModule(moduleFileName:Pchar;
argc:size_t;
argp:PPchar;
flags:DWORD;
pOpt:PSceKernelLoadModuleOpt;
pRes:PInteger):SceKernelModule; SysV_ABI_CDecl;
begin
Writeln('Load Lib:',moduleFileName);
Result:=1;
end;
function ps4_memset(ptr:Pointer;value:Integer;num:size_t):Pointer; assembler; nostackframe;
asm
//mov %rdx , %rdx //3->2
mov %rsi , %r8 //2->3
mov %rdi , %rcx //1
jmp FillByte
end;
function ps4_memcmp(buf1,buf2:Pointer;count:size_t):Integer; assembler; nostackframe;
asm
mov %rdx , %r8 //3
mov %rsi , %rdx //2
mov %rdi , %rcx //1
jmp CompareByte
end;
function ps4_memcpy_s(dst:Pointer;dstSize:size_t;src:Pointer;count:size_t):Integer; SysV_ABI_CDecl;
begin
if (count=0) then Exit(0);
if (dst=nil) or (src=nil) then
begin
if (dst<>nil) then FillChar(dst^,dstSize,0);
lc_set_errno(EINVAL);
Exit(EINVAL);
end;
if (dstSize<count) then
begin
FillChar(dst^,dstSize,0);
lc_set_errno(ERANGE);
Exit(ERANGE);
end;
Move(src^,dst^,count);
Result:=0;
end;
function ps4_strcpy_s(dst:PChar;destSize:size_t;src:PChar):Integer; SysV_ABI_CDecl;
var
count:size_t;
begin
if (dst=nil) or (src=nil) then
begin
if (dst<>nil) then dst[0]:=#0;
lc_set_errno(EINVAL);
Exit(EINVAL);
end;
count:=System.strlen(src)+1;
if (count>destSize) then
begin
dst[0]:=#0;
lc_set_errno(ERANGE);
Exit(ERANGE);
end;
Move(src^,dst^,count);
Result:=0;
end;
function ps4_memmove(dst,src:Pointer;len:size_t):Pointer; assembler; nostackframe;
asm
mov %rdx, %r8 //3
mov %rsi, %rcx //2->1
mov %rdi, %rdx //1->2
call Move
end;
const
SCE_LIBC_MSPACE_THREAD_UNSAFE =($00000001);
SCE_LIBC_MSPACE_DEBUG_SHORTAGE =($00000004);
type
SceLibcMspace=^TSceLibcMspace;
TSceLibcMspace=packed record
base:Pointer;
capacity:size_t;
count:size_t;
lock:TRWLock;
end;
function ps4_sceLibcMspaceCreate(name:PChar;base:Pointer;capacity:size_t;flag:Integer):SceLibcMspace; SysV_ABI_CDecl;
begin
Result:=nil;
if ((QWORD(base) and $F)<>0) or ((capacity and $F)<>0) then Exit;
if (capacity<=1440) then Exit;
Writeln('sceLibcMspaceCreate:',name,':',HexStr(base),'..',HexStr(base+capacity));
Result:=AllocMem(SizeOf(TSceLibcMspace));
Result^.base:=base;
Result^.capacity:=capacity;
Result^.count:=1440;
rwlock_init(Result^.lock);
end;
function ps4_sceLibcMspaceMalloc(msp:SceLibcMspace;size:size_t):Pointer; SysV_ABI_CDecl;
begin
Result:=nil;
if (msp=nil) then Exit;
rwlock_wrlock(msp^.lock);
if (msp^.count+size)>msp^.capacity then Exit;
Result:=msp^.base+msp^.count;
msp^.count:=msp^.count+size;
rwlock_unlock(msp^.lock);
end;
function ps4_expf(x:Single):Single; SysV_ABI_CDecl;
begin
Result:=System.Exp(x);
end;
type
PGetTraceInfo=^TGetTraceInfo;
TGetTraceInfo=packed record
Size:QWORD; //32
flag:DWORD; //1
get_segment_info:DWORD; //0
Unknow4:Pointer; //[2]
Unknow5:Pointer; //[3]
end;
var
td1:Pointer=Pointer($101);
td2:Pointer=Pointer($202);
//mysterious function
procedure ps4_sceLibcHeapGetTraceInfo(P:PGetTraceInfo); SysV_ABI_CDecl;
begin
P^.get_segment_info:=0;
P^.Unknow4:=@td1;
P^.Unknow5:=@td2;
end;
function ps4_sceSysmoduleLoadModule(id:Word):Integer; SysV_ABI_CDecl;
begin
Writeln('sceSysmoduleLoadModule:',HexStr(id,4)); //libSceNgs2.sprx SCE_SYSMODULE_NGS2 0x000B
Result:=0;
end;
function ps4_sceSysmoduleUnloadModule(id:Word):Integer; SysV_ABI_CDecl;
begin
Writeln('sceSysmoduleUnloadModule:',HexStr(id,4));
Result:=0;
end;
function ps4_sceSysmoduleIsLoaded(id:Word):Integer; SysV_ABI_CDecl;
begin
Writeln('sceSysmoduleIsLoaded:',HexStr(id,4));
Result:=0;
end;
const
__progname:PChar='progname.elf';
Const
Need_sceLibcInternal:QWORD=1;
_Stdin :QWORD=0;
_Stdout:QWORD=1;
_Stderr:QWORD=2;
function _get_proc_libSceLibcInternal(src:PLIBRARY;nid:QWORD):Pointer;
var
lib:PLIBRARY;
begin
Result:=src^._get_proc(nid);
if (Result=nil) then
begin
Case nid of
$78B743C3A974FDB5: //snprintf
begin
lib:=ps4_app.GetLib('libc');
if (lib<>nil) then
begin
Result:=lib^.get_proc(Nid);
end;
end;
$F33B2ED385CDB19E: //expf
begin
lib:=ps4_app.GetLib('libc');
if (lib<>nil) then
begin
Result:=lib^.get_proc(Nid);
end;
if (Result=nil) then
begin
Result:=@ps4_expf;
end;
end;
end;
if (Result<>nil) then
begin
src^.set_proc(nid,Result);
end;
end;
end;
function Load_libSceLibcInternal(Const name:RawByteString):TElf_node;
var
lib:PLIBRARY;
begin
Result:=TElf_node.Create;
Result.pFileName:=name;
lib:=Result._add_lib('libSceLibcInternal');
lib^.Fget_proc_cb:=@_get_proc_libSceLibcInternal;
lib^.set_proc($653E0E0C3D93B3DA,@Need_sceLibcInternal);
lib^.set_proc($D530E8FC89AA9097,@_Stdin );
lib^.set_proc($DAC5B3858A851F81,@_Stdout);
lib^.set_proc($1FC029ACA799B4D8,@_Stderr);
lib^.set_proc($F334C5BC120020DF,@ps4_memset);
lib^.set_proc($0DF8AF3C0AE1B9C8,@ps4_memcmp);
lib^.set_proc($3452ECF9D44918D8,@ps4_memcpy_s);
lib^.set_proc($E576B600234409DA,@ps4_strcpy_s);
lib^.set_proc($437541C425E1507B,@ps4_memmove);//memcpy
lib^.set_proc($FE19F5B5C547AB94,@ps4_sceLibcMspaceCreate);
lib^.set_proc($3898E6FD03881E52,@ps4_sceLibcMspaceMalloc);
lib:=Result._add_lib('libSceLibcInternalExt');
lib^.set_proc($356B53375D1C2731,@ps4_sceLibcHeapGetTraceInfo);
end;
function Load_libSceSysmodule(Const name:RawByteString):TElf_node;
var
lib:PLIBRARY;
begin
Result:=TElf_node.Create;
Result.pFileName:=name;
lib:=Result._add_lib('libSceSysmodule');
lib^.set_proc($83C70CDFD11467AA,@ps4_sceSysmoduleLoadModule);
lib^.set_proc($791D9B6450005344,@ps4_sceSysmoduleUnloadModule);
lib^.set_proc($7CC3F934750E68C9,@ps4_sceSysmoduleIsLoaded);
end;
function Load_libkernel(Const name:RawByteString):TElf_node;
var
lib,px:PLIBRARY;
begin
Result:=TElf_node.Create;
Result.pFileName:=name;
lib:=Result._add_lib('libkernel');
lib^.set_proc($BCD7B5C387622C2B,@_dynamic_tls_get_addr);
lib^.set_proc($763C713A65BAFDAC,@__progname);
lib^.set_proc($F41703CA43E6A352,@ps4___error);
lib^.set_proc($7FBB8EC58F663355,@ps4_stack_chk_guard);
lib^.set_proc($3AEDE22F569BBE78,@ps4_stack_chk_fail);
lib^.set_proc($91BC385071D2632D,@ps4_pthread_cxa_finalize);
lib^.set_proc($38C0D128A019F08E,@ps4_sceKernelDebugRaiseException);
lib^.set_proc($CC4FF05C86632E83,@ps4_sceKernelDebugRaiseExceptionOnReleaseMode);
lib^.set_proc($5644C0B2B643709D,@ps4_sigfillset);
lib^.set_proc($68F732A6D6CE899B,@ps4_sigprocmask);
lib^.set_proc($EB1569CB415DABE2,@ps4__sigprocmask);
lib^.set_proc($72B6F98FB9A49357,@ps4_is_signal_return);
lib^.set_proc($93E017AAEDBF7817,@ps4_getpagesize);
lib^.set_proc($04F13DB3DBD0417A,@ps4_mmap);
lib^.set_proc($52A0C68D7039C943,@ps4_munmap);
lib^.set_proc($B59638F9264D1610,@ps4_msync);
lib^.set_proc($FD84D6FAA5DCDC24,@ps4_sceKernelInternalMemoryGetModuleSegmentInfo);
lib^.set_proc($7FB28139A7F2B17A,@ps4_sceKernelGetModuleInfoFromAddr);
lib^.set_proc($F79F6AADACCF22B8,@ps4_sceKernelGetProcParam);
lib^.set_proc($A7911C41E11E2401,@ps4_sceKernelRtldSetApplicationHeapAPI);
lib^.set_proc($ACD856CFE96F38C5,@ps4_sceKernelSetThreadDtors);
lib^.set_proc($A41FF2199DA743DA,@ps4_sceKernelSetThreadAtexitCount);
lib^.set_proc($5A109CD70DC48522,@ps4_sceKernelSetThreadAtexitReport);
lib^.set_proc($6E7671620005780D,@ps4_sceKernelGetSanitizerNewReplaceExternal);
lib^.set_proc($8E1FBC5E22B82DE1,@ps4_sceKernelIsAddressSanitizerEnabled);
lib^.set_proc($C33BEA4F852A297F,@ps4_sceKernelLoadStartModule);
//mutex
lib^.set_proc($7501D612C26DA04E,@ps4_pthread_mutexattr_init);
lib^.set_proc($1C5EE52B8EB1CE36,@ps4_pthread_mutexattr_destroy);
lib^.set_proc($19916523B461B90A,@ps4_pthread_mutexattr_gettype);
lib^.set_proc($9839A030E19552A8,@ps4_pthread_mutexattr_settype);
lib^.set_proc($3E62FF4F0294CD72,@ps4_pthread_mutexattr_getpshared);
lib^.set_proc($117BF7CED1AAB433,@ps4_pthread_mutexattr_setpshared);
lib^.set_proc($C83696C54139D2CD,@ps4_pthread_mutexattr_getprotocol);
lib^.set_proc($E6DC4A7DC3140289,@ps4_pthread_mutexattr_setprotocol);
lib^.set_proc($FA6F3EAAEA8EC213,@ps4_pthread_mutexattr_getprioceiling);
lib^.set_proc($64BBDFEA55407383,@ps4_pthread_mutexattr_setprioceiling);
lib^.set_proc($B6D1CD7D4FAA0C15,@ps4_pthread_mutex_init);
lib^.set_proc($96D09F686AF62461,@ps4_pthread_mutex_destroy);
lib^.set_proc($EC7D224CE7224CBA,@ps4_pthread_mutex_lock);
lib^.set_proc($D99F8FA58E826898,@ps4_pthread_mutex_unlock);
lib^.set_proc($228F7E9D329766D0,@ps4_pthread_mutex_timedlock);
lib^.set_proc($2BF8D785BB76827E,@ps4_pthread_mutex_trylock);
lib^.set_proc($17C6D41F0006DBCE,@ps4_scePthreadMutexattrInit);
lib^.set_proc($B2658492D8B2C86D,@ps4_scePthreadMutexattrDestroy);
lib^.set_proc($82AB84841AD2DA2C,@ps4_scePthreadMutexattrGettype);
lib^.set_proc($88CA7C42913E5CEE,@ps4_scePthreadMutexattrSettype);
lib^.set_proc($1A84E615EBA2FA14,@ps4_scePthreadMutexattrGetprotocol);
lib^.set_proc($D451AF5348BDB1A4,@ps4_scePthreadMutexattrSetprotocol);
lib^.set_proc($4A08CCA721FD67D2,@ps4_scePthreadMutexattrGetprioceiling);
lib^.set_proc($E77D8869082EC0C8,@ps4_scePthreadMutexattrSetprioceiling);
lib^.set_proc($726A3544862F6BDA,@ps4_scePthreadMutexInit);
lib^.set_proc($D8E7F47FEDE68611,@ps4_scePthreadMutexDestroy);
lib^.set_proc($F542B5BCB6507EDE,@ps4_scePthreadMutexLock);
lib^.set_proc($21A7C8D8FC5C3E74,@ps4_scePthreadMutexTimedlock);
lib^.set_proc($B67DD5943D211BAD,@ps4_scePthreadMutexUnlock);
lib^.set_proc($BA9A15AF330715E1,@ps4_scePthreadMutexTrylock);
//mutex
//rwlock
lib^.set_proc($C4579BB00E18B052,@ps4_pthread_rwlockattr_init);
lib^.set_proc($AAC7668178EA4A09,@ps4_pthread_rwlockattr_destroy);
lib^.set_proc($97E6C6E5FB189218,@ps4_pthread_rwlockattr_gettype_np);
lib^.set_proc($F0DB8E1E24EBD55C,@ps4_pthread_rwlockattr_settype_np);
lib^.set_proc($56A10CB82BFFA876,@ps4_pthread_rwlockattr_getpshared);
lib^.set_proc($3AE2A0FA44430FB5,@ps4_pthread_rwlockattr_setpshared);
lib^.set_proc($CAD4142CDFE784BE,@ps4_pthread_rwlock_init);
lib^.set_proc($D78EF56A33F3C61D,@ps4_pthread_rwlock_destroy);
lib^.set_proc($8868ECAF5580B48D,@ps4_pthread_rwlock_rdlock);
lib^.set_proc($B08951BD0AAC3766,@ps4_pthread_rwlock_wrlock);
lib^.set_proc($485C5330E7EE0A41,@ps4_pthread_rwlock_tryrdlock);
lib^.set_proc($5E15879FA3F947B5,@ps4_pthread_rwlock_trywrlock);
lib^.set_proc($12098BA3A11682CA,@ps4_pthread_rwlock_unlock);
lib^.set_proc($E942C06B47EAE230,@ps4_scePthreadRwlockInit);
lib^.set_proc($041FA46F4F1397D0,@ps4_scePthreadRwlockDestroy);
lib^.set_proc($3B1F62D1CECBE70D,@ps4_scePthreadRwlockRdlock);
lib^.set_proc($9AA74DA2BAC1FA02,@ps4_scePthreadRwlockWrlock);
lib^.set_proc($5C3DE60DEC9B0A79,@ps4_scePthreadRwlockTryrdlock);
lib^.set_proc($6C81E86424E89AC2,@ps4_scePthreadRwlockTrywrlock);
lib^.set_proc($F8BF7C3C86C6B6D9,@ps4_scePthreadRwlockUnlock);
//rwlock
//Sema
lib^.set_proc($A43B8F11FDE6E1F2,@ps4_sem_init);
lib^.set_proc($7035B6DF7440C16A,@ps4_sem_destroy);
lib^.set_proc($06AF8B455FCDE879,@ps4_sem_getvalue);
lib^.set_proc($20A3FCB72A744149,@ps4_sem_post);
lib^.set_proc($C39207CAF6A183FA,@ps4_sem_timedwait);
lib^.set_proc($5815B3B1189F0840,@ps4_sem_trywait);
lib^.set_proc($602579746181702A,@ps4_sem_wait);
lib^.set_proc($D7CF31E7B258A748,@ps4_sceKernelCreateSema);
lib^.set_proc($47526F9FC6D2096F,@ps4_sceKernelDeleteSema);
lib^.set_proc($6716B45614154EC9,@ps4_sceKernelWaitSema);
lib^.set_proc($E1CCE9A47062AE2C,@ps4_sceKernelSignalSema);
lib^.set_proc($D76C0E1E4F32C1BD,@ps4_sceKernelPollSema);
lib^.set_proc($E03334E94D813446,@ps4_sceKernelCancelSema);
//Sema
//cond
lib^.set_proc($D13C959383122EDD,@ps4_pthread_cond_init);
lib^.set_proc($9A4C767D584D32C8,@ps4_pthread_cond_broadcast);
lib^.set_proc($9B9FF66EC35FBFBB,@ps4_scePthreadCondattrInit);
lib^.set_proc($C1A3DCC58891DD60,@ps4_scePthreadCondattrDestroy);
lib^.set_proc($D936FDDAABA9AE5D,@ps4_scePthreadCondInit);
lib^.set_proc($83E3D977686269C8,@ps4_scePthreadCondDestroy);
lib^.set_proc($90387F35FC6032D1,@ps4_scePthreadCondSignal);
lib^.set_proc($58A0172785C13D0E,@ps4_scePthreadCondWait);
lib^.set_proc($06632363199EC35C,@ps4_scePthreadCondTimedwait);
lib^.set_proc($246823ED4BEB97E0,@ps4_scePthreadCondBroadcast);
//cond
//thread
lib^.set_proc($9EC628351CB0C0D8,@ps4_scePthreadAttrInit);
lib^.set_proc($EB6282C04326CDC3,@ps4_scePthreadAttrDestroy);
lib^.set_proc($5135F325B5A18531,@ps4_scePthreadAttrSetstacksize);
lib^.set_proc($FD6ADEA6BB6ED10B,@ps4_scePthreadAttrSetdetachstate);
lib^.set_proc($E3E87D133C0A1782,@ps4_scePthreadAttrSetschedpolicy);
lib^.set_proc($0F3112F61405E1FE,@ps4_scePthreadAttrSetschedparam);
lib^.set_proc($DEAC603387B31130,@ps4_scePthreadAttrSetaffinity);
lib^.set_proc($7976D44A911A4EC0,@ps4_scePthreadAttrSetinheritsched);
lib^.set_proc($E9482DC15FB4CDBE,@ps4_scePthreadCreate);
lib^.set_proc($E2A1AB47A7A83FD6,@ps4_scePthreadDetach);
lib^.set_proc($A27358F41CA7FD6F,@ps4_scePthreadJoin);
lib^.set_proc($DE483BAD3D0D408B,@ps4_scePthreadExit);
lib^.set_proc($128B51F1ADC049FE,@ps4_pthread_self);
lib^.set_proc($688F8E782CFCC6B4,@ps4_scePthreadSelf);
lib^.set_proc($1E8C3B07C39EB7A9,@ps4_scePthreadGetname);
lib^.set_proc($181518EF2C1D50B1,@ps4_scePthreadRename);
lib^.set_proc($6EDDC24C12A61B22,@ps4_scePthreadSetaffinity);
lib^.set_proc($D6D2B21BB465309A,@ps4_scePthreadGetprio);
lib^.set_proc($5B41E99B65F4B8F1,@ps4_scePthreadSetprio);
lib^.set_proc($4FBDA1CFA7DFAB4F,@ps4_scePthreadYield);
//thread
lib^.set_proc($5AC95C2B51507062,@ps4_sceKernelIsNeoMode);
lib^.set_proc($A4EF7A4F0CCE9B91,@ps4_sceKernelGetDirectMemorySize);
lib^.set_proc($AD35F0EB9C662C80,@ps4_sceKernelAllocateDirectMemory);
lib^.set_proc($2FF4372C48C86E00,@ps4_sceKernelMapDirectMemory);
lib^.set_proc($98BF0D0C7F3A8902,@ps4_sceKernelMapNamedFlexibleMemory);
lib^.set_proc($21620105D4C78ADE,@ps4_sceKernelMapFlexibleMemory);
lib^.set_proc($71091EF54B8140E9,@ps4_sceKernelMunmap);
lib^.set_proc($58571F2F697389DA,@ps4_sceKernelQueryMemoryProtection);
//queue
lib^.set_proc($0F439D14C8E9E3A2,@ps4_sceKernelCreateEqueue);
lib^.set_proc($7F3C8C2ACF648A6D,@ps4_sceKernelWaitEqueue);
lib^.set_proc($BF3FA9836CDDA292,@ps4_sceKernelGetEventUserData);
//queue
//time
lib^.set_proc($9FCF2FC770B99D6F,@ps4_gettimeofday);
lib^.set_proc($94B313F6F240724D,@ps4_clock_gettime);
lib^.set_proc($D63DD2DE7FED4D6E,@ps4_sceKernelGetTscFrequency);
lib^.set_proc($FF62115023BFFCF3,@ps4_sceKernelReadTsc);
lib^.set_proc($4018BB1C22B4DE1C,@ps4_sceKernelClockGettime);
lib^.set_proc($E09DAC5099AE1D94,@ps4_sceKernelGetProcessTime);
lib^.set_proc($C92F14D931827B50,@ps4_nanosleep);
lib^.set_proc($41CB5E4706EC9D5D,@ps4_usleep);
lib^.set_proc($D637D72D15738AC7,@ps4_sceKernelUsleep);
//time
//file
lib^.set_proc($D46DE51751A0D64F,@ps4_sceKernelOpen);
lib^.set_proc($A226FBE85FF5D9F9,@ps4_sceKernelLseek);
lib^.set_proc($E304B37BDD8184B2,@ps4_sceKernelWrite);
lib^.set_proc($0A0E2CAD9E9329B5,@ps4_sceKernelRead);
lib^.set_proc($FABDEB305C08B55E,@ps4_sceKernelPread);
lib^.set_proc($50AD939760D6527B,@ps4_sceKernelClose);
lib^.set_proc($171559A81000EE4B,@ps4_write);
lib^.set_proc($0D1B81B76A6F2029,@ps4_read);
lib^.set_proc($D7F2C52E6445C713,@ps4_sceKernelMkdir);
lib^.set_proc($795F70003DAB8880,@ps4_sceKernelStat);
lib^.set_proc($13A6A8DF8C0FC3E5,@ps4_stat);
lib^.set_proc($246322A3EDB52F87,@ps4_mkdir);
//file
px:=Result._add_lib('libScePosix');
px^.MapSymbol:=lib^.MapSymbol;
end;
initialization
ps4_app.RegistredPreLoad('libSceLibcInternal.prx',@Load_libSceLibcInternal);
ps4_app.RegistredPreLoad('libSceSysmodule.prx',@Load_libSceSysmodule);
ps4_app.RegistredPreLoad('libkernel.prx',@Load_libkernel);
end.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,578 @@
unit ps4_mutex;
{$mode objfpc}{$H+}
interface
uses
Windows,
sysutils,
ps4_types;
type
Ppthread_mutex_attr=^pthread_mutex_attr_t;
pthread_mutex_attr_t=bitpacked record
_type:0..7; //3
_shared:0..1; //1
_protocol:0..3; //2
_align:0..67108863; //26
_prioceiling:Integer; //32
end;
Ppthread_mutex=^pthread_mutex;
pthread_mutex=^pthread_mutex_t;
pthread_mutex_t=packed record
valid:DWORD;
state:DWORD;
_type:DWORD;
rec_lock:DWORD;
owner:DWORD;
event:THandle;
name:array[0..31] of AnsiChar;
end;
ScePthreadMutex=pthread_mutex;
PScePthreadMutex=Ppthread_mutex;
const
SCE_PTHREAD_MUTEX_ERRORCHECK = 1; // Default POSIX mutex
SCE_PTHREAD_MUTEX_RECURSIVE = 2; // Recursive mutex
SCE_PTHREAD_MUTEX_NORMAL = 3; // No error checking
SCE_PTHREAD_MUTEX_ADAPTIVE = 4; // Adaptive mutex, spins briefly before blocking on lock
SCE_PTHREAD_MUTEX_DEFAULT = SCE_PTHREAD_MUTEX_ERRORCHECK;
PTHREAD_MUTEX_ERRORCHECK = SCE_PTHREAD_MUTEX_ERRORCHECK;
PTHREAD_MUTEX_RECURSIVE = SCE_PTHREAD_MUTEX_RECURSIVE;
PTHREAD_MUTEX_NORMAL = SCE_PTHREAD_MUTEX_NORMAL;
PTHREAD_MUTEX_ADAPTIVE = SCE_PTHREAD_MUTEX_ADAPTIVE;
PTHREAD_MUTEX_DEFAULT = SCE_PTHREAD_MUTEX_ERRORCHECK;{SCE_PTHREAD_MUTEX_RECURSIVE;}//PTHREAD_MUTEX_ERRORCHECK;
PTHREAD_PROCESS_PRIVATE=0;
PTHREAD_PROCESS_SHARED =1;
PTHREAD_PRIO_NONE =0;
PTHREAD_PRIO_INHERIT =1;
PTHREAD_PRIO_PROTECT =2;
PTHREAD_MUTEX_INITIALIZER =0;
PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP=1;
function ps4_pthread_mutexattr_init(pAttr:Ppthread_mutex_attr):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutexattr_destroy(pAttr:Ppthread_mutex_attr):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutexattr_gettype(pAttr:Ppthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutexattr_settype(pAttr:Ppthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutexattr_getpshared(pAttr:Ppthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutexattr_setpshared(pAttr:Ppthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutexattr_getprotocol(pAttr:Ppthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutexattr_setprotocol(pAttr:Ppthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutexattr_getprioceiling(pAttr:Ppthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutexattr_setprioceiling(pAttr:Ppthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutex_lock(pMutex:Ppthread_mutex):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutex_timedlock(pMutex:Ppthread_mutex;ts:Ptimespec):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutex_trylock(pMutex:Ppthread_mutex):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutex_unlock(pMutex:Ppthread_mutex):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutex_init(pMutex:Ppthread_mutex;pAttr:Ppthread_mutex_attr):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutex_destroy(pMutex:Ppthread_mutex):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexattrInit(pAttr:Ppthread_mutex_attr):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexattrDestroy(pAttr:Ppthread_mutex_attr):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexattrGettype(pAttr:Ppthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexattrSettype(pAttr:Ppthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexattrGetprotocol(pAttr:Ppthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexattrSetprotocol(pAttr:Ppthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexattrGetprioceiling(pAttr:Ppthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexattrSetprioceiling(pAttr:Ppthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexInit(pMutex:PScePthreadMutex;pAttr:Ppthread_mutex_attr;str:PChar):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexLock(pMutex:PScePthreadMutex):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexTimedlock(pMutex:PScePthreadMutex;usec:DWORD):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexTrylock(pMutex:PScePthreadMutex):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexUnlock(pMutex:PScePthreadMutex):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexDestroy(pMutex:PScePthreadMutex):Integer; SysV_ABI_CDecl;
//pthread_mutexattr_setkind_np
implementation
Uses
spinlock,
ps4_sema,
ps4_libkernel,
ps4_time;
function ps4_pthread_mutexattr_init(pAttr:Ppthread_mutex_attr):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(EINVAL);
pAttr^:=Default(pthread_mutex_attr_t);
pAttr^._type:=PTHREAD_MUTEX_DEFAULT;
Result:=0;
end;
function ps4_pthread_mutexattr_destroy(pAttr:Ppthread_mutex_attr):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(EINVAL);
Result:=0;
end;
function ps4_pthread_mutexattr_gettype(pAttr:Ppthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) or (t=nil) then Exit(EINVAL);
t^:=pAttr^._type;
Result:=0;
end;
function ps4_pthread_mutexattr_settype(pAttr:Ppthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(EINVAL);
Case t of
PTHREAD_MUTEX_ERRORCHECK:;
PTHREAD_MUTEX_RECURSIVE :;
PTHREAD_MUTEX_NORMAL :;
PTHREAD_MUTEX_ADAPTIVE :;
else
Exit(EINVAL);
end;
pAttr^._type:=t;
Result:=0;
end;
function ps4_pthread_mutexattr_getpshared(pAttr:Ppthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) or (t=nil) then Exit(EINVAL);
t^:=pAttr^._shared;
Result:=0;
end;
function ps4_pthread_mutexattr_setpshared(pAttr:Ppthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(EINVAL);
Case t of
PTHREAD_PROCESS_PRIVATE:;
PTHREAD_PROCESS_SHARED :;
else
Exit(EINVAL);
end;
pAttr^._shared:=t;
Result:=0;
end;
function ps4_pthread_mutexattr_getprotocol(pAttr:Ppthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) or (t=nil) then Exit(EINVAL);
t^:=pAttr^._protocol;
Result:=0;
end;
function ps4_pthread_mutexattr_setprotocol(pAttr:Ppthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(EINVAL);
Case t of
PTHREAD_PRIO_NONE :;
PTHREAD_PRIO_INHERIT:;
PTHREAD_PRIO_PROTECT:;
else
Exit(EINVAL);
end;
pAttr^._protocol:=t;
Result:=0;
end;
function ps4_pthread_mutexattr_getprioceiling(pAttr:Ppthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) or (t=nil) then Exit(EINVAL);
t^:=pAttr^._prioceiling;
Result:=0;
end;
function ps4_pthread_mutexattr_setprioceiling(pAttr:Ppthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(EINVAL);
pAttr^._prioceiling:=t;
Result:=0;
end;
///////////////////////////
Const
LIFE_MUTEX=$BAB1F00D;
DEAD_MUTEX=$DEADBEEF;
MS_Unlocked=0;
MS_Locked =1;
MS_Waiting =2;
function STATIC_INITIALIZER(m:pthread_mutex):Boolean; inline;
begin
Result:=False;
Case PtrUInt(m) of
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP:Result:=True;
end;
end;
function CAS(Var addr:Pointer;Comp,New:Pointer):Boolean; inline;
begin
Result:=System.InterlockedCompareExchange(addr,New,Comp)=Comp;
end;
function CAS(Var addr:SizeUInt;Comp,New:SizeUInt):Boolean; inline;
begin
Result:=system.InterlockedCompareExchange(Pointer(addr),Pointer(New),Pointer(Comp))=Pointer(Comp);
end;
function CAS(Var addr:DWORD;Comp,New:DWORD):Boolean; inline;
begin
Result:=System.InterlockedCompareExchange(addr,New,Comp)=Comp;
end;
function XCHG(Var addr:Pointer;New:Pointer):Pointer; inline;
begin
Result:=System.InterLockedExchange(addr,New);
end;
function XCHG(Var addr:DWORD;New:DWORD):DWORD; inline;
begin
Result:=System.InterLockedExchange(addr,New);
end;
function mutex_impl_init(m:Ppthread_mutex;mi:pthread_mutex;_type:Integer):pthread_mutex;
var
new_mi:pthread_mutex;
begin
new_mi:=AllocMem(SizeOf(pthread_mutex_t));
if (new_mi=nil) then Exit(new_mi);
new_mi^.valid:=LIFE_MUTEX;
new_mi^.state:=MS_Unlocked;
new_mi^._type:=_type;
new_mi^.owner:=DWORD(-1);
if CAS(m^,mi,new_mi) then
begin
Result:=new_mi;
end else
begin
FreeMem(new_mi);
Result:=m^;
end;
end;
function mutex_impl(m:Ppthread_mutex;var mi:pthread_mutex;default:Integer):Integer;
begin
if (m=nil) then Exit(EINVAL);
mi:=m^;
Case PtrUInt(mi) of
PTHREAD_MUTEX_INITIALIZER :mi:=mutex_impl_init(m,mi,default);
PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP:mi:=mutex_impl_init(m,mi,PTHREAD_MUTEX_ADAPTIVE);
end;
if (mi=nil) then Exit(ENOMEM);
if (mi^.valid<>LIFE_MUTEX) then Exit(EINVAL);
Result:=0;
end;
function pthread_mutex_lock_intern(m:Ppthread_mutex;timeout:DWORD;default:Integer):Integer;
var
mi:pthread_mutex;
old_state:DWORD;
ev:THandle;
begin
Result:=mutex_impl(m,mi,default);
if (Result<>0) then Exit;
old_state:=XCHG(mi^.state,MS_Locked);
if (old_state<>MS_Unlocked) then
begin
if (mi^._type<>PTHREAD_MUTEX_NORMAL) then
if (mi^.owner=GetCurrentThreadId) then
begin
CAS(mi^.state,MS_Locked,old_state);
if (mi^._type=PTHREAD_MUTEX_RECURSIVE) then
begin
Inc(mi^.rec_lock);
Exit(0);
end else
begin
Exit(EDEADLK);
end;
end;
if (mi^.event=0) then
begin
ev:=CreateEvent(nil,false,false,nil);
if (ev=0) then
Case GetLastError of
ERROR_ACCESS_DENIED:Exit(EPERM);
else
Exit(EPERM);
end;
if not CAS(mi^.event,0,ev) then
begin
CloseHandle(ev);
end;
end;
While (XCHG(mi^.state,MS_Waiting)<>MS_Unlocked) do
begin
Result:=do_sema_b_wait_intern(mi^.event,timeout);
if (Result<>0) then Exit;
end;
end;
if (mi^._type<>PTHREAD_MUTEX_NORMAL) then
begin
mi^.owner:=GetCurrentThreadId;
end;
Result:=0;
end;
function ps4_pthread_mutex_lock(pMutex:Ppthread_mutex):Integer; SysV_ABI_CDecl;
begin
Result:=pthread_mutex_lock_intern(pMutex,INFINITE,PTHREAD_MUTEX_DEFAULT);
end;
function ps4_pthread_mutex_timedlock(pMutex:Ppthread_mutex;ts:Ptimespec):Integer; SysV_ABI_CDecl;
var
t:DWORD;
begin
if (ts=nil) then
begin
t:=INFINITE;
end else
begin
t:=dwMilliSecs(_pthread_rel_time_in_ms(ts^));
end;
Result:=pthread_mutex_lock_intern(pMutex,t,PTHREAD_MUTEX_DEFAULT);
end;
function pthread_mutex_unlock(m:Ppthread_mutex;default:Integer):Integer;
var
mi:pthread_mutex;
begin
Result:=mutex_impl(m,mi,default);
if (Result<>0) then Exit;
if (mi^._type<>PTHREAD_MUTEX_NORMAL) then
begin
if (mi^.state=MS_Unlocked) then Exit(EPERM);
if (mi^.owner<>GetCurrentThreadId) then Exit(EPERM);
if (mi^.rec_lock>0) then
begin
Dec(mi^.rec_lock);
Exit(0);
end;
mi^.owner:=DWORD(-1);
end;
if XCHG(mi^.state,MS_Unlocked)=MS_Waiting then
begin
if not SetEvent(mi^.event) then Exit(EPERM);
end;
Result:=0;
end;
function ps4_pthread_mutex_unlock(pMutex:Ppthread_mutex):Integer; SysV_ABI_CDecl;
begin
Result:=pthread_mutex_unlock(pMutex,PTHREAD_MUTEX_DEFAULT);
end;
function pthread_mutex_trylock(m:Ppthread_mutex;default:Integer):Integer;
var
mi:pthread_mutex;
begin
Result:=mutex_impl(m,mi,default);
if (Result<>0) then Exit;
if CAS(mi^.state,MS_Unlocked,MS_Locked) then
begin
if (mi^._type<>PTHREAD_MUTEX_NORMAL) then
begin
mi^.owner:=GetCurrentThreadId;
end;
Exit(0);
end else
begin
if (mi^._type=PTHREAD_MUTEX_RECURSIVE) and (mi^.owner=GetCurrentThreadId) then
begin
Inc(mi^.rec_lock);
Exit(0);
end;
Exit(EBUSY);
end;
end;
function ps4_pthread_mutex_trylock(pMutex:Ppthread_mutex):Integer; SysV_ABI_CDecl;
begin
Result:=pthread_mutex_trylock(pMutex,PTHREAD_MUTEX_DEFAULT);
end;
function pthread_mutex_init(m:Ppthread_mutex;a:Ppthread_mutex_attr;str:PChar;default:Integer):Integer;
var
mi:pthread_mutex;
begin
if (m=nil) then Exit(EINVAL);
mi:=m^;
if (a<>nil) then
begin
mi:=mutex_impl_init(m,mi,a^._type);
end else
begin
mi:=mutex_impl_init(m,mi,default);
end;
if (mi=nil) then Exit(ENOMEM);
if (mi^.valid<>LIFE_MUTEX) then Exit(EINVAL);
if (str<>nil) then MoveChar0(str^,mi^.name,32);
Result:=0;
end;
function ps4_pthread_mutex_init(pMutex:Ppthread_mutex;pAttr:Ppthread_mutex_attr):Integer; SysV_ABI_CDecl;
begin
Result:=pthread_mutex_init(pMutex,pAttr,nil,PTHREAD_MUTEX_DEFAULT);
end;
function pthread_mutex_destroy(m:Ppthread_mutex):Integer;
var
mi:pthread_mutex;
begin
if (m=nil) then Exit(EINVAL);
mi:=m^;
if not STATIC_INITIALIZER(mi) then
begin
mi:=XCHG(m^,nil);
if STATIC_INITIALIZER(mi) then Exit(0);
if not CAS(mi^.valid,LIFE_MUTEX,DEAD_MUTEX) then Exit(EINVAL);
if (mi^.event<>0) then CloseHandle(mi^.event);
FreeMem(mi);
end;
Result:=0;
end;
function ps4_pthread_mutex_destroy(pMutex:Ppthread_mutex):Integer; SysV_ABI_CDecl;
begin
Result:=pthread_mutex_destroy(pMutex);
end;
//---------------------------------------------------------
//sce
function ps4_scePthreadMutexattrInit(pAttr:Ppthread_mutex_attr):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
pAttr^:=Default(pthread_mutex_attr_t);
pAttr^._type:=SCE_PTHREAD_MUTEX_DEFAULT;
Result:=0;
end;
function ps4_scePthreadMutexattrDestroy(pAttr:Ppthread_mutex_attr):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
Result:=0;
end;
function ps4_scePthreadMutexattrGettype(pAttr:Ppthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) or (t=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
t^:=pAttr^._type;
Result:=0;
end;
function ps4_scePthreadMutexattrSettype(pAttr:Ppthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
Case t of
SCE_PTHREAD_MUTEX_ERRORCHECK:;
SCE_PTHREAD_MUTEX_RECURSIVE :;
SCE_PTHREAD_MUTEX_NORMAL :;
SCE_PTHREAD_MUTEX_ADAPTIVE :;
else
Exit(SCE_KERNEL_ERROR_EINVAL);
end;
pAttr^._type:=t;
Result:=0;
end;
function ps4_scePthreadMutexattrGetprotocol(pAttr:Ppthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) or (t=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
t^:=pAttr^._protocol;
Result:=0;
end;
function ps4_scePthreadMutexattrSetprotocol(pAttr:Ppthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
Case t of
PTHREAD_PRIO_NONE :;
PTHREAD_PRIO_INHERIT:;
PTHREAD_PRIO_PROTECT:;
else
Exit(SCE_KERNEL_ERROR_EINVAL);
end;
pAttr^._protocol:=t;
Result:=0;
end;
function ps4_scePthreadMutexattrGetprioceiling(pAttr:Ppthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) or (t=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
t^:=pAttr^._prioceiling;
Result:=0;
end;
function ps4_scePthreadMutexattrSetprioceiling(pAttr:Ppthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
pAttr^._prioceiling:=t;
Result:=0;
end;
//////////////
function ps4_scePthreadMutexLock(pMutex:Ppthread_mutex):Integer; SysV_ABI_CDecl;
begin
//Writeln('scePthreadMutexLock:',HexStr(pMutex));
Result:=px2sce(pthread_mutex_lock_intern(pMutex,INFINITE,SCE_PTHREAD_MUTEX_DEFAULT));
//if (Result<>0) then Writeln('scePthreadMutexLock:',HexStr(pMutex),':',HexStr(Result,8));
end;
function ps4_scePthreadMutexTimedlock(pMutex:PScePthreadMutex;usec:DWORD):Integer; SysV_ABI_CDecl;
begin
//Writeln('scePthreadMutexTimedlock:',HexStr(pMutex));
Result:=px2sce(pthread_mutex_lock_intern(pMutex,_usec2msec(usec),SCE_PTHREAD_MUTEX_DEFAULT));
//if (Result<>0) then Writeln('scePthreadMutexTimedlock:',HexStr(pMutex),':',HexStr(Result,8));
end;
function ps4_scePthreadMutexUnlock(pMutex:Ppthread_mutex):Integer; SysV_ABI_CDecl;
begin
//Writeln('scePthreadMutexUnlock:',HexStr(pMutex));
Result:=px2sce(pthread_mutex_unlock(pMutex,SCE_PTHREAD_MUTEX_DEFAULT));
//if (Result<>0) then Writeln('scePthreadMutexUnlock:',HexStr(pMutex),':',pMutex^^.name,':',HexStr(Result,8));
end;
function ps4_scePthreadMutexTrylock(pMutex:Ppthread_mutex):Integer; SysV_ABI_CDecl;
begin
//Writeln('scePthreadMutexTrylock:',HexStr(pMutex));
Result:=px2sce(pthread_mutex_trylock(pMutex,SCE_PTHREAD_MUTEX_DEFAULT));
//if (Result<>0) then Writeln('scePthreadMutexTrylock:',HexStr(pMutex),':',HexStr(Result,8));
end;
function ps4_scePthreadMutexInit(pMutex:PScePthreadMutex;pAttr:Ppthread_mutex_attr;str:PChar):Integer; SysV_ABI_CDecl;
begin
//if str='NP CVariable Mutex' then
// writeln;
Result:=px2sce(pthread_mutex_init(pMutex,pAttr,str,SCE_PTHREAD_MUTEX_DEFAULT));
end;
function ps4_scePthreadMutexDestroy(pMutex:Ppthread_mutex):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(pthread_mutex_destroy(pMutex));
end;
end.

View File

@ -0,0 +1,500 @@
unit ps4_pthread;
{$mode objfpc}{$H+}
interface
uses
windows,
Classes, SysUtils;
type
Ppthread_attr_t=^pthread_attr_t;
pthread_attr_t=^tthread_attr_t;
tthread_attr_t=packed record
policy:Integer;
sched_priority:Integer;
//prio :Integer;
suspend :Integer;
flags :Integer;
stackaddr_attr:Pointer;
stacksize_attr:size_t;
cpuset:QWORD;
//guardsize_attr:size_t;
//cpuset :Pointer;//cpuset_t
//cpusetsize :size_t;
detachstate:Integer;
end;
Ppthread=^pthread;
pthread=^pthread_t;
pthread_t=record
entry:Pointer;
arg:Pointer;
handle:TThreadID;
detachstate:Integer;
name:array[0..31] of AnsiChar;
end;
const
//Run-time invariant values:
PTHREAD_STACK_MIN=4*1024;
PTHREAD_DETACHED =$1;
PTHREAD_SCOPE_SYSTEM =$2;
PTHREAD_INHERIT_SCHED=$4;
PTHREAD_NOFLOAT =$8;
PTHREAD_CREATE_DETACHED=PTHREAD_DETACHED;
PTHREAD_CREATE_JOINABLE=0;
SCE_PTHREAD_DESTRUCTOR_ITERATIONS =4;
SCE_PTHREAD_KEYS_MAX =256;
SCE_PTHREAD_STACK_MIN =PTHREAD_STACK_MIN;
SCE_PTHREAD_THREADS_MAX =High(DWORD);
SCE_PTHREAD_BARRIER_SERIAL_THREAD =-1;
//Flags for threads and thread attributes.
SCE_PTHREAD_DETACHED =$1;
SCE_PTHREAD_INHERIT_SCHED =$4;
SCE_PTHREAD_NOFLOAT =$8;
SCE_PTHREAD_CREATE_DETACHED =SCE_PTHREAD_DETACHED;
SCE_PTHREAD_CREATE_JOINABLE =0;
SCE_PTHREAD_EXPLICIT_SCHED =0;
//Flags for read/write lock attributes
SCE_PTHREAD_PROCESS_PRIVATE =0;
SCE_PTHREAD_PROCESS_SHARED =1;
const
//POSIX scheduling policies
SCHED_FIFO =1;
SCHED_OTHER =2;
SCHED_RR =3;
// for sceKernelMsync()
SCE_KERNEL_MS_SYNC =$0;
SCE_KERNEL_MS_ASYNC =$1;
SCE_KERNEL_MS_INVALIDATE =$2;
// for sceKernelSchedGetPriorityMax()/Min()
SCE_KERNEL_SCHED_FIFO =SCHED_FIFO;
SCE_KERNEL_SCHED_RR =SCHED_RR;
SCE_KERNEL_PRIO_FIFO_DEFAULT =700;
SCE_KERNEL_PRIO_FIFO_HIGHEST =256;
SCE_KERNEL_PRIO_FIFO_LOWEST =767;
// for SceKernelCpumask
SCE_KERNEL_CPUMASK_6CPU_ALL =$3f;
SCE_KERNEL_CPUMASK_7CPU_ALL =$7f;
SCE_KERNEL_CPUMASK_USER_ALL =$3f; // obsolete
procedure ps4_pthread_cxa_finalize(P:Pointer); SysV_ABI_CDecl;
function ps4_scePthreadAttrInit(pAttr:Ppthread_attr_t):Integer; SysV_ABI_CDecl;
function ps4_scePthreadAttrDestroy(pAttr:Ppthread_attr_t):Integer; SysV_ABI_CDecl;
function ps4_scePthreadAttrSetstacksize(pAttr:Ppthread_attr_t;size:size_t):Integer; SysV_ABI_CDecl;
function ps4_scePthreadAttrSetdetachstate(pAttr:Ppthread_attr_t;detachstate:Integer):Integer; SysV_ABI_CDecl;
function ps4_scePthreadAttrSetschedpolicy(pAttr:Ppthread_attr_t;policy:Integer):Integer; SysV_ABI_CDecl;
function ps4_scePthreadAttrSetschedparam(pAttr:Ppthread_attr_t;param:PInteger):Integer; SysV_ABI_CDecl;
function ps4_scePthreadAttrSetaffinity(pAttr:Ppthread_attr_t;mask:QWORD):Integer; SysV_ABI_CDecl;
function ps4_scePthreadAttrSetinheritsched(pAttr:Ppthread_attr_t;inheritSched:Integer):Integer; SysV_ABI_CDecl;
function ps4_scePthreadCreate(pthread:Ppthread;pAttr:Ppthread_attr_t;entry:Pointer;arg:Pointer;name:Pchar):Integer; SysV_ABI_CDecl;
function ps4_scePthreadDetach(_pthread:pthread):Integer; SysV_ABI_CDecl;
function ps4_scePthreadJoin(_pthread:pthread;value:PPointer):Integer; SysV_ABI_CDecl;
procedure ps4_scePthreadExit(value_ptr:Pointer); SysV_ABI_CDecl;
function ps4_pthread_self():pthread; SysV_ABI_CDecl;
function ps4_scePthreadSelf():pthread; SysV_ABI_CDecl;
function ps4_scePthreadGetname(_pthread:pthread;name:Pchar):Integer; SysV_ABI_CDecl;
function ps4_scePthreadRename(_pthread:pthread;name:Pchar):Integer; SysV_ABI_CDecl;
function ps4_scePthreadSetaffinity(_pthread:pthread;mask:QWORD):Integer; SysV_ABI_CDecl;
function ps4_scePthreadGetprio(_pthread:pthread;prio:PInteger):Integer; SysV_ABI_CDecl;
function ps4_scePthreadSetprio(_pthread:pthread;prio:Integer):Integer; SysV_ABI_CDecl;
procedure ps4_scePthreadYield(); SysV_ABI_CDecl;
procedure _pthread_run_entry(pthread:Ppthread);
implementation
uses
ps4_map_mm,
ps4_program,
ps4_elf,
ps4_libkernel;
//struct dl_phdr_info
procedure ps4_pthread_cxa_finalize(P:Pointer); SysV_ABI_CDecl;
begin
Writeln('__pthread_cxa_finalize');
end;
function ps4_scePthreadAttrInit(pAttr:Ppthread_attr_t):Integer; SysV_ABI_CDecl;
begin
Writeln('scePthreadAttrInit');
Result:=SCE_KERNEL_ERROR_EINVAL;
if (pAttr=nil) then Exit;
pAttr^:=AllocMem(SizeOf(tthread_attr_t));
Result:=0;
end;
function ps4_scePthreadAttrDestroy(pAttr:Ppthread_attr_t):Integer; SysV_ABI_CDecl;
begin
Writeln('scePthreadAttrDestroy');
Result:=SCE_KERNEL_ERROR_EINVAL;
if (pAttr=nil) then Exit;
FreeMem(System.InterlockedExchange(pAttr^,nil));
Result:=0;
end;
function ps4_scePthreadAttrSetstacksize(pAttr:Ppthread_attr_t;size:size_t):Integer; SysV_ABI_CDecl;
begin
Result:=SCE_KERNEL_ERROR_EINVAL;
if (pAttr=nil) then Exit;
if (pAttr^=nil) then Exit;
pAttr^^.stacksize_attr:=size;
Result:=0;
end;
function ps4_scePthreadAttrSetdetachstate(pAttr:Ppthread_attr_t;detachstate:Integer):Integer; SysV_ABI_CDecl;
begin
Result:=SCE_KERNEL_ERROR_EINVAL;
if (pAttr=nil) then Exit;
if (pAttr^=nil) then Exit;
Case detachstate of
PTHREAD_CREATE_JOINABLE:;
PTHREAD_CREATE_DETACHED:;
else
Exit(SCE_KERNEL_ERROR_EINVAL);
end;
pAttr^^.detachstate:=detachstate;
Result:=0;
end;
function ps4_scePthreadAttrSetschedpolicy(pAttr:Ppthread_attr_t;policy:Integer):Integer; SysV_ABI_CDecl;
begin
Result:=SCE_KERNEL_ERROR_EINVAL;
if (pAttr=nil) then Exit;
if (pAttr^=nil) then Exit;
pAttr^^.policy:=policy;
Result:=0;
end;
function ps4_scePthreadAttrSetschedparam(pAttr:Ppthread_attr_t;param:PInteger):Integer; SysV_ABI_CDecl;
begin
Result:=SCE_KERNEL_ERROR_EINVAL;
if (pAttr=nil) or (param=nil) then Exit;
if (pAttr^=nil) then Exit;
pAttr^^.sched_priority:=param^;
Result:=0;
end;
function ps4_scePthreadAttrSetaffinity(pAttr:Ppthread_attr_t;mask:QWORD):Integer; SysV_ABI_CDecl;
begin
Result:=SCE_KERNEL_ERROR_EINVAL;
if (pAttr=nil) then Exit;
if (pAttr^=nil) then Exit;
pAttr^^.cpuset:=mask;
Result:=0;
end;
function ps4_scePthreadAttrSetinheritsched(pAttr:Ppthread_attr_t;inheritSched:Integer):Integer; SysV_ABI_CDecl;
begin
Result:=0;
end;
function CAS(Var addr:Integer;Comp,New:Integer):Boolean; inline;
begin
Result:=System.InterlockedCompareExchange(addr,New,Comp)=Comp;
end;
procedure _free_pthread(data:pthread);
begin
System.CloseThread(data^.handle);
FreeMem(data);
end;
threadvar
_pthread_self:pthread;
function on_ps4_run_entry(data:pthread):ptrint;
type
Tps4entry=function(arg:Pointer):Pointer; SysV_ABI_CDecl;
begin
Result:=0;
RegistredStack;
ps4_app.InitThread;
While (System.InterLockedExchangeAdd(data^.handle,0)=0) do System.ThreadSwitch;
_pthread_self:=data;
ps4_app.InitCode;
Telf_file(ps4_app.prog).mapCodeEntry;
ps4_app.FreeThread;
UnRegistredStack;
end;
procedure _pthread_run_entry(pthread:Ppthread);
Var
data:pthread;
Handle,ThreadId:TThreadID;
begin
if (pthread=nil) then Exit;
data:=AllocMem(SizeOf(pthread_t));
if (data=nil) then Exit;
ThreadId:=0;
Handle:=BeginThread(TThreadFunc(@on_ps4_run_entry),data,ThreadId);
if (Handle=0) then
begin
FreeMem(data);
Exit;
end;
System.InterlockedExchange(data^.handle,Handle);
pthread^:=data;
end;
const
_PREPARE_FREE=2;
_PREPARE_JOIN=3;
function on_ps4_run_thread(data:pthread):ptrint;
type
Tps4entry=function(arg:Pointer):Pointer; SysV_ABI_CDecl;
begin
Result:=0;
ReadBarrier;
if (data<>nil) and (data^.entry<>nil) then
begin
writeln('BeginThread:',data^.name,':',HexStr(data^.entry));
RegistredStack;
ps4_app.InitThread;
While (System.InterLockedExchangeAdd(data^.handle,0)=0) do System.ThreadSwitch;
_pthread_self:=data;
data^.arg:=Tps4entry(data^.entry)(data^.arg);
ReadWriteBarrier;
ps4_app.FreeThread;
UnRegistredStack;
writeln('EndThread:',data^.name);
if CAS(data^.detachstate,PTHREAD_CREATE_DETACHED,_PREPARE_FREE) then
begin
_free_pthread(data);
end else
begin
CAS(data^.detachstate,PTHREAD_CREATE_JOINABLE,_PREPARE_JOIN);
end;
end;
end;
//typedef pthread_t ScePthread;
function ps4_scePthreadCreate(pthread:Ppthread;pAttr:Ppthread_attr_t;entry:Pointer;arg:Pointer;name:Pchar):Integer; SysV_ABI_CDecl;
Var
data:pthread;
Handle,ThreadId:TThreadID;
sa:Pointer;
ss:SizeUInt;
creationFlags:dword;
begin
Writeln('scePthreadCreate:',HexStr(entry),' ',name);
Result:=SCE_KERNEL_ERROR_EINVAL;
if (pthread=nil) then Exit;
//if {false} name='AudioOutThread' then
//if (name='streamThread') or (name='AudioOutThread') then
//if false then
begin
data:=AllocMem(SizeOf(pthread_t));
if (data=nil) then Exit(SCE_KERNEL_ERROR_ENOMEM);
data^.entry:=entry;
data^.arg:=arg;
if (name<>nil) then MoveChar0(name^,data^.name,32);
ReadWriteBarrier;
if (pAttr<>nil) and (pAttr^<>nil) then
begin
data^.detachstate:=pAttr^^.detachstate;
ReadWriteBarrier;
creationFlags:=0;
sa:=pAttr^^.stackaddr_attr;
ss:=pAttr^^.stacksize_attr;
if (ss<DefaultStackSize) then ss:=DefaultStackSize;
ThreadId:=0;
Handle:=BeginThread(sa,ss,TThreadFunc(@on_ps4_run_thread),data,creationFlags,ThreadId);
if (Handle=0) then
begin
FreeMem(data);
Exit(SCE_KERNEL_ERROR_EAGAIN);
end;
if (pAttr^^.cpuset<>0) then
begin
SetThreadAffinityMask(Handle,pAttr^^.cpuset);
end;
end else
begin
ThreadId:=0;
Handle:=BeginThread(TThreadFunc(@on_ps4_run_thread),data,ThreadId);
if (Handle=0) then
begin
FreeMem(data);
Exit(SCE_KERNEL_ERROR_EAGAIN);
end;
end;
System.InterlockedExchange(data^.handle,Handle);
pthread^:=data;
end;
Result:=0;
end;
function ps4_scePthreadDetach(_pthread:pthread):Integer; SysV_ABI_CDecl;
begin
if (_pthread=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
Writeln('scePthreadDetach:',_pthread^.name);
if CAS(_pthread^.detachstate,PTHREAD_CREATE_JOINABLE,PTHREAD_CREATE_DETACHED) then
begin
Result:=0
end else
if CAS(_pthread^.detachstate,_PREPARE_JOIN,_PREPARE_FREE) then
begin
_free_pthread(_pthread);
Result:=0
end else
begin
Result:=SCE_KERNEL_ERROR_EINVAL;
end;
end;
function ps4_scePthreadJoin(_pthread:pthread;value:PPointer):Integer; SysV_ABI_CDecl;
begin
if (_pthread=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
Writeln('scePthreadJoin:',_pthread^.name);
if CAS(_pthread^.detachstate,PTHREAD_CREATE_JOINABLE,_PREPARE_FREE) then
begin
System.WaitForThreadTerminate(_pthread^.handle,INFINITE);
if (value<>nil) then value^:=_pthread^.arg;
_free_pthread(_pthread);
Result:=0;
end else
if CAS(_pthread^.detachstate,_PREPARE_JOIN,_PREPARE_FREE) then
begin
if (value<>nil) then value^:=_pthread^.arg;
_free_pthread(_pthread);
Result:=0;
end else
begin
Result:=SCE_KERNEL_ERROR_EINVAL;
end;
end;
procedure ps4_scePthreadExit(value_ptr:Pointer); SysV_ABI_CDecl;
var
data:pthread;
begin
data:=_pthread_self;
if (data=nil) then Exit;
Writeln('ExitThread:',data^.name);
data^.arg:=value_ptr;
ReadWriteBarrier;
ps4_app.FreeThread;
UnRegistredStack;
if CAS(data^.detachstate,PTHREAD_CREATE_DETACHED,_PREPARE_FREE) then
begin
_free_pthread(data);
end else
begin
CAS(data^.detachstate,PTHREAD_CREATE_JOINABLE,_PREPARE_JOIN);
end;
System.EndThread(0);
end;
function ps4_pthread_self():pthread; SysV_ABI_CDecl;
begin
Result:=_pthread_self;
end;
function ps4_scePthreadSelf():pthread; SysV_ABI_CDecl;
begin
Result:=_pthread_self;
end;
function ps4_scePthreadGetname(_pthread:pthread;name:Pchar):Integer; SysV_ABI_CDecl;
begin
if (_pthread=nil) or (name=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
MoveChar0(_pthread^.name,name^,32);
end;
function ps4_scePthreadRename(_pthread:pthread;name:Pchar):Integer; SysV_ABI_CDecl;
begin
if (_pthread=nil) or (name=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
MoveChar0(name^,_pthread^.name,32);
end;
function ps4_scePthreadSetaffinity(_pthread:pthread;mask:QWORD):Integer; SysV_ABI_CDecl;
begin
if (_pthread=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
Result:=0;
SetThreadAffinityMask(_pthread^.handle,mask);
end;
//ThreadGetPriority = -15 and 15. :0..30
//scePthreadGetprio = 767 and 256 :0..511
function ps4_scePthreadGetprio(_pthread:pthread;prio:PInteger):Integer; SysV_ABI_CDecl;
Var
r:Integer;
begin
if (_pthread=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
if (prio=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
r:=System.ThreadGetPriority(_pthread^.handle);
prio^:=767-(((r+15)*511) div 30);
Result:=0;
end;
function ps4_scePthreadSetprio(_pthread:pthread;prio:Integer):Integer; SysV_ABI_CDecl;
Var
r:Integer;
begin
if (_pthread=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
if (prio>767) then prio:=767;
if (prio<256) then prio:=256;
//Writeln('scePthreadSetprio:',prio);
r:=(((767-prio)*30) div 511)-15;
Result:=0;
if not System.ThreadSetPriority(_pthread^.handle,r) then Result:=SCE_KERNEL_ERROR_ESRCH;
end;
procedure ps4_scePthreadYield(); SysV_ABI_CDecl;
begin
System.ThreadSwitch;
end;
end.

View File

@ -0,0 +1,368 @@
unit ps4_queue;
{$mode objfpc}{$H+}
interface
uses
windows,
Classes, SysUtils;
const
EVFILT_READ =(-1) ;
EVFILT_WRITE =(-2) ;
EVFILT_AIO =(-3) ; // attached to aio requests
EVFILT_VNODE =(-4) ; // attached to vnodes
EVFILT_PROC =(-5) ; // attached to struct proc
EVFILT_SIGNAL =(-6) ; // attached to struct proc
EVFILT_TIMER =(-7) ; // timers
EVFILT_FS =(-9) ; // filesystem events
EVFILT_LIO =(-10); // attached to lio requests
EVFILT_USER =(-11); // User events
EVFILT_POLLING =(-12);
EVFILT_DISPLAY =(-13);
EVFILT_GRAPHICS_CORE =(-14);
EVFILT_HRTIMER =(-15);
EVFILT_UVD_TRAP =(-16);
EVFILT_VCE_TRAP =(-17);
EVFILT_SDMA_TRAP =(-18);
EVFILT_REG_EV =(-19);
EVFILT_GPU_EXCEPTION =(-20);
EVFILT_GPU_SYSTEM_EXCEPTION=(-21);
EVFILT_GPU_DBGGC_EV =(-22);
EVFILT_SYSCOUNT =(22) ;
// actions
EV_ADD =$0001; // add event to kq (implies enable)
EV_DELETE =$0002; // delete event from kq
EV_ENABLE =$0004; // enable event
EV_DISABLE =$0008; // disable event (not reported)
// flags
EV_ONESHOT =$0010; // only report one occurrence
EV_CLEAR =$0020; // clear event state after reporting
EV_RECEIPT =$0040; // force EV_ERROR on success, data=0
EV_DISPATCH =$0080; // disable event after reporting
EV_SYSFLAGS =$F000; // reserved by system
EV_FLAG1 =$2000; // filter-specific flag
// returned values
EV_EOF =$8000; // EOF detected
EV_ERROR =$4000; // error, data contains errno
NOTE_DELETE =$0001; // vnode was removed
NOTE_WRITE =$0002; // data contents changed
NOTE_EXTEND =$0004; // size increased
NOTE_ATTRIB =$0008; // attributes changed
NOTE_LINK =$0010; // link count changed
NOTE_RENAME =$0020; // vnode was renamed
NOTE_REVOKE =$0040; // vnode access was revoked
SCE_KERNEL_EVFILT_TIMER =EVFILT_TIMER ;
SCE_KERNEL_EVFILT_READ =EVFILT_READ ;
SCE_KERNEL_EVFILT_WRITE =EVFILT_WRITE ;
SCE_KERNEL_EVFILT_USER =EVFILT_USER ;
SCE_KERNEL_EVFILT_FILE =EVFILT_VNODE ;
SCE_KERNEL_EVFILT_GNM =EVFILT_GRAPHICS_CORE;
SCE_KERNEL_EVFILT_VIDEO_OUT =EVFILT_DISPLAY ;
SCE_KERNEL_EVFILT_HRTIMER =EVFILT_HRTIMER ;
SCE_KERNEL_EVNOTE_DELETE =NOTE_DELETE ;
SCE_KERNEL_EVNOTE_WRITE =NOTE_WRITE ;
SCE_KERNEL_EVNOTE_EXTEND =NOTE_EXTEND ;
SCE_KERNEL_EVNOTE_ATTRIB =NOTE_ATTRIB ;
SCE_KERNEL_EVNOTE_RENAME =NOTE_RENAME ;
SCE_KERNEL_EVNOTE_REVOKE =NOTE_REVOKE ;
SCE_KERNEL_EVFLAG_EOF =EV_EOF ;
SCE_KERNEL_EVFLAG_ERROR =EV_ERROR ;
SCE_VIDEO_OUT_EVENT_FLIP =0; //Flip completion event
SCE_VIDEO_OUT_EVENT_VBLANK =1; //Vblank event
SCE_VIDEO_OUT_EVENT_PRE_VBLANK_START=2; //PreVblankStart event
type
PSceKernelEvent=^SceKernelEvent;
SceKernelEvent=packed record
ident:PtrUint; // identifier for this event
filter:SmallInt; // filter for event
flags:Word; // action flags for kqueue
fflags:DWORD; // filter flag value
data:Ptrint; // filter data value
udata:Pointer; // opaque user data identifier
end;
type
PSceKernelEqueue=^SceKernelEqueue;
SceKernelEqueue=^SceKernelEqueue_t;
SceKernelEqueue_t=record
valid:DWORD;
FRefs:DWORD;
hIOCP:Thandle;
name:array[0..31] of AnsiChar;
end;
PKEventNode=^TKEventNode;
TKEventNode=object
refs:DWORD;
lock:DWORD;
eq:SceKernelEqueue;
ev:SceKernelEvent;
end;
function ps4_sceKernelCreateEqueue(outEq:PSceKernelEqueue;name:PChar):Integer; SysV_ABI_CDecl;
function ps4_sceKernelWaitEqueue(
eq:SceKernelEqueue;
ev:PSceKernelEvent;
num:Integer;
out_num:PInteger;
timo:PDWORD):Integer; SysV_ABI_CDecl;
function ps4_sceKernelGetEventUserData(ev:PSceKernelEvent):Pointer; SysV_ABI_CDecl;
type
TKFetchEvent=function(node:PKEventNode;ev:PSceKernelEvent):Boolean;
TKAfterEvent=function(node:PKEventNode;data:Pointer):Boolean;
function _acqure_equeue(eq:SceKernelEqueue):SceKernelEqueue;
procedure _release_equeue(eq:SceKernelEqueue);
function _post_event(eq:SceKernelEqueue;node:Pointer;cb:TKFetchEvent):Boolean;
function _alloc_kevent_node(eq:SceKernelEqueue;size:qword):Pointer;
procedure _free_kevent_node(node:PKEventNode);
function _get_kevent_node(node:PKEventNode;ev:PSceKernelEvent):Boolean;
function _trigger_kevent_node(node:PKEventNode;after:TKAfterEvent;data:Pointer):Boolean;
implementation
uses
spinlock,
ps4_time,
ps4_libkernel;
const
LIFE_EQ=$BAB1F00D;
DEAD_EQ=$DEADBEEF;
function _alloc_kevent_node(eq:SceKernelEqueue;size:qword):Pointer;
begin
eq:=_acqure_equeue(eq);
if (eq=nil) then Exit(Pointer(1));
Result:=AllocMem(size);
if (Result=nil) then
begin
_release_equeue(eq);
Exit;
end;
PKEventNode(Result)^.eq :=eq;
PKEventNode(Result)^.refs:=1;
end;
procedure _free_kevent_node(node:PKEventNode);
begin
if (node=nil) then Exit;
_release_equeue(System.InterlockedExchange(node^.eq,nil));
if System.InterlockedDecrement(node^.refs)=0 then
begin
FreeMem(node);
end;
end;
function _get_kevent_node(node:PKEventNode;ev:PSceKernelEvent):Boolean;
var
tmp:SceKernelEvent;
begin
Result:=false;
if (node=nil) or (ev=nil) then Exit;
tmp:=node^.ev;
spin_unlock(node^.lock);
if System.InterlockedDecrement(node^.refs)=0 then
begin
FreeMem(node);
Exit;
end;
ev^:=tmp;
Result:=True;
end;
function _trigger_kevent_node(node:PKEventNode;after:TKAfterEvent;data:Pointer):Boolean;
var
eq:SceKernelEqueue;
begin
Result:=False;
if (node=nil) then Exit;
eq:=node^.eq;
if (eq=nil) or (eq^.valid<>LIFE_EQ) then Exit;
if spin_trylock(node^.lock) then
begin
System.InterlockedIncrement(node^.refs);
if (after<>nil) then after(node,data);
Result:=_post_event(eq,node,@_get_kevent_node);
if not Result then
begin
spin_unlock(node^.lock);
if System.InterlockedDecrement(node^.refs)=0 then
begin
FreeMem(node);
Exit;
end;
end;
end;
end;
function ps4_sceKernelCreateEqueue(outEq:PSceKernelEqueue;name:PChar):Integer; SysV_ABI_CDecl;
var
hIOCP:Thandle;
data:SceKernelEqueue;
begin
Writeln('sceKernelCreateEqueue:',name);
if (outEq=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
data:=AllocMem(SizeOf(SceKernelEqueue_t));
if (data=nil) then
begin
Exit(SCE_KERNEL_ERROR_ENOMEM);
end;
hIOCP:=CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,High(Integer));
if (hIOCP=0) then
begin
Exit(SCE_KERNEL_ERROR_EMFILE);
end;
data^.valid:=LIFE_EQ;
data^.FRefs:=1;
data^.hIOCP:=hIOCP;
if (name<>nil) then MoveChar0(name^,data^.name,32);
outEq^:=data;
Result:=0;
end;
function _post_event(eq:SceKernelEqueue;node:Pointer;cb:TKFetchEvent):Boolean;
begin
Result:=False;
if (eq=nil) then Exit;
if (eq^.valid<>LIFE_EQ) then Exit;
Result:=PostQueuedCompletionStatus(eq^.hIOCP,1,ULONG_PTR(cb),node);
end;
function _acqure_equeue(eq:SceKernelEqueue):SceKernelEqueue;
begin
Result:=nil;
if (eq=nil) then Exit;
if (eq^.valid<>LIFE_EQ) then Exit;
System.InterlockedIncrement(eq^.FRefs);
Result:=eq;
end;
procedure _release_equeue(eq:SceKernelEqueue);
begin
if (eq=nil) then Exit;
if System.InterlockedDecrement(eq^.FRefs)=0 then
begin
FreeMem(eq);
end;
end;
type
TOVERLAPPED_ENTRY=record
lpCompletionKey:ULONG_PTR;
lpOverlapped:POverlapped;
Internal:ULONG_PTR;
dwNumberOfBytesTransferred:DWORD;
end;
POVERLAPPED_ENTRY=^TOVERLAPPED_ENTRY;
function GetQueuedCompletionStatusEx(CompletionPort:THandle;
lpCompletionPortEntries:POVERLAPPED_ENTRY;
ulCount:ULONG;
var ulNumEntriesRemoved:ULONG;
dwMilliseconds:DWORD;
fAlertable:BOOL):BOOL; stdcall; external kernel32;
function ps4_sceKernelWaitEqueue(
eq:SceKernelEqueue;
ev:PSceKernelEvent;
num:Integer;
out_num:PInteger;
timo:PDWORD):Integer; SysV_ABI_CDecl;
Var
QTIME:DWORD;
LTIME:DWORD;
OE:array[0..15] of TOVERLAPPED_ENTRY;
i,ulNum,olNum:ULONG;
CTXProc:TKFetchEvent;
Q:Boolean;
begin
if (eq=nil) then Exit(SCE_KERNEL_ERROR_EBADF);
if (eq^.valid<>LIFE_EQ) then Exit(SCE_KERNEL_ERROR_EBADF);
if (ev=nil) then Exit(SCE_KERNEL_ERROR_EFAULT);
if (num<1) then Exit(SCE_KERNEL_ERROR_EINVAL);
//Writeln('>sceKernelWaitEqueue');
if (timo<>nil) then
begin
//LTIME:=dwMilliSecs(timo^);
LTIME:=_usec2msec(timo^);
end else
begin
LTIME:=INFINITE;
end;
if (num>16) then num:=16;
Result:=0;
out_num^:=0;
FillChar(OE,SizeOf(OE),0);
CTXProc:=nil;
Repeat
ulNum:=0;
if (LTIME<>INFINITE) then QTIME:=Windows.GetTickCount;
Q:=GetQueuedCompletionStatusEX(eq^.hIOCP,@OE,num,ulNum,LTIME,True);
if (LTIME<>INFINITE) then
begin
QTIME:=Windows.GetTickCount-QTIME;
if (QTIME>LTIME) then
LTIME:=0
else
LTIME:=LTIME-QTIME;
end;
if not Q then
begin
Case GetLastError of
ERROR_INVALID_PARAMETER,
ERROR_INVALID_HANDLE :Exit(SCE_KERNEL_ERROR_EBADF);
WAIT_TIMEOUT :Exit(SCE_KERNEL_ERROR_ETIMEDOUT);
end;
end;
if (ulNum<>0) then
begin
olNum:=0;
For i:=0 to ulNum-1 do
begin
CTXProc:=TKFetchEvent(OE[i].lpCompletionKey);
if Assigned(CTXProc) then
begin
if CTXProc(PKEventNode(OE[i].lpOverlapped),@ev[olNum]) then Inc(olNum);
end;
end;
if (olNum<>0) then
begin
out_num^:=olNum;
//Writeln('<sceKernelWaitEqueue');
Exit(0);
end;
end;
Until false;
end;
function ps4_sceKernelGetEventUserData(ev:PSceKernelEvent):Pointer; SysV_ABI_CDecl;
begin
if (ev=nil) then Exit(nil);
Result:=ev^.udata;
end;
end.

View File

@ -0,0 +1,339 @@
unit ps4_rwlock;
{$mode objfpc}{$H+}
interface
uses
RWLock,
ps4_types;
const
PTHREAD_RWLOCK_INITIALIZER=nil;
SCE_PTHREAD_RWLOCK_NORMAL = 1; // Default POSIX rwlock
SCE_PTHREAD_RWLOCK_PREFER_READER = 2; // Reader preferred rwlock
type
Ppthread_rwlock=^pthread_rwlock;
pthread_rwlock=^pthread_rwlock_t;
pthread_rwlock_t=record
valid:DWORD;
Lock:TRWLock;
name:array[0..31] of AnsiChar;
end;
Ppthread_rwlockattr=^pthread_rwlockattr_t;
pthread_rwlockattr_t=packed record
_type:0..3; //2
_shared:0..1; //1
_align:0..536870911; //29
_align2:Integer; //32
end;
function ps4_pthread_rwlockattr_init(pAttr:Ppthread_rwlockattr):Integer; SysV_ABI_CDecl;
function ps4_pthread_rwlockattr_destroy(pAttr:Ppthread_rwlockattr):Integer; SysV_ABI_CDecl;
function ps4_pthread_rwlockattr_gettype_np(pAttr:Ppthread_rwlockattr;t:PInteger):Integer; SysV_ABI_CDecl;
function ps4_pthread_rwlockattr_settype_np(pAttr:Ppthread_rwlockattr;t:Integer):Integer; SysV_ABI_CDecl;
function ps4_pthread_rwlockattr_getpshared(pAttr:Ppthread_rwlockattr;t:PInteger):Integer; SysV_ABI_CDecl;
function ps4_pthread_rwlockattr_setpshared(pAttr:Ppthread_rwlockattr;t:Integer):Integer; SysV_ABI_CDecl;
function ps4_pthread_rwlock_init(pRwlock:Ppthread_rwlock;pAttr:Ppthread_rwlockattr):Integer; SysV_ABI_CDecl;
function ps4_pthread_rwlock_destroy(m:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
function ps4_pthread_rwlock_rdlock(m:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
function ps4_pthread_rwlock_wrlock(m:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
function ps4_pthread_rwlock_tryrdlock(m:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
function ps4_pthread_rwlock_trywrlock(m:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
function ps4_pthread_rwlock_unlock(m:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
function ps4_scePthreadRwlockattrInit(pAttr:Ppthread_rwlockattr):Integer; SysV_ABI_CDecl;
function ps4_scePthreadRwlockattrDestroy(pAttr:Ppthread_rwlockattr):Integer; SysV_ABI_CDecl;
function ps4_scePthreadRwlockattrGettype(pAttr:Ppthread_rwlockattr;t:Pinteger):Integer; SysV_ABI_CDecl;
function ps4_scePthreadRwlockattrSettype(pAttr:Ppthread_rwlockattr;t:integer):Integer; SysV_ABI_CDecl;
function ps4_scePthreadRwlockInit(pRwlock:Ppthread_rwlock;pAttr:Ppthread_rwlockattr;str:PChar):Integer; SysV_ABI_CDecl;
function ps4_scePthreadRwlockDestroy(pRwlock:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
function ps4_scePthreadRwlockRdlock(pRwlock:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
function ps4_scePthreadRwlockWrlock(pRwlock:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
function ps4_scePthreadRwlockTryrdlock(pRwlock:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
function ps4_scePthreadRwlockTrywrlock(pRwlock:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
function ps4_scePthreadRwlockUnlock(pRwlock:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
//function ps4_scePthreadRwlockTimedrdlock(pRwlock:Ppthread_rwlock;usec:DWORD):Integer; SysV_ABI_CDecl;
//function ps4_scePthreadRwlockTimedwrlock(pRwlock:Ppthread_rwlock;usec:DWORD):Integer; SysV_ABI_CDecl;
implementation
Uses
spinlock,
ps4_mutex,
ps4_libkernel;
//int pthread_rwlock_timedrdlock(pthread_rwlock_t *,const struct timespec *);
//int pthread_rwlock_timedwrlock(pthread_rwlock_t *,const struct timespec *);
//int pthread_rwlockattr_getkind_np(const pthread_rwlockattr_t *,int *);
//int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t *, int);
function ps4_pthread_rwlockattr_init(pAttr:Ppthread_rwlockattr):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(EINVAL);
pAttr^:=Default(pthread_rwlockattr_t);
pAttr^._type:=SCE_PTHREAD_RWLOCK_NORMAL;
Result:=0;
end;
function ps4_pthread_rwlockattr_destroy(pAttr:Ppthread_rwlockattr):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(EINVAL);
Result:=0;
end;
function ps4_pthread_rwlockattr_gettype_np(pAttr:Ppthread_rwlockattr;t:PInteger):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) or (t=nil) then Exit(EINVAL);
t^:=pAttr^._type;
Result:=0;
end;
function ps4_pthread_rwlockattr_settype_np(pAttr:Ppthread_rwlockattr;t:Integer):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(EINVAL);
Case t of
SCE_PTHREAD_RWLOCK_NORMAL :;
SCE_PTHREAD_RWLOCK_PREFER_READER:;
else
Exit(EINVAL);
end;
pAttr^._type:=t;
Result:=0;
end;
function ps4_pthread_rwlockattr_getpshared(pAttr:Ppthread_rwlockattr;t:PInteger):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) or (t=nil) then Exit(EINVAL);
t^:=pAttr^._shared;
Result:=0;
end;
function ps4_pthread_rwlockattr_setpshared(pAttr:Ppthread_rwlockattr;t:Integer):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(EINVAL);
Case t of
PTHREAD_PROCESS_PRIVATE:;
PTHREAD_PROCESS_SHARED :;
else
Exit(EINVAL);
end;
pAttr^._shared:=t;
Result:=0;
end;
Const
LIFE_RWLOCK=$BAB1F0ED;
DEAD_RWLOCK=$DEADB0EF;
function STATIC_RWL_INITIALIZER(x:pthread_rwlock):Boolean; inline;
begin
Result:=(x=PTHREAD_RWLOCK_INITIALIZER);
end;
function CAS(Var addr:Pointer;Comp,New:Pointer):Boolean; inline;
begin
Result:=System.InterlockedCompareExchange(addr,New,Comp)=Comp;
end;
function CAS(Var addr:DWORD;Comp,New:DWORD):Boolean; inline;
begin
Result:=System.InterlockedCompareExchange(addr,New,Comp)=Comp;
end;
function XCHG(Var addr:Pointer;New:Pointer):Pointer; inline;
begin
Result:=System.InterLockedExchange(addr,New);
end;
function rwlock_impl_init(m:Ppthread_rwlock;mi:pthread_rwlock):pthread_rwlock;
var
new_mi:pthread_rwlock;
begin
new_mi:=AllocMem(SizeOf(pthread_rwlock_t));
if (new_mi=nil) then Exit(new_mi);
new_mi^.valid:=LIFE_RWLOCK;
rwlock_init(new_mi^.Lock);
if CAS(m^,mi,new_mi) then
begin
Result:=new_mi;
end else
begin
rwlock_destroy(new_mi^.Lock);
FreeMem(new_mi);
Result:=m^;
end;
end;
function rwlock_impl(m:Ppthread_rwlock;var mi:pthread_rwlock):Integer;
begin
if (m=nil) then Exit(EINVAL);
mi:=m^;
if STATIC_RWL_INITIALIZER(mi) then
begin
mi:=rwlock_impl_init(m,mi);
if (mi=nil) then Exit(ENOMEM);
end;
if (mi^.valid<>LIFE_RWLOCK) then Exit(EINVAL);
end;
function pthread_rwlock_init(m:Ppthread_rwlock;a:Ppthread_rwlockattr;str:PChar):Integer; SysV_ABI_CDecl;
var
mi:pthread_rwlock;
begin
Result:=rwlock_impl(m,mi);
if (Result<>0) then Exit;
if (str<>nil) then MoveChar0(str^,mi^.name,32);
end;
function ps4_pthread_rwlock_init(pRwlock:Ppthread_rwlock;pAttr:Ppthread_rwlockattr):Integer; SysV_ABI_CDecl;
begin
Result:=pthread_rwlock_init(pRwlock,pAttr,nil);
end;
function ps4_pthread_rwlock_destroy(m:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
var
mi:pthread_rwlock;
begin
if (m=nil) then Exit(EINVAL);
mi:=m^;
if not STATIC_RWL_INITIALIZER(mi) then
begin
mi:=XCHG(m^,nil);
if STATIC_RWL_INITIALIZER(mi) then Exit(0);
if not CAS(mi^.valid,LIFE_RWLOCK,DEAD_RWLOCK) then Exit(EINVAL);
rwlock_destroy(mi^.Lock);
FreeMem(mi);
end;
Result:=0;
end;
function ps4_pthread_rwlock_rdlock(m:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
var
mi:pthread_rwlock;
begin
Result:=rwlock_impl(m,mi);
if (Result<>0) then Exit;
rwlock_rdlock(mi^.Lock);
end;
function ps4_pthread_rwlock_wrlock(m:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
var
mi:pthread_rwlock;
begin
Result:=rwlock_impl(m,mi);
if (Result<>0) then Exit;
rwlock_wrlock(mi^.Lock);
end;
function ps4_pthread_rwlock_tryrdlock(m:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
var
mi:pthread_rwlock;
begin
Result:=rwlock_impl(m,mi);
if (Result<>0) then Exit;
if not rwlock_tryrdlock(mi^.Lock) then Result:=EBUSY;
end;
function ps4_pthread_rwlock_trywrlock(m:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
var
mi:pthread_rwlock;
begin
Result:=rwlock_impl(m,mi);
if (Result<>0) then Exit;
if not rwlock_trywrlock(mi^.Lock) then Result:=EBUSY;
end;
function ps4_pthread_rwlock_unlock(m:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
var
mi:pthread_rwlock;
begin
Result:=rwlock_impl(m,mi);
if (Result<>0) then Exit;
rwlock_unlock(mi^.Lock);
end;
///////////
function ps4_scePthreadRwlockattrInit(pAttr:Ppthread_rwlockattr):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
pAttr^:=Default(pthread_rwlockattr_t);
pAttr^._type:=SCE_PTHREAD_RWLOCK_NORMAL;
Result:=0;
end;
function ps4_scePthreadRwlockattrDestroy(pAttr:Ppthread_rwlockattr):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
Result:=0;
end;
function ps4_scePthreadRwlockattrGettype(pAttr:Ppthread_rwlockattr;t:Pinteger):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) or (t=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
t^:=pAttr^._type;
Result:=0;
end;
function ps4_scePthreadRwlockattrSettype(pAttr:Ppthread_rwlockattr;t:integer):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(SCE_KERNEL_ERROR_EINVAL);
Case t of
SCE_PTHREAD_RWLOCK_NORMAL :;
SCE_PTHREAD_RWLOCK_PREFER_READER:;
else
Exit(SCE_KERNEL_ERROR_EINVAL);
end;
pAttr^._type:=t;
Result:=0;
end;
//
function ps4_scePthreadRwlockInit(pRwlock:Ppthread_rwlock;pAttr:Ppthread_rwlockattr;str:PChar):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(pthread_rwlock_init(pRwlock,pAttr,str));
end;
function ps4_scePthreadRwlockDestroy(pRwlock:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(ps4_pthread_rwlock_destroy(pRwlock));
end;
function ps4_scePthreadRwlockRdlock(pRwlock:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(ps4_pthread_rwlock_rdlock(pRwlock));
end;
function ps4_scePthreadRwlockWrlock(pRwlock:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(ps4_pthread_rwlock_wrlock(pRwlock));
end;
function ps4_scePthreadRwlockTryrdlock(pRwlock:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(ps4_pthread_rwlock_tryrdlock(pRwlock));
end;
function ps4_scePthreadRwlockTrywrlock(pRwlock:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(ps4_pthread_rwlock_trywrlock(pRwlock));
end;
function ps4_scePthreadRwlockUnlock(pRwlock:Ppthread_rwlock):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(ps4_pthread_rwlock_unlock(pRwlock));
end;
end.

512
ps4_libkerenel/ps4_sema.pas Normal file
View File

@ -0,0 +1,512 @@
unit ps4_sema;
{$mode objfpc}{$H+}
interface
uses
windows,
ps4_types;
const
SCE_KERNEL_SEMA_ATTR_TH_FIFO=$01;
SCE_KERNEL_SEMA_ATTR_TH_PRIO=$02;
SCE_KERNEL_SEMA_ID_INVALID:Int64=-1;
SEM_FAILED =nil;
SEM_VALUE_MAX =High(Integer);
type
PSceKernelSemaOptParam=^TSceKernelSemaOptParam;
TSceKernelSemaOptParam=packed record
size:QWORD;
end;
PSceKernelSema=^SceKernelSema;
SceKernelSema=^_sem_t;
_sem_t=record
valid:DWORD;
s:THandle;
init,max:Integer;
num:Integer;
value:Integer;
//vlock:pthread_mutex_t;
lock:Pointer;
name:array[0..31] of AnsiChar;
end;
function ps4_sem_init(sem:PSceKernelSema;value:Integer):Integer; SysV_ABI_CDecl;
function ps4_sem_destroy(sem:PSceKernelSema):Integer; SysV_ABI_CDecl;
function ps4_sem_getvalue(sem:PSceKernelSema;sval:PInteger):Integer; SysV_ABI_CDecl;
function ps4_sem_post(sem:PSceKernelSema):Integer; SysV_ABI_CDecl;
function ps4_sem_timedwait(sem:PSceKernelSema;ts:Ptimespec):Integer; SysV_ABI_CDecl;
function ps4_sem_trywait(sem:PSceKernelSema):Integer; SysV_ABI_CDecl;
function ps4_sem_wait(sem:PSceKernelSema):Integer; SysV_ABI_CDecl;
function ps4_sceKernelCreateSema(
sem:PSceKernelSema;
name:Pchar;
attr:DWORD;
init,max:Integer;
opt:PSceKernelSemaOptParam):Integer; SysV_ABI_CDecl;
function ps4_sceKernelDeleteSema(sem:SceKernelSema):Integer; SysV_ABI_CDecl;
function ps4_sceKernelWaitSema(sem:SceKernelSema;Count:Integer;pTimeout:PDWORD):Integer; SysV_ABI_CDecl;
function ps4_sceKernelSignalSema(sem:SceKernelSema;Count:Integer):Integer; SysV_ABI_CDecl;
function ps4_sceKernelPollSema(sem:SceKernelSema;Count:Integer):Integer; SysV_ABI_CDecl;
function ps4_sceKernelCancelSema(sem:SceKernelSema;count:Integer;threads:PInteger):Integer; SysV_ABI_CDecl;
function do_sema_b_wait(sema:THandle;timeout:DWORD;var cs:TRTLCriticalSection;var val:Integer):Integer;
function do_sema_b_wait_intern(sema:THandle;timeout:DWORD):Integer;
function do_sema_b_release(sema:THandle;count:DWORD;var cs:TRTLCriticalSection;var val:Integer):Integer;
implementation
//int sem_unlink(const char *);
uses
spinlock,
ps4_time,
ps4_libkernel;
const
LIFE_SEM=$BAB1F00D;
DEAD_SEM=$DEADBEEF;
function do_sema_b_wait(sema:THandle;timeout:DWORD;var cs:TRTLCriticalSection;var val:Integer):Integer;
var
r:Integer;
v:Integer;
begin
System.EnterCriticalSection(cs);
System.InterlockedDecrement(val);
v:=val;
System.LeaveCriticalSection(cs);
if (v>=0) then Exit(0);
r:=do_sema_b_wait_intern(sema,timeout);
System.EnterCriticalSection(cs);
if (r<>0) then
begin
System.InterlockedIncrement(val);
end;
System.LeaveCriticalSection(cs);
Result:=r;
end;
function do_sema_b_wait_intern(sema:THandle;timeout:DWORD):Integer;
var
r:Integer;
res:DWORD;
begin
res:=WaitForSingleObject(sema,timeout);
case res of
WAIT_TIMEOUT :r:=ETIMEDOUT;
WAIT_ABANDONED:r:=EPERM;
WAIT_OBJECT_0 :r:=0;
else
r:=EINVAL;
end;
if (r<>0) and (r<>EINVAL) and (WaitForSingleObject(sema,0)=WAIT_OBJECT_0) then
r:=0;
Result:=r;
end;
function do_sema_b_release(sema:THandle;count:DWORD;var cs:TRTLCriticalSection;var val:Integer):Integer;
var
wc,s:Integer;
begin
System.EnterCriticalSection(cs);
if (Int64(val)+Int64(count))>$7fffffff then
begin
System.LeaveCriticalSection(cs);
Exit(EINVAL);
end;
wc:=-val;
//if (wc=0) then wc:=1;
System.InterlockedExchangeAdd(val,count);
if (wc<count) then s:=wc else s:=count;
if ((wc<=0) or ReleaseSemaphore(sema,s,nil)) then
begin
LeaveCriticalSection(cs);
Exit(0);
end;
System.InterlockedExchangeAdd(val, -count);
System.LeaveCriticalSection(cs);
Exit(EINVAL);
end;
/////
function CAS(Var addr:Pointer;Comp,New:Pointer):Boolean; inline;
begin
Result:=System.InterlockedCompareExchange(addr,New,Comp)=Comp;
end;
function CAS(Var addr:DWORD;Comp,New:DWORD):Boolean; inline;
begin
Result:=System.InterlockedCompareExchange(addr,New,Comp)=Comp;
end;
function XCHG(Var addr:Pointer;New:Pointer):Pointer; inline;
begin
Result:=System.InterLockedExchange(addr,New);
end;
function sem_impl_init(m,mi:PSceKernelSema;max,value:Integer):Integer;
var
new_mi:SceKernelSema;
begin
new_mi:=AllocMem(SizeOf(_sem_t));
if (new_mi=nil) then Exit(ENOMEM);
new_mi^.init:=value;
new_mi^.max:=max;
new_mi^.value:=value;
new_mi^.s:=CreateSemaphore(nil,0,SEM_VALUE_MAX,nil);
if (new_mi^.s=0) then
begin
FreeMem(new_mi);
Exit(ENOSPC);
end;
new_mi^.valid:=LIFE_SEM;
if CAS(m^,mi^,new_mi) then
begin
mi^:=new_mi;
end else
begin
FreeMem(new_mi);
mi^:=m^;
end;
end;
function _sem_init(sem:PSceKernelSema;value:Integer):Integer;
var
sv:SceKernelSema;
begin
if (sem=nil) or (value<0) then Exit(EINVAL);
sv:=sem^;
Result:=sem_impl_init(sem,@sv,SEM_VALUE_MAX,value);
end;
function _sem_destroy(sem:PSceKernelSema):Integer;
var
sv:SceKernelSema;
bkoff:backoff_exp;
begin
if (sem=nil) then Exit(EINVAL);
sv:=XCHG(sem^,nil);
if (sv=nil) then Exit(EINVAL);
spin_lock(sv^.lock);
if (sv^.valid<>LIFE_SEM) then Exit(EINVAL);
if not CloseHandle(sv^.s) then
begin
spin_unlock(sv^.lock);
Exit(EINVAL);
end;
sv^.value:=SEM_VALUE_MAX;
if CAS(sv^.valid,LIFE_SEM,DEAD_SEM) then
begin
spin_unlock(sv^.lock);
bkoff.Reset;
While (sv^.num<>0) do bkoff.Wait;
FreeMem(sv);
Result:=0;
end else
begin
spin_unlock(sv^.lock);
Result:=EINVAL;
end;
end;
function sem_std_enter(sem,svp:PSceKernelSema):Integer;
var
sv:SceKernelSema;
begin
if (sem=nil) then Exit(EINVAL);
sv:=sem^;
if (sv=nil) then Exit(EINVAL);
if (sv^.valid<>LIFE_SEM) then Exit(EINVAL);
spin_lock(sv^.lock);
if (sv^.valid<>LIFE_SEM) then Exit(EINVAL);
if (sem^=nil) then
begin
spin_unlock(sv^.lock);
Exit(EINVAL);
end;
svp^:=sv;
Result:=0;
end;
function _sem_trywait(sem:PSceKernelSema):Integer;
var
sv:SceKernelSema;
begin
Result:=sem_std_enter(sem,@sv);
if (Result<>0) then Exit;
if (sv^.value<=0) then
begin
spin_unlock(sv^.lock);
Exit(EAGAIN);
end;
Dec(sv^.value);
spin_unlock(sv^.lock);
Result:=0;
end;
function _sem_wait(sem:PSceKernelSema;count:Integer;t:DWORD):Integer;
var
sv:SceKernelSema;
cur_v:Integer;
semh:THandle;
begin
if (count<=0) then Exit(EINVAL);
Result:=sem_std_enter(sem,@sv);
if (Result<>0) then Exit;
if (count>sv^.max) then
begin
spin_unlock(sv^.lock);
Exit(EINVAL);
end;
Dec(sv^.value,count);
cur_v:=sv^.value;
semh :=sv^.s;
spin_unlock(sv^.lock);
if (cur_v>=0) then Exit(0);
//pthread_cleanup_push (clean_wait_sem, (void *) &arg);
System.InterlockedIncrement(sv^.num);
Result:=do_sema_b_wait_intern(semh,t);
System.InterlockedDecrement(sv^.num);
//pthread_cleanup_pop (ret);
if (Result=EINVAL) then Result:=0;
end;
function _sem_timedwait(sem:PSceKernelSema;ts:Ptimespec):Integer;
var
t:DWORD;
begin
if (ts=nil) then
begin
t:=INFINITE;
end else
begin
t:=dwMilliSecs(_pthread_rel_time_in_ms(ts^));
end;
Result:=_sem_wait(sem,1,t);
end;
function _sem_post(sem:PSceKernelSema;count:Integer):Integer;
var
sv:SceKernelSema;
waiters_count,w:Integer;
begin
if (count<=0) then Exit(EINVAL);
Result:=sem_std_enter(sem,@sv);
if (Result<>0) then Exit;
if (count>sv^.max) or (sv^.value>(sv^.max-count)) then
begin
spin_unlock(sv^.lock);
Exit(EINVAL);
end;
waiters_count:=-sv^.value;
Inc(sv^.value,count);
if (waiters_count<count) then w:=waiters_count else w:=count;
if (waiters_count<=0) or ReleaseSemaphore(sv^.s,w,nil) then
begin
spin_unlock(sv^.lock);
Exit(0);
end;
Dec(sv^.value,count);
spin_unlock(sv^.lock);
Result:=EINVAL;
end;
function _sem_getvalue(sem:PSceKernelSema;sval:PInteger):Integer;
var
sv:SceKernelSema;
begin
if (sval=nil) then Exit(EINVAL);
Result:=sem_std_enter(sem,@sv);
if (Result<>0) then Exit;
sval^:=sv^.value;
spin_unlock(sv^.lock);
Result:=0;
end;
//
function ps4_sem_init(sem:PSceKernelSema;value:Integer):Integer; SysV_ABI_CDecl;
begin
Result:=lc_set_errno(_sem_init(sem,value));
end;
function ps4_sem_destroy(sem:PSceKernelSema):Integer; SysV_ABI_CDecl;
begin
Result:=lc_set_errno(_sem_destroy(sem));
end;
function ps4_sem_getvalue(sem:PSceKernelSema;sval:PInteger):Integer; SysV_ABI_CDecl;
begin
Result:=lc_set_errno(_sem_getvalue(sem,sval));
end;
function ps4_sem_post(sem:PSceKernelSema):Integer; SysV_ABI_CDecl;
begin
Result:=lc_set_errno(_sem_post(sem,1));
end;
function ps4_sem_timedwait(sem:PSceKernelSema;ts:Ptimespec):Integer; SysV_ABI_CDecl;
begin
Result:=lc_set_errno(_sem_timedwait(sem,ts));
end;
function ps4_sem_trywait(sem:PSceKernelSema):Integer; SysV_ABI_CDecl;
begin
Result:=lc_set_errno(_sem_trywait(sem));
end;
function ps4_sem_wait(sem:PSceKernelSema):Integer; SysV_ABI_CDecl;
begin
Result:=lc_set_errno(_sem_wait(sem,1,INFINITE));
end;
////
function ps4_sceKernelCreateSema(
sem:PSceKernelSema;
name:Pchar;
attr:DWORD;
init,max:Integer;
opt:PSceKernelSemaOptParam):Integer; SysV_ABI_CDecl;
var
sv:SceKernelSema;
begin
if (sem=nil) or (max<=0) or (init<0) then Exit(SCE_KERNEL_ERROR_EINVAL);
sv:=sem^;
Result:=px2sce(sem_impl_init(sem,@sv,max,init));
if (Result<>0) then Exit;
if (name<>nil) then MoveChar0(name^,sv^.name,32);
end;
function ps4_sceKernelDeleteSema(sem:SceKernelSema):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(_sem_destroy(@sem));
end;
//typedef unsigned int SceKernelUseconds;
function ps4_sceKernelWaitSema(sem:SceKernelSema;Count:Integer;pTimeout:PDWORD):Integer; SysV_ABI_CDecl;
var
q:QWORD;
t:DWORD;
begin
if (pTimeout=nil) then
begin
t:=INFINITE;
end else
begin
t:=_usec2msec(pTimeout^);
q:=_pthread_time_in_ms;
end;
Result:=px2sce(_sem_wait(@sem,Count,t));
if (pTimeout<>nil) then
begin
if (Result=SCE_KERNEL_ERROR_ETIMEDOUT) then
begin
pTimeout^:=0;
end else
begin
q:=_pthread_time_in_ms-q;
q:=q*1000;
pTimeout^:=dwMilliSecs(q);
end;
end;
end;
function ps4_sceKernelSignalSema(sem:SceKernelSema;Count:Integer):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(_sem_post(@sem,Count));
end;
function ps4_sceKernelPollSema(sem:SceKernelSema;Count:Integer):Integer; SysV_ABI_CDecl;
var
sv:SceKernelSema;
begin
if (Count<=0) then Exit(SCE_KERNEL_ERROR_EINVAL);
Result:=px2sce(sem_std_enter(@sem,@sv));
if (Result<>0) then Exit;
if (Count>sv^.max) then
begin
spin_unlock(sv^.lock);
Exit(SCE_KERNEL_ERROR_EINVAL);
end;
if (sv^.value>=Count) then
begin
Dec(sv^.value,Count);
Result:=0;
end else
begin
Result:=SCE_KERNEL_ERROR_EBUSY;
end;
spin_unlock(sv^.lock);
end;
function ps4_sceKernelCancelSema(sem:SceKernelSema;count:Integer;threads:PInteger):Integer; SysV_ABI_CDecl;
var
sv:SceKernelSema;
waiters_count:Integer;
begin
Result:=px2sce(sem_std_enter(@sem,@sv));
if (Result<>0) then Exit;
if (count>sv^.max) then
begin
spin_unlock(sv^.lock);
Exit(SCE_KERNEL_ERROR_EINVAL);
end;
if (threads<>nil) then threads^:=sv^.num;
waiters_count:=-sv^.value;
if (waiters_count>0) then
begin
ReleaseSemaphore(sv^.s,waiters_count,nil);
end;
if (count<0) then
sv^.value:=sv^.init
else
sv^.value:=count;
spin_unlock(sv^.lock);
Result:=0;
end;
end.

337
ps4_libkerenel/ps4_time.pas Normal file
View File

@ -0,0 +1,337 @@
unit ps4_time;
{$mode objfpc}{$H+}
interface
uses
spinlock,
windows,
ps4_types,
Classes, SysUtils;
const
CLOCK_REALTIME =0;
CLOCK_VIRTUAL =1;
CLOCK_PROF =2;
CLOCK_MONOTONIC =4;
CLOCK_UPTIME =5; // FreeBSD-specific.
CLOCK_UPTIME_PRECISE =7; // FreeBSD-specific.
CLOCK_UPTIME_FAST =8; // FreeBSD-specific.
CLOCK_REALTIME_PRECISE =9; // FreeBSD-specific.
CLOCK_REALTIME_FAST =10; // FreeBSD-specific.
CLOCK_MONOTONIC_PRECISE=11; // FreeBSD-specific.
CLOCK_MONOTONIC_FAST =12; // FreeBSD-specific.
CLOCK_SECOND =13; // FreeBSD-specific.
CLOCK_THREAD_CPUTIME_ID=14;
CLOCK_PROCTIME =15; // ORBIS only
CLOCK_EXT_NETWORK =16; // ORBIS only
CLOCK_EXT_DEBUG_NETWORK=17; // ORBIS only
CLOCK_EXT_AD_NETWORK =18; // ORBIS only
CLOCK_EXT_RAW_NETWORK =19; // ORBIS only
function _usec2msec(usec:DWORD):DWORD;
function _pthread_time_in_ms_from_timespec(const ts:timespec):QWORD; inline;
function _pthread_time_in_ms:QWORD; inline;
function _pthread_rel_time_in_ms(const ts:timespec):QWORD;
function dwMilliSecs(ms:QWORD):DWORD; inline;
function ps4_gettimeofday(tv:Ptimeval;tz:Ptimezone):Integer; SysV_ABI_CDecl;
function ps4_clock_gettime(clock_id:Integer;tp:Ptimespec):Integer; SysV_ABI_CDecl;
function ps4_sceKernelGetTscFrequency():QWORD; SysV_ABI_CDecl;
function ps4_sceKernelReadTsc():QWORD; SysV_ABI_CDecl;
function ps4_sceKernelClockGettime(clockId:Integer;tp:Ptimespec):Integer; SysV_ABI_CDecl;
function ps4_sceKernelGetProcessTime:QWORD; SysV_ABI_CDecl; //microseconds
function ps4_nanosleep(req,rem:Ptimespec):Integer; SysV_ABI_CDecl;
function ps4_usleep(usec:Integer):Integer; SysV_ABI_CDecl;
function ps4_sceKernelUsleep(usec:DWORD):Integer; SysV_ABI_CDecl;
Const
FILETIME_1970 =116444736000000000;
HECTONANOSEC_PER_SEC =10000000;
DELTA_EPOCH_IN_100NS =116444736000000000;
POW10_7 =10000000;
POW10_9 =1000000000;
implementation
Uses
ps4_libkernel;
function _usec2msec(usec:DWORD):DWORD;
begin
Result:=(usec+999) div 1000;
end;
function _pthread_time_in_ms_from_timespec(const ts:timespec):QWORD; inline;
begin
Result:=QWORD(ts.tv_sec)*1000+QWORD(ts.tv_nsec+999999) div 1000000;
end;
function _pthread_time_in_ms:QWORD; inline;
var
ts:timespec;
begin
ts:=Default(timespec);
ps4_clock_gettime(CLOCK_REALTIME,@ts);
Result:=_pthread_time_in_ms_from_timespec(ts);
end;
function _pthread_rel_time_in_ms(const ts:timespec):QWORD;
var
t1,t2:QWORD;
begin
t1:=_pthread_time_in_ms_from_timespec(ts);
t2:=_pthread_time_in_ms;
if (t1<t2) then
Result:=0
else
Result:=t1-t2;
end;
function dwMilliSecs(ms:QWORD):DWORD; inline;
begin
if (ms>=$ffffffff) then
Result:=$ffffffff
else
Result:=DWORD(ms);
end;
type
TGetSystemTimeAsFileTime=procedure(var lpSystemTimeAsFileTime:TFILETIME); stdcall;
var
_GetSystemTimeAsFileTime:TGetSystemTimeAsFileTime;
procedure GetSystemTimeAsFileTime(var lpSystemTimeAsFileTime:TFILETIME);
var
h:HMODULE;
begin
if (_GetSystemTimeAsFileTime=nil) then
begin
h:=GetModuleHandle('kernel32.dll');
Pointer(_GetSystemTimeAsFileTime):=GetProcAddress(h,'GetSystemTimePreciseAsFileTime');
if (_GetSystemTimeAsFileTime=nil) then
begin
Pointer(_GetSystemTimeAsFileTime):=GetProcAddress(h,'GetSystemTimeAsFileTime');
end;
end;
_GetSystemTimeAsFileTime(lpSystemTimeAsFileTime);
end;
procedure gettimezone(z:Ptimezone);
var
TZInfo:TTimeZoneInformation;
tzi:DWORD;
begin
if (z<>nil) then
begin
tzi:=GetTimeZoneInformation(@TZInfo);
if (tzi<>TIME_ZONE_ID_INVALID) then
begin
z^.tz_minuteswest:=TZInfo.Bias;
if (tzi=TIME_ZONE_ID_DAYLIGHT) then
z^.tz_dsttime:=1
else
z^.tz_dsttime:=0;
end else
begin
z^.tz_minuteswest:=0;
z^.tz_dsttime :=0;
end;
end;
end;
function getntptimeofday(tp:Ptimespec;z:Ptimezone):Integer;
var
_now:TFILETIME;
begin
gettimezone(z);
if (tp<>nil) then
begin
GetSystemTimeAsFileTime(_now);
QWORD(_now):=QWORD(_now)-FILETIME_1970;
tp^.tv_sec :=QWORD(_now) div HECTONANOSEC_PER_SEC;
tp^.tv_nsec:=(QWORD(_now) mod HECTONANOSEC_PER_SEC)*100;
end;
Result:=0;
end;
function ps4_gettimeofday(tv:Ptimeval;tz:Ptimezone):Integer; SysV_ABI_CDecl;
Var
tp:timespec;
begin
Result:=getntptimeofday(@tp,tz);
if (tv<>nil) then
begin
tv^.tv_sec :=tp.tv_sec;
tv^.tv_usec:=(tp.tv_nsec div 1000);
end;
end;
var
FPerformanceFrequency:TLargeInteger=1;
function ps4_clock_gettime(clock_id:Integer;tp:Ptimespec):Integer; SysV_ABI_CDecl;
var
ct,et,kt,ut:TFILETIME;
pf,pc,tc:TLargeInteger;
begin
if (tp=nil) then Exit(-1);
Result:=0;
case clock_id of
CLOCK_SECOND:
begin
GetSystemTimeAsFileTime(ct);
QWORD(ct):=QWORD(ct)-DELTA_EPOCH_IN_100NS;
tp^.tv_sec :=QWORD(ct) div POW10_7;
//tp^.tv_nsec:=(QWORD(ct) mod POW10_7)*100;
tp^.tv_nsec:=0;
end;
CLOCK_REALTIME,
CLOCK_REALTIME_PRECISE,
CLOCK_REALTIME_FAST:
begin
GetSystemTimeAsFileTime(ct);
QWORD(ct):=QWORD(ct)-DELTA_EPOCH_IN_100NS;
tp^.tv_sec :=QWORD(ct) div POW10_7;
tp^.tv_nsec:=(QWORD(ct) mod POW10_7)*100;
end;
CLOCK_MONOTONIC,
CLOCK_MONOTONIC_PRECISE,
CLOCK_MONOTONIC_FAST:
begin
System.ThreadSwitch; //this stabilize timers, why? idk
System.ThreadSwitch;
pf:=FPerformanceFrequency;
pc:=0;
QueryPerformanceCounter(pc);
tp^.tv_sec :=pc div pf;
tp^.tv_nsec:=((pc mod pf)*POW10_9+(pf shr 1)) div pf;
if (tp^.tv_nsec>=POW10_9) then
begin
Inc(tp^.tv_sec);
Dec(tp^.tv_nsec,POW10_9);
end;
end;
CLOCK_PROCTIME:
begin
if not GetProcessTimes(GetCurrentProcess,ct,et,kt,ut) then Exit(lc_set_errno(EINVAL));
QWORD(ct) :=QWORD(kt)+QWORD(ut);
tp^.tv_sec :=QWORD(ct) div POW10_7;
tp^.tv_nsec:=(QWORD(ct) mod POW10_7)*100;
end;
CLOCK_THREAD_CPUTIME_ID:
begin
if not GetThreadTimes(GetCurrentProcess,ct,et,kt,ut) then Exit(lc_set_errno(EINVAL));
QWORD(ct) :=QWORD(kt)+QWORD(ut);
tp^.tv_sec :=QWORD(ct) div POW10_7;
tp^.tv_nsec:=(QWORD(ct) mod POW10_7)*100;
end
else
Result:=lc_set_errno(EINVAL);
end;
end;
function ps4_sceKernelGetTscFrequency():QWORD; SysV_ABI_CDecl;
begin
Result:=FPerformanceFrequency;
end;
function ps4_sceKernelReadTsc():QWORD; SysV_ABI_CDecl;
begin
System.ThreadSwitch; //this stabilize timers, why? idk
System.ThreadSwitch;
Result:=0;
QueryPerformanceCounter(TLargeInteger(Result));
end;
function ps4_sceKernelClockGettime(clockId:Integer;tp:Ptimespec):Integer; SysV_ABI_CDecl;
begin
Result:=ps4_clock_gettime(clockId,tp);
end;
function ps4_sceKernelGetProcessTime:QWORD; SysV_ABI_CDecl; //microseconds
var
ct,et,kt,ut:TFileTime;
begin
if GetProcessTimes(GetCurrentProcess,ct,et,kt,ut) then
begin
Result:=(QWORD(kt)+QWORD(ut)) div 10;
end else
begin
lc_set_errno(EINVAL);
Result:=0;
end;
end;
//1sec=10 000 000
//lpUserTime/ 10 000 000 *1 000 000
//lpUserTime/ 10 *1
function ps4_nanosleep(req,rem:Ptimespec):Integer; SysV_ABI_CDecl;
var
timer:THandle;
ft:TLargeInteger;
begin
if (req=nil) then Exit(EINVAL);
ft:=req^.tv_nsec+req^.tv_sec*1000000000;
ft:=-(ft div 100);
timer:=CreateWaitableTimer(nil,True,nil);
SetWaitableTimer(timer,ft,0,nil,nil,False);
WaitForSingleObject(timer,INFINITE);
CloseHandle(timer);
if (rem<>nil) then
begin
rem^:=Default(timespec);
end;
Result:=0;
end;
function ps4_usleep(usec:Integer):Integer; SysV_ABI_CDecl;
var
timer:THandle;
ft:TLargeInteger;
begin
ft:=-(10*usec);
timer:=CreateWaitableTimer(nil,True,nil);
SetWaitableTimer(timer,ft,0,nil,nil,False);
WaitForSingleObject(timer,INFINITE);
CloseHandle(timer);
Result:=0;
end;
function ps4_sceKernelUsleep(usec:DWORD):Integer; SysV_ABI_CDecl;
var
timer:THandle;
ft:TLargeInteger;
begin
ft:=-(10*usec);
timer:=CreateWaitableTimer(nil,True,nil);
SetWaitableTimer(timer,ft,0,nil,nil,False);
WaitForSingleObject(timer,INFINITE);
CloseHandle(timer);
Result:=0;
end;
initialization
QueryPerformanceFrequency(FPerformanceFrequency);
end.

View File

@ -0,0 +1,107 @@
const
SCE_KERNEL_ERROR_UNKNOWN=Integer($80020000);
SCE_KERNEL_ERROR_EPERM=-2147352575; // 0x80020001
SCE_KERNEL_ERROR_ENOENT=-2147352574; // 0x80020002
SCE_KERNEL_ERROR_ESRCH=-2147352573; // 0x80020003
SCE_KERNEL_ERROR_EINTR=-2147352572; // 0x80020004
SCE_KERNEL_ERROR_EIO=-2147352571; // 0x80020005
SCE_KERNEL_ERROR_ENXIO=-2147352570; // 0x80020006
SCE_KERNEL_ERROR_E2BIG=-2147352569; // 0x80020007
SCE_KERNEL_ERROR_ENOEXEC=-2147352568; // 0x80020008
SCE_KERNEL_ERROR_EBADF=-2147352567; // 0x80020009
SCE_KERNEL_ERROR_ECHILD=-2147352566; // 0x8002000A
SCE_KERNEL_ERROR_EDEADLK=-2147352565; // 0x8002000B
SCE_KERNEL_ERROR_ENOMEM=-2147352564; // 0x8002000C
SCE_KERNEL_ERROR_EACCES=-2147352563; // 0x8002000D
SCE_KERNEL_ERROR_EFAULT=-2147352562; // 0x8002000E
SCE_KERNEL_ERROR_ENOTBLK=-2147352561; // 0x8002000F
SCE_KERNEL_ERROR_EBUSY=-2147352560; // 0x80020010
SCE_KERNEL_ERROR_EEXIST=-2147352559; // 0x80020011
SCE_KERNEL_ERROR_EXDEV=-2147352558; // 0x80020012
SCE_KERNEL_ERROR_ENODEV=-2147352557; // 0x80020013
SCE_KERNEL_ERROR_ENOTDIR=-2147352556; // 0x80020014
SCE_KERNEL_ERROR_EISDIR=-2147352555; // 0x80020015
SCE_KERNEL_ERROR_EINVAL=-2147352554; // 0x80020016
SCE_KERNEL_ERROR_ENFILE=-2147352553; // 0x80020017
SCE_KERNEL_ERROR_EMFILE=-2147352552; // 0x80020018
SCE_KERNEL_ERROR_ENOTTY=-2147352551; // 0x80020019
SCE_KERNEL_ERROR_ETXTBSY=-2147352550; // 0x8002001A
SCE_KERNEL_ERROR_EFBIG=-2147352549; // 0x8002001B
SCE_KERNEL_ERROR_ENOSPC=-2147352548; // 0x8002001C
SCE_KERNEL_ERROR_ESPIPE=-2147352547; // 0x8002001D
SCE_KERNEL_ERROR_EROFS=-2147352546; // 0x8002001E
SCE_KERNEL_ERROR_EMLINK=-2147352545; // 0x8002001F
SCE_KERNEL_ERROR_EPIPE=-2147352544; // 0x80020020
SCE_KERNEL_ERROR_EDOM=-2147352543; // 0x80020021
SCE_KERNEL_ERROR_ERANGE=-2147352542; // 0x80020022
SCE_KERNEL_ERROR_EAGAIN=-2147352541; // 0x80020023
SCE_KERNEL_ERROR_EWOULDBLOCK=-2147352541; // 0x80020023
SCE_KERNEL_ERROR_EINPROGRESS=-2147352540; // 0x80020024
SCE_KERNEL_ERROR_EALREADY=-2147352539; // 0x80020025
SCE_KERNEL_ERROR_ENOTSOCK=-2147352538; // 0x80020026
SCE_KERNEL_ERROR_EDESTADDRREQ=-2147352537; // 0x80020027
SCE_KERNEL_ERROR_EMSGSIZE=-2147352536; // 0x80020028
SCE_KERNEL_ERROR_EPROTOTYPE=-2147352535; // 0x80020029
SCE_KERNEL_ERROR_ENOPROTOOPT=-2147352534; // 0x8002002A
SCE_KERNEL_ERROR_EPROTONOSUPPORT=-2147352533; // 0x8002002B
SCE_KERNEL_ERROR_ESOCKTNOSUPPORT=-2147352532; // 0x8002002C
SCE_KERNEL_ERROR_EOPNOTSUPP=-2147352531; // 0x8002002D
SCE_KERNEL_ERROR_ENOTSUP=-2147352531; // 0x8002002D
SCE_KERNEL_ERROR_EPFNOSUPPORT=-2147352530; // 0x8002002E
SCE_KERNEL_ERROR_EAFNOSUPPORT=-2147352529; // 0x8002002F
SCE_KERNEL_ERROR_EADDRINUSE=-2147352528; // 0x80020030
SCE_KERNEL_ERROR_EADDRNOTAVAIL=-2147352527; // 0x80020031
SCE_KERNEL_ERROR_ENETDOWN=-2147352526; // 0x80020032
SCE_KERNEL_ERROR_ENETUNREACH=-2147352525; // 0x80020033
SCE_KERNEL_ERROR_ENETRESET=-2147352524; // 0x80020034
SCE_KERNEL_ERROR_ECONNABORTED=-2147352523; // 0x80020035
SCE_KERNEL_ERROR_ECONNRESET=-2147352522; // 0x80020036
SCE_KERNEL_ERROR_ENOBUFS=-2147352521; // 0x80020037
SCE_KERNEL_ERROR_EISCONN=-2147352520; // 0x80020038
SCE_KERNEL_ERROR_ENOTCONN=-2147352519; // 0x80020039
SCE_KERNEL_ERROR_ESHUTDOWN=-2147352518; // 0x8002003A
SCE_KERNEL_ERROR_ETOOMANYREFS=-2147352517; // 0x8002003B
SCE_KERNEL_ERROR_ETIMEDOUT=-2147352516; // 0x8002003C
SCE_KERNEL_ERROR_ECONNREFUSED=-2147352515; // 0x8002003D
SCE_KERNEL_ERROR_ELOOP=-2147352514; // 0x8002003E
SCE_KERNEL_ERROR_ENAMETOOLONG=-2147352513; // 0x8002003F
SCE_KERNEL_ERROR_EHOSTDOWN=-2147352512; // 0x80020040
SCE_KERNEL_ERROR_EHOSTUNREACH=-2147352511; // 0x80020041
SCE_KERNEL_ERROR_ENOTEMPTY=-2147352510; // 0x80020042
SCE_KERNEL_ERROR_EPROCLIM=-2147352509; // 0x80020043
SCE_KERNEL_ERROR_EUSERS=-2147352508; // 0x80020044
SCE_KERNEL_ERROR_EDQUOT=-2147352507; // 0x80020045
SCE_KERNEL_ERROR_ESTALE=-2147352506; // 0x80020046
SCE_KERNEL_ERROR_EREMOTE=-2147352505; // 0x80020047
SCE_KERNEL_ERROR_EBADRPC=-2147352504; // 0x80020048
SCE_KERNEL_ERROR_ERPCMISMATCH=-2147352503; // 0x80020049
SCE_KERNEL_ERROR_EPROGUNAVAIL=-2147352502; // 0x8002004A
SCE_KERNEL_ERROR_EPROGMISMATCH=-2147352501; // 0x8002004B
SCE_KERNEL_ERROR_EPROCUNAVAIL=-2147352500; // 0x8002004C
SCE_KERNEL_ERROR_ENOLCK=-2147352499; // 0x8002004D
SCE_KERNEL_ERROR_ENOSYS=-2147352498; // 0x8002004E
SCE_KERNEL_ERROR_EFTYPE=-2147352497; // 0x8002004F
SCE_KERNEL_ERROR_EAUTH=-2147352496; // 0x80020050
SCE_KERNEL_ERROR_ENEEDAUTH=-2147352495; // 0x80020051
SCE_KERNEL_ERROR_EIDRM=-2147352494; // 0x80020052
SCE_KERNEL_ERROR_ENOMSG=-2147352493; // 0x80020053
SCE_KERNEL_ERROR_EOVERFLOW=-2147352492; // 0x80020054
SCE_KERNEL_ERROR_ECANCELED=-2147352491; // 0x80020055
SCE_KERNEL_ERROR_EILSEQ=-2147352490; // 0x80020056
SCE_KERNEL_ERROR_ENOATTR=-2147352489; // 0x80020057
SCE_KERNEL_ERROR_EDOOFUS=-2147352488; // 0x80020058
SCE_KERNEL_ERROR_EBADMSG=-2147352487; // 0x80020059
SCE_KERNEL_ERROR_EMULTIHOP=-2147352486; // 0x8002005A
SCE_KERNEL_ERROR_ENOLINK=-2147352485; // 0x8002005B
SCE_KERNEL_ERROR_EPROTO=-2147352484; // 0x8002005C
SCE_KERNEL_ERROR_ENOTCAPABLE=-2147352483; // 0x8002005D
SCE_KERNEL_ERROR_ECAPMODE=-2147352482; // 0x8002005E
SCE_KERNEL_ERROR_ENOBLK=-2147352481; // 0x8002005F
SCE_KERNEL_ERROR_EICV=-2147352480; // 0x80020060
SCE_KERNEL_ERROR_ENOPLAYGOENT=-2147352479; // 0x80020061
SCE_KERNEL_ERROR_EREVOKE=-2147352478; // 0x80020062
SCE_KERNEL_ERROR_ESDKVERSION=-2147352477; // 0x80020063
SCE_KERNEL_ERROR_ESTART=-2147352476; // 0x80020064
SCE_KERNEL_ERROR_ESTOP=-2147352475; // 0x80020065

187
ps4_libkerenel/spinlock.pas Normal file
View File

@ -0,0 +1,187 @@
unit spinlock;
{$mode objfpc}{$H+}
interface
type
backoff_exp=object
private
Const
lower_bound = 16; ///< Minimum spinning limit
upper_bound = 16*1024; ///< Maximum spinning limit
Var
m_nExpCur:SizeUInt; //=lower_bound
public
Procedure Wait;
Procedure Reset;
end;
function spin_trylock(Var P:Pointer):Boolean; inline;
function spin_trylock(Var P:DWORD):Boolean; inline;
function spin_tryunlock(Var P:Pointer):Boolean; inline;
function spin_tryunlock(Var P:DWORD):Boolean; inline;
procedure spin_lock(Var P:Pointer);
procedure spin_lock(Var P:DWORD);
procedure spin_unlock(Var P:Pointer);
procedure spin_unlock(Var P:DWORD);
function event_try_enable(Var P:Pointer):Boolean;
function event_try_enable(Var P:DWORD):Boolean;
function event_try_disable(Var P:Pointer):Boolean;
function event_try_disable(Var P:DWORD):Boolean;
procedure event_disable(Var P:Pointer);
procedure event_disable(Var P:DWORD);
implementation
function XCHG(Var addr:Pointer;New:Pointer):Pointer; inline;
begin
Result:=System.InterLockedExchange(addr,New);
end;
function XCHG(Var addr:DWORD;New:DWORD):DWORD; inline;
begin
Result:=System.InterLockedExchange(addr,New);
end;
function CAS(Var addr:Pointer;Comp,New:Pointer):Boolean; inline;
begin
Result:=System.InterlockedCompareExchange(addr,New,Comp)=Comp;
end;
function CAS(Var addr:DWORD;Comp,New:DWORD):Boolean; inline;
begin
Result:=System.InterlockedCompareExchange(addr,New,Comp)=Comp;
end;
Procedure store_release(Var addr:Pointer;v:Pointer); inline;
begin
WriteBarrier;
addr:=v;
end;
Procedure store_release(Var addr:DWORD;v:DWORD); inline;
begin
WriteBarrier;
addr:=v;
end;
procedure spin_pause; assembler; nostackframe;
asm
pause
end;
Procedure backoff_exp.Wait;
Var
n:SizeUInt;
begin
if (m_nExpCur<=upper_bound) then
begin
For n:=0 to m_nExpCur-1 do
begin
spin_pause;
end;
m_nExpCur:=m_nExpCur*2;
end else
begin
System.ThreadSwitch;
end;
end;
Procedure backoff_exp.Reset;
begin
m_nExpCur:=lower_bound;
end;
function spin_trylock(Var P:Pointer):Boolean; inline;
begin
Result:=XCHG(P,Pointer(1))=nil;
end;
function spin_trylock(Var P:DWORD):Boolean; inline;
begin
Result:=XCHG(P,1)=0;
end;
function spin_tryunlock(Var P:Pointer):Boolean; inline;
begin
Result:=XCHG(P,nil)=Pointer(1);
end;
function spin_tryunlock(Var P:DWORD):Boolean; inline;
begin
Result:=XCHG(P,0)=1;
end;
procedure spin_lock(Var P:Pointer);
Var
bkoff:backoff_exp;
begin
bkoff.Reset;
While (XCHG(P,Pointer(1))<>nil) do bkoff.Wait;
end;
procedure spin_lock(Var P:DWORD);
Var
bkoff:backoff_exp;
begin
bkoff.Reset;
While (XCHG(P,1)<>0) do bkoff.Wait;
end;
procedure spin_unlock(Var P:Pointer);
begin
store_release(P,nil);
end;
procedure spin_unlock(Var P:DWORD);
begin
store_release(P,0);
end;
const
EVL_DIS=0; //disable
EVL_NEW=1; //new
EVL_ENB=2; //enable
function event_try_enable(Var P:Pointer):Boolean;
begin
Result:=(XCHG(P,Pointer(EVL_NEW))=Pointer(EVL_DIS));
if Result then
begin
store_release(P,Pointer(EVL_ENB));
end;
end;
function event_try_enable(Var P:DWORD):Boolean;
begin
Result:=(XCHG(P,EVL_NEW)=EVL_DIS);
if Result then
begin
store_release(P,EVL_ENB);
end;
end;
function event_try_disable(Var P:Pointer):Boolean;
begin
Result:=CAS(P,Pointer(EVL_ENB),Pointer(EVL_DIS));
end;
function event_try_disable(Var P:DWORD):Boolean;
begin
Result:=CAS(P,EVL_ENB,EVL_DIS);
end;
procedure event_disable(Var P:Pointer);
begin
store_release(P,Pointer(EVL_DIS));
end;
procedure event_disable(Var P:DWORD);
begin
store_release(P,EVL_DIS);
end;
end.

641
ps4_libsceaudioout.pas Normal file
View File

@ -0,0 +1,641 @@
unit ps4_libSceAudioOut;
{$mode objfpc}{$H+}
{/$define silent}
interface
uses
libportaudio,
ps4_handles,
ps4_program,
Classes, SysUtils;
implementation
uses
ps4_libkernel;
const
SCE_AUDIO_OUT_ERROR_NOT_OPENED =-2144993279; // 0x80260001
SCE_AUDIO_OUT_ERROR_BUSY =-2144993278; // 0x80260002
SCE_AUDIO_OUT_ERROR_INVALID_PORT =-2144993277; // 0x80260003
SCE_AUDIO_OUT_ERROR_INVALID_POINTER =-2144993276; // 0x80260004
SCE_AUDIO_OUT_ERROR_PORT_FULL =-2144993275; // 0x80260005
SCE_AUDIO_OUT_ERROR_INVALID_SIZE =-2144993274; // 0x80260006
SCE_AUDIO_OUT_ERROR_INVALID_FORMAT =-2144993273; // 0x80260007
SCE_AUDIO_OUT_ERROR_INVALID_SAMPLE_FREQ=-2144993272; // 0x80260008
SCE_AUDIO_OUT_ERROR_INVALID_VOLUME =-2144993271; // 0x80260009
SCE_AUDIO_OUT_ERROR_INVALID_PORT_TYPE =-2144993270; // 0x8026000A
SCE_AUDIO_OUT_ERROR_INVALID_CONF_TYPE =-2144993268; // 0x8026000C
SCE_AUDIO_OUT_ERROR_OUT_OF_MEMORY =-2144993267; // 0x8026000D
SCE_AUDIO_OUT_ERROR_ALREADY_INIT =-2144993266; // 0x8026000E
SCE_AUDIO_OUT_ERROR_NOT_INIT =-2144993265; // 0x8026000F
SCE_AUDIO_OUT_ERROR_MEMORY =-2144993264; // 0x80260010
SCE_AUDIO_OUT_ERROR_SYSTEM_RESOURCE =-2144993263; // 0x80260011
SCE_AUDIO_OUT_ERROR_TRANS_EVENT =-2144993262; // 0x80260012
SCE_AUDIO_OUT_ERROR_INVALID_FLAG =-2144993261; // 0x80260013
SCE_AUDIO_OUT_ERROR_INVALID_MIXLEVEL =-2144993260; // 0x80260014
SCE_AUDIO_OUT_ERROR_INVALID_ARG =-2144993259; // 0x80260015
SCE_AUDIO_OUT_ERROR_INVALID_PARAM =-2144993258; // 0x80260016
SCE_AUDIO_MIN_LEN=256;
SCE_AUDIO_MAX_LEN=(256*8);
SCE_AUDIO_OUT_PORT_TYPE_MAIN =0;
SCE_AUDIO_OUT_PORT_TYPE_BGM =1;
SCE_AUDIO_OUT_PORT_TYPE_VOICE =2;
SCE_AUDIO_OUT_PORT_TYPE_PERSONAL =3;
SCE_AUDIO_OUT_PORT_TYPE_PADSPK =4;
SCE_AUDIO_OUT_PORT_TYPE_AUX =127;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_MONO =0;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_STEREO =1;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_8CH =2;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_MONO =3;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_STEREO =4;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH =5;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_8CH_STD =6;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH_STD=7;
SCE_AUDIO_OUT_PARAM_FORMAT_MASK =$000000FF;
SCE_AUDIO_OUT_PARAM_FORMAT_SHIFT =0;
SCE_AUDIO_OUT_PARAM_ATTR_RESTRICTED =$00010000;
SCE_AUDIO_OUT_PARAM_ATTR_MIX_TO_MAIN =$00020000;
SCE_AUDIO_OUT_PARAM_ATTR_MASK =$000F0000;
SCE_AUDIO_OUT_PARAM_ATTR_SHIFT =16;
SCE_AUDIO_VOLUME_SHIFT =15;
SCE_AUDIO_VOLUME_0DB =(1<<SCE_AUDIO_VOLUME_SHIFT);
SCE_AUDIO_VOLUME_FLAG_L_CH =(1 shl 0);
SCE_AUDIO_VOLUME_FLAG_R_CH =(1 shl 1);
SCE_AUDIO_VOLUME_FLAG_C_CH =(1 shl 2);
SCE_AUDIO_VOLUME_FLAG_LFE_CH =(1 shl 3);
SCE_AUDIO_VOLUME_FLAG_LS_CH =(1 shl 4);
SCE_AUDIO_VOLUME_FLAG_RS_CH =(1 shl 5);
SCE_AUDIO_VOLUME_FLAG_LE_CH =(1 shl 6);
SCE_AUDIO_VOLUME_FLAG_RE_CH =(1 shl 7);
var
_lazy_init:Integer=0;
_lazy_wait:Integer=0;
HAudioOuts:TIntegerHandles;
function ps4_sceAudioOutInit():Integer; SysV_ABI_CDecl;
begin
if System.InterlockedExchange(_lazy_init,1)=0 then
begin
Result:=Pa_Initialize();
if (Result<>0) then Exit(SCE_AUDIO_OUT_ERROR_TRANS_EVENT);
HAudioOuts:=TIntegerHandles.Create;
System.InterLockedExchangeAdd(_lazy_wait,1);
end else
begin
While (System.InterLockedExchangeAdd(_lazy_wait,0)=0) do System.ThreadSwitch;
Result:=SCE_AUDIO_OUT_ERROR_ALREADY_INIT;
end;
//Writeln('sceAudioOutInit');
//Result:=111;
end;
{
userId
User ID of the output destination
type
Virtual device type
index
Device index (unused; specify 0)
len
Granularity (number of samples to be output at once; 256, 512, 768, 1024, 1280, 1536, 1792, or 2048)
freq
Sampling frequency (Hz; specify 48000)
param
Data format, etc.
}
type
TAudioOutHandle=class(TClassHandle)
userId,_type,index:Integer;
len,freq,param:DWORD;
volume:array[0..7] of Integer;
pstream:PaStream;
pnumOutputChannels:Integer;
psampleFormat:PaSampleFormat;
bufsize:Integer;
buf:Pointer;
//d:QWORD;
Destructor Destroy; override;
end;
Destructor TAudioOutHandle.Destroy;
begin
Pa_StopStream(pstream);
Pa_CloseStream(pstream);
FreeMem(buf);
inherited;
end;
//int32_t SceUserServiceUserId;
function ps4_sceAudioOutOpen(userId,_type,index:Integer;
len,freq,param:DWORD):Integer; SysV_ABI_CDecl;
Var
H:TAudioOutHandle;
i:Byte;
err:Integer;
pstream:PaStream;
pnumOutputChannels:Integer;
psampleFormat:PaSampleFormat;
begin
Result:=0;
if (HAudioOuts=nil) then Exit(SCE_AUDIO_OUT_ERROR_NOT_INIT);
case _type of
SCE_AUDIO_OUT_PORT_TYPE_MAIN :;
SCE_AUDIO_OUT_PORT_TYPE_BGM :;
SCE_AUDIO_OUT_PORT_TYPE_VOICE :;
SCE_AUDIO_OUT_PORT_TYPE_PERSONAL:;
SCE_AUDIO_OUT_PORT_TYPE_PADSPK :;
SCE_AUDIO_OUT_PORT_TYPE_AUX :;
else
Exit(SCE_AUDIO_OUT_ERROR_INVALID_PORT_TYPE);
end;
case len of
256,
512,
768,
1024,
1280,
1536,
1792,
2048:;
else
Exit(SCE_AUDIO_OUT_ERROR_INVALID_SIZE);
end;
case freq of
48000:;
else
Exit(SCE_AUDIO_OUT_ERROR_INVALID_SAMPLE_FREQ);
end;
case (param and SCE_AUDIO_OUT_PARAM_FORMAT_MASK) of
SCE_AUDIO_OUT_PARAM_FORMAT_S16_MONO:
begin
pnumOutputChannels:=1;
psampleFormat:=paInt16;
end;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_STEREO:
begin
pnumOutputChannels:=2;
psampleFormat:=paInt16;
end;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_8CH:
begin
pnumOutputChannels:=8;
psampleFormat:=paInt16;
end;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_MONO:
begin
pnumOutputChannels:=1;
psampleFormat:=paFloat32;
end;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_STEREO:
begin
pnumOutputChannels:=2;
psampleFormat:=paFloat32;
end;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH:
begin
pnumOutputChannels:=8;
psampleFormat:=paFloat32;
end;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_8CH_STD:
begin
pnumOutputChannels:=8;
psampleFormat:=paInt16;
end;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH_STD:
begin
pnumOutputChannels:=8;
psampleFormat:=paFloat32;
end;
else
Exit(SCE_AUDIO_OUT_ERROR_INVALID_FORMAT);
end;
err:=Pa_OpenDefaultStream(@pstream,
0,
pnumOutputChannels,
psampleFormat,
freq,
paFramesPerBufferUnspecified,nil,nil);
if (err<>0) and (pnumOutputChannels>2) then
begin
pnumOutputChannels:=2;
err:=Pa_OpenDefaultStream(@pstream,
0,
pnumOutputChannels,
psampleFormat,
freq,
paFramesPerBufferUnspecified,nil,nil);
end;
if (err<>0) then
begin
Exit(SCE_AUDIO_OUT_ERROR_NOT_INIT);
end;
err:=Pa_StartStream(pstream);
if (err<>0) then
begin
Exit(SCE_AUDIO_OUT_ERROR_NOT_INIT);
end;
H:=TAudioOutHandle.Create;
H.userId:=userId;
H._type :=_type ;
H.index :=index ;
H.len :=len ;
H.freq :=freq ;
H.param :=param ;
For i:=0 to 7 do
H.volume[i]:=SCE_AUDIO_VOLUME_0DB;
H.pstream :=pstream;
H.pnumOutputChannels:=pnumOutputChannels;
H.psampleFormat :=psampleFormat;
if not HAudioOuts.New(H,Result) then Result:=SCE_AUDIO_OUT_ERROR_PORT_FULL;
Case QWORD(psampleFormat) of
QWORD(paInt16 ):H.bufsize:=2*pnumOutputChannels*len;
QWORD(paFloat32):H.bufsize:=4*pnumOutputChannels*len;
end;
H.buf:=GetMem(H.bufsize);
H.Release;
Writeln('AudioOutOpen:',userId,':',_type,':',index,':',len,':',freq,':',param);
end;
function ps4_sceAudioOutClose(handle:Integer):Integer; SysV_ABI_CDecl;
begin
if (HAudioOuts=nil) then Exit(SCE_AUDIO_OUT_ERROR_NOT_INIT);
if not HAudioOuts.Delete(handle) then Exit(SCE_AUDIO_OUT_ERROR_INVALID_PORT);
Result:=0;
end;
function ps4_sceAudioOutSetVolume(handle,flag:Integer;vol:PInteger):Integer; SysV_ABI_CDecl;
Var
H:TAudioOutHandle;
i:Integer;
begin
if (HAudioOuts=nil) then Exit(SCE_AUDIO_OUT_ERROR_NOT_INIT);
if (vol=nil) then Exit(SCE_AUDIO_OUT_ERROR_INVALID_POINTER);
i:=vol^;
if (i>SCE_AUDIO_VOLUME_0DB) then Exit(SCE_AUDIO_OUT_ERROR_INVALID_VOLUME);
{$ifdef silent}if (i>800) then i:=800;{$endif}
H:=TAudioOutHandle(HAudioOuts.Acqure(handle));
if (H=nil) then Exit(SCE_AUDIO_OUT_ERROR_INVALID_PORT);
if (flag and SCE_AUDIO_VOLUME_FLAG_L_CH <>0) then H.volume[0]:=i;
if (flag and SCE_AUDIO_VOLUME_FLAG_R_CH <>0) then H.volume[1]:=i;
if (flag and SCE_AUDIO_VOLUME_FLAG_C_CH <>0) then H.volume[2]:=i;
if (flag and SCE_AUDIO_VOLUME_FLAG_LFE_CH<>0) then H.volume[3]:=i;
if (flag and SCE_AUDIO_VOLUME_FLAG_LS_CH <>0) then H.volume[4]:=i;
if (flag and SCE_AUDIO_VOLUME_FLAG_RS_CH <>0) then H.volume[5]:=i;
if (flag and SCE_AUDIO_VOLUME_FLAG_LE_CH <>0) then H.volume[6]:=i;
if (flag and SCE_AUDIO_VOLUME_FLAG_RE_CH <>0) then H.volume[7]:=i;
H.Release;
Writeln('sceAudioOutSetVolume:',handle,':',flag);
Result:=0;
end;
procedure _VecMulI16M(Src,Dst:Pointer;count:Integer;volume:Integer);// inline;
begin
if volume=SCE_AUDIO_VOLUME_0DB then
begin
Move(Src^,Dst^,count*2);
end else
While (count>0) do
begin
PSmallInt(Dst)^:=(PSmallInt(Src)^*volume) div SCE_AUDIO_VOLUME_0DB;
Inc(Src,2);
Inc(Dst,2);
Dec(count);
end;
end;
procedure _VecMulI16S(Src,Dst:Pointer;count:Integer;volume:PInteger); inline;
begin
if (volume[0]=SCE_AUDIO_VOLUME_0DB) and (volume[1]=SCE_AUDIO_VOLUME_0DB) then
begin
Move(Src^,Dst^,count*2*2);
end else
While (count>0) do
begin
PSmallInt(Dst)^:=(PSmallInt(Src)^*volume[0]) div SCE_AUDIO_VOLUME_0DB;
Inc(Src,2);
Inc(Dst,2);
PSmallInt(Dst)^:=(PSmallInt(Src)^*volume[1]) div SCE_AUDIO_VOLUME_0DB;
Inc(Src,2);
Inc(Dst,2);
Dec(count);
end;
end;
procedure _VecMulF32M(Src,Dst:Pointer;count:Integer;volume:Integer); inline;
var
fvolume:Single;
begin
if volume=SCE_AUDIO_VOLUME_0DB then
begin
Move(Src^,Dst^,count*4);
end else
begin
fvolume:=volume/SCE_AUDIO_VOLUME_0DB;
While (count>0) do
begin
PSingle(Dst)^:=PSingle(Src)^*fvolume;
Inc(Src,4);
Inc(Dst,4);
Dec(count);
end;
end;
end;
procedure _VecMulF32S(Src,Dst:Pointer;count:Integer;volume:PInteger); inline;
var
fvolume:array[0..1] of Single;
begin
if (volume[0]=SCE_AUDIO_VOLUME_0DB) and (volume[1]=SCE_AUDIO_VOLUME_0DB) then
begin
Move(Src^,Dst^,count*4*2);
end else
begin
fvolume[0]:=volume[0]/SCE_AUDIO_VOLUME_0DB;
fvolume[1]:=volume[1]/SCE_AUDIO_VOLUME_0DB;
While (count>0) do
begin
PSingle(Dst)^:=PSingle(Src)^*fvolume[0];
Inc(Src,4);
Inc(Dst,4);
PSingle(Dst)^:=PSingle(Src)^*fvolume[1];
Inc(Src,4);
Inc(Dst,4);
Dec(count);
end;
end;
end;
// 1+3/2
//L=FL+0.707*C+0.707*SL+0.707*BL
//R=FR+0.707*C+0.707*SR+0.707*BR
//1/2
const
_FL=0;
_FR=1;
_FC=2;
_LF=3;
_SL=4;
_SR=5;
_BL=6;
_BR=7;
procedure _VecMulF32CH8ToS(Src,Dst:Pointer;count:Integer;volume:PInteger);
const
fdiv1:Single=1+(3/Sqrt(2));
fdiv2:Single=(1/Sqrt(2))*(1+(3/Sqrt(2)));
var
fvolume:array[0..7] of Single;
fL,fR:Single;
begin
fvolume[_FL]:=(volume[_FL]/SCE_AUDIO_VOLUME_0DB)*fdiv1;
fvolume[_FR]:=(volume[_FR]/SCE_AUDIO_VOLUME_0DB)*fdiv1;
fvolume[_FC]:=(volume[_FC]/SCE_AUDIO_VOLUME_0DB)*fdiv2;
fvolume[_SL]:=(volume[_SL]/SCE_AUDIO_VOLUME_0DB)*fdiv2;
fvolume[_SR]:=(volume[_SR]/SCE_AUDIO_VOLUME_0DB)*fdiv2;
fvolume[_BL]:=(volume[_BL]/SCE_AUDIO_VOLUME_0DB)*fdiv2;
fvolume[_BR]:=(volume[_BR]/SCE_AUDIO_VOLUME_0DB)*fdiv2;
While (count>0) do
begin
fL:=(PSingle(Src)[_FL]*fvolume[_FL])+
(PSingle(Src)[_FC]*fvolume[_FC])+
(PSingle(Src)[_SL]*fvolume[_SL])+
(PSingle(Src)[_BL]*fvolume[_BL]);
fR:=(PSingle(Src)[_FR]*fvolume[_FR])+
(PSingle(Src)[_FC]*fvolume[_FC])+
(PSingle(Src)[_SR]*fvolume[_SR])+
(PSingle(Src)[_BR]*fvolume[_BR]);
//fL:=fL*0.05;
//fR:=fR*0.05;
PSingle(Dst)^:=fL;
Inc(Dst,4);
PSingle(Dst)^:=fR;
Inc(Dst,4);
Inc(Src,4*8);
Dec(count);
end;
end;
function ps4_sceAudioOutOutput(handle:Integer;ptr:Pointer):Integer; SysV_ABI_CDecl;
Var
H:TAudioOutHandle;
count,err:Integer;
begin
if (HAudioOuts=nil) then Exit(SCE_AUDIO_OUT_ERROR_NOT_INIT);
if (ptr=nil) then Exit(0);
err:=0;
H:=TAudioOutHandle(HAudioOuts.Acqure(handle));
if (H=nil) then Exit(SCE_AUDIO_OUT_ERROR_INVALID_PORT);
count:=H.len;
case (H.param and SCE_AUDIO_OUT_PARAM_FORMAT_MASK) of
SCE_AUDIO_OUT_PARAM_FORMAT_S16_MONO:
begin
_VecMulI16M(ptr,H.buf,count,H.volume[0]);
err:=Pa_WriteStream(H.pstream,H.buf,count);
end;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_STEREO:
begin
_VecMulI16S(ptr,H.buf,count,@H.volume);
err:=Pa_WriteStream(H.pstream,H.buf,count);
end;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_8CH:
begin
Assert(false);
end;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_MONO:
begin
_VecMulF32M(ptr,H.buf,count,H.volume[0]);
err:=Pa_WriteStream(H.pstream,H.buf,count);
end;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_STEREO:
begin
_VecMulF32S(ptr,H.buf,count,@H.volume);
err:=Pa_WriteStream(H.pstream,H.buf,count);
end;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH:
begin
if H.pnumOutputChannels=2 then
begin
_VecMulF32CH8ToS(ptr,H.buf,count,@H.volume);
err:=Pa_WriteStream(H.pstream,H.buf,count);
end else
begin
Assert(false);
end;
end;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_8CH_STD:
begin
Assert(false);
end;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH_STD:
begin
Assert(false);
end;
end;
if err<>0 then
case PaErrorCode(err) of
paNotInitialized :Writeln('paNotInitialized ');
paUnanticipatedHostError :Writeln('paUnanticipatedHostError ');
paInvalidChannelCount :Writeln('paInvalidChannelCount ');
paInvalidSampleRate :Writeln('paInvalidSampleRate ');
paInvalidDevice :Writeln('paInvalidDevice ');
paInvalidFlag :Writeln('paInvalidFlag ');
paSampleFormatNotSupported :Writeln('paSampleFormatNotSupported ');
paBadIODeviceCombination :Writeln('paBadIODeviceCombination ');
paInsufficientMemory :Writeln('paInsufficientMemory ');
paBufferTooBig :Writeln('paBufferTooBig ');
paBufferTooSmall :Writeln('paBufferTooSmall ');
paNullCallback :Writeln('paNullCallback ');
paBadStreamPtr :Writeln('paBadStreamPtr ');
paTimedOut :Writeln('paTimedOut ');
paInternalError :Writeln('paInternalError ');
paDeviceUnavailable :Writeln('paDeviceUnavailable ');
paIncompatibleHostApiSpecificStreamInfo:Writeln('paIncompatibleHostApiSpecificStreamInfo');
paStreamIsStopped :Writeln('paStreamIsStopped ');
paStreamIsNotStopped :Writeln('paStreamIsNotStopped ');
paInputOverflowed :Writeln('paInputOverflowed ');
paOutputUnderflowed :Writeln('paOutputUnderflowed ');
paHostApiNotFound :Writeln('paHostApiNotFound ');
paInvalidHostApi :Writeln('paInvalidHostApi ');
paCanNotReadFromACallbackStream :Writeln('paCanNotReadFromACallbackStream ');
paCanNotWriteToACallbackStream :Writeln('paCanNotWriteToACallbackStream ');
paCanNotReadFromAnOutputOnlyStream :Writeln('paCanNotReadFromAnOutputOnlyStream ');
paCanNotWriteToAnInputOnlyStream :Writeln('paCanNotWriteToAnInputOnlyStream ');
paIncompatibleStreamHostApi :Writeln('paIncompatibleStreamHostApi ');
paBadBufferPtr :Writeln('paBadBufferPtr ');
end;
//Writeln('sceAudioOutOutput:',handle,':',HexStr(ptr));
H.Release;
Result:=0;
end;
type
PSceAudioOutOutputParam=^SceAudioOutOutputParam;
SceAudioOutOutputParam=packed record
handle:Integer;
align:Integer;
ptr:Pointer;
end;
function ps4_sceAudioOutOutputs(param:PSceAudioOutOutputParam;num:DWORD):Integer; SysV_ABI_CDecl;
var
i:DWORD;
begin
if (param=nil) then Exit(SCE_AUDIO_OUT_ERROR_INVALID_POINTER);
if (num=0) then Exit(SCE_AUDIO_OUT_ERROR_INVALID_PARAM);
For i:=0 to num-1 do
begin
Result:=ps4_sceAudioOutOutput(param[i].handle,param[i].ptr);
if (Result<>0) then Exit;
end;
end;
function Load_libSceAudioOut(Const name:RawByteString):TElf_node;
var
lib:PLIBRARY;
begin
Result:=TElf_node.Create;
Result.pFileName:=name;
lib:=Result._add_lib('libSceAudioOut');
lib^.set_proc($25F10F5D5C6116A0,@ps4_sceAudioOutInit);
lib^.set_proc($7A436FB13DB6AEC6,@ps4_sceAudioOutOpen);
lib^.set_proc($B35FFFB84F66045C,@ps4_sceAudioOutClose);
lib^.set_proc($6FEB8057CF489711,@ps4_sceAudioOutSetVolume);
lib^.set_proc($40E42D6DE0EAB13E,@ps4_sceAudioOutOutput);
lib^.set_proc($C373DD6924D2C061,@ps4_sceAudioOutOutputs);
end;
const
SCE_AUDIO_IN_ERROR_NOT_OPENED=$80260109;
function ps4_sceAudioInOpen(userID,busType,index,len,freq,param:Integer):Integer; SysV_ABI_CDecl;
begin
Result:=Integer(SCE_AUDIO_IN_ERROR_NOT_OPENED);
end;
function Load_libSceAudioIn(Const name:RawByteString):TElf_node;
var
lib:PLIBRARY;
begin
Result:=TElf_node.Create;
Result.pFileName:=name;
lib:=Result._add_lib('libSceAudioIn');
lib^.set_proc($E4D13C4A373B542F,@ps4_sceAudioInOpen);
end;
initialization
ps4_app.RegistredPreLoad('libSceAudioOut.prx',@Load_libSceAudioOut);
ps4_app.RegistredPreLoad('libSceAudioIn.prx',@Load_libSceAudioIn);
end.

116
ps4_libscedialogs.pas Normal file
View File

@ -0,0 +1,116 @@
unit ps4_libSceDialogs;
{$mode objfpc}{$H+}
interface
uses
ps4_program,
Classes, SysUtils;
implementation
const
//SceCommonDialogStatus
SCE_COMMON_DIALOG_STATUS_NONE = 0;
SCE_COMMON_DIALOG_STATUS_INITIALIZED = 1;
SCE_COMMON_DIALOG_STATUS_RUNNING = 2;
SCE_COMMON_DIALOG_STATUS_FINISHED = 3;
//SceCommonDialogResult {
SCE_COMMON_DIALOG_RESULT_OK = 0;
SCE_COMMON_DIALOG_RESULT_USER_CANCELED = 1;
function ps4_sceCommonDialogInitialize():Integer; SysV_ABI_CDecl;
begin
Writeln('sceCommonDialogInitialize');
Result:=0;
end;
function ps4_sceErrorDialogInitialize():Integer; SysV_ABI_CDecl;
begin
Writeln('sceErrorDialogInitialize');
Result:=0;
end;
function ps4_sceNpProfileDialogInitialize():Integer; SysV_ABI_CDecl;
begin
Writeln('sceNpProfileDialogInitialize');
Result:=0;
end;
function ps4_sceSaveDataDialogUpdateStatus():Integer; SysV_ABI_CDecl;
begin
Writeln('sceSaveDataDialogUpdateStatus');
Result:=SCE_COMMON_DIALOG_STATUS_NONE;
end;
function ps4_sceSaveDataDialogProgressBarSetValue(target:Integer;rate:DWORD):Integer; SysV_ABI_CDecl;
begin
Writeln('sceSaveDataDialogProgressBarSetValue:',rate);
Result:=0;
end;
function ps4_sceSaveDataDialogTerminate():Integer; SysV_ABI_CDecl;
begin
Writeln('sceSaveDataDialogTerminate');
Result:=0;
end;
function Load_libSceCommonDialog(Const name:RawByteString):TElf_node;
var
lib:PLIBRARY;
begin
Result:=TElf_node.Create;
Result.pFileName:=name;
lib:=Result._add_lib('libSceCommonDialog');
lib^.set_proc($BA85292C6364CA09,@ps4_sceCommonDialogInitialize);
end;
//
function Load_libSceErrorDialog(Const name:RawByteString):TElf_node;
var
lib:PLIBRARY;
begin
Result:=TElf_node.Create;
Result.pFileName:=name;
lib:=Result._add_lib('libSceErrorDialog');
lib^.set_proc($23CF0A0A19729D2B,@ps4_sceErrorDialogInitialize);
end;
//
function Load_libSceNpProfileDialog(Const name:RawByteString):TElf_node;
var
lib:PLIBRARY;
begin
Result:=TElf_node.Create;
Result.pFileName:=name;
lib:=Result._add_lib('libSceNpProfileDialog');
lib^.set_proc($2E0F8D084EA94F04,@ps4_sceNpProfileDialogInitialize);
end;
//
function Load_libSceSaveDataDialog(Const name:RawByteString):TElf_node;
var
lib:PLIBRARY;
begin
Result:=TElf_node.Create;
Result.pFileName:=name;
lib:=Result._add_lib('libSceSaveDataDialog');
lib^.set_proc($28ADC1760D5158AD,@ps4_sceSaveDataDialogUpdateStatus);
lib^.set_proc($85ACB509F4E62F20,@ps4_sceSaveDataDialogProgressBarSetValue);
lib^.set_proc($62E1F6140EDACEA4,@ps4_sceSaveDataDialogTerminate);
end;
initialization
ps4_app.RegistredPreLoad('libSceCommonDialog.prx',@Load_libSceCommonDialog);
ps4_app.RegistredPreLoad('libSceErrorDialog.prx',@Load_libSceErrorDialog);
ps4_app.RegistredPreLoad('libSceNpProfileDialog.prx',@Load_libSceNpProfileDialog);
ps4_app.RegistredPreLoad('libSceSaveDataDialog.prx',@Load_libSceSaveDataDialog);
end.

1161
ps4_libscegnmdriver.pas Normal file

File diff suppressed because it is too large Load Diff

68
ps4_libscehttp.pas Normal file
View File

@ -0,0 +1,68 @@
unit ps4_libSceHttp;
{$mode objfpc}{$H+}
interface
uses
ps4_program,
Classes, SysUtils;
implementation
function ps4_sceHttpInit(libnetMemId,libsslCtxId:Integer;poolSize:size_t):Integer; SysV_ABI_CDecl;
begin
Writeln('sceHttpInit:',poolSize);
Result:=4;
end;
function ps4_sceHttpCreateTemplate(
libhttpCtxId:Integer;
userAgent:PChar;
httpVer:Integer;
autoProxyConf:Integer):Integer; SysV_ABI_CDecl;
begin
Writeln('userAgent:',userAgent);
Result:=0;
end;
function ps4_sceHttpSetNonblock(id:Integer;enable:Boolean):Integer; SysV_ABI_CDecl;
begin
Result:=0;
end;
type
PSceHttpEpollHandle=^SceHttpEpollHandle;
SceHttpEpollHandle=Pointer;
function ps4_sceHttpCreateEpoll(libhttpCtxId:Integer;eh:PSceHttpEpollHandle):Integer; SysV_ABI_CDecl;
begin
Result:=0;
eh^:=Pointer($BADF);
end;
function ps4_sceHttpAddRequestHeader(id:Integer;name:PChar;value:PChar;mode:Integer):Integer; SysV_ABI_CDecl;
begin
Result:=0;
Writeln(name,': ',value);
end;
function Load_libSceHttp(Const name:RawByteString):TElf_node;
var
lib:PLIBRARY;
begin
Result:=TElf_node.Create;
Result.pFileName:=name;
lib:=Result._add_lib('libSceHttp');
lib^.set_proc($03D715314B44A786,@ps4_sceHttpInit);
lib^.set_proc($D206233D347FE9C6,@ps4_sceHttpCreateTemplate);
lib^.set_proc($B36FCD3C8BF3FA20,@ps4_sceHttpSetNonblock);
lib^.set_proc($EB7F3575617EC6C4,@ps4_sceHttpCreateEpoll);
lib^.set_proc($118DBC4F66E437B9,@ps4_sceHttpAddRequestHeader);
end;
initialization
ps4_app.RegistredPreLoad('libSceHttp.prx',@Load_libSceHttp);
end.

116
ps4_libscenet.pas Normal file
View File

@ -0,0 +1,116 @@
unit ps4_libSceNet;
{$mode objfpc}{$H+}
interface
uses
ps4_program,
Classes, SysUtils;
implementation
function ps4_sceNetInit:Integer; SysV_ABI_CDecl;
begin
Result:=0;
end;
function ps4_sceNetPoolCreate(name:PChar;size,flags:Integer):Integer; SysV_ABI_CDecl;
begin
Writeln('sceNetPoolCreate:',name,':',size,':',flags);
Result:=2;
end;
//
function ps4_sceNetCtlInit:Integer; SysV_ABI_CDecl;
begin
Result:=0;
end;
const
SCE_NET_CTL_ERROR_INVALID_ADDR=$80412107;
SCE_NET_CTL_STATE_DISCONNECTED=0;
SCE_NET_CTL_STATE_CONNECTING =1;
SCE_NET_CTL_STATE_IPOBTAINING =2;
SCE_NET_CTL_STATE_IPOBTAINED =3;
SCE_NET_CTL_EVENT_TYPE_DISCONNECTED=1;
SCE_NET_CTL_EVENT_TYPE_DISCONNECT_REQ_FINISHED=2;
SCE_NET_CTL_EVENT_TYPE_IPOBTAINED=3;
function ps4_sceNetCtlGetState(state:PInteger):Integer; SysV_ABI_CDecl;
begin
if (state=nil) then Exit(Integer(SCE_NET_CTL_ERROR_INVALID_ADDR));
state^:=SCE_NET_CTL_STATE_DISCONNECTED;
Result:=0;
end;
type
SceNetCtlCallback=Procedure(eventType:Integer;arg:Pointer); SysV_ABI_CDecl;
var
NetCtlCb:packed record
func:SceNetCtlCallback;
arg:Pointer;
end;
function ps4_sceNetCtlRegisterCallback(func:SceNetCtlCallback;arg:Pointer;cid:PInteger):Integer; SysV_ABI_CDecl;
begin
NetCtlCb.func:=func;
NetCtlCb.arg:=arg;
if (cid<>nil) then cid^:=0;
Result:=0;
end;
function ps4_sceNetCtlCheckCallback():Integer; SysV_ABI_CDecl;
begin
if (NetCtlCb.func<>nil) then
begin
NetCtlCb.func(SCE_NET_CTL_EVENT_TYPE_DISCONNECTED,NetCtlCb.arg);
end;
Result:=0;
end;
Const
SCE_NET_CTL_ERROR_ETHERNET_PLUGOUT=$80412115;
function ps4_sceNetCtlGetResult(eventType:Integer;errorCode:PInteger):Integer; SysV_ABI_CDecl;
begin
if (errorCode=nil) then Exit(Integer(SCE_NET_CTL_ERROR_INVALID_ADDR));
errorCode^:=Integer(SCE_NET_CTL_ERROR_ETHERNET_PLUGOUT);
Result:=0;
end;
function Load_libSceNet(Const name:RawByteString):TElf_node;
var
lib:PLIBRARY;
begin
Result:=TElf_node.Create;
Result.pFileName:=name;
lib:=Result._add_lib('libSceNet');
lib^.set_proc($3657AFECB83C9370,@ps4_sceNetInit);
lib^.set_proc($76024169E2671A9A,@ps4_sceNetPoolCreate);
end;
function Load_libSceNetCtl(Const name:RawByteString):TElf_node;
var
lib:PLIBRARY;
begin
Result:=TElf_node.Create;
Result.pFileName:=name;
lib:=Result._add_lib('libSceNetCtl');
lib^.set_proc($824CB4FA868D3389,@ps4_sceNetCtlInit);
lib^.set_proc($B813E5AF495BBA22,@ps4_sceNetCtlGetState);
lib^.set_proc($509F99ED0FB8724D,@ps4_sceNetCtlRegisterCallback);
lib^.set_proc($890C378903E1BD44,@ps4_sceNetCtlCheckCallback);
lib^.set_proc($D1C06076E3D147E3,@ps4_sceNetCtlGetResult);
end;
initialization
ps4_app.RegistredPreLoad('libSceNet.prx' ,@Load_libSceNet);
ps4_app.RegistredPreLoad('libSceNetCtl.prx',@Load_libSceNetCtl);
end.

166
ps4_libscenpmanager.pas Normal file
View File

@ -0,0 +1,166 @@
unit ps4_libSceNpManager;
{$mode objfpc}{$H+}
interface
uses
ps4_program,
Classes, SysUtils;
implementation
Const
SCE_NP_COUNTRY_CODE_LENGTH=2;
type
// Np country code (ISO 3166-1 two-letter system)
SceNpCountryCode=packed record
data:array[0..SCE_NP_COUNTRY_CODE_LENGTH-1] of AnsiChar;
term:AnsiChar;
padding:array[0..1] of AnsiChar;
end;
SceNpAgeRestriction=packed record
countryCode:SceNpCountryCode;
age:Shortint;
padding:array[0..2] of Byte;
end;
PSceNpContentRestriction=^SceNpContentRestriction;
SceNpContentRestriction=packed record
size:QWORD;
defaultAgeRestriction:Byte;
padding:array[0..2] of Byte;
ageRestrictionCount:Integer;
ageRestriction:SceNpAgeRestriction;
end;
function ps4_sceNpSetContentRestriction(pRestriction:PSceNpContentRestriction):Integer; SysV_ABI_CDecl;
begin
Writeln('sceNpSetContentRestriction:',HexStr(pRestriction));
Result:=0;
end;
const
SCE_NP_ONLINEID_MIN_LENGTH=3;
SCE_NP_ONLINEID_MAX_LENGTH=16;
type
SceNpOnlineId=packed record
data:array[0..SCE_NP_ONLINEID_MAX_LENGTH-1] of AnsiChar;
term:AnsiChar;
dummy:array[0..2] of AnsiChar;
end;
PSceNpId=^SceNpId;
SceNpId=packed record
handle:SceNpOnlineId;
opt:array[0..7] of Byte;
reserved:array[0..7] of Byte;
end;
function ps4_sceNpGetNpId(userId:Integer;npId:PSceNpId):Integer; SysV_ABI_CDecl;
begin
npId^:=Default(SceNpId);
npId^.handle.data:='user';
Result:=0;
end;
const
SCE_NP_TITLE_ID_LEN=12;
type
PSceNpTitleId=^SceNpTitleId;
SceNpTitleId=packed record
id:array[0..SCE_NP_TITLE_ID_LEN] of Char;
padding:array[0..2] of Byte;
end;
const
SCE_NP_TITLE_SECRET_SIZE=128;
type
PSceNpTitleSecret=^SceNpTitleSecret;
SceNpTitleSecret=array[0..SCE_NP_TITLE_SECRET_SIZE-1] of Byte;
function GetStr(p:Pointer;L:SizeUint):RawByteString; inline;
begin
SetString(Result,P,L);
end;
function ps4_sceNpSetNpTitleId(titleId:PSceNpTitleId;titleSecret:PSceNpTitleSecret):Integer; SysV_ABI_CDecl;
begin
Writeln(GetStr(@titleId^.id,StrLen(@titleId^.id)));
Result:=0;
end;
function ps4_sceNpCheckCallback():Integer; SysV_ABI_CDecl;
begin
Result:=0;
end;
const
SCE_NP_STATE_UNKNOWN =0;
SCE_NP_STATE_SIGNED_OUT =1;
SCE_NP_STATE_SIGNED_IN =2;
type
SceUserServiceUserId=Integer;
SceNpStateCallbackA=procedure(userId:SceUserServiceUserId;state:Integer;userdata:Pointer); SysV_ABI_CDecl;
//int sceNpRegisterStateCallbackA(
// SceNpStateCallbackA callback,
// void *userdata);
const
SCE_NP_ERROR_INVALID_ARGUMENT=$80550003;
SCE_NP_ERROR_CALLBACK_ALREADY_REGISTERED=$80550008;
var
Cb4Toolkit:packed record
callback:SceNpStateCallbackA;
userdata:Pointer;
end;
function ps4_sceNpRegisterStateCallbackForToolkit(callback:SceNpStateCallbackA;userdata:Pointer):Integer; SysV_ABI_CDecl;
begin
Cb4Toolkit.callback:=callback;
Cb4Toolkit.userdata:=userdata;
Result:=0;
end;
function ps4_sceNpCheckCallbackForLib():Integer; SysV_ABI_CDecl;
begin
if (Cb4Toolkit.callback<>nil) then
begin
//Cb4Toolkit.callback(0,SCE_NP_STATE_SIGNED_OUT,Cb4Toolkit.userdata);
end;
Result:=0;
end;
function Load_libSceNpManager(Const name:RawByteString):TElf_node;
var
lib:PLIBRARY;
begin
Result:=TElf_node.Create;
Result.pFileName:=name;
lib:=Result._add_lib('libSceNpManager');
lib^.set_proc($036090DE4812A294,@ps4_sceNpSetContentRestriction);
lib^.set_proc($A7FA3BE029E83736,@ps4_sceNpGetNpId);
lib^.set_proc($11CEB7CB9F65F6DC,@ps4_sceNpSetNpTitleId);
lib^.set_proc($DD997C05E3D387D6,@ps4_sceNpCheckCallback);
lib:=Result._add_lib('libSceNpManagerForToolkit');
lib^.set_proc($D1CEC76D744A52DE,@ps4_sceNpRegisterStateCallbackForToolkit);
lib^.set_proc($2442C77F8C4FB9FA,@ps4_sceNpCheckCallbackForLib);
end;
initialization
ps4_app.RegistredPreLoad('libSceNpManager.prx',@Load_libSceNpManager);
end.

151
ps4_libscenpscore.pas Normal file
View File

@ -0,0 +1,151 @@
unit ps4_libSceNpScore;
{$mode objfpc}{$H+}
interface
uses
ps4_program,
Classes, SysUtils;
implementation
function ps4_sceNpScoreCreateNpTitleCtx(npServiceLabel:Integer;selfId:Integer):Integer; SysV_ABI_CDecl;
begin
Result:=0;
end;
function ps4_sceNpScoreCreateRequest(titleCtxId:Integer):Integer; SysV_ABI_CDecl;
begin
writeln('ScoreCreateRequest:',titleCtxId);
Result:=894;
end;
function ps4_sceNpScoreDeleteRequest(reqId:Integer):Integer; SysV_ABI_CDecl;
begin
writeln('sceNpScoreDeleteRequest:',reqId);
Result:=0;
end;
const
SCE_NP_ONLINEID_MIN_LENGTH=3;
SCE_NP_ONLINEID_MAX_LENGTH=16;
type
SceNpOnlineId=packed record
data:array[0..SCE_NP_ONLINEID_MAX_LENGTH-1] of Char;
term:Char;
dummy:array[0..2] of Char;
end;
PSceNpScoreRankDataA=^SceNpScoreRankDataA;
SceNpScoreRankDataA=packed record
onlineId:SceNpOnlineId;
reserved0:array[0..15] of Byte;
reserved:array[0..48] of Byte;
pad0:array[0..2] of Byte;
pcId:Integer;
serialRank:DWORD;
rank:DWORD;
highestRank:DWORD;
hasGameData:Integer;
pad1:array[0..3] of Byte;
scoreValue:Int64;
recordDate:QWORD;
accountId:QWORD;
pad2:array[0..7] of Byte;
end;
const
SCE_NP_SCORE_COMMENT_MAXLEN=63;
type
PSceNpScoreComment=^SceNpScoreComment;
SceNpScoreComment=packed record
utf8Comment:array[0..SCE_NP_SCORE_COMMENT_MAXLEN] of Char;
end;
const
SCE_NP_SCORE_GAMEINFO_MAXSIZE=189;
type
PSceNpScoreGameInfo=^SceNpScoreGameInfo;
SceNpScoreGameInfo=packed record
infoSize:size_t;
data:array[0..SCE_NP_SCORE_GAMEINFO_MAXSIZE-1] of Byte;
pad2:array[0..2] of Byte;
end;
PSceNpScoreGetFriendRankingOptParam=^SceNpScoreGetFriendRankingOptParam;
SceNpScoreGetFriendRankingOptParam=packed record
size:size_t;
startSerialRank:PInteger;
hits:PInteger;
end;
function ps4_sceNpScoreGetFriendsRanking(
reqId:Integer; //1
boardId:DWORD; //2
includeSelf:Integer; //3
rankArray:PSceNpScoreRankDataA; //4
rankArraySize:size_t; //5
commentArray:PSceNpScoreComment; //6
commentArraySize:size_t; //7
infoArray:PSceNpScoreGameInfo; //8
infoArraySize:size_t; //9
arrayNum:size_t; //10
lastSortDate:PQWORD; //11
totalRecord:PDWORD; //12
option:PSceNpScoreGetFriendRankingOptParam):Integer; SysV_ABI_CDecl; //13
begin
//lastSortDate^:=0;
//totalRecord^:=0;
Result:=0;
end;
type
PSceNpScoreAccountIdPcId=^SceNpScoreAccountIdPcId;
SceNpScoreAccountIdPcId=packed record
accountId:QWORD;
pcId:Integer;
pad:array[0..3] of Byte;
end;
function ps4_sceNpScoreGetRankingByAccountIdPcId(
reqId:Integer;
boardId:DWORD;
idArray:PSceNpScoreAccountIdPcId;
idArraySize:size_t;
rankArray:PSceNpScoreRankDataA;
rankArraySize:size_t;
commentArray:PSceNpScoreComment;
commentArraySize:size_t;
infoArray:PSceNpScoreGameInfo;
infoArraySize:size_t;
arrayNum:size_t;
lastSortDate:PQWORD;
totalRecord:PDWORD;
option:Pointer):Integer; SysV_ABI_CDecl;
begin
Result:=0;
end;
function Load_libSceNpScoreRanking(Const name:RawByteString):TElf_node;
var
lib:PLIBRARY;
begin
Result:=TElf_node.Create;
Result.pFileName:=name;
lib:=Result._add_lib('libSceNpScore');
lib^.set_proc($2A7340D53120B412,@ps4_sceNpScoreCreateNpTitleCtx);
lib^.set_proc($816F2ACA362B51B9,@ps4_sceNpScoreCreateRequest);
lib^.set_proc($74AF3F4A061FEABE,@ps4_sceNpScoreDeleteRequest);
lib^.set_proc($F24B88CD4C3ABAD4,@ps4_sceNpScoreGetFriendsRanking);
lib^.set_proc($F66644828884ABA6,@ps4_sceNpScoreGetRankingByAccountIdPcId);
end;
initialization
ps4_app.RegistredPreLoad('libSceNpScoreRanking.prx',@Load_libSceNpScoreRanking);
end.

57
ps4_libscenptrophy.pas Normal file
View File

@ -0,0 +1,57 @@
unit ps4_libSceNpTrophy;
{$mode objfpc}{$H+}
interface
uses
ps4_program,
Classes, SysUtils;
implementation
function ps4_sceNpTrophyCreateContext(context:PInteger;
userId:Integer;
serviceLabel:DWORD;
options:QWORD):Integer; SysV_ABI_CDecl;
begin
context^:=543;
Result:=0;
end;
function ps4_sceNpTrophyCreateHandle(handle:PInteger):Integer; SysV_ABI_CDecl;
begin
handle^:=3333;
Result:=0;
end;
function ps4_sceNpTrophyRegisterContext(context:Integer;
handle:Integer;
options:QWORD):Integer; SysV_ABI_CDecl;
begin
Result:=0;
end;
function ps4_sceNpTrophyDestroyHandle(handle:Integer):Integer; SysV_ABI_CDecl;
begin
Result:=0;
end;
function Load_libSceNpTrophy(Const name:RawByteString):TElf_node;
var
lib:PLIBRARY;
begin
Result:=TElf_node.Create;
Result.pFileName:=name;
lib:=Result._add_lib('libSceNpTrophy');
lib^.set_proc($5DB9236E86D99426,@ps4_sceNpTrophyCreateContext);
lib^.set_proc($ABB53AB440107FB7,@ps4_sceNpTrophyCreateHandle);
lib^.set_proc($4C9080C6DA3D4845,@ps4_sceNpTrophyRegisterContext);
lib^.set_proc($18D705E2889D6346,@ps4_sceNpTrophyDestroyHandle);
end;
initialization
ps4_app.RegistredPreLoad('libSceNpTrophy.prx',@Load_libSceNpTrophy);
end.

308
ps4_libscepad.pas Normal file
View File

@ -0,0 +1,308 @@
unit ps4_libScePad;
{$mode objfpc}{$H+}
interface
uses
windows,
ps4_program,
Classes, SysUtils;
implementation
const
SCE_PAD_ERROR_INVALID_ARG =-2137915391; // 0x80920001
SCE_PAD_ERROR_INVALID_PORT =-2137915390; // 0x80920002
SCE_PAD_ERROR_INVALID_HANDLE =-2137915389; // 0x80920003
SCE_PAD_ERROR_ALREADY_OPENED =-2137915388; // 0x80920004
SCE_PAD_ERROR_NOT_INITIALIZED =-2137915387; // 0x80920005
SCE_PAD_ERROR_INVALID_LIGHTBAR_SETTING=-2137915386; // 0x80920006
SCE_PAD_ERROR_DEVICE_NOT_CONNECTED =-2137915385; // 0x80920007
SCE_PAD_ERROR_NO_HANDLE =-2137915384; // 0x80920008
SCE_PAD_ERROR_FATAL =-2137915137; // 0x809200FF
function ps4_scePadInit():Integer; SysV_ABI_CDecl;
begin
Writeln('scePadInit');
Result:=0;
end;
function ps4_scePadOpen(userID,_type,index:Integer;param:Pointer):Integer; SysV_ABI_CDecl;
begin
//Writeln('scePadOpen:',userID);
Result:=222;
end;
const
ORBIS_PAD_PORT_TYPE_STANDARD=0;
SCE_PAD_BUTTON_L3 = $00000002;
SCE_PAD_BUTTON_R3 = $00000004;
SCE_PAD_BUTTON_OPTIONS = $00000008;
SCE_PAD_BUTTON_UP = $00000010;
SCE_PAD_BUTTON_RIGHT = $00000020;
SCE_PAD_BUTTON_DOWN = $00000040;
SCE_PAD_BUTTON_LEFT = $00000080;
SCE_PAD_BUTTON_L2 = $00000100;
SCE_PAD_BUTTON_R2 = $00000200;
SCE_PAD_BUTTON_L1 = $00000400;
SCE_PAD_BUTTON_R1 = $00000800;
SCE_PAD_BUTTON_TRIANGLE = $00001000;
SCE_PAD_BUTTON_CIRCLE = $00002000;
SCE_PAD_BUTTON_CROSS = $00004000;
SCE_PAD_BUTTON_SQUARE = $00008000;
SCE_PAD_BUTTON_TOUCH_PAD = $00100000;
SCE_PAD_BUTTON_INTERCEPTED = $80000000;
SCE_PAD_MAX_TOUCH_NUM=2;
SCE_PAD_MAX_DEVICE_UNIQUE_DATA_SIZE=12;
type
Tvec_float3=packed record
x,y,z:Single;
end;
Tvec_float4=packed record
x,y,z,w:Single;
end;
ScePadAnalogStick=packed record
x,y:Byte;
end;
ScePadAnalogButtons=packed record
l2,r2:Byte;
padding :Word;
end;
ScePadTouch=packed record
x:Word;
y:Word;
id:Byte;
reserve:array[0..2] of Byte;
end;
ScePadTouchData=packed record
touchNum:Byte;
reserve:array[0..2] of Byte;
reserve1:DWORD;
touch:array[0..SCE_PAD_MAX_TOUCH_NUM-1] of ScePadTouch;
end;
ScePadExtensionUnitData=packed record
extensionUnitId:DWORD;
reserve:Byte;
dataLength:Byte;
data:array[0..9] of Byte;
end;
PScePadData=^ScePadData;
ScePadData=packed record
buttons :DWORD;
leftStick :ScePadAnalogStick;
rightStick :ScePadAnalogStick;
analogButtons :ScePadAnalogButtons;
orientation :Tvec_float4;
acceleration :Tvec_float3;
angularVelocity :Tvec_float3;
touchData :ScePadTouchData;
connected :Boolean;
timestamp :QWORD;
extensionUnitData:ScePadExtensionUnitData;
connectedCount :Byte;
reserve:array[0..1] of Byte;
deviceUniqueDataLen:Byte;
deviceUniqueData:array[0..SCE_PAD_MAX_DEVICE_UNIQUE_DATA_SIZE-1] of Byte;
end;
TPadColor=packed record
r,g,b,a:Byte;
end;
PScePadVibrationParam=^ScePadVibrationParam;
ScePadVibrationParam=packed record
largeMotor:Byte;
smallMotor:Byte;
end;
ScePadColor=packed record
r:Byte;
g:Byte;
b:Byte;
reserve:Byte;
end;
ScePadLightBarParam=ScePadColor;
PScePadLightBarParam=^ScePadLightBarParam;
function ps4_scePadReadState(handle:Integer;data:PScePadData):Integer; SysV_ABI_CDecl;
begin
Result:=SCE_PAD_ERROR_INVALID_ARG;
if (data=nil) then Exit;
//Writeln(SizeOf(TPadData)); //184
data^:=Default(ScePadData);
//FillChar(data^,SizeOf(ScePadData),1);
data^.connected:=True;
data^.timestamp:=Sysutils.GetTickCount64;
data^.connectedCount:=1;
data^.leftStick.x:=$80;
data^.leftStick.y:=$80;
data^.rightStick.x:=$80;
data^.rightStick.y:=$80;
if GetAsyncKeyState(VK_W)<>0 then
data^.leftStick.y:=0;
if GetAsyncKeyState(VK_S)<>0 then
data^.leftStick.y:=$FF;
if GetAsyncKeyState(VK_A)<>0 then
data^.leftStick.x:=0;
if GetAsyncKeyState(VK_D)<>0 then
data^.leftStick.x:=$FF;
if GetAsyncKeyState(VK_RETURN)<>0 then
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_OPTIONS;
if GetAsyncKeyState(VK_UP)<>0 then
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_UP;
if GetAsyncKeyState(VK_RIGHT)<>0 then
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_RIGHT;
if GetAsyncKeyState(VK_DOWN)<>0 then
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_DOWN;
if GetAsyncKeyState(VK_LEFT)<>0 then
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_LEFT;
if GetAsyncKeyState(VK_NUMPAD1)<>0 then
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_TRIANGLE;
if GetAsyncKeyState(VK_NUMPAD2)<>0 then
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_CIRCLE;
if GetAsyncKeyState(VK_NUMPAD4)<>0 then
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_CROSS;
if GetAsyncKeyState(VK_NUMPAD5)<>0 then
data^.buttons:=data^.buttons or SCE_PAD_BUTTON_SQUARE;
//data^.buttons:=not data^.buttons;
Result:=0;
end;
function ps4_scePadRead(handle:Integer;data:PScePadData;num:Integer):Integer; SysV_ABI_CDecl;
begin
ps4_scePadReadState(handle,data);
Result:=1;
end;
function ps4_scePadSetVibration(handle:Integer;pParam:PScePadVibrationParam):Integer; SysV_ABI_CDecl;
begin
Result:=0;
end;
function ps4_scePadResetLightBar(handle:Integer):Integer; assembler; nostackframe;
asm
xor %rax,%rax
end;
type
ScePadTouchPadInformation=packed record
pixelDensity:Single;
resolution:packed record
x,y:Word;
end;
end;
ScePadStickInformation=packed record
deadZoneLeft:Byte;
deadZoneRight:Byte;
end;
PScePadControllerInformation=^ScePadControllerInformation;
ScePadControllerInformation=packed record
touchPadInfo:ScePadTouchPadInformation;
stickInfo:ScePadStickInformation;
connectionType:Byte;
connectedCount:Byte;
connected:Boolean;
deviceClass:DWORD;
reserve:array[0..7] of Byte;
end;
const
SCE_PAD_CONNECTION_TYPE_LOCAL=0;
SCE_PAD_CONNECTION_TYPE_REMOTE=1;
SCE_PAD_CONNECTION_TYPE_REMOTE_VITA=SCE_PAD_CONNECTION_TYPE_REMOTE;
SCE_PAD_CONNECTION_TYPE_REMOTE_DUALSHOCK4=2;
SCE_PAD_DEVICE_CLASS_INVALID = -1;
SCE_PAD_DEVICE_CLASS_STANDARD = 0;
SCE_PAD_DEVICE_CLASS_GUITAR = 1;
SCE_PAD_DEVICE_CLASS_DRUM = 2;
SCE_PAD_DEVICE_CLASS_DJ_TURNTABLE = 3;
SCE_PAD_DEVICE_CLASS_DANCEMAT = 4;
SCE_PAD_DEVICE_CLASS_NAVIGATION = 5;
SCE_PAD_DEVICE_CLASS_STEERING_WHEEL = 6;
SCE_PAD_DEVICE_CLASS_STICK = 7;
SCE_PAD_DEVICE_CLASS_FLIGHT_STICK = 8;
SCE_PAD_DEVICE_CLASS_GUN = 9;
function ps4_scePadGetControllerInformation(handle:Integer;pInfo:PScePadControllerInformation):Integer; SysV_ABI_CDecl;
begin
//FillChar(pInfo^,SizeOf(ScePadControllerInformation),1);
//Exit(0);
if (pInfo=nil) then Exit(SCE_PAD_ERROR_INVALID_ARG);
pInfo^:=Default(ScePadControllerInformation);
pInfo^.touchPadInfo.pixelDensity := 1;
pInfo^.touchPadInfo.resolution.x := 256;
pInfo^.touchPadInfo.resolution.y := 256;
pInfo^.stickInfo.deadZoneLeft := 2;
pInfo^.stickInfo.deadZoneRight := 2;
pInfo^.connectionType := SCE_PAD_CONNECTION_TYPE_LOCAL;
pInfo^.connectedCount := 1;
pInfo^.connected := True;
pInfo^.deviceClass := SCE_PAD_DEVICE_CLASS_STANDARD;
Result:=0;
end;
function ps4_scePadSetMotionSensorState(handle:Integer;bEnable:Boolean):Integer; SysV_ABI_CDecl;
begin
Result:=0;
end;
function ps4_scePadSetLightBar(handle:Integer;pParam:PScePadLightBarParam):Integer; SysV_ABI_CDecl;
begin
Result:=0;
end;
function Load_libScePad(Const name:RawByteString):TElf_node;
var
lib:PLIBRARY;
begin
Result:=TElf_node.Create;
Result.pFileName:=name;
lib:=Result._add_lib('libScePad');
lib^.set_proc($86FD65BA226BA903,@ps4_scePadInit);
lib^.set_proc($C64D0071AACFDD5E,@ps4_scePadOpen);
lib^.set_proc($6277605EA41557B7,@ps4_scePadReadState);
lib^.set_proc($AB570735F1B270B2,@ps4_scePadRead);
lib^.set_proc($C8556739D1B1BD96,@ps4_scePadSetVibration);
lib^.set_proc($0EC703D62F475F5C,@ps4_scePadResetLightBar);
lib^.set_proc($8233FDFCA433A149,@ps4_scePadGetControllerInformation);
lib^.set_proc($72556F2F86439EDC,@ps4_scePadSetMotionSensorState);
lib^.set_proc($451E27A2F50410D6,@ps4_scePadSetLightBar);
end;
initialization
ps4_app.RegistredPreLoad('libScePad.prx',@Load_libScePad);
end.

180
ps4_libscesavedata.pas Normal file
View File

@ -0,0 +1,180 @@
unit ps4_libSceSaveData;
{$mode objfpc}{$H+}
interface
uses
ps4_program,
Classes, SysUtils;
Const
SCE_SAVE_DATA_TITLE_MAXSIZE =128;
SCE_SAVE_DATA_SUBTITLE_MAXSIZE=128;
SCE_SAVE_DATA_DETAIL_MAXSIZE =1024;
SCE_SAVE_DATA_DIRNAME_DATA_MAXSIZE=32;
SCE_SAVE_DATA_MOUNT_POINT_DATA_MAXSIZE=16;
SCE_SAVE_DATA_MOUNT_STATUS_CREATED=$00000001;
type
PSceSaveDataParam=^SceSaveDataParam;
SceSaveDataParam=packed record
title:array[0..SCE_SAVE_DATA_TITLE_MAXSIZE-1] of AnsiChar;
subTitle:array[0..SCE_SAVE_DATA_SUBTITLE_MAXSIZE-1] of AnsiChar;
detail:array[0..SCE_SAVE_DATA_DETAIL_MAXSIZE-1] of AnsiChar;
userParam:DWORD;
align:DWORD;
mtime:QWORD;
reserved:array[0..31] of Byte;
end;
PSceSaveDataIcon=^SceSaveDataIcon;
SceSaveDataIcon=packed record
buf:Pointer;
bufSize:size_t;
dataSize:size_t;
reserved:array[0..31] of Byte;
end;
PSceSaveDataMemorySetup2=^SceSaveDataMemorySetup2;
SceSaveDataMemorySetup2=packed record
option:DWORD;
userId:Integer;
memorySize:size_t;
iconMemorySize:size_t;
initParam:PSceSaveDataParam;
initIcon:PSceSaveDataIcon;
reserved:array[0..23] of Byte;
end;
PSceSaveDataMemorySetupResult=^SceSaveDataMemorySetupResult;
SceSaveDataMemorySetupResult=packed record
existedMemorySize:size_t;
reserved:array[0..15] of Byte;
end;
PSceSaveDataDirName=^SceSaveDataDirName;
SceSaveDataDirName=array[0..SCE_SAVE_DATA_DIRNAME_DATA_MAXSIZE-1] of Char;
PSceSaveDataMountPoint=^SceSaveDataMountPoint;
SceSaveDataMountPoint=array[0..SCE_SAVE_DATA_MOUNT_POINT_DATA_MAXSIZE-1] of Char;
PSceSaveDataMount2=^SceSaveDataMount2;
SceSaveDataMount2=packed record
userId:Integer;
align1:Integer;
dirName:PSceSaveDataDirName;
blocks:QWORD;
mountMode:DWORD;
reserved:array[0..31] of Byte;
align2:Integer;
end;
PSceSaveDataMountResult=^SceSaveDataMountResult;
SceSaveDataMountResult=packed record
mountPoint:SceSaveDataMountPoint;
requiredBlocks:QWORD;
unused:DWORD;
mountStatus:DWORD;
reserved:array[0..27] of Byte;
align1:Integer;
end;
implementation
uses
ps4_libkernel;
function ps4_sceSaveDataInitialize(params:Pointer):Integer; assembler; nostackframe;
asm
xor %rax,%rax
end;
function ps4_sceSaveDataInitialize3(params:Pointer):Integer; assembler; nostackframe;
asm
xor %rax,%rax
end;
function ps4_sceSaveDataSetupSaveDataMemory(userId:Integer;
memorySize:QWORD;
param:PSceSaveDataParam):Integer; SysV_ABI_CDecl;
begin
Result:=0;
end;
function sceSaveDataSetupSaveDataMemory2(setupParam:PSceSaveDataMemorySetup2;
_result:PSceSaveDataMemorySetupResult):Integer; SysV_ABI_CDecl;
begin
Result:=0;
end;
function ps4_sceSaveDataGetSaveDataMemory(userId:Integer;
buf:Pointer;
bufSize:size_t;
offset:QWORD):Integer; SysV_ABI_CDecl;
begin
FillChar(buf^,bufSize,0);
Result:=0;
end;
function ps4_sceSaveDataSetSaveDataMemory(userId:Integer;
buf:Pointer;
bufSize:size_t;
offset:QWORD):Integer; SysV_ABI_CDecl;
begin
Result:=0;
end;
const
SCE_SAVE_DATA_ERROR_PARAMETER =-2137063424; // 0x809F0000
SCE_SAVE_DATA_ERROR_EXISTS =-2137063417; // 0x809F0007
SCE_SAVE_DATA_ERROR_MOUNT_FULL =-2137063412; // 0x809F000C
SCE_SAVE_DATA_ERROR_NOT_MOUNTED=-2137063420; // 0x809F0004
function ps4_sceSaveDataMount2(mount:PSceSaveDataMount2;mountResult:PSceSaveDataMountResult):Integer; SysV_ABI_CDecl;
begin
if (mount=nil) or (mountResult=nil) then Exit(SCE_SAVE_DATA_ERROR_PARAMETER);
Result:=FetchMount(PChar(mount^.dirName),@mountResult^.mountPoint);
end;
function ps4_sceSaveDataUmount(mountPoint:PSceSaveDataMountPoint):Integer; SysV_ABI_CDecl;
begin
Result:=UnMountPath(PChar(mountPoint));
end;
type
SceSaveDataParamType=DWORD;
function ps4_sceSaveDataSetParam(mountPoint:PSceSaveDataMountPoint;
paramType:SceSaveDataParamType;
paramBuf:Pointer;
paramBufSize:size_t):Integer; SysV_ABI_CDecl;
begin
Result:=0;
end;
function Load_libSceSaveData(Const name:RawByteString):TElf_node;
var
lib:PLIBRARY;
begin
Result:=TElf_node.Create;
Result.pFileName:=name;
lib:=Result._add_lib('libSceSaveData');
lib^.set_proc($664661B2408F5C5C,@ps4_sceSaveDataInitialize);
lib^.set_proc($4F2C2B14A0A82C66,@ps4_sceSaveDataInitialize3);
lib^.set_proc($BFB00000CA342F3E,@ps4_sceSaveDataSetupSaveDataMemory);
lib^.set_proc($EC1B79A410BF01CA,@ps4_sceSaveDataGetSaveDataMemory);
lib^.set_proc($8776144735C64954,@ps4_sceSaveDataSetSaveDataMemory);
lib^.set_proc($D33E393C81FE48D2,@ps4_sceSaveDataMount2);
lib^.set_proc($04C47817F51E9371,@ps4_sceSaveDataUmount);
lib^.set_proc($F39CEE97FFDE197B,@ps4_sceSaveDataSetParam);
end;
initialization
ps4_app.RegistredPreLoad('libSceSaveData.prx',@Load_libSceSaveData);
end.

176
ps4_libscesystemservice.pas Normal file
View File

@ -0,0 +1,176 @@
unit ps4_libSceSystemService;
{$mode objfpc}{$H+}
interface
uses
ps4_program,
Classes, SysUtils;
implementation
uses
ps4_libkernel;
const
SCE_SYSTEM_SERVICE_PARAM_ID_LANG =1;
SCE_SYSTEM_SERVICE_PARAM_ID_DATE_FORMAT =2;
SCE_SYSTEM_SERVICE_PARAM_ID_TIME_FORMAT =3;
SCE_SYSTEM_SERVICE_PARAM_ID_TIME_ZONE =4;
SCE_SYSTEM_SERVICE_PARAM_ID_SUMMERTIME =5;
SCE_SYSTEM_SERVICE_PARAM_ID_SYSTEM_NAME =6;
SCE_SYSTEM_SERVICE_PARAM_ID_GAME_PARENTAL_LEVEL =7;
SCE_SYSTEM_SERVICE_PARAM_ID_ENTER_BUTTON_ASSIGN =1000;
SCE_SYSTEM_SERVICE_ERROR_INTERNAL =-2136932351;
SCE_SYSTEM_SERVICE_ERROR_UNAVAILABLE =-2136932350;
SCE_SYSTEM_SERVICE_ERROR_PARAMETER =-2136932349;
SCE_SYSTEM_SERVICE_ERROR_NO_EVENT =-2136932348;
SCE_SYSTEM_SERVICE_ERROR_REJECTED =-2136932347;
SCE_SYSTEM_SERVICE_ERROR_NEED_DISPLAY_SAFE_AREA_SETTINGS =-2136932346;
SCE_SYSTEM_SERVICE_ERROR_INVALID_URI_LEN =-2136932345;
SCE_SYSTEM_SERVICE_ERROR_INVALID_URI_SCHEME =-2136932344;
SCE_SYSTEM_SERVICE_ERROR_NO_APP_INFO =-2136932343;
SCE_SYSTEM_SERVICE_ERROR_NOT_FLAG_IN_PARAM_SFO =-2136932342;
// Language
SCE_SYSTEM_PARAM_LANG_JAPANESE =0;
SCE_SYSTEM_PARAM_LANG_ENGLISH_US =1;
SCE_SYSTEM_PARAM_LANG_FRENCH =2;
SCE_SYSTEM_PARAM_LANG_SPANISH =3;
SCE_SYSTEM_PARAM_LANG_GERMAN =4;
SCE_SYSTEM_PARAM_LANG_ITALIAN =5;
SCE_SYSTEM_PARAM_LANG_DUTCH =6;
SCE_SYSTEM_PARAM_LANG_PORTUGUESE_PT =7;
SCE_SYSTEM_PARAM_LANG_RUSSIAN =8;
SCE_SYSTEM_PARAM_LANG_KOREAN =9;
SCE_SYSTEM_PARAM_LANG_CHINESE_T =10;
SCE_SYSTEM_PARAM_LANG_CHINESE_S =11;
SCE_SYSTEM_PARAM_LANG_FINNISH =12;
SCE_SYSTEM_PARAM_LANG_SWEDISH =13;
SCE_SYSTEM_PARAM_LANG_DANISH =14;
SCE_SYSTEM_PARAM_LANG_NORWEGIAN =15;
SCE_SYSTEM_PARAM_LANG_POLISH =16;
SCE_SYSTEM_PARAM_LANG_PORTUGUESE_BR =17;
SCE_SYSTEM_PARAM_LANG_ENGLISH_GB =18;
SCE_SYSTEM_PARAM_LANG_TURKISH =19;
SCE_SYSTEM_PARAM_LANG_SPANISH_LA =20;
SCE_SYSTEM_PARAM_LANG_ARABIC =21;
SCE_SYSTEM_PARAM_LANG_FRENCH_CA =22;
// Date
SCE_SYSTEM_PARAM_DATE_FORMAT_YYYYMMDD=0;
SCE_SYSTEM_PARAM_DATE_FORMAT_DDMMYYYY=1;
SCE_SYSTEM_PARAM_DATE_FORMAT_MMDDYYYY=2;
// Time
SCE_SYSTEM_PARAM_TIME_FORMAT_12HOUR=0;
SCE_SYSTEM_PARAM_TIME_FORMAT_24HOUR=1;
//
SCE_SYSTEM_SERVICE_MAX_SYSTEM_NAME_LENGTH=65;
//
SCE_SYSTEM_PARAM_GAME_PARENTAL_OFF =0;
SCE_SYSTEM_PARAM_GAME_PARENTAL_LEVEL01=1;
SCE_SYSTEM_PARAM_GAME_PARENTAL_LEVEL02=2;
SCE_SYSTEM_PARAM_GAME_PARENTAL_LEVEL03=3;
SCE_SYSTEM_PARAM_GAME_PARENTAL_LEVEL04=4;
SCE_SYSTEM_PARAM_GAME_PARENTAL_LEVEL05=5;
SCE_SYSTEM_PARAM_GAME_PARENTAL_LEVEL06=6;
SCE_SYSTEM_PARAM_GAME_PARENTAL_LEVEL07=7;
SCE_SYSTEM_PARAM_GAME_PARENTAL_LEVEL08=8;
SCE_SYSTEM_PARAM_GAME_PARENTAL_LEVEL09=9;
SCE_SYSTEM_PARAM_GAME_PARENTAL_LEVEL10=10;
SCE_SYSTEM_PARAM_GAME_PARENTAL_LEVEL11=11;
//
SCE_SYSTEM_PARAM_ENTER_BUTTON_ASSIGN_CIRCLE=0;
SCE_SYSTEM_PARAM_ENTER_BUTTON_ASSIGN_CROSS =1;
function ps4_sceSystemServiceParamGetInt(paramId:Integer;value:Pinteger):Integer; SysV_ABI_CDecl;
begin
Writeln('ParamGetInt:',paramId);
Result:=SCE_SYSTEM_SERVICE_ERROR_PARAMETER;
if value=nil then Exit;
value^:=0;
if ((paramId<>SCE_SYSTEM_SERVICE_PARAM_ID_ENTER_BUTTON_ASSIGN) and
((paramId < SCE_SYSTEM_SERVICE_PARAM_ID_LANG) or (paramId > SCE_SYSTEM_SERVICE_PARAM_ID_GAME_PARENTAL_LEVEL))) then
Exit;
Case paramId of
SCE_SYSTEM_SERVICE_PARAM_ID_LANG :value^:=SCE_SYSTEM_PARAM_LANG_CHINESE_T;
SCE_SYSTEM_SERVICE_PARAM_ID_DATE_FORMAT:value^:=SCE_SYSTEM_PARAM_DATE_FORMAT_DDMMYYYY;
SCE_SYSTEM_SERVICE_PARAM_ID_TIME_FORMAT:value^:=SCE_SYSTEM_PARAM_TIME_FORMAT_12HOUR;
SCE_SYSTEM_SERVICE_PARAM_ID_TIME_ZONE :value^:=480;// GMT+8
SCE_SYSTEM_SERVICE_PARAM_ID_SUMMERTIME :value^:=1; // 1 in daylight savings time, 0 not in daylight savings time
SCE_SYSTEM_SERVICE_PARAM_ID_SYSTEM_NAME:;// for sceSystemServiceParamGetString, shouldn't be used here.
SCE_SYSTEM_SERVICE_PARAM_ID_GAME_PARENTAL_LEVEL:value^:=SCE_SYSTEM_PARAM_GAME_PARENTAL_OFF;
SCE_SYSTEM_SERVICE_PARAM_ID_ENTER_BUTTON_ASSIGN:value^:=SCE_SYSTEM_PARAM_ENTER_BUTTON_ASSIGN_CIRCLE;
end;
end;
procedure ps4_sceSystemServiceHideSplashScreen; assembler; nostackframe;
asm
xor %rax,%rax
end;
type
PSceSystemServiceDisplaySafeAreaInfo=^SceSystemServiceDisplaySafeAreaInfo;
SceSystemServiceDisplaySafeAreaInfo=packed record
ratio:Single; //Ratio of the safe area (0.9 or more, 1.0 or less)
reserved:array[0..127] of Byte;
end;
function ps4_sceSystemServiceGetDisplaySafeAreaInfo(info:PSceSystemServiceDisplaySafeAreaInfo):Integer; SysV_ABI_CDecl;
begin
Result:=SCE_KERNEL_ERROR_UNKNOWN;
if (info=nil) then Exit(SCE_SYSTEM_SERVICE_ERROR_PARAMETER);
info^.ratio:=1.0;
Result:=0;
end;
type
PSceSystemServiceStatus=^SceSystemServiceStatus;
SceSystemServiceStatus=packed record
eventNum:Integer;
isSystemUiOverlaid,
isInBackgroundExecution,
isCpuMode7CpuNormal,
isGameLiveStreamingOnAir,
isOutOfVrPlayArea:Boolean;
reserved:array[0..124] of Byte;
end;
function ps4_sceSystemServiceGetStatus(status:PSceSystemServiceStatus):Integer; SysV_ABI_CDecl;
begin
if status=nil then Exit(SCE_SYSTEM_SERVICE_ERROR_PARAMETER);
status^.eventNum:=0;
status^.isSystemUiOverlaid:=false;
status^.isInBackgroundExecution:=false;
status^.isCpuMode7CpuNormal:=true;
status^.isGameLiveStreamingOnAir:=false;
status^.isOutOfVrPlayArea:=false;
Result:=0;
end;
function Load_libSceSystemService(Const name:RawByteString):TElf_node;
var
lib:PLIBRARY;
begin
Result:=TElf_node.Create;
Result.pFileName:=name;
lib:=Result._add_lib('libSceSystemService');
lib^.set_proc($7D9A38F2E9FB2CAE,@ps4_sceSystemServiceParamGetInt);
lib^.set_proc($568E55F0A0300A69,@ps4_sceSystemServiceHideSplashScreen);
lib^.set_proc($D67DFBAB506F7396,@ps4_sceSystemServiceGetDisplaySafeAreaInfo);
lib^.set_proc($ACFA3AB55F03F5B3,@ps4_sceSystemServiceGetStatus);
end;
initialization
ps4_app.RegistredPreLoad('libSceSystemService.prx',@Load_libSceSystemService);
end.

84
ps4_libsceuserservice.pas Normal file
View File

@ -0,0 +1,84 @@
unit ps4_libSceUserService;
{$mode objfpc}{$H+}
interface
uses
ps4_program,
Classes, SysUtils;
const
SCE_KERNEL_PRIO_FIFO_LOWEST =$2FF;
SCE_KERNEL_PRIO_FIFO_NORMAL =$2BC;
SCE_KERNEL_PRIO_FIFO_HIGHEST=$100;
SCE_USER_SERVICE_MAX_LOGIN_USERS=4;
SCE_USER_SERVICE_USER_ID_INVALID=Integer($FFFFFFFF);
type
PUserServiceInitializeParams=^TUserServiceInitializeParams;
TUserServiceInitializeParams=packed record
priority:DWORD;
end;
PUserServiceLoginUserIdList=^TUserServiceLoginUserIdList;
TUserServiceLoginUserIdList=packed record
userId:array[0..SCE_USER_SERVICE_MAX_LOGIN_USERS-1] of Integer;
end;
implementation
function ps4_sceUserServiceInitialize(params:PUserServiceInitializeParams):Integer; assembler; nostackframe;
asm
xor %rax,%rax
end;
function ps4_sceUserServiceGetLoginUserIdList(List:PUserServiceLoginUserIdList):Integer; SysV_ABI_CDecl;
var
i:Integer;
begin
Result:=-1;
if (List=nil) then Exit;
List^.userId[0]:=1;
For i:=1 to SCE_USER_SERVICE_MAX_LOGIN_USERS-1 do
List^.userId[i]:=SCE_USER_SERVICE_USER_ID_INVALID;
Result:=0;
end;
function ps4_sceUserServiceGetInitialUser(pUserId:PInteger):Integer; SysV_ABI_CDecl;
begin
Result:=-1;
if pUserId=nil then Exit;
pUserId^:=1;
Result:=0;
end;
function ps4_sceUserServiceGetUserName(userId:Integer;userName:PChar;size:size_t):Integer; SysV_ABI_CDecl;
Const
cuser:PChar='user';
begin
Move(cuser^,userName^,Length(cuser)+1);
Result:=0;
end;
function Load_libSceUserService(Const name:RawByteString):TElf_node;
var
lib:PLIBRARY;
begin
Result:=TElf_node.Create;
Result.pFileName:=name;
lib:=Result._add_lib('libSceUserService');
lib^.set_proc($8F760CBB531534DA,@ps4_sceUserServiceInitialize);
lib^.set_proc($7CF87298A36F2BF0,@ps4_sceUserServiceGetLoginUserIdList);
lib^.set_proc($09D5A9D281D61ABD,@ps4_sceUserServiceGetInitialUser);
lib^.set_proc($D71C5C3221AED9FA,@ps4_sceUserServiceGetUserName);
end;
initialization
ps4_app.RegistredPreLoad('libSceUserService.prx',@Load_libSceUserService);
end.

1248
ps4_libscevideoout.pas Normal file

File diff suppressed because it is too large Load Diff

1347
ps4_program.pas Normal file

File diff suppressed because it is too large Load Diff

500
ps4_types.pas Normal file
View File

@ -0,0 +1,500 @@
unit ps4_types;
{$mode objfpc}{$H+}
interface
uses ctypes;
Const
ET_NONE =0;
ET_REL =1;
ET_EXEC =2;
ET_DYN =3;
ET_CORE =4;
ET_LOPROC=$ff00;
ET_HIPROC=$ffff;
EI_MAG0 = 0; // e_ident[] indexes
EI_MAG1 = 1;
EI_MAG2 = 2;
EI_MAG3 = 3;
EI_CLASS = 4;
EI_DATA = 5;
EI_VERSION = 6;
EI_OSABI = 7;
EI_PAD = 8;
ELFMAG =$464C457F;
SELFMAG=4;
ET_SCE_DYNEXEC=$FE10;
ET_SCE_DYNAMIC=$FE18;
EM_X86_64 =62; // AMD x86-64
EI_NIDENT=16;
PT_NULL =0;
PT_LOAD =1;
PT_DYNAMIC=2;
PT_INTERP =3;
PT_NOTE =4;
PT_SHLIB =5;
PT_PHDR =6;
PT_TLS =7; // Thread local storage segment
PT_LOOS =$60000000; // OS-specific
PT_HIOS =$6fffffff; // OS-specific
PT_LOPROC =$70000000;
PT_HIPROC =$7fffffff;
PT_GNU_EH_FRAME=$6474e550;
PT_GNU_STACK =$6474E551;
PT_SCE_RELA = $60000000;
PT_SCE_DYNLIBDATA = $61000000;
PT_SCE_PROCPARAM = $61000001;
PT_SCE_MODULE_PARAM = $61000002;
PT_SCE_RELRO = $61000010;
PT_SCE_COMMENT = $6FFFFF00;
PT_SCE_VERSION = $6FFFFF01;
// This is the info that is needed to parse the dynamic section of the file
DT_NULL = 0;
DT_NEEDED = 1;
DT_PLTRELSZ = 2;
DT_PLTGOT = 3;
DT_HASH = 4;
DT_STRTAB = 5;
DT_SYMTAB = 6;
DT_RELA = 7;
DT_RELASZ = 8;
DT_RELAENT = 9;
DT_STRSZ =10;
DT_SYMENT =11;
DT_INIT =12;
DT_FINI =13;
DT_SONAME =14;
DT_RPATH =15;
DT_SYMBOLIC =16;
DT_REL =17;
DT_RELSZ =18;
DT_RELENT =19;
DT_PLTREL =20;
DT_DEBUG =21;
DT_TEXTREL =22;
DT_JMPREL =23;
DT_BIND_NOW =24;
DT_INIT_ARRAY =25;
DT_FINI_ARRAY =26;
DT_INIT_ARRAYSZ =27;
DT_FINI_ARRAYSZ =28;
DT_RUNPATH =29;
DT_FLAGS =30;
DT_ENCODING =32;
DT_PREINIT_ARRAY =32;
DT_PREINIT_ARRAYSZ =33;
// Dynamic Section Types
DT_SCE_IDTABENTSZ =$61000005;
DT_SCE_FINGERPRINT =$61000007;
DT_SCE_FILENAME =$61000009;
DT_SCE_MODULE_INFO =$6100000D;
DT_SCE_NEEDED_MODULE =$6100000F;
DT_SCE_MODULE_ATTR =$61000011;
DT_SCE_EXPORT_LIB =$61000013;
DT_SCE_IMPORT_LIB =$61000015;
DT_SCE_EXPORT_LIB_ATTR =$61000017;
DT_SCE_IMPORT_LIB_ATTR =$61000019;
DT_SCE_STUB_MODULE_NAME =$6100001D;
DT_SCE_STUB_MODULE_VERSION =$6100001F;
DT_SCE_STUB_LIBRARY_NAME =$61000021;
DT_SCE_STUB_LIBRARY_VERSION =$61000023;
DT_SCE_HASH =$61000025;
DT_SCE_PLTGOT =$61000027;
DT_SCE_JMPREL =$61000029;
DT_SCE_PLTREL =$6100002B;
DT_SCE_PLTRELSZ =$6100002D;
DT_SCE_RELA =$6100002F;
DT_SCE_RELASZ =$61000031;
DT_SCE_RELAENT =$61000033;
DT_SCE_STRTAB =$61000035;
DT_SCE_STRSZ =$61000037;
DT_SCE_SYMTAB =$61000039;
DT_SCE_SYMENT =$6100003B;
DT_SCE_HASHSZ =$6100003D;
DT_SCE_SYMTABSZ =$6100003F;
DT_SCE_HIOS =$6FFFF000;
DF_ORIGIN =$1;
DF_SYMBOLIC =$2;
DF_TEXTREL =$4;
DF_BIND_NOW =$8;
DF_STATIC_TLS=$10;
SHT_SYMTAB=2;
SHT_STRTAB=3;
// Relocation types for AMD x86-64 architecture
R_X86_64_NONE = 0; // No reloc
R_X86_64_64 = 1; // Direct 64 bit
R_X86_64_PC32 = 2; // PC relative 32 bit signed
R_X86_64_GOT32 = 3; // 32 bit GOT entry
R_X86_64_PLT32 = 4; // 32 bit PLT address
R_X86_64_COPY = 5; // Copy symbol at runtime
R_X86_64_GLOB_DAT = 6; // Create GOT entry
R_X86_64_JUMP_SLOT = 7; // Create PLT entry
R_X86_64_RELATIVE = 8; // Adjust by program base
R_X86_64_GOTPCREL = 9; // 32 bit signed pc relative offset to GOT
R_X86_64_32 =10; // Direct 32 bit zero extended
R_X86_64_32S =11; // Direct 32 bit sign extended
R_X86_64_16 =12; // Direct 16 bit zero extended
R_X86_64_PC16 =13; // 16 bit sign extended pc relative
R_X86_64_8 =14; // Direct 8 bit sign extended
R_X86_64_PC8 =15; // 8 bit sign extended pc relative
R_X86_64_DTPMOD64 =16; // ID of module containing symbol
R_X86_64_DTPOFF64 =17; // Offset in module's TLS block
R_X86_64_TPOFF64 =18; // Offset in initial TLS block
R_X86_64_TLSGD =19; // 32 bit signed PC relative offset
//to two GOT entries for GD symbol
R_X86_64_TLSLD =20; // 32 bit signed PC relative offset
//to two GOT entries for LD symbol
R_X86_64_DTPOFF32 =21; // Offset in TLS block
R_X86_64_GOTTPOFF =22; // 32 bit signed PC relative offset
//to GOT entry for IE symbol
R_X86_64_TPOFF32 =23; // Offset in initial TLS block
R_X86_64_PC64 =24; // PC relative 64 bit
R_X86_64_GOTOFF64 =25; // 64 bit offset to GOT
R_X86_64_GOTPC32 =26; // 32 bit signed pc relative offset to GOT
R_X86_64_GOT64 =27; // 64-bit GOT entry offset
R_X86_64_GOTPCREL64 =28; // 64-bit PC relative offset to GOT entry
R_X86_64_GOTPC64 =29; // 64-bit PC relative offset to GOT
R_X86_64_GOTPLT64 =30; // like GOT64, says PLT entry needed
R_X86_64_PLTOFF64 =31; // 64-bit GOT relative offset to PLT entry
R_X86_64_SIZE32 =32; // Size of symbol plus 32-bit addend
R_X86_64_SIZE64 =33; // Size of symbol plus 64-bit addend
R_X86_64_GOTPC32_TLSDESC =34; // GOT offset for TLS descriptor
R_X86_64_TLSDESC_CALL =35; // Marker for call through TLS descriptor
R_X86_64_TLSDESC =36; // TLS descriptor
R_X86_64_IRELATIVE =37; // Adjust indirectly by program base
R_X86_64_RELATIVE64 =38; // 64bit adjust by program base
R_X86_64_ORBIS_GOTPCREL_LOAD =40;
type
Elf64_Addr =cuint64;
Elf64_Half =cuint16;
Elf64_SHalf =cint64 ;
Elf64_Off =cuint64;
Elf64_Sword =cint32 ;
Elf64_Word =cuint32;
Elf64_Xword =cuint64;
Elf64_Sxword=cint64 ;
Pelf64_hdr=^elf64_hdr;
elf64_hdr=packed record
e_ident:Array[0..EI_NIDENT-1] of Byte; // ELF "magic number"
e_type :Elf64_Half;
e_machine :Elf64_Half;
e_version :Elf64_Word;
e_entry :Elf64_Addr; // Entry point virtual address from where the process starts executing.
e_phoff :Elf64_Off ; // Program header table file offset
e_shoff :Elf64_Off ; // Section header table file offset
e_flags :Elf64_Word;
e_ehsize :Elf64_Half;
e_phentsize:Elf64_Half;
e_phnum :Elf64_Half;
e_shentsize:Elf64_Half;
e_shnum :Elf64_Half;
e_shstrndx :Elf64_Half;
end;
const
PF_W=$2;
PF_R=$4;
PF_X=$1;
type
Pelf64_phdr=^elf64_phdr;
elf64_phdr=packed record
p_type :Elf64_Word ;
p_flags :Elf64_Word ;
p_offset:Elf64_Off ; // Segment file offset
p_vaddr :Elf64_Addr ; // Segment virtual address
p_paddr :Elf64_Addr ; // Segment physical address
p_filesz:Elf64_Xword; // Segment size in file
p_memsz :Elf64_Xword; // Segment size in memory
p_align :Elf64_Xword; // Segment alignment, file & memory
end;
elf64_shdr=packed record
sh_name :Elf64_Word ; // Section name, index in string tbl
sh_type :Elf64_Word ; // Type of section
sh_flags :Elf64_Xword; // Miscellaneous section attributes
sh_addr :Elf64_Addr ; // Section virtual addr at execution
sh_offset :Elf64_Off ; // Section file offset
sh_size :Elf64_Xword; // Size of section in bytes
sh_link :Elf64_Word ; // Index of another section
sh_info :Elf64_Word ; // Additional section information
sh_addralign:Elf64_Xword; // Section alignment
sh_entsize :Elf64_Xword; // Entry size if section holds table
end;
PElf64_Dyn=^Elf64_Dyn;
Elf64_Dyn=packed record
d_tag:Elf64_Sxword; // entry tag value
d_un:packed record
Case Byte of
0:(d_val:Elf64_Xword);
1:(d_ptr:Elf64_Addr);
end;
end;
Pelf64_rela=^elf64_rela;
elf64_rela=packed record
r_offset:Elf64_Addr; // Location at which to apply the action
r_info:Elf64_Xword; // index and type of relocation
r_addend:Elf64_Sxword; // Constant addend used to compute value
end;
Pelf64_sym=^elf64_sym;
elf64_sym=packed record
st_name :Elf64_Word; // Symbol name, index in string tbl
st_info :Byte; // Type and binding attributes
st_other:Byte; // No defined meaning, 0
st_shndx:Elf64_Half; // Associated section index
st_value:Elf64_Addr; // Value of the symbol
st_size :Elf64_Xword; // Associated symbol size
end;
const
self_magic=$1D3D154F;
type
Pself_header=^Tself_header;
Tself_header=packed record
Magic:DWORD; //Magic 4F 15 3D 1D
Unknown:DWORD; //Unknown Always 00 01 01 12
Content_Type:Byte; //Content Type 1 on Self, 4 on PUP Entry
Program_Type:Byte; //Program Type
Padding:Word; //Padding
Header_Size:Word; //Header Size
Sign_Size:Word; //Signature Size Metadata Size?
Size_of:DWORD; //Size of SELF
Padding2:DWORD; //Padding
Num_Segments:Word; //Number of Segments
Unknown2:Word; //Unknown Always 0x22
Padding3:DWORD; //Padding
end;
const
SF_ORDR = $1; // ordered?
SF_ENCR = $2; // encrypted
SF_SIGN = $4; // signed
SF_DFLG = $8; // deflated
SF_BFLG = $800; // block segment
type
Pself_segment=^Tself_segment;
Tself_segment=packed record
flags,
offset,
encrypted_compressed_size, //fileSz
decrypted_decompressed_size:QWORD; //memSz
end;
Tself_spec=packed record
AuthorityID:QWORD;
Program_Type:QWORD;
Version1:QWORD;
Version2:QWORD;
Content_ID:array[0..31] of Byte;
Digest_SHA_256:array[0..31] of Byte;
end;
const
SCE_DBG_MAX_NAME_LENGTH = 256;
SCE_DBG_MAX_SEGMENTS = 4;
SCE_DBG_NUM_FINGERPRINT = 20;
type
TKernelModuleSegmentInfo=packed record
address:Pointer;
size:DWORD;
prot:Integer; //PF_
end;
PKernelModuleInfo=^TKernelModuleInfo;
TKernelModuleInfo=packed record
size:QWORD; //Size of this structure
name:array[0..SCE_DBG_MAX_NAME_LENGTH-1] of AnsiChar; //module name
segmentInfo:array[0..SCE_DBG_MAX_SEGMENTS-1] of TKernelModuleSegmentInfo;
segmentCount:DWORD;
fingerprint:array[0..SCE_DBG_NUM_FINGERPRINT-1] of Byte;
end;
TModuleValue=packed record
case Byte of
0:(value:Int64);
1:(name_offset:DWORD;
version_minor:Byte;
version_major:Byte;
id:Word);
end;
TLibraryValue=packed record
case Byte of
0:(value:Int64);
1:(name_offset:DWORD;
version_minor:Byte;
version_major:Byte;
id:Word);
end;
PsceModuleParam=^TsceModuleParam;
TsceModuleParam=packed record
Size:QWORD;
Magic:QWORD;
SDK_version:QWORD;
end;
PTLS_index=^TLS_index;
TLS_index=packed record
ti_moduleid :QWORD;
ti_tlsoffset:QWORD;
end;
PPS4StartupParams=^TPS4StartupParams;
TPS4StartupParams=packed record
argc:Integer;
align:Integer;
argv:array[0..1] of Pointer;
end;
Const
PHYSICAL_PAGE_SIZE=$1000;
GRANULAR_PAGE_SIZE=$10000;
LOGICAL_PAGE_SIZE =$4000;
STB_LOCAL =0;
STB_GLOBAL=1;
STB_WEAK =2;
STT_NOTYPE =0 ;
STT_OBJECT =1 ;
STT_FUN =2 ;
STT_SECTION =3 ;
STT_FILE =4 ;
STT_COMMON =5 ;
STT_TLS =6;
STT_LOOS =10;
STT_HIOS =12;
STT_LOPRO =13;
STT_SPARC_REGISTER=13;
STT_HIPROC =15;
STV_DEFAULT =0;
STV_INTERNAL =1;
STV_HIDDEN =2;
STV_PROTECTED =3;
SHN_UNDEF=0;
function ELF64_R_SYM(i:QWORD):DWORD; inline;
function ELF64_R_TYPE(i:QWORD):DWORD; inline;
function ELF64_ST_BIND(i:Byte):Byte; inline;
function ELF64_ST_TYPE(i:Byte):Byte; inline;
function ELF64_ST_VISIBILITY(i:Byte):Byte; inline;
function AlignUp(addr:PtrUInt;alignment:PtrUInt):PtrUInt; inline;
function AlignUp(addr:Pointer;alignment:PtrUInt):Pointer; inline;
function AlignDw(addr:PtrUInt;alignment:PtrUInt):PtrUInt; inline;
function AlignDw(addr:Pointer;alignment:PtrUInt):Pointer; inline;
function IsAlign(Addr:Pointer;Alignment:PtrUInt):Boolean; inline;
function IsAlign(Addr:PtrUInt;Alignment:PtrUInt):Boolean; inline;
type
Ptimespec=^timespec;
timespec=packed record
tv_sec:Int64; /// seconds
tv_nsec:Int64; /// nanoseconds
end;
timeval = record
tv_sec: int64;
tv_usec: int64; //microsecond
end;
Ptimeval=^timeval;
timezone = record
tz_minuteswest:Integer;
tz_dsttime:Integer;
end;
Ptimezone=^timezone;
TMemChunk=packed record
pAddr:Pointer;
nSize:Int64;
end;
implementation
function ELF64_R_SYM(i:QWORD):DWORD; inline;
begin
Result:=i shr 32;
end;
function ELF64_R_TYPE(i:QWORD):DWORD; inline;
begin
Result:=i and $ffffffff;
end;
function ELF64_ST_BIND(i:Byte):Byte; inline;
begin
Result:=i shr 4;
end;
function ELF64_ST_TYPE(i:Byte):Byte; inline;
begin
Result:=i and $f;
end;
function ELF64_ST_VISIBILITY(i:Byte):Byte; inline;
begin
Result:=i and 3;
end;
function AlignUp(addr:PtrUInt;alignment:PtrUInt):PtrUInt; inline;
var
tmp:PtrUInt;
begin
if (alignment=0) then Exit(addr);
tmp:=addr+PtrUInt(alignment-1);
Result:=tmp-(tmp mod alignment)
end;
function AlignUp(addr:Pointer;alignment:PtrUInt):Pointer; inline;
begin
Result:=Pointer(Align(PtrUInt(addr),alignment));
end;
function AlignDw(addr:PtrUInt;alignment:PtrUInt):PtrUInt; inline;
begin
Result:=addr-(addr mod alignment)
end;
function AlignDw(addr:Pointer;alignment:PtrUInt):Pointer; inline;
begin
Result:=Pointer(AlignDw(PtrUInt(addr),alignment));
end;
function IsAlign(Addr:Pointer;Alignment:PtrUInt):Boolean; inline;
begin
Result:=(PtrUInt(addr) mod alignment)=0;
end;
function IsAlign(Addr:PtrUInt;Alignment:PtrUInt):Boolean; inline;
begin
Result:=(addr mod alignment)=0;
end;
end.

65349
ps4libdoc.pas Normal file

File diff suppressed because it is too large Load Diff

406
seh64.pas Normal file
View File

@ -0,0 +1,406 @@
unit seh64;
{$mode objfpc}{$H+}
interface
implementation
uses
Windows,
SysConst,
SysUtils,
hamt,
ps4libdoc,
ps4_types,
ps4_program;
function AddVectoredExceptionHandler(FirstHandler: DWORD; VectoredHandler: pointer): pointer; stdcall;
external 'kernel32.dll' name 'AddVectoredExceptionHandler';
function RemoveVectoredExceptionHandler(VectoredHandlerHandle: pointer): ULONG; stdcall;
external 'kernel32.dll' name 'RemoveVectoredExceptionHandler';
function GetModuleHandleEx(dwFlags: DWORD; lpModuleName: pointer; var hModule: THandle): BOOL; stdcall;
external 'kernel32.dll' name 'GetModuleHandleExA';
// sysutils.GetModuleName();
const
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT = 2;
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS = 4;
function GetModuleByAdr(adr:Pointer):THandle;
var
Flags:DWORD;
begin
Flags:=GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS or GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
Result:=0;
GetModuleHandleEx(Flags,adr,Result);
end;
function RunErrorCode(const rec: TExceptionRecord): longint;
begin
{ negative result means 'FPU reset required' }
case rec.ExceptionCode of
STATUS_INTEGER_DIVIDE_BY_ZERO: result := 200; { reDivByZero }
STATUS_FLOAT_DIVIDE_BY_ZERO: result := -208; { !!reZeroDivide }
STATUS_ARRAY_BOUNDS_EXCEEDED: result := 201; { reRangeError }
STATUS_STACK_OVERFLOW: result := 202; { reStackOverflow }
STATUS_FLOAT_OVERFLOW: result := -205; { reOverflow }
STATUS_FLOAT_DENORMAL_OPERAND,
STATUS_FLOAT_UNDERFLOW: result := -206; { reUnderflow }
STATUS_FLOAT_INEXACT_RESULT,
STATUS_FLOAT_INVALID_OPERATION,
STATUS_FLOAT_STACK_CHECK: result := -207; { reInvalidOp }
STATUS_INTEGER_OVERFLOW: result := 215; { reIntOverflow }
STATUS_ILLEGAL_INSTRUCTION: result := -216;
STATUS_ACCESS_VIOLATION: result := 216; { reAccessViolation }
STATUS_CONTROL_C_EXIT: result := 217; { reControlBreak }
STATUS_PRIVILEGED_INSTRUCTION: result := 218; { rePrivilegedInstruction }
STATUS_FLOAT_MULTIPLE_TRAPS,
STATUS_FLOAT_MULTIPLE_FAULTS: result := -255; { indicate FPU reset }
else
result := 255; { reExternalException }
end;
end;
procedure TranslateMxcsr(mxcsr: longword; var code: longint);
begin
{ we can return only one value, further one's are lost }
{ InvalidOp }
if (mxcsr and 1)<>0 then
code:=-207
{ Denormal }
else if (mxcsr and 2)<>0 then
code:=-206
{ !!reZeroDivide }
else if (mxcsr and 4)<>0 then
code:=-208
{ reOverflow }
else if (mxcsr and 8)<>0 then
code:=-205
{ Underflow }
else if (mxcsr and 16)<>0 then
code:=-206
{ Precision }
else if (mxcsr and 32)<>0 then
code:=-207
else { this should not happen }
code:=-255
end;
function RunErrorCodex64(const rec: TExceptionRecord; const context: TContext): Longint;
begin
Result:=RunErrorCode(rec);
if (Result=-255) then
TranslateMxcsr(context.MxCsr,result);
end;
type
_TElf_node=class(TElf_node)
end;
PTLQRec=^TLQRec;
TLQRec=record
pAddr:Pointer;
ExceptAddr:Pointer;
LastAdr:Pointer;
LastNid:QWORD;
end;
procedure trav_proc(data,userdata:Pointer);
var
adr:Pointer;
nid:QWORD;
begin
if (data=nil) then Exit;
safe_move_ptr(PPointer(data)[0],adr);
safe_move_ptr(PPointer(data)[1],nid);
if (adr>=PTLQRec(userdata)^.pAddr) then
if (adr<=PTLQRec(userdata)^.ExceptAddr) then
if (adr>PTLQRec(userdata)^.LastAdr) then
begin
PTLQRec(userdata)^.LastAdr:=adr;
PTLQRec(userdata)^.LastNid:=nid;
end;
end;
function IsSubTrie64(n:PHAMTNode64):Boolean; inline;
var
BaseValue:PtrUint;
begin
safe_move_ptr(n^.BaseValue,BaseValue);
Result:=(BaseValue and 1)<>0;
end;
function GetBitMapSize64(n:PHAMTNode64):QWORD; inline;
var
BitMapKey:QWORD;
begin
safe_move_ptr(n^.BitMapKey,BitMapKey);
Result:=PopCnt(BitMapKey);
Result:=Result and HAMT64.node_mask;
if (Result=0) then Result:=HAMT64.node_size;
end;
function GetSubTrie64(n:PHAMTNode64):PHAMTNode64; inline;
var
BaseValue:PtrUint;
begin
safe_move_ptr(n^.BaseValue,BaseValue);
PtrUint(Result):=(BaseValue or 1) xor 1;
end;
function GetValue64(n:PHAMTNode64):Pointer; inline;
begin
safe_move_ptr(n^.BaseValue,Result);
end;
procedure HAMT_traverse_trie64(node:PHAMTNode64;cb:Tfree_data_cb;userdata:Pointer); inline;
type
PStackNode=^TStackNode;
TStackNode=packed record
cnode,enode:PHAMTNode64;
end;
var
curr:PStackNode;
data:array[0..HAMT64.stack_max] of TStackNode;
Size:QWORD;
begin
if IsSubTrie64(node) then
begin
curr:=@data;
Size:=GetBitMapSize64(node);
With curr^ do
begin
cnode:=GetSubTrie64(node);
enode:=@cnode[Size];
end;
repeat
if (curr^.cnode>=curr^.enode) then
begin
if (curr=@data) then Break;
Dec(curr);
Inc(curr^.cnode);
Continue;
end;
if IsSubTrie64(curr^.cnode) then
begin
node:=curr^.cnode;
Inc(curr);
Size:=GetBitMapSize64(node);
With curr^ do
begin
cnode:=GetSubTrie64(node);
enode:=@cnode[Size];
end;
end else
begin
if (cb<>nil) then
cb(GetValue64(curr^.cnode),userdata);
Inc(curr^.cnode);
end;
until false;
end else
begin
if (cb<>nil) then
cb(GetValue64(node),userdata);
end;
end;
function HAMT_traverse64(hamt:THAMT;cb:Tfree_data_cb;userdata:Pointer):Boolean;
var
i:Integer;
node:PHAMTNode64;
begin
if (hamt=nil) then Exit(False);
For i:=0 to HAMT64.root_mask do
begin
node:=@PHAMTNode64(hamt)[i];
HAMT_traverse_trie64(node,cb,userdata);
end;
Result:=True;
end;
Function FindLQProc(node:TElf_node;r:PTLQRec):Boolean;
var
i,l:SizeInt;
lib:PLIBRARY;
MapSymbol:THAMT;
Import:Boolean;
begin
Result:=false;
l:=Length(_TElf_node(node).aLibs);
if (l<>0) then
begin
r^.LastAdr:=nil;
r^.LastNid:=0;
For i:=0 to l-1 do
begin
safe_move_ptr(_TElf_node(node).aLibs[i],lib);
if (lib<>nil) then
begin
Import:=True;
safe_move(lib^.Import,Import,SizeOf(Boolean));
if not Import then
begin
safe_move_ptr(lib^.MapSymbol,MapSymbol);
HAMT_traverse64(MapSymbol,@trav_proc,r);
end;
end;
end;
Result:=(r^.LastAdr<>nil);
end;
end;
Procedure WriteErr(Const s:shortstring);
var
num:DWORD;
begin
WriteConsole(GetStdHandle(STD_ERROR_HANDLE),@s[1],ord(s[0]),num,nil);
end;
function IntToStr(Value:longint): shortstring;
begin
System.Str(Value,result);
end;
function GetModuleName(Module:HMODULE): shortstring;
var
Len:DWORD;
Buffer:array[0..MAX_PATH] of WideChar;
P:PWideChar;
begin
Len:=GetModuleFileNameW(Module,@Buffer,MAX_PATH);
P:=@Buffer[Len];
While (P<>@Buffer) do
begin
if (P^='\') then
begin
Inc(P);
Break;
end;
Dec(P);
end;
Len:=@Buffer[Len]-P;
Len:=UnicodeToUtf8(@Result[1],255,P,Len);
Byte(Result[0]):=Len;
end;
Procedure DumpException(node:TElf_node;code:Longint;ExceptAddr:Pointer;ContextRecord:PCONTEXT);
var
Report:shortstring;
pFileName:PChar;
Mem:TMemChunk;
top,rbp:PPointer;
procedure print_adr;
var
r:TLQRec;
begin
Report:=' $'+hexstr(ExceptAddr);
if (node<>nil) then
begin
Mem:=node.GetCodeFrame;
if (Mem.pAddr<>nil) and (Mem.nSize<>0) then
begin
safe_move_ptr(node.pFileName,pFileName);
Report:=Report+' offset $'+hexstr(ExceptAddr-Mem.pAddr,8)+' '+safe_str(pFileName);
r.pAddr:=Mem.pAddr;
r.ExceptAddr:=ExceptAddr;
if FindLQProc(node,@r) then
begin
Report:=Report+':'+ps4libdoc.GetFunctName(r.LastNid)+'+$'+hexstr(ExceptAddr-r.LastAdr,8);
end else
if (node.GetEntryPoint<>nil) then
begin
Report:=Report+':EntryPoint+$'+hexstr(ExceptAddr-node.GetEntryPoint,8);
end;
end;
end;
Report:=Report+#13#10;
WriteErr(Report);
end;
procedure print_adr2;
begin
Report:=' $'+hexstr(ExceptAddr);
Report:=Report+' '+GetModuleName(GetModuleByAdr(ExceptAddr));
Report:=Report+#13#10;
WriteErr(Report);
end;
begin
Report:='';
Report:=Report+'Message: '+SysConst.GetRunError(abs(code));
Report:=Report+' ('+IntToStr(longint(code))+')';
Report:=Report+#13#10;
WriteErr(Report);
print_adr;
top:=Pointer(ContextRecord^.Rbp);
//if (top>StackBottom) and (top<StackTop) then
begin
rbp:=top;
repeat
safe_move_ptr(rbp[1],ExceptAddr);
safe_move_ptr(rbp[0],rbp);
if (ExceptAddr<>nil) then
begin
node:=ps4_app.FindFileByCodeAdr(ExceptAddr);
if (node<>nil) then
begin
print_adr;
end else
begin
print_adr2;
end;
end;
until (node=nil) {or (rbp>top) or (rbp<StackBottom)};
end;
end;
const
FPC_EXCEPTION_CODE=$E0465043;
function ProcessException(p: PExceptionPointers): longint; stdcall;
var
code: Longint;
node:TElf_node;
begin
Result := 0;
if (p^.ExceptionRecord^.ExceptionCode=FPC_EXCEPTION_CODE) then Exit(EXCEPTION_CONTINUE_SEARCH);
node:=ps4_app.FindFileByCodeAdr(p^.ExceptionRecord^.ExceptionAddress);
if (node=nil) and
(GetModuleByAdr(p^.ExceptionRecord^.ExceptionAddress)<>GetModuleByAdr(@ProcessException)) then
Exit(EXCEPTION_CONTINUE_SEARCH);
code:=RunErrorCodex64(p^.ExceptionRecord^,p^.ContextRecord^);
DumpException(node,code,p^.ExceptionRecord^.ExceptionAddress,P^.ContextRecord);
halt;
end;
var
VEHandler: pointer = Nil;
procedure InstallExceptionHandler;
begin
VEHandler := AddVectoredExceptionHandler(1, @ProcessException);
end;
procedure UninstallExceptionHandler;
begin
if Assigned(VEHandler) then
begin
RemoveVectoredExceptionHandler(VEHandler);
VEHandler := Nil;
end;
end;
initialization
InstallExceptionHandler;
finalization
UninstallExceptionHandler;
end.

60
shaders/FLIP_CURSOR.comp Normal file
View File

@ -0,0 +1,60 @@
#version 450
layout (local_size_x = 16, local_size_y = 16) in;
layout (binding = 0) readonly buffer Host
{
uint data[];
} host;
layout (binding = 1, rgba8) uniform image2D resultImage;
layout (push_constant) uniform constants
{
vec4 gamma;
ivec2 pos;
} cfg;
void main()
{
ivec2 pixelCoords = ivec2(gl_GlobalInvocationID.xy);
int offset = (pixelCoords.y*64)+pixelCoords.x;
uint pack=host.data[offset];
////const uvec4 shift = uvec4(16,8,0,24);
////const uvec4 mask4 = uvec4(255,255,255,255);
////uvec4 pix_int=(uvec4(pack,pack,pack,pack) >> shift) & mask4;
//24,16, 8, 0
//AA,RR,GG,BB
//0,8,16,24
//R,G, B,A
//16,8,0,24
//BGRA
//24,0,8,16
//ARGB
////vec4 pixel = vec4(pix_int) / mask4;
vec4 pixel=unpackUnorm4x8(pack);
pixel=pixel.bgra;
pixel = pow(pixel, cfg.gamma);
pixelCoords = pixelCoords + cfg.pos;
vec4 prev = imageLoad(resultImage, pixelCoords);
pixel.rgb = mix(prev.rgb,pixel.rgb,pixel.a);
imageStore(resultImage, pixelCoords, pixel);
}

BIN
shaders/FLIP_CURSOR.spv Normal file

Binary file not shown.

View File

@ -0,0 +1,44 @@
#version 450
layout (local_size_x = 16, local_size_y = 16) in;
layout (binding = 0) readonly buffer Host
{
uint data[];
} host;
layout (binding = 1, rgba8) writeonly uniform image2D resultImage;
layout (push_constant) uniform constants
{
vec4 gamma;
ivec2 Width;
} cfg;
void main()
{
ivec2 pixelCoords = ivec2(gl_GlobalInvocationID.xy);
int offset = (pixelCoords.y*cfg.Width.y)+pixelCoords.x;
uint pack=host.data[offset];
const uvec4 shift = uvec4(16,8,0,24);
const uvec4 mask4 = uvec4(255,255,255,255);
uvec4 pix_int=(uvec4(pack,pack,pack,pack) >> shift) & mask4;
//0,8,16,24
//R,G, B,A
//16,8,0,24
//BGRA
vec4 pixel = vec4(pix_int) / mask4;
pixel = pow(pixel, cfg.gamma);
imageStore(resultImage, pixelCoords, pixel);
}

Binary file not shown.

View File

@ -0,0 +1,95 @@
#version 450
layout (local_size_x = 16, local_size_y = 16) in;
layout (binding = 0) readonly buffer Host
{
uint data[];
} host;
layout (binding = 1, rgba8) writeonly uniform image2D resultImage;
layout (push_constant) uniform constants
{
vec4 gamma;
ivec2 pitch;
} cfg;
const ivec2 sh02 = ivec2(0,2);
const ivec4 sh1212 = ivec4(1,2,1,2);
const ivec4 sh1345 = ivec4(1,3,4,5);
const ivec3 sh345 = ivec3(3,4,5);
const ivec3 sh678 = ivec3(6,7,8);
const ivec4 sh6789 = ivec4(6,7,8,9);
const ivec4 sh6543 = ivec4(6,5,4,3);
const ivec4 sh9101112 = ivec4(9,10,11,12);
const ivec2 i2_1 = ivec2(1,1);
const ivec3 i3_1 = ivec3(1,1,1);
const ivec4 i4_1 = ivec4(1,1,1,1);
int getElementIndex(ivec2 p) //[0..5]
{
ivec2 t1=(p.xy & i2_1) << sh02;
ivec4 t2=((p.xxyy >> sh1212) & i4_1) << sh1345;
t1=t1 | t2.xy | t2.zw;
return t1.x | t1.y;
}
int getPipeIndex(ivec2 p) //[6..8]
{
ivec3 t=(((p.xxx >> sh345) ^ (p.yyy >> sh345) ^ ivec3(p.x>>4,0,0)) & i3_1) << sh678;
return t.x | t.y | t.z;
}
int getBankIndex(ivec2 p) //[9..12]
{
ivec4 bank=(((p.xxxx >> sh6789) ^ (p.yyyy >> sh6543) ^ ivec4(0,p.y>>6,0,0)) & i4_1) << sh9101112;
ivec2 t=bank.xy | bank.zw;
return t.x | t.y;
}
void main()
{
ivec2 pixelCoords = ivec2(gl_GlobalInvocationID.xy);
int element_index=getElementIndex(pixelCoords);
int pipe=getPipeIndex(pixelCoords);
int bank=getBankIndex(pixelCoords);
const ivec4 shmt = ivec4(7,6,6,3);
const ivec2 bmod = ivec2(1,1);
ivec4 mt=(pixelCoords.xyxy >> shmt);
ivec2 total_offset=(mt.xy*cfg.pitch)+(mt.zw % bmod);
int offset = element_index | pipe | bank | ((total_offset.x+total_offset.y) << 13);
uint pack=host.data[offset];
////const uvec4 shift = uvec4(16,8,0,24);
////const uvec4 mask4 = uvec4(255,255,255,255);
////uvec4 pix_int=(uvec4(pack,pack,pack,pack) >> shift) & mask4;
//0,8,16,24
//R,G, B,A
//16,8,0,24
//BGRA
////vec4 pixel = vec4(pix_int) / mask4;
vec4 pixel=unpackUnorm4x8(pack);
pixel=pixel.bgra;
pixel = pow(pixel, cfg.gamma);
imageStore(resultImage, pixelCoords, pixel);
}

Binary file not shown.

View File

@ -0,0 +1,97 @@
#version 450
layout (local_size_x = 16, local_size_y = 16) in;
layout (binding = 0) readonly buffer Host
{
uint data[];
} host;
layout (binding = 1, rgba8) writeonly uniform image2D resultImage;
layout (push_constant) uniform constants
{
vec4 gamma;
ivec2 pitch;
} cfg;
const ivec2 sh02 = ivec2(0,2);
const ivec4 sh1212 = ivec4(1,2,1,2);
const ivec4 sh1345 = ivec4(1,3,4,5);
const ivec4 sh3456 = ivec4(3,4,5,6);
const ivec4 sh3455 = ivec4(3,4,5,5);
const ivec4 sh6789 = ivec4(6,7,8,9);
const ivec3 sh789 = ivec3(7,8,9);
const ivec3 sh654 = ivec3(6,5,4);
const ivec3 sh101112 = ivec3(10,11,12);
const ivec2 i2_1 = ivec2(1,1);
const ivec3 i3_1 = ivec3(1,1,1);
const ivec4 i4_1 = ivec4(1,1,1,1);
int getElementIndex(ivec2 p) //[0..5]
{
ivec2 t1=(p.xy & i2_1) << sh02;
ivec4 t2=((p.xxyy >> sh1212) & i4_1) << sh1345;
t1=t1 | t2.xy | t2.zw;
return t1.x | t1.y;
}
int getPipeIndex(ivec2 p) //[6..9]
{
ivec4 t=(((p.xxxx >> sh3456) ^ (p.yyyy >> sh3455) ^ ivec4(p.x>>4,0,0,0)) & i4_1) << sh6789;
ivec2 t2=t.xy | t.zw;
return t2.x | t2.y;
}
int getBankIndex(ivec2 p) //[10..12]
{
ivec3 bank=(((p.xxx >> sh789) ^ (p.yyy >> sh654) ^ ivec3(0,p.y>>6,0)) & i3_1) << sh101112;
return bank.x | bank.y | bank.z;
}
void main()
{
ivec2 pixelCoords = ivec2(gl_GlobalInvocationID.xy);
int element_index=getElementIndex(pixelCoords);
int pipe=getPipeIndex(pixelCoords);
int bank=getBankIndex(pixelCoords);
const ivec4 shmt = ivec4(7,7,7,3);
const ivec2 bmod = ivec2(1,2);
ivec4 mt=(pixelCoords.xyxy >> shmt);
ivec2 total_offset=((mt.xy*cfg.pitch) << i2_1)+(mt.zw % bmod);
int offset = element_index | pipe | bank | ((total_offset.x+total_offset.y) << 13);
uint pack=host.data[offset];
////const uvec4 shift = uvec4(16,8,0,24);
////const uvec4 mask4 = uvec4(255,255,255,255);
////uvec4 pix_int=(uvec4(pack,pack,pack,pack) >> shift) & mask4;
//0,8,16,24
//R,G, B,A
//16,8,0,24
//BGRA
////vec4 pixel = vec4(pix_int) / mask4;
vec4 pixel=unpackUnorm4x8(pack);
pixel=pixel.bgra;
pixel = pow(pixel, cfg.gamma);
imageStore(resultImage, pixelCoords, pixel);
}

Binary file not shown.

19
shaders/compile.cmd Normal file
View File

@ -0,0 +1,19 @@
Set spirvgls=spirv\glslangValidator -g0 -V --target-env vulkan1.0
Set spirvopt=spirv\spirv-opt --eliminate-dead-branches --eliminate-local-multi-store --inline-entry-points-exhaustive --eliminate-dead-code-aggressive --scalar-replacement --simplify-instructions
%spirvgls% FLIP_CURSOR.comp -o FLIP_CURSOR.spv
%spirvopt% FLIP_CURSOR.spv -o FLIP_CURSOR.spv
%spirvgls% FLIP_TILE_A8R8G8B8_SRGB.comp -o FLIP_TILE_A8R8G8B8_SRGB.spv
%spirvopt% FLIP_TILE_A8R8G8B8_SRGB.spv -o FLIP_TILE_A8R8G8B8_SRGB.spv
%spirvgls% FLIP_LINE_A8R8G8B8_SRGB.comp -o FLIP_LINE_A8R8G8B8_SRGB.spv
%spirvopt% FLIP_LINE_A8R8G8B8_SRGB.spv -o FLIP_LINE_A8R8G8B8_SRGB.spv
%spirvgls% FLIP_TILE_A8R8G8B8_SRGB_NEO.comp -o FLIP_TILE_A8R8G8B8_SRGB_NEO.spv
%spirvopt% FLIP_TILE_A8R8G8B8_SRGB_NEO.spv -o FLIP_TILE_A8R8G8B8_SRGB_NEO.spv
pause

184
stub_manager.pas Normal file
View File

@ -0,0 +1,184 @@
unit stub_manager;
{$mode objfpc}{$H+}
interface
uses
Windows;
type
TStubMemory=object
protected
type
PNode=^TNode;
TNode=record
pNext:PNode;
Stub_va:Pointer;
end;
Const
VA_SIZE=16*1024;
var
pHead:PNode;
Stub_va:Pointer;
Stub_pos:Word;
procedure Push(P:Pointer);
function Pop:Pointer;
public
Procedure Clear;
procedure FinStub;
function NewStub(data:Pointer;size:Word):Pointer;
end;
TStubMemoryProc=object(TStubMemory)
function NewNopStub(nid:QWORD;lib,proc:Pointer):Pointer;
end;
implementation
procedure TStubMemory.Push(P:Pointer);
var
Node:PNode;
begin
Node:=AllocMem(SizeOf(TNode));
Node^.Stub_va:=P;
if (pHead=nil) then
begin
node^.pNext:=nil;
end else
begin
node^.pNext:=pHead;
end;
pHead:=node;
end;
function TStubMemory.Pop:Pointer;
var
Node:PNode;
begin
Result:=nil;
Node:=pHead;
if (pHead<>nil) then
begin
pHead:=pHead^.pNext;
end;
if (Node<>nil) then
begin
Node^.pNext:=nil;
end;
if (Node<>nil) then
begin
Result:=Node^.Stub_va;
FreeMem(Node);
end;
end;
Procedure TStubMemory.Clear;
var
P:Pointer;
begin
P:=Pop;
While (P<>nil) do
begin
VirtualFree(P,0,MEM_RELEASE);
P:=Pop;
end;
if (Stub_va<>nil) then
begin
VirtualFree(Stub_va,0,MEM_RELEASE);
end;
Stub_va:=nil;
Stub_pos:=0;
end;
procedure TStubMemory.FinStub;
var
dummy:DWORD;
begin
if (Stub_va<>nil) then
begin
Push(Stub_va);
VirtualProtect(Stub_va,VA_SIZE,PAGE_EXECUTE_READ,@dummy);
FlushInstructionCache(GetCurrentProcess,Stub_va,VA_SIZE);
Stub_va:=nil;
Stub_pos:=0;
end;
end;
function TStubMemory.NewStub(data:Pointer;size:Word):Pointer;
begin
if ((Stub_pos+size)>VA_SIZE) then
FinStub;
if (Stub_va=nil) then
begin
Stub_va:=VirtualAlloc(nil,VA_SIZE,MEM_COMMIT or MEM_RESERVE,PAGE_READWRITE);
end;
Result:=Stub_va+Stub_pos;
Move(data^,Result^,size);
Stub_pos:=Stub_pos+size;
end;
//
//52 push %rdx
//51 push %rcx
//48ba0100000000000000 movabs $0x1,%rdx
//48b90200000000000000 movabs $0x2,%rcx
//48b80300000000000000 movabs $0x3,%rax
//ffd0 callq *%rax
//4831c0 xor %rax,%rax
//59 pop %rcx
//5a pop %rdx
//c3 retq
Type
Pnopstub=^Tnopstub;
Tnopstub=packed record
_push_rdx:Byte; // $52
_push_rcx:Byte; // $51
_movabs_rdx:array[0..1] of Byte; // $48 $ba
_lib:Pointer;
_movabs_rcx:array[0..1] of Byte; // $48 $B9
_nid:QWord;
_movabs_rax:array[0..1] of Byte; // $48 $B8
_addr:Pointer;
_call_rax:array[0..1] of Byte; // $FF $D0
_pop_rcx:Byte; // $59
_pop_rdx:Byte; // $5A
_ret:Byte; // $C3
end;
const
_nopstub:Tnopstub=(
_push_rdx:$52;
_push_rcx:$51;
_movabs_rdx:($48,$BA);
_lib:nil;
_movabs_rcx:($48,$B9);
_nid:0;
_movabs_rax:($48,$B8);
_addr:nil;
_call_rax:($FF,$D0);
_pop_rcx:$59;
_pop_rdx:$5A;
_ret:$C3
);
function TStubMemoryProc.NewNopStub(nid:QWORD;lib,proc:Pointer):Pointer;
var
nopstub:Tnopstub;
begin
nopstub:=_nopstub;
nopstub._lib:=lib;
nopstub._nid:=nid;
nopstub._addr:=proc;
Result:=NewStub(@nopstub,SizeOf(Tnopstub));
end;
end.

38766
vulkan/Vulkan.pas Normal file

File diff suppressed because it is too large Load Diff

1019
vulkan/vDevice.pas Normal file

File diff suppressed because it is too large Load Diff

1053
vulkan/vFlip.pas Normal file

File diff suppressed because it is too large Load Diff

539
vulkan/vImage.pas Normal file
View File

@ -0,0 +1,539 @@
unit vImage;
{$mode objfpc}{$H+}
interface
uses
g23tree,
vulkan,
vDevice,
vPipeline,
vMemory;
type
TSwapChain=class
FSurface:TvSurface;
FSize:TVkExtent2D;
FHandle:TVkSwapchainKHR;
FImage:array of TVkImage;
FViews:array of TVkImageView;
Constructor Create(Surface:TvSurface;mode:Integer;imageUsage:TVkImageUsageFlags);
Destructor Destroy; override;
end;
TvImageView=class
FHandle:TVkImageView;
Destructor Destroy; override;
end;
TvImage=class
FHandle:TVkImage;
FFormat:TVkFormat;
FUsage:TVkFlags;
FExtent:TVkExtent3D;
Constructor Create(format:TVkFormat;extent:TVkExtent3D;usage:TVkFlags;ext:Pointer=nil);
Destructor Destroy; override;
function GetRequirements:TVkMemoryRequirements;
function GetDedicatedAllocation:Boolean;
function BindMem(P:TvPointer):TVkResult;
function GetCInfo:TVkImageCreateInfo; virtual; abstract;
function GetIVCInfo:TVkImageViewCreateInfo; virtual; abstract;
function NewView:TvImageView;
function NewViewF(Format:TVkFormat):TvImageView;
end;
TvHostImage2D=class(TvImage)
function GetCInfo:TVkImageCreateInfo; override;
end;
TvDeviceImage2D=class(TvImage)
function GetIVCInfo:TVkImageViewCreateInfo; override;
function GetCInfo:TVkImageCreateInfo; override;
end;
TvBuffer=class
FHandle:TVkBuffer;
FSize:TVkDeviceSize;
FUsage:TVkFlags;
Constructor Create(size:TVkDeviceSize;usage:TVkFlags;ext:Pointer=nil);
Destructor Destroy; override;
function GetRequirements:TVkMemoryRequirements;
function GetDedicatedAllocation:Boolean;
function BindMem(P:TvPointer):TVkResult;
end;
_TvImageViewCompare=object
function c(const a,b:TvImageView):Integer; static;
end;
_TvImageViewSet=specialize T23treeSet<TvImageView,_TvImageViewCompare>;
TvFramebuffer=class
FHandle:TVkFramebuffer;
FEdit,FCompile:ptruint;
FRenderPass:TvRenderPass;
FSize:TVkExtent2D;
FImages:_TvImageViewSet;
Procedure SetRenderPass(r:TvRenderPass);
Procedure SetSize(Size:TVkExtent2D);
Procedure AddImageView(v:TvImageView);
Procedure ClearImageViews;
Procedure FreeImageViews;
function IsEdit:Boolean;
function Compile:Boolean;
Destructor Destroy; override;
end;
implementation
function _TvImageViewCompare.c(const a,b:TvImageView):Integer;
begin
Result:=CompareByte(a,b,SizeOf(TvImageView));
end;
Procedure TvFramebuffer.SetRenderPass(r:TvRenderPass);
begin
if (r=FRenderPass) then Exit;
FRenderPass:=r;
Inc(FEdit);
end;
Procedure TvFramebuffer.SetSize(Size:TVkExtent2D);
begin
if CompareByte(Size,FSize,SizeOf(TVkExtent2D))=0 then Exit;
FSize:=Size;
Inc(FEdit);
end;
Procedure TvFramebuffer.AddImageView(v:TvImageView);
begin
if (v=nil) then Exit;
if FImages.Contains(v) then Exit;
FImages.Insert(v);
Inc(FEdit);
end;
Procedure TvFramebuffer.ClearImageViews;
begin
FImages.Free;
Inc(FEdit);
end;
Procedure TvFramebuffer.FreeImageViews;
var
It:_TvImageViewSet.Iterator;
begin
It:=FImages.cbegin;
if (It.Item<>nil) then
repeat
TvImageView(It.Item^).Free;
until not It.Next;
FImages.Free;
Inc(FEdit);
end;
function TvFramebuffer.IsEdit:Boolean;
begin
Result:=(FEdit<>FCompile);
end;
function TvFramebuffer.Compile:Boolean;
var
i:TVkUInt32;
It:_TvImageViewSet.Iterator;
v:TvImageView;
r:TVkResult;
info:TVkFramebufferCreateInfo;
begin
Result:=False;
if (FHandle<>VK_NULL_HANDLE) and (not IsEdit) then Exit(true);
if (FRenderPass=nil) then Exit;
if (FRenderPass.FHandle=VK_NULL_HANDLE) then Exit;
if (FSize.width=0) or (FSize.height=0) then Exit;
info:=Default(TVkFramebufferCreateInfo);
info.sType :=VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
info.renderPass :=FRenderPass.FHandle;
info.attachmentCount:=FImages.Size;
info.width :=FSize.width;
info.height:=FSize.height;
info.layers:=1;
if (info.attachmentCount<>0) then
begin
info.pAttachments:=AllocMem(info.attachmentCount*SizeOf(TVkImageView));
i:=0;
It:=FImages.cbegin;
if (It.Item<>nil) then
repeat
v:=It.Item^;
if (v<>nil) then
begin
info.pAttachments[i]:=v.FHandle;
Inc(i);
end;
until not It.Next;
info.attachmentCount:=i;
end;
if (info.attachmentCount=0) then
begin
if (info.pAttachments<>nil) then
FreeMem(info.pAttachments);
info.flags:=ord(VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT);
info.pAttachments:=nil;
end;
r:=vkCreateFramebuffer(Device.FHandle,@info,nil,@FHandle);
if (r<>VK_SUCCESS) then
begin
Writeln('vkCreateFramebuffer');
end;
if (info.pAttachments<>nil) then
FreeMem(info.pAttachments);
Result:=(r=VK_SUCCESS);
end;
Destructor TvFramebuffer.Destroy;
begin
if (FHandle<>VK_NULL_HANDLE) then
vkDestroyFramebuffer(Device.FHandle,FHandle,nil);
inherited;
end;
Constructor TSwapChain.Create(Surface:TvSurface;mode:Integer;imageUsage:TVkImageUsageFlags);
var
queueFamilyIndices:array[0..1] of TVkUInt32;
cinfo:TVkSwapchainCreateInfoKHR;
r:TVkResult;
i,count:TVkUInt32;
cimg:TVkImageViewCreateInfo;
begin
FSurface:=Surface;
Case mode of
1,2,3:;
else
mode:=1;
end;
FSize:=Surface.GetSize;
if (FSize.width=0) or (FSize.height=0) then Exit;
cinfo:=Default(TVkSwapchainCreateInfoKHR);
cinfo.sType :=VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
cinfo.surface :=FSurface.FHandle;
cinfo.minImageCount :=2;
cinfo.imageFormat :=FSurface.Fformat.format;
cinfo.imageColorSpace :=FSurface.Fformat.colorSpace;
cinfo.imageExtent :=FSize;
cinfo.imageArrayLayers:=1;
cinfo.imageUsage :=imageUsage or ord(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
if (VulkanApp.FGFamily<>Surface.FPFamily) then
begin
queueFamilyIndices[0]:=VulkanApp.FGFamily;
queueFamilyIndices[1]:=Surface.FPFamily;
cinfo.imageSharingMode :=VK_SHARING_MODE_CONCURRENT;
cinfo.queueFamilyIndexCount :=2;
cinfo.pQueueFamilyIndices :=@queueFamilyIndices;
end else
begin
cinfo.imageSharingMode :=VK_SHARING_MODE_EXCLUSIVE;
cinfo.queueFamilyIndexCount :=0;
cinfo.pQueueFamilyIndices :=nil;
end;
cinfo.preTransform :=VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
cinfo.compositeAlpha:=VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
cinfo.presentMode :=Surface.FModes[mode-1];
cinfo.clipped :=VK_TRUE;
cinfo.oldSwapchain :=VK_NULL_HANDLE;
r:=vkCreateSwapchainKHR(Device.FHandle,@cinfo,nil,@FHandle);
if (r<>VK_SUCCESS) then
begin
Writeln('vkCreateSwapchainKHR:',r);
Exit;
end;
count:=1;
Case mode of
1,2:count:=2;
3:count:=3;
end;
SetLength(FImage,count);
SetLength(FViews,count);
r:=vkGetSwapchainImagesKHR(Device.FHandle,FHandle,@count,@FImage[0]);
if (r<>VK_SUCCESS) then
begin
Writeln('vkGetSwapchainImagesKHR:',r);
Exit;
end;
cimg:=Default(TVkImageViewCreateInfo);
cimg.sType :=VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
cimg.viewType :=VK_IMAGE_VIEW_TYPE_2D;
cimg.format :=Surface.Fformat.format;
cimg.components.r:=VK_COMPONENT_SWIZZLE_IDENTITY;
cimg.components.g:=VK_COMPONENT_SWIZZLE_IDENTITY;
cimg.components.b:=VK_COMPONENT_SWIZZLE_IDENTITY;
cimg.components.a:=VK_COMPONENT_SWIZZLE_IDENTITY;
cimg.subresourceRange.aspectMask :=TVkImageAspectFlags(VK_IMAGE_ASPECT_COLOR_BIT);
cimg.subresourceRange.baseMipLevel :=0;
cimg.subresourceRange.levelCount :=1;
cimg.subresourceRange.baseArrayLayer:=0;
cimg.subresourceRange.layerCount :=1;
For i:=0 to count-1 do
begin
cimg.image:=FImage[i];
r:=vkCreateImageView(Device.FHandle,@cimg,nil,@FViews[i]);
if (r<>VK_SUCCESS) then
begin
Writeln('vkCreateImageView:',r);
Exit;
end;
end;
end;
Destructor TSwapChain.Destroy;
var
i:Integer;
begin
For i:=0 to High(FViews) do
begin
vkDestroyImageView(Device.FHandle,FViews[i],nil);
end;
vkDestroySwapchainKHR(Device.FHandle,FHandle,nil);
end;
Constructor TvImage.Create(format:TVkFormat;extent:TVkExtent3D;usage:TVkFlags;ext:Pointer=nil);
var
cinfo:TVkImageCreateInfo;
r:TVkResult;
begin
FFormat:=format;
FUsage:=usage;
FExtent:=extent;
cinfo:=GetCInfo;
cinfo.format:=format;
cinfo.extent:=extent;
cinfo.usage :=usage;
cinfo.pNext:=ext;
r:=vkCreateImage(Device.FHandle,@cinfo,nil,@FHandle);
if (r<>VK_SUCCESS) then
begin
Writeln('vkCreateImage:',r);
Exit;
end;
end;
Destructor TvImage.Destroy;
begin
vkDestroyImage(Device.FHandle,FHandle,nil);
end;
function TvImage.GetRequirements:TVkMemoryRequirements;
begin
Result:=Default(TVkMemoryRequirements);
vkGetImageMemoryRequirements(Device.FHandle,FHandle,@Result);
end;
function TvImage.GetDedicatedAllocation:Boolean;
var
info:TVkImageMemoryRequirementsInfo2;
rmem:TVkMemoryRequirements2;
rded:TVkMemoryDedicatedRequirements;
begin
Result:=false;
if Pointer(vkGetImageMemoryRequirements2)=nil then Exit;
info:=Default(TVkImageMemoryRequirementsInfo2);
info.sType:=VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2;
info.image:=FHandle;
rmem:=Default(TVkMemoryRequirements2);
rmem.sType:=VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
rded:=Default(TVkMemoryDedicatedRequirements);
rded.sType:=VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;
rmem.pNext:=@rded;
vkGetImageMemoryRequirements2(Device.FHandle,@info,@rmem);
Result:=(rded.requiresDedicatedAllocation<>VK_FALSE) or
(rded.prefersDedicatedAllocation <>VK_FALSE);
end;
function TvImage.BindMem(P:TvPointer):TVkResult;
begin
Result:=vkBindImageMemory(Device.FHandle,FHandle,P.FHandle,P.FOffset);
end;
function TvImage.NewView:TvImageView;
var
cinfo:TVkImageViewCreateInfo;
FImg:TVkImageView;
r:TVkResult;
begin
Result:=nil;
cinfo:=GetIVCInfo;
cinfo.image:=FHandle;
FImg:=VK_NULL_HANDLE;
r:=vkCreateImageView(Device.FHandle,@cinfo,nil,@FImg);
if (r<>VK_SUCCESS) then
begin
Writeln('vkCreateImageView:',r);
Exit;
end;
Result:=TvImageView.Create;
Result.FHandle:=FImg;
end;
function TvImage.NewViewF(Format:TVkFormat):TvImageView;
var
cinfo:TVkImageViewCreateInfo;
FImg:TVkImageView;
r:TVkResult;
begin
Result:=nil;
cinfo:=GetIVCInfo;
cinfo.image :=FHandle;
cinfo.format:=Format;
FImg:=VK_NULL_HANDLE;
r:=vkCreateImageView(Device.FHandle,@cinfo,nil,@FImg);
if (r<>VK_SUCCESS) then
begin
Writeln('vkCreateImageView:',r);
Exit;
end;
Result:=TvImageView.Create;
Result.FHandle:=FImg;
end;
Destructor TvImageView.Destroy;
begin
vkDestroyImageView(Device.FHandle,FHandle,nil);
end;
function TvHostImage2D.GetCInfo:TVkImageCreateInfo;
begin
Result:=Default(TVkImageCreateInfo);
Result.sType :=VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
Result.imageType :=VK_IMAGE_TYPE_2D;
Result.arrayLayers :=1;
Result.mipLevels :=1;
Result.initialLayout:=VK_IMAGE_LAYOUT_UNDEFINED;
Result.samples :=VK_SAMPLE_COUNT_1_BIT;
Result.tiling :=VK_IMAGE_TILING_LINEAR;
end;
//
function TvDeviceImage2D.GetCInfo:TVkImageCreateInfo;
begin
Result:=Default(TVkImageCreateInfo);
Result.sType :=VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
Result.imageType :=VK_IMAGE_TYPE_2D;
Result.arrayLayers :=1;
Result.mipLevels :=1;
Result.initialLayout:=VK_IMAGE_LAYOUT_UNDEFINED;
Result.samples :=VK_SAMPLE_COUNT_1_BIT;
Result.tiling :=VK_IMAGE_TILING_OPTIMAL;
end;
function TvDeviceImage2D.GetIVCInfo:TVkImageViewCreateInfo;
begin
Result:=Default(TVkImageViewCreateInfo);
Result.sType :=VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
Result.viewType :=VK_IMAGE_VIEW_TYPE_2D;
Result.format :=FFormat;
Result.components.r:=VK_COMPONENT_SWIZZLE_IDENTITY;
Result.components.g:=VK_COMPONENT_SWIZZLE_IDENTITY;
Result.components.b:=VK_COMPONENT_SWIZZLE_IDENTITY;
Result.components.a:=VK_COMPONENT_SWIZZLE_IDENTITY;
Case FFormat of
VK_FORMAT_S8_UINT:
Result.subresourceRange.aspectMask :=ord(VK_IMAGE_ASPECT_STENCIL_BIT);
VK_FORMAT_D16_UNORM,
VK_FORMAT_X8_D24_UNORM_PACK32,
VK_FORMAT_D32_SFLOAT:
Result.subresourceRange.aspectMask :=ord(VK_IMAGE_ASPECT_DEPTH_BIT);
VK_FORMAT_D16_UNORM_S8_UINT,
VK_FORMAT_D24_UNORM_S8_UINT,
VK_FORMAT_D32_SFLOAT_S8_UINT:
Result.subresourceRange.aspectMask :=ord(VK_IMAGE_ASPECT_DEPTH_BIT) or ord(VK_IMAGE_ASPECT_STENCIL_BIT);
else
Result.subresourceRange.aspectMask :=ord(VK_IMAGE_ASPECT_COLOR_BIT);
end;
Result.subresourceRange.baseMipLevel :=0;
Result.subresourceRange.levelCount :=1;
Result.subresourceRange.baseArrayLayer:=0;
Result.subresourceRange.layerCount :=1;
end;
Constructor TvBuffer.Create(size:TVkDeviceSize;usage:TVkFlags;ext:Pointer=nil);
var
cinfo:TVkBufferCreateInfo;
r:TVkResult;
begin
FSize:=size;
FUsage:=usage;
cinfo:=Default(TVkBufferCreateInfo);
cinfo.sType:=VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
cinfo.size :=size;
cinfo.usage:=usage;
cinfo.sharingMode:=VK_SHARING_MODE_EXCLUSIVE;
cinfo.pNext:=ext;
r:=vkCreateBuffer(Device.FHandle,@cinfo,nil,@FHandle);
if (r<>VK_SUCCESS) then
begin
Writeln('vkCreateBuffer:',r);
Exit;
end;
end;
Destructor TvBuffer.Destroy;
begin
vkDestroyBuffer(Device.FHandle,FHandle,nil);
end;
function TvBuffer.GetRequirements:TVkMemoryRequirements;
begin
Result:=Default(TVkMemoryRequirements);
vkGetBufferMemoryRequirements(Device.FHandle,FHandle,@Result);
end;
function TvBuffer.GetDedicatedAllocation:Boolean;
var
info:TVkBufferMemoryRequirementsInfo2;
rmem:TVkMemoryRequirements2;
rded:TVkMemoryDedicatedRequirements;
begin
Result:=false;
if Pointer(vkGetImageMemoryRequirements2)=nil then Exit;
info:=Default(TVkBufferMemoryRequirementsInfo2);
info.sType:=VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2;
info.buffer:=FHandle;
rmem:=Default(TVkMemoryRequirements2);
rmem.sType:=VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
rded:=Default(TVkMemoryDedicatedRequirements);
rded.sType:=VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;
rmem.pNext:=@rded;
vkGetBufferMemoryRequirements2(Device.FHandle,@info,@rmem);
Result:=(rded.requiresDedicatedAllocation<>VK_FALSE) or
(rded.prefersDedicatedAllocation <>VK_FALSE);
end;
function TvBuffer.BindMem(P:TvPointer):TVkResult;
begin
Result:=vkBindBufferMemory(Device.FHandle,FHandle,P.FHandle,P.FOffset);
end;
end.

593
vulkan/vMemory.pas Normal file
View File

@ -0,0 +1,593 @@
unit vMemory;
{$mode objfpc}{$H+}
interface
uses
bittype,
g23tree,
vulkan,
vDevice;
type
TvPointer=packed record
FHandle:TVkDeviceMemory;
FOffset:TVkDeviceSize;
end;
Const
GRANULAR_DEV_BLOCK_SIZE=128*1024*1024;
type
TDevNode=packed record
FSize :TVkDeviceSize;
FOffset :TVkDeviceSize;
FBlockId:Word;
FmType :Byte;
Fisfree :Boolean;
end;
TDevBlock=object
FHandle:TVkDeviceMemory;
nSize :TVkDeviceSize;
mType :Byte;
end;
//free: [FmType]|[FSize]|[FBlockId]
//alloc: [FBlockId]|[FOffset]
TFreeCompare=object
function c(const a,b:TDevNode):Integer; static;
end;
TAllcCompare=object
function c(const a,b:TDevNode):Integer; static;
end;
TFreeDevNodeSet=specialize T23treeSet<TDevNode,TFreeCompare>;
TAllcDevNodeSet=specialize T23treeSet<TDevNode,TAllcCompare>;
TvMemManager=class
FProperties:TVkPhysicalDeviceMemoryProperties;
FHostVisibMt:TVkUInt32;
FHostCacheMt:TVkUInt32;
lock:Pointer;
FDevBlocks:array of TDevBlock;
FFreeSet:TFreeDevNodeSet;
FAllcSet:TAllcDevNodeSet;
Constructor Create;
function findMemoryType(Filter:TVkUInt32;prop:TVkMemoryPropertyFlags):Integer;
procedure PrintMemoryType(typeFilter:TVkUInt32);
Function _AllcDevBlock(Size:TVkDeviceSize;mtindex:Byte;Var R:Word):Boolean;
Function _FreeDevBlock(i:Word):Boolean;
Function _FindDevBlock(FHandle:TVkDeviceMemory;Var R:Word):Boolean;
Function _FetchFree_a(Size,Align:TVkDeviceSize;mtindex:Byte;var R:TDevNode):Boolean;
Function _FetchFree_l(key:TDevNode;var R:TDevNode):Boolean;
Function _FetchFree_b(key:TDevNode;var R:TDevNode):Boolean;
Function _FetchAllc(FOffset:TVkDeviceSize;FBlockId:Word;var R:TDevNode):Boolean;
Function Alloc(const mr:TVkMemoryRequirements;pr:TVkMemoryPropertyFlags):TvPointer;
Function Alloc(Size,Align:TVkDeviceSize;mtindex:Byte):TvPointer;
Function Free(P:TvPointer):Boolean;
end;
var
MemManager:TvMemManager;
function vkAllocMemory(device:TVkDevice;Size:TVkDeviceSize;mtindex:TVkUInt32):TVkDeviceMemory;
function vkAllocHostPointer(device:TVkDevice;Size:TVkDeviceSize;mtindex:TVkUInt32;adr:Pointer):TVkDeviceMemory;
function vkAllocDedicatedImage(device:TVkDevice;Size:TVkDeviceSize;mtindex:TVkUInt32;FHandle:TVkImage):TVkDeviceMemory;
function vkAllocDedicatedBuffer(device:TVkDevice;Size:TVkDeviceSize;mtindex:TVkUInt32;FHandle:TVkBuffer):TVkDeviceMemory;
Function TryGetHostPointerByAddr(addr:Pointer;var P:TvPointer):Boolean;
implementation
uses
spinlock,
ps4_map_mm;
//free: [FmType]|[FSize]|[FBlockId]
function TFreeCompare.c(const a,b:TDevNode):Integer;
begin
if (a.FmType=b.FmType) then
begin
if (a.FSize=b.FSize) then
begin
if (a.FBlockId=b.FBlockId) then
Result:=0
else
if (a.FBlockId<b.FBlockId) then
Result:=-1
else
Result:=1;
end else
if (a.FSize<b.FSize) then
Result:=-1
else
Result:=1;
end else
if (a.FmType<b.FmType) then
Result:=-1
else
Result:=1;
end;
//alloc: [FBlockId]|[FOffset]
function TAllcCompare.c(const a,b:TDevNode):Integer;
begin
if (a.FBlockId=b.FBlockId) then
begin
if (a.FOffset=b.FOffset) then
Result:=0
else
if (a.FOffset<b.FOffset) then
Result:=-1
else
Result:=1;
end else
if (a.FBlockId<b.FBlockId) then
Result:=-1
else
Result:=1;
end;
Constructor TvMemManager.Create;
begin
FProperties:=Default(TVkPhysicalDeviceMemoryProperties);
vkGetPhysicalDeviceMemoryProperties(VulkanApp.FPhysicalDevice,@FProperties);
FHostVisibMt:=findMemoryType($FFFFFFFF,
ord(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) or
ord(VK_MEMORY_PROPERTY_HOST_COHERENT_BIT));
if (FHostVisibMt=DWORD(-1)) then
begin
FHostVisibMt:=findMemoryType($FFFFFFFF,
ord(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
end;
FHostCacheMt:=findMemoryType($FFFFFFFF,
ord(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) or
ord(VK_MEMORY_PROPERTY_HOST_CACHED_BIT));
if (FHostCacheMt=DWORD(-1)) then
begin
FHostCacheMt:=FHostVisibMt;
end;
end;
function TvMemManager.findMemoryType(Filter:TVkUInt32;prop:TVkMemoryPropertyFlags):Integer;
var
i:TVkUInt32;
begin
Result:=-1;
For i:=0 to FProperties.memoryTypeCount-1 do
begin
if ((Filter and (1 shl i))<>0) and ((FProperties.memoryTypes[i].propertyFlags and prop)=prop) then
begin
Exit(i);
end;
end;
end;
procedure TvMemManager.PrintMemoryType(typeFilter:TVkUInt32);
var
i:TVkUInt32;
begin
For i:=0 to FProperties.memoryTypeCount-1 do
begin
if ((typeFilter and (1 shl i))<>0) then
begin
Write(i,':',HexStr(FProperties.memoryTypes[i].propertyFlags,8));
if (FProperties.memoryTypes[i].propertyFlags and
TVkUInt32(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT))<>0 then
Write(' DEVICE_LOCAL');
if (FProperties.memoryTypes[i].propertyFlags and
TVkUInt32(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))<>0 then
Write(' HOST_VISIBLE');
if (FProperties.memoryTypes[i].propertyFlags and
TVkUInt32(VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))<>0 then
Write(' HOST_COHERENT');
if (FProperties.memoryTypes[i].propertyFlags and
TVkUInt32(VK_MEMORY_PROPERTY_HOST_CACHED_BIT))<>0 then
Write(' HOST_CACHED');
if (FProperties.memoryTypes[i].propertyFlags and
TVkUInt32(VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT))<>0 then
Write(' LAZILY_ALLOCATED');
if (FProperties.memoryTypes[i].propertyFlags and
TVkUInt32(VK_MEMORY_PROPERTY_PROTECTED_BIT))<>0 then
Write(' PROTECTED');
if (FProperties.memoryTypes[i].propertyFlags and
TVkUInt32(VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD))<>0 then
Write(' DEVICE_COHERENT_AMD');
if (FProperties.memoryTypes[i].propertyFlags and
TVkUInt32(VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD))<>0 then
Write(' DEVICE_UNCACHED_AMD');
if (FProperties.memoryTypes[i].propertyFlags and
TVkUInt32(VK_MEMORY_PROPERTY_RDMA_CAPABLE_BIT_NV))<>0 then
Write(' RDMA_CAPABLE_NV');
Writeln;
end;
end;
end;
Function TvMemManager._AllcDevBlock(Size:TVkDeviceSize;mtindex:Byte;Var R:Word):Boolean;
var
FHandle:TVkDeviceMemory;
i:Word;
begin
Result:=False;
FHandle:=vkAllocMemory(Device.FHandle,Size,mtindex);
if (FHandle=VK_NULL_HANDLE) then Exit;
if Length(FDevBlocks)<>0 then
For i:=0 to High(FDevBlocks) do
if (FDevBlocks[i].FHandle=VK_NULL_HANDLE) then
begin
FDevBlocks[i].FHandle:=FHandle;
FDevBlocks[i].nSize :=Size;
FDevBlocks[i].mType :=mtindex;
R:=i;
Exit(True);
end;
i:=Length(FDevBlocks);
SetLength(FDevBlocks,i+1);
FDevBlocks[i].FHandle:=FHandle;
FDevBlocks[i].nSize :=Size;
FDevBlocks[i].mType :=mtindex;
R:=i;
Result:=True;
end;
Function TvMemManager._FreeDevBlock(i:Word):Boolean;
var
c:Word;
begin
Result:=False;
if (i>=Length(FDevBlocks)) then Exit;
if (FDevBlocks[i].FHandle=VK_NULL_HANDLE) then Exit;
vkFreeMemory(Device.FHandle,FDevBlocks[i].FHandle,nil);
FDevBlocks[i].FHandle:=VK_NULL_HANDLE;
FDevBlocks[i].nSize :=0;
FDevBlocks[i].mType :=0;
Result:=True;
//shrink
c:=Length(FDevBlocks);
While (c<>0) do
if (FDevBlocks[c-1].FHandle=VK_NULL_HANDLE) then
Dec(c);
SetLength(FDevBlocks,c);
end;
Function TvMemManager._FindDevBlock(FHandle:TVkDeviceMemory;Var R:Word):Boolean;
var
i:Word;
begin
Result:=False;
if Length(FDevBlocks)<>0 then
For i:=0 to High(FDevBlocks) do
if (FDevBlocks[i].FHandle=FHandle) then
begin
R:=i;
Exit(True);
end;
end;
//free: [FmType]|[FSize]|[FBlockId]
Function TvMemManager._FetchFree_a(Size,Align:TVkDeviceSize;mtindex:Byte;var R:TDevNode):Boolean;
var
It:TFreeDevNodeSet.Iterator;
key:TDevNode;
Offset:TVkDeviceSize;
begin
Result:=false;
key:=Default(TDevNode);
key.FmType:=mtindex;
key.FSize:=Size;
It:=FFreeSet.find_be(key);
if (It.Item=nil) then Exit;
repeat
key:=It.Item^;
if (key.FmType<>mtindex) then Exit;
Offset:=System.Align(key.FOffset,Align);
if (Offset+Size)<=(key.FOffset+key.FSize) then
begin
R:=key;
FAllcSet.delete(key);
FFreeSet.erase(It);
Exit(True);
end;
until not It.Next;
end;
//alloc: [FBlockId]|[FOffset]
Function TvMemManager._FetchFree_l(key:TDevNode;var R:TDevNode):Boolean;
var
It:TFreeDevNodeSet.Iterator;
key2:TDevNode;
begin
Result:=false;
It:=FAllcSet.find_le(key);
if (It.Item=nil) then Exit;
key2:=It.Item^;
if (key2.FBlockId<>key.FBlockId) or
(key2.FmType <>key.FmType) or
(not key2.Fisfree) then Exit;
R:=key2;
FAllcSet.erase(It);
FFreeSet.delete(key2);
Result:=True;
end;
//alloc: [FBlockId]|[FOffset]
Function TvMemManager._FetchFree_b(key:TDevNode;var R:TDevNode):Boolean;
var
It:TFreeDevNodeSet.Iterator;
key2:TDevNode;
begin
Result:=false;
It:=FAllcSet.find_be(key);
if (It.Item=nil) then Exit;
key2:=It.Item^;
if (key2.FBlockId<>key.FBlockId) or
(key2.FmType <>key.FmType) or
(not key2.Fisfree) then Exit;
R:=key2;
FAllcSet.erase(It);
FFreeSet.delete(key2);
Result:=True;
end;
//alloc: [FBlockId]|[FOffset]
Function TvMemManager._FetchAllc(FOffset:TVkDeviceSize;FBlockId:Word;var R:TDevNode):Boolean;
var
It:TAllcDevNodeSet.Iterator;
key:TDevNode;
begin
Result:=False;
key:=Default(TDevNode);
key.FOffset :=FOffset;
key.FBlockId:=FBlockId;
It:=FAllcSet.find(key);
if (It.Item=nil) then Exit;
key:=It.Item^;
if key.Fisfree then Exit;
R:=key;
FAllcSet.erase(It);
Result:=True;
end;
//GRANULAR_DEV_BLOCK_SIZE
Function TvMemManager.Alloc(const mr:TVkMemoryRequirements;pr:TVkMemoryPropertyFlags):TvPointer;
var
mt:Integer;
begin
mt:=findMemoryType(mr.memoryTypeBits,pr);
if (mt=-1) then Exit(Default(TvPointer));
Result:=Alloc(mr.size,mr.alignment,mt);
end;
Function TvMemManager.Alloc(Size,Align:TVkDeviceSize;mtindex:Byte):TvPointer;
var
key:TDevNode;
Offset:TVkDeviceSize;
FSize:TVkDeviceSize;
FEndN,FEndO:TVkDeviceSize;
begin
Result:=Default(TvPointer);
if (Size=0) then Exit;
key:=Default(TDevNode);
Size:=System.Align(Size,8);
if (Align>GRANULAR_DEV_BLOCK_SIZE) then Align:=GRANULAR_DEV_BLOCK_SIZE;
spin_lock(lock);
if _FetchFree_a(Size,Align,mtindex,key) then
begin
Offset:=System.Align(key.FOffset,Align);
FSize:=key.FSize;
if (Offset<>key.FOffset) then //prev free save
begin
key.FSize:=Offset-key.FOffset;
FFreeSet.Insert(key);
FAllcSet.Insert(key);
end;
FEndN:=Offset+Size;
FEndO:=key.FOffset+FSize;
if (FEndN<>FEndO) then //next free save
begin
key.FOffset:=FEndN;
key.FSize :=FEndO-FEndN;
FFreeSet.Insert(key);
FAllcSet.Insert(key);
end;
//alloc save
key.Fisfree:=False;
key.FOffset:=Offset;
key.FSize :=Size;
FAllcSet.Insert(key);
Result.FHandle:=FDevBlocks[key.FBlockId].FHandle;
Result.FOffset:=key.FOffset;
end else
if _AllcDevBlock(System.Align(Size,GRANULAR_DEV_BLOCK_SIZE),mtindex,key.FBlockId) then
begin
//alloc save
key.Fisfree:=False;
key.FSize :=Size;
key.FOffset:=0;
key.FmType :=mtindex;
FAllcSet.Insert(key);
Result.FHandle:=FDevBlocks[key.FBlockId].FHandle;
Result.FOffset:=0;
//next free save
FSize:=FDevBlocks[key.FBlockId].nSize;
if (Size<>FSize) then
begin
key.Fisfree:=True;
key.FOffset:=Size;
key.FSize :=FSize-Size;
FFreeSet.Insert(key);
FAllcSet.Insert(key);
end;
end;
spin_unlock(lock);
end;
Function TvMemManager.Free(P:TvPointer):Boolean;
var
key,key2:TDevNode;
begin
if (P.FHandle=VK_NULL_HANDLE) then Exit;
key:=Default(TDevNode);
spin_lock(lock);
if _FindDevBlock(P.FHandle,key.FBlockId) then
if _FetchAllc(P.FOffset,key.FBlockId,key) then
begin
//prev union
repeat
if (key.FOffset=0) then Break;
key2:=key;
key2.FOffset:=key2.FOffset-1;
if not _FetchFree_l(key2,key2) then Break;
Assert((key2.FOffset+key2.FSize)=key.FOffset);
key.FSize :=key.FSize+(key.FOffset-key2.FOffset);
key.FOffset:=key2.FOffset;
until false;
//next union
repeat
key2:=key;
key2.FOffset:=key2.FOffset+key2.FSize;
if not _FetchFree_b(key2,key2) then Break;
Assert((key.FOffset+key.FSize)=key2.FOffset);
key.FSize :=key.FSize+key2.FSize;
until false;
//
if (key.FOffset=0) and (key.FSize>=FDevBlocks[key.FBlockId].nSize) then
begin
//free block
_FreeDevBlock(key.FBlockId);
end else
begin
//add free
key.Fisfree:=True;
FFreeSet.Insert(key);
FAllcSet.Insert(key);
end;
Result:=True;
end;
spin_unlock(lock);
end;
function vkAllocMemory(device:TVkDevice;Size:TVkDeviceSize;mtindex:TVkUInt32):TVkDeviceMemory;
var
ainfo:TVkMemoryAllocateInfo;
begin
ainfo:=Default(TVkMemoryAllocateInfo);
ainfo.sType :=VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
ainfo.allocationSize :=Size;
ainfo.memoryTypeIndex:=mtindex;
Result:=VK_NULL_HANDLE;
vkAllocateMemory(device,@ainfo,nil,@Result);
end;
function vkAllocHostPointer(device:TVkDevice;Size:TVkDeviceSize;mtindex:TVkUInt32;adr:Pointer):TVkDeviceMemory;
var
ainfo:TVkMemoryAllocateInfo;
import:TVkImportMemoryHostPointerInfoEXT;
begin
ainfo:=Default(TVkMemoryAllocateInfo);
ainfo.sType :=VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
ainfo.allocationSize :=Size;
ainfo.memoryTypeIndex:=mtindex;
ainfo.pNext:=@import;
import:=Default(TVkImportMemoryHostPointerInfoEXT);
import.sType:=VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT;
import.handleType:=VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT;
import.pHostPointer:=adr;
Result:=VK_NULL_HANDLE;
vkAllocateMemory(device,@ainfo,nil,@Result);
end;
function vkAllocDedicatedImage(device:TVkDevice;Size:TVkDeviceSize;mtindex:TVkUInt32;FHandle:TVkImage):TVkDeviceMemory;
var
ainfo:TVkMemoryAllocateInfo;
dinfo:TVkMemoryDedicatedAllocateInfo;
begin
ainfo:=Default(TVkMemoryAllocateInfo);
ainfo.sType :=VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
ainfo.allocationSize :=Size;
ainfo.memoryTypeIndex:=mtindex;
ainfo.pNext:=@dinfo;
dinfo:=Default(TVkMemoryDedicatedAllocateInfo);
dinfo.sType:=VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
dinfo.image:=FHandle;
Result:=VK_NULL_HANDLE;
vkAllocateMemory(device,@ainfo,nil,@Result);
end;
function vkAllocDedicatedBuffer(device:TVkDevice;Size:TVkDeviceSize;mtindex:TVkUInt32;FHandle:TVkBuffer):TVkDeviceMemory;
var
ainfo:TVkMemoryAllocateInfo;
dinfo:TVkMemoryDedicatedAllocateInfo;
begin
ainfo:=Default(TVkMemoryAllocateInfo);
ainfo.sType :=VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
ainfo.allocationSize :=Size;
ainfo.memoryTypeIndex:=mtindex;
ainfo.pNext:=@dinfo;
dinfo:=Default(TVkMemoryDedicatedAllocateInfo);
dinfo.sType:=VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
dinfo.buffer:=FHandle;
Result:=VK_NULL_HANDLE;
vkAllocateMemory(device,@ainfo,nil,@Result);
end;
function OnGpuMemAlloc(addr:Pointer;len:size_t):TVkDeviceMemory;
begin
InitVulkan;
Result:=vkAllocHostPointer(Device.FHandle,len,MemManager.FHostCacheMt,addr);
Assert(Result<>VK_NULL_HANDLE);
end;
procedure OnGpuMemFree(h:TVkDeviceMemory);
begin
if (h=VK_NULL_HANDLE) then Exit;
if not IsInitVulkan then Exit;
vkFreeMemory(Device.FHandle,h,nil);
end;
Function TryGetHostPointerByAddr(addr:Pointer;var P:TvPointer):Boolean;
var
block:TGpuMemBlock;
begin
Result:=False;
if TryGetGpuMemBlockByAddr(addr,block) then
begin
P.FHandle:=TVkDeviceMemory(block.Handle);
P.FOffset:=addr-block.pAddr;
Result:=True;
end;
end;
initialization
GpuMemCb.Alloc:=TGpuMemAlloc(@OnGpuMemAlloc);
GpuMemCb.Free :=TGpuMemFree (@OnGpuMemFree);
end.

717
vulkan/vPipeline.pas Normal file
View File

@ -0,0 +1,717 @@
unit vPipeline;
{$mode objfpc}{$H+}
interface
uses
g23tree,
vulkan,vDevice,vShader;
type
TvSetLayout=class
FHandle:TVkDescriptorSetLayout;
FEdit,FCompile:ptruint;
FBinds:array of TVkDescriptorSetLayoutBinding;
Destructor Destroy; override;
Procedure Add(aBind:TVkUInt32;dType:TVkDescriptorType;Flags:TVkShaderStageFlags;count:TVkUInt32=1);
procedure Clear;
function Compile:Boolean;
function IsEdit:Boolean;
end;
TvPipelineLayout=class
FHandle:TVkPipelineLayout;
FEdit,FCompile:ptruint;
FLayouts:array of TvSetLayout;
FPushConsts:array of TVkPushConstantRange;
Destructor Destroy; override;
Procedure Add(F:TvSetLayout);
Procedure AddPushConst(offset,size:TVkUInt32;Flags:TVkShaderStageFlags);
procedure Clear;
function Compile:Boolean;
function IsEdit:Boolean;
end;
TvPipeline=class
FHandle:TVkPipeline;
FEdit,FCompile:ptruint;
Destructor Destroy; override;
end;
TvRenderPass=class
FHandle:TVkRenderPass;
Destructor Destroy; override;
end;
TvComputePipeline=class(TvPipeline)
FLayout:TvPipelineLayout;
FComputeShader:TvShader;
procedure SetLayout(Layout:TvPipelineLayout);
Procedure SetShader(Shader:TvShader);
function Compile:Boolean;
function IsEdit:Boolean;
end;
TvSetsPool=class;
TvDescriptorSet=class
FParent:TvSetsPool;
FLayout:TvSetLayout;
FHandle:TVkDescriptorSet;
procedure _AllocDesc;
procedure _FreeDesc;
Destructor Destroy; override;
Procedure BindUB (aBind,aElem:TVkUInt32;const buf:TVkDescriptorBufferInfo);
Procedure BindSB (aBind,aElem:TVkUInt32;const buf:TVkDescriptorBufferInfo);
Procedure BindUBD(aBind,aElem:TVkUInt32;const buf:TVkDescriptorBufferInfo);
Procedure BindSBD(aBind,aElem:TVkUInt32;const buf:TVkDescriptorBufferInfo);
Procedure BindSTI(aBind,aElem:TVkUInt32;const img:TVkImageView);
end;
_TvSetLayoutKey=object
Layout:TvSetLayout;
fcount:TVkUInt32;
function c(const a,b:_TvSetLayoutKey):Integer; static;
end;
_TvSetLayoutSet=specialize T23treeSet<_TvSetLayoutKey,_TvSetLayoutKey>;
_TvDescriptorSetCompare=object
function c(const a,b:TvDescriptorSet):Integer; static;
end;
_TvDescriptorSetSet=specialize T23treeSet<TvDescriptorSet,_TvDescriptorSetCompare>;
TvSetsPool=class
FHandle:TVkDescriptorPool;
FEdit,FCompile:ptruint;
FmaxSets:TVkUInt32;
FLayouts:_TvSetLayoutSet;
FSets:_TvDescriptorSetSet;
Destructor Destroy; override;
function _FindLayout(L:TvSetLayout):Boolean;
procedure ClearLayouts;
Procedure AddLayout(L:TvSetLayout;count:TVkUInt32=1);
Procedure AddFormPipelineLayout(L:TvPipelineLayout;count:TVkUInt32=1);
function Alloc(L:TvSetLayout):TvDescriptorSet;
function Compile:Boolean;
function IsEdit:Boolean;
end;
implementation
function _TvSetLayoutKey.c(const a,b:_TvSetLayoutKey):Integer;
begin
Result:=CompareByte(a.Layout,b.Layout,SizeOf(TvSetLayout));
end;
function _TvDescriptorSetCompare.c(const a,b:TvDescriptorSet):Integer;
begin
Result:=CompareByte(a,b,SizeOf(TvDescriptorSet));
end;
Procedure TvSetLayout.Add(aBind:TVkUInt32;dType:TVkDescriptorType;Flags:TVkShaderStageFlags;count:TVkUInt32=1);
var
i:Integer;
begin
i:=Length(FBinds);
SetLength(FBinds,i+1);
FBinds[i]:=Default(TVkDescriptorSetLayoutBinding);
FBinds[i].binding:=aBind;
FBinds[i].descriptorType:=dType;
FBinds[i].descriptorCount:=count;
FBinds[i].stageFlags:=Flags;
Inc(FEdit);
end;
Procedure TvSetLayout.Clear;
begin
SetLength(FBinds,0);
Inc(FEdit);
end;
function TvSetLayout.Compile:Boolean;
var
cinfo:TVkDescriptorSetLayoutCreateInfo;
r:TVkResult;
begin
Result:=False;
if (FHandle<>VK_NULL_HANDLE) then
begin
if (FEdit=FCompile) then Exit(true);
vkDestroyDescriptorSetLayout(Device.FHandle,FHandle,nil);
FHandle:=VK_NULL_HANDLE;
end;
cinfo:=Default(TVkDescriptorSetLayoutCreateInfo);
cinfo.sType:=VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
cinfo.bindingCount:=Length(FBinds);
if (cinfo.bindingCount<>0) then
begin
cinfo.pBindings:=@FBinds[0];
end;
r:=vkCreateDescriptorSetLayout(Device.FHandle,@cinfo,nil,@FHandle);
if (r<>VK_SUCCESS) then
begin
Writeln('vkCreateDescriptorSetLayout:',r);
Exit;
end;
FCompile:=FEdit;
Result:=True;
end;
Destructor TvSetLayout.Destroy;
begin
if (FHandle<>VK_NULL_HANDLE) then
vkDestroyDescriptorSetLayout(Device.FHandle,FHandle,nil);
end;
function TvSetLayout.IsEdit:Boolean;
begin
Result:=FEdit<>FCompile;
end;
Destructor TvPipelineLayout.Destroy;
begin
if (FHandle<>VK_NULL_HANDLE) then
vkDestroyPipelineLayout(Device.FHandle,FHandle,nil);
end;
Procedure TvPipelineLayout.Add(F:TvSetLayout);
var
i:Integer;
begin
if (F=nil) then Exit;
i:=Length(FLayouts);
SetLength(FLayouts,i+1);
FLayouts[i]:=F;
Inc(FEdit);
end;
Procedure TvPipelineLayout.AddPushConst(offset,size:TVkUInt32;Flags:TVkShaderStageFlags);
var
i:Integer;
begin
i:=Length(FPushConsts);
SetLength(FPushConsts,i+1);
FPushConsts[i].stageFlags:=Flags;
FPushConsts[i].offset :=offset;
FPushConsts[i].size :=size;
Inc(FEdit);
end;
procedure TvPipelineLayout.Clear;
begin
SetLength(FLayouts,0);
SetLength(FPushConsts,0);
Inc(FEdit);
end;
function TvPipelineLayout.Compile:Boolean;
var
cinfo:TVkPipelineLayoutCreateInfo;
r:TVkResult;
_data_set:array of TVkDescriptorSetLayout;
i:Integer;
begin
Result:=false;
if (FHandle<>VK_NULL_HANDLE) then
begin
if (not IsEdit) then Exit(true);
vkDestroyPipelineLayout(Device.FHandle,FHandle,nil);
FHandle:=VK_NULL_HANDLE;
end;
if (Length(FLayouts)<>0) then
begin
_data_set:=nil;
SetLength(_data_set,Length(FLayouts));
For i:=0 to High(FLayouts) do
begin
if not FLayouts[i].Compile then Exit;
_data_set[i]:=FLayouts[i].FHandle;
end;
end;
cinfo:=Default(TVkPipelineLayoutCreateInfo);
cinfo.sType :=VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
cinfo.setLayoutCount:=Length(_data_set);
if (cinfo.setLayoutCount<>0) then
begin
cinfo.pSetLayouts:=@_data_set[0];
end;
cinfo.pushConstantRangeCount:=Length(FPushConsts);
if (cinfo.pushConstantRangeCount<>0) then
begin
cinfo.pPushConstantRanges:=@FPushConsts[0];
end;
r:=vkCreatePipelineLayout(Device.FHandle,@cinfo,nil,@FHandle);
if (r<>VK_SUCCESS) then
begin
Writeln('vkCreatePipelineLayout:',r);
Exit;
end;
FCompile:=FEdit;
Result:=True;
end;
function TvPipelineLayout.IsEdit:Boolean;
var
i:Integer;
begin
Result:=FEdit<>FCompile;
if not Result then
if (Length(FLayouts)<>0) then
For i:=0 to High(FLayouts) do
if FLayouts[i].IsEdit then Exit(true);
end;
Destructor TvPipeline.Destroy;
begin
if (FHandle<>VK_NULL_HANDLE) then
vkDestroyPipeline(Device.FHandle,FHandle,nil);
end;
Destructor TvRenderPass.Destroy;
begin
if (FHandle<>VK_NULL_HANDLE) then
vkDestroyRenderPass(Device.FHandle,FHandle,nil);
end;
procedure TvComputePipeline.SetLayout(Layout:TvPipelineLayout);
begin
if (FLayout<>Layout) then
begin
Inc(FEdit);
FLayout:=Layout;
Compile;
end;
end;
Procedure TvComputePipeline.SetShader(Shader:TvShader);
begin
if (FComputeShader<>Shader) then
begin
Inc(FEdit);
if (Shader=nil) then
begin
FComputeShader:=nil;
end else
if (Shader.FStage=VK_SHADER_STAGE_COMPUTE_BIT) then
begin
FComputeShader:=Shader;
Compile;
end;
end;
end;
function TvComputePipeline.Compile:Boolean;
var
cinfo:TVkComputePipelineCreateInfo;
r:TVkResult;
begin
Result:=False;
if (FLayout=nil) or (FComputeShader=nil) then Exit;
if (FHandle<>VK_NULL_HANDLE) then
begin
if (not IsEdit) then Exit(true);
vkDestroyPipeline(Device.FHandle,FHandle,nil);
FHandle:=VK_NULL_HANDLE;
end;
if not FLayout.Compile then Exit;
cinfo:=Default(TVkComputePipelineCreateInfo);
cinfo.sType:=VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
cinfo.stage.sType:=VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
cinfo.stage.stage:=VK_SHADER_STAGE_COMPUTE_BIT;
cinfo.stage.module:=FComputeShader.FHandle;
cinfo.stage.pName:=PChar(FComputeShader.FEntry);
cinfo.layout:=FLayout.FHandle;
r:=vkCreateComputePipelines(Device.FHandle,VK_NULL_HANDLE,1,@cinfo,nil,@FHandle);
if (r<>VK_SUCCESS) then
begin
Writeln('vkCreateComputePipelines:',r);
Exit;
end;
FCompile:=FEdit;
Result:=True;
end;
function TvComputePipeline.IsEdit:Boolean;
begin
Result:=(FEdit<>FCompile);
if (not Result) and (FLayout<>nil) then
Result:=Result or FLayout.IsEdit;
end;
Destructor TvSetsPool.Destroy;
var
It:_TvDescriptorSetSet.Iterator;
begin
It:=FSets.cbegin;
if (It.Item<>nil) then
repeat
It.Item^.FHandle:=VK_NULL_HANDLE;
until not It.Next;
if (FHandle<>VK_NULL_HANDLE) then
vkDestroyDescriptorPool(Device.FHandle,FHandle,nil);
FSets.Free;
FLayouts.Free;
end;
function _GetTypeById(i:Byte):TVkDescriptorType;
begin
Result:=VK_DESCRIPTOR_TYPE_SAMPLER;
Case i of
0:Result:=VK_DESCRIPTOR_TYPE_SAMPLER ;
1:Result:=VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ;
2:Result:=VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ;
3:Result:=VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ;
4:Result:=VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ;
5:Result:=VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER ;
6:Result:=VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ;
7:Result:=VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ;
8:Result:=VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ;
9:Result:=VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC ;
10:Result:=VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT ;
11:Result:=VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT ;
12:Result:=VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
13:Result:=VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV ;
14:Result:=VK_DESCRIPTOR_TYPE_MUTABLE_VALVE ;
end;
end;
function _GetIdByType(i:TVkDescriptorType):Byte;
begin
Result:=0;
Case i of
VK_DESCRIPTOR_TYPE_SAMPLER :Result:=0;
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER :Result:=1;
VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE :Result:=2;
VK_DESCRIPTOR_TYPE_STORAGE_IMAGE :Result:=3;
VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER :Result:=4;
VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER :Result:=5;
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER :Result:=6;
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER :Result:=7;
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC :Result:=8;
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC :Result:=9;
VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT :Result:=10;
VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT :Result:=11;
VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:Result:=12;
VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV :Result:=13;
VK_DESCRIPTOR_TYPE_MUTABLE_VALVE :Result:=14;
end;
end;
function TvSetsPool.Compile:Boolean;
var
i,b,L:Integer;
It:_TvSetLayoutSet.Iterator;
Ik:_TvSetLayoutKey;
Id:_TvDescriptorSetSet.Iterator;
FCounts:array[0..14] of TVkUInt32;
FSize:array of TVkDescriptorPoolSize;
cinfo:TVkDescriptorPoolCreateInfo;
r:TVkResult;
begin
Result:=False;
if (FHandle<>VK_NULL_HANDLE) and (not IsEdit) then Exit(true);
if (FLayouts.Size=0) then Exit;
FSize:=nil;
FmaxSets:=0;
FillChar(FCounts,SizeOf(FCounts),0);
It:=FLayouts.cbegin;
repeat
Ik:=It.Item^;
if (Ik.Layout<>nil) and (Ik.fcount<>0) then
if (Length(Ik.Layout.FBinds)<>0) then
begin
FmaxSets:=FmaxSets+Ik.fcount;
For i:=0 to Ik.fcount-1 do
For b:=0 to High(Ik.Layout.FBinds) do
with Ik.Layout.FBinds[b] do
begin
Inc(FCounts[_GetIdByType(descriptorType)],descriptorCount);
end;
end;
until not It.Next;
For i:=0 to 14 do
if (FCounts[i]<>0) then
begin
L:=Length(FSize);
SetLength(FSize,L+1);
FSize[L].type_:=_GetTypeById(i);
FSize[L].descriptorCount:=FCounts[i];
end;
if (Length(FSize)=0) then Exit;
Id:=FSets.cbegin;
if (Id.Item<>nil) then
repeat
Id.Item^.FHandle:=VK_NULL_HANDLE;
until not Id.Next;
if (FHandle<>VK_NULL_HANDLE) then
begin
vkDestroyDescriptorPool(Device.FHandle,FHandle,nil);
FHandle:=VK_NULL_HANDLE;
end;
It:=FLayouts.cbegin;
repeat
Ik:=It.Item^;
if (Ik.Layout<>nil) and (Ik.fcount<>0) then
begin
if not Ik.Layout.Compile then Exit;
end;
until not It.Next;
cinfo:=Default(TVkDescriptorPoolCreateInfo);
cinfo.sType :=VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
cinfo.poolSizeCount:=Length(FSize);
cinfo.pPoolSizes :=@FSize[0];
cinfo.maxSets :=FmaxSets;
r:=vkCreateDescriptorPool(Device.FHandle,@cinfo,nil,@FHandle);
if (r<>VK_SUCCESS) then
begin
Writeln('vkCreateDescriptorPool:',r);
Exit;
end;
i:=0;
Id:=FSets.cbegin;
if (Id.Item<>nil) then
repeat
Id.Item^._AllocDesc;
Inc(i);
if (i>=FmaxSets) then Break;
until not Id.Next;
FCompile:=FEdit;
Result:=True;
end;
function TvSetsPool.IsEdit:Boolean;
var
It:_TvSetLayoutSet.Iterator;
Ik:_TvSetLayoutKey;
begin
Result:=False;
if (FEdit<>FCompile) then Exit(True);
It:=FLayouts.cbegin;
if (It.Item=nil) then Exit;
repeat
Ik:=It.Item^;
if (Ik.Layout<>nil) and (Ik.fcount<>0) then
if Ik.Layout.IsEdit then Exit(True);
until not It.Next;
end;
procedure TvSetsPool.ClearLayouts;
begin
FLayouts.Free;
Inc(FEdit);
end;
function TvSetsPool._FindLayout(L:TvSetLayout):Boolean;
var
Ik:_TvSetLayoutKey;
begin
Ik.Layout:=L;
Ik.fcount:=0;
Result:=FLayouts.Contains(Ik);
end;
Procedure TvSetsPool.AddLayout(L:TvSetLayout;count:TVkUInt32);
var
It:_TvSetLayoutSet.Iterator;
Ik:_TvSetLayoutKey;
begin
if (L=nil) then Exit;
if (count=0) then count:=1;
Ik.Layout:=L;
Ik.fcount:=count;
It:=FLayouts.find(Ik);
if (It.Item<>nil) then
begin
It.Item^.fcount:=It.Item^.fcount+count;
end else
begin
FLayouts.Insert(Ik);
end;
Inc(FEdit);
end;
Procedure TvSetsPool.AddFormPipelineLayout(L:TvPipelineLayout;count:TVkUInt32);
var
i:Integer;
begin
if (L=nil) then Exit;
if (Length(L.FLayouts)<>0) then
For i:=0 to High(L.FLayouts) do
begin
AddLayout(L.FLayouts[i],count);
end;
end;
function TvSetsPool.Alloc(L:TvSetLayout):TvDescriptorSet;
var
ainfo:TVkDescriptorSetAllocateInfo;
FResult:TVkDescriptorSet;
r:TVkResult;
begin
Result:=nil;
if (L=nil) then Exit;
if not _FindLayout(L) then Exit;
if not Compile then Exit;
if (FSets.Size>=FmaxSets) then Exit;
ainfo:=Default(TVkDescriptorSetAllocateInfo);
ainfo.sType :=VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
ainfo.descriptorPool :=FHandle;
ainfo.descriptorSetCount:=1;
ainfo.pSetLayouts:=@L.FHandle;
r:=vkAllocateDescriptorSets(Device.FHandle,@ainfo,@FResult);
if (r<>VK_SUCCESS) then
begin
Writeln('vkAllocateDescriptorSets:',r);
Exit;
end;
Result:=TvDescriptorSet.Create;
Result.FParent:=Self;
Result.FLayout:=L;
Result.FHandle:=FResult;
FSets.Insert(Result);
end;
procedure TvDescriptorSet._AllocDesc;
var
ainfo:TVkDescriptorSetAllocateInfo;
r:TVkResult;
begin
if (FParent<>nil) and (FLayout<>nil) then
if (FHandle=VK_NULL_HANDLE) and
(FParent.FHandle<>VK_NULL_HANDLE) then
begin
ainfo:=Default(TVkDescriptorSetAllocateInfo);
ainfo.sType :=VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
ainfo.descriptorPool :=FParent.FHandle;
ainfo.descriptorSetCount:=1;
ainfo.pSetLayouts:=@FLayout.FHandle;
r:=vkAllocateDescriptorSets(Device.FHandle,@ainfo,@FHandle);
if (r<>VK_SUCCESS) then
begin
Writeln('vkAllocateDescriptorSets:',r);
Exit;
end;
end;
end;
procedure TvDescriptorSet._FreeDesc;
var
r:TVkResult;
begin
if (FParent<>nil) then
if (FHandle<>VK_NULL_HANDLE) and
(FParent.FHandle<>VK_NULL_HANDLE) then
begin
r:=vkFreeDescriptorSets(Device.FHandle,FParent.FHandle,1,@FHandle);
if (r<>VK_SUCCESS) then
begin
Writeln('vkFreeDescriptorSets:',r);
end;
end;
FHandle:=VK_NULL_HANDLE;
end;
Destructor TvDescriptorSet.Destroy;
begin
if (FParent<>nil) then
begin
_FreeDesc;
FParent.FSets.delete(Self);
end;
inherited;
end;
Procedure TvDescriptorSet.BindUB(aBind,aElem:TVkUInt32;const buf:TVkDescriptorBufferInfo);
var
dwrite:TVkWriteDescriptorSet;
begin
dwrite:=Default(TVkWriteDescriptorSet);
dwrite.sType :=VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
dwrite.dstSet :=FHandle;
dwrite.dstBinding :=aBind;
dwrite.dstArrayElement:=aElem;
dwrite.descriptorType :=VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
dwrite.descriptorCount:=1;
dwrite.pBufferInfo :=@buf;
vkUpdateDescriptorSets(Device.FHandle,1,@dwrite,0,nil);
end;
Procedure TvDescriptorSet.BindSB(aBind,aElem:TVkUInt32;const buf:TVkDescriptorBufferInfo);
var
dwrite:TVkWriteDescriptorSet;
begin
dwrite:=Default(TVkWriteDescriptorSet);
dwrite.sType :=VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
dwrite.dstSet :=FHandle;
dwrite.dstBinding :=aBind;
dwrite.dstArrayElement:=aElem;
dwrite.descriptorType :=VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
dwrite.descriptorCount:=1;
dwrite.pBufferInfo :=@buf;
vkUpdateDescriptorSets(Device.FHandle,1,@dwrite,0,nil);
end;
Procedure TvDescriptorSet.BindUBD(aBind,aElem:TVkUInt32;const buf:TVkDescriptorBufferInfo);
var
dwrite:TVkWriteDescriptorSet;
begin
dwrite:=Default(TVkWriteDescriptorSet);
dwrite.sType :=VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
dwrite.dstSet :=FHandle;
dwrite.dstBinding :=aBind;
dwrite.dstArrayElement:=aElem;
dwrite.descriptorType :=VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
dwrite.descriptorCount:=1;
dwrite.pBufferInfo :=@buf;
vkUpdateDescriptorSets(Device.FHandle,1,@dwrite,0,nil);
end;
Procedure TvDescriptorSet.BindSBD(aBind,aElem:TVkUInt32;const buf:TVkDescriptorBufferInfo);
var
dwrite:TVkWriteDescriptorSet;
begin
dwrite:=Default(TVkWriteDescriptorSet);
dwrite.sType :=VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
dwrite.dstSet :=FHandle;
dwrite.dstBinding :=aBind;
dwrite.dstArrayElement:=aElem;
dwrite.descriptorType :=VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
dwrite.descriptorCount:=1;
dwrite.pBufferInfo :=@buf;
vkUpdateDescriptorSets(Device.FHandle,1,@dwrite,0,nil);
end;
Procedure TvDescriptorSet.BindSTI(aBind,aElem:TVkUInt32;const img:TVkImageView);
var
dwrite:TVkWriteDescriptorSet;
dimg:TVkDescriptorImageInfo;
begin
dimg:=Default(TVkDescriptorImageInfo);
dimg.imageView:=img;
dimg.imageLayout:=VK_IMAGE_LAYOUT_GENERAL;
dwrite:=Default(TVkWriteDescriptorSet);
dwrite.sType :=VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
dwrite.dstSet :=FHandle;
dwrite.dstBinding :=aBind;
dwrite.dstArrayElement:=aElem;
dwrite.descriptorType :=VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
dwrite.descriptorCount:=1;
dwrite.pImageInfo :=@dimg;
vkUpdateDescriptorSets(Device.FHandle,1,@dwrite,0,nil);
end;
end.

983
vulkan/vRender.pas Normal file
View File

@ -0,0 +1,983 @@
unit vRender;
{$mode objfpc}{$H+}
interface
uses
Classes,
SysUtils,
ps4_types,
g23tree,
ps4_libSceVideoOut,
si_ci_vi_merged_enum,
vulkan,
vDevice,
vMemory,
vShader,
vPipeline,
vImage;
type
TvRenderPass=class(vPipeline.TvRenderPass)
AtCount:TVkUInt32;
ColorAt:array[0..8] of TVkAttachmentDescription;
ColorRef:array[0..7] of TVkAttachmentReference; //subpass.colorAttachmentCount
pDepthStencilRef:TVkAttachmentReference;
subpass:TVkSubpassDescription;
dependency:TVkSubpassDependency;
Procedure Clear;
Procedure SetZorderStage(s:TVkPipelineStageFlagBits);
Procedure AddColorRef(id:TVkUInt32);
Procedure SetDepthStencilRef(id:TVkUInt32);
Procedure AddColorAt(format:TVkFormat;ClearColor,DrawColor:Boolean);
Procedure AddDepthAt(format:TVkFormat;ClearDepth,DrawDepth,ClearStencil,DrawStencil:Boolean);
Function Compile:Boolean;
end;
TvGraphicsPipeline=class(TvPipeline)
FLayout:TvPipelineLayout;
FRenderPass:TvRenderPass;
Viewports:array[0..15] of TVkViewport; //viewportState.viewportCount
Scissors :array[0..15] of TVkRect2D; //viewportState.scissorCount
ColorBlends:array[0..7] of TVkPipelineColorBlendAttachmentState; //colorBlending.attachmentCount
FShaders:array[0..5] of TvShader;
dynamicStates:array[0..1] of TVkDynamicState; //dynamicState.dynamicStateCount
vertexInputInfo:TVkPipelineVertexInputStateCreateInfo;
inputAssembly:TVkPipelineInputAssemblyStateCreateInfo;
viewportState:TVkPipelineViewportStateCreateInfo;
rasterizer:TVkPipelineRasterizationStateCreateInfo;
multisampling:TVkPipelineMultisampleStateCreateInfo;
colorBlending:TVkPipelineColorBlendStateCreateInfo;
DepthStencil:TVkPipelineDepthStencilStateCreateInfo;
dynamicState:TVkPipelineDynamicStateCreateInfo;
emulate_primtype:TVkPrimitiveTopology;
Procedure SetPrimType(t:TVkPrimitiveTopology);
Procedure AddVPort(const V:TVkViewport;const S:TVkRect2D);
Procedure AddBlend(const b:TVkPipelineColorBlendAttachmentState);
Procedure Clear;
Procedure SetLSShader(Shader:TvShader);
Procedure SetHSShader(Shader:TvShader);
Procedure SetESShader(Shader:TvShader);
Procedure SetGSShader(Shader:TvShader);
Procedure SetVSShader(Shader:TvShader);
Procedure SetPSShader(Shader:TvShader);
procedure SetLayout(Layout:TvPipelineLayout);
procedure SetRenderPass(RenderPass:TvRenderPass);
function Compile:Boolean;
end;
TvRenderTargets=class
FRenderPass:TvRenderPass;
FPipeline:TvGraphicsPipeline;
FFramebuffer:TvFramebuffer;
FRenderArea:TVkRect2D;
FClearValuesCount:TVkUInt32;
FClearValues:array[0..8] of TVkClearValue;
Procedure AddClearColor(clr:TVkClearValue);
class function c(const a,b:TvRenderTargets):Integer;
Destructor Destroy; override;
end;
TvRenderTargetsSet=specialize T23treeSet<TvRenderTargets,TvRenderTargets>;
TvCmdBuffer=class
cmdbuf:TVkCommandBuffer;
FRenderTargets:TvRenderTargets;
FRenderList:TvRenderTargetsSet;
FWaitSemaphore:TvSemaphore;
FSignSemaphore:TvSemaphore;
FSignFence:TvFence;
FCBState:Boolean;
function BeginCmdBuffer:Boolean;
Procedure EndCmdBuffer;
function BeginRenderPass(RT:TvRenderTargets):Boolean;
Procedure EndRenderPass;
Procedure QueueSubmit;
Procedure ClearRenderList;
Procedure DrawIndex2(Addr:Pointer;INDICES:DWORD;INDEX_TYPE:TVkIndexType);
Procedure DrawIndexAuto(INDICES:DWORD;INDEX_TYPE:TVkIndexType);
end;
TUnionResource=class
Addr:Pointer;
host:TvPointer;
end;
TUnionResourceBuffer=class(TUnionResource)
FHostBuf:TvBuffer;
Foffset:TVkDeviceSize; //offset inside buffer
Destructor Destroy; override;
end;
TUnionResourceImage=class(TUnionResource)
FImage:TvDeviceImage2D;
devc:TvPointer;
Destructor Destroy; override;
end;
function FindHostBuffer(Addr:Pointer):TUnionResourceBuffer;
function FetchHostBuffer(Addr:Pointer;Size:TVkDeviceSize;usage:TVkFlags):TUnionResourceBuffer;
function FindUnionImage2D(Addr:Pointer):TUnionResourceImage;
function FetchUnionImage2D(Addr:Pointer;cformat:TVkFormat;extend:TVkExtent2D;usage:TVkFlags):TUnionResourceImage;
implementation
//lock res TODO
type
TUnionResourceCompare=object
function c(const a,b:TUnionResource):Integer; static;
end;
TUnionResourceSet=specialize T23treeSet<TUnionResource,TUnionResourceCompare>;
var
FUnionBuffer:TUnionResourceSet;
FUnionImages2D:TUnionResourceSet;
function FindHostBuffer(Addr:Pointer):TUnionResourceBuffer;
var
i:TUnionResourceSet.Iterator;
t:TUnionResourceBuffer;
begin
Result:=nil;
t:=TUnionResourceBuffer.Create;
t.Addr:=Addr;
i:=FUnionBuffer.find(t);
if (i.Item<>nil) then
begin
Result:=TUnionResourceBuffer(i.Item^);
end;
FreeAndNil(t);
end;
function FetchHostBuffer(Addr:Pointer;Size:TVkDeviceSize;usage:TVkFlags):TUnionResourceBuffer;
const
buf_ext:TVkExternalMemoryBufferCreateInfo=(
sType:VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
pNext:nil;
handleTypes:ord(VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT);
);
var
i:TUnionResourceSet.Iterator;
t:TUnionResourceBuffer;
host:TvPointer;
procedure _init;
var
mr:TVkMemoryRequirements;
p:TVkDeviceSize;
begin
t.host:=host;
t.FHostBuf:=TvBuffer.Create(Size,usage,@buf_ext);
t.Foffset:=0;
mr:=t.FHostBuf.GetRequirements;
if IsAlign(host.FOffset,mr.alignment) then
begin
t.FHostBuf.BindMem(host);
end else
begin
p:=AlignDw(host.FOffset,mr.alignment);
t.Foffset:=(host.FOffset-p);
host.FOffset:=p;
Size:=Size+t.Foffset;
FreeAndNil(t.FHostBuf);
t.FHostBuf:=TvBuffer.Create(Size,usage,@buf_ext);
t.FHostBuf.BindMem(host);
end;
end;
begin
Result:=nil;
t:=TUnionResourceBuffer.Create;
t.Addr:=Addr;
i:=FUnionBuffer.find(t);
if (i.Item=nil) then
begin
if not TryGetHostPointerByAddr(addr,host) then
begin
FreeAndNil(t);
Exit;
end;
FUnionBuffer.Insert(t);
_init;
Result:=t;
end else
begin
FreeAndNil(t);
t:=TUnionResourceBuffer(i.Item^);
if not TryGetHostPointerByAddr(addr,host) then
begin
FUnionBuffer.delete(t);
FreeAndNil(t);
Exit;
end;
if (t.host.FHandle<>host.FHandle) or
(t.host.FOffset<>host.FOffset) or
(t.FHostBuf.FSize<>Size) or
(t.FHostBuf.FUsage<>usage) then
begin
FreeAndNil(t.FHostBuf);
_init;
end;
Result:=t;
end;
end;
function FindUnionImage2D(Addr:Pointer):TUnionResourceImage;
var
i:TUnionResourceSet.Iterator;
t:TUnionResourceImage;
begin
Result:=nil;
t:=TUnionResourceImage.Create;
t.Addr:=Addr;
i:=FUnionImages2D.find(t);
if (i.Item<>nil) then
begin
Result:=TUnionResourceImage(i.Item^);
end;
FreeAndNil(t);
end;
function FetchUnionImage2D(Addr:Pointer;cformat:TVkFormat;extend:TVkExtent2D;usage:TVkFlags):TUnionResourceImage;
var
i:TUnionResourceSet.Iterator;
t:TUnionResourceImage;
host:TvPointer;
procedure _init;
begin
t.host:=host;
t.FImage:=TvDeviceImage2D.Create(cformat,TVkExtent3D.Create(extend.width,extend.height,1),usage);
t.devc:=MemManager.Alloc(
t.FImage.GetRequirements,
ord(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
);
t.FImage.BindMem(t.devc);
end;
begin
Result:=nil;
t:=TUnionResourceImage.Create;
t.Addr:=Addr;
i:=FUnionImages2D.find(t);
if (i.Item=nil) then
begin
if not TryGetHostPointerByAddr(addr,host) then
begin
FreeAndNil(t);
Exit;
end;
FUnionImages2D.Insert(t);
_init;
Result:=t;
end else
begin
FreeAndNil(t);
t:=TUnionResourceImage(i.Item^);
if not TryGetHostPointerByAddr(addr,host) then
begin
FUnionImages2D.delete(t);
FreeAndNil(t);
Exit;
end;
if (t.host.FHandle<>host.FHandle) or
(t.host.FOffset<>host.FOffset) or
(t.FImage.FFormat<>cformat) or
(t.FImage.FUsage<>usage) or
(t.FImage.FExtent.width<>extend.width) or
(t.FImage.FExtent.height<>extend.height) then
begin
FreeAndNil(t.FImage);
MemManager.Free(t.devc);
_init;
end;
Result:=t;
end;
end;
Procedure TvRenderPass.Clear;
begin
AtCount:=0;
FillChar(ColorAt,SizeOf(ColorAt),0);
FillChar(ColorRef,SizeOf(ColorRef),0);
subpass:=Default(TVkSubpassDescription);
subpass.pipelineBindPoint:=VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.inputAttachmentCount :=0;
subpass.pInputAttachments :=nil;
subpass.colorAttachmentCount:=0;
subpass.pColorAttachments :=@ColorRef;
subpass.pResolveAttachments :=nil; //colorAttachmentCount VK_ATTACHMENT_UNUSED
subpass.pDepthStencilAttachment:=nil; //1
subpass.preserveAttachmentCount:=0;
subpass.pPreserveAttachments :=nil;
dependency:=Default(TVkSubpassDependency);
dependency.srcSubpass :=VK_SUBPASS_EXTERNAL;
dependency.dstSubpass :=0;
dependency.srcStageMask :=0{ord(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)};
dependency.dstStageMask :=0{ord(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)};
dependency.srcAccessMask:=0;
dependency.dstAccessMask:=0{ord(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT)};
end;
Procedure TvRenderPass.SetZorderStage(s:TVkPipelineStageFlagBits);
begin
dependency.srcStageMask:=TVkPipelineStageFlags(ord(dependency.srcStageMask) or ord(s));
dependency.dstStageMask:=TVkPipelineStageFlags(ord(dependency.dstStageMask) or ord(s));
end;
Procedure TvRenderPass.AddColorRef(id:TVkUInt32);
begin
if (subpass.colorAttachmentCount>7) then Exit;
ColorRef[subpass.colorAttachmentCount].attachment:=id;
ColorRef[subpass.colorAttachmentCount].layout :=VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL{VK_IMAGE_LAYOUT_GENERAL};
Inc(subpass.colorAttachmentCount);
dependency.srcStageMask :=TVkPipelineStageFlags(ord(dependency.srcStageMask) or ord(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT));
dependency.dstStageMask :=TVkPipelineStageFlags(ord(dependency.dstStageMask) or ord(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT));
dependency.dstAccessMask:=TVkAccessFlags(ord(dependency.dstAccessMask) or ord(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT));
end;
Procedure TvRenderPass.SetDepthStencilRef(id:TVkUInt32);
begin
subpass.pDepthStencilAttachment:=@pDepthStencilRef;
pDepthStencilRef.attachment :=id;
pDepthStencilRef.layout :=VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
dependency.dstAccessMask:=TVkAccessFlags(ord(dependency.dstAccessMask) or ord(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT));
end;
Procedure TvRenderPass.AddColorAt(format:TVkFormat;ClearColor,DrawColor:Boolean);
begin
if (AtCount>8) then Exit;
ColorAt[AtCount]:=Default(TVkAttachmentDescription);
ColorAt[AtCount].format :=format;
ColorAt[AtCount].samples :=VK_SAMPLE_COUNT_1_BIT;
Case ClearColor of
True :ColorAt[AtCount].loadOp:=VK_ATTACHMENT_LOAD_OP_CLEAR;
False:ColorAt[AtCount].loadOp:=VK_ATTACHMENT_LOAD_OP_DONT_CARE;
end;
Case DrawColor of
True :ColorAt[AtCount].storeOp:=VK_ATTACHMENT_STORE_OP_STORE;
False:ColorAt[AtCount].storeOp:=VK_ATTACHMENT_STORE_OP_DONT_CARE;
end;
ColorAt[AtCount].stencilLoadOp :=VK_ATTACHMENT_LOAD_OP_DONT_CARE;
ColorAt[AtCount].stencilStoreOp:=VK_ATTACHMENT_STORE_OP_DONT_CARE;
ColorAt[AtCount].initialLayout :=VK_IMAGE_LAYOUT_UNDEFINED;
ColorAt[AtCount].finalLayout :=VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
{VK_IMAGE_LAYOUT_GENERAL}
{VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL};
Inc(AtCount);
end;
Procedure TvRenderPass.AddDepthAt(format:TVkFormat;ClearDepth,DrawDepth,ClearStencil,DrawStencil:Boolean);
begin
if (AtCount>8) then Exit;
ColorAt[AtCount]:=Default(TVkAttachmentDescription);
ColorAt[AtCount].format :=format;
ColorAt[AtCount].samples :=VK_SAMPLE_COUNT_1_BIT;
Case ClearDepth of
True :ColorAt[AtCount].loadOp:=VK_ATTACHMENT_LOAD_OP_CLEAR;
False:ColorAt[AtCount].loadOp:=VK_ATTACHMENT_LOAD_OP_DONT_CARE;
end;
Case DrawDepth of
True :ColorAt[AtCount].storeOp:=VK_ATTACHMENT_STORE_OP_STORE;
False:ColorAt[AtCount].storeOp:=VK_ATTACHMENT_STORE_OP_DONT_CARE;
end;
Case ClearStencil of
True :ColorAt[AtCount].stencilLoadOp:=VK_ATTACHMENT_LOAD_OP_CLEAR;
False:ColorAt[AtCount].stencilLoadOp:=VK_ATTACHMENT_LOAD_OP_DONT_CARE;
end;
Case DrawStencil of
True :ColorAt[AtCount].stencilStoreOp:=VK_ATTACHMENT_STORE_OP_STORE;
False:ColorAt[AtCount].stencilStoreOp:=VK_ATTACHMENT_STORE_OP_DONT_CARE;
end;
ColorAt[AtCount].initialLayout :=VK_IMAGE_LAYOUT_UNDEFINED;
ColorAt[AtCount].finalLayout :=VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
{VK_IMAGE_LAYOUT_GENERAL}
{VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL};
Inc(AtCount);
end;
Function TvRenderPass.Compile:Boolean;
var
r:TVkResult;
info:TVkRenderPassCreateInfo;
begin
Result:=False;
if (AtCount=0) then Exit;
info:=Default(TVkRenderPassCreateInfo);
info.sType :=VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
info.attachmentCount:=AtCount;
info.pAttachments :=@ColorAt;
info.subpassCount :=1;
info.pSubpasses :=@subpass;
info.dependencyCount:=1;
info.pDependencies :=@dependency;
r:=vkCreateRenderPass(Device.FHandle,@info,nil,@FHandle);
if (r<>VK_SUCCESS) then
begin
Writeln('vkCreateRenderPass');
Exit;
end;
Result:=True;
end;
//
Procedure TvGraphicsPipeline.SetPrimType(t:TVkPrimitiveTopology);
begin
Case ord(t) of
ord(VK_PRIMITIVE_TOPOLOGY_POINT_LIST)..ord(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY):
inputAssembly.topology:=t;
DI_PT_RECTLIST ,
DI_PT_LINELOOP ,
DI_PT_QUADLIST ,
DI_PT_QUADSTRIP,
DI_PT_POLYGON :
begin
inputAssembly.topology:=VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
emulate_primtype:=t;
end;
end;
end;
Procedure TvGraphicsPipeline.AddVPort(const V:TVkViewport;const S:TVkRect2D);
begin
if (viewportState.viewportCount>15) then Exit;
Viewports[viewportState.viewportCount]:=V;
Scissors [viewportState.viewportCount]:=S;
Inc(viewportState.viewportCount);
viewportState.scissorCount:=viewportState.viewportCount;
end;
Procedure TvGraphicsPipeline.AddBlend(const b:TVkPipelineColorBlendAttachmentState);
begin
if (colorBlending.attachmentCount>7) then Exit;
ColorBlends[colorBlending.attachmentCount]:=b;
Inc(colorBlending.attachmentCount);
end;
Procedure TvGraphicsPipeline.Clear;
begin
vertexInputInfo:=Default(TVkPipelineVertexInputStateCreateInfo);
vertexInputInfo.sType :=VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
inputAssembly:=Default(TVkPipelineInputAssemblyStateCreateInfo);
inputAssembly.sType :=VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssembly.topology :=VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
inputAssembly.primitiveRestartEnable:=VK_FALSE;
FillChar(Viewports ,SizeOf(Viewports),0);
FillChar(Scissors ,SizeOf(Scissors) ,0);
FillChar(ColorBlends,SizeOf(ColorBlends),0);
FillChar(FShaders ,SizeOf(FShaders),0);
viewportState:=Default(TVkPipelineViewportStateCreateInfo);
viewportState.sType :=VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.viewportCount:=0;
viewportState.pViewports :=@Viewports;
viewportState.scissorCount :=0;
viewportState.pScissors :=@Scissors;
rasterizer:=Default(TVkPipelineRasterizationStateCreateInfo);
rasterizer.sType :=VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer.depthClampEnable:=VK_FALSE;
rasterizer.rasterizerDiscardEnable:=VK_FALSE;
rasterizer.polygonMode :=VK_POLYGON_MODE_FILL;
rasterizer.lineWidth :=1;
rasterizer.cullMode :=ord(VK_CULL_MODE_NONE);
rasterizer.frontFace :=VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterizer.depthBiasEnable :=VK_FALSE;
rasterizer.depthBiasConstantFactor:=0;
rasterizer.depthBiasClamp :=0;
rasterizer.depthBiasSlopeFactor :=0;
multisampling:=Default(TVkPipelineMultisampleStateCreateInfo);
multisampling.sType :=VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling.sampleShadingEnable :=VK_FALSE;
multisampling.rasterizationSamples :=VK_SAMPLE_COUNT_1_BIT;
multisampling.minSampleShading :=1;
multisampling.pSampleMask :=nil;
multisampling.alphaToCoverageEnable:=VK_FALSE;
multisampling.alphaToOneEnable :=VK_FALSE;
colorBlending:=Default(TVkPipelineColorBlendStateCreateInfo);
colorBlending.sType :=VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlending.logicOpEnable :=VK_FALSE;
colorBlending.logicOp :=VK_LOGIC_OP_COPY;
colorBlending.attachmentCount :=0;
colorBlending.pAttachments :=@ColorBlends;
DepthStencil:=Default(TVkPipelineDepthStencilStateCreateInfo);
DepthStencil.sType :=VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
DepthStencil.depthTestEnable :=VK_FALSE;
DepthStencil.depthWriteEnable :=VK_FALSE;
DepthStencil.depthCompareOp :=VK_COMPARE_OP_LESS;
DepthStencil.depthBoundsTestEnable:=VK_FALSE;
DepthStencil.stencilTestEnable :=VK_FALSE;
//DepthStencil.front :TVkStencilOpState;
//DepthStencil.back :TVkStencilOpState;
DepthStencil.minDepthBounds :=0;
DepthStencil.maxDepthBounds :=0;
dynamicState:=Default(TVkPipelineDynamicStateCreateInfo);
dynamicState.sType :=VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicState.dynamicStateCount:=0{2};
dynamicState.pDynamicStates :=@dynamicStates;
dynamicStates[0]:=VK_DYNAMIC_STATE_VIEWPORT;
dynamicStates[1]:=VK_DYNAMIC_STATE_LINE_WIDTH;
end;
//kShaderStageCs = 0x00000000, ///< Compute shader stage.
//kShaderStagePs = 0x00000001, ///< Pixel shader stage.
//kShaderStageVs = 0x00000002, ///< Vertex shader stage.
//kShaderStageGs = 0x00000003, ///< Geometry shader stage.
//kShaderStageEs = 0x00000004, ///< Export shader stage.
//kShaderStageHs = 0x00000005, ///< Hull shader stage.
//kShaderStageLs = 0x00000006, ///< LDS shader stage. = Vertex shader to share data
//kActiveShaderStagesVsPs = 0x00000000
//kActiveShaderStagesEsGsVsPs = 0x000000B0
//kActiveShaderStagesLsHsVsPs = 0x00000045
//kActiveShaderStagesLsHsEsGsVsPs = 0x000000AD
//kActiveShaderStagesDispatchDrawVsPs = 0x00000200
//Logical Pipeline
//VK_SHADER_STAGE_VERTEX_BIT Vertex VS LS LS ES
//VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT Hull [] HS HS []
//VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT Domain [] VS ES []
//VK_SHADER_STAGE_GEOMETRY_BIT Geometry [] [] GS, VS GS, VS
//VK_SHADER_STAGE_FRAGMENT_BIT Pixel PS PS PS PS
//0 LS VK_SHADER_STAGE_VERTEX_BIT
//1 HS VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT
//2 ES VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT
//3 GS VK_SHADER_STAGE_GEOMETRY_BIT
//4 VS VK_SHADER_STAGE_VERTEX_BIT
//5 PS VK_SHADER_STAGE_FRAGMENT_BIT
Procedure TvGraphicsPipeline.SetLSShader(Shader:TvShader);
begin
if (Shader=nil) then Exit;
if (Shader.FStage=VK_SHADER_STAGE_VERTEX_BIT) then
FShaders[0]:=Shader;
end;
Procedure TvGraphicsPipeline.SetHSShader(Shader:TvShader);
begin
if (Shader=nil) then Exit;
if (Shader.FStage=VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) then
FShaders[1]:=Shader;
end;
Procedure TvGraphicsPipeline.SetESShader(Shader:TvShader);
begin
if (Shader=nil) then Exit;
if (Shader.FStage=VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) then
FShaders[2]:=Shader;
end;
Procedure TvGraphicsPipeline.SetGSShader(Shader:TvShader);
begin
if (Shader=nil) then Exit;
if (Shader.FStage=VK_SHADER_STAGE_GEOMETRY_BIT) then
FShaders[3]:=Shader;
end;
Procedure TvGraphicsPipeline.SetVSShader(Shader:TvShader);
begin
if (Shader=nil) then Exit;
if (Shader.FStage=VK_SHADER_STAGE_VERTEX_BIT) then
FShaders[4]:=Shader;
end;
Procedure TvGraphicsPipeline.SetPSShader(Shader:TvShader);
begin
if (Shader=nil) then Exit;
if (Shader.FStage=VK_SHADER_STAGE_FRAGMENT_BIT) then
FShaders[5]:=Shader;
end;
procedure TvGraphicsPipeline.SetLayout(Layout:TvPipelineLayout);
begin
if (FLayout<>Layout) then
begin
FLayout:=Layout;
end;
end;
procedure TvGraphicsPipeline.SetRenderPass(RenderPass:TvRenderPass);
begin
if (FRenderPass<>RenderPass) then
begin
FRenderPass:=RenderPass;
end;
end;
function TvGraphicsPipeline.Compile:Boolean;
var
r:TVkResult;
i:Integer;
shaderStages:array[0..5] of TVkPipelineShaderStageCreateInfo; // info.stageCount
info:TVkGraphicsPipelineCreateInfo;
begin
Result:=False;
if (FLayout=nil) then Exit;
if (FRenderPass=nil) then Exit;
if (viewportState.viewportCount=0) then Exit;
if (viewportState.scissorCount=0) then Exit;
info:=Default(TVkGraphicsPipelineCreateInfo);
FillChar(shaderStages,SizeOf(shaderStages),0);
For i:=0 to 5 do
if (FShaders[i]<>nil) then
begin
shaderStages[info.stageCount].sType :=VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shaderStages[info.stageCount].stage :=FShaders[i].FStage;
shaderStages[info.stageCount].module:=FShaders[i].FHandle;
shaderStages[info.stageCount].pName :=PChar(FShaders[i].FEntry);
Inc(info.stageCount);
end;
if (info.stageCount=0) then Exit;
if (not FLayout.Compile) then Exit;
if (not FRenderPass.Compile) then Exit;
info.sType :=VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
info.pStages :=@shaderStages;
info.pVertexInputState :=@vertexInputInfo;
info.pInputAssemblyState:=@inputAssembly;
info.pViewportState :=@viewportState;
info.pRasterizationState:=@rasterizer;
info.pMultisampleState :=@multisampling;
info.pDepthStencilState :=@DepthStencil;
info.pColorBlendState :=@colorBlending;
info.pDynamicState :=@dynamicState;
info.layout :=FLayout.FHandle;
info.renderPass :=FRenderPass.FHandle;
info.subpass :=0;
info.basePipelineHandle :=VK_NULL_HANDLE;
info.basePipelineIndex :=-1;
r:=vkCreateGraphicsPipelines(Device.FHandle,VK_NULL_HANDLE,1,@info,nil,@FHandle);
if (r<>VK_SUCCESS) then
begin
Writeln('failed to create graphics pipeline!');
exit;
end;
Result:=True;
end;
/////////
Procedure TvRenderTargets.AddClearColor(clr:TVkClearValue);
begin
if (FClearValuesCount>8) then Exit;
FClearValues[FClearValuesCount]:=clr;
Inc(FClearValuesCount);
end;
class function TvRenderTargets.c(const a,b:TvRenderTargets):Integer;
begin
Result:=CompareByte(a,b,SizeOf(Pointer));
end;
Destructor TvRenderTargets.Destroy;
begin
FreeAndNil(FRenderPass);
FreeAndNil(FPipeline);
FreeAndNil(FFramebuffer);
inherited;
end;
///////////////
function TvCmdBuffer.BeginCmdBuffer:Boolean;
var
r:TVkResult;
Info:TVkCommandBufferBeginInfo;
begin
Result:=False;
if (Self=nil) then Exit;
if FCBState then Exit(True);
if (cmdbuf=VK_NULL_HANDLE) then Exit;
Info:=Default(TVkCommandBufferBeginInfo);
Info.sType:=VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
Info.flags:=ord(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
Info.pInheritanceInfo:=nil;
r:=vkBeginCommandBuffer(cmdbuf,@Info);
if (r<>VK_SUCCESS) then
begin
Writeln('vkBeginCommandBuffer:',r);
Exit;
end;
FCBState:=True;
Result:=True;
end;
Procedure TvCmdBuffer.EndCmdBuffer;
var
r:TVkResult;
begin
if (Self=nil) then Exit;
if FCBState then
begin
EndRenderPass;
r:=vkEndCommandBuffer(cmdbuf);
if (r<>VK_SUCCESS) then
begin
Writeln('vkEndCommandBuffer:',r);
end;
FCBState:=False;
end;
end;
function TvCmdBuffer.BeginRenderPass(RT:TvRenderTargets):Boolean;
var
info:TVkRenderPassBeginInfo;
begin
Result:=False;
if (Self=nil) then Exit;
if (cmdbuf=VK_NULL_HANDLE) then Exit;
if (RT=nil) then
begin
EndRenderPass;
Exit(True);
end;
if (FRenderTargets=RT) then Exit(True);
if (RT.FRenderPass=nil) then Exit;
if (RT.FPipeline=nil) then Exit;
if (RT.FFramebuffer=nil) then Exit;
if (not RT.FRenderPass.Compile) then Exit;
if (not RT.FPipeline.Compile) then Exit;
if (not RT.FFramebuffer.Compile) then Exit;
if (not BeginCmdBuffer) then Exit;
EndRenderPass;
info:=Default(TVkRenderPassBeginInfo);
info.sType :=VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass :=RT.FRenderPass.FHandle;
info.renderArea :=RT.FRenderArea;
info.clearValueCount:=RT.FClearValuesCount;
info.pClearValues :=RT.FClearValues;
info.framebuffer :=RT.FFramebuffer.FHandle;
vkCmdBeginRenderPass(cmdbuf,@info,VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline (cmdbuf,VK_PIPELINE_BIND_POINT_GRAPHICS,RT.FPipeline.FHandle);
FRenderTargets:=RT;
Result:=True;
end;
Procedure TvCmdBuffer.EndRenderPass;
begin
if (Self=nil) then Exit;
if (FRenderTargets<>nil) then
begin
vkCmdEndRenderPass(cmdbuf);
FRenderList.Insert(FRenderTargets);
FRenderTargets:=nil;
end;
end;
Procedure TvCmdBuffer.QueueSubmit;
var
r:TVkResult;
info:TVkSubmitInfo;
waitStages:TVkPipelineStageFlags;
Fence:TVkFence;
begin
if (Self=nil) then Exit;
if (cmdbuf=VK_NULL_HANDLE) then Exit;
EndCmdBuffer;
waitStages:=ord(VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);
info:=Default(TVkSubmitInfo);
info.sType :=VK_STRUCTURE_TYPE_SUBMIT_INFO;
info.commandBufferCount :=1;
info.pCommandBuffers :=@cmdbuf;
info.pWaitDstStageMask :=@waitStages;
if (FWaitSemaphore<>nil) then
begin
info.waitSemaphoreCount:=1;
info.pWaitSemaphores :=@FWaitSemaphore.FHandle;
end;
if (FSignSemaphore<>nil) then
begin
info.signalSemaphoreCount:=1;
info.pSignalSemaphores :=@FSignSemaphore.FHandle;
end;
Fence:=VK_NULL_HANDLE;
if (FSignFence<>nil) then
begin
Fence:=FSignFence.FHandle;
end;
r:=vkQueueSubmit(RenderQueue,1,@info,Fence);
if (r<>VK_SUCCESS) then
begin
Writeln('vkQueueSubmit');
exit;
end;
end;
Procedure TvCmdBuffer.ClearRenderList;
var
It:TvRenderTargetsSet.Iterator;
begin
if (Self=nil) then Exit;
It:=FRenderList.cbegin;
if (It.Item<>nil) then
repeat
TvRenderTargets(It.Item^).Free;
until not It.Next;
FRenderList.Free;
FreeAndNil(FRenderTargets);
end;
function GET_INDEX_TYPE_SIZE(INDEX_TYPE:TVkIndexType):Byte;
begin
Case INDEX_TYPE of
VK_INDEX_TYPE_UINT16:Result:=16;
VK_INDEX_TYPE_UINT32:Result:=32;
VK_INDEX_TYPE_UINT8_EXT :Result:=8;
else Result:=0;
end;
end;
Procedure TvCmdBuffer.DrawIndex2(Addr:Pointer;INDICES:DWORD;INDEX_TYPE:TVkIndexType);
var
rb:TUnionResourceBuffer;
Size:TVkDeviceSize;
begin
if (Self=nil) then Exit;
if (FRenderTargets=nil) then Exit;
Size:=INDICES*GET_INDEX_TYPE_SIZE(INDEX_TYPE);
rb:=FetchHostBuffer(Addr,Size,ord(VK_BUFFER_USAGE_INDEX_BUFFER_BIT));
Assert(rb<>nil);
vkCmdBindIndexBuffer(
cmdbuf,
rb.FHostBuf.FHandle,
rb.Foffset,
INDEX_TYPE);
vkCmdDrawIndexed(
cmdbuf,
INDICES,
1,0,0,0);
end;
Procedure TvCmdBuffer.DrawIndexAuto(INDICES:DWORD;INDEX_TYPE:TVkIndexType);
begin
if (Self=nil) then Exit;
if (FRenderTargets=nil) then Exit;
vkCmdDraw(
cmdbuf,
INDICES,
1,0,0);
end;
//
function TUnionResourceCompare.c(const a,b:TUnionResource):Integer;
begin
Result:=CompareByte(a.Addr,b.Addr,SizeOf(Pointer));
end;
//
Destructor TUnionResourceBuffer.Destroy;
begin
FreeAndNil(FHostBuf);
inherited;
end;
//
Destructor TUnionResourceImage.Destroy;
begin
FreeAndNil(FImage);
MemManager.Free(devc);
inherited;
end;
end.

406
vulkan/vShader.pas Normal file
View File

@ -0,0 +1,406 @@
unit vShader;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, vulkan, vDevice;
type
TvSupportDescriptorType=array[0..1] of TVkDescriptorType;
PvShaderBind=^TvShaderBind;
TvShaderBind=packed object
FDVID:DWORD;
FDSET:DWORD;
FBIND:DWORD;
FSCLS:DWORD;
FTYPE:DWORD;
end;
TvShader=class
FHandle:TVkShaderModule;
FStage:TVkShaderStageFlagBits;
FLocalSize:TVkOffset3D;
FEntry:RawByteString;
FBinds:array of TvShaderBind;
Destructor Destroy; override;
procedure LoadFromMemory(data:Pointer;size:Ptruint);
procedure LoadFromStream(Stream:TStream);
procedure LoadFromFile(const FileName:RawByteString);
procedure Parse(data:Pointer;size:Ptruint);
end;
implementation
Destructor TvShader.Destroy;
begin
if (FHandle<>VK_NULL_HANDLE) then
vkDestroyShaderModule(Device.FHandle,FHandle,nil);
end;
procedure TvShader.LoadFromMemory(data:Pointer;size:Ptruint);
var
cinfo:TVkShaderModuleCreateInfo;
r:TVkResult;
begin
if (FHandle<>VK_NULL_HANDLE) then
vkDestroyShaderModule(Device.FHandle,FHandle,nil);
FHandle:=VK_NULL_HANDLE;
FStage:=Default(TVkShaderStageFlagBits);
FLocalSize:=TVkOffset3D.Create(1,1,1);
FEntry:='';
SetLength(FBinds,0);
cinfo:=Default(TVkShaderModuleCreateInfo);
cinfo.sType :=VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
cinfo.codeSize:=size;
cinfo.pCode :=data;
r:=vkCreateShaderModule(Device.FHandle,@cinfo,nil,@FHandle);
if (r<>VK_SUCCESS) then
begin
Writeln('vkCreateShaderModule:',r);
Exit;
end;
Parse(data,size);
end;
procedure TvShader.LoadFromStream(Stream:TStream);
var
M:TCustomMemoryStream;
begin
if Stream.InheritsFrom(TCustomMemoryStream) then
begin
M:=TCustomMemoryStream(Stream);
end else
begin
M:=TMemoryStream.Create;
TMemoryStream(M).LoadFromStream(Stream);
end;
LoadFromMemory(M.Memory,M.Size);
if (M<>Stream) then
begin
M.Free;
end;
end;
procedure TvShader.LoadFromFile(const FileName:RawByteString);
Var
S:TFileStream;
begin
S:=TFileStream.Create(FileName,fmOpenRead or fmShareDenyWrite);
Try
LoadFromStream(S);
finally
S.Free;
end;
end;
type
PSPIRVHeader=^TSPIRVHeader;
TSPIRVHeader=packed record
MAGIC:DWORD;
VERSION_MINOR:WORD;
VERSION_MAJOR:WORD;
TOOL_VERSION:WORD;
TOOL_ID:WORD;
BOUND:DWORD;
RESERVED:DWORD;
end;
PSPIRVInstruction=^TSPIRVInstruction;
TSPIRVInstruction=packed record
OP:WORD;
COUNT:WORD;
end;
Const
MagicNumber = 119734787;
//Operation
OpEntryPoint = 15;
OpExecutionMode = 16;
OpTypeVoid = 19;
OpTypeBool = 20;
OpTypeInt = 21;
OpTypeFloat = 22;
OpTypeVector = 23;
OpTypeMatrix = 24;
OpTypeImage = 25;
OpTypeSampler = 26;
OpTypeSampledImage = 27;
OpTypeArray = 28;
OpTypeRuntimeArray = 29;
OpTypeStruct = 30;
OpTypeOpaque = 31;
OpTypePointer = 32;
OpTypeFunction = 33;
OpTypeEvent = 34;
OpTypeDeviceEvent = 35;
OpTypeReserveId = 36;
OpTypeQueue = 37;
OpTypePipe = 38;
OpTypeForwardPointer = 39;
OpDecorate = 71;
OpVariable = 59;
//ExecutionMode
LocalSize = 17;
//Decoration
Sample = 17;
Binding = 33;
DescriptorSet = 34;
//StorageClass
UniformConstant = 0;
Uniform = 2;
Image = 11;
StorageBuffer = 12;
//ExecutionModel
Vertex = 0;
TessellationControl = 1;
TessellationEvaluation = 2;
Geometry = 3;
Fragment = 4;
GLCompute = 5;
Kernel = 6;
TaskNV = 5267;
MeshNV = 5268;
RayGenerationKHR = 5313;
IntersectionKHR = 5314;
AnyHitKHR = 5315;
ClosestHitKHR = 5316;
MissKHR = 5317;
CallableKHR = 5318;
procedure TvShader.Parse(data:Pointer;size:Ptruint);
var
orig_data:Pointer;
orig_size:Ptruint;
I:TSPIRVInstruction;
f:Ptruint;
r:PvShaderBind;
d:dword;
function Fetch(ID:DWORD):PvShaderBind;
var
i:Integer;
begin
if Length(FBinds)<>0 then
For i:=0 to High(FBinds) do
if (ID=FBinds[i].FDVID) then
begin
Exit(@FBinds[i]);
end;
i:=Length(FBinds);
SetLength(FBinds,i+1);
FBinds[i]:=Default(TvShaderBind);
FBinds[i].FDVID:=ID;
Result:=@FBinds[i];
end;
function GetStageFlag(FStage:DWORD):TVkShaderStageFlagBits;
begin
case FStage of
Vertex :Result:=VK_SHADER_STAGE_VERTEX_BIT;
TessellationControl :Result:=VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
TessellationEvaluation:Result:=VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
Geometry :Result:=VK_SHADER_STAGE_GEOMETRY_BIT;
Fragment :Result:=VK_SHADER_STAGE_FRAGMENT_BIT;
GLCompute :Result:=VK_SHADER_STAGE_COMPUTE_BIT;
Kernel :Result:=VK_SHADER_STAGE_COMPUTE_BIT;
TaskNV :Result:=VK_SHADER_STAGE_TASK_BIT_NV;
MeshNV :Result:=VK_SHADER_STAGE_MESH_BIT_NV;
RayGenerationKHR :Result:=VK_SHADER_STAGE_RAYGEN_BIT_KHR;
IntersectionKHR :Result:=VK_SHADER_STAGE_INTERSECTION_BIT_KHR;
AnyHitKHR :Result:=VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
ClosestHitKHR :Result:=VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
MissKHR :Result:=VK_SHADER_STAGE_MISS_BIT_KHR;
CallableKHR :Result:=VK_SHADER_STAGE_CALLABLE_BIT_KHR;
else
Result:=Default(TVkShaderStageFlagBits);
end;
end;
function find_pointer_type(data:Pointer;size:Ptruint;var id:DWORD):boolean;
var
I:TSPIRVInstruction;
f:Ptruint;
begin
Result:=false;
repeat
I:=PSPIRVInstruction(data)^;
if (I.OP=OpTypePointer) and (I.COUNT=4) then
if (PDWORD(data)[1]=id) then
begin
id:=PDWORD(data)[3];
Exit(true);
end;
if (I.COUNT=0) then I.COUNT:=1;
f:=I.COUNT*SizeOf(DWORD);
if (size<f) then Break;
data:=data+f;
size:=size-f;
until false;
end;
function find_type(data:Pointer;size:Ptruint;var id:DWORD):boolean;
var
I:TSPIRVInstruction;
f:Ptruint;
begin
Result:=false;
repeat
I:=PSPIRVInstruction(data)^;
Case I.OP of
OpTypeVoid ,
OpTypeBool ,
OpTypeInt ,
OpTypeFloat ,
OpTypeVector ,
OpTypeMatrix ,
OpTypeImage ,
OpTypeSampler ,
OpTypeSampledImage ,
OpTypeArray ,
OpTypeRuntimeArray ,
OpTypeStruct ,
OpTypeOpaque ,
OpTypePointer ,
OpTypeFunction ,
OpTypeEvent ,
OpTypeDeviceEvent ,
OpTypeReserveId ,
OpTypeQueue ,
OpTypePipe ,
OpTypeForwardPointer:
if (PDWORD(data)[1]=id) then
begin
id:=PDWORD(data)[3];
Exit(true);
end;
end;
if (I.COUNT=0) then I.COUNT:=1;
f:=I.COUNT*SizeOf(DWORD);
if (size<f) then Break;
data:=data+f;
size:=size-f;
until false;
end;
begin
if (size<=SizeOf(TSPIRVHeader)) then Exit;
if (PSPIRVHeader(data)^.MAGIC<>MagicNumber) then Exit;
data:=data+SizeOf(TSPIRVHeader);
size:=size-SizeOf(TSPIRVHeader);
orig_data:=data;
orig_size:=size;
repeat
I:=PSPIRVInstruction(data)^;
Case I.OP of
OpEntryPoint:
if (I.COUNT>=4) then
begin
FStage:=GetStageFlag(PDWORD(data)[1]);
FEntry:=PChar(@PDWORD(data)[3]);
end;
OpExecutionMode:
if (I.COUNT>=3) then
begin
d:=PDWORD(data)[2];
case d of
LocalSize:
if (I.COUNT>=6) then
begin
FLocalSize.x:=PDWORD(data)[3];
FLocalSize.y:=PDWORD(data)[4];
FLocalSize.z:=PDWORD(data)[5];
end;
end;
end;
OpDecorate:
if (I.COUNT>=4) then
begin
d:=PDWORD(data)[2];
case d of
Sample:
begin
r:=Fetch(PDWORD(data)[1]);
r^.FSCLS:=Sample shl 16;
end;
Binding:
begin
r:=Fetch(PDWORD(data)[1]);
r^.FBIND:=PDWORD(data)[3];
end;
DescriptorSet:
begin
r:=Fetch(PDWORD(data)[1]);
r^.FDSET:=PDWORD(data)[3];
end;
end;
end;
OpVariable:
if (I.COUNT>=4) then
begin
d:=PDWORD(data)[3];
case d of
UniformConstant,
Uniform,
Image,
StorageBuffer:
begin
r:=Fetch(PDWORD(data)[2]);
r^.FSCLS:=d;
d:=PDWORD(data)[1];
if find_pointer_type(orig_data,orig_size,d) then
if find_type(orig_data,orig_size,d) then
begin
r^.FTYPE:=d;
end;
end;
end;
end;
end;
if (I.COUNT=0) then I.COUNT:=1;
f:=I.COUNT*SizeOf(DWORD);
if (size<f) then Break;
data:=data+f;
size:=size-f;
until false;
end;
// =0,
// VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER=1,
// VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE=2,
// VK_DESCRIPTOR_TYPE_STORAGE_IMAGE=3,
// VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER=4,
// VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER=5,
// VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER=6,
// VK_DESCRIPTOR_TYPE_STORAGE_BUFFER=7,
// VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC=8,
// VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC=9,
// VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT=10,
// VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT=1000138000,
// VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR=1000150000,
// VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV=1000165000,
// VK_DESCRIPTOR_TYPE_MUTABLE_VALVE=1000351000
{
function TvShaderBind.GetSupportTypes:TvSupportDescriptorType;
begin
Result:=Default(TvSupportDescriptorType);
case FType of
Sample shl 16 :begin Result[0]:=VK_DESCRIPTOR_TYPE_SAMPLER; end;;
UniformConstant :begin Result[0]:=; end;;
Uniform :begin Result[0]:=; end;;
Workgroup :begin Result[0]:=; end;;
CrossWorkgroup :begin Result[0]:=; end;;
Image :begin Result[0]:=; end;;
StorageBuffer :begin Result[0]:=; end;;
end;
end;}
end.