--- /dev/null
+bin/
+config.make
+mandelbrot.pam
+movie.avi
+/build/
+/dist/
+/.lib/
+/nbproject/private/
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, 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
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If 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 convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU 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
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state 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 program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
--- /dev/null
+
+dist_VERSION=0.0.99
+dist_NAME=vulkanz
+dist_EXTRA=README COPYING
+
+include config.make
+
+java_MODULES = \
+ notzed.xlib notzed.xcb notzed.display \
+ notzed.vulkan notzed.vulkan.test
+
+notzed.vulkan_JDEPMOD = notzed.xlib notzed.xcb
+notzed.vulkan.test_JDEPMOD = notzed.vulkan
+notzed.xcb_JDEPMOD =
+notzed.xlib_JDEPMOD =
+notzed.display_JDEPMOD = notzed.xlib notzed.xcb notzed.vulkan
+
+notzed.vulkan.test_JMAIN = vulkan.test.TestMandelbrot vulkan.test.TestCube vulkan.test.TestSDF
+
+$(foreach module,$(java_MODULES),$(eval $(module)_JMAINFLAGS=--enable-native-access=notzed.nativez,$(module)))
+
+notzed.vulkan.test_JMAINFLAGS = --enable-native-access=notzed.nativez,notzed.xlib,notzed.xcb,notzed.vulkan
+
+include java.make
+
+maven_central_JARS =org.openjdk.jmh:jmh-core:1.33 org.openjdk.jmh:jmh-generator-annprocess:1.33
+
+include maven.make
--- /dev/null
+
+Introduction
+------------
+
+This is various experiments with the panama-foreign abi JEP for
+invoking native C functions from Java directly and without JNI.
+
+The main goal is to experiment with creating a "java friendly" and
+mostly type-safe api directly in one step, without requiring
+additional wrapping.
+
+It uses a gcc plugin to compile c headers to obtain most of the api
+information, but requires cpp and perl to extract the values of
+#define constants as they are not available to the gcc plugin.
+
+This api information is then converted to Java code using a
+config-directed perl script `export-api'. The config file can be used
+to create static (all-in-one) or object oriented output. It includes
+templated strings as well as perl fragments to generate various source
+parts.
+
+The vulkan api is officially defined by a registry in xml, so there's
+a separate generator for that.
+
+Compile
+-------
+
+Requirements are gcc and GNU cpp, perl, GNU make, and of course a
+compatible jdk-foreign jdk. The various modules require headers or
+sdks for their corresponding libraries, e.g. ffmpeg-5.x,
+vulkan-tools-1.2.x.
+
+Copy config.make.in to config.make and modify any variables required.
+
+Then make everything, parallel make should work.
+
+$ make -j
+
+Or build one module:
+
+$ make notzed.nativez
+
+Or run a demo (see next section):
+
+$ make run-notzed.vkregistry.test/vulkan.test.TestMandelbrot
+
+A non-recursive make setup is used although make file fragments are
+included from various locations across the modules. All java is
+compiled as modules.
+
+JAVA_HOME must point to a compatible panama-enabled jdk.
+
+The latest at the time of writing was:
+
+ branch: foreign-jextract
+ commit: 2e1291680024f12fbf2f0f02b0f79d7b4348b369
+ date: Fri Feb 4 11:01:21 2022 +0000
+
+All output and intermediate files are in bin/
+
+bin/modules/<module>/classes - compiled java modules
+bin/gen/<module>/classes - generated java
+bin/gen/<module>/gen - generated intermediate non-java
+
+These are more or less an exploded view of all jmod files:
+
+bin/<target>/bin - commands for all modules
+bin/<target>/lib - libraries/config and modular jar files for all modules
+bin/<target>/include - header files for all modules
+
+Finally:
+
+bin/<target>/jmods - .jmod modules
+
+
+Demos
+-----
+
+Most examples have a demo, see the <module>_JMAIN variables in the
+Makefile for the targets. They are executed using:
+
+$ make run-<module>/<main-class>
+
+Modules
+--------
+
+notzed.nativez contains some support classes and the code generator.
+The gcc plugin source is in src/notzed.nativez/native/ the code
+generator is in src/notzed.nativez/{bin,lib}.
+
+notzed.api is a pseudo-module containing a simple test c api for
+experiments, it just builds into a library.
+
+notzed.apistatic is a 'all in one class' static wrapper for
+notzed.api.
+
+notzed.apiobject is an object-oriented wrapper for notzed.api.
+
+notzed.clstatic is an 'all in one class' static wrapper for OpenCL
+(2.1). The api closesly matches the C api except it converts error
+codes into exceptins and can infer certain arguments from others such
+as length parameters. This is probably the most complete api.
+
+notzed.ffmpeg is a partial object-oriented mapping for ffmpeg-5.0 that
+closely follows the jjmpeg design. It's enough to read video frames.
+The demo requires a file 'movie.api' in the root directory to run.
+
+notzed.vkheader uses the header-based generator on the vulkan
+installed headers. This is still very incomplete work in progress.
+Much meta-data is lost such as which functions are extensions during
+the generation of the headers. This is incomplete and dead-ended.
+
+notzed.vkregistry uses a completely different generator which directly
+parses the official xml registry specification for vulkan
+(/usr/share/vulkan/registry/vk.xml). This is directly converted to
+about-as-java-friendly a vulkan api as one can hope for, particularly
+the constructors for all the config objects. This is incomplete and
+dead-ended.
+
+notzed.vulkan also uses a different generator which directly parses
+the official xml registry specification for vulkan
+(/usr/share/vulkan/registry/vk.xml). This version uses templates to
+generate the various structures in more concise and relatively
+consistenet way. Work in progress.
+
+Export process
+--------------
+
+The main generator is written in perl and lives in
+src/notzed.nativez/{bin,lib}.
+
+The process:
+
+* run the gcc plugin to extract all of the available c structures from
+ gcc and save them to a perl hash.
+
+ gcc plugins aren't very well documented so it was a lot of trial and
+ error to get it to output all the type information even starting
+ with a partial example. The names of parameters for function calls
+ were particularly problematic.
+
+* optionally run export-defines to extract #define constants. They
+ can be grouped/excluded by name or by the filename they belong to.
+ The the first rule to match will complete the processing for a given
+ type.
+
+ This is also a surprisingly difficult process because the c
+ pre-processor can just generate arbitrary c expressions so the only
+ way to find their correct value is to execute the c. So the export
+ script generates a c file which is compiled and executed to generate
+ the perl definitions.
+
+ Currently the types are mapped to a 'compatible' native type by
+ using the gcc operators __builtin_choose_expr,
+ __builtin_types_compatible_p, and typeof to implement a
+ pseudo-function overloading in c - possiblly using c++ is a better
+ choice here. For now inclusions or exclusions are required to
+ avoid problematic definitions that confuse these operators.
+
+These files are then fed to generate-api. It proceeds in multiple
+stages.
+
+First stages are handled by lib/api.pm.
+
+* Load and preprocess the api definition.
+
+ - Perform a bunch of 'fix up' processing on the data structures such
+ as inserting anonymous types which are not generated by the plugin.
+
+ - Create a full dependency tree for the objects
+ specificallyreferenced by the api definition so only objects and
+ functions of interest are included.
+
+ - Resolve all the various export options using some rules and store
+ the information about the selected options onto target objects.
+
+Then generate-api produces the java files from a combination of the
+processed data definitions and the api definition.
+
+* Export 'libraries'. These are static classes of functions and/or
+ constants.
+
+ - Can include static methods. Methods can have per-method template
+ overrides.
+
+ - Can include constants.
+
+* Export 'structures'. These represent C pointers.
+
+ - struct/union have a MemorySegment, a layout, and potentially
+ accessors for fields.
+
+ - anonymous structures just have a MemoryAddress and no accessors.
+
+ - Can include static and member methods. Methods can have per-method
+ template overrides.
+
+ - Can include constants.
+
+* Export 'calls'. These are function interfaces for function pointers.
+
+ - The interface is the java form of the call.
+
+ - If available a typedef name is used, otherwise the names are mapped
+ to a mangled name of the form Call_<args>_<return>.
+
+ - An upcall factory creates an upcall to an instance of a hidden
+ trampline interface which performs the mapping of arguments to java
+ and returns to c.
+
+ - A downcall factory creates a downcall which maps the java call to
+ native and back.
+
+ - Both factories return a record of type FunctionPointer<type> which
+ contains both a NativeSymbol and the java interface instance so they
+ can be used from either environment.
+
+* Export 'constants'. These are referenced enums or any defines which
+ haven't been included in any other library or struct.
+
+ - enums are mapped to an interface with fields of:
+ 'static final int FOO = xx'
+ of
+ 'static final long FOO = xx'
+
+ - defines are mapped to a matching native type which includes
+ floating point types and strings in addition to all the integral
+ types.
+
+lib/code.pm is used to generate some of the code and handle
+templating. Common code templates are defined in lib/code.api but can
+be extended or replaced by a given api file.
+
+lib/method.pm is used to generate per-field (struct) and per-argument
+(function) sub-templates for mapping c to and from java. The
+sub-templates it uses are defined in lib/types.api but again they can
+be extended or replaced by a given api file.
+
+Status
+------
+
+It's all very much work in progress and due to the constant changes in
+panama will be in flux for some time.
+
+* bitfields are implemented.
+* varargs is not implemented.
+* the generator for notzed.vkregistry uses a lot of miserable
+ write-once perl.
+* the scope and object lifecycle stuff is not really sorted out yet.
+* the config format and features are still being fiddled with.
+* the config file isn't really documented.
+* the build system is still being fiddled with, some of the output
+ directories are mixed up.
+* linux-amd64 only at this point in time.
+
+License
+-------
+
+GNU General Public License, version 3 or later, but see individual
+file headers for specifics.
+
+Links
+-----
+
+ * https://www.zedzone/software/panamaz.html - project page.
+ * https://openjdk.java.net/projects/panama - openjdk panama page.
+ * https://github.com/openjdk/panama-foreign - openjdk panama source.
--- /dev/null
+
+TARGET ?= linux-amd64
+
+JAVA_HOME ?= /usr/local/jdk
+JAVAFX_HOME ?= /usr/local/javafx-sdk
+FFMPEG_HOME ?= /opt/ffmpeg-5.0
+NATIVEZ_HOME=bin/$(TARGET)
+GCCPLUGINDIR:=$(shell gcc -print-file-name=plugin)
+
+JAVAMODPATH = bin/$(TARGET)/lib
+JAVACFLAGS =
+JMAINFLAGS = -Djava.library.path=bin/linux-amd64/lib:$(FFMPEG_HOME)/lib:/usr/lib64
+
+JAVA ?= $(JAVA_HOME)/bin/java
+JAVAC ?= $(JAVA_HOME)/bin/javac
+JAR ?= $(JAVA_HOME)/bin/jar
+JMOD ?= $(JAVA_HOME)/bin/jmod
+
+CFLAGS = -fPIC -Os -Wall
+CXXFLAGS =-fPIC -Os -Wall
+
+# Linux options
+# USE_SO_VERSION adds the major version to the library open name for ffmpeg libs on linux.
+linux-amd64_CPPFLAGS = \
+ -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux \
+ -DUSE_SO_VERSION=1
+linux-amd64_CFLAGS = -fPIC -Os -Wall
+linux-amd64_CC = cc
+linux-amd64_CXXFLAGS = -fPIC -Os -Wall
+linux-amd64_CXX = g++
+linux-amd64_LD = ld
+
+linux-amd64_SO = .so
+linux-amd64_LIB = lib
+
+# Windows options
+windows-amd64_CPPFLAGS = \
+ -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux \
+ -DHAVE_ALIGNED_MALLOC \
+ -DWIN32
+windows-amd64_CFLAGS = -Os -Wall
+windows-amd64_CC = x86_64-w64-mingw32-gcc
+windows-amd64_CXXFLAGS = -Os -Wall
+windows-amd64_CXX = x86_64-w64-mingw32-g++
+windows-amd64_LD = x86_64-w64-mingw32-ld
+windows-amd64_LDFLAGS = -Wl,--subsystem,windows
+
+windows-amd64_SO = .dll
+windows-amd64_LIB =
--- /dev/null
+#
+# Copyright (C) 2019,2022 Michael Zucchi
+#
+# This is the copyright for java.make
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# General purpose modular java makefile that supports native library
+# compilation directly. Non-recrusve implementation.
+#
+# Uses metamake programming with some file conventions to implement
+# auto-make-like features.
+
+# Define modules
+# --------------
+# java_MODULES list of java modules to compile. The sources must
+# exist in src/<module>/classes. Resource files are
+# stored in src/<module>/classes. Source-code
+# generators must exist in src/<module>/gen. Native
+# libraries must exist in src/<module>/jni.
+
+# native_MODULES list of native-only "modules".
+
+
+# Global variables
+
+# JAVA_HOME location of jdk.
+# JAVAC java compiler to use. Default is 'javac' on the path.
+# JAVACFLAGS javac flags applied to all invocations.
+# JAR jar command.
+# JARFLAGS jar flags
+# JMOD jmod command.
+# JMODFLAGS jmod flags.
+# JAVAFLAGS java flags for run targets
+
+# Module specific variables
+
+# <module>_JDEPMOD Lists modules which this one depends on.
+
+# <module>_JAVACFLAGS Extra module-specific flags for each command.
+# <module>_JARFLAGS
+# <module>_JMODFLAGS
+
+# all paths are relative to the root package name
+
+# <module>_JAVA Java sources. If not set it is found from src/<module>/classes/(*.java)
+# <module>_RESOURCES .jar resources. If not set it is found from src/<module>/classes/(not *.java)
+# <module>_JAVA_GENERATED Java generated sources.
+# <module>_RESOURCES_GENERATED Java generated sources.
+
+# Variables for use in fragments
+
+# gen.make and jni.make can additionally make use of these variables
+
+# <module>_gendir Location for files used in Java generation process (per project).
+# <module>_genjavadir Location where _JAVA_GENERATED .java files will be created (per project).
+# <module>_objdir Location for c objects (per target).
+# <module>_incdir Location for output includes, .jmod staging.
+# <module>_libdir Location for output libraries, .jmod staging. May point to _bindir.
+# <module>_bindir Location for output commands, .jmod staging.
+
+# Define libraries
+# ----------------
+
+# Each module can define one or more native libraries.
+
+# These are compiled after the java sources have been compiled as that
+# process also generates any native binding headers.
+
+# <module>_NATIVE_LIBRARIES list of libraries to build.
+# library names match System.loadLibrary().
+
+# Global variables
+
+# <target>_LDFLAGS
+# <target>_LDLIBS
+# <target>_CPPFLAGS
+# <target>_CFLAGS
+# <target>_CC
+# <target>_CXXFLAGS
+# <target>_CXX
+# SO shared library suffix
+# LIB shared library prefix
+
+# Utility functions
+#
+# $(call library-path,<module>,<libname>) will resolve to the library file name.
+
+# Per library variables.
+
+# <library>_SOURCES .c source files for library. Paths are relative to src/<module>/native.
+# <library>_CXXSOURCES .c source files for library. Paths are relative to src/<module>/native.
+# <library>_HEADERS header files for install/jmod
+# <library>_COMMANDS commands/bin/scripts for install/jmod
+
+# <library>_LDFLAGS link flags
+# <library>_LIBADD extra objects to add to link line
+# <library>_LDLIBS link libraries
+# <library>_CPPFLAGS c and c++ pre-processor flags. "-Isrc/<module>/jni -Ibin/include/<module>" is implicit.
+# <library>_CCFLAGS c compiler flags
+# <library>_CXXFLAGS c++ compiler flags
+
+# <library>_DEPENDENCIES A list of other objects on which this library depends before linking.
+
+# .c and .cc files have dependencies automatically generated
+
+# Targets
+# -------
+
+# make gen only generate java sources
+# make clean rm -rf bin
+# make dist create dist tar in bin/
+# make | make jar make all jars and jmods
+
+# Outputs
+# -------
+
+# All intermediate and output files are written to bin/
+
+# This layout is enforced by javac
+# bin/include/<module>/ .h files from javac -h
+# bin/modules/<module>/ .class files from javac
+
+# This layout is convenient for netbeans
+# bin/gen/<module>/gen/ .c, exe files for generator free use
+# bin/gen/<module>/classes/ .java files from generator <module>_JAVA_GENERATED
+
+# Working files
+# bin/status/ marker files for makefile
+
+# bin/<module>/<target>/lib .so librareies for jmod <module>_LIBRARIES = libname
+# bin/<module>/<target>/obj .o, .d files for library <libname>_SOURCES
+# bin/<module>/<target>/include .h files for jmod <libname>_HEADERS
+# bin/<module>/<target>/<module>.jmod .jmod module
+
+# Output files
+# bin/<target>/lib/ modular jar files and shared libraries for GNU/linux dev
+# bin/<target>/include/ header files for exported shared libraries
+# bin/<target>/bin/ shared libraries for microsoft dev
+# bin/<target>/jmods/ jmod files for 'jlink' use.
+
+# ######################################################################
+
+all_MODULES = $(java_MODULES) $(native_MODULES)
+
+E:=
+S:=$(E) $(E)
+SO=$($(TARGET)_SO)
+LIB=$($(TARGET)_LIB)
+
+# Define some useful variables before including fragments
+define common_variables=
+$1_gendir:=bin/gen/$1/gen
+$1_genjavadir:=bin/gen/$1/classes
+$1_objdir:=bin/$1/$(TARGET)/obj
+$1_incdir:=bin/$1/$(TARGET)/include
+$1_libdir:=$$(if $$(filter windows-%,$(TARGET)),bin/$1/$(TARGET)/bin,bin/$1/$(TARGET)/lib)
+$1_bindir:=bin/$1/$(TARGET)/bin
+endef
+
+define java_variables=
+ifndef $1_JAVA
+$1_JAVA := $$(shell cd src/$1/classes && find * -type f -name '*.java')
+endif
+ifndef $1_RESOURCES
+$1_RESOURCES := $$(shell cd src/$1/classes && find * -type f \! -name '*.java')
+endif
+endef
+
+java_libdir:=$(if $(filter windows-%,$(TARGET)),bin/$(TARGET)/bin,bin/$(TARGET)/lib)
+java_bindir:=bin/$(TARGET)/bin
+java_jardir:=bin/$(TARGET)/lib
+java_incdir:=bin/$(TARGET)/include
+java_jmoddir:=bin/$(TARGET)/jmods
+
+$(foreach module,$(java_MODULES) $(native_MODULES),$(eval $(call common_variables,$(module))))
+$(foreach module,$(java_MODULES),$(eval $(call java_variables,$(module))))
+
+# ######################################################################
+
+all:
+jar:
+gen:
+
+.PHONY: all clean jar gen $(java_MODULES)
+clean:
+ rm -rf bin
+
+# Gen is things that go into the jar (sources and resources)
+include $(wildcard $(all_MODULES:%=src/%/gen/gen.make))
+# Native is things that go into the sdk/jmod
+include $(wildcard $(all_MODULES:%=src/%/native/native.make))
+
+# ######################################################################
+
+# create module depencies
+# variables:
+# <module>_sdk is the target location of an expanded 'sdk' for this module
+# it resides in a common location bin/<target>/
+# <module>_jmod is the target location of a staging area for jmod files
+# is resides in a per-module lcoation bin/<module>/<target>/
+# <module>_java is all the targets that will cause the invocation of javac
+# it includes the module source, generated sources, and sentinals for generated sources
+
+# targets:
+# bin/status/<module>.depjava marks all source/generated sources are ready/updated
+# bin/status/<module>.depjar all compiled class files and resources are ready/updated
+# bin/status/<module>.sdk all files are available in bin/<target> as if it was an installed image
+
+define module_vars=
+$1_sdk := $(addprefix $(java_bindir)/,$($1_COMMANDS)) $(addprefix $(java_libdir)/,$($1_LIBRARIES)) $($1_NATIVE_LIBRARIES:%=$(java_libdir)/lib%.so)
+$1_jmod := $(addprefix $($1_bindir)/,$($1_COMMANDS)) $(addprefix $($1_libdir)/,$($1_LIBRARIES)) $($1_NATIVE_LIBRARIES:%=$($1_libdir)/lib%.so)
+$1_java :=$($1_JAVA:%=src/$1/classes/%) $($1_JAVA_GENERATED:%=$($1_genjavadir)/%)
+$1_resources:= $($1_RESOURCES:%=src/$1/classes/%) $($1_RESOURCES_GENERATED:%=$($1_genjavadir)/%)
+$1_depjava := $($1_API:%=bin/status/$1-%.export) $(patsubst %,bin/status/%.classes, $(filter $($1_JDEPMOD),$(java_MODULES)))
+
+ifneq ("$$(strip $$($1_java) $$($1_depjava))", "")
+bin/status/$1.depjava: $$($1_java) $$($1_depjava)
+ @install -d $$(@D)
+ touch $$@
+bin/status/$1.depjar: bin/status/$1.classes $$($1_resources)
+ @install -d $$(@D)
+ touch $$@
+bin/status/$1.depmod: bin/status/$1.classes $$($1_resources) $$($1_jmod)
+ @install -d $$(@D)
+ touch $$@
+bin/status/$1.sdk: $(java_jardir)/$1.jar
+jar: $(java_jardir)/$1.jar
+gen: bin/status/$1.depjava
+$1 all: $(java_jardir)/$1.jar $(java_jmoddir)/$1.jmod
+else
+# acutally not sure here?
+$1 all: bin/status/$1.sdk
+endif
+
+$1-sdk sdk: bin/status/$1.sdk
+
+bin/status/$1.sdk: $$($1_sdk) $$($1_jmod)
+ @install -d $$(@D)
+ touch $$@
+
+endef
+
+#$(foreach m,$(all_MODULES),$(info $(call module_vars,$m)))
+$(foreach m,$(all_MODULES),$(eval $(call module_vars,$m)))
+
+# ######################################################################
+# notzed.nativez export-api
+# ######################################################################
+
+define api_targets=
+bin/status/$1-$2.export: src/$1/gen/$2.api src/$1/gen/$2.h
+bin/status/$1-$2.export:
+ mkdir -p bin/gen/$1/gen bin/status
+ $(NATIVEZ_HOME)/bin/export-api \
+ -w bin/gen/$1/gen -d bin/gen/$1/classes $($1_APIFLAGS) $($1_$2_APIFLAGS) src/$1/gen/$2.api
+ touch $$@
+
+bin/status/$1-$2.export.d:
+ @$(NATIVEZ_HOME)/bin/export-api -M -MT "$$(@:.d=) $$@" -MF $$@ \
+ -w bin/gen/$1/gen -d bin/gen/$1/classes $($1_APIFLAGS) $($1_$2_APIFLAGS) src/$1/gen/$2.api 2>/dev/null
+
+$(if $(filter clean dist gen,$(MAKECMDGOALS)),,-include bin/status/$1-$2.export.d)
+endef
+
+$(foreach m,$(all_MODULES),$(foreach a,$($m_API),$(eval $(call api_targets,$m,$a))))
+
+# ######################################################################
+# Java
+# ######################################################################
+
+# Build targets for java modules
+
+define java_targets=
+
+# Create (modular) jar
+$(java_jardir)/$1.jar: bin/status/$1.depjar
+ @install -d $$(@D)
+ $(JAR) cf $$@ \
+ $(JARFLAGS) $$($(1)_JARFLAGS) \
+ -C bin/modules/$(1) . \
+ $(if $($1_RESOURCES),$($1_RESOURCES:%=-C src/$1/classes %)) \
+ $(if $($1_RESOURCES_GENERATED),$($1_RESOURCES_GENERATED:%=-C bin/gen/$1/classes %))
+
+# Create a jmod
+$(java_jmoddir)/$1.jmod: bin/status/$1.depmod
+ rm -f $$@
+ @install -d $$(@D)
+ $$(JMOD) create \
+ $$(JMODFLAGS) $$($(1)_JMODFLAGS) \
+ --target-platform $(TARGET) \
+ --class-path bin/modules/$(1) \
+ $$(if $$(wildcard bin/$(1)/$(TARGET)/include),--header-files bin/$(1)/$(TARGET)/include) \
+ $$(if $$(wildcard src/$(1)/legal),--legal-notices src/$(1)/legal) \
+ $$(if $$(wildcard bin/$(1)/$(TARGET)/bin),--cmds bin/$(1)/$(TARGET)/bin) \
+ $$(if $$(wildcard bin/$(1)/$(TARGET)/lib),--libs bin/$(1)/$(TARGET)/lib) \
+ $$@
+
+# Create an IDE source zip, paths have to match --module-source-path
+$(java_jardir)/$1-sources.zip: bin/status/$1.depjar
+ @install -d $$(@D)
+ $(JAR) -c -f $$@ -M \
+ $$($1_JAVA:%=-C src/$1/classes %) \
+ $$($1_JAVA_GENERATED:%=-C bin/gen/$1/classes %)
+
+# resources
+bin/modules/$1/%: src/$1/classes/%
+ install -vD $$< $$@
+
+# Compile module.
+bin/status/$1.classes: bin/status/$1.depjava
+ @install -d $$(@D)
+ $(JAVAC) \
+ --module-source-path "src/*/classes:bin/gen/*/classes" \
+ $(if $(JAVAMODPATH),--module-path $(subst $(S),:,$(JAVAMODPATH))) \
+ $(JAVACFLAGS) $($1_JAVACFLAGS) \
+ -d bin/modules \
+ -m $1 \
+ $$($1_JAVA:%=src/$1/classes/%) \
+ $$($1_JAVA_GENERATED:%=bin/gen/$1/classes/%)
+ touch $$@
+endef
+
+#$(foreach module,$(java_MODULES),$(info $(call java_targets,$(module))))
+$(foreach module,$(java_MODULES),$(eval $(call java_targets,$(module))))
+
+# ######################################################################
+
+# setup run-* targets
+define run_targets=
+run-$1/$2: bin/status/$1.sdk $($1_JDEPMOD:%=bin/status/%.sdk)
+ LD_LIBRARY_PATH=$(FFMPEG_HOME)/lib \
+ $(JAVA) \
+ $(if $(strip $(JAVAMODPATH) $($1_JAVAMODPATH)),--module-path $(subst $(S),:,$(strip $(JAVAMODPATH) $($1_JAVAMODPATH)))) \
+ $(JMAINFLAGS) $($1_JMAINFLAGS) \
+ -m $1/$2 \
+ $(ARGV)
+.PHONY: run-$1/$2
+endef
+
+#$(foreach module,$(java_MODULES),$(foreach main,$($(module)_JMAIN),$(info $(call run_targets,$(module),$(main)))))
+$(foreach module,$(java_MODULES),$(foreach main,$($(module)_JMAIN),$(eval $(call run_targets,$(module),$(main)))))
+
+# ######################################################################
+# C and c++ native library support
+# ######################################################################
+
+define native_library=
+# Rule for library $$2 in module $$1
+$2_OBJS = $(patsubst %.c, $($1_objdir)/%.o, $($2_SOURCES)) \
+ $(patsubst %.cc, $($1_objdir)/%.o, $($2_CXXSOURCES))
+$2_SRCS = $(addprefix src/$1/native/,$($2_SOURCES))
+$2_SO = $($1_libdir)/$(LIB)$2$(SO)
+
+# Copy anything from staging area for jmods bin/module/<target>/* to sdk area bin/<target>/*
+$(java_libdir)/%: $($(1)_libdir)/%
+ @install -d $$(@D)
+ ln -fs $$(abspath $$<) $$@
+$(java_bindir)/%: $($(1)_bindir)/%
+ @install -d $$(@D)
+ ln -fs $$(abspath $$<) $$@
+$(java_incdir)/%: $($(1)_incdir)/%
+ @install -d $$(@D)
+ ln -fs $$(abspath $$<) $$@
+
+$($1_libdir)/$(LIB)$2$(SO): $$($2_OBJS) $($2_LIBADD) $($2_DEPENDENCIES)
+ @install -d $$(@D)
+ $($(TARGET)_CC) -o $$@ -shared \
+ $($(TARGET)_LDFLAGS) $($2_LDFLAGS) $$($2_OBJS) $($2_LIBADD) $($(TARGET)_LDLIBS) $($2_LDLIBS)
+
+$($1_objdir)/%.o: src/$1/native/%.c
+ @install -d $$(@D)
+ $($(TARGET)_CC) -Isrc/$1/native -Ibin/include/$1 \
+ $($(TARGET)_CPPFLAGS) $($2_CPPFLAGS) \
+ $($(TARGET)_CFLAGS) $($2_CFLAGS) -c -o $$@ $$<
+
+$($1_objdir)/%.o: src/$1/native/%.cc
+ @install -d $$(@D)
+ $($(TARGET)_CXX) -Isrc/$1/native -Ibin/include/$1 \
+ $($(TARGET)_CPPFLAGS) $($2_CPPFLAGS) \
+ $($(TARGET)_CXXFLAGS) $($2_CXXFLAGS) -c -o $$@ $$<
+
+# auto-dependencies for c files
+$($1_objdir)/%.d: src/$1/native/%.c
+ @install -d $$(@D)
+ @rm -f $$@
+ @$($(TARGET)_CC) -MM -MT "$$(@:.d=.o) $$@" -Isrc/$1/jni -Ibin/include/$1 \
+ $($(TARGET)_CPPFLAGS) $($2_CPPFLAGS) $$< -o $$@ 2>/dev/null
+
+# auto-dependencies for c++ files
+$($1_objdir)/%.d: src/$1/native/%.cc
+ @install -d $$(@D)
+ @rm -f $$@
+ @$($(TARGET)_CXX) -MM -MT "$$(@:.d=.o) $$@" -Isrc/$1/jni -Ibin/include/$1 \
+ $($(TARGET)_CPPFLAGS) $($2_CPPFLAGS) $$< -o $$@ 2>/dev/null
+
+$(if $(filter clean dist gen,$(MAKECMDGOALS)),,-include $$($2_OBJS:.o=.d))
+endef
+
+#$(foreach module,$(all_MODULES),$(foreach library,$($(module)_NATIVE_LIBRARIES),$(info $(call native_library,$(module),$(library)))))
+$(foreach module,$(all_MODULES),$(foreach library,$($(module)_NATIVE_LIBRARIES),$(eval $(call native_library,$(module),$(library)))))
+
+# ######################################################################
+
+dist:
+ @install -d bin
+ tar cfz bin/$(dist_NAME)-$(dist_VERSION).tar.gz \
+ --transform=s,^,$(dist_NAME)-$(dist_VERSION)/, \
+ config.make.in java.make Makefile src \
+ $(dist_EXTRA)
--- /dev/null
+#
+# Copyright (C) 2021 Michael Zucchi
+#
+# This is the copyright for maven.make
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# This lets one download maven packages using simple automake syntax.
+
+# maven_<name>_URL = baseurl
+
+# Define the base url. maven_central_URL is already defined as
+# maven_central_URL:=https://repo1.maven.org/maven2
+
+# maven_<name>_JARS = group:artifact:version group:artifact:version ...
+
+# Define the artifacts required from the given maven repository.
+
+# That's it!
+
+# It defines several make targets.
+
+# make maven-init
+# Will download the jar files.
+
+# make maven-verify
+# Will download and check the signatures using gpg. The public key
+# required for verification must be imported to gpg separately.
+
+# make distclean
+# Will delete .lib
+
+# define maven central
+maven_central_URL:=https://repo1.maven.org/maven2
+maven_repository_URL:=https://mvnrepository.com/artifact
+
+# find out what repositories the makefile defined
+maven_REPOS=$(patsubst maven_%_URL,%,$(filter maven_%_URL,$(.VARIABLES)))
+
+# (group artifact version baseurl)
+define maven_func=
+.lib/$2-$3.jar:
+ mkdir -p .lib
+ wget -O $$@ $(4)/$(subst .,/,$1)/$2/$3/$2-$3.jar || ( rm $$@ ; exit 1 )
+.lib/$2-$3.jar.asc: .lib/$2-$3.jar
+ wget -O $$@ $(4)/$(subst .,/,$1)/$2/$3/$2-$3.jar.asc
+ gpg --batch --verify $$@ $$< || ( rm $$@ ; echo "GPG verification failed, you may need to import the public key." ; exit 1 )
+maven-init: .lib/$2-$3.jar
+maven-verify: .lib/$2-$3.jar.asc
+endef
+
+maven-init:
+maven-verify:
+
+.PHONY: maven-init maven-verify
+
+$(foreach repo,$(maven_REPOS),\
+ $(foreach jar,$(maven_$(repo)_JARS), \
+ $(eval $(call maven_func,$(word 1,$(subst :, ,$(jar))),$(word 2,$(subst :, ,$(jar))),$(word 3,$(subst :, ,$(jar))),$(maven_$(repo)_URL)))))
+
+distclean:
+ rm -rf .lib
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+*** GENERATED FROM project.xml - DO NOT EDIT ***
+*** EDIT ../build.xml INSTEAD ***
+
+For the purpose of easier reading the script
+is divided into following sections:
+
+ - initialization
+ - compilation
+ - jar
+ - execution
+ - debugging
+ - javadoc
+ - test compilation
+ - test execution
+ - test debugging
+ - applet
+ - cleanup
+
+ -->
+<project xmlns:if="ant:if" xmlns:unless="ant:unless" basedir=".." default="default" name="vulkanz-impl">
+ <fail message="Please build using Ant 1.9.7 or higher.">
+ <condition>
+ <not>
+ <antversion atleast="1.9.7"/>
+ </not>
+ </condition>
+ </fail>
+ <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
+ <!--
+ ======================
+ INITIALIZATION SECTION
+ ======================
+ -->
+ <target name="-pre-init">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="-pre-init" name="-init-private">
+ <property file="nbproject/private/config.properties"/>
+ <property file="nbproject/private/configs/${config}.properties"/>
+ <property file="nbproject/private/private.properties"/>
+ </target>
+ <target depends="-pre-init,-init-private" name="-init-user">
+ <property file="${user.properties.file}"/>
+ <!-- The two properties below are usually overridden -->
+ <!-- by the active platform. Just a fallback. -->
+ <property name="default.javac.source" value="9"/>
+ <property name="default.javac.target" value="9"/>
+ </target>
+ <target depends="-pre-init,-init-private,-init-user" name="-init-pre-project">
+ <property file="nbproject/configs/${config}.properties"/>
+ <property file="nbproject/project.properties"/>
+ <property name="netbeans.modular.tasks.version" value="1"/>
+ <property location="${build.dir}/tasks/${netbeans.modular.tasks.version}" name="netbeans.modular.tasks.dir"/>
+ </target>
+ <target depends="-init-pre-project" name="-check-netbeans-tasks">
+ <condition property="netbeans.tasks.compiled">
+ <available file="${netbeans.modular.tasks.dir}/out/netbeans/ModuleInfoSelector.class"/>
+ </condition>
+ </target>
+ <target depends="-init-pre-project,-check-netbeans-tasks" name="-init-compile-netbeans-tasks" unless="netbeans.tasks.compiled">
+ <echo file="${netbeans.modular.tasks.dir}/src/netbeans/CoalesceKeyvalue.java">
+
+package netbeans;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+public class CoalesceKeyvalue extends Task {
+ private String property;
+
+ public void setProperty(String property) {
+ this.property = property;
+ }
+
+ private String value;
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ private String valueSep;
+
+ public void setValueSep(String valueSep) {
+ this.valueSep = valueSep;
+ }
+
+ private String entrySep;
+
+ public void setEntrySep(String entrySep) {
+ this.entrySep = entrySep;
+ }
+
+ private String multiSep;
+
+ public void setMultiSep(String multiSep) {
+ this.multiSep = multiSep;
+ }
+
+ private String outSep;
+
+ public void setOutSep(String outSep) {
+ this.outSep = outSep;
+ }
+
+ @Override
+ public void execute() throws BuildException {
+ List<String> result = new ArrayList<>();
+ Map<String, List<String>> module2Paths = new HashMap<>();
+
+ for (String entry : value.split(Pattern.quote(entrySep))) {
+ String[] keyValue = entry.split(Pattern.quote(valueSep), 2);
+ if (keyValue.length == 1) {
+ result.add(keyValue[0]);
+ } else {
+ module2Paths.computeIfAbsent(keyValue[0], s -> new ArrayList<>())
+ .add(keyValue[1].trim());
+ }
+ }
+ module2Paths.entrySet()
+ .stream()
+ .forEach(e -> result.add(e.getKey() + valueSep + e.getValue().stream().collect(Collectors.joining(multiSep))));
+ getProject().setProperty(property, result.stream().collect(Collectors.joining(" " + entrySep)));
+ }
+
+}
+
+ </echo>
+ <echo file="${netbeans.modular.tasks.dir}/src/netbeans/ModsourceRegexp.java">
+
+package netbeans;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+public class ModsourceRegexp extends Task {
+ private String property;
+
+ public void setProperty(String property) {
+ this.property = property;
+ }
+
+ private String filePattern;
+
+ public void setFilePattern(String filePattern) {
+ this.filePattern = filePattern;
+ }
+
+ private String modsource;
+
+ public void setModsource(String modsource) {
+ this.modsource = modsource;
+ }
+
+ private List<String> expandGroup(String grp) {
+ List<String> exp = new ArrayList<>();
+ String item = "";
+ int depth = 0;
+
+ for (int i = 0; i < grp.length(); i++) {
+ char c = grp.charAt(i);
+ switch (c) {
+ case '{':
+ if (depth++ == 0) {
+ continue;
+ }
+ break;
+ case '}':
+ if (--depth == 0) {
+ exp.add(item);
+ continue;
+ }
+ break;
+ case ',':
+ if (depth == 1) {
+ exp.add(item);
+ item = "";
+ continue;
+ }
+ default:
+ break;
+ }
+ item = item + c;
+ }
+ return exp;
+ }
+
+ private List<String> pathVariants(String spec) {
+ return pathVariants(spec, new ArrayList<>());
+ }
+
+ private List<String> pathVariants(String spec, List<String> res) {
+ int start = spec.indexOf('{');
+ if (start == -1) {
+ res.add(spec);
+ return res;
+ }
+ int depth = 1;
+ int end;
+ for (end = start + 1; end < spec.length() && depth > 0; end++) {
+ char c = spec.charAt(end);
+ switch (c) {
+ case '{': depth++; break;
+ case '}': depth--; break;
+ }
+ }
+ String prefix = spec.substring(0, start);
+ String suffix = spec.substring(end);
+ expandGroup(spec.substring(start, end)).stream().forEach(item -> {
+ pathVariants(prefix + item + suffix, res);
+ });
+ return res;
+ }
+
+ private String toRegexp2(String spec, String filepattern, String separator) {
+ List<String> prefixes = new ArrayList<>();
+ List<String> suffixes = new ArrayList<>();
+ pathVariants(spec).forEach(item -> {
+ suffixes.add(item);
+ });
+ String tail = "";
+ String separatorString = separator;
+ if ("\\".equals(separatorString)) {
+ separatorString = "\\\\";
+ }
+ if (filepattern != null && !Objects.equals(filepattern, tail)) {
+ tail = separatorString + filepattern;
+ }
+ return "([^" + separatorString +"]+)\\Q" + separator + "\\E(" + suffixes.stream().collect(Collectors.joining("|")) + ")" + tail;
+ }
+
+ @Override
+ public void execute() throws BuildException {
+ getProject().setProperty(property, toRegexp2(modsource, filePattern, getProject().getProperty("file.separator")));
+ }
+
+}
+
+ </echo>
+ <echo file="${netbeans.modular.tasks.dir}/src/netbeans/ModuleInfoSelector.java">
+
+package netbeans;
+
+import java.io.File;
+import java.util.Arrays;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.selectors.BaseExtendSelector;
+
+public class ModuleInfoSelector extends BaseExtendSelector {
+
+ @Override
+ public boolean isSelected(File basedir, String filename, File file) throws BuildException {
+ String extension = Arrays.stream(getParameters())
+ .filter(p -> "extension".equals(p.getName()))
+ .map(p -> p.getValue())
+ .findAny()
+ .get();
+ return !new File(file, "module-info." + extension).exists();
+ }
+
+}
+
+ </echo>
+ <mkdir dir="${netbeans.modular.tasks.dir}/out"/>
+ <javac classpath="${ant.core.lib}" destdir="${netbeans.modular.tasks.dir}/out" srcdir="${netbeans.modular.tasks.dir}/src"/>
+ </target>
+ <target depends="-init-pre-project,-init-compile-netbeans-tasks" name="-init-project">
+ <taskdef classname="netbeans.CoalesceKeyvalue" classpath="${netbeans.modular.tasks.dir}/out" name="coalesce_keyvalue" uri="http://www.netbeans.org/ns/j2se-modular-project/1"/>
+ <taskdef classname="netbeans.ModsourceRegexp" classpath="${netbeans.modular.tasks.dir}/out" name="modsource_regexp" uri="http://www.netbeans.org/ns/j2se-modular-project/1"/>
+ </target>
+ <target name="-init-source-module-properties">
+ <property name="javac.modulepath" value=""/>
+ <property name="run.modulepath" value="${javac.modulepath}:${build.modules.dir}"/>
+ <property name="debug.modulepath" value="${run.modulepath}"/>
+ <property name="javac.upgrademodulepath" value=""/>
+ <property name="run.upgrademodulepath" value="${javac.upgrademodulepath}"/>
+ <condition else="" property="javac.systemmodulepath.cmd.line.arg" value="-system '${javac.systemmodulepath}'">
+ <and>
+ <isset property="javac.systemmodulepath"/>
+ <length length="0" string="${javac.systemmodulepath}" when="greater"/>
+ </and>
+ </condition>
+ <property name="dist.jlink.dir" value="${dist.dir}/jlink"/>
+ <property name="dist.jlink.output" value="${dist.jlink.dir}/${application.title}"/>
+ </target>
+ <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
+ <property name="platform.java" value="${java.home}/bin/java"/>
+ <j2semodularproject1:modsource_regexp xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" modsource="${test.src.dir.path}" property="have.tests.test.src.dir.regexp"/>
+ <dirset dir="${basedir}/${test.src.dir}" id="have.tests.test.src.dir.set" includes="*/*">
+ <filename regex="${have.tests.test.src.dir.regexp}"/>
+ </dirset>
+ <union id="have.tests.set">
+ <dirset refid="have.tests.test.src.dir.set"/>
+ </union>
+ <condition property="have.tests">
+ <or>
+ <resourcecount count="0" when="greater">
+ <union refid="have.tests.set"/>
+ </resourcecount>
+ </or>
+ </condition>
+ <j2semodularproject1:modsource_regexp xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" modsource="${test.src.dir.path}" property="have.tests.test.src.dir.regexp"/>
+ <dirset dir="${basedir}/${test.src.dir}" id="have.tests.test.src.dir.patchset" includes="*/*">
+ <filename regex="${have.tests.test.src.dir.regexp}"/>
+ </dirset>
+ <union id="have.tests.patchset">
+ <dirset refid="have.tests.test.src.dir.patchset"/>
+ </union>
+ <j2semodularproject1:modsource_regexp xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" modsource="${src.dir.path}" property="have.sources.src.dir.regexp"/>
+ <dirset dir="${basedir}/${src.dir}" id="have.sources.src.dir.set" includes="*/*">
+ <filename regex="${have.sources.src.dir.regexp}"/>
+ </dirset>
+ <j2semodularproject1:modsource_regexp xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" modsource="${src.gen.dir.path}" property="have.sources.src.gen.dir.regexp"/>
+ <dirset dir="${basedir}/${src.gen.dir}" id="have.sources.src.gen.dir.set" includes="*/*">
+ <filename regex="${have.sources.src.gen.dir.regexp}"/>
+ </dirset>
+ <union id="have.sources.set">
+ <dirset refid="have.sources.src.dir.set"/>
+ <dirset refid="have.sources.src.gen.dir.set"/>
+ </union>
+ <condition property="have.sources">
+ <or>
+ <resourcecount count="0" when="greater">
+ <union refid="have.sources.set"/>
+ </resourcecount>
+ <resourcecount count="0" when="greater">
+ <union refid="have.sources.set"/>
+ </resourcecount>
+ </or>
+ </condition>
+ <condition property="main.class.available">
+ <and>
+ <isset property="main.class"/>
+ <not>
+ <equals arg1="${main.class}" arg2="" trim="true"/>
+ </not>
+ </and>
+ </condition>
+ <condition property="netbeans.home+have.tests">
+ <and>
+ <isset property="netbeans.home"/>
+ <isset property="have.tests"/>
+ </and>
+ </condition>
+ <condition property="no.javadoc.preview">
+ <and>
+ <isset property="javadoc.preview"/>
+ <isfalse value="${javadoc.preview}"/>
+ </and>
+ </condition>
+ <condition property="do.archive">
+ <or>
+ <not>
+ <istrue value="${jar.archive.disabled}"/>
+ </not>
+ <istrue value="${not.archive.disabled}"/>
+ </or>
+ </condition>
+ <property name="run.jvmargs" value=""/>
+ <property name="run.jvmargs.ide" value=""/>
+ <property name="javac.compilerargs" value=""/>
+ <property name="work.dir" value="${basedir}"/>
+ <condition property="no.deps">
+ <and>
+ <istrue value="${no.dependencies}"/>
+ </and>
+ </condition>
+ <property name="javac.debug" value="true"/>
+ <property name="javadoc.preview" value="true"/>
+ <property name="application.args" value=""/>
+ <property name="source.encoding" value="${file.encoding}"/>
+ <property name="runtime.encoding" value="${source.encoding}"/>
+ <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
+ <and>
+ <isset property="javadoc.encoding"/>
+ <not>
+ <equals arg1="${javadoc.encoding}" arg2=""/>
+ </not>
+ </and>
+ </condition>
+ <property name="javadoc.encoding.used" value="${source.encoding}"/>
+ <property name="includes" value="**"/>
+ <property name="excludes" value=""/>
+ <property name="do.depend" value="false"/>
+ <condition property="do.depend.true">
+ <istrue value="${do.depend}"/>
+ </condition>
+ <path id="endorsed.classpath.path" path="${endorsed.classpath}"/>
+ <condition else="" property="endorsed.classpath.cmd.line.arg" value="-Xbootclasspath/p:'${toString:endorsed.classpath.path}'">
+ <and>
+ <isset property="endorsed.classpath"/>
+ <not>
+ <equals arg1="${endorsed.classpath}" arg2="" trim="true"/>
+ </not>
+ </and>
+ </condition>
+ <condition else="" property="javac.profile.cmd.line.arg" value="-profile ${javac.profile}">
+ <isset property="profile.available"/>
+ </condition>
+ <condition else="false" property="jdkBug6558476">
+ <and>
+ <matches pattern="1\.[56]" string="${java.specification.version}"/>
+ <not>
+ <os family="unix"/>
+ </not>
+ </and>
+ </condition>
+ <condition else="false" property="javac.fork">
+ <or>
+ <istrue value="${jdkBug6558476}"/>
+ <istrue value="${javac.external.vm}"/>
+ </or>
+ </condition>
+ <condition property="main.class.check.available">
+ <and>
+ <isset property="libs.CopyLibs.classpath"/>
+ <available classname="org.netbeans.modules.java.j2seproject.moduletask.ModuleMainClass" classpath="${libs.CopyLibs.classpath}"/>
+ </and>
+ </condition>
+ <property name="jar.index" value="false"/>
+ <property name="jar.index.metainf" value="${jar.index}"/>
+ <condition property="junit.available">
+ <or>
+ <available classname="org.junit.Test" classpath="${run.test.classpath}"/>
+ <available classname="junit.framework.Test" classpath="${run.test.classpath}"/>
+ </or>
+ </condition>
+ <condition property="testng.available">
+ <available classname="org.testng.annotations.Test" classpath="${run.test.classpath}"/>
+ </condition>
+ <condition property="junit+testng.available">
+ <and>
+ <istrue value="${junit.available}"/>
+ <istrue value="${testng.available}"/>
+ </and>
+ </condition>
+ <condition else="testng" property="testng.mode" value="mixed">
+ <istrue value="${junit+testng.available}"/>
+ </condition>
+ <condition else="" property="testng.debug.mode" value="-mixed">
+ <istrue value="${junit+testng.available}"/>
+ </condition>
+ <property name="java.failonerror" value="true"/>
+ <macrodef name="for-paths" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute name="paths"/>
+ <attribute default="${path.separator}" name="separator"/>
+ <element implicit="yes" name="call"/>
+ <sequential>
+ <local name="entry"/>
+ <local name="tail"/>
+ <local name="moreElements"/>
+ <loadresource property="entry" quiet="true" unless:blank="@{paths}">
+ <concat>@{paths}</concat>
+ <filterchain>
+ <replaceregex pattern="([^@{separator}]*)\Q@{separator}\E.*" replace="\1"/>
+ </filterchain>
+ </loadresource>
+ <sequential if:set="entry">
+ <call/>
+ </sequential>
+ <condition else="false" property="moreElements" value="true">
+ <contains string="@{paths}" substring="@{separator}"/>
+ </condition>
+ <loadresource if:true="${moreElements}" property="tail" quiet="true">
+ <concat>@{paths}</concat>
+ <filterchain>
+ <replaceregex pattern="[^@{separator}]*\Q@{separator}\E(.*)" replace="\1"/>
+ </filterchain>
+ </loadresource>
+ <j2semodularproject1:for-paths xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" if:true="${moreElements}" paths="${tail}">
+ <call/>
+ </j2semodularproject1:for-paths>
+ </sequential>
+ </macrodef>
+ <property name="modules.supported.internal" value="true"/>
+ <condition else="${file.separator}" property="file.separator.string" value="\${file.separator}">
+ <equals arg1="${file.separator}" arg2="\"/>
+ </condition>
+ </target>
+ <target name="-post-init">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
+ <fail unless="src.dir">Must set src.dir</fail>
+ <fail unless="src.gen.dir">Must set src.gen.dir</fail>
+ <fail unless="test.src.dir">Must set test.src.dir</fail>
+ <fail unless="build.dir">Must set build.dir</fail>
+ <fail unless="dist.dir">Must set dist.dir</fail>
+ <fail unless="build.modules.dir">Must set build.modules.dir</fail>
+ <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
+ <fail unless="build.test.modules.dir">Must set build.test.modules.dir</fail>
+ <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
+ <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
+ <fail message="Java 9 support requires Ant 1.10.0 or higher.">
+ <condition>
+ <not>
+ <antversion atleast="1.10.0"/>
+ </not>
+ </condition>
+ </fail>
+ </target>
+ <target name="-init-macrodef-property">
+ <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute name="name"/>
+ <attribute name="value"/>
+ <sequential>
+ <property name="@{name}" value="${@{value}}"/>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-ap-cmdline-properties,-init-source-module-properties" name="-init-macrodef-javac">
+ <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute default="${build.modules.dir}" name="destdir"/>
+ <attribute default="${javac.classpath}" name="classpath"/>
+ <attribute default="${javac.modulepath}" name="modulepath"/>
+ <attribute default="${src.dir}/*/${src.dir.path}:${src.gen.dir}/*/${src.gen.dir.path}" name="modulesourcepath"/>
+ <attribute default="${javac.upgrademodulepath}" name="upgrademodulepath"/>
+ <attribute default="${javac.processorpath}" name="processorpath"/>
+ <attribute default="${javac.processormodulepath}" name="processormodulepath"/>
+ <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="${javac.debug}" name="debug"/>
+ <attribute default="${empty.dir}" name="gensrcdir"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <property location="${build.dir}/empty" name="empty.dir"/>
+ <mkdir dir="${empty.dir}"/>
+ <mkdir dir="@{apgeneratedsrcdir}"/>
+ <condition property="processormodulepath.set">
+ <resourcecount count="0" when="greater">
+ <path>
+ <pathelement path="@{processormodulepath}"/>
+ </path>
+ </resourcecount>
+ </condition>
+ <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" target="${javac.target}" tempdir="${java.io.tmpdir}">
+ <classpath>
+ <path path="@{classpath}"/>
+ </classpath>
+ <modulepath>
+ <path path="@{modulepath}"/>
+ </modulepath>
+ <modulesourcepath>
+ <path path="@{modulesourcepath}"/>
+ </modulesourcepath>
+ <upgrademodulepath>
+ <path path="@{upgrademodulepath}"/>
+ </upgrademodulepath>
+ <compilerarg line="${javac.systemmodulepath.cmd.line.arg}"/>
+ <compilerarg line="${javac.profile.cmd.line.arg}"/>
+ <compilerarg line="${javac.compilerargs}"/>
+ <compilerarg if:set="processormodulepath.set" value="--processor-module-path"/>
+ <compilerarg if:set="processormodulepath.set" path="@{processormodulepath}"/>
+ <compilerarg unless:set="processormodulepath.set" value="-processorpath"/>
+ <compilerarg path="@{processorpath}:${empty.dir}" unless:set="processormodulepath.set"/>
+ <compilerarg line="${ap.processors.internal}"/>
+ <compilerarg line="${annotation.processing.processor.options}"/>
+ <compilerarg value="-s"/>
+ <compilerarg path="@{apgeneratedsrcdir}"/>
+ <compilerarg line="${ap.proc.none.internal}"/>
+ <customize/>
+ </javac>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-javac" name="-init-macrodef-javac-depend">
+ <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute default="${src.dir}:${src.gen.dir}" name="srcdir"/>
+ <attribute default="${build.classes.dir}" name="destdir"/>
+ <attribute default="${javac.classpath}" name="classpath"/>
+ <sequential>
+ <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
+ <classpath>
+ <path path="@{classpath}"/>
+ </classpath>
+ </depend>
+ </sequential>
+ </macrodef>
+ <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute default="${build.modules.dir}" name="destdir"/>
+ <sequential>
+ <fail unless="javac.includes">Must set javac.includes</fail>
+ <pathconvert pathsep="${line.separator}" property="javac.includes.binary">
+ <path>
+ <filelist dir="@{destdir}" files="${javac.includes}"/>
+ </path>
+ <globmapper from="*.java" to="*.class"/>
+ </pathconvert>
+ <tempfile deleteonexit="true" property="javac.includesfile.binary"/>
+ <echo file="${javac.includesfile.binary}" message="${javac.includes.binary}"/>
+ <delete>
+ <files includesfile="${javac.includesfile.binary}"/>
+ </delete>
+ <delete>
+ <fileset file="${javac.includesfile.binary}"/>
+ </delete>
+ </sequential>
+ </macrodef>
+ </target>
+ <target if="${junit.available}" name="-init-macrodef-junit-init">
+ <condition else="false" property="nb.junit.batch" value="true">
+ <and>
+ <istrue value="${junit.available}"/>
+ <not>
+ <isset property="test.method"/>
+ </not>
+ </and>
+ </condition>
+ <condition else="false" property="nb.junit.single" value="true">
+ <and>
+ <istrue value="${junit.available}"/>
+ <isset property="test.method"/>
+ </and>
+ </condition>
+ </target>
+ <target name="-init-test-properties">
+ <property name="test.binaryincludes" value="<nothing>"/>
+ <property name="test.binarytestincludes" value=""/>
+ <property name="test.binaryexcludes" value=""/>
+ </target>
+ <target name="-init-macrodef-junit-prototype">
+ <macrodef name="junit-prototype" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <element name="customizePrototype" optional="true"/>
+ <sequential>
+ <property location="${build.dir}/empty" name="empty.dir"/>
+ <property name="junit.forkmode" value="perTest"/>
+ <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+ <syspropertyset>
+ <propertyref prefix="test-sys-prop."/>
+ <mapper from="test-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ <classpath>
+ <path path="${run.test.classpath}"/>
+ </classpath>
+ <formatter type="brief" usefile="false"/>
+ <formatter type="xml"/>
+ <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+ <jvmarg value="-ea"/>
+ <jvmarg value="--module-path"/>
+ <jvmarg path="${run.modulepath}${path.separator}${run.test.modulepath}${path.separator}${empty.dir}"/>
+ <jvmarg line="${run.test.jvmargs}"/>
+ <customizePrototype/>
+ </junit>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-test-properties,-init-macrodef-junit-prototype" if="${nb.junit.single}" name="-init-macrodef-junit-single" unless="${nb.junit.batch}">
+ <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <j2semodularproject1:junit-prototype xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <customizePrototype>
+ <test methods="@{testmethods}" name="@{testincludes}" todir="${build.test.results.dir}"/>
+ <customize/>
+ </customizePrototype>
+ </j2semodularproject1:junit-prototype>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-test-properties,-init-macrodef-junit-prototype" if="${nb.junit.batch}" name="-init-macrodef-junit-batch" unless="${nb.junit.single}">
+ <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <j2semodularproject1:junit-prototype xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <customizePrototype>
+ <batchtest todir="${build.test.results.dir}">
+ <mappedresources>
+ <union>
+ <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="**/@{includes}">
+ <filename name="**/@{testincludes}"/>
+ <filename regex="${have.tests.test.src.dir.regexp}"/>
+ </fileset>
+ </union>
+ <regexpmapper from="${have.tests.test.src.dir.regexp}\Q${file.separator}\E(.*)$" to="\3"/>
+ </mappedresources>
+ <fileset dir="${build.test.modules.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
+ <filename name="${test.binarytestincludes}"/>
+ </fileset>
+ </batchtest>
+ <customize/>
+ </customizePrototype>
+ </j2semodularproject1:junit-prototype>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-junit-init,-init-macrodef-junit-single, -init-macrodef-junit-batch" if="${junit.available}" name="-init-macrodef-junit"/>
+ <target if="${testng.available}" name="-init-macrodef-testng">
+ <macrodef name="testng" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <condition else="" property="testng.methods.arg" value="@{testincludes}.@{testmethods}">
+ <isset property="test.method"/>
+ </condition>
+ <union id="test.set">
+ <fileset dir="${test.src.dir}" excludes="@{excludes},**/*.xml,${excludes}" includes="@{includes}">
+ <filename name="@{testincludes}"/>
+ </fileset>
+ </union>
+ <taskdef classname="org.testng.TestNGAntTask" classpath="${run.test.classpath}" name="testng"/>
+ <testng classfilesetref="test.set" failureProperty="tests.failed" listeners="org.testng.reporters.VerboseReporter" methods="${testng.methods.arg}" mode="${testng.mode}" outputdir="${build.test.results.dir}" suitename="vulkanz" testname="TestNG tests" workingDir="${work.dir}">
+ <xmlfileset dir="${build.test.classes.dir}" includes="@{testincludes}"/>
+ <propertyset>
+ <propertyref prefix="test-sys-prop."/>
+ <mapper from="test-sys-prop.*" to="*" type="glob"/>
+ </propertyset>
+ <classpath>
+ <path path="${run.test.classpath}"/>
+ </classpath>
+ <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+ <customize/>
+ </testng>
+ </sequential>
+ </macrodef>
+ </target>
+ <target name="-init-macrodef-test-impl">
+ <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element implicit="true" name="customize" optional="true"/>
+ <sequential>
+ <echo>No tests executed.</echo>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-junit" if="${junit.available}" name="-init-macrodef-junit-impl">
+ <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element implicit="true" name="customize" optional="true"/>
+ <sequential>
+ <j2semodularproject1:junit xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+ <customize/>
+ </j2semodularproject1:junit>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-testng" if="${testng.available}" name="-init-macrodef-testng-impl">
+ <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element implicit="true" name="customize" optional="true"/>
+ <sequential>
+ <j2semodularproject1:testng xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+ <customize/>
+ </j2semodularproject1:testng>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-test-impl,-init-macrodef-junit-impl,-init-macrodef-testng-impl" name="-init-macrodef-test">
+ <macrodef name="test" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <sequential>
+ <j2semodularproject1:test-impl xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+ <customize>
+ <jvmarg line="${run.jvmargs}"/>
+ <jvmarg line="${run.jvmargs.ide}"/>
+ </customize>
+ </j2semodularproject1:test-impl>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-junit" if="${junit.available}" name="-init-macrodef-junit-debug-impl">
+ <macrodef name="test-debug-impl" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element name="customizeDebuggee" optional="true"/>
+ <sequential>
+ <j2semodularproject1:junit xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+ <customize>
+ <jvmarg value="-agentlib:jdwp=transport=${debug-transport},address=${jpda.address}"/>
+ <customizeDebuggee/>
+ </customize>
+ </j2semodularproject1:junit>
+ </sequential>
+ </macrodef>
+ </target>
+ <target if="${testng.available}" name="-init-macrodef-testng-debug">
+ <macrodef name="testng-debug" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute default="${main.class}" name="testClass"/>
+ <attribute default="" name="testMethod"/>
+ <element name="customize2" optional="true"/>
+ <sequential>
+ <condition else="-testclass @{testClass}" property="test.class.or.method" value="-methods @{testClass}.@{testMethod}">
+ <isset property="test.method"/>
+ </condition>
+ <condition else="-suitename vulkanz -testname @{testClass} ${test.class.or.method}" property="testng.cmd.args" value="@{testClass}">
+ <matches pattern=".*\.xml" string="@{testClass}"/>
+ </condition>
+ <delete dir="${build.test.results.dir}" quiet="true"/>
+ <mkdir dir="${build.test.results.dir}"/>
+ <j2semodularproject1:debug xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" classname="org.testng.TestNG" classpath="${debug.test.classpath}">
+ <customizeDebuggee>
+ <customize2/>
+ <jvmarg value="-ea"/>
+ <arg line="${testng.debug.mode}"/>
+ <arg line="-d ${build.test.results.dir}"/>
+ <arg line="-listener org.testng.reporters.VerboseReporter"/>
+ <arg line="${testng.cmd.args}"/>
+ </customizeDebuggee>
+ </j2semodularproject1:debug>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-testng-debug" if="${testng.available}" name="-init-macrodef-testng-debug-impl">
+ <macrodef name="testng-debug-impl" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute default="${main.class}" name="testClass"/>
+ <attribute default="" name="testMethod"/>
+ <element implicit="true" name="customize2" optional="true"/>
+ <sequential>
+ <j2semodularproject1:testng-debug xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" testClass="@{testClass}" testMethod="@{testMethod}">
+ <customize2/>
+ </j2semodularproject1:testng-debug>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-junit-debug-impl" if="${junit.available}" name="-init-macrodef-test-debug-junit">
+ <macrodef name="test-debug" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <attribute default="${main.class}" name="testClass"/>
+ <attribute default="" name="testMethod"/>
+ <sequential>
+ <j2semodularproject1:test-debug-impl xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+ <customizeDebuggee>
+ <jvmarg line="${run.jvmargs}"/>
+ <jvmarg line="${run.jvmargs.ide}"/>
+ </customizeDebuggee>
+ </j2semodularproject1:test-debug-impl>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-testng-debug-impl" if="${testng.available}" name="-init-macrodef-test-debug-testng">
+ <macrodef name="test-debug" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <attribute default="${main.class}" name="testClass"/>
+ <attribute default="" name="testMethod"/>
+ <sequential>
+ <j2semodularproject1:testng-debug-impl xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" testClass="@{testClass}" testMethod="@{testMethod}">
+ <customize2>
+ <syspropertyset>
+ <propertyref prefix="test-sys-prop."/>
+ <mapper from="test-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ </customize2>
+ </j2semodularproject1:testng-debug-impl>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-test-debug-junit,-init-macrodef-test-debug-testng" name="-init-macrodef-test-debug"/>
+ <!--
+ pre NB7.2 profiling section; consider it deprecated
+ -->
+ <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile, -profile-init-check" if="profiler.info.jvmargs.agent" name="profile-init"/>
+ <target if="profiler.info.jvmargs.agent" name="-profile-pre-init">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target if="profiler.info.jvmargs.agent" name="-profile-post-init">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target if="profiler.info.jvmargs.agent" name="-profile-init-macrodef-profile">
+ <macrodef name="resolve">
+ <attribute name="name"/>
+ <attribute name="value"/>
+ <sequential>
+ <property name="@{name}" value="${env.@{value}}"/>
+ </sequential>
+ </macrodef>
+ <macrodef name="profile">
+ <attribute default="${main.class}" name="classname"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <property environment="env"/>
+ <resolve name="profiler.current.path" value="${profiler.info.pathvar}"/>
+ <java classname="@{classname}" dir="${profiler.info.dir}" failonerror="${java.failonerror}" fork="true" jvm="${profiler.info.jvm}">
+ <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+ <jvmarg value="${profiler.info.jvmargs.agent}"/>
+ <jvmarg line="${profiler.info.jvmargs}"/>
+ <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
+ <arg line="${application.args}"/>
+ <classpath>
+ <path path="${run.classpath}"/>
+ </classpath>
+ <syspropertyset>
+ <propertyref prefix="run-sys-prop."/>
+ <mapper from="run-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ <customize/>
+ </java>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile" if="profiler.info.jvmargs.agent" name="-profile-init-check">
+ <fail unless="profiler.info.jvm">Must set JVM to use for profiling in profiler.info.jvm</fail>
+ <fail unless="profiler.info.jvmargs.agent">Must set profiler agent JVM arguments in profiler.info.jvmargs.agent</fail>
+ </target>
+ <!--
+ end of pre NB7.2 profiling section
+ -->
+ <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
+ <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute default="${main.class}" name="name"/>
+ <attribute default="${debug.modulepath}" name="modulepath"/>
+ <attribute default="${debug.classpath}" name="classpath"/>
+ <attribute default="" name="stopclassname"/>
+ <sequential>
+ <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
+ <modulepath>
+ <path path="@{modulepath}"/>
+ </modulepath>
+ <classpath>
+ <path path="@{classpath}"/>
+ </classpath>
+ </nbjpdastart>
+ </sequential>
+ </macrodef>
+ <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute default="${debug.modules.dir}" name="dir"/>
+ <sequential>
+ <nbjpdareload>
+ <fileset dir="@{dir}" includes="${fix.classes}">
+ <include name="*/${fix.includes}*.class"/>
+ </fileset>
+ </nbjpdareload>
+ </sequential>
+ </macrodef>
+ </target>
+ <target name="-init-debug-args">
+ <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
+ <os family="windows"/>
+ </condition>
+ <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
+ <isset property="debug.transport"/>
+ </condition>
+ </target>
+ <target depends="-init-debug-args" name="-init-macrodef-debug">
+ <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute default="${module.name}" name="modulename"/>
+ <attribute default="${main.class}" name="classname"/>
+ <attribute default="${debug.modulepath}" name="modulepath"/>
+ <attribute default="${debug.classpath}" name="classpath"/>
+ <element name="customizeDebuggee" optional="true"/>
+ <sequential>
+ <j2semodularproject1:java xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" classname="@{classname}" classpath="@{classpath}" modulename="@{modulename}" modulepath="@{modulepath}">
+ <customize>
+ <jvmarg value="-agentlib:jdwp=transport=${debug-transport},address=${jpda.address}"/>
+ <customizeDebuggee/>
+ </customize>
+ </j2semodularproject1:java>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-source-module-properties" name="-init-macrodef-java">
+ <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute default="${module.name}" name="modulename"/>
+ <attribute default="${main.class}" name="classname"/>
+ <attribute default="${run.modulepath}" name="modulepath"/>
+ <attribute default="${run.upgrademodulepath}" name="upgrademodulepath"/>
+ <attribute default="${run.classpath}" name="classpath"/>
+ <attribute default="jvm" name="jvm"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <java classname="@{classname}" dir="${work.dir}" failonerror="${java.failonerror}" fork="true" module="@{modulename}">
+ <classpath>
+ <path path="@{classpath}"/>
+ </classpath>
+ <modulepath>
+ <path path="@{modulepath}"/>
+ </modulepath>
+ <upgrademodulepath>
+ <path path="@{upgrademodulepath}"/>
+ </upgrademodulepath>
+ <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+ <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+ <jvmarg line="${run.jvmargs}"/>
+ <jvmarg line="${run.jvmargs.ide}"/>
+ <syspropertyset>
+ <propertyref prefix="run-sys-prop."/>
+ <mapper from="run-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ <customize/>
+ </java>
+ </sequential>
+ </macrodef>
+ </target>
+ <target name="-init-presetdef-jar">
+ <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <jar compress="${jar.compress}" index="${jar.index}" jarfile="${dist.jar}" manifestencoding="UTF-8">
+ <j2semodularproject1:fileset xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" dir="${build.classes.dir}" excludes="${dist.archive.excludes}"/>
+ </jar>
+ </presetdef>
+ </target>
+ <target name="-init-ap-cmdline-properties">
+ <property name="annotation.processing.enabled" value="true"/>
+ <property name="annotation.processing.processors.list" value=""/>
+ <property name="annotation.processing.processor.options" value=""/>
+ <property name="annotation.processing.run.all.processors" value="true"/>
+ <property name="javac.processorpath" value="${javac.classpath}"/>
+ <property name="javac.test.processorpath" value="${javac.test.classpath}"/>
+ </target>
+ <target depends="-init-ap-cmdline-properties" name="-init-ap-cmdline-supported">
+ <condition else="" property="ap.processors.internal" value="-processor ${annotation.processing.processors.list}">
+ <isfalse value="${annotation.processing.run.all.processors}"/>
+ </condition>
+ <condition else="" property="ap.proc.none.internal" value="-proc:none">
+ <isfalse value="${annotation.processing.enabled}"/>
+ </condition>
+ </target>
+ <target depends="-init-ap-cmdline-properties,-init-ap-cmdline-supported" name="-init-ap-cmdline">
+ <property name="ap.cmd.line.internal" value=""/>
+ </target>
+ <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac-depend,-init-macrodef-test,-init-macrodef-test-debug,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar,-init-ap-cmdline" name="init"/>
+ <!--
+ ===================
+ COMPILATION SECTION
+ ===================
+ -->
+ <target name="-deps-jar-init" unless="built-jar.properties">
+ <property location="${build.dir}/built-jar.properties" name="built-jar.properties"/>
+ <delete file="${built-jar.properties}" quiet="true"/>
+ </target>
+ <target if="already.built.jar.${basedir}" name="-warn-already-built-jar">
+ <echo level="warn" message="Cycle detected: vulkanz was already built"/>
+ </target>
+ <target depends="init,-deps-jar-init" name="deps-jar" unless="no.deps">
+ <mkdir dir="${build.dir}"/>
+ <touch file="${built-jar.properties}" verbose="false"/>
+ <property file="${built-jar.properties}" prefix="already.built.jar."/>
+ <antcall target="-warn-already-built-jar"/>
+ <propertyfile file="${built-jar.properties}">
+ <entry key="${basedir}" value=""/>
+ </propertyfile>
+ <antcall target="-maybe-call-dep">
+ <param name="call.built.properties" value="${built-jar.properties}"/>
+ <param location="${project.notzed_nativez}" name="call.subproject"/>
+ <param location="${project.notzed_nativez}/build.xml" name="call.script"/>
+ <param name="call.target" value="jar"/>
+ <param name="transfer.built-jar.properties" value="${built-jar.properties}"/>
+ <param name="transfer.not.archive.disabled" value="true"/>
+ <param name="transfer.do.jlink" value="false"/>
+ </antcall>
+ </target>
+ <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
+ <target depends="init" name="-check-automatic-build">
+ <available file="${build.modules.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
+ </target>
+ <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
+ <antcall target="clean">
+ <param name="no.dependencies" value="true"/>
+ </antcall>
+ </target>
+ <target name="-pre-pre-compile">
+ <mkdir dir="${build.modules.dir}"/>
+ </target>
+ <target name="-pre-compile">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target if="do.depend.true" name="-compile-depend">
+ <pathconvert property="build.generated.subdirs">
+ <dirset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+ <include name="*"/>
+ </dirset>
+ </pathconvert>
+ <j2semodularproject1:depend xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" srcdir="${src.dir}:${src.gen.dir}:${build.generated.subdirs}"/>
+ </target>
+ <target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
+ <j2semodularproject1:javac xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" gensrcdir="${build.generated.sources.dir}"/>
+ <j2semodularproject1:modsource_regexp xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" filePattern="(.*$)" modsource="${src.dir.path}" property="src.dir.path.regexp"/>
+ <echo message="Copying resources from ${src.dir}"/>
+ <copy todir="${build.modules.dir}">
+ <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+ <regexpmapper from="${src.dir.path.regexp}" to="\1/\3"/>
+ </copy>
+ <j2semodularproject1:modsource_regexp xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" filePattern="(.*$)" modsource="${src.gen.dir.path}" property="src.gen.dir.path.regexp"/>
+ <echo message="Copying resources from ${src.gen.dir}"/>
+ <copy todir="${build.modules.dir}">
+ <fileset dir="${src.gen.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+ <regexpmapper from="${src.gen.dir.path.regexp}" to="\1/\3"/>
+ </copy>
+ </target>
+ <target if="has.persistence.xml" name="-copy-persistence-xml">
+ <fail message="XXX: Not supported on MM projects"/>
+ <mkdir dir="${build.classes.dir}/META-INF"/>
+ <copy todir="${build.classes.dir}/META-INF">
+ <fileset dir="${meta.inf.dir}" includes="persistence.xml orm.xml"/>
+ </copy>
+ </target>
+ <target name="-post-compile">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
+ <target name="-pre-compile-single">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,deps-jar" name="-do-compile-single">
+ <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+ <j2semodularproject1:force-recompile xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1"/>
+ <j2semodularproject1:javac xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}, module-info.java"/>
+ </target>
+ <target name="-post-compile-single">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
+ <!--
+ ====================
+ JAR BUILDING SECTION
+ ====================
+ -->
+ <target depends="init,compile" name="-check-module-main-class">
+ <condition property="do.module.main.class">
+ <and>
+ <available file="${module.dir}/module-info.class"/>
+ <isset property="main.class.check.available"/>
+ </and>
+ </condition>
+ </target>
+ <target depends="init" name="-pre-pre-jar">
+ <dirname file="${dist.jar}" property="dist.jar.dir"/>
+ <mkdir dir="${dist.jar.dir}"/>
+ </target>
+ <target name="-pre-jar">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target name="-pre-single-jar"/>
+ <target depends="-pre-single-jar" if="module.jar.filename" name="-make-single-jar">
+ <jar basedir="${module.dir}" compress="${jar.compress}" destfile="${dist.dir}/${module.jar.filename}" excludes="${dist.archive.excludes}" manifestencoding="UTF-8"/>
+ </target>
+ <target depends="init,compile,-pre-pre-jar,-pre-jar,-main-module-check-condition" if="do.archive" name="-do-jar-jar" unless="do.mkdist">
+ <property location="${build.modules.dir}" name="build.modules.dir.resolved"/>
+ <dirset dir="${build.modules.dir.resolved}" id="do.jar.dirs" includes="*"/>
+ <pathconvert property="do.jar.dir.list" refid="do.jar.dirs">
+ <identitymapper/>
+ </pathconvert>
+ <j2semodularproject1:for-paths xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" paths="${do.jar.dir.list}">
+ <local name="module.jar.filename"/>
+ <local name="module.jar.name.tmp"/>
+ <basename file="${entry}" property="module.jar.name.tmp"/>
+ <property name="module.jar.filename" value="${module.jar.name.tmp}.jar"/>
+ <antcall inheritRefs="true" target="-make-single-jar">
+ <param name="module.jar.filename" value="${module.jar.filename}"/>
+ <param location="${entry}" name="module.dir"/>
+ </antcall>
+ </j2semodularproject1:for-paths>
+ <condition property="named.module.internal">
+ <and>
+ <isset property="module.name"/>
+ <length length="0" string="${module.name}" when="greater"/>
+ </and>
+ </condition>
+ <condition property="unnamed.module.internal">
+ <not>
+ <isset property="named.module.internal"/>
+ </not>
+ </condition>
+ <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+ <property location="${dist.jar}" name="dist.jar.resolved"/>
+ <pathconvert property="run.classpath.with.dist.jar">
+ <path path="${run.classpath}"/>
+ <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
+ </pathconvert>
+ <pathconvert property="run.modulepath.with.dist.jar">
+ <path path="${run.modulepath}"/>
+ <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
+ </pathconvert>
+ <condition else="" property="jar.usage.message.module.path" value=" --module-path ${run.modulepath.with.dist.jar}">
+ <and>
+ <isset property="modules.supported.internal"/>
+ <length length="0" string="${run.modulepath.with.dist.jar}" when="greater"/>
+ </and>
+ </condition>
+ <condition else="" property="jar.usage.message.class.path" value=" -cp ${run.classpath.with.dist.jar}">
+ <length length="0" string="${run.classpath.with.dist.jar}" when="greater"/>
+ </condition>
+ <condition else=" ${main.class}" property="jar.usage.message.main.class" value=" -m ${module.name}/${main.class}">
+ <isset property="named.module.internal"/>
+ </condition>
+ <condition else="" property="jar.usage.message" value="To run this application from the command line without Ant, try:${line.separator}${platform.java}${jar.usage.message.module.path}${jar.usage.message.class.path}${jar.usage.message.main.class}">
+ <isset property="main.class.available"/>
+ </condition>
+ <condition else="debug" property="jar.usage.level" value="info">
+ <isset property="main.class.available"/>
+ </condition>
+ <echo level="${jar.usage.level}" message="${jar.usage.message}"/>
+ </target>
+ <target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-jar" name="-do-jar-without-libraries"/>
+ <target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-with-libraries"/>
+ <target name="-post-jar">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,compile,-pre-jar,-do-jar-without-libraries,-do-jar-with-libraries,-post-jar" name="-do-jar"/>
+ <target depends="init,compile,-pre-jar,-do-jar,-post-jar,deploy" description="Build JAR." name="jar"/>
+ <!--
+ =================
+ DEPLOY SECTION
+ =================
+ -->
+ <target name="-pre-deploy">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init" name="-check-jlink">
+ <condition property="do.jlink.internal">
+ <and>
+ <istrue value="${do.jlink}"/>
+ <isset property="do.archive"/>
+ </and>
+ </condition>
+ </target>
+ <target depends="init,-do-jar,-post-jar,-pre-deploy,-check-jlink,-main-module-set" if="do.jlink.internal" name="-do-deploy">
+ <delete dir="${dist.jlink.dir}" failonerror="false" quiet="true"/>
+ <property name="jlink.launcher.name" value="${application.title}"/>
+ <pathconvert pathsep="," property="jlink.modulelist.internal">
+ <fileset dir="${dist.dir}" includes="*.jar"/>
+ <mapper>
+ <chainedmapper>
+ <flattenmapper/>
+ <globmapper from="*.jar" to="*"/>
+ </chainedmapper>
+ </mapper>
+ </pathconvert>
+ <condition else="${jlink.modulelist.internal}" property="jlink.add.modules" value="${jlink.modulelist.internal},${jlink.additionalmodules}">
+ <and>
+ <isset property="jlink.additionalmodules"/>
+ <length length="0" string="${jlink.additionalmodules}" when="greater"/>
+ </and>
+ </condition>
+ <condition property="jlink.do.strip.internal">
+ <and>
+ <isset property="jlink.strip"/>
+ <istrue value="${jlink.strip}"/>
+ </and>
+ </condition>
+ <condition property="jlink.do.additionalparam.internal">
+ <and>
+ <isset property="jlink.additionalparam"/>
+ <length length="0" string="${jlink.additionalparam}" when="greater"/>
+ </and>
+ </condition>
+ <condition property="jlink.do.launcher.internal">
+ <and>
+ <istrue value="${jlink.launcher}"/>
+ <isset property="module.name"/>
+ <length length="0" string="${module.name}" when="greater"/>
+ <isset property="main.class.available"/>
+ </and>
+ </condition>
+ <property name="platform.jlink" value="${jdk.home}/bin/jlink"/>
+ <property name="jlink.systemmodules.internal" value="${jdk.home}/jmods"/>
+ <exec executable="${platform.jlink}">
+ <arg value="--module-path"/>
+ <arg path="${jlink.systemmodules.internal}:${run.modulepath}:${dist.dir}"/>
+ <arg value="--add-modules"/>
+ <arg value="${jlink.add.modules}"/>
+ <arg if:set="jlink.do.strip.internal" value="--strip-debug"/>
+ <arg if:set="jlink.do.launcher.internal" value="--launcher"/>
+ <arg if:set="jlink.do.launcher.internal" value="${jlink.launcher.name}=${module.name}/${main.class}"/>
+ <arg if:set="jlink.do.additionalparam.internal" line="${jlink.additionalparam}"/>
+ <arg value="--output"/>
+ <arg value="${dist.jlink.output}"/>
+ </exec>
+ </target>
+ <target name="-post-deploy">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="-do-jar,-post-jar,-pre-deploy,-do-deploy,-post-deploy" name="deploy"/>
+ <!--
+ =================
+ EXECUTION SECTION
+ =================
+ -->
+ <target name="-check-main-class">
+ <fail unless="main.class">No main class specified</fail>
+ </target>
+ <target depends="init,compile,-check-main-class,-main-module-check" description="Run a main class." name="run">
+ <property name="main.class.relativepath" refid="main.class.relativepath"/>
+ <pathconvert pathsep="," property="src.dir.list" refid="have.sources.set"/>
+ <j2semodularproject1:modsource_regexp xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" filePattern="(.*$)" modsource="${src.dir.path}" property="run.src.dir.path.regexp"/>
+ <j2semodularproject1:java xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <customize>
+ <arg line="${application.args}"/>
+ </customize>
+ </j2semodularproject1:java>
+ </target>
+ <target name="-main-module-set" unless="module.name">
+ <condition else="${main.class}" property="check.class.name" value="${run.class}">
+ <isset property="run.class"/>
+ </condition>
+ <condition property="run.modules.dir" value="${build.modules.dir}">
+ <not>
+ <isset property="run.modules.dir"/>
+ </not>
+ </condition>
+ <resources id="main.class.relativepath">
+ <mappedresources>
+ <string value="${check.class.name}"/>
+ <unpackagemapper from="*" to="*.class"/>
+ </mappedresources>
+ </resources>
+ <property location="${run.modules.dir}" name="run.modules.dir.location"/>
+ <pathconvert property="module.name">
+ <fileset dir="${run.modules.dir}" includes="**/${toString:main.class.relativepath}"/>
+ <regexpmapper from="\Q${run.modules.dir.location}${file.separator}\E([^${file.separator.string}]+)\Q${file.separator}\E.*\.class" to="\1"/>
+ </pathconvert>
+ </target>
+ <target depends="-main-module-set" name="-main-module-check">
+ <fail message="Could not determine module of the main class and module.name is not set">
+ <condition>
+ <or>
+ <not>
+ <isset property="module.name"/>
+ </not>
+ <length length="0" string="${module.name}" when="equal"/>
+ </or>
+ </condition>
+ </fail>
+ </target>
+ <target depends="-main-module-set" if="main.class.available" name="-main-module-check-condition">
+ <fail message="Could not determine module of the main class and module.name is not set">
+ <condition>
+ <or>
+ <not>
+ <isset property="module.name"/>
+ </not>
+ <length length="0" string="${module.name}" when="equal"/>
+ </or>
+ </condition>
+ </fail>
+ </target>
+ <target name="-do-not-recompile">
+ <property name="javac.includes.binary" value=""/>
+ </target>
+ <target depends="init,compile-single,-main-module-check" name="run-single">
+ <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+ <j2semodularproject1:java xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" classname="${run.class}"/>
+ </target>
+ <target depends="init,compile-test-single,-init-test-run-module-properties,-main-module-check" name="run-test-with-main">
+ <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+ <j2semodularproject1:java xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" classname="${run.class}" classpath="${run.test.classpath}" modulepath="${run.test.modulepath}">
+ <customize>
+ <jvmarg line="${run.test.jvmargs}"/>
+ </customize>
+ </j2semodularproject1:java>
+ </target>
+ <!--
+ =================
+ DEBUGGING SECTION
+ =================
+ -->
+ <target name="-debug-init">
+ <condition else="${main.class}" property="run.class" value="${debug.class}">
+ <isset property="debug.class"/>
+ </condition>
+ <fail message="debug.class or main.class property is not set" unless="run.class"/>
+ </target>
+ <target depends="init,-debug-init,-main-module-check" if="netbeans.home" name="-debug-start-debugger">
+ <j2semodularproject1:nbjpdastart xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" name="${debug.class}"/>
+ </target>
+ <target depends="init,-debug-init,-main-module-check" if="netbeans.home" name="-debug-start-debugger-main-test">
+ <j2semodularproject1:nbjpdastart xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" classpath="${debug.test.classpath}" name="${debug.class}"/>
+ </target>
+ <target depends="init,compile,-debug-init,-main-module-check" name="-debug-start-debuggee">
+ <j2semodularproject1:debug xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" classname="${run.class}">
+ <customizeDebuggee>
+ <arg line="${application.args}"/>
+ </customizeDebuggee>
+ </j2semodularproject1:debug>
+ </target>
+ <target depends="init,compile,-debug-init,-main-module-check,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
+ <target depends="init,-debug-init,-main-module-check" if="netbeans.home" name="-debug-start-debugger-stepinto">
+ <j2semodularproject1:nbjpdastart xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" stopclassname="${debug.class}"/>
+ </target>
+ <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
+ <target depends="init,compile-single,-debug-init,-main-module-check" if="netbeans.home" name="-debug-start-debuggee-single">
+ <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+ <j2semodularproject1:debug xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" classname="${debug.class}"/>
+ </target>
+ <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
+ <target depends="init,compile-test-single,-debug-init,-main-module-check" if="netbeans.home" name="-debug-start-debuggee-main-test">
+ <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+ <j2semodularproject1:debug xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" classname="${debug.class}" classpath="${debug.test.classpath}"/>
+ </target>
+ <target depends="init,compile-test-single,-debug-start-debugger-main-test,-debug-start-debuggee-main-test" if="netbeans.home" name="debug-test-with-main"/>
+ <target depends="init" name="-pre-debug-fix">
+ <fail unless="fix.includes">Must set fix.includes</fail>
+ <property name="javac.includes" value="${fix.includes}.java"/>
+ </target>
+ <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
+ <property location="${build.modules.dir}" name="debug.modules.dir"/>
+ <j2semodularproject1:nbjpdareload xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1"/>
+ </target>
+ <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
+ <!--
+ =================
+ PROFILING SECTION
+ =================
+ -->
+ <!--
+ pre NB7.2 profiler integration
+ -->
+ <target depends="profile-init,compile" description="Profile a project in the IDE." if="profiler.info.jvmargs.agent" name="-profile-pre72">
+ <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+ <nbprofiledirect>
+ <classpath>
+ <path path="${run.classpath}"/>
+ </classpath>
+ </nbprofiledirect>
+ <profile/>
+ </target>
+ <target depends="profile-init,compile-single" description="Profile a selected class in the IDE." if="profiler.info.jvmargs.agent" name="-profile-single-pre72">
+ <fail unless="profile.class">Must select one file in the IDE or set profile.class</fail>
+ <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+ <nbprofiledirect>
+ <classpath>
+ <path path="${run.classpath}"/>
+ </classpath>
+ </nbprofiledirect>
+ <profile classname="${profile.class}"/>
+ </target>
+ <target depends="profile-init,compile-single" if="profiler.info.jvmargs.agent" name="-profile-applet-pre72">
+ <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+ <nbprofiledirect>
+ <classpath>
+ <path path="${run.classpath}"/>
+ </classpath>
+ </nbprofiledirect>
+ <profile classname="sun.applet.AppletViewer">
+ <customize>
+ <arg value="${applet.url}"/>
+ </customize>
+ </profile>
+ </target>
+ <target depends="-init-macrodef-junit,profile-init,compile-test-single" if="profiler.info.jvmargs.agent" name="-profile-test-single-pre72">
+ <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+ <nbprofiledirect>
+ <classpath>
+ <path path="${run.test.classpath}"/>
+ </classpath>
+ </nbprofiledirect>
+ <j2semodularproject1:junit xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" excludes="${excludes}" includes="${includes}" testincludes="${profile.class}" testmethods="">
+ <customize>
+ <jvmarg value="-agentlib:jdwp=transport=${debug-transport},address=${jpda.address}"/>
+ <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
+ <jvmarg value="${profiler.info.jvmargs.agent}"/>
+ <jvmarg line="${profiler.info.jvmargs}"/>
+ <classpath>
+ <path path="${run.test.classpath}"/>
+ </classpath>
+ </customize>
+ </j2semodularproject1:junit>
+ </target>
+ <!--
+ end of pre NB72 profiling section
+ -->
+ <target if="netbeans.home" name="-profile-check">
+ <condition property="profiler.configured">
+ <or>
+ <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-agentpath:"/>
+ <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-javaagent:"/>
+ </or>
+ </condition>
+ </target>
+ <target depends="-profile-check,-profile-pre72" description="Profile a project in the IDE." if="profiler.configured" name="profile" unless="profiler.info.jvmargs.agent">
+ <startprofiler/>
+ <antcall target="run"/>
+ </target>
+ <target depends="-profile-check,-profile-single-pre72" description="Profile a selected class in the IDE." if="profiler.configured" name="profile-single" unless="profiler.info.jvmargs.agent">
+ <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+ <startprofiler/>
+ <antcall target="run-single"/>
+ </target>
+ <target depends="-profile-test-single-pre72" description="Profile a selected test in the IDE." name="profile-test-single"/>
+ <target depends="-profile-check" description="Profile a selected test in the IDE." if="profiler.configured" name="profile-test" unless="profiler.info.jvmargs">
+ <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
+ <startprofiler/>
+ <antcall target="test-single"/>
+ </target>
+ <target depends="-profile-check" description="Profile a selected class in the IDE." if="profiler.configured" name="profile-test-with-main">
+ <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+ <startprofiler/>
+ <antcall target="run-test-with-main"/>
+ </target>
+ <target depends="-profile-check,-profile-applet-pre72" if="profiler.configured" name="profile-applet" unless="profiler.info.jvmargs.agent">
+ <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+ <startprofiler/>
+ <antcall target="run-applet"/>
+ </target>
+ <!--
+ ===============
+ JAVADOC SECTION
+ ===============
+ -->
+ <target depends="init" if="have.sources" name="-javadoc-build">
+ <mkdir dir="${dist.javadoc.dir}"/>
+ <condition else="" property="javadoc.endorsed.classpath.cmd.line.arg" value="-J${endorsed.classpath.cmd.line.arg}">
+ <and>
+ <isset property="endorsed.classpath.cmd.line.arg"/>
+ <not>
+ <equals arg1="${endorsed.classpath.cmd.line.arg}" arg2=""/>
+ </not>
+ </and>
+ </condition>
+ <condition else="" property="bug5101868workaround" value="*.java">
+ <matches pattern="1\.[56](\..*)?" string="${java.version}"/>
+ </condition>
+ <condition else="" property="javadoc.html5.cmd.line.arg" value="-html5">
+ <and>
+ <isset property="javadoc.html5"/>
+ <available file="${jdk.home}${file.separator}lib${file.separator}jrt-fs.jar"/>
+ </and>
+ </condition>
+ <javadoc additionalparam="-J-Dfile.encoding=${file.encoding} ${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
+ <classpath>
+ <path path="${javac.classpath}"/>
+ </classpath>
+ <fileset dir="${src.dir}" excludes="${bug5101868workaround},${excludes}" includes="${includes}">
+ <filename name="**/*.java"/>
+ </fileset>
+ <fileset dir="${src.gen.dir}" excludes="${bug5101868workaround},${excludes}" includes="${includes}">
+ <filename name="**/*.java"/>
+ </fileset>
+ <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+ <include name="**/*.java"/>
+ <exclude name="*.java"/>
+ </fileset>
+ <arg line="${javadoc.endorsed.classpath.cmd.line.arg}"/>
+ <arg line="${javadoc.html5.cmd.line.arg}"/>
+ </javadoc>
+ <copy todir="${dist.javadoc.dir}">
+ <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
+ <filename name="**/doc-files/**"/>
+ </fileset>
+ <fileset dir="${src.gen.dir}" excludes="${excludes}" includes="${includes}">
+ <filename name="**/doc-files/**"/>
+ </fileset>
+ <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+ <include name="**/doc-files/**"/>
+ </fileset>
+ </copy>
+ </target>
+ <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
+ <nbbrowse file="${dist.javadoc.dir}/index.html"/>
+ </target>
+ <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
+ <!--
+ =========================
+ TEST COMPILATION SECTION
+ =========================
+ -->
+ <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
+ <mkdir dir="${build.test.modules.dir}"/>
+ </target>
+ <target name="-pre-compile-test">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="-init-source-module-properties" name="-init-test-run-module-properties">
+ <fileset dir="${build.test.modules.dir}" id="run.test.packages.internal" includes="**/*.class"/>
+ <property location="${build.test.modules.dir}" name="build.test.modules.dir.abs.internal"/>
+ <pathconvert pathsep=" " property="run.test.addexports.internal" refid="run.test.packages.internal">
+ <chainedmapper>
+ <filtermapper>
+ <replacestring from="${build.test.modules.dir.abs.internal}${file.separator}" to=""/>
+ </filtermapper>
+ <regexpmapper from="^([^${file.separator.string}]*)\Q${file.separator}\E(.*)\Q${file.separator}\E.*\.class$$" to="\1${path.separator}\2"/>
+ <filtermapper>
+ <uniqfilter/>
+ <replacestring from="${file.separator}" to="."/>
+ </filtermapper>
+ <regexpmapper from="([^${file.separator.string}]+)${path.separator}(.*)" to="--add-exports \1/\2=ALL-UNNAMED"/>
+ </chainedmapper>
+ </pathconvert>
+ <property location="${build.test.modules.dir}" name="build.test.modules.location"/>
+ <pathconvert pathsep="," property="run.test.addmodules.list">
+ <map from="${build.test.modules.location}${file.separator}" to=""/>
+ <dirset dir="${build.test.modules.dir}" includes="*"/>
+ <chainedmapper>
+ <filtermapper>
+ <uniqfilter/>
+ </filtermapper>
+ </chainedmapper>
+ </pathconvert>
+ <pathconvert pathsep=" " property="run.test.patchmodules.list">
+ <dirset dir="${build.test.modules.dir}" includes="*">
+ <custom classname="netbeans.ModuleInfoSelector" classpath="${netbeans.modular.tasks.dir}/out">
+ <param name="extension" value="class"/>
+ </custom>
+ </dirset>
+ <chainedmapper>
+ <filtermapper>
+ <uniqfilter/>
+ </filtermapper>
+ <regexpmapper from=".*\Q${file.separator}\E([^${file.separator.string}]+)$" to="--patch-module \1=\0"/>
+ </chainedmapper>
+ </pathconvert>
+ <j2semodularproject1:coalesce_keyvalue xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" entrySep="--patch-module " multiSep="${path.separator}" property="run.test.patchmodules" value="${run.test.patchmodules.list}" valueSep="="/>
+ <condition else="" property="run.test.addmodules.internal" value="--add-modules ${run.test.addmodules.list}">
+ <isset property="run.test.addmodules.list"/>
+ </condition>
+ <pathconvert pathsep=" " property="run.test.addreads.internal">
+ <map from="${build.test.modules.location}" to=""/>
+ <dirset dir="${build.test.modules.dir}" includes="*"/>
+ <chainedmapper>
+ <regexpmapper from="^\Q${build.test.modules.location}${file.separator}\E(.*)" to="\1"/>
+ <regexpmapper from="(.*)" to="--add-reads \1=ALL-UNNAMED"/>
+ <filtermapper>
+ <uniqfilter/>
+ </filtermapper>
+ </chainedmapper>
+ </pathconvert>
+ <property name="run.test.jvmargs" value="${run.test.addmodules.internal} ${run.test.addreads.internal} ${run.test.addexports.internal} ${run.test.patchmodules}"/>
+ </target>
+ <target depends="-init-source-module-properties" name="-init-test-javac-module-properties">
+ <pathconvert pathsep=" " property="compile.test.patchmodule.internal" refid="have.tests.patchset">
+ <regexpmapper from="(.*\Q${file.separator}\E)([^${file.separator.string}]+)\Q${file.separator}\E(.*)$$" to="--patch-module \2=\1\2${file.separator.string}\3"/>
+ </pathconvert>
+ <pathconvert pathsep=" " property="compile.test.addreads">
+ <union refid="have.tests.set"/>
+ <chainedmapper>
+ <firstmatchmapper>
+ <regexpmapper from="${have.tests.test.src.dir.regexp}" to="\1"/>
+ </firstmatchmapper>
+ <regexpmapper from="(.*)" to="--add-reads \1=ALL-UNNAMED"/>
+ <filtermapper>
+ <uniqfilter/>
+ </filtermapper>
+ </chainedmapper>
+ </pathconvert>
+ <j2semodularproject1:coalesce_keyvalue xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" entrySep="--patch-module " multiSep="${path.separator}" property="compile.test.patchmodules" value="${compile.test.patchmodule.internal}" valueSep="="/>
+ <property name="javac.test.moduleargs" value="${compile.test.patchmodules} ${compile.test.addreads}"/>
+ </target>
+ <target depends="-init-test-javac-module-properties" name="-init-test-module-properties">
+ <property location="${build.modules.dir}" name="test.module.build.location"/>
+ <property name="test.source.modulepath" value="${test.src.dir}/*/${test.src.dir.path}"/>
+ <property name="test.compile.modulepath" value="${javac.test.modulepath}:${build.modules.dir}"/>
+ <macrodef name="test-javac" uri="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <element implicit="true" name="additionalargs" optional="true"/>
+ <sequential>
+ <j2semodularproject1:javac xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" apgeneratedsrcdir="${build.test.modules.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.modules.dir}" excludes="@{excludes}" includes="@{includes}" modulepath="${test.compile.modulepath}" modulesourcepath="${test.source.modulepath}" processorpath="${javac.test.processorpath}">
+ <customize>
+ <compilerarg line="${javac.test.moduleargs}"/>
+ <additionalargs/>
+ </customize>
+ </j2semodularproject1:javac>
+ </sequential>
+ </macrodef>
+ </target>
+ <target if="do.depend.true" name="-compile-test-depend">
+ <j2semodularproject1:depend xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
+ </target>
+ <target depends="init,deps-jar,compile,-init-test-module-properties,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
+ <j2semodularproject1:test-javac xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1"/>
+ <j2semodularproject1:modsource_regexp xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" filePattern="(.*$)" modsource="${test.src.dir.path}" property="test.src.dir.path.regexp"/>
+ <echo message="Copying resources from ${test.src.dir}"/>
+ <copy todir="${build.test.modules.dir}">
+ <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+ <regexpmapper from="${test.src.dir.path.regexp}" to="\1/\3"/>
+ </copy>
+ </target>
+ <target name="-post-compile-test">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
+ <target name="-pre-compile-test-single">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,deps-jar,compile,-init-test-module-properties,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
+ <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+ <j2semodularproject1:force-recompile xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" destdir="${build.test.modules.dir}"/>
+ <j2semodularproject1:test-javac xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" includes="${javac.includes}"/>
+ <j2semodularproject1:modsource_regexp xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" filePattern="(.*$)" modsource="${test.src.dir.path}" property="test.src.dir.path.regexp"/>
+ <echo message="Copying resources from ${test.src.dir}"/>
+ <copy todir="${build.test.modules.dir}">
+ <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+ <regexpmapper from="${test.src.dir.path.regexp}" to="\1/\3"/>
+ </copy>
+ </target>
+ <target name="-post-compile-test-single">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
+ <!--
+ =======================
+ TEST EXECUTION SECTION
+ =======================
+ -->
+ <target depends="init" if="have.tests" name="-pre-test-run">
+ <mkdir dir="${build.test.results.dir}"/>
+ </target>
+ <target name="-init-test-run">
+ <property name="run.modules.dir" value="${build.test.modules.dir}"/>
+ </target>
+ <target depends="init,compile-test,-init-test-run-module-properties,-pre-test-run" if="have.tests" name="-do-test-run">
+ <j2semodularproject1:test xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" includes="${includes}" testincludes="**/*Test.java"/>
+ </target>
+ <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
+ <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+ </target>
+ <target depends="init" if="have.tests" name="test-report"/>
+ <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
+ <target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
+ <target depends="init" if="have.tests" name="-pre-test-run-single">
+ <mkdir dir="${build.test.results.dir}"/>
+ </target>
+ <target depends="init,compile-test-single,-init-test-run-module-properties,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
+ <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
+ <j2semodularproject1:test xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" excludes="" includes="${test.includes}" testincludes="${test.includes}"/>
+ </target>
+ <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
+ <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+ </target>
+ <target depends="init,compile-test-single,-init-test-run-module-properties,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
+ <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single-method">
+ <fail unless="test.class">Must select some files in the IDE or set test.class</fail>
+ <fail unless="test.method">Must select some method in the IDE or set test.method</fail>
+ <j2semodularproject1:test xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" excludes="" includes="${javac.includes}" testincludes="${test.class}" testmethods="${test.method}"/>
+ </target>
+ <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single-method" if="have.tests" name="-post-test-run-single-method">
+ <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+ </target>
+ <target depends="init,compile-test-single,-init-test-run-module-properties,-pre-test-run-single,-do-test-run-single-method,-post-test-run-single-method" description="Run single unit test." name="test-single-method"/>
+ <!--
+ =======================
+ TEST DEBUGGING SECTION
+ =======================
+ -->
+ <target depends="init,compile-test-single,-init-test-run-module-properties,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test">
+ <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
+ <j2semodularproject1:test-debug xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" excludes="" includes="${javac.includes}" testClass="${test.class}" testincludes="${javac.includes}"/>
+ </target>
+ <target depends="init,compile-test-single,-init-test-run-module-properties,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test-method">
+ <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
+ <fail unless="test.method">Must select some method in the IDE or set test.method</fail>
+ <j2semodularproject1:test-debug xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" excludes="" includes="${javac.includes}" testClass="${test.class}" testMethod="${test.method}" testincludes="${test.class}" testmethods="${test.method}"/>
+ </target>
+ <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
+ <j2semodularproject1:nbjpdastart xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1" classpath="${debug.test.classpath}" name="${test.class}"/>
+ </target>
+ <target depends="init,compile-test-single,-init-test-run-module-properties,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
+ <target depends="init,compile-test-single,-init-test-run-module-properties,-debug-start-debugger-test,-debug-start-debuggee-test-method" name="debug-test-method"/>
+ <target depends="debug-test-method" name="debug-single-method"/>
+ <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
+ <property name="debug.modules.dir" value="${build.test.modules.dir}"/>
+ <j2semodularproject1:nbjpdareload xmlns:j2semodularproject1="http://www.netbeans.org/ns/j2se-modular-project/1"/>
+ </target>
+ <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
+ <!--
+ =========================
+ APPLET EXECUTION SECTION
+ =========================
+ -->
+ <target name="run-applet">
+ <fail message="Applets are no longer supported by JDK 9"/>
+ </target>
+ <!--
+ =========================
+ APPLET DEBUGGING SECTION
+ =========================
+ -->
+ <target name="-debug-start-debuggee-applet">
+ <fail message="Applets are no longer supported by JDK 9"/>
+ </target>
+ <target name="debug-applet">
+ <fail message="Applets are no longer supported by JDK 9"/>
+ </target>
+ <!--
+ ===============
+ CLEANUP SECTION
+ ===============
+ -->
+ <target name="-deps-clean-init" unless="built-clean.properties">
+ <property location="${build.dir}/built-clean.properties" name="built-clean.properties"/>
+ <delete file="${built-clean.properties}" quiet="true"/>
+ </target>
+ <target if="already.built.clean.${basedir}" name="-warn-already-built-clean">
+ <echo level="warn" message="Cycle detected: vulkanz was already built"/>
+ </target>
+ <target depends="init,-deps-clean-init" name="deps-clean" unless="no.deps">
+ <mkdir dir="${build.dir}"/>
+ <touch file="${built-clean.properties}" verbose="false"/>
+ <property file="${built-clean.properties}" prefix="already.built.clean."/>
+ <antcall target="-warn-already-built-clean"/>
+ <propertyfile file="${built-clean.properties}">
+ <entry key="${basedir}" value=""/>
+ </propertyfile>
+ <antcall target="-maybe-call-dep">
+ <param name="call.built.properties" value="${built-clean.properties}"/>
+ <param location="${project.notzed_nativez}" name="call.subproject"/>
+ <param location="${project.notzed_nativez}/build.xml" name="call.script"/>
+ <param name="call.target" value="clean"/>
+ <param name="transfer.built-clean.properties" value="${built-clean.properties}"/>
+ <param name="transfer.not.archive.disabled" value="true"/>
+ <param name="transfer.do.jlink" value="false"/>
+ </antcall>
+ </target>
+ <target depends="init" name="-do-clean">
+ <delete dir="${build.dir}"/>
+ <delete dir="${dist.jlink.output}"/>
+ <delete dir="${dist.dir}" followsymlinks="false" includeemptydirs="true"/>
+ </target>
+ <target name="-post-clean">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target name="-recompile-netbeans-tasks-after-clean">
+ <antcall inheritall="false" target="-init-compile-netbeans-tasks"/>
+ </target>
+ <target depends="init,deps-clean,-do-clean,-recompile-netbeans-tasks-after-clean,-post-clean" description="Clean build products." name="clean"/>
+ <target name="-check-call-dep">
+ <property file="${call.built.properties}" prefix="already.built."/>
+ <condition property="should.call.dep">
+ <and>
+ <not>
+ <isset property="already.built.${call.subproject}"/>
+ </not>
+ <available file="${call.script}"/>
+ </and>
+ </condition>
+ </target>
+ <target depends="-check-call-dep" if="should.call.dep" name="-maybe-call-dep">
+ <ant antfile="${call.script}" inheritall="false" target="${call.target}">
+ <propertyset>
+ <propertyref prefix="transfer."/>
+ <mapper from="transfer.*" to="*" type="glob"/>
+ </propertyset>
+ </ant>
+ </target>
+</project>
--- /dev/null
+build.xml.data.CRC32=9e6776ee
+build.xml.script.CRC32=84612a8f
+build.xml.stylesheet.CRC32=32069288@1.17
+# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
+# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
+nbproject/build-impl.xml.data.CRC32=9e6776ee
+nbproject/build-impl.xml.script.CRC32=4a65f9d9
+nbproject/build-impl.xml.stylesheet.CRC32=d1ebcf0f@1.17
--- /dev/null
+annotation.processing.enabled=true
+annotation.processing.enabled.in.editor=false
+annotation.processing.processors.list=
+annotation.processing.run.all.processors=true
+annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
+application.title=vulkanz
+application.vendor=notzed
+build.classes.dir=${build.dir}/classes
+build.classes.excludes=**/*.java,**/*.form
+# This directory is removed when the project is cleaned:
+build.dir=build
+build.generated.dir=${build.dir}/generated
+build.generated.sources.dir=${build.dir}/generated-sources
+build.modules.dir=${build.dir}/modules
+# Only compile against the classpath explicitly listed here:
+build.sysclasspath=ignore
+build.test.classes.dir=${build.dir}/test/classes
+build.test.modules.dir=${build.dir}/test/modules
+build.test.results.dir=${build.dir}/test/results
+# Uncomment to specify the preferred debugger connection transport:
+#debug.transport=dt_socket
+debug.classpath=\
+ ${run.classpath}
+debug.modulepath=\
+ ${run.modulepath}
+debug.test.classpath=\
+ ${run.test.classpath}
+debug.test.modulepath=\
+ ${run.test.modulepath}
+# Files in build.classes.dir which should be excluded from distribution jar
+dist.archive.excludes=
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.javadoc.dir=${dist.dir}/javadoc
+dist.jlink.dir=${dist.dir}/jlink
+dist.jlink.output=${dist.jlink.dir}/vulkanz
+endorsed.classpath=
+excludes=
+includes=**
+jar.compress=false
+javac.classpath=
+# Space-separated list of extra javac options
+javac.compilerargs=
+javac.deprecation=false
+javac.external.vm=false
+javac.modulepath=\
+ ${reference.notzed_nativez.notzed_nativez_jar}
+javac.processormodulepath=
+javac.processorpath=\
+ ${javac.classpath}
+javac.source=18
+javac.target=18
+javac.test.classpath=\
+ ${javac.classpath}
+javac.test.modulepath=\
+ ${javac.modulepath}:\
+ ${build.modules.dir}
+javac.test.processorpath=\
+ ${javac.test.classpath}
+javadoc.additionalparam=
+javadoc.author=false
+javadoc.encoding=${source.encoding}
+javadoc.html5=false
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.splitindex=true
+javadoc.use=true
+javadoc.version=false
+javadoc.windowtitle=
+# The jlink additional root modules to resolve
+jlink.additionalmodules=
+# The jlink additional command line parameters
+jlink.additionalparam=
+jlink.launcher=true
+jlink.launcher.name=vulkanz
+platform.active=default_platform
+project.license=gpl3-notzed
+project.notzed_nativez=../nativez
+reference.notzed_nativez.notzed_nativez_jar=${project.notzed_nativez}/dist/notzed.nativez.jar
+run.classpath=
+# Space-separated list of JVM arguments used when running the project.
+# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
+# To set system properties for unit tests define test-sys-prop.name=value:
+run.jvmargs=--enable-native-access=notzed.vulkan,notzed.nativez,notzed.xlib
+run.modulepath=\
+ ${javac.modulepath}:\
+ ${build.modules.dir}
+run.test.classpath=\
+ ${javac.test.classpath}
+run.test.modulepath=\
+ ${javac.test.modulepath}:\
+ ${build.test.modules.dir}
+source.encoding=UTF-8
+src.dir=src
+src.dir.path=classes
+src.gen.dir=bin/gen
+src.gen.dir.path=classes
+test.src.dir=src
+test.src.dir.path=tests
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1">
+ <type>org.netbeans.modules.java.j2semodule</type>
+ <configuration>
+ <data xmlns="http://www.netbeans.org/ns/j2se-modular-project/1">
+ <name>vulkanz</name>
+ <source-roots>
+ <root id="src.dir" pathref="src.dir.path"/>
+ <root id="src.gen.dir" pathref="src.gen.dir.path"/>
+ </source-roots>
+ <test-roots>
+ <root id="test.src.dir" pathref="test.src.dir.path"/>
+ </test-roots>
+ </data>
+ <references xmlns="http://www.netbeans.org/ns/ant-project-references/1">
+ <reference>
+ <foreign-project>notzed_nativez</foreign-project>
+ <artifact-type>jar</artifact-type>
+ <script>build.xml</script>
+ <target>jar</target>
+ <clean-target>clean</clean-target>
+ <id>notzed.nativez.jar</id>
+ </reference>
+ </references>
+ </configuration>
+</project>
--- /dev/null
+
+package au.notzed.display;
+
+import jdk.incubator.foreign.*;
+import au.notzed.nativez.*;
+
+import vulkan.*;
+import static vulkan.Vulkan.*;
+
+import xlib.*;
+import static xlib.XLib.*;
+
+public abstract class Display {
+
+ public abstract Window createWindow(int width, int height);
+ public abstract void close();
+
+ public static Display createX11Display() {
+ return new X11Display(XOpenDisplay(null));
+ }
+
+ static class X11Display extends Display {
+ XDisplay display;
+
+ static {
+ XInitThreads();
+ }
+
+ X11Display(XDisplay display) {
+ this.display = display;
+ }
+
+ public Window createWindow(int width, int height) {
+ return Window.createX11Window(display, width, height);
+ }
+
+ public void close() {
+ XCloseDisplay(display);
+ }
+ }
+
+ // xcb, sdl etc
+}
--- /dev/null
+package au.notzed.display;
+
+// basic event handling
+public class Event {
+
+ public final int type;
+ public final int x, y, width, height;
+ // shift etc
+ public final int key;
+ public final int button;
+
+ public static final int CLOSE = 0;
+ public static final int KEY = 1;
+ public static final int POINTER = 2;
+ public static final int BUTTON = 3;
+ public static final int EXPOSE = 4;
+ public static final int RESIZE = 5;
+
+ public Event(int type, int x, int y, int width, int height, int key, int button) {
+ this.type = type;
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ this.key = key;
+ this.button = button;
+ }
+
+ public static Event key(int key) {
+ return new Event(KEY, 0, 0, 0, 0, key, 0);
+ }
+
+ public static Event expose(int x, int y, int width, int height) {
+ return new Event(EXPOSE, x, y, width, height, 0, 0);
+ }
+
+ public static Event resize(int x, int y, int width, int height) {
+ return new Event(RESIZE, x, y, width, height, 0, 0);
+ }
+
+ public static Event close() {
+ return new Event(CLOSE, 0, 0, 0, 0, 0, 0);
+ }
+
+ public String toString() {
+ switch (type) {
+ case CLOSE:
+ return "[Event close]";
+ case KEY:
+ return "[Event key=" + key + "]";
+ case EXPOSE:
+ return "[Event expose=" + x + "," + y + "," + width + "," + height + "]";
+ case RESIZE:
+ return "[Event resize=" + x + "," + y + "," + width + "," + height + "]";
+ default:
+ return "[Event]";
+ }
+ }
+}
--- /dev/null
+package au.notzed.display;
+
+import jdk.incubator.foreign.*;
+import au.notzed.nativez.*;
+
+import vulkan.*;
+import static vulkan.Vulkan.*;
+
+import xlib.*;
+import static xlib.XLib.*;
+
+public abstract class Window {
+
+ public abstract VkSurfaceKHR createVulkanSurface(VkInstance instance, ResourceScope scope);
+
+ public abstract Event nextEvent(boolean blocking);
+
+ public abstract void close();
+
+ static Window createX11Window(XDisplay display, int width, int height) {
+ try ( Frame frame = Frame.frame()) {
+ long visualMask = VisualScreenMask;
+ IntArray numberOfVisuals = IntArray.createArray(1, frame);
+ XVisualInfo vInfoTemplate = XVisualInfo.create(frame);
+
+ vInfoTemplate.setScreen(DefaultScreen(display));
+
+ XVisualInfo visualInfo = XGetVisualInfo(display, visualMask, vInfoTemplate, numberOfVisuals);
+ long colormap = XCreateColormap(display, RootWindow(display, vInfoTemplate.getScreen()), visualInfo.getVisual(), AllocNone);
+
+ XSetWindowAttributes windowAttributes = XSetWindowAttributes.create(frame);
+
+ windowAttributes.setBackgroundPixmap(0);
+ windowAttributes.setColormap(colormap);
+ windowAttributes.setEventMask(KeyPressMask | KeyReleaseMask | StructureNotifyMask | ExposureMask);
+
+ long window = XCreateWindow(display, RootWindow(display, vInfoTemplate.getScreen()),
+ 0, 0, width, height,
+ 0, visualInfo.getDepth(), InputOutput, visualInfo.getVisual(),
+ CWBackPixmap | CWEventMask | CWColormap, windowAttributes);
+
+ XSelectInput(display, window, ExposureMask | KeyPressMask | StructureNotifyMask | PointerMotionMask);
+
+ XMapWindow(display, window);
+ XFlush(display);
+
+ return new X11Window(display, window);
+ }
+ }
+
+ static class X11Window extends Window {
+
+ XDisplay display;
+ long window;
+ // TODO: move to display
+ long wm_delete_window;
+ long wm_protocols;
+
+ X11Window(XDisplay display, long window) {
+ this.display = display;
+ this.window = window;
+ wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", 0);
+ wm_protocols = XInternAtom(display, "WM_PROTOCOLS", 0);
+ try ( Frame frame = Frame.frame()) {
+ LongArray atoms = LongArray.create(frame, wm_delete_window);
+ XSetWMProtocols(display, window, atoms, 1);
+ }
+ }
+
+ @Override
+ public void close() {
+ XDestroyWindow(display, window);
+ }
+
+ @Override
+ public Event nextEvent(boolean blocking) {
+
+ try ( Frame frame = Frame.frame()) {
+ XEvent event = XEvent.create(frame);
+
+ while (true) {
+ if (!blocking && XPending(display) == 0)
+ return null;
+
+ int res = XNextEvent(display, event);
+
+ //System.out.printf("next event: %d type %d\n", res, event.getType());
+ switch (event.getType()) {
+ case KeyPress:
+ return Event.key(event.getXkey().getKeycode());
+ case Expose: {
+ XExposeEvent x = event.getXexpose();
+ return Event.expose(x.getX(), x.getY(), x.getWidth(), x.getHeight());
+ }
+ case ConfigureNotify: {
+ // nb: xy isn't useful
+ XConfigureEvent x = event.getXconfigure();
+ return Event.resize(x.getX(), x.getY(), x.getWidth(), x.getHeight());
+ }
+ case UnmapNotify: {
+ XUnmapEvent x = event.getXunmap();
+ return Event.resize(0, 0, 0, 0);
+ }
+ case MapNotify: {
+ try ( Frame sub = Frame.frame()) {
+ XWindowAttributes at = XWindowAttributes.create(sub);
+ XGetWindowAttributes(display, window, at);
+
+ return Event.resize(at.getX(), at.getY(), at.getWidth(), at.getHeight());
+ }
+ }
+ case ClientMessage: {
+ XClientMessageEvent x = event.getXclient();
+
+ if (x.getMessageType() == wm_protocols
+ && x.getData().getLElement(0) == wm_delete_window) {
+ return Event.close();
+ } else {
+ System.out.printf("unknown client message\n");
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public VkSurfaceKHR createVulkanSurface(VkInstance instance, ResourceScope scope) {
+ try ( Frame frame = Frame.frame()) {
+ VkXlibSurfaceCreateInfoKHR surfaceinfo = VkXlibSurfaceCreateInfoKHR.create(
+ 0,
+ display,
+ window,
+ frame);
+
+ return instance.vkCreateXlibSurfaceKHR(surfaceinfo, scope);
+ }
+ }
+ }
+}
--- /dev/null
+
+module notzed.display {
+ requires notzed.xlib;
+ requires notzed.xcb;
+ requires notzed.vulkan;
+
+ exports au.notzed.display;
+}
--- /dev/null
+
+module notzed.vulkan.test {
+ requires notzed.vulkan;
+ requires notzed.display;
+
+ requires java.desktop;
+}
--- /dev/null
+
+package vulkan.test;
+
+//struct Vertex {
+// float posX, posY, posZ, posW; // Position data
+// float r, g, b, a; // Color
+//};
+
+class Cube {
+ static final int dataStride = 8 * 4;
+ static final float[] data = new float[] {
+ // red face
+ -1, -1, 1, 1.f, 1.f, 0.f, 0.f, 1.f,
+ -1, 1, 1, 1.f, 1.f, 0.f, 0.f, 1.f,
+ 1, -1, 1, 1.f, 1.f, 0.f, 0.f, 1.f,
+ 1, -1, 1, 1.f, 1.f, 0.f, 0.f, 1.f,
+ -1, 1, 1, 1.f, 1.f, 0.f, 0.f, 1.f,
+ 1, 1, 1, 1.f, 1.f, 0.f, 0.f, 1.f,
+ // green face
+ -1, -1, -1, 1.f, 0.f, 1.f, 0.f, 1.f,
+ 1, -1, -1, 1.f, 0.f, 1.f, 0.f, 1.f,
+ -1, 1, -1, 1.f, 0.f, 1.f, 0.f, 1.f,
+ -1, 1, -1, 1.f, 0.f, 1.f, 0.f, 1.f,
+ 1, -1, -1, 1.f, 0.f, 1.f, 0.f, 1.f,
+ 1, 1, -1, 1.f, 0.f, 1.f, 0.f, 1.f,
+ // blue face
+ -1, 1, 1, 1.f, 0.f, 0.f, 1.f, 1.f,
+ -1, -1, 1, 1.f, 0.f, 0.f, 1.f, 1.f,
+ -1, 1, -1, 1.f, 0.f, 0.f, 1.f, 1.f,
+ -1, 1, -1, 1.f, 0.f, 0.f, 1.f, 1.f,
+ -1, -1, 1, 1.f, 0.f, 0.f, 1.f, 1.f,
+ -1, -1, -1, 1.f, 0.f, 0.f, 1.f, 1.f,
+ // yellow face
+ 1, 1, 1, 1.f, 1.f, 1.f, 0.f, 1.f,
+ 1, 1, -1, 1.f, 1.f, 1.f, 0.f, 1.f,
+ 1, -1, 1, 1.f, 1.f, 1.f, 0.f, 1.f,
+ 1, -1, 1, 1.f, 1.f, 1.f, 0.f, 1.f,
+ 1, 1, -1, 1.f, 1.f, 1.f, 0.f, 1.f,
+ 1, -1, -1, 1.f, 1.f, 1.f, 0.f, 1.f,
+ // magenta face
+ 1, 1, 1, 1.f, 1.f, 0.f, 1.f, 1.f,
+ -1, 1, 1, 1.f, 1.f, 0.f, 1.f, 1.f,
+ 1, 1, -1, 1.f, 1.f, 0.f, 1.f, 1.f,
+ 1, 1, -1, 1.f, 1.f, 0.f, 1.f, 1.f,
+ -1, 1, 1, 1.f, 1.f, 0.f, 1.f, 1.f,
+ -1, 1, -1, 1.f, 1.f, 0.f, 1.f, 1.f,
+ // cyan face
+ 1, -1, 1, 1.f, 0.f, 1.f, 1.f, 1.f,
+ 1, -1, -1, 1.f, 0.f, 1.f, 1.f, 1.f,
+ -1, -1, 1, 1.f, 0.f, 1.f, 1.f, 1.f,
+ -1, -1, 1, 1.f, 0.f, 1.f, 1.f, 1.f,
+ 1, -1, -1, 1.f, 0.f, 1.f, 1.f, 1.f,
+ -1, -1, -1, 1.f, 0.f, 1.f, 1.f, 1.f,
+ };
+}
--- /dev/null
+/*
+ * Copyright (C) 2022 Michael Zucchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package vulkan.test;
+
+import au.notzed.nativez.FloatArray;
+import au.notzed.nativez.Frame;
+import au.notzed.nativez.HandleArray;
+import au.notzed.nativez.IntArray;
+import au.notzed.nativez.Memory;
+import java.util.HashSet;
+import java.util.List;
+import java.util.stream.Stream;
+import jdk.incubator.foreign.GroupLayout;
+import jdk.incubator.foreign.MemoryLayout;
+import jdk.incubator.foreign.MemorySegment;
+import jdk.incubator.foreign.ResourceScope;
+import jdk.incubator.foreign.SegmentAllocator;
+import jdk.incubator.foreign.ValueLayout;
+import vulkan.PFN_vkDebugUtilsMessengerCallbackEXT;
+import vulkan.VkApplicationInfo;
+import vulkan.VkAttachmentDescription;
+import vulkan.VkAttachmentReference;
+import vulkan.VkBuffer;
+import vulkan.VkBufferCopy;
+import vulkan.VkBufferCreateInfo;
+import vulkan.VkCommandBuffer;
+import vulkan.VkCommandBufferAllocateInfo;
+import vulkan.VkCommandBufferBeginInfo;
+import vulkan.VkCommandPool;
+import vulkan.VkCommandPoolCreateInfo;
+import vulkan.VkDebugUtilsMessengerCreateInfoEXT;
+import vulkan.VkDebugUtilsMessengerEXT;
+import vulkan.VkDevice;
+import vulkan.VkDeviceCreateInfo;
+import vulkan.VkDeviceMemory;
+import vulkan.VkDeviceQueueCreateInfo;
+import vulkan.VkExtensionProperties;
+import vulkan.VkFence;
+import vulkan.VkFenceCreateInfo;
+import vulkan.VkFramebuffer;
+import vulkan.VkFramebufferCreateInfo;
+import vulkan.VkGraphicsPipelineCreateInfo;
+import vulkan.VkImage;
+import vulkan.VkImageView;
+import vulkan.VkImageViewCreateInfo;
+import vulkan.VkInstance;
+import vulkan.VkInstanceCreateInfo;
+import vulkan.VkMemoryAllocateInfo;
+import vulkan.VkMemoryRequirements;
+import vulkan.VkPhysicalDevice;
+import vulkan.VkPhysicalDeviceFeatures;
+import vulkan.VkPhysicalDeviceMemoryProperties;
+import vulkan.VkPhysicalDeviceProperties;
+import vulkan.VkPipeline;
+import vulkan.VkPipelineColorBlendAttachmentState;
+import vulkan.VkPipelineColorBlendStateCreateInfo;
+import vulkan.VkPipelineDynamicStateCreateInfo;
+import vulkan.VkPipelineInputAssemblyStateCreateInfo;
+import vulkan.VkPipelineLayout;
+import vulkan.VkPipelineLayoutCreateInfo;
+import vulkan.VkPipelineMultisampleStateCreateInfo;
+import vulkan.VkPipelineRasterizationStateCreateInfo;
+import vulkan.VkPipelineShaderStageCreateInfo;
+import vulkan.VkPipelineVertexInputStateCreateInfo;
+import vulkan.VkPipelineViewportStateCreateInfo;
+import vulkan.VkQueue;
+import vulkan.VkQueueFamilyProperties;
+import vulkan.VkRenderPass;
+import vulkan.VkRenderPassCreateInfo;
+import vulkan.VkSemaphore;
+import vulkan.VkSemaphoreCreateInfo;
+import vulkan.VkShaderModule;
+import vulkan.VkShaderModuleCreateInfo;
+import vulkan.VkSubmitInfo;
+import vulkan.VkSubpassDependency;
+import vulkan.VkSubpassDescription;
+import vulkan.VkSurfaceCapabilitiesKHR;
+import vulkan.VkSurfaceFormatKHR;
+import vulkan.VkSurfaceKHR;
+import vulkan.VkSwapchainCreateInfoKHR;
+import vulkan.VkSwapchainKHR;
+import vulkan.VkVertexInputAttributeDescription;
+import vulkan.VkVertexInputBindingDescription;
+import vulkan.Vulkan;
+import static vulkan.Vulkan.*;
+
+/**
+ * Basic demo setup.
+ */
+public class Demo {
+
+ // requested queue types, includes the pseudo-type PRESENT to simplify api
+ public final static int QUEUE_GRAPHICS = VK_QUEUE_GRAPHICS_BIT;
+ public final static int QUEUE_COMPUTE = VK_QUEUE_COMPUTE_BIT;
+ public final static int QUEUE_TRANSFER = VK_QUEUE_TRANSFER_BIT;
+ public final static int QUEUE_PRESENT = 0x80;
+ public final static int QUEUE_MASK = QUEUE_GRAPHICS | QUEUE_COMPUTE | QUEUE_TRANSFER;
+
+ public static VkInstance createInstance(int apiVersion, String[] layers, String[] extensions, ResourceScope scope) {
+ try ( Frame frame = Frame.frame()) {
+ VkInstanceCreateInfo info = VkInstanceCreateInfo.create(
+ 0,
+ VkApplicationInfo.create(null, 0, null, 0, apiVersion, frame),
+ layers.length, layers,
+ extensions.length, extensions,
+ frame
+ );
+
+ return VkInstance.vkCreateInstance(info, scope);
+ }
+ }
+
+ public static VkDebugUtilsMessengerEXT createLogger(VkInstance instance, ResourceScope scope) throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ var cb = PFN_vkDebugUtilsMessengerCallbackEXT.upcall((severity, flags, data) -> {
+ System.out.printf("Debug: %d: %s\n", severity, data.getMessage());
+ return 0;
+ }, scope);
+ VkDebugUtilsMessengerCreateInfoEXT info = VkDebugUtilsMessengerCreateInfoEXT.create(
+ 0,
+ //VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
+ VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT
+ | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
+ | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
+ VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT
+ | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT
+ | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
+ cb,
+ null,
+ frame);
+
+ return instance.vkCreateDebugUtilsMessengerEXT(info, scope);
+ }
+ }
+
+ static float priority(VkPhysicalDeviceProperties props) {
+ switch (props.getDeviceType()) {
+ default:
+ case VK_PHYSICAL_DEVICE_TYPE_OTHER:
+ return 0;
+ case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
+ return 3;
+ case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
+ return 4;
+ case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
+ return 2;
+ case VK_PHYSICAL_DEVICE_TYPE_CPU:
+ return 1;
+ }
+ }
+
+ static VkDeviceQueueCreateInfo selectQueues(VkPhysicalDevice dev, VkSurfaceKHR surface, int[] dflags, int[] families, SegmentAllocator frame$) {
+ try ( Frame frame = Frame.frame()) {
+ int allFamilies = 0;
+
+ // This tries to find a matching queue for each application queue requested.
+ // It priorities queues which are 'more exclusive' than others.
+ VkQueueFamilyProperties p = dev.vkGetPhysicalDeviceQueueFamilyProperties(frame);
+ for (int i = 0; i < dflags.length; i++) {
+ int dflag = dflags[i];
+ int family = -1;
+ float bestPri = 0;
+
+ for (int j = 0; j < p.length(); j++) {
+ int flags = p.getQueueFlagsAtIndex(j);
+ float pri = 0;
+
+ if (surface != null && dev.vkGetPhysicalDeviceSurfaceSupportKHR(j, surface))
+ flags |= QUEUE_PRESENT;
+ // according to vulkan tutorial either implies transfer
+ if ((flags & (Vulkan.VK_QUEUE_GRAPHICS_BIT | Vulkan.VK_QUEUE_COMPUTE_BIT)) != 0)
+ flags |= QUEUE_TRANSFER;
+
+ if ((flags & dflag) == dflag)
+ pri = 5 - Integer.bitCount(flags & ~dflag);
+
+ if (pri > bestPri) {
+ bestPri = pri;
+ family = j;
+ }
+ }
+
+ if (family == -1)
+ throw new RuntimeException("Cannot find required queues");
+
+ families[i] = family;
+ allFamilies |= 1 << family;
+ }
+
+ int nfamilies = Integer.bitCount(allFamilies);
+
+ VkDeviceQueueCreateInfo qinfo = VkDeviceQueueCreateInfo.createArray(nfamilies, frame$);
+ for (int i = 0; i < nfamilies; i++) {
+ int family = Integer.numberOfTrailingZeros(allFamilies);
+ FloatArray qpri = FloatArray.create(frame$, 0.0f);
+
+ qinfo.setQueueFamilyIndexAtIndex(i, family);
+ qinfo.setQueueCountAtIndex(i, 1);
+ qinfo.setQueuePrioritiesAtIndex(i, qpri);
+
+ allFamilies = allFamilies & ~(1 << family);
+ }
+
+ System.out.println(qinfo);
+
+ return qinfo;
+ }
+ }
+
+ // instance? scope?
+ // allocation?
+ public static record DemoDevice(
+ VkPhysicalDevice dev,
+ VkPhysicalDeviceMemoryProperties memory,
+ VkDevice device,
+ VkSurfaceKHR surface,
+ int[] queueFamilies,
+ VkQueue[] queues, VkCommandPool[] pools) {
+
+ public void close() {
+ Stream.of(pools).forEach(device::vkDestroyCommandPool);
+ device.vkDestroyDevice();
+ }
+
+ public VkSemaphore createSemaphore(ResourceScope scope) {
+ try ( Frame frame = Frame.frame()) {
+ VkSemaphoreCreateInfo info = VkSemaphoreCreateInfo.create(frame);
+ return device.vkCreateSemaphore(info, scope);
+ }
+ }
+
+ public VkFence createFence(ResourceScope scope) {
+ try ( Frame frame = Frame.frame()) {
+ VkFenceCreateInfo info = VkFenceCreateInfo.create(frame);
+ return device.vkCreateFence(info, scope);
+ }
+ }
+
+ public HandleArray<VkSemaphore> createSemaphores(int count, SegmentAllocator alloc, ResourceScope scope) {
+ HandleArray<VkSemaphore> list = VkSemaphore.createArray(count, alloc, scope);
+ try ( Frame frame = Frame.frame()) {
+ VkSemaphoreCreateInfo info = VkSemaphoreCreateInfo.create(frame);
+
+ for (int i = 0; i < count; i++)
+ list.set(i, device.vkCreateSemaphore(info, scope));
+ }
+ return list;
+ }
+
+ public HandleArray<VkFence> createFences(int count, int flags, SegmentAllocator alloc, ResourceScope scope) {
+ HandleArray<VkFence> list = VkFence.createArray(count, alloc, scope);
+ try ( Frame frame = Frame.frame()) {
+ VkFenceCreateInfo info = VkFenceCreateInfo.create(flags, frame);
+
+ for (int i = 0; i < count; i++)
+ list.set(i, device.vkCreateFence(info, scope));
+ }
+ return list;
+ }
+
+ public int findMemory(int type, int reqProp) {
+ for (int i = 0, len = memory.getMemoryTypeCount(); i < len; i++) {
+ int prop = memory.getMemoryTypes$propertyFlagsAtIndex(i);
+
+ if (((1 << i) & type) != 0 && (prop & reqProp) == reqProp)
+ return i;
+
+ }
+ throw new RuntimeException("memory type not found");
+ }
+ }
+
+ // TODO: alloc?
+ public static DemoDevice createDevice(VkInstance instance, VkPhysicalDeviceFeatures features, VkSurfaceKHR surface, int[] queueFlags, String[] extensions, ResourceScope scope) {
+ try ( Frame frame = Frame.frame()) {
+ HandleArray<VkPhysicalDevice> devs = instance.vkEnumeratePhysicalDevices(frame, scope);
+ VkPhysicalDeviceProperties dp = VkPhysicalDeviceProperties.create(frame);
+ VkPhysicalDeviceFeatures df = VkPhysicalDeviceFeatures.create(frame);
+
+ // First select best device
+ // - must support features
+ // - if surface non-null then must support surface output
+ VkPhysicalDevice dev = null;
+ VkSurfaceFormatKHR surfaceFormats = null;
+ IntArray presentModes = null;
+
+ float bestPriority = -1;
+ for (int i = 0; i < devs.size(); i++) {
+ VkPhysicalDevice d = devs.getAtIndex(i);
+ VkSurfaceFormatKHR formats = null;
+ IntArray modes = null;
+ float pri;
+
+ d.vkGetPhysicalDeviceProperties(dp);
+ pri = priority(dp);
+ if (pri <= bestPriority)
+ continue;
+
+ if (!checkDeviceExtensionSupport(d, extensions))
+ continue;
+
+ d.vkGetPhysicalDeviceFeatures(df);
+ if (!df.hasFeatures(features))
+ continue;
+
+ if (surface != null) {
+ formats = d.vkGetPhysicalDeviceSurfaceFormatsKHR(surface, frame);
+ modes = d.vkGetPhysicalDeviceSurfacePresentModesKHR(surface, frame);
+
+ if (formats.isEmpty() || modes.isEmpty())
+ continue;
+ }
+
+ dev = d;
+ surfaceFormats = formats;
+ presentModes = modes;
+ bestPriority = pri;
+ }
+
+ if (dev == null)
+ throw new RuntimeException("No suitable device found");
+
+ int[] families = new int[queueFlags.length];
+ VkDeviceQueueCreateInfo qinfo = selectQueues(dev, surface, queueFlags, families, frame);
+
+ VkDeviceCreateInfo devinfo = VkDeviceCreateInfo.create(
+ 0,
+ (int)qinfo.length(), qinfo,
+ 0, null, // enabled layers
+ (int)Memory.length(extensions), extensions,
+ features,
+ frame);
+
+ var device = dev.vkCreateDevice(devinfo, scope);
+
+ VkCommandPoolCreateInfo poolInfo = VkCommandPoolCreateInfo.create(0, 0, frame);
+
+ // TODO: only create one pool/queue per unique family?
+ VkQueue[] queues = new VkQueue[families.length];
+ VkCommandPool[] pools = new VkCommandPool[families.length];
+
+ for (int i = 0; i < families.length; i++) {
+ System.out.printf(" queue[%d] = family[%d]\n", i, families[i]);
+ queues[i] = device.vkGetDeviceQueue(families[i], 0, scope);
+
+ poolInfo.setQueueFamilyIndex(families[i]);
+ pools[i] = device.vkCreateCommandPool(poolInfo, scope);
+ }
+
+ VkPhysicalDeviceMemoryProperties memory = VkPhysicalDeviceMemoryProperties.create((SegmentAllocator)scope);
+
+ dev.vkGetPhysicalDeviceMemoryProperties(memory);
+
+ return new DemoDevice(dev, memory, device, surface, families, queues, pools);
+ }
+ }
+
+ public record ColourFormat(int format, int colourSpace) {
+
+ boolean matchAt(VkSurfaceFormatKHR fmt, int i) {
+ return fmt.getFormatAtIndex(i) == format
+ & fmt.getColorSpaceAtIndex(i) == colourSpace;
+ }
+
+ public static ColourFormat SRGB = new ColourFormat(VK_FORMAT_B8G8R8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR);
+
+ }
+
+ static ColourFormat selectColourFormat(VkSurfaceFormatKHR formats, ColourFormat def, ColourFormat... query) {
+ int len = (int)formats.length();
+
+ if (len == 1 && formats.getColorSpaceAtIndex(0) == VK_FORMAT_UNDEFINED)
+ return def;
+
+ for (ColourFormat q: query) {
+ for (int i = 0; i < len; i++) {
+ if (q.matchAt(formats, i))
+ return q;
+ }
+ }
+
+ return new ColourFormat(formats.getFormatAtIndex(0), formats.getColorSpaceAtIndex(0));
+ }
+
+ static int selectPresentMode(IntArray modes, int def, int... query) {
+ for (int q: query) {
+ if (modes.contains(q))
+ return q;
+ }
+ return def;
+ }
+
+ static int selectFlags(int flag, int def, int... query) {
+ for (int q: query) {
+ if ((flag & q) == q)
+ return q;
+ }
+ return def;
+ }
+
+ static int clampi(int v, int min, int max) {
+ return Math.max(min, Math.min(max, v));
+ }
+
+ public static record DemoChain(VkSwapchainKHR swapchain,
+ ColourFormat format,
+ int extWidth, int extHeight,
+ HandleArray<VkImage> images,
+ HandleArray<VkImageView> views,
+ VkRenderPass renderPass) {
+
+ }
+
+ static DemoChain createSwapchain(DemoDevice dd, ColourFormat prefFormat, int prefPresentMode, int pixWidth, int pixHeight, SegmentAllocator alloc, ResourceScope scope) {
+ try ( Frame frame = Frame.frame()) {
+ ColourFormat format = selectColourFormat(
+ dd.dev.vkGetPhysicalDeviceSurfaceFormatsKHR(dd.surface, frame),
+ ColourFormat.SRGB,
+ prefFormat);
+
+ int presentMode = selectPresentMode(dd.dev.vkGetPhysicalDeviceSurfacePresentModesKHR(dd.surface, frame),
+ VK_PRESENT_MODE_FIFO_KHR,
+ prefPresentMode,
+ VK_PRESENT_MODE_FIFO_KHR,
+ VK_PRESENT_MODE_FIFO_RELAXED_KHR,
+ VK_PRESENT_MODE_MAILBOX_KHR,
+ VK_PRESENT_MODE_IMMEDIATE_KHR);
+
+ VkSurfaceCapabilitiesKHR caps = VkSurfaceCapabilitiesKHR.create(frame);
+
+ dd.dev.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(dd.surface, caps);
+
+ int extWidth = caps.getCurrentExtent$width();
+ int extHeight = caps.getCurrentExtent$height();
+
+ if (extWidth == ~0) {
+ extWidth = clampi(pixWidth, caps.getMinImageExtent$width(), caps.getMaxImageExtent$width());
+ extHeight = clampi(pixHeight, caps.getMinImageExtent$height(), caps.getMaxImageExtent$height());
+ }
+
+ int minCount = caps.getMinImageCount();
+ int maxCount = caps.getMaxImageCount();
+ int imageCount = clampi(minCount + 1, minCount, maxCount == 0 ? Integer.MAX_VALUE : maxCount);
+
+ int composite = selectFlags(caps.getSupportedCompositeAlpha(),
+ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+ VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
+ VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
+ VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR);
+
+ VkSwapchainCreateInfoKHR chainInfo = VkSwapchainCreateInfoKHR.create(
+ 0,
+ dd.surface,
+ imageCount,
+ format.format, format.colourSpace,
+ extWidth, extHeight,
+ 1, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+ VK_SHARING_MODE_EXCLUSIVE, 0, null,// createDevice requires present+graphics queue the same
+ caps.getCurrentTransform(), // prefer VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR ?
+ composite,
+ presentMode,
+ VK_TRUE, // clipped
+ null, // old chain
+ frame);
+
+ VkSwapchainKHR swapchain = dd.device.vkCreateSwapchainKHR(chainInfo, scope);
+
+ // Create images and image views, here or elsewhere?
+ HandleArray<VkImage> images = dd.device.vkGetSwapchainImagesKHR(swapchain, alloc, scope);
+ HandleArray<VkImageView> views = VkImageView.createArray(images.length(), alloc, scope);
+
+ VkImageViewCreateInfo viewInfo = VkImageViewCreateInfo.create(
+ 0,
+ null,
+ VK_IMAGE_VIEW_TYPE_2D,
+ format.format,
+ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A,
+ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1,
+ frame);
+
+ for (int i = 0; i < images.size(); i++) {
+ viewInfo.setImage(images.get(i));
+ views.set(i, dd.device.vkCreateImageView(viewInfo, scope));
+ }
+
+ VkRenderPass renderPass = dumbRenderPass(dd.device, format.format, scope);
+
+ return new DemoChain(swapchain, format, extWidth, extHeight, images, views, renderPass);
+ }
+ }
+
+ /* graphics pipeline model from vulkan tutorial [programmable shader]
+
+ input assembler
+ [vertex shader]
+ [tesselation]
+ [geometry shader]
+ rasterisation
+ [fragment shader]
+ colour blending
+
+ */
+
+ /* each shader (code, stage, main)
+ + specialisation info to initialise constants per-pipeline shader stage init
+
+ */
+ static VkRenderPass dumbRenderPass(VkDevice device, int format, ResourceScope scope) {
+ try ( Frame frame = Frame.frame()) {
+ VkAttachmentDescription colourAttachment = VkAttachmentDescription.create(
+ 0,
+ format,
+ VK_SAMPLE_COUNT_1_BIT,
+ VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE,
+ VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
+ VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+ frame);
+
+ VkAttachmentReference colourRef = VkAttachmentReference.create(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, frame);
+ VkSubpassDescription subpass = VkSubpassDescription.create(
+ 0,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ 0, null,
+ 1, colourRef, null, null,
+ 0, null,
+ frame);
+
+ VkSubpassDependency dependency = VkSubpassDependency.create(
+ VK_SUBPASS_EXTERNAL, 0,
+ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+ 0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+ 0, frame);
+
+ VkRenderPassCreateInfo renderPassInfo = VkRenderPassCreateInfo.create(
+ 0,
+ 1, colourAttachment,
+ 1, subpass,
+ 0, null,
+ frame);
+
+ return device.vkCreateRenderPass(renderPassInfo, scope);
+ }
+ }
+
+ static VkShaderModule createShaderModule(VkDevice device, IntArray spirv, ResourceScope scope) {
+ try ( Frame frame = Frame.frame()) {
+ VkShaderModuleCreateInfo vsInfo = VkShaderModuleCreateInfo.create(
+ 0,
+ spirv.length() * 4,
+ spirv,
+ frame);
+ return device.vkCreateShaderModule(vsInfo, scope);
+ }
+ }
+
+ static VkPipelineLayout dumbPipelineLayout(VkDevice device, ResourceScope scope) {
+ try ( Frame frame = Frame.frame()) {
+ VkPipelineLayoutCreateInfo layoutInfo = VkPipelineLayoutCreateInfo.create(0, 0, null, 0, null, frame);
+ return device.vkCreatePipelineLayout(layoutInfo, scope);
+ }
+ }
+
+ static VkPipeline dumbPipeline(VkDevice device, VkShaderModule vertex, VkShaderModule fragment, VkPipelineLayout layout, VkRenderPass renderPass, ResourceScope scope) {
+ try ( Frame frame = Frame.frame()) {
+ VkPipelineShaderStageCreateInfo shader = VkPipelineShaderStageCreateInfo.createArray(2, frame);
+
+ shader.setAtIndex(0, 0, VK_SHADER_STAGE_VERTEX_BIT, vertex, "main", null, frame);
+ shader.setAtIndex(1, 0, VK_SHADER_STAGE_FRAGMENT_BIT, fragment, "main", null, frame);
+
+ VkPipelineDynamicStateCreateInfo dynamic = VkPipelineDynamicStateCreateInfo.create(
+ 0,
+ 2, IntArray.create(frame, VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR),
+ frame);
+
+ // TODO: parameter?
+ VkVertexInputBindingDescription binding = VkVertexInputBindingDescription.createArray(1, frame);
+ VkVertexInputAttributeDescription attribute = VkVertexInputAttributeDescription.createArray(2, frame);
+
+ binding.setAtIndex(0, 0, 5 * 4, Vulkan.VK_VERTEX_INPUT_RATE_VERTEX, frame);
+ attribute.setAtIndex(0, 0, 0, Vulkan.VK_FORMAT_R32G32_SFLOAT, 0, frame);
+ attribute.setAtIndex(1, 1, 0, Vulkan.VK_FORMAT_R32G32B32_SFLOAT, 2 * 4, frame);
+
+ VkPipelineVertexInputStateCreateInfo vertextInput = VkPipelineVertexInputStateCreateInfo.create(
+ 0,
+ 1, binding,
+ 2, attribute,
+ frame);
+
+ VkPipelineInputAssemblyStateCreateInfo inputAssembly = VkPipelineInputAssemblyStateCreateInfo.create(
+ 0,
+ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
+ VK_FALSE,
+ frame);
+
+ VkPipelineViewportStateCreateInfo viewport = VkPipelineViewportStateCreateInfo.create(
+ 0,
+ 1, null,
+ 1, null,
+ frame);
+
+ VkPipelineRasterizationStateCreateInfo rasterisation = VkPipelineRasterizationStateCreateInfo.create(
+ 0,
+ VK_FALSE,
+ VK_FALSE,
+ VK_POLYGON_MODE_FILL, VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_CLOCKWISE,
+ VK_FALSE, 0.0f, 0.0f, 0.0f,
+ 1.0f, frame);
+
+ VkPipelineMultisampleStateCreateInfo multisample = VkPipelineMultisampleStateCreateInfo.create(
+ 0,
+ VK_SAMPLE_COUNT_1_BIT,
+ VK_FALSE, 1.0f, null,
+ VK_FALSE, VK_FALSE,
+ frame);
+
+ VkPipelineColorBlendAttachmentState colourBlendAttachment = VkPipelineColorBlendAttachmentState.create(
+ VK_FALSE,
+ VK_BLEND_FACTOR_ZERO, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD,
+ VK_BLEND_FACTOR_ZERO, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD,
+ VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
+ frame);
+
+ VkPipelineColorBlendStateCreateInfo colourBlend = VkPipelineColorBlendStateCreateInfo.create(
+ 0,
+ VK_FALSE, VK_LOGIC_OP_NO_OP,
+ 1, colourBlendAttachment,
+ 1.0f, 1.0f, 1.0f, 1.0f,
+ frame);
+
+ VkGraphicsPipelineCreateInfo pipeline = VkGraphicsPipelineCreateInfo.create(
+ 0,
+ 2, shader,
+ vertextInput, inputAssembly,
+ null,
+ viewport,
+ rasterisation,
+ multisample,
+ null,
+ colourBlend,
+ dynamic,
+ layout,
+ renderPass, 0,
+ null, 0, frame);
+
+ return device.vkCreateGraphicsPipeline(null, pipeline, scope);
+
+ }
+ }
+
+ public static HandleArray<VkFramebuffer> createFramebuffers(DemoDevice device, DemoChain chain, SegmentAllocator alloc, ResourceScope scope) {
+ try ( Frame frame = Frame.frame()) {
+ var frameBuffers = VkFramebuffer.createArray(chain.views.length(), alloc);
+ HandleArray<VkImageView> attachments = VkImageView.createArray(1, frame);
+ VkFramebufferCreateInfo framebufferInfo = VkFramebufferCreateInfo.create(
+ 0,
+ chain.renderPass,
+ 1, attachments,
+ chain.extWidth, chain.extHeight,
+ 1,
+ frame);
+
+ for (int i = 0; i < chain.views.size(); i++) {
+ attachments.setAtIndex(0, chain.views.get(i));
+ frameBuffers.setAtIndex(i, device.device.vkCreateFramebuffer(framebufferInfo, scope));
+ }
+ return frameBuffers;
+ }
+ }
+
+ public static HandleArray<VkCommandBuffer> createCommandBuffers(DemoDevice device, int appIndex, int count, SegmentAllocator alloc, ResourceScope scope) {
+ try ( Frame frame = Frame.frame()) {
+ VkCommandBufferAllocateInfo bufferInfo = VkCommandBufferAllocateInfo.create(
+ device.pools[appIndex],
+ VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+ count,
+ frame);
+
+ return device.device.vkAllocateCommandBuffers(bufferInfo, (SegmentAllocator)scope, scope);
+ }
+ }
+
+ public static void resetCommandBuffers(DemoDevice device, int appIndex, HandleArray<VkCommandBuffer> commandBuffers) {
+ try ( Frame frame = Frame.frame()) {
+ VkCommandBufferAllocateInfo bufferInfo = VkCommandBufferAllocateInfo.create(
+ device.pools[appIndex],
+ VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+ commandBuffers.size(),
+ frame);
+
+ device.device.vkAllocateCommandBuffers(bufferInfo, commandBuffers);
+ }
+ }
+
+ // device?
+ public record Buffer(
+ VkBuffer buffer,
+ VkDeviceMemory memory,
+ long size,
+ long offset) {
+
+ public void close(VkDevice device) {
+ device.vkFreeMemory(memory);
+ device.vkDestroyBuffer(buffer);
+ }
+ }
+
+ // TODO: memory allocator? - limited memory blocks?
+ public static Buffer createBuffer(DemoDevice device, long size, int usage, int props, int[] sharedFamilies, MemorySegment src, ResourceScope scope) {
+ try ( Frame frame = Frame.frame()) {
+ IntArray families = sharedFamilies != null ? IntArray.create(frame, sharedFamilies) : null;
+ VkBufferCreateInfo create = VkBufferCreateInfo.create(0, size, usage, VK_SHARING_MODE_CONCURRENT, sharedFamilies != null ? sharedFamilies.length : 0, families, frame);
+ VkBuffer buffer = device.device.vkCreateBuffer(create, scope);
+ VkMemoryRequirements req = VkMemoryRequirements.create(frame);
+
+ device.device.vkGetBufferMemoryRequirements(buffer, req);
+
+ VkMemoryAllocateInfo allocate = VkMemoryAllocateInfo.create(
+ req.getSize(),
+ device.findMemory(req.getMemoryTypeBits(), props),
+ frame);
+
+ System.out.printf("size = %x\n", size);
+
+ VkDeviceMemory memory = device.device.vkAllocateMemory(allocate, scope);
+
+ device.device.vkBindBufferMemory(buffer, memory, 0);
+
+ if (src != null) {
+ MemorySegment mem = device.device.vkMapMemory(memory, 0, size, 0, frame.scope());
+
+ mem.copyFrom(src);
+ device.device.vkUnmapMemory(memory);
+ }
+
+ return new Buffer(buffer, memory, size, 0);
+ }
+ }
+
+ public static void copyBuffer(DemoDevice device, Buffer src, Buffer dst) {
+ try ( Frame frame = Frame.frame()) {
+ VkCommandPool xfer = device.pools()[1];
+ VkCommandBufferAllocateInfo alloc = VkCommandBufferAllocateInfo.create(xfer, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1, frame);
+ HandleArray<VkCommandBuffer> cmds = device.device.vkAllocateCommandBuffers(alloc, frame, frame.scope());
+ VkCommandBuffer cmd = cmds.get(0);
+
+ VkCommandBufferBeginInfo begin = VkCommandBufferBeginInfo.create(Vulkan.VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, null, frame);
+ VkBufferCopy region = VkBufferCopy.create(0, 0, dst.size, frame);
+
+ cmd.vkBeginCommandBuffer(begin);
+ cmd.vkCmdCopyBuffer(src.buffer, dst.buffer, 1, region);
+ cmd.vkEndCommandBuffer();
+
+ VkSubmitInfo submit = VkSubmitInfo.create(0, null, null, 1, cmds, 0, null, frame);
+ device.queues[1].vkQueueSubmit(1, submit, null);
+
+ device.queues[1].vkQueueWaitIdle();
+
+ // NB: must be finished before freeing
+ device.device.vkFreeCommandBuffers(xfer, 1, cmds);
+ }
+
+ }
+
+ // not worth it, its simple enough
+ static VkVertexInputAttributeDescription createInputAttributes(SegmentAllocator alloc, int binding, int... loc) {
+ int len = loc.length / 3;
+
+ VkVertexInputAttributeDescription attribute = VkVertexInputAttributeDescription.createArray(len, alloc);
+ for (int i = 0; i < len; i++) {
+ attribute.setAtIndex(i, loc[i * 3 + 0], binding, loc[i * 3 + 1], loc[i * 3 + 2], alloc);
+ }
+ return attribute;
+ }
+
+ static boolean checkDeviceExtensionSupport(VkPhysicalDevice dev, String... query) {
+ // spec versions?
+ if (query.length > 0) {
+ try ( Frame frame = Frame.frame()) {
+ VkExtensionProperties props = dev.vkEnumerateDeviceExtensionProperties(null, frame);
+ HashSet<String> set = new HashSet(List.of(query));
+ for (int i = 0; i < props.length(); i++)
+ set.remove(props.getExtensionNameAtIndex(i));
+
+ if (!set.isEmpty())
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+}
--- /dev/null
+
+package vulkan.test;
+
+import static java.lang.Math.*;
+import java.util.Arrays;
+
+public class GLMaths {
+ public static void identity4f(float []matrix) {
+ Arrays.fill(matrix, 0.0f);
+ for (int i = 0; i < 4; i++)
+ matrix[i * 4 + i] = 1.0f;
+ }
+
+ public static float length3f(float [] a) {
+ float sum = 0;
+ for (int i = 0; i < 3; i++)
+ sum += a[i] * a[i];
+ return (float)sqrt(sum);
+ }
+
+ public static void sub3f(float [] c, float [] a, float [] b) {
+ for (int i = 0; i < 3; i++)
+ c[i] = a[i] - b[i];
+ }
+
+ public static void norm3f(float [] vec) {
+ float fix = 1.0f / length3f(vec);
+ for (int i = 0; i < 3; i++)
+ vec[i] *= fix;
+ }
+
+ public static void cross3f(float [] c, float [] a, float [] b) {
+ c[0] = a[1] * b[2] - a[2] * b[1];
+ c[1] = a[2] * b[0] - a[0] * b[2];
+ c[2] = a[0] * b[1] - a[1] * b[0];
+ }
+
+ public static float dot3f(float [] a, float [] b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+ }
+
+ public static float [] mult4x4f(float [] c, float [] b, float [] a) {
+ c[0] = a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12];
+ c[1] = a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13];
+ c[2] = a[0] * b[2] + a[1] * b[6] + a[2] * b[10] + a[3] * b[14];
+ c[3] = a[0] * b[3] + a[1] * b[7] + a[2] * b[11] + a[3] * b[15];
+
+ c[4] = a[4] * b[0] + a[5] * b[4] + a[6] * b[8] + a[7] * b[12];
+ c[5] = a[4] * b[1] + a[5] * b[5] + a[6] * b[9] + a[7] * b[13];
+ c[6] = a[4] * b[2] + a[5] * b[6] + a[6] * b[10] + a[7] * b[14];
+ c[7] = a[4] * b[3] + a[5] * b[7] + a[6] * b[11] + a[7] * b[15];
+
+ c[8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[8] + a[11] * b[12];
+ c[9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[9] + a[11] * b[13];
+ c[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10] + a[11] * b[14];
+ c[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11] * b[15];
+
+ c[12] = a[12] * b[0] + a[13] * b[4] + a[14] * b[8] + a[15] * b[12];
+ c[13] = a[12] * b[1] + a[13] * b[5] + a[14] * b[9] + a[15] * b[13];
+ c[14] = a[12] * b[2] + a[13] * b[6] + a[14] * b[10] + a[15] * b[14];
+ c[15] = a[12] * b[3] + a[13] * b[7] + a[14] * b[11] + a[15] * b[15];
+
+ return c;
+ }
+
+ public static void lookAt(float []mat, float []eye, float []centre, float []up) {
+ float forward[] = new float[3], side[] = new float[3], u[] = new float[3];
+
+ sub3f(forward, centre, eye);
+ norm3f(forward);
+ cross3f(side, forward, up);
+ norm3f(side);
+ cross3f(u, side, forward);
+
+ mat[0] = side[0];
+ mat[4] = side[1];
+ mat[8] = side[2];
+
+ mat[1] = u[0];
+ mat[5] = u[1];
+ mat[9] = u[2];
+
+ mat[2] = -forward[0];
+ mat[6] = -forward[1];
+ mat[10] = -forward[2];
+
+ mat[12] = -dot3f(side, eye);
+ mat[13] = -dot3f(u, eye);
+ mat[14] = dot3f(forward, eye);
+
+ mat[3] = 0.0f;
+ mat[7] = 0.0f;
+ mat[11] = 0.0f;
+
+ mat[15] = 1.0f;
+ }
+
+ public static void frustum(float []mat, float left, float right, float bottom, float top, float znear, float zfar) {
+ float temp, temp2, temp3, temp4;
+
+ temp = 2.0f * znear;
+ temp2 = right - left;
+ temp3 = top - bottom;
+ temp4 = zfar - znear;
+ mat[0] = temp / temp2;
+ mat[1] = 0.0f;
+ mat[2] = 0.0f;
+ mat[3] = 0.0f;
+ mat[4] = 0.0f;
+ mat[5] = temp / temp3;
+ mat[6] = 0.0f;
+ mat[7] = 0.0f;
+ mat[8] = (right + left) / temp2;
+ mat[9] = (top + bottom) / temp3;
+ mat[10] = (-zfar - znear) / temp4;
+ mat[11] = -1.0f;
+ mat[12] = 0.0f;
+ mat[13] = 0.0f;
+ mat[14] = (-temp * zfar) / temp4;
+ mat[15] = 0.0f;
+ }
+
+ public static void perspective(float []mat, float fovy, float aspect, float znear, float zfar) {
+ float ymax, xmax;
+
+ ymax = znear * (float)tan(fovy * 0.5f);
+ xmax = ymax * aspect;
+
+ frustum(mat, -xmax, xmax, -ymax, ymax, znear, zfar);
+ }
+}
--- /dev/null
+/*
+The MIT License (MIT)
+
+Copyright (C) 2017 Eric Arnebäck
+Copyright (C) 2019 Michael Zucchi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+ */
+
+ /*
+ * This is a Java conversion of a C conversion of this:
+ * https://github.com/Erkaman/vulkan_minimal_compute
+ *
+ * It's been simplified a bit and converted to the 'zvk' api.
+ */
+package vulkan.test;
+
+import au.notzed.display.Display;
+import jdk.incubator.foreign.*;
+import au.notzed.nativez.*;
+
+import vulkan.*;
+import static vulkan.Vulkan.*;
+
+import au.notzed.display.*;
+import static vulkan.test.GLMaths.*;
+
+public class TestCube {
+
+ static final boolean debug = true;
+
+ final static int NUM_SAMPLES = VK_SAMPLE_COUNT_1_BIT;
+ final static int NUM_DESCRIPTOR_SETS = 1;
+
+ ResourceScope scope = ResourceScope.newSharedScope();
+
+ int width = 800;
+ int height = 800;
+ float projection[] = new float[16];
+ float view[] = new float[16];
+ float model[] = new float[16];
+ float clip[] = new float[]{
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.5f, 0.0f,
+ 0.0f, 0.0f, 0.5f, 1.0f
+ };
+ float mvp[] = new float[16];
+
+ VkInstance instance;
+ VkPhysicalDevice physicalDevice;
+ VkPhysicalDeviceMemoryProperties memory_properties;
+ VkPhysicalDeviceFeatures device_features;
+
+ int present_queue_index;
+ int graphics_queue_index;
+
+ VkDevice device;
+ VkSwapchainKHR chain;
+
+ VkQueue graphics_queue;
+ VkQueue present_queue;
+
+ int chainImageFormat;
+ HandleArray<VkImage> chainImage;
+ HandleArray<VkImageView> chainImageView;
+
+ int depthFormat;
+ VkImage depthImage;
+ VkImageView depthView;
+ VkDeviceMemory depthMemory;
+
+ VkCommandPool cmd_pool;
+ HandleArray<VkCommandBuffer> cmd;
+
+ BufferMemory uniform;
+ VkPipelineLayout pipeline_layout;
+
+ VkDescriptorSetLayout desc_layout;
+ VkDescriptorPool desc_pool;
+ HandleArray<VkDescriptorSet> desc_set;
+
+ VkRenderPass render_pass;
+ HandleArray<VkFramebuffer> framebuffers;
+
+ BufferMemory vertex;
+ HandleArray<VkBuffer> vertexBuffer = VkBuffer.createArray(1, (SegmentAllocator)scope);
+ VkVertexInputBindingDescription vi_binding = VkVertexInputBindingDescription.createArray(1, (SegmentAllocator)scope);
+ VkVertexInputAttributeDescription vi_attribs = VkVertexInputAttributeDescription.createArray(2, (SegmentAllocator)scope);
+
+ IntArray cube_vs;
+ IntArray cube_fs;
+ HandleArray<VkShaderModule> shader = VkShaderModule.createArray(2, (SegmentAllocator)scope);
+
+ HandleArray<VkPipeline> pipeline = VkPipeline.createArray(1, (SegmentAllocator)scope);
+
+ VkSemaphore chainSemaphore;
+ VkFence drawFence;
+
+ record BufferMemory(VkBuffer buffer, VkDeviceMemory memory, long size) {
+
+ public void free(VkDevice device) {
+ device.vkFreeMemory(memory);
+ device.vkDestroyBuffer(buffer);
+ }
+ }
+
+ VkDebugUtilsMessengerEXT logger;
+
+ void init_debug() throws Exception {
+ if (!debug)
+ return;
+ try ( Frame frame = Frame.frame()) {
+ var cb = PFN_vkDebugUtilsMessengerCallbackEXT.upcall((severity, flags, data) -> {
+ System.out.printf("Debug: %d: %s\n", severity, data.getMessage());
+ return 0;
+ }, scope);
+ VkDebugUtilsMessengerCreateInfoEXT info = VkDebugUtilsMessengerCreateInfoEXT.create(
+ 0,
+ VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT
+ | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
+ | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
+ VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
+ cb,
+ null,
+ frame);
+
+ logger = instance.vkCreateDebugUtilsMessengerEXT(info, scope);
+ }
+
+ //typedef VkBool32 (*PFN_vkDebugUtilsMessengerCallbackEXT)(VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT, const VkDebugUtilsMessengerCallbackDataEXT *, void *);
+ }
+
+ void init_instance() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ VkInstanceCreateInfo info = VkInstanceCreateInfo.create(
+ 0,
+ VkApplicationInfo.create("cube", 1, "cube-engine", 2, VK_API_VERSION_1_0, frame),
+ 1, new String[]{"VK_LAYER_KHRONOS_validation"},
+ 3, new String[]{"VK_KHR_surface", "VK_KHR_xlib_surface", "VK_EXT_debug_utils"},
+ frame
+ );
+
+ instance = VkInstance.vkCreateInstance(info, scope);
+ System.out.printf("instance = %s\n", instance);
+ }
+ }
+
+ Display display;
+ Window window;
+ VkSurfaceKHR surface;
+
+ void init_surface() throws Exception {
+ display = Display.createX11Display();
+ window = display.createWindow(width, height);
+ surface = window.createVulkanSurface(instance, scope);
+ System.out.printf("surface: %s\n", surface);
+ }
+
+ void init_device() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ IntArray count$h = IntArray.create(frame, 1);
+ IntArray present$h = IntArray.create(frame, 1);
+ HandleArray<VkPhysicalDevice> devs;
+ int count;
+ int res;
+
+ devs = instance.vkEnumeratePhysicalDevices(frame, scope);
+
+ // Search for device and queue indices
+ int devid = -1;
+ int present_queue = -1;
+ int graphics_queue = -1;
+ for (int i = 0; i < devs.length(); i++) {
+ VkPhysicalDevice dev = devs.getAtIndex(i);
+ VkQueueFamilyProperties famprops;
+
+ famprops = dev.vkGetPhysicalDeviceQueueFamilyProperties(frame);
+
+ for (int j = 0; j < famprops.length(); j++) {
+ boolean present = dev.vkGetPhysicalDeviceSurfaceSupportKHR(j, surface);
+
+ if (present && present_queue == -1)
+ present_queue = j;
+ if ((famprops.getQueueFlagsAtIndex(j) & VK_QUEUE_GRAPHICS_BIT) != 0) {
+ graphics_queue = j;
+ if (present) {
+ present_queue = j;
+ break;
+ }
+ }
+ }
+ if (present_queue != -1 && graphics_queue != -1) {
+ devid = i;
+ break;
+ }
+ }
+
+ if (devid == -1)
+ throw new Exception("Cannot find a suitable device");
+
+ physicalDevice = devs.getAtIndex(devid);
+ present_queue_index = present_queue;
+ graphics_queue_index = graphics_queue;
+
+ // NOTE: app scope
+ memory_properties = VkPhysicalDeviceMemoryProperties.create((SegmentAllocator)scope);
+ physicalDevice.vkGetPhysicalDeviceMemoryProperties(memory_properties);
+ device_features = VkPhysicalDeviceFeatures.create((SegmentAllocator)scope);
+ physicalDevice.vkGetPhysicalDeviceFeatures(device_features);
+
+ FloatArray qpri = FloatArray.create(frame, 0.0f);
+ VkDeviceQueueCreateInfo qinfo = VkDeviceQueueCreateInfo.create(
+ 0,
+ graphics_queue,
+ 1, qpri,
+ frame);
+ String[] extensions = {
+ "VK_KHR_swapchain"
+ };
+ VkPhysicalDeviceFeatures features = VkPhysicalDeviceFeatures.create(frame);
+ features.setDepthClamp(1);
+ VkDeviceCreateInfo devinfo = VkDeviceCreateInfo.create(
+ 0,
+ 1, qinfo,
+ 0, null,
+ extensions.length, extensions,
+ features,
+ frame);
+
+ device = physicalDevice.vkCreateDevice(devinfo, scope);
+
+ System.out.printf("device = %s\n", device);
+
+ /* ************************************************************** */
+ int format;
+ VkSurfaceFormatKHR surfFormats = physicalDevice.vkGetPhysicalDeviceSurfaceFormatsKHR(surface, frame);
+ // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
+ // the surface has no preferred format. Otherwise, at least one
+ // supported format will be returned.
+ if (surfFormats.length() == 1 && surfFormats.getFormatAtIndex(0) == VK_FORMAT_UNDEFINED) {
+ format = VK_FORMAT_B8G8R8A8_UNORM;
+ } else {
+ format = surfFormats.getFormatAtIndex(0);
+ }
+
+ VkSurfaceCapabilitiesKHR surfCapabilities = VkSurfaceCapabilitiesKHR.create(frame);
+
+ physicalDevice.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(surface, surfCapabilities);
+ IntArray presentModes = physicalDevice.vkGetPhysicalDeviceSurfacePresentModesKHR(surface, frame);
+
+ VkExtent2D swapchainExtent;
+ // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
+ if (surfCapabilities.getCurrentExtent().getWidth() == 0xFFFFFFFF) {
+ // If the surface size is undefined, the size is set to
+ // the size of the images requested.
+ swapchainExtent = VkExtent2D.create(
+ clampi(width, surfCapabilities.getMinImageExtent().getWidth(), surfCapabilities.getMaxImageExtent().getWidth()),
+ clampi(height, surfCapabilities.getMinImageExtent().getHeight(), surfCapabilities.getMaxImageExtent().getHeight()),
+ frame);
+ } else {
+ // If the surface size is defined, the swap chain size must match
+ swapchainExtent = surfCapabilities.getCurrentExtent();
+ }
+ int compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+ int compositeAlphaFlags[] = {
+ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+ VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
+ VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
+ VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,};
+ for (int flag: compositeAlphaFlags) {
+ if ((surfCapabilities.getSupportedCompositeAlpha() & flag) != 0) {
+ compositeAlpha = flag;
+ break;
+ }
+ }
+
+ VkSwapchainCreateInfoKHR chaininfo = VkSwapchainCreateInfoKHR.create(
+ 0,
+ surface,
+ surfCapabilities.getMinImageCount(),
+ format,
+ VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
+ swapchainExtent.getWidth(), swapchainExtent.getHeight(),
+ 1, //.imageArrayLayers = 1,
+ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+ VK_SHARING_MODE_EXCLUSIVE,
+ // assumes queues are same.
+ 0, null,
+ (surfCapabilities.getSupportedTransforms() & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) != 0
+ ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : surfCapabilities.getCurrentTransform(),
+ compositeAlpha,
+ VK_PRESENT_MODE_FIFO_KHR,
+ VK_TRUE,
+ null,
+ frame);
+
+ chain = device.vkCreateSwapchainKHR(chaininfo, scope);
+
+ int chainImageCount;
+
+ chainImage = device.vkGetSwapchainImagesKHR(chain, (SegmentAllocator)scope, scope);
+ chainImageCount = (int)chainImage.length();
+ chainImageView = VkImageView.createArray(chainImageCount, (SegmentAllocator)scope);
+
+ VkImageViewCreateInfo viewinfo = VkImageViewCreateInfo.create(
+ 0,
+ null,
+ VK_IMAGE_VIEW_TYPE_2D,
+ format,
+ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A,
+ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1,
+ frame);
+
+ for (int i = 0; i < chainImageCount; i++) {
+ viewinfo.setImage(chainImage.get(i));
+
+ chainImageView.setAtIndex(i, device.vkCreateImageView(viewinfo, scope));
+ }
+
+ chainImageFormat = format;
+ }
+ }
+
+ void init_device_queue() {
+ graphics_queue = device.vkGetDeviceQueue(graphics_queue_index, 0, scope);
+ if (graphics_queue_index == present_queue_index) {
+ present_queue = graphics_queue;
+ } else {
+ present_queue = device.vkGetDeviceQueue(present_queue_index, 0, scope);
+ }
+ }
+
+ void init_command() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ VkCommandPoolCreateInfo poolinfo = VkCommandPoolCreateInfo.create(
+ 0,
+ graphics_queue_index,
+ frame);
+
+ cmd_pool = device.vkCreateCommandPool(poolinfo, scope);
+
+ VkCommandBufferAllocateInfo cmdinfo = VkCommandBufferAllocateInfo.create(
+ cmd_pool,
+ VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+ 1,
+ frame);
+
+ cmd = device.vkAllocateCommandBuffers(cmdinfo, (SegmentAllocator)scope, scope);
+ }
+ }
+
+ // parameterise as init_image?
+ void init_depth() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ int format = VK_FORMAT_D16_UNORM;
+ VkMemoryRequirements req = VkMemoryRequirements.create(frame);
+ VkImageCreateInfo imageinfo = VkImageCreateInfo.create(
+ 0,
+ VK_IMAGE_TYPE_2D,
+ format,
+ width, height, 1,
+ 1,
+ 1,
+ NUM_SAMPLES,
+ 0,
+ VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
+ VK_SHARING_MODE_EXCLUSIVE,
+ 0, null,
+ VK_IMAGE_LAYOUT_UNDEFINED,
+ frame);
+
+ depthImage = device.vkCreateImage(imageinfo, scope);
+
+ device.vkGetImageMemoryRequirements(depthImage, req);
+ VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(
+ req.getSize(),
+ find_memory_type(memory_properties, req.getMemoryTypeBits(), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT),
+ frame);
+
+ depthMemory = device.vkAllocateMemory(alloc, scope);
+
+ device.vkBindImageMemory(depthImage, depthMemory, 0);
+
+ VkImageViewCreateInfo viewinfo = VkImageViewCreateInfo.create(
+ 0,
+ depthImage,
+ VK_IMAGE_VIEW_TYPE_2D,
+ VK_FORMAT_D16_UNORM,
+ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A,
+ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1,
+ frame);
+
+ depthView = device.vkCreateImageView(viewinfo, scope);
+ depthFormat = format;
+ }
+ }
+
+ void init_uniform() throws Exception {
+ uniform = init_buffer(mvp.length * 4, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, MemorySegment.ofArray(mvp));
+ }
+
+ void init_descriptor() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ HandleArray<VkDescriptorSetLayout> layout_table = VkDescriptorSetLayout.createArray(1, frame);
+ VkDescriptorSetLayoutBinding layout_binding = VkDescriptorSetLayoutBinding.create(
+ 0,
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ 1,
+ VK_SHADER_STAGE_VERTEX_BIT,
+ null,
+ frame);
+ VkDescriptorSetLayoutCreateInfo descriptor_layout = VkDescriptorSetLayoutCreateInfo.create(
+ 0,
+ 1, layout_binding,
+ frame);
+
+ desc_layout = device.vkCreateDescriptorSetLayout(descriptor_layout, scope);
+ layout_table.setAtIndex(0, desc_layout);
+
+ VkPipelineLayoutCreateInfo pipeline_info = VkPipelineLayoutCreateInfo.create(
+ 0,
+ 1, layout_table,
+ 0, null,
+ frame);
+
+ pipeline_layout = device.vkCreatePipelineLayout(pipeline_info, scope);
+
+ VkDescriptorPoolSize type_count = VkDescriptorPoolSize.create(
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ 1,
+ frame);
+
+ VkDescriptorPoolCreateInfo descriptor_pool = VkDescriptorPoolCreateInfo.create(
+ 0,
+ 1,
+ 1, type_count,
+ frame);
+
+ desc_pool = device.vkCreateDescriptorPool(descriptor_pool, scope);
+
+ VkDescriptorSetAllocateInfo alloc_info = VkDescriptorSetAllocateInfo.create(
+ desc_pool,
+ 1, layout_table,
+ frame);
+
+ System.out.println(alloc_info);
+
+ desc_set = device.vkAllocateDescriptorSets(alloc_info, (SegmentAllocator)scope, scope);
+
+ VkDescriptorBufferInfo uniformInfo = VkDescriptorBufferInfo.create(uniform.buffer, 0, uniform.size, frame);
+ VkWriteDescriptorSet writes = VkWriteDescriptorSet.create(
+ desc_set.getAtIndex(0),
+ 0,
+ 0,
+ 1,
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ null,
+ uniformInfo,
+ null,
+ frame);
+
+ device.vkUpdateDescriptorSets(1, writes, 0, null);
+ }
+ }
+
+ void init_render() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ VkAttachmentDescription attachments = VkAttachmentDescription.createArray(2, frame);
+
+ attachments.setFormat(chainImageFormat);
+ attachments.setSamples(NUM_SAMPLES);
+ attachments.setLoadOp(VK_ATTACHMENT_LOAD_OP_CLEAR);
+ attachments.setStoreOp(VK_ATTACHMENT_STORE_OP_STORE);
+ attachments.setStencilLoadOp(VK_ATTACHMENT_LOAD_OP_DONT_CARE);
+ attachments.setStencilStoreOp(VK_ATTACHMENT_STORE_OP_DONT_CARE);
+ attachments.setInitialLayout(VK_IMAGE_LAYOUT_UNDEFINED);
+ attachments.setFinalLayout(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
+ attachments.setFlags(0);
+
+ attachments.setFormatAtIndex(1, depthFormat);
+ attachments.setSamplesAtIndex(1, NUM_SAMPLES);
+ attachments.setLoadOpAtIndex(1, VK_ATTACHMENT_LOAD_OP_CLEAR);
+ attachments.setStoreOpAtIndex(1, VK_ATTACHMENT_STORE_OP_STORE);
+ attachments.setStencilLoadOpAtIndex(1, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
+ attachments.setStencilStoreOpAtIndex(1, VK_ATTACHMENT_STORE_OP_DONT_CARE);
+ attachments.setInitialLayoutAtIndex(1, VK_IMAGE_LAYOUT_UNDEFINED);
+ attachments.setFinalLayoutAtIndex(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+ attachments.setFlagsAtIndex(1, 0);
+
+ VkAttachmentReference color_reference = VkAttachmentReference.create(
+ 0,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ frame);
+
+ VkAttachmentReference depth_reference = VkAttachmentReference.create(
+ 1,
+ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+ frame);
+
+ VkSubpassDescription subpass = VkSubpassDescription.create(
+ 0,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ 0, null,
+ 1, color_reference, null, depth_reference,
+ 0, null,
+ frame);
+
+ VkRenderPassCreateInfo rp_info = VkRenderPassCreateInfo.create(
+ 0,
+ 2, attachments,
+ 1, subpass,
+ 0, null,
+ frame);
+
+ render_pass = device.vkCreateRenderPass(rp_info, scope);
+ }
+ }
+
+ void init_framebuffer() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ HandleArray<VkImageView> attachments = VkImageView.createArray(2, frame);
+
+ attachments.setAtIndex(1, depthView);
+
+ VkFramebufferCreateInfo fb_info = VkFramebufferCreateInfo.create(
+ 0,
+ render_pass,
+ 2, attachments,
+ width, height, 1,
+ frame);
+
+ framebuffers = VkFramebuffer.createArray(chainImage.length(), (SegmentAllocator)scope);
+ for (int i = 0; i < chainImage.size(); i++) {
+ attachments.setAtIndex(0, chainImageView.get(i));
+ framebuffers.setAtIndex(i, device.vkCreateFramebuffer(fb_info, scope));
+ System.out.printf("framebuffer[%d] = %s\n", i, framebuffers.getAtIndex(i));
+ }
+ }
+ }
+
+ void init_vertexbuffer() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ vertex = init_buffer(Cube.data.length * 4, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, MemorySegment.ofArray(Cube.data));
+
+ vertexBuffer.setAtIndex(0, vertex.buffer);
+
+ /* ***************************************** */
+ vi_binding.setBinding(0);
+ vi_binding.setInputRate(VK_VERTEX_INPUT_RATE_VERTEX);
+ vi_binding.setStride(Cube.dataStride);
+
+ vi_attribs.setBinding(0);
+ vi_attribs.setLocation(0);
+ vi_attribs.setFormat(VK_FORMAT_R32G32B32A32_SFLOAT);
+ vi_attribs.setOffset(0);
+ vi_attribs.setBindingAtIndex(1, 0);
+ vi_attribs.setLocationAtIndex(1, 1);
+ vi_attribs.setFormatAtIndex(1, VK_FORMAT_R32G32B32A32_SFLOAT);
+ vi_attribs.setOffsetAtIndex(1, 16);
+ }
+ }
+
+ void init_pipeline() throws Exception {
+ int res;
+ try ( Frame frame = Frame.frame()) {
+ IntArray dynamicStateEnables = IntArray.create(frame,
+ VK_DYNAMIC_STATE_VIEWPORT,
+ VK_DYNAMIC_STATE_SCISSOR);
+
+ VkPipelineDynamicStateCreateInfo dynamicState = VkPipelineDynamicStateCreateInfo.create(
+ 0,
+ 2, dynamicStateEnables,
+ frame);
+
+ VkPipelineVertexInputStateCreateInfo vi = VkPipelineVertexInputStateCreateInfo.create(
+ 0,
+ (int)vi_binding.length(), vi_binding,
+ (int)vi_attribs.length(), vi_attribs,
+ frame);
+
+ VkPipelineInputAssemblyStateCreateInfo ia = VkPipelineInputAssemblyStateCreateInfo.create(
+ 0,
+ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
+ 0,
+ frame);
+
+ VkPipelineRasterizationStateCreateInfo rs = VkPipelineRasterizationStateCreateInfo.create(
+ 0,
+ VK_TRUE,
+ VK_FALSE,
+ VK_POLYGON_MODE_FILL,
+ VK_CULL_MODE_BACK_BIT,
+ VK_FRONT_FACE_CLOCKWISE,
+ VK_FALSE,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ frame);
+
+ VkPipelineColorBlendAttachmentState att_state = VkPipelineColorBlendAttachmentState.create(
+ VK_FALSE,
+ VK_BLEND_FACTOR_ZERO,
+ VK_BLEND_FACTOR_ZERO,
+ VK_BLEND_OP_ADD,
+ VK_BLEND_FACTOR_ZERO,
+ VK_BLEND_FACTOR_ZERO,
+ VK_BLEND_OP_ADD,
+ 0xf,
+ frame);
+
+ VkPipelineColorBlendStateCreateInfo cb = VkPipelineColorBlendStateCreateInfo.create(
+ 0,
+ VK_FALSE,
+ VK_LOGIC_OP_NO_OP,
+ 1, att_state,
+ 1.0f, 1.0f, 1.0f, 1.0f,
+ frame);
+
+ VkPipelineViewportStateCreateInfo vp = VkPipelineViewportStateCreateInfo.create(
+ 0,
+ 1, null,
+ 1, null,
+ frame);
+
+ VkPipelineDepthStencilStateCreateInfo ds = VkPipelineDepthStencilStateCreateInfo.create(
+ 0,
+ VK_TRUE,
+ VK_TRUE,
+ VK_COMPARE_OP_LESS_OR_EQUAL,
+ VK_FALSE,
+ VK_FALSE,
+ 0.0f,
+ 0.0f,
+ frame);
+ VkStencilOpState back = ds.getBack();
+
+ back.setFailOp(VK_STENCIL_OP_KEEP);
+ back.setPassOp(VK_STENCIL_OP_KEEP);
+ back.setCompareOp(VK_COMPARE_OP_ALWAYS);
+ back.setCompareMask(0);
+ back.setReference(0);
+ back.setDepthFailOp(VK_STENCIL_OP_KEEP);
+ back.setWriteMask(0);
+
+ VkStencilOpState front = ds.getFront();
+
+ front.setFailOp(VK_STENCIL_OP_KEEP);
+ front.setPassOp(VK_STENCIL_OP_KEEP);
+ front.setCompareOp(VK_COMPARE_OP_ALWAYS);
+ front.setCompareMask(0);
+ front.setReference(0);
+ front.setDepthFailOp(VK_STENCIL_OP_KEEP);
+ front.setWriteMask(0);
+
+ VkPipelineMultisampleStateCreateInfo ms = VkPipelineMultisampleStateCreateInfo.create(
+ 0,
+ NUM_SAMPLES,
+ 0, //.sampleShadingEnable = VK_FALSE,
+ 0.0f,
+ null,
+ 0, //.alphaToCoverageEnable = VK_FALSE,
+ 0, //.alphaToOneEnable = VK_FALSE,
+ frame
+ );
+
+ VkShaderModuleCreateInfo vsInfo = VkShaderModuleCreateInfo.create(
+ 0,
+ cube_vs.length() * 4,
+ cube_vs,
+ frame);
+ VkShaderModuleCreateInfo fsInfo = VkShaderModuleCreateInfo.create(
+ 0,
+ cube_fs.length() * 4,
+ cube_fs,
+ frame);
+
+ shader.setAtIndex(0, device.vkCreateShaderModule(vsInfo, scope));
+ shader.setAtIndex(1, device.vkCreateShaderModule(fsInfo, scope));
+
+ VkPipelineShaderStageCreateInfo shaderStages = VkPipelineShaderStageCreateInfo.createArray(2, (SegmentAllocator)scope);
+
+ shaderStages.setStage(VK_SHADER_STAGE_VERTEX_BIT);
+ shaderStages.setName("main", (SegmentAllocator)scope);
+ shaderStages.setModule(shader.get(0));
+
+ shaderStages.setStageAtIndex(1, VK_SHADER_STAGE_FRAGMENT_BIT);
+ shaderStages.setNameAtIndex(1, "main", (SegmentAllocator)scope);
+ shaderStages.setModuleAtIndex(1, shader.get(1));
+
+ VkGraphicsPipelineCreateInfo pipeline = VkGraphicsPipelineCreateInfo.create(
+ 0,
+ 2, shaderStages,
+ vi,
+ ia,
+ null,
+ vp,
+ rs,
+ ms,
+ ds,
+ cb,
+ dynamicState,
+ pipeline_layout,
+ render_pass,
+ 0,
+ null,
+ 0,
+ frame);
+
+ res = device.vkCreateGraphicsPipelines(null, 1, pipeline, this.pipeline);
+
+ VkSemaphoreCreateInfo seminfo = VkSemaphoreCreateInfo.create(0, frame);
+ chainSemaphore = device.vkCreateSemaphore(seminfo, scope);
+
+ VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(0, frame);
+ drawFence = device.vkCreateFence(fenceInfo, scope);
+ }
+ }
+
+ void execute_begin_command_buffer() throws Exception {
+ /* DEPENDS on init_command() */
+ try ( Frame frame = Frame.frame()) {
+ VkCommandBufferBeginInfo cmd_buf_info = VkCommandBufferBeginInfo.create(
+ 0,
+ null,
+ frame);
+
+ cmd.getAtIndex(0).vkBeginCommandBuffer(cmd_buf_info);
+ }
+ }
+
+ void execute_end_command_buffer() throws Exception {
+ cmd.getAtIndex(0).vkEndCommandBuffer();
+ }
+
+ final static long FENCE_TIMEOUT = 100000000;
+
+ void execute_queue_command_buffer() throws Exception {
+ int res;
+
+ /* Queue the command buffer for execution */
+ /* FIXME: frame shoudl provide or take explicit scope */
+ try ( ResourceScope scope = ResourceScope.newConfinedScope(); Frame frame = Frame.frame()) {
+ IntArray pipe_stage_flags = IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
+ VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(0, frame);
+ HandleArray<VkFence> fences = VkFence.createArray(1, frame);
+
+ fences.setAtIndex(0, device.vkCreateFence(fenceInfo, scope));
+
+ VkSubmitInfo submit_info = VkSubmitInfo.create(
+ 1, null, pipe_stage_flags,
+ (int)cmd.length(), cmd,
+ 0, null,
+ frame);
+
+ graphics_queue.vkQueueSubmit(1, submit_info, drawFence);
+
+ do {
+ res = device.vkWaitForFences(1, fences, 1, FENCE_TIMEOUT);
+ } while (res == VK_TIMEOUT);
+
+ device.vkDestroyFence(fences.getAtIndex(0));
+ }
+ }
+
+ void cmd_viewport() {
+ try ( Frame frame = Frame.frame()) {
+ VkCommandBuffer cmd = this.cmd.getAtIndex(0);
+ VkViewport viewport = VkViewport.create(
+ 0, 0, width, height, 0.0f, 1.0f,
+ frame);
+ cmd.vkCmdSetViewport(0, 1, viewport);
+ }
+ }
+
+ void cmd_scissors() {
+ try ( Frame frame = Frame.frame()) {
+ VkCommandBuffer cmd = this.cmd.getAtIndex(0);
+ VkRect2D scissor = VkRect2D.create(0, 0, width, height, frame);
+ cmd.vkCmdSetScissor(0, 1, scissor);
+ }
+ }
+
+ void cmd_paint() throws Exception {
+ int res;
+ try ( Frame frame = Frame.frame()) {
+ int chainIndex;
+ IntArray chainIndices = IntArray.createArray(1, frame);
+ VkCommandBuffer cmd = this.cmd.getAtIndex(0);
+
+ device.vkAcquireNextImageKHR(chain, ~0L, chainSemaphore, null, chainIndices);
+ chainIndex = chainIndices.getAtIndex(0);
+ LongArray offsets = LongArray.createArray(1, frame);
+
+ VkClearValue clear_values = VkClearValue.createArray(2, frame);
+ FloatArray col = clear_values.getColor().getFloat32();
+ col.setAtIndex(0, 0.2f);
+ col.setAtIndex(1, 0.2f);
+ col.setAtIndex(2, 0.2f);
+ col.setAtIndex(3, 0.2f);
+ VkClearDepthStencilValue depthStencil = clear_values.getAtIndex(1).getDepthStencil();
+ depthStencil.setDepth(1.0f);
+ depthStencil.setStencil(0);
+
+ System.out.printf("render framebuffer[%d] = %s\n", chainIndex, framebuffers.getAtIndex(chainIndex));
+
+ VkRenderPassBeginInfo rp_begin = VkRenderPassBeginInfo.create(
+ render_pass,
+ framebuffers.getAtIndex(chainIndex),
+ 0, 0, width, height,
+ 2, clear_values,
+ frame);
+
+ cmd.vkCmdBeginRenderPass(rp_begin, VK_SUBPASS_CONTENTS_INLINE);
+
+ cmd.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.getAtIndex(0));
+ cmd.vkCmdBindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, NUM_DESCRIPTOR_SETS, desc_set, 0, null);
+ cmd.vkCmdBindVertexBuffers(0, 1, vertexBuffer, offsets);
+
+ cmd_viewport();
+ cmd_scissors();
+
+ cmd.vkCmdDraw(12 * 3, 1, 0, 0);
+ cmd.vkCmdEndRenderPass();
+
+ cmd.vkEndCommandBuffer();
+
+ IntArray pipe_stage_flags = IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
+ HandleArray<VkSemaphore> semaphores = VkSemaphore.createArray(1, frame);//, chainSemaphore, scope);
+
+ semaphores.setAtIndex(0, chainSemaphore);
+
+ VkSubmitInfo submit_info = VkSubmitInfo.create(
+ 1, semaphores, pipe_stage_flags,
+ (int)this.cmd.length(), this.cmd,
+ 0, null,
+ frame);
+
+ HandleArray<VkFence> fences = VkFence.createArray(1, frame);
+
+ fences.setAtIndex(0, drawFence);
+
+ // Queue the command buffer for execution
+ device.vkResetFences(1, fences);
+
+ graphics_queue.vkQueueSubmit(1, submit_info, drawFence);
+
+ // Make sure command buffer is finished before presenting
+ do {
+ res = device.vkWaitForFences(1, fences, VK_TRUE, FENCE_TIMEOUT);
+ } while (res == VK_TIMEOUT);
+
+ // Now present the image in the window
+ HandleArray<VkSwapchainKHR> chains = VkSwapchainKHR.createArray(1, frame);
+ chains.setAtIndex(0, chain);
+ VkPresentInfoKHR present = VkPresentInfoKHR.create(
+ 0, null,
+ 1, chains, chainIndices, null,
+ frame);
+
+ present_queue.vkQueuePresentKHR(present);
+ }
+ }
+
+ /**
+ * Buffers are created in three steps:
+ * 1) create buffer, specifying usage and size
+ * 2) allocate memory based on memory requirements
+ * 3) bind memory
+ * <p>
+ */
+ BufferMemory init_buffer(long dataSize, int usage, int properties, MemorySegment init) throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ VkMemoryRequirements req = VkMemoryRequirements.create(frame);
+ VkBufferCreateInfo buf_info = VkBufferCreateInfo.create(
+ 0,
+ dataSize,
+ usage,
+ VK_SHARING_MODE_EXCLUSIVE,
+ 0, null,
+ frame);
+
+ VkBuffer buffer = device.vkCreateBuffer(buf_info, scope);
+
+ device.vkGetBufferMemoryRequirements(buffer, req);
+
+ VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(
+ req.getSize(),
+ find_memory_type(memory_properties, req.getMemoryTypeBits(), properties),
+ frame);
+
+ VkDeviceMemory memory = device.vkAllocateMemory(alloc, scope);
+
+ if (init != null) {
+ MemorySegment mem = device.vkMapMemory(memory, 0, dataSize, 0, scope);
+ mem.copyFrom(init);
+ device.vkUnmapMemory(memory);
+ }
+
+ device.vkBindBufferMemory(buffer, memory, 0);
+
+ return new BufferMemory(buffer, memory, dataSize);
+ }
+ }
+
+ void shutdown() {
+ device.vkDestroyFence(drawFence);
+ device.vkDestroySemaphore(chainSemaphore);
+
+ device.vkDestroyPipeline(pipeline.getAtIndex(0));
+ for (int i = 0; i < shader.size(); i++)
+ device.vkDestroyShaderModule(shader.getAtIndex(i));
+
+ vertex.free(device);
+ uniform.free(device);
+
+ for (int i = 0; i < framebuffers.size(); i++)
+ device.vkDestroyFramebuffer(framebuffers.getAtIndex(i));
+
+ device.vkDestroyRenderPass(render_pass);
+
+ device.vkDestroyDescriptorPool(desc_pool);
+ device.vkDestroyPipelineLayout(pipeline_layout);
+ device.vkDestroyDescriptorSetLayout(desc_layout);
+
+ device.vkDestroyImageView(depthView);
+ device.vkFreeMemory(depthMemory);
+ device.vkDestroyImage(depthImage);
+
+ for (int i = 0; i < chainImageView.size(); i++)
+ device.vkDestroyImageView(chainImageView.getAtIndex(i));
+
+ device.vkDestroySwapchainKHR(chain);
+
+ device.vkDestroyCommandPool(cmd_pool);
+ device.vkDestroyDevice();
+
+ instance.vkDestroySurfaceKHR(surface);
+ window.close();
+ display.close();
+
+ if (logger != null)
+ instance.vkDestroyDebugUtilsMessengerEXT(logger);
+ instance.vkDestroyInstance();
+ }
+
+ /**
+ * This finds the memory type index for the memory on a specific device.
+ */
+ static int find_memory_type(VkPhysicalDeviceMemoryProperties memory, int typeMask, int query) {
+ VkMemoryType mtypes = memory.getMemoryTypes();
+
+ for (int i = 0; i < memory.getMemoryTypeCount(); i++) {
+ if (((1 << i) & typeMask) != 0 && ((mtypes.getPropertyFlagsAtIndex(i) & query) == query))
+ return i;
+ }
+ return -1;
+ }
+
+ static int clampi(int v, int min, int max) {
+ return v < min ? min : v < max ? v : max;
+ }
+
+ void init_matrices() {
+ float eye[] = new float[]{-5, 3, -10};
+ float centre[] = new float[]{0, 0, 0};
+ float up[] = new float[]{0, -1, 0};
+ float t0[] = new float[16], t1[] = new float[16];
+
+ perspective(projection, (float)(Math.PI * 0.25), 1.0f, 0.1f, 100.0f);
+ lookAt(view, eye, centre, up);
+ identity4f(model);
+ mult4x4f(t0, clip, projection);
+ mult4x4f(t1, t0, view);
+ mult4x4f(mvp, t1, model);
+ }
+
+ void demo() throws Exception {
+ cube_vs = ShaderIO.loadCube_vert((SegmentAllocator)scope);
+ cube_fs = ShaderIO.loadCube_frag((SegmentAllocator)scope);
+
+ init_matrices();
+
+ init_instance();
+ init_debug();
+ init_surface();
+ init_device();
+ init_device_queue();
+
+ init_command();
+ init_depth();
+ init_uniform();
+
+ init_descriptor();
+ init_render();
+ init_framebuffer();
+ init_vertexbuffer();
+ init_pipeline();
+
+ execute_begin_command_buffer();
+
+ cmd_paint();
+
+ System.out.println("Any key to quit");
+ Event e;
+outer: while ((e = window.nextEvent(true)) != null) {
+ switch (e.type) {
+ case Event.KEY:
+ case Event.CLOSE:
+ break outer;
+ }
+ }
+
+ shutdown();
+ }
+
+ public static void main(String[] args) throws Throwable {
+ System.loadLibrary("vulkan");
+ System.loadLibrary("X11");
+
+ new TestCube().demo();
+ }
+}
--- /dev/null
+/*
+The MIT License (MIT)
+
+Copyright (C) 2017 Eric Arnebäck
+Copyright (C) 2019 Michael Zucchi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+ */
+
+ /*
+ * This is a Java conversion of a C conversion of this:
+ * https://github.com/Erkaman/vulkan_minimal_compute
+ *
+ * It's been simplified a bit and converted to the 'zvk' api.
+ */
+package vulkan.test;
+
+import java.io.InputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.channels.Channels;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.awt.image.MemoryImageSource;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import jdk.incubator.foreign.*;
+import au.notzed.nativez.*;
+import java.util.ArrayList;
+import java.util.List;
+
+import vulkan.*;
+import static vulkan.Vulkan.*;
+
+public class TestMandelbrot {
+
+ static final boolean debug = true;
+ ResourceScope scope = ResourceScope.newSharedScope();
+
+ int WIDTH = 1920 * 1;
+ int HEIGHT = 1080 * 1;
+
+ VkInstance instance;
+ VkPhysicalDevice physicalDevice;
+
+ VkDevice device;
+ VkQueue computeQueue;
+
+ long dstBufferSize = WIDTH * HEIGHT * 4;
+ //VkBuffer dstBuffer;
+ //VkDeviceMemory dstMemory;
+ BufferMemory dst;
+
+ VkDescriptorSetLayout descriptorSetLayout;
+ VkDescriptorPool descriptorPool;
+ HandleArray<VkDescriptorSet> descriptorSets;
+
+ int computeQueueIndex;
+ VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
+
+ String mandelbrot_entry = "main";
+ IntArray mandelbrot_cs;
+
+ VkShaderModule mandelbrotShader;
+ VkPipelineLayout pipelineLayout;
+ HandleArray<VkPipeline> computePipeline = VkPipeline.createArray(1, (SegmentAllocator)scope);
+
+ VkCommandPool commandPool;
+ HandleArray<VkCommandBuffer> commandBuffers;
+
+ record BufferMemory(VkBuffer buffer, VkDeviceMemory memory) {
+
+ }
+
+ VkDebugUtilsMessengerEXT logger;
+
+ void init_debug() throws Exception {
+ if (!debug)
+ return;
+ try ( Frame frame = Frame.frame()) {
+ var cb = PFN_vkDebugUtilsMessengerCallbackEXT.upcall((severity, flags, data) -> {
+ System.out.printf("Debug: %d: %s\n", severity, data.getMessage());
+ return 0;
+ }, scope);
+ VkDebugUtilsMessengerCreateInfoEXT info = VkDebugUtilsMessengerCreateInfoEXT.create(
+ 0,
+ //VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
+ VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT
+ | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
+ | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
+ VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT
+ | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT
+ | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
+ cb,
+ null,
+ frame);
+
+ logger = instance.vkCreateDebugUtilsMessengerEXT(info, scope);
+ }
+ }
+
+ void init_instance() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ VkInstanceCreateInfo info = VkInstanceCreateInfo.create(
+ 0,
+ VkApplicationInfo.create("test", 1, "test-engine", 2, VK_API_VERSION_1_0, frame),
+ 1,
+ new String[]{"VK_LAYER_KHRONOS_validation"},
+ debug ? 1 : 0,
+ debug ? new String[]{"VK_EXT_debug_utils"} : null,
+ frame
+ );
+
+ instance = VkInstance.vkCreateInstance(info, scope);
+ }
+ }
+
+ void init_device() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ HandleArray<VkPhysicalDevice> devs;
+ int count;
+ int res;
+
+ devs = instance.vkEnumeratePhysicalDevices(frame, scope);
+
+ int best = 0;
+ int devid = -1;
+ int queueid = -1;
+
+ for (int i = 0; i < devs.length(); i++) {
+ VkPhysicalDevice dev = devs.getAtIndex(i);
+ VkQueueFamilyProperties famprops = dev.vkGetPhysicalDeviceQueueFamilyProperties(frame);
+ int family_count = (int)famprops.length();
+
+ for (int j = 0; j < family_count; j++) {
+ var flags = famprops.getAtIndex(j).getQueueFlags();
+ int score = 0;
+
+ if ((flags & VK_QUEUE_COMPUTE_BIT) != 0)
+ score += 1;
+ if ((flags & VK_QUEUE_GRAPHICS_BIT) == 0)
+ score += 1;
+
+ if (score > best) {
+ score = best;
+ devid = i;
+ queueid = j;
+ }
+ }
+ }
+
+ if (devid == -1)
+ throw new Exception("Cannot find a suitable device");
+
+ computeQueueIndex = queueid;
+ physicalDevice = devs.getAtIndex(devid);
+
+ FloatArray qpri = FloatArray.create(frame, 0.0f);
+ VkDeviceQueueCreateInfo qinfo = VkDeviceQueueCreateInfo.create(
+ 0,
+ queueid,
+ 1,
+ qpri,
+ frame);
+ VkDeviceCreateInfo devinfo = VkDeviceCreateInfo.create(
+ 0,
+ 1, qinfo,
+ 0, null,
+ 0, null,
+ null,
+ frame);
+
+ device = physicalDevice.vkCreateDevice(devinfo, scope);
+
+ System.out.printf("device = %s\n", device.address());
+
+ // NOTE: app scope
+ deviceMemoryProperties = VkPhysicalDeviceMemoryProperties.create((SegmentAllocator)scope);
+ physicalDevice.vkGetPhysicalDeviceMemoryProperties(deviceMemoryProperties);
+
+ computeQueue = device.vkGetDeviceQueue(queueid, 0, scope);
+ }
+ }
+
+ /**
+ * Buffers are created in three steps:
+ * 1) create buffer, specifying usage and size
+ * 2) allocate memory based on memory requirements
+ * 3) bind memory
+ * <p>
+ */
+ BufferMemory init_buffer(long dataSize, int usage, int properties) throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ VkMemoryRequirements req = VkMemoryRequirements.create(frame);
+ VkBufferCreateInfo buf_info = VkBufferCreateInfo.create(
+ 0,
+ dataSize,
+ usage,
+ VK_SHARING_MODE_EXCLUSIVE,
+ 0, null,
+ frame);
+
+ VkBuffer buffer = device.vkCreateBuffer(buf_info, scope);
+
+ device.vkGetBufferMemoryRequirements(buffer, req);
+
+ VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(
+ req.getSize(),
+ find_memory_type(deviceMemoryProperties, req.getMemoryTypeBits(), properties),
+ frame);
+
+ VkDeviceMemory memory = device.vkAllocateMemory(alloc, scope);
+
+ device.vkBindBufferMemory(buffer, memory, 0);
+
+ return new BufferMemory(buffer, memory);
+ }
+ }
+
+ /**
+ * Descriptors are used to bind and describe memory blocks
+ * to shaders.
+ * <p>
+ * *Pool is used to allocate descriptors, it is per-device.
+ * *Layout is used to group descriptors for a given pipeline,
+ * The descriptors describe individually-addressable blocks.
+ */
+ void init_descriptor() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ /* Create descriptorset layout */
+ VkDescriptorSetLayoutBinding layout_binding = VkDescriptorSetLayoutBinding.create(
+ 0,
+ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ 1,
+ VK_SHADER_STAGE_COMPUTE_BIT,
+ null,
+ frame);
+
+ VkDescriptorSetLayoutCreateInfo descriptor_layout = VkDescriptorSetLayoutCreateInfo.create(
+ 0,
+ 1, layout_binding,
+ frame);
+
+ descriptorSetLayout = device.vkCreateDescriptorSetLayout(descriptor_layout, scope);
+
+ /* Create descriptor pool */
+ VkDescriptorPoolSize type_count = VkDescriptorPoolSize.create(
+ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ 1,
+ frame);
+
+ VkDescriptorPoolCreateInfo descriptor_pool = VkDescriptorPoolCreateInfo.create(
+ 0,
+ 1,
+ 1, type_count,
+ frame);
+
+ descriptorPool = device.vkCreateDescriptorPool(descriptor_pool, scope);
+
+ /* Allocate from pool */
+ HandleArray<VkDescriptorSetLayout> layout_table = VkDescriptorSetLayout.createArray(1, frame);
+
+ layout_table.setAtIndex(0, descriptorSetLayout);
+
+ VkDescriptorSetAllocateInfo alloc_info = VkDescriptorSetAllocateInfo.create(
+ descriptorPool,
+ 1, layout_table,
+ frame);
+
+ descriptorSets = device.vkAllocateDescriptorSets(alloc_info, (SegmentAllocator)scope, scope);
+
+ /* Bind a buffer to the descriptor */
+ VkDescriptorBufferInfo bufferInfo = VkDescriptorBufferInfo.create(
+ dst.buffer,
+ 0,
+ dstBufferSize,
+ frame);
+
+ VkWriteDescriptorSet writeSet = VkWriteDescriptorSet.create(
+ descriptorSets.getAtIndex(0),
+ 0,
+ 0,
+ 1,
+ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ null,
+ bufferInfo,
+ null,
+ frame);
+
+ System.out.println(writeSet);
+
+ device.vkUpdateDescriptorSets(1, writeSet, 0, null);
+ }
+ }
+
+ /**
+ * Create the compute pipeline. This is the shader and data layouts for it.
+ */
+ void init_pipeline() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ /* Set shader code */
+ VkShaderModuleCreateInfo vsInfo = VkShaderModuleCreateInfo.create(
+ 0,
+ mandelbrot_cs.length() * 4,
+ mandelbrot_cs,
+ frame);
+
+ mandelbrotShader = device.vkCreateShaderModule(vsInfo, scope);
+
+ /* Link shader to layout */
+ HandleArray<VkDescriptorSetLayout> layout_table = VkDescriptorSetLayout.createArray(1, frame);
+
+ layout_table.setAtIndex(0, descriptorSetLayout);
+
+ VkPipelineLayoutCreateInfo pipelineinfo = VkPipelineLayoutCreateInfo.create(
+ 0,
+ 1, layout_table,
+ 0, null,
+ frame);
+
+ pipelineLayout = device.vkCreatePipelineLayout(pipelineinfo, scope);
+
+ /* Create pipeline */
+ VkComputePipelineCreateInfo pipeline = VkComputePipelineCreateInfo.create(
+ 0,
+ pipelineLayout,
+ null,
+ 0,
+ frame);
+
+ VkPipelineShaderStageCreateInfo stage = pipeline.getStage();
+
+ stage.setStage(VK_SHADER_STAGE_COMPUTE_BIT);
+ stage.setModule(mandelbrotShader);
+ stage.setName(mandelbrot_entry, frame);
+
+ device.vkCreateComputePipelines(null, 1, pipeline, computePipeline);
+ }
+ }
+
+ /**
+ * Create a command buffer, this is somewhat like a display list.
+ */
+ void init_command_buffer() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ VkCommandPoolCreateInfo poolinfo = VkCommandPoolCreateInfo.create(
+ 0,
+ computeQueueIndex,
+ frame);
+
+ commandPool = device.vkCreateCommandPool(poolinfo, scope);
+
+ VkCommandBufferAllocateInfo cmdinfo = VkCommandBufferAllocateInfo.create(
+ commandPool,
+ VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+ 1,
+ frame);
+
+ // should it take a scope?
+ commandBuffers = device.vkAllocateCommandBuffers(cmdinfo, (SegmentAllocator)scope, scope);
+
+ /* Fill command buffer with commands for later operation */
+ VkCommandBufferBeginInfo beginInfo = VkCommandBufferBeginInfo.create(
+ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
+ null,
+ frame);
+
+ commandBuffers.get(0).vkBeginCommandBuffer(beginInfo);
+
+ /* Bind the compute operation and data */
+ commandBuffers.get(0).vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline.get(0));
+ commandBuffers.get(0).vkCmdBindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0, 1, descriptorSets, 0, null);
+
+ /* Run it */
+ commandBuffers.get(0).vkCmdDispatch(WIDTH, HEIGHT, 1);
+
+ commandBuffers.get(0).vkEndCommandBuffer();
+ }
+ }
+
+ /**
+ * Execute the pre-created command buffer.
+ * <p>
+ * A fence is used to wait for completion.
+ */
+ void execute() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ VkSubmitInfo submitInfo = VkSubmitInfo.create(frame);
+
+ submitInfo.setCommandBufferCount(1);
+ submitInfo.setCommandBuffers(commandBuffers);
+
+ /* Create fence to mark the task completion */
+ VkFence fence;
+ HandleArray<VkFence> fences = VkFence.createArray(1, frame);
+ VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(frame);
+
+ // maybe this should take a HandleArray<Fence> rather than being a constructor
+ // FIXME: some local scope
+ fence = device.vkCreateFence(fenceInfo, scope);
+ fences.set(0, fence);
+
+ /* Await completion */
+ computeQueue.vkQueueSubmit(1, submitInfo, fence);
+
+ int VK_TRUE = 1;
+ int res;
+ do {
+ res = device.vkWaitForFences(1, fences, VK_TRUE, 1000000);
+ } while (res == VK_TIMEOUT);
+
+ device.vkDestroyFence(fence);
+ }
+ }
+
+ void shutdown() {
+ device.vkDestroyCommandPool(commandPool);
+ device.vkDestroyPipeline(computePipeline.getAtIndex(0));
+ device.vkDestroyPipelineLayout(pipelineLayout);
+ device.vkDestroyShaderModule(mandelbrotShader);
+
+ device.vkDestroyDescriptorPool(descriptorPool);
+ device.vkDestroyDescriptorSetLayout(descriptorSetLayout);
+
+ device.vkFreeMemory(dst.memory());
+ device.vkDestroyBuffer(dst.buffer());
+
+ device.vkDestroyDevice();
+ if (logger != null)
+ instance.vkDestroyDebugUtilsMessengerEXT(logger);
+ instance.vkDestroyInstance();
+ }
+
+ /**
+ * Accesses the gpu buffer, converts it to RGB byte, and saves it as a pam file.
+ */
+ void save_result() throws Exception {
+ try ( ResourceScope scope = ResourceScope.newConfinedScope()) {
+ MemorySegment mem = device.vkMapMemory(dst.memory(), 0, dstBufferSize, 0, scope);
+ byte[] pixels = new byte[WIDTH * HEIGHT * 3];
+
+ System.out.printf("map %d bytes\n", dstBufferSize);
+
+ for (int i = 0; i < WIDTH * HEIGHT; i++) {
+ pixels[i * 3 + 0] = mem.get(Memory.BYTE, i * 4 + 0);
+ pixels[i * 3 + 1] = mem.get(Memory.BYTE, i * 4 + 1);
+ pixels[i * 3 + 2] = mem.get(Memory.BYTE, i * 4 + 2);
+ }
+
+ device.vkUnmapMemory(dst.memory());
+
+ pam_save("mandelbrot.pam", WIDTH, HEIGHT, 3, pixels);
+ }
+ }
+
+ void show_result() throws Exception {
+ try ( ResourceScope scope = ResourceScope.newConfinedScope()) {
+ MemorySegment mem = device.vkMapMemory(dst.memory(), 0, dstBufferSize, 0, scope);
+ int[] pixels = new int[WIDTH * HEIGHT];
+
+ System.out.printf("map %d bytes\n", dstBufferSize);
+
+ MemorySegment.ofArray(pixels).copyFrom(mem);
+
+ device.vkUnmapMemory(dst.memory());
+
+ swing_show(WIDTH, HEIGHT, pixels);
+ }
+ }
+
+ /**
+ * Trivial pnm format image output.
+ */
+ void pam_save(String name, int width, int height, int depth, byte[] pixels) throws IOException {
+ try ( FileOutputStream fos = new FileOutputStream(name)) {
+ fos.write(String.format("P6\n%d\n%d\n255\n", width, height).getBytes());
+ fos.write(pixels);
+ System.out.printf("wrote: %s\n", name);
+ }
+ }
+
+ static class DataImage extends JPanel {
+
+ final int w, h, stride;
+ final MemoryImageSource source;
+ final Image image;
+ final int[] pixels;
+
+ public DataImage(int w, int h, int[] pixels) {
+ this.w = w;
+ this.h = h;
+ this.stride = w;
+ this.pixels = pixels;
+ this.source = new MemoryImageSource(w, h, pixels, 0, w);
+ this.source.setAnimated(true);
+ this.source.setFullBufferUpdates(true);
+ this.image = Toolkit.getDefaultToolkit().createImage(source);
+ }
+
+ @Override
+ protected void paintComponent(Graphics g) {
+ super.paintComponent(g);
+ g.drawImage(image, 0, 0, this);
+ }
+ }
+
+ void swing_show(int w, int h, int[] pixels) {
+ JFrame window;
+ DataImage image = new DataImage(w, h, pixels);
+
+ window = new JFrame("mandelbrot");
+ window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ window.setContentPane(image);
+ window.setSize(w, h);
+ window.setVisible(true);
+ }
+
+ /**
+ * This finds the memory type index for the memory on a specific device.
+ */
+ static int find_memory_type(VkPhysicalDeviceMemoryProperties memory, int typeMask, int query) {
+ VkMemoryType mtypes = memory.getMemoryTypes();
+
+ for (int i = 0; i < memory.getMemoryTypeCount(); i++) {
+ if (((1 << i) & typeMask) != 0 && ((mtypes.getAtIndex(i).getPropertyFlags() & query) == query))
+ return i;
+ }
+ return -1;
+ }
+
+ void demo() throws Exception {
+ mandelbrot_cs = ShaderIO.loadMandelbrot_comp((SegmentAllocator)scope);
+
+ init_instance();
+ init_debug();
+
+ init_device();
+
+ dst = init_buffer(dstBufferSize,
+ VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
+
+ init_descriptor();
+
+ init_pipeline();
+ init_command_buffer();
+
+ System.out.printf("Calculating %dx%d\n", WIDTH, HEIGHT);
+ execute();
+ //System.out.println("Saving ...");
+ //save_result();
+ System.out.println("Showing ...");
+ show_result();
+ System.out.println("Done.");
+
+ shutdown();
+ }
+
+ public static void main(String[] args) throws Throwable {
+ System.loadLibrary("vulkan");
+
+ new TestMandelbrot().demo();
+ }
+}
--- /dev/null
+/*
+The MIT License (MIT)
+
+Copyright (C) 2017 Eric Arnebäck
+Copyright (C) 2019 Michael Zucchi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+ */
+
+ /*
+ * This is a Java conversion of a C conversion of this:
+ * https://github.com/Erkaman/vulkan_minimal_compute
+ *
+ * It's been simplified a bit and converted to the 'zvk' api.
+ */
+package vulkan.test;
+
+import au.notzed.display.Display;
+import au.notzed.display.Event;
+import au.notzed.display.Window;
+import jdk.incubator.foreign.*;
+import au.notzed.nativez.*;
+
+import vulkan.*;
+import static vulkan.Vulkan.*;
+
+import static vulkan.test.GLMaths.*;
+
+public class TestSDF {
+
+ static final boolean debug = true;
+
+ final static int NUM_SAMPLES = VK_SAMPLE_COUNT_1_BIT;
+ final static int NUM_DESCRIPTOR_SETS = 1;
+
+ ResourceScope scope = ResourceScope.newSharedScope();
+
+ int width = 800;
+ int height = 800;
+ float projection[] = new float[16];
+ float view[] = new float[16];
+ float model[] = new float[16];
+ float clip[] = new float[]{
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.5f, 0.0f,
+ 0.0f, 0.0f, 0.5f, 1.0f
+ };
+ float mvp[] = new float[16];
+
+ VkInstance instance;
+ VkPhysicalDevice physicalDevice;
+ VkPhysicalDeviceMemoryProperties memory_properties;
+ VkPhysicalDeviceFeatures device_features;
+
+ int present_queue_index;
+ int graphics_queue_index;
+
+ VkDevice device;
+ VkSwapchainKHR chain;
+
+ VkQueue graphics_queue;
+ VkQueue present_queue;
+
+ int chainImageFormat;
+ HandleArray<VkImage> chainImage;
+ HandleArray<VkImageView> chainImageView;
+
+ int depthFormat;
+ VkImage depthImage;
+ VkImageView depthView;
+ VkDeviceMemory depthMemory;
+
+ VkCommandPool cmd_pool;
+ HandleArray<VkCommandBuffer> cmd;
+
+ BufferMemory uniform;
+ VkPipelineLayout pipeline_layout;
+
+ VkDescriptorSetLayout desc_layout;
+ VkDescriptorPool desc_pool;
+ HandleArray<VkDescriptorSet> desc_set;
+
+ VkRenderPass render_pass;
+ HandleArray<VkFramebuffer> framebuffers;
+
+ BufferMemory vertex;
+ HandleArray<VkBuffer> vertexBuffer = VkBuffer.createArray(1, (SegmentAllocator)scope);
+ VkVertexInputBindingDescription vi_binding = VkVertexInputBindingDescription.createArray(1, (SegmentAllocator)scope);
+ VkVertexInputAttributeDescription vi_attribs = VkVertexInputAttributeDescription.createArray(1, (SegmentAllocator)scope);
+
+ IntArray sdf_vs;
+ IntArray sdf_fs;
+ HandleArray<VkShaderModule> shader = VkShaderModule.createArray(2, (SegmentAllocator)scope);
+
+ HandleArray<VkPipeline> pipeline = VkPipeline.createArray(1, (SegmentAllocator)scope);
+
+ VkSemaphore chainSemaphore;
+ VkFence drawFence;
+
+ record BufferMemory(VkBuffer buffer, VkDeviceMemory memory, long size) {
+
+ public void free(VkDevice device) {
+ device.vkFreeMemory(memory);
+ device.vkDestroyBuffer(buffer);
+ }
+ }
+
+ VkDebugUtilsMessengerEXT logger;
+
+ void init_debug() throws Exception {
+ if (!debug)
+ return;
+ try ( Frame frame = Frame.frame()) {
+ var cb = PFN_vkDebugUtilsMessengerCallbackEXT.upcall((severity, flags, data) -> {
+ System.out.printf("Debug: %d: %s\n", severity, data.getMessage());
+ return 0;
+ }, scope);
+ VkDebugUtilsMessengerCreateInfoEXT info = VkDebugUtilsMessengerCreateInfoEXT.create(
+ 0,
+ VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT
+ | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
+ | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
+ VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
+ cb,
+ null,
+ frame);
+
+ logger = instance.vkCreateDebugUtilsMessengerEXT(info, scope);
+ }
+
+ //typedef VkBool32 (*PFN_vkDebugUtilsMessengerCallbackEXT)(VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT, const VkDebugUtilsMessengerCallbackDataEXT *, void *);
+ }
+
+ void init_instance() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ VkInstanceCreateInfo info = VkInstanceCreateInfo.create(
+ 0,
+ VkApplicationInfo.create("cube", 1, "cube-engine", 2, VK_API_VERSION_1_0, frame),
+ 1, new String[]{"VK_LAYER_KHRONOS_validation"},
+ 3, new String[]{"VK_KHR_surface", "VK_KHR_xlib_surface", "VK_EXT_debug_utils"},
+ frame
+ );
+
+ instance = VkInstance.vkCreateInstance(info, scope);
+ System.out.printf("instance = %s\n", instance);
+ }
+ }
+
+ Display display;
+ Window window;
+ VkSurfaceKHR surface;
+
+ void init_surface() throws Exception {
+ display = Display.createX11Display();
+ window = display.createWindow(width, height);
+ surface = window.createVulkanSurface(instance, scope);
+ System.out.printf("surface: %s\n", surface);
+ }
+
+ void init_device() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ IntArray count$h = IntArray.create(frame, 1);
+ IntArray present$h = IntArray.create(frame, 1);
+ HandleArray<VkPhysicalDevice> devs;
+ int count;
+ int res;
+
+ devs = instance.vkEnumeratePhysicalDevices(frame, scope);
+
+ // Search for device and queue indices
+ int devid = -1;
+ int present_queue = -1;
+ int graphics_queue = -1;
+ for (int i = 0; i < devs.length(); i++) {
+ VkPhysicalDevice dev = devs.getAtIndex(i);
+ VkQueueFamilyProperties famprops;
+
+ famprops = dev.vkGetPhysicalDeviceQueueFamilyProperties(frame);
+
+ for (int j = 0; j < famprops.length(); j++) {
+ boolean present = dev.vkGetPhysicalDeviceSurfaceSupportKHR(j, surface);
+
+ if (present && present_queue == -1)
+ present_queue = j;
+ if ((famprops.getQueueFlagsAtIndex(j) & VK_QUEUE_GRAPHICS_BIT) != 0) {
+ graphics_queue = j;
+ if (present) {
+ present_queue = j;
+ break;
+ }
+ }
+ }
+ if (present_queue != -1 && graphics_queue != -1) {
+ devid = i;
+ break;
+ }
+ }
+
+ if (devid == -1)
+ throw new Exception("Cannot find a suitable device");
+
+ physicalDevice = devs.getAtIndex(devid);
+ present_queue_index = present_queue;
+ graphics_queue_index = graphics_queue;
+
+ // NOTE: app scope
+ memory_properties = VkPhysicalDeviceMemoryProperties.create((SegmentAllocator)scope);
+ physicalDevice.vkGetPhysicalDeviceMemoryProperties(memory_properties);
+ device_features = VkPhysicalDeviceFeatures.create((SegmentAllocator)scope);
+ physicalDevice.vkGetPhysicalDeviceFeatures(device_features);
+
+ FloatArray qpri = FloatArray.create(frame, 0.0f);
+ VkDeviceQueueCreateInfo qinfo = VkDeviceQueueCreateInfo.create(
+ 0,
+ graphics_queue,
+ 1, qpri,
+ frame);
+ String[] extensions = {
+ "VK_KHR_swapchain"
+ };
+ VkPhysicalDeviceFeatures features = VkPhysicalDeviceFeatures.create(frame);
+ features.setDepthClamp(1);
+ VkDeviceCreateInfo devinfo = VkDeviceCreateInfo.create(
+ 0,
+ 1, qinfo,
+ 0, null,
+ extensions.length, extensions,
+ features,
+ frame);
+
+ device = physicalDevice.vkCreateDevice(devinfo, scope);
+
+ System.out.printf("device = %s\n", device);
+
+ /* ************************************************************** */
+ int format;
+ VkSurfaceFormatKHR surfFormats = physicalDevice.vkGetPhysicalDeviceSurfaceFormatsKHR(surface, frame);
+ // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
+ // the surface has no preferred format. Otherwise, at least one
+ // supported format will be returned.
+ if (surfFormats.length() == 1 && surfFormats.getFormatAtIndex(0) == VK_FORMAT_UNDEFINED) {
+ format = VK_FORMAT_B8G8R8A8_UNORM;
+ } else {
+ format = surfFormats.getFormatAtIndex(0);
+ }
+
+ VkSurfaceCapabilitiesKHR surfCapabilities = VkSurfaceCapabilitiesKHR.create(frame);
+
+ physicalDevice.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(surface, surfCapabilities);
+ IntArray presentModes = physicalDevice.vkGetPhysicalDeviceSurfacePresentModesKHR(surface, frame);
+
+ VkExtent2D swapchainExtent;
+ // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
+ if (surfCapabilities.getCurrentExtent().getWidth() == 0xFFFFFFFF) {
+ // If the surface size is undefined, the size is set to
+ // the size of the images requested.
+ swapchainExtent = VkExtent2D.create(
+ clampi(width, surfCapabilities.getMinImageExtent().getWidth(), surfCapabilities.getMaxImageExtent().getWidth()),
+ clampi(height, surfCapabilities.getMinImageExtent().getHeight(), surfCapabilities.getMaxImageExtent().getHeight()),
+ frame);
+ } else {
+ // If the surface size is defined, the swap chain size must match
+ swapchainExtent = surfCapabilities.getCurrentExtent();
+ }
+ int compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+ int compositeAlphaFlags[] = {
+ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+ VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
+ VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
+ VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,};
+ for (int flag: compositeAlphaFlags) {
+ if ((surfCapabilities.getSupportedCompositeAlpha() & flag) != 0) {
+ compositeAlpha = flag;
+ break;
+ }
+ }
+
+ VkSwapchainCreateInfoKHR chaininfo = VkSwapchainCreateInfoKHR.create(
+ 0,
+ surface,
+ surfCapabilities.getMinImageCount(),
+ format,
+ VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
+ swapchainExtent.getWidth(), swapchainExtent.getHeight(),
+ 1, //.imageArrayLayers = 1,
+ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+ VK_SHARING_MODE_EXCLUSIVE,
+ // assumes queues are same.
+ 0, null,
+ (surfCapabilities.getSupportedTransforms() & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) != 0
+ ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : surfCapabilities.getCurrentTransform(),
+ compositeAlpha,
+ VK_PRESENT_MODE_FIFO_KHR,
+ VK_TRUE,
+ null,
+ frame);
+
+ chain = device.vkCreateSwapchainKHR(chaininfo, scope);
+
+ int chainImageCount;
+
+ chainImage = device.vkGetSwapchainImagesKHR(chain, (SegmentAllocator)scope, scope);
+ chainImageCount = (int)chainImage.length();
+ chainImageView = VkImageView.createArray(chainImageCount, (SegmentAllocator)scope);
+
+ VkImageViewCreateInfo viewinfo = VkImageViewCreateInfo.create(
+ 0,
+ null,
+ VK_IMAGE_VIEW_TYPE_2D,
+ format,
+ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A,
+ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1,
+ frame);
+
+ for (int i = 0; i < chainImageCount; i++) {
+ viewinfo.setImage(chainImage.get(i));
+
+ chainImageView.setAtIndex(i, device.vkCreateImageView(viewinfo, scope));
+ }
+
+ chainImageFormat = format;
+ }
+ }
+
+ void init_device_queue() {
+ graphics_queue = device.vkGetDeviceQueue(graphics_queue_index, 0, scope);
+ if (graphics_queue_index == present_queue_index) {
+ present_queue = graphics_queue;
+ } else {
+ present_queue = device.vkGetDeviceQueue(present_queue_index, 0, scope);
+ }
+ }
+
+ void init_command() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ VkCommandPoolCreateInfo poolinfo = VkCommandPoolCreateInfo.create(
+ 0,
+ graphics_queue_index,
+ frame);
+
+ cmd_pool = device.vkCreateCommandPool(poolinfo, scope);
+
+ VkCommandBufferAllocateInfo cmdinfo = VkCommandBufferAllocateInfo.create(
+ cmd_pool,
+ VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+ 1,
+ frame);
+
+ cmd = device.vkAllocateCommandBuffers(cmdinfo, (SegmentAllocator)scope, scope);
+ }
+ }
+
+ // parameterise as init_image?
+ void init_depth() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ int format = VK_FORMAT_D16_UNORM;
+ VkMemoryRequirements req = VkMemoryRequirements.create(frame);
+ VkImageCreateInfo imageinfo = VkImageCreateInfo.create(
+ 0,
+ VK_IMAGE_TYPE_2D,
+ format,
+ width, height, 1,
+ 1,
+ 1,
+ NUM_SAMPLES,
+ 0,
+ VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
+ VK_SHARING_MODE_EXCLUSIVE,
+ 0, null,
+ VK_IMAGE_LAYOUT_UNDEFINED,
+ frame);
+
+ depthImage = device.vkCreateImage(imageinfo, scope);
+
+ device.vkGetImageMemoryRequirements(depthImage, req);
+ VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(
+ req.getSize(),
+ find_memory_type(memory_properties, req.getMemoryTypeBits(), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT),
+ frame);
+
+ depthMemory = device.vkAllocateMemory(alloc, scope);
+
+ device.vkBindImageMemory(depthImage, depthMemory, 0);
+
+ VkImageViewCreateInfo viewinfo = VkImageViewCreateInfo.create(
+ 0,
+ depthImage,
+ VK_IMAGE_VIEW_TYPE_2D,
+ VK_FORMAT_D16_UNORM,
+ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A,
+ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1,
+ frame);
+
+ depthView = device.vkCreateImageView(viewinfo, scope);
+ depthFormat = format;
+ }
+ }
+
+ void init_uniform() throws Exception {
+ uniform = init_buffer(mvp.length * 4, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, MemorySegment.ofArray(mvp));
+ }
+
+ void init_descriptor() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ HandleArray<VkDescriptorSetLayout> layout_table = VkDescriptorSetLayout.createArray(1, frame);
+ VkDescriptorSetLayoutBinding layout_binding = VkDescriptorSetLayoutBinding.create(
+ 0,
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ 1,
+ VK_SHADER_STAGE_VERTEX_BIT,
+ null,
+ frame);
+ VkDescriptorSetLayoutCreateInfo descriptor_layout = VkDescriptorSetLayoutCreateInfo.create(
+ 0,
+ 1, layout_binding,
+ frame);
+
+ desc_layout = device.vkCreateDescriptorSetLayout(descriptor_layout, scope);
+ layout_table.setAtIndex(0, desc_layout);
+
+ VkPipelineLayoutCreateInfo pipeline_info = VkPipelineLayoutCreateInfo.create(
+ 0,
+ 1, layout_table,
+ 0, null,
+ frame);
+
+ pipeline_layout = device.vkCreatePipelineLayout(pipeline_info, scope);
+
+ VkDescriptorPoolSize type_count = VkDescriptorPoolSize.create(
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ 1,
+ frame);
+
+ VkDescriptorPoolCreateInfo descriptor_pool = VkDescriptorPoolCreateInfo.create(
+ 0,
+ 1,
+ 1, type_count,
+ frame);
+
+ desc_pool = device.vkCreateDescriptorPool(descriptor_pool, scope);
+
+ VkDescriptorSetAllocateInfo alloc_info = VkDescriptorSetAllocateInfo.create(
+ desc_pool,
+ 1, layout_table,
+ frame);
+
+ System.out.println(alloc_info);
+
+ desc_set = device.vkAllocateDescriptorSets(alloc_info, (SegmentAllocator)scope, scope);
+
+ VkDescriptorBufferInfo uniformInfo = VkDescriptorBufferInfo.create(uniform.buffer, 0, uniform.size, frame);
+ VkWriteDescriptorSet writes = VkWriteDescriptorSet.create(
+ desc_set.getAtIndex(0),
+ 0,
+ 0,
+ 1,
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ null,
+ uniformInfo,
+ null,
+ frame);
+
+ device.vkUpdateDescriptorSets(1, writes, 0, null);
+ }
+ }
+
+ void init_render() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ VkAttachmentDescription attachments = VkAttachmentDescription.createArray(2, frame);
+
+ attachments.setFormat(chainImageFormat);
+ attachments.setSamples(NUM_SAMPLES);
+ attachments.setLoadOp(VK_ATTACHMENT_LOAD_OP_CLEAR);
+ attachments.setStoreOp(VK_ATTACHMENT_STORE_OP_STORE);
+ attachments.setStencilLoadOp(VK_ATTACHMENT_LOAD_OP_DONT_CARE);
+ attachments.setStencilStoreOp(VK_ATTACHMENT_STORE_OP_DONT_CARE);
+ attachments.setInitialLayout(VK_IMAGE_LAYOUT_UNDEFINED);
+ attachments.setFinalLayout(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
+ attachments.setFlags(0);
+
+ attachments.setFormatAtIndex(1, depthFormat);
+ attachments.setSamplesAtIndex(1, NUM_SAMPLES);
+ attachments.setLoadOpAtIndex(1, VK_ATTACHMENT_LOAD_OP_CLEAR);
+ attachments.setStoreOpAtIndex(1, VK_ATTACHMENT_STORE_OP_STORE);
+ attachments.setStencilLoadOpAtIndex(1, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
+ attachments.setStencilStoreOpAtIndex(1, VK_ATTACHMENT_STORE_OP_DONT_CARE);
+ attachments.setInitialLayoutAtIndex(1, VK_IMAGE_LAYOUT_UNDEFINED);
+ attachments.setFinalLayoutAtIndex(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+ attachments.setFlagsAtIndex(1, 0);
+
+ VkAttachmentReference color_reference = VkAttachmentReference.create(
+ 0,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ frame);
+
+ VkAttachmentReference depth_reference = VkAttachmentReference.create(
+ 1,
+ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+ frame);
+
+ VkSubpassDescription subpass = VkSubpassDescription.create(
+ 0,
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ 0, null,
+ 1, color_reference,
+ null,
+ depth_reference,
+ 0, null,
+ frame);
+
+ VkRenderPassCreateInfo rp_info = VkRenderPassCreateInfo.create(
+ 0,
+ 2, attachments,
+ 1, subpass,
+ 0, null,
+ frame);
+
+ render_pass = device.vkCreateRenderPass(rp_info, scope);
+ }
+ }
+
+ void init_framebuffer() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ HandleArray<VkImageView> attachments = VkImageView.createArray(2, frame);
+
+ attachments.setAtIndex(1, depthView);
+
+ VkFramebufferCreateInfo fb_info = VkFramebufferCreateInfo.create(
+ 0,
+ render_pass,
+ 2, attachments,
+ width, height, 1,
+ frame);
+
+ framebuffers = VkFramebuffer.createArray(chainImage.length(), (SegmentAllocator)scope);
+ for (int i = 0; i < chainImage.size(); i++) {
+ attachments.setAtIndex(0, chainImageView.get(i));
+ framebuffers.setAtIndex(i, device.vkCreateFramebuffer(fb_info, scope));
+ System.out.printf("framebuffer[%d] = %s\n", i, framebuffers.getAtIndex(i));
+ }
+ }
+ }
+
+ void init_vertexbuffer() throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ float[] image = {
+ -1, -1, 0, 1,
+ 1, -1, 0, 1,
+ -1, 1, 0, 1,
+ -1, 1, 0, 1,
+ 1, -1, 0, 1,
+ 1, 1, 0, 1
+ // 1, -1, 0, 1,
+ // -1, 1, 0, 1,
+ // 1, 1, 0, 1
+ };
+ vertex = init_buffer(image.length * 4, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, MemorySegment.ofArray(image));
+
+ vertexBuffer.setAtIndex(0, vertex.buffer);
+
+ /* ***************************************** */
+ vi_binding.setBinding(0);
+ vi_binding.setInputRate(VK_VERTEX_INPUT_RATE_VERTEX);
+ vi_binding.setStride(4 * 4);
+
+ vi_attribs.setBinding(0);
+ vi_attribs.setLocation(0);
+ vi_attribs.setFormat(VK_FORMAT_R32G32B32A32_SFLOAT);
+ vi_attribs.setOffset(0);
+ //vi_attribs.setBindingAtIndex(1, 0);
+ //vi_attribs.setLocationAtIndex(1, 1);
+ //vi_attribs.setFormatAtIndex(1, VK_FORMAT_R32G32B32A32_SFLOAT);
+ //vi_attribs.setOffsetAtIndex(1, 16);
+ }
+ }
+
+ void init_pipeline() throws Exception {
+ int res;
+ try ( Frame frame = Frame.frame()) {
+ IntArray dynamicStateEnables = IntArray.create(frame,
+ VK_DYNAMIC_STATE_VIEWPORT,
+ VK_DYNAMIC_STATE_SCISSOR);
+
+ VkPipelineDynamicStateCreateInfo dynamicState = VkPipelineDynamicStateCreateInfo.create(
+ 0,
+ 2, dynamicStateEnables,
+ frame);
+
+ VkPipelineVertexInputStateCreateInfo vi = VkPipelineVertexInputStateCreateInfo.create(
+ 0,
+ (int)vi_binding.length(), vi_binding,
+ (int)vi_attribs.length(), vi_attribs,
+ frame);
+
+ VkPipelineInputAssemblyStateCreateInfo ia = VkPipelineInputAssemblyStateCreateInfo.create(
+ 0,
+ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
+ 0,
+ frame);
+
+ VkPipelineRasterizationStateCreateInfo rs = VkPipelineRasterizationStateCreateInfo.create(
+ 0,
+ VK_TRUE,
+ VK_FALSE,
+ VK_POLYGON_MODE_FILL,
+ VK_CULL_MODE_BACK_BIT,
+ VK_FRONT_FACE_CLOCKWISE,
+ VK_FALSE,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ frame);
+
+ VkPipelineColorBlendAttachmentState att_state = VkPipelineColorBlendAttachmentState.create(
+ VK_FALSE,
+ VK_BLEND_FACTOR_ZERO,
+ VK_BLEND_FACTOR_ZERO,
+ VK_BLEND_OP_ADD,
+ VK_BLEND_FACTOR_ZERO,
+ VK_BLEND_FACTOR_ZERO,
+ VK_BLEND_OP_ADD,
+ 0xf,
+ frame);
+
+ VkPipelineColorBlendStateCreateInfo cb = VkPipelineColorBlendStateCreateInfo.create(
+ 0,
+ VK_FALSE,
+ VK_LOGIC_OP_NO_OP,
+ 1, att_state,
+ 1.0f, 1.0f, 1.0f, 1.0f,
+ frame);
+
+ VkPipelineViewportStateCreateInfo vp = VkPipelineViewportStateCreateInfo.create(
+ 0,
+ 1, null,
+ 1, null,
+ frame);
+
+ VkPipelineDepthStencilStateCreateInfo ds = VkPipelineDepthStencilStateCreateInfo.create(
+ 0,
+ VK_TRUE,
+ VK_TRUE,
+ VK_COMPARE_OP_LESS_OR_EQUAL,
+ VK_FALSE,
+ VK_FALSE,
+ 0.0f,
+ 0.0f,
+ frame);
+ VkStencilOpState back = ds.getBack();
+
+ back.setFailOp(VK_STENCIL_OP_KEEP);
+ back.setPassOp(VK_STENCIL_OP_KEEP);
+ back.setCompareOp(VK_COMPARE_OP_ALWAYS);
+ back.setCompareMask(0);
+ back.setReference(0);
+ back.setDepthFailOp(VK_STENCIL_OP_KEEP);
+ back.setWriteMask(0);
+
+ VkStencilOpState front = ds.getFront();
+
+ front.setFailOp(VK_STENCIL_OP_KEEP);
+ front.setPassOp(VK_STENCIL_OP_KEEP);
+ front.setCompareOp(VK_COMPARE_OP_ALWAYS);
+ front.setCompareMask(0);
+ front.setReference(0);
+ front.setDepthFailOp(VK_STENCIL_OP_KEEP);
+ front.setWriteMask(0);
+
+ VkPipelineMultisampleStateCreateInfo ms = VkPipelineMultisampleStateCreateInfo.create(
+ 0,
+ NUM_SAMPLES,
+ 0, //.sampleShadingEnable = VK_FALSE,
+ 0.0f,
+ null,
+ 0, //.alphaToCoverageEnable = VK_FALSE,
+ 0, //.alphaToOneEnable = VK_FALSE,
+ frame
+ );
+
+ VkShaderModuleCreateInfo vsInfo = VkShaderModuleCreateInfo.create(
+ 0,
+ sdf_vs.length() * 4,
+ sdf_vs,
+ frame);
+ VkShaderModuleCreateInfo fsInfo = VkShaderModuleCreateInfo.create(
+ 0,
+ sdf_fs.length() * 4,
+ sdf_fs,
+ frame);
+
+ shader.setAtIndex(0, device.vkCreateShaderModule(vsInfo, scope));
+ shader.setAtIndex(1, device.vkCreateShaderModule(fsInfo, scope));
+
+ VkPipelineShaderStageCreateInfo shaderStages = VkPipelineShaderStageCreateInfo.createArray(2, (SegmentAllocator)scope);
+
+ shaderStages.setStage(VK_SHADER_STAGE_VERTEX_BIT);
+ shaderStages.setName("main", (SegmentAllocator)scope);
+ shaderStages.setModule(shader.get(0));
+
+ shaderStages.setStageAtIndex(1, VK_SHADER_STAGE_FRAGMENT_BIT);
+ shaderStages.setNameAtIndex(1, "main", (SegmentAllocator)scope);
+ shaderStages.setModuleAtIndex(1, shader.get(1));
+
+ VkGraphicsPipelineCreateInfo pipeline = VkGraphicsPipelineCreateInfo.create(
+ 0,
+ 2, shaderStages,
+ vi,
+ ia,
+ null,
+ vp,
+ rs,
+ ms,
+ ds,
+ cb,
+ dynamicState,
+ pipeline_layout,
+ render_pass,
+ 0,
+ null,
+ 0,
+ frame);
+
+ res = device.vkCreateGraphicsPipelines(null, 1, pipeline, this.pipeline);
+
+ VkSemaphoreCreateInfo seminfo = VkSemaphoreCreateInfo.create(0, frame);
+ chainSemaphore = device.vkCreateSemaphore(seminfo, scope);
+
+ VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(0, frame);
+ drawFence = device.vkCreateFence(fenceInfo, scope);
+ }
+ }
+
+ void execute_begin_command_buffer() throws Exception {
+ /* DEPENDS on init_command() */
+ try ( Frame frame = Frame.frame()) {
+ VkCommandBufferBeginInfo cmd_buf_info = VkCommandBufferBeginInfo.create(
+ 0,
+ null,
+ frame);
+
+ cmd.getAtIndex(0).vkBeginCommandBuffer(cmd_buf_info);
+ }
+ }
+
+ void execute_end_command_buffer() throws Exception {
+ cmd.getAtIndex(0).vkEndCommandBuffer();
+ }
+
+ final static long FENCE_TIMEOUT = 100000000;
+
+ void execute_queue_command_buffer() throws Exception {
+ int res;
+
+ /* Queue the command buffer for execution */
+ /* FIXME: frame shoudl provide or take explicit scope */
+ try ( ResourceScope scope = ResourceScope.newConfinedScope(); Frame frame = Frame.frame()) {
+ IntArray pipe_stage_flags = IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
+ VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.create(0, frame);
+ HandleArray<VkFence> fences = VkFence.createArray(1, frame);
+
+ fences.setAtIndex(0, device.vkCreateFence(fenceInfo, scope));
+
+ VkSubmitInfo submit_info = VkSubmitInfo.create(
+ 1, null, pipe_stage_flags,
+ (int)cmd.length(), cmd,
+ 0, null,
+ frame);
+
+ graphics_queue.vkQueueSubmit(1, submit_info, drawFence);
+
+ do {
+ res = device.vkWaitForFences(1, fences, 1, FENCE_TIMEOUT);
+ } while (res == VK_TIMEOUT);
+
+ device.vkDestroyFence(fences.getAtIndex(0));
+ }
+ }
+
+ void cmd_viewport() {
+ try ( Frame frame = Frame.frame()) {
+ VkCommandBuffer cmd = this.cmd.getAtIndex(0);
+ VkViewport viewport = VkViewport.create(
+ 0, 0, width, height, 0.0f, 1.0f,
+ frame);
+ cmd.vkCmdSetViewport(0, 1, viewport);
+ }
+ }
+
+ void cmd_scissors() {
+ try ( Frame frame = Frame.frame()) {
+ VkCommandBuffer cmd = this.cmd.getAtIndex(0);
+ VkRect2D scissor = VkRect2D.create(frame);
+ VkExtent2D extent = scissor.getExtent();
+
+ extent.setWidth(width);
+ extent.setHeight(height);
+
+ cmd.vkCmdSetScissor(0, 1, scissor);
+ }
+ }
+
+ void cmd_paint() throws Exception {
+ int res;
+ try ( Frame frame = Frame.frame()) {
+ int chainIndex;
+ IntArray chainIndices = IntArray.createArray(1, frame);
+ VkCommandBuffer cmd = this.cmd.getAtIndex(0);
+
+ device.vkAcquireNextImageKHR(chain, ~0L, chainSemaphore, null, chainIndices);
+ chainIndex = chainIndices.getAtIndex(0);
+ LongArray offsets = LongArray.createArray(1, frame);
+
+ VkClearValue clear_values = VkClearValue.createArray(2, frame);
+ clear_values.getColor().setFloat32(0.2f, 0.2f, 0.2f, 0.2f, frame);
+ VkClearDepthStencilValue depthStencil = clear_values.getAtIndex(1).getDepthStencil();
+ depthStencil.setDepth(1.0f);
+ depthStencil.setStencil(0);
+
+ System.out.printf("render framebuffer[%d] = %s\n", chainIndex, framebuffers.getAtIndex(chainIndex));
+
+ VkRenderPassBeginInfo rp_begin = VkRenderPassBeginInfo.create(
+ render_pass,
+ framebuffers.getAtIndex(chainIndex),
+ 0, 0, width, height,
+ 2, clear_values,
+ frame);
+
+ cmd.vkCmdBeginRenderPass(rp_begin, VK_SUBPASS_CONTENTS_INLINE);
+
+ cmd.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.getAtIndex(0));
+ cmd.vkCmdBindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, NUM_DESCRIPTOR_SETS, desc_set, 0, null);
+ cmd.vkCmdBindVertexBuffers(0, 1, vertexBuffer, offsets);
+
+ cmd_viewport();
+ cmd_scissors();
+
+ cmd.vkCmdDraw(12 * 3, 1, 0, 0);
+ cmd.vkCmdEndRenderPass();
+
+ cmd.vkEndCommandBuffer();
+
+ IntArray pipe_stage_flags = IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
+ HandleArray<VkSemaphore> semaphores = VkSemaphore.createArray(1, frame);//, chainSemaphore, scope);
+
+ semaphores.setAtIndex(0, chainSemaphore);
+
+ VkSubmitInfo submit_info = VkSubmitInfo.create(
+ 1, semaphores, pipe_stage_flags,
+ (int)this.cmd.length(), this.cmd,
+ 0, null,
+ frame);
+
+ HandleArray<VkFence> fences = VkFence.createArray(1, frame);
+
+ fences.setAtIndex(0, drawFence);
+
+ // Queue the command buffer for execution
+ device.vkResetFences(1, fences);
+
+ graphics_queue.vkQueueSubmit(1, submit_info, drawFence);
+
+ // Make sure command buffer is finished before presenting
+ do {
+ res = device.vkWaitForFences(1, fences, VK_TRUE, FENCE_TIMEOUT);
+ } while (res == VK_TIMEOUT);
+
+ // Now present the image in the window
+ HandleArray<VkSwapchainKHR> chains = VkSwapchainKHR.createArray(1, frame);
+ chains.setAtIndex(0, chain);
+ VkPresentInfoKHR present = VkPresentInfoKHR.create(
+ 0, null,
+ 1, chains, chainIndices, null,
+ frame);
+
+ present_queue.vkQueuePresentKHR(present);
+ }
+ }
+
+ /**
+ * Buffers are created in three steps:
+ * 1) create buffer, specifying usage and size
+ * 2) allocate memory based on memory requirements
+ * 3) bind memory
+ * <p>
+ */
+ BufferMemory init_buffer(long dataSize, int usage, int properties, MemorySegment init) throws Exception {
+ try ( Frame frame = Frame.frame()) {
+ VkMemoryRequirements req = VkMemoryRequirements.create(frame);
+ VkBufferCreateInfo buf_info = VkBufferCreateInfo.create(
+ 0,
+ dataSize,
+ usage,
+ VK_SHARING_MODE_EXCLUSIVE,
+ 0, null,
+ frame);
+
+ VkBuffer buffer = device.vkCreateBuffer(buf_info, scope);
+
+ device.vkGetBufferMemoryRequirements(buffer, req);
+
+ VkMemoryAllocateInfo alloc = VkMemoryAllocateInfo.create(
+ req.getSize(),
+ find_memory_type(memory_properties, req.getMemoryTypeBits(), properties),
+ frame);
+
+ VkDeviceMemory memory = device.vkAllocateMemory(alloc, scope);
+
+ if (init != null) {
+ MemorySegment mem = device.vkMapMemory(memory, 0, dataSize, 0, scope);
+ mem.copyFrom(init);
+ device.vkUnmapMemory(memory);
+ }
+
+ device.vkBindBufferMemory(buffer, memory, 0);
+
+ return new BufferMemory(buffer, memory, dataSize);
+ }
+ }
+
+ void shutdown() {
+ device.vkDestroyFence(drawFence);
+ device.vkDestroySemaphore(chainSemaphore);
+
+ device.vkDestroyPipeline(pipeline.getAtIndex(0));
+ for (int i = 0; i < shader.size(); i++)
+ device.vkDestroyShaderModule(shader.getAtIndex(i));
+
+ vertex.free(device);
+ uniform.free(device);
+
+ for (int i = 0; i < framebuffers.size(); i++)
+ device.vkDestroyFramebuffer(framebuffers.getAtIndex(i));
+
+ device.vkDestroyRenderPass(render_pass);
+
+ device.vkDestroyDescriptorPool(desc_pool);
+ device.vkDestroyPipelineLayout(pipeline_layout);
+ device.vkDestroyDescriptorSetLayout(desc_layout);
+
+ device.vkDestroyImageView(depthView);
+ device.vkFreeMemory(depthMemory);
+ device.vkDestroyImage(depthImage);
+
+ for (int i = 0; i < chainImageView.size(); i++)
+ device.vkDestroyImageView(chainImageView.getAtIndex(i));
+
+ device.vkDestroySwapchainKHR(chain);
+
+ device.vkDestroyCommandPool(cmd_pool);
+ device.vkDestroyDevice();
+
+ instance.vkDestroySurfaceKHR(surface);
+ window.close();
+ display.close();
+
+ if (logger != null)
+ instance.vkDestroyDebugUtilsMessengerEXT(logger);
+ instance.vkDestroyInstance();
+ }
+
+ /**
+ * This finds the memory type index for the memory on a specific device.
+ */
+ static int find_memory_type(VkPhysicalDeviceMemoryProperties memory, int typeMask, int query) {
+ VkMemoryType mtypes = memory.getMemoryTypes();
+
+ for (int i = 0; i < memory.getMemoryTypeCount(); i++) {
+ if (((1 << i) & typeMask) != 0 && ((mtypes.getAtIndex(i).getPropertyFlags() & query) == query))
+ return i;
+ }
+ return -1;
+ }
+
+ static int clampi(int v, int min, int max) {
+ return v < min ? min : v < max ? v : max;
+ }
+
+ void init_matrices() {
+ //float eye[] = new float[] {-5, 3, -10};
+ float eye[] = new float[]{0, 0, -10};
+ float centre[] = new float[]{0, 0, 0};
+ float up[] = new float[]{0, -1, 0};
+ float t0[] = new float[16], t1[] = new float[16];
+
+ perspective(projection, (float)(Math.PI * 0.25), 1.0f, 0.1f, 100.0f);
+ lookAt(view, eye, centre, up);
+ identity4f(model);
+ mult4x4f(t0, clip, projection);
+ mult4x4f(t1, t0, view);
+ mult4x4f(mvp, t1, model);
+ }
+
+ void demo() throws Exception {
+ sdf_vs = ShaderIO.loadSdf_vert((SegmentAllocator)scope);
+ sdf_fs = ShaderIO.loadSdf_frag((SegmentAllocator)scope);
+
+ init_matrices();
+
+ init_instance();
+ init_debug();
+
+ init_surface();
+ init_device();
+ init_device_queue();
+ init_command();
+ init_depth();
+ init_uniform();
+
+ init_descriptor();
+ init_render();
+ init_framebuffer();
+ init_vertexbuffer();
+ init_pipeline();
+
+ execute_begin_command_buffer();
+
+ cmd_paint();
+
+ System.out.println("Any key to quit");
+ Event e;
+outer: while ((e = window.nextEvent(true)) != null) {
+ switch (e.type) {
+ case Event.KEY:
+ case Event.CLOSE:
+ break outer;
+ }
+ }
+
+ shutdown();
+ }
+
+ public static void main(String[] args) throws Throwable {
+ System.loadLibrary("vulkan");
+ System.loadLibrary("X11");
+
+ new TestSDF().demo();
+ }
+}
--- /dev/null
+/*
+ Going through the Vulkan Tutorial.
+*/
+package vulkan.test;
+
+import au.notzed.display.Display;
+import au.notzed.display.Event;
+import au.notzed.display.Window;
+import au.notzed.nativez.Frame;
+
+import au.notzed.nativez.HandleArray;
+import au.notzed.nativez.IntArray;
+import au.notzed.nativez.LongArray;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+import jdk.incubator.foreign.MemorySegment;
+import jdk.incubator.foreign.ResourceScope;
+import jdk.incubator.foreign.SegmentAllocator;
+import vulkan.VkBuffer;
+import vulkan.VkClearValue;
+import vulkan.VkCommandBuffer;
+import vulkan.VkCommandBufferBeginInfo;
+import vulkan.VkDevice;
+import vulkan.VkFence;
+import vulkan.VkFramebuffer;
+import vulkan.VkInstance;
+import vulkan.VkPhysicalDeviceFeatures;
+import vulkan.VkPipeline;
+import vulkan.VkPipelineLayout;
+import vulkan.VkPresentInfoKHR;
+import vulkan.VkRect2D;
+import vulkan.VkRenderPassBeginInfo;
+import vulkan.VkSemaphore;
+import vulkan.VkShaderModule;
+import vulkan.VkSubmitInfo;
+import vulkan.VkSurfaceKHR;
+import vulkan.VkSwapchainKHR;
+import vulkan.VkViewport;
+import vulkan.Vulkan;
+import static vulkan.Vulkan.VK_API_VERSION_1_2;
+import static vulkan.Vulkan.VK_FENCE_CREATE_SIGNALED_BIT;
+import static vulkan.Vulkan.VK_KHR_SWAPCHAIN_EXTENSION_NAME;
+import static vulkan.Vulkan.VK_PIPELINE_BIND_POINT_GRAPHICS;
+import static vulkan.Vulkan.VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+import static vulkan.Vulkan.VK_PRESENT_MODE_FIFO_KHR;
+import static vulkan.Vulkan.VK_SUBOPTIMAL_KHR;
+import static vulkan.Vulkan.VK_SUBPASS_CONTENTS_INLINE;
+import static vulkan.Vulkan.VK_SUCCESS;
+import static vulkan.Vulkan.VK_TRUE;
+//import static vulkan.Vulkan.*;
+
+public class Tutorial {
+
+ static int width = 724, height = 580;
+ static final int MAX_FRAMES_INFLIGHT = 2;
+
+ static String[] deviceTypes = {
+ "VK_PHYSICAL_DEVICE_TYPE_OTHER",
+ "VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU",
+ "VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU",
+ "VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU",
+ "VK_PHYSICAL_DEVICE_TYPE_CPU"
+ };
+
+ static final float[] vertices = {
+ 0.0f, -0.5f, 1, 0, 0,
+ 0.5f, 0.5f, 0, 1, 0,
+ -0.5f, 0.5f, 0, 0, 1
+ };
+
+ public static record RenderInfo(
+ Demo.DemoDevice device,
+ Demo.DemoChain chain,
+ VkPipeline pipeline,
+ VkPipelineLayout pipelineLayout,
+ HandleArray<VkCommandBuffer> commandBuffers,
+ HandleArray<VkFramebuffer> frameBuffers,
+ Runnable[] resources,
+ ResourceScope scope) {
+
+ public void close() {
+ VkDevice d = device.device();
+ frameBuffers.stream().forEach(d::vkDestroyFramebuffer);
+ d.vkFreeCommandBuffers(device.pools()[0], commandBuffers.size(), commandBuffers);
+ d.vkDestroyPipeline(pipeline);
+ d.vkDestroyPipelineLayout(pipelineLayout);
+
+ for (int i = resources.length - 1; i >= 0; i--)
+ resources[i].run();
+
+ // here? chain?
+ d.vkDestroyRenderPass(chain.renderPass());
+ chain.views().forEach(d::vkDestroyImageView);
+ d.vkDestroySwapchainKHR(chain.swapchain());
+
+ scope.close();
+ }
+ }
+
+ static void rebuildCommandBuffersx(RenderInfo info, int extWidth, int extHeight) {
+ Demo.DemoChain chain = info.chain();
+ HandleArray<VkCommandBuffer> commandBuffers = info.commandBuffers();
+ HandleArray<VkFramebuffer> frameBuffers = info.frameBuffers();
+ VkPipeline pipeline = info.pipeline;
+
+ Demo.resetCommandBuffers(info.device, 0, commandBuffers);
+
+ try ( Frame frame = Frame.frame()) {
+ VkCommandBufferBeginInfo begin = VkCommandBufferBeginInfo.create(0, null, frame);
+ VkClearValue clear = VkClearValue.createColour(0, 0, 0, 1, frame);
+ VkRenderPassBeginInfo render = VkRenderPassBeginInfo.create(
+ chain.renderPass(), null,
+ 0, 0, extWidth, extHeight,
+ 1, clear,
+ frame);
+ VkViewport viewports = VkViewport.create(0, 0, extWidth, extHeight, 0, 1, frame);
+ VkRect2D scissors = VkRect2D.create(0, 0, extWidth, extHeight, frame);
+
+ for (int i = 0; i < commandBuffers.size(); i++) {
+ VkCommandBuffer cmd = commandBuffers.get(i);
+
+ render.setFramebuffer(frameBuffers.get(i));
+
+ cmd.vkBeginCommandBuffer(begin);
+ cmd.vkCmdBeginRenderPass(render, VK_SUBPASS_CONTENTS_INLINE); // SECONDARY... for sub-rendering?
+
+ cmd.vkCmdSetViewport(0, 1, viewports);
+ cmd.vkCmdSetScissor(0, 1, scissors);
+
+ cmd.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
+ cmd.vkCmdDraw(3, 1, 0, 0);
+
+ cmd.vkCmdEndRenderPass();
+ cmd.vkEndCommandBuffer();
+ }
+ }
+ }
+
+ static RenderInfo createRenderInfo(Demo.DemoDevice device, int pixWidth, int pixHeight, VkShaderModule vertex, VkShaderModule fragment) {
+ ResourceScope scope = ResourceScope.newSharedScope();
+ try ( Frame frame = Frame.frame()) {
+ SegmentAllocator alloc = SegmentAllocator.newNativeArena(scope);
+ List<Runnable> cleanup = new ArrayList<>();
+
+ Demo.DemoChain chain = Demo.createSwapchain(
+ device,
+ Demo.ColourFormat.SRGB,
+ //VK_PRESENT_MODE_IMMEDIATE_KHR,
+ VK_PRESENT_MODE_FIFO_KHR,
+ pixWidth, pixHeight, alloc, scope);
+
+ VkPipelineLayout layout = Demo.dumbPipelineLayout(device.device(), scope);
+ VkPipeline pipeline = Demo.dumbPipeline(device.device(), vertex, fragment, layout, chain.renderPass(), scope);
+
+ // could move to chain?
+ HandleArray<VkFramebuffer> frameBuffers = Demo.createFramebuffers(device, chain, alloc, scope);
+ HandleArray<VkCommandBuffer> commandBuffers = Demo.createCommandBuffers(device, 0, frameBuffers.size(), alloc, scope);
+
+ // could move creation to Chain?
+ VkCommandBufferBeginInfo begin = VkCommandBufferBeginInfo.create(0, null, frame);
+ VkClearValue clear = VkClearValue.createColour(0, 0, 0.25f, 1, frame);
+ VkRenderPassBeginInfo render = VkRenderPassBeginInfo.create(
+ chain.renderPass(), null,
+ 0, 0, chain.extWidth(), chain.extHeight(),
+ 1, clear,
+ frame);
+ VkViewport viewports = VkViewport.create(0, 0, chain.extWidth(), chain.extHeight(), 0, 1, frame);
+ VkRect2D scissors = VkRect2D.create(0, 0, chain.extWidth(), chain.extHeight(), frame);
+
+ Demo.Buffer vertexStaging = Demo.createBuffer(device, vertices.length * 4, Vulkan.VK_BUFFER_USAGE_TRANSFER_SRC_BIT, Vulkan.VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, device.queueFamilies(), MemorySegment.ofArray(vertices), scope);
+ Demo.Buffer vertexBuffer = Demo.createBuffer(device, vertices.length * 4, Vulkan.VK_BUFFER_USAGE_TRANSFER_DST_BIT | Vulkan.VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, Vulkan.VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, device.queueFamilies(), null, scope);
+ HandleArray<VkBuffer> buffers = VkBuffer.createArray(1, alloc, scope);
+ LongArray buffersOffset = LongArray.createArray(1, alloc);
+
+ buffers.set(0, vertexBuffer.buffer());
+
+ Demo.copyBuffer(device, vertexStaging, vertexBuffer);
+ vertexStaging.close(device.device());
+ cleanup.add(() -> vertexBuffer.close(device.device()));
+
+ for (int i = 0; i < commandBuffers.size(); i++) {
+ VkCommandBuffer cmd = commandBuffers.get(i);
+
+ render.setFramebuffer(frameBuffers.get(i));
+
+ cmd.vkBeginCommandBuffer(begin);
+ cmd.vkCmdBeginRenderPass(render, VK_SUBPASS_CONTENTS_INLINE); // SECONDARY... for sub-rendering?
+
+ cmd.vkCmdSetViewport(0, 1, viewports);
+ cmd.vkCmdSetScissor(0, 1, scissors);
+
+ cmd.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
+ cmd.vkCmdBindVertexBuffers(0, 1, buffers, buffersOffset);
+ cmd.vkCmdDraw(3, 1, 0, 0);
+
+ cmd.vkCmdEndRenderPass();
+ cmd.vkEndCommandBuffer();
+ }
+ return new RenderInfo(device, chain, pipeline, layout, commandBuffers, frameBuffers, cleanup.toArray(Runnable[]::new), scope);
+ } catch (Throwable t) {
+ scope.close();
+ throw new RuntimeException(t);
+ }
+ }
+
+ public static void main(String[] args) throws IOException, InterruptedException {
+ ResourceScope scope = ResourceScope.globalScope();
+
+ System.loadLibrary("vulkan");
+ System.loadLibrary("X11");
+
+ try ( Frame frame = Frame.frame()) {
+ VkInstance instance = Demo.createInstance(VK_API_VERSION_1_2,
+ new String[]{"VK_LAYER_KHRONOS_validation"},
+ new String[]{"VK_KHR_surface", "VK_KHR_xlib_surface", "VK_EXT_debug_utils"},
+ scope);
+
+ Display display;
+ Window window;
+ VkSurfaceKHR surface;
+
+ display = Display.createX11Display();
+ window = display.createWindow(width, height);
+ surface = window.createVulkanSurface(instance, scope);
+
+ VkPhysicalDeviceFeatures features = VkPhysicalDeviceFeatures.create(frame);
+
+ features.setDepthClamp(VK_TRUE);
+
+ // Select 3 application queues
+ // graphics, compute, present
+ Demo.DemoDevice device = Demo.createDevice(instance, features, surface,
+ new int[]{Demo.QUEUE_GRAPHICS | Demo.QUEUE_PRESENT, Demo.QUEUE_TRANSFER},
+ new String[]{
+ VK_KHR_SWAPCHAIN_EXTENSION_NAME
+ }, scope);
+
+ VkShaderModule vertex = Demo.createShaderModule(device.device(), ShaderIO.loadDemo_vert(frame), scope);
+ VkShaderModule fragment = Demo.createShaderModule(device.device(), ShaderIO.loadDemo_frag(frame), scope);
+ HandleArray<VkSwapchainKHR> chains = VkSwapchainKHR.createArray(1, frame, scope);
+
+ HandleArray<VkSemaphore> imageReady = device.createSemaphores(MAX_FRAMES_INFLIGHT, frame, scope);
+ HandleArray<VkSemaphore> renderDone = device.createSemaphores(MAX_FRAMES_INFLIGHT, frame, scope);
+ HandleArray<VkFence> renderFence = device.createFences(MAX_FRAMES_INFLIGHT, VK_FENCE_CREATE_SIGNALED_BIT, frame, scope);
+
+ RenderInfo render = createRenderInfo(device, width, height, vertex, fragment);
+
+ Demo.DemoChain chain = render.chain();
+ HandleArray<VkCommandBuffer> commandBuffers = render.commandBuffers();
+
+ chains.setAtIndex(0, chain.swapchain());
+
+ HandleArray<VkFence> imageFence = VkFence.createArray(chain.images().size(), frame, scope);
+
+ VkSubmitInfo submitDraw = VkSubmitInfo.create(
+ 1, null, // imageRead.current
+ IntArray.create(frame, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT),
+ 1, null, // commandBuffers.current
+ 1, null, // renderDone.current
+ frame);
+
+ IntArray imageIndex = IntArray.createArray(1, frame);
+ VkPresentInfoKHR present = VkPresentInfoKHR.create(
+ 1, null, //renderDone,
+ 1, chains, imageIndex,
+ null,
+ frame);
+
+ int currentFrame = 0;
+ long last = System.nanoTime();
+outer: while (true) {
+ int res;
+
+ System.out.println(currentFrame);
+ for (Event e = window.nextEvent(true); e != null; e = window.nextEvent(false)) {
+ System.out.println(e);
+ switch (e.type) {
+ case Event.KEY:
+ if (e.key == 9)
+ break outer;
+ break;
+ case Event.CLOSE:
+ break outer;
+ case Event.RESIZE:
+ if (e.width == 0) {
+ System.out.println("iconise");
+ while (true) {
+ e = window.nextEvent(true);
+ if (e.type == Event.RESIZE && e.width > 0 && e.height > 0)
+ break;
+ if (e.type == Event.CLOSE)
+ break outer;
+ }
+ }
+ width = e.width;
+ height = e.height;
+ System.out.printf("resize: %dx%d\n", width, height);
+ break;
+ }
+ }
+
+ long next = System.nanoTime();
+ //System.out.printf(" %12.9f\n", (next - last) * 1E-9);
+ last = next;
+
+ res = device.device().vkAcquireNextImageKHR(chain.swapchain(), ~0, imageReady.get(currentFrame), null, imageIndex);
+ if (res == VK_SUCCESS || res == VK_SUBOPTIMAL_KHR) {
+ int index = imageIndex.get(0);
+ VkFence renderBusy = renderFence.get(currentFrame);
+
+ // This logic is to handle multiple inflight frames
+ {
+ HandleArray<VkFence> imageBusy = imageFence.asSlice(index, 1);
+ HandleArray<VkFence> renderCurrent = renderFence.asSlice(currentFrame, 1);
+
+ if (imageFence.get(index) != null)
+ device.device().vkWaitForFences(1, imageBusy, VK_TRUE, ~0);
+ else
+ device.device().vkWaitForFences(1, renderCurrent, VK_TRUE, ~0);
+
+ imageFence.set(index, renderBusy);
+ device.device().vkResetFences(1, renderCurrent);
+ }
+
+ submitDraw.setWaitSemaphores(imageReady.asSlice(currentFrame));
+ submitDraw.setSignalSemaphores(renderDone.asSlice(currentFrame));
+ submitDraw.setCommandBuffers(commandBuffers.asSlice(index));
+
+ present.setWaitSemaphores(renderDone.asSlice(currentFrame));
+
+ device.queues()[0].vkQueueSubmit(1, submitDraw, renderBusy);
+ device.queues()[0].vkQueuePresentKHR(present);
+
+ //device.device().vkWaitForFences(1, renderFence, VK_TRUE, ~0);
+ // resize
+ if (res == VK_SUBOPTIMAL_KHR) {
+ device.device().vkDeviceWaitIdle();
+
+ System.out.println("reconfigure");
+ render.close();
+ render = createRenderInfo(device, width, height, vertex, fragment);
+ chain = render.chain();
+ chains.setAtIndex(0, chain.swapchain());
+ commandBuffers = render.commandBuffers();
+ }
+
+ } else {
+ System.out.println(Vulkan.getErrorMessage(res));
+ }
+
+ currentFrame = (currentFrame + 1) % MAX_FRAMES_INFLIGHT;
+ }
+ device.device().vkDeviceWaitIdle();
+
+ Stream.concat(imageReady.stream(), renderDone.stream()).forEach(device.device()::vkDestroySemaphore);
+ renderFence.stream().forEach(device.device()::vkDestroyFence);
+
+ device.device().vkDestroyShaderModule(fragment);
+ device.device().vkDestroyShaderModule(vertex);
+
+ render.close();
+ device.close();
+ instance.vkDestroySurfaceKHR(surface);
+ instance.vkDestroyInstance();
+ }
+ }
+}
--- /dev/null
+
+notzed.vulkan.test_SHADERS = \
+ vulkan/test/mandelbrot.comp.bin \
+ vulkan/test/cube.vert.bin \
+ vulkan/test/cube.frag.bin \
+ vulkan/test/sdf.vert.bin \
+ vulkan/test/sdf.frag.bin \
+ vulkan/test/demo.vert.bin \
+ vulkan/test/demo.frag.bin
+
+notzed.vulkan.test_JAVA_GENERATED = \
+ vulkan/test/ShaderIO.java
+
+notzed.vulkan.test_RESOURCES_GENERATED = \
+ $(notzed.vulkan.test_SHADERS)
+
+notzed.vulkan.test_SPIRV = $(notzed.vulkan.test_SHADERS:%=bin/gen/notzed.vulkan.test/classes/%)
+
+bin/gen/notzed.vulkan.test/classes/%.bin: src/notzed.vulkan.test/shaders/%
+ mkdir -p $(@D)
+ glslangValidator --target-env vulkan1.0 -V -o $@ $<
+
+bin/gen/notzed.vulkan.test/classes/vulkan/test/ShaderIO.java: $(notzed.vulkan.test_SPIRV) src/notzed.vulkan.test/gen/generate-shaderio
+ src/notzed.vulkan.test/gen/generate-shaderio $@ $(notzed.vulkan.test_SPIRV)
--- /dev/null
+#!/usr/bin/perl
+
+# probably should take scope
+
+use strict;
+
+use File::Path qw(make_path);
+use File::Basename;
+
+my $path = shift;
+
+open my $f, ">", "$path~" || die;
+
+print $f <<END;
+package vulkan.test;
+
+import au.notzed.nativez.IntArray;
+import au.notzed.nativez.Memory;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.channels.Channels;
+import jdk.incubator.foreign.MemorySegment;
+import jdk.incubator.foreign.SegmentAllocator;
+
+public class ShaderIO {
+ static IntArray loadSPIRV(String name, long size, SegmentAllocator alloc) throws IOException {
+ try ( InputStream is = TestMandelbrot.class.getResourceAsStream(name)) {
+ MemorySegment seg = alloc.allocateArray(Memory.INT, size);
+ int length = Channels.newChannel(is).read(seg.asByteBuffer());
+ return IntArray.create(seg.asSlice(0, length));
+ }
+ }
+END
+
+while ($#ARGV >= 0) {
+ my $file = shift;
+ my $func = ucfirst(basename($file, '.bin'));
+ my $name = basename($file);
+ my $size = (stat($file))[7];
+
+ die "No such file: $file" if !-f $file;
+
+ $func =~ s/\./_/gon;
+
+ print $f "\tstatic IntArray load$func(SegmentAllocator alloc) throws IOException { return loadSPIRV(\"$name\", $size, alloc); }\n";
+}
+
+print $f "}\n";
+
+close $f;
+
+rename "$path~",$path;
--- /dev/null
+#version 400
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+layout (location = 0) in vec4 color;
+layout (location = 0) out vec4 outColor;
+void main() {
+ outColor = color;
+}
--- /dev/null
+#version 400
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+layout (std140, binding = 0) uniform bufferVals {
+ mat4 mvp;
+} data;
+layout (location = 0) in vec4 pos;
+layout (location = 1) in vec4 inColor;
+layout (location = 0) out vec4 outColor;
+
+void main() {
+ outColor = inColor;
+ gl_Position = data.mvp * pos;
+}
--- /dev/null
+#version 450
+
+layout (location = 0) in vec3 colour;
+layout (location = 0) out vec4 pixel;
+
+void main() {
+ pixel = vec4(colour, 1);
+}
--- /dev/null
+#version 450
+
+layout (location=0) in vec2 inPosition;
+layout (location=1) in vec3 inColour;
+
+layout (location=0) out vec3 colour;
+
+void main() {
+ gl_Position = vec4(inPosition, 0.0, 1.0);
+ colour = inColour;
+}
--- /dev/null
+#version 450
+
+#define WIDTH (1920*1)
+#define HEIGHT (1080*1)
+#define LWS_X 8
+#define LWS_Y 8
+#define LIMIT 10000
+
+layout (local_size_x = LWS_X, local_size_y = LWS_Y, local_size_z = 1 ) in;
+
+layout(std430, binding = 0) buffer buf {
+ uint imageData[];
+};
+
+void main() {
+
+ /*
+ In order to fit the work into workgroups, some unnecessary threads are launched.
+ We terminate those threads here.
+ */
+ if(gl_GlobalInvocationID.x >= WIDTH || gl_GlobalInvocationID.y >= HEIGHT)
+ return;
+
+ float x = float(gl_GlobalInvocationID.x) / float(WIDTH);
+ float y = float(gl_GlobalInvocationID.y) / float(HEIGHT);
+
+ /*
+ What follows is code for rendering the mandelbrot set.
+ */
+ vec2 uv = vec2(x, (y - 0.5) * (12.0 / 19.0) + 0.5);
+ float n = 0.0;
+ vec2 c = vec2(-.445, 0.0) + (uv - 0.5)*(4.0);
+ vec2 z = vec2(0.0);
+ const int M = LIMIT;
+
+ for (int i = 0; i<M; i++) {
+ z = vec2(z.x*z.x - z.y*z.y, 2.*z.x*z.y) + c;
+
+ if (dot(z, z) > 4)
+ break;
+ n++;
+ }
+
+ // we use a simple cosine palette to determine color:
+ // http://iquilezles.org/www/articles/palettes/palettes.htm
+ float t = float(n) * 500.0 / float(M);
+ vec3 d = vec3(0.5, 0.5, 0.5);
+ vec3 e = vec3(0.5, 0.5, 0.5);
+ vec3 f = vec3(1.0, 1.0, 1.0);
+ vec3 g = vec3(0.00, 0.33, 0.67);
+
+ vec4 color = vec4( d + e*cos( 6.28318*(f*t+g) ) ,1.0);
+
+ if (n == M)
+ color = vec4(0, 0, 0, 1);
+
+ // store the rendered mandelbrot set into a storage buffer:
+ imageData[WIDTH * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x] = packUnorm4x8(color);
+ //imageData[WIDTH * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x].value = color;
+}
--- /dev/null
+#version 400
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+layout (location = 0) out vec4 outColor;
+
+void main() {
+ vec2 res = vec2(800, 800);
+ vec2 uv = (gl_FragCoord.xy - 0.5 * res) * (1.0 / 400.0);
+
+ float d = max(-(length(uv) - 0.5), length(uv + vec2(0.1, 0.1)) - 0.6);
+
+ if (d < 0) {
+ outColor = vec4(0, 0, 1, 1);
+ } else {
+ outColor = vec4(1, 0, 0, 1);
+ }
+
+
+ //outColor = vec4(1, 0, 1, 1);
+ //outColor = vec4(gl_FragCoord.xy * 1.0 / 500.0, 0, 1);
+}
--- /dev/null
+#version 400
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+layout (location = 0) in vec4 pos;
+
+void main() {
+ gl_Position = pos;
+}
--- /dev/null
+
+module notzed.vulkan {
+ requires transitive notzed.nativez;
+ requires notzed.xlib;
+ requires notzed.xcb;
+
+ exports vulkan;
+}
--- /dev/null
+# -*- Mode:text; tab-width:4; electric-indent-mode: nil; indent-line-function:insert-tab; -*-
+
+# things to check; vkCmdSetFragmentShadingRateKHR
+
+# types for function calls
+
+code method {
+ invoke {{
+ /* method:invoke */
+ static final MethodHandle {name}$FH = Memory.downcall("{name}",
+ {function-descriptor});
+ /**
+ * success: {successcodes}
+ * errors: {errorcodes}
+ */
+ public {static}{java-result} {rename}(
+ {java-arg}) {
+ {native-result-define}
+ try {create-frame}{
+ {native-init}
+ {native-result-assign}{name}$FH.invokeExact({invoke-arg});
+ {result-test}{
+ {java-result-assign}
+ {java-result-return}
+ }
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ {result-throw}
+ }
+ }}
+}
+
+code method-query {
+ invoke {{
+ /* method-query:invoke */
+ static final MethodHandle {name}$FH = Memory.downcall("{name}",
+ {function-descriptor});
+ /**
+ * success: {successcodes}
+ * errors: {errorcodes}
+ */
+ public {static}{java-result} {rename}(
+ {java-arg}) {
+ {native-result-define}
+ try {create-frame}{
+ {native-init}
+ {native-result-assign}{name}$FH.invokeExact({query-arg});
+ {result-test}{
+ {query-init}
+ {native-result-assign}{name}$FH.invokeExact({invoke-arg});
+ {java-result-assign}
+ {java-result-return}
+ }
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ {result-throw}
+ }
+ }}
+}
+
+code method-extension {
+ dispatch {{
+ final NativeSymbol {name}$NS;
+ }}
+ invoke {{
+ /* method-extension:invoke */
+ final static MethodHandle {name}$DH = Memory.downcall(
+ {function-descriptor});
+ /**
+ * success: {successcodes}
+ * errors: {errorcodes}
+ */
+ public {static}{java-result} {rename}(
+ {java-arg}) {
+ {native-result-define}
+ try {create-frame}{
+ {native-init}
+ {native-result-assign}{name}$DH.invokeExact(dispatch.{name}$NS, {invoke-arg});
+ {result-test}{
+ {java-result-assign}
+ {java-result-return}
+ }
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ {result-throw}
+ }
+ }}
+}
+
+code method-extension-query {
+ dispatch {{
+ final NativeSymbol {name}$NS;
+ }}
+ invoke {{
+ /* method-extension:invoke */
+ final static MethodHandle {name}$DH = Memory.downcall(
+ {function-descriptor});
+ /**
+ * success: {successcodes}
+ * errors: {errorcodes}
+ */
+ public {static}{java-result} {rename}(
+ {java-arg}) {
+ {native-result-define}
+ try {create-frame}{
+ {native-init}
+ {native-result-assign}{name}$DH.invokeExact(dispatch.{name}$NS, {query-arg});
+ {result-test}{
+ {query-init}
+ {native-result-assign}{name}$DH.invokeExact(dispatch.{name}$NS, {invoke-arg});
+ {java-result-assign}
+ {java-result-return}
+ }
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ {result-throw}
+ }
+ }}
+}
+
+# ###################################################################### #
+
+# common parts for funcpointer
+code funcpointer {
+ common {{
+ public {java-result} call({java-arg});
+
+ public final static FunctionDescriptor DESCRIPTOR =
+ {function-descriptor};
+ }}
+ upcall {{
+ public static FunctionPointer<{rename}> upcall({rename} target$, ResourceScope scope$) {
+ interface Trampoline {
+ {native-result} call({native-arg});
+ }
+ Trampoline trampoline = ({native-arg}) -> {
+ // frame? scope?
+ try {trampoline-scope} {
+ {trampoline-result-define}
+ {trampoline-result-assign}target$.call({trampoline-arg});
+ {trampoline-result-return}
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ };
+ return new FunctionPointer<>(
+ Memory.upcall(
+ MethodHandles.lookup(),
+ trampoline,
+ "call",
+ "{trampoline-signature}",
+ DESCRIPTOR,
+ scope$),
+ target$);
+ }
+ }}
+ # vulkan has none
+ downcall {{ }}
+}
+
+code funcpointer-readwrite insert=funcpointer:common,funcpointer:upcall,funcpointer:downcall {
+ class {{
+ package {package};
+
+ import jdk.incubator.foreign.*;
+ import java.lang.invoke.*;
+ import au.notzed.nativez.*;
+
+ @FunctionalInterface
+ public interface {name} {
+
+ {common}
+
+ {upcall}
+ {downcall}
+ }
+ }}
+}
+
+# ###################################################################### #
+
+# values required
+
+# java-arg java parameter type and and name
+# invoke-arg native value for invokeExact argument
+# native-arg native parameter type and name
+# trampoline-arg java value for upcall invocation
+# layout MemoryLayout
+# sig JNI signature string
+
+# parameterisation values
+# type java type
+# carrier native (jdk.foriegn) type
+# length array length
+
+type value {
+ java-arg {{ {type} {name} }}
+ invoke-arg {{ {name} }}
+
+ native-arg {{ {carrier} {name}$ }}
+ trampoline-arg {{ {name}$ }}
+}
+
+type value-array {
+ java-arg {{ {type} {name} }}
+ invoke-arg {{ {name} }}
+
+ native-arg {{ {carrier} {name}$ }}
+ trampoline-arg {{ {name}$ }}
+}
+
+type value-array2d {
+ java-arg {{ {type} {name} }}
+ invoke-arg {{ {name} }}
+
+ native-arg {{ {carrier} {name}$ }}
+ trampoline-arg {{ {name}$ }}
+}
+
+type uint8_t,char value {
+ carrier {{ byte }}
+ type {{ byte }}
+ layout {{ Memory.BYTE }}
+}
+
+type uint16_t value {
+ carrier {{ short }}
+ type {{ short }}
+ layout {{ Memory.SHORT }}
+}
+
+type uint32_t,int,int32_t value {
+ carrier {{ int }}
+ type {{ int }}
+ layout {{ Memory.INT }}
+ sig {{ I }}
+}
+
+type uint64_t,int64_t,size_t value {
+ carrier {{ long }}
+ type {{ long }}
+ layout {{ Memory.LONG }}
+ sig {{ J }}
+}
+
+type float value {
+ carrier {{ float }}
+ type {{ float }}
+ layout {{ Memory.FLOAT }}
+}
+
+type double value {
+ carrier {{ double }}
+ type {{ double }}
+ layout {{ Memory.DOUBLE }}
+}
+
+# ###################################################################### #
+
+# type uint8_t[],char[] value-array {
+# type {{ ByteArray }}
+# layout {{ MemoryLayout.sequenceLayout({len1}, Memory.BYTE) }}
+# typei {{ byte }}
+# }
+
+#type uint32_t[],int32_t[] value-array {
+# type {{ IntArray }}
+# layout {{ MemoryLayout.sequenceLayout({len1}, Memory.INT) }}
+# typei {{ int }}
+#}
+
+# type uint64_t[] value-array {
+# type {{ LongArray }}
+# layout {{ MemoryLayout.sequenceLayout({len1}, Memory.LONG) }}
+# typei {{ long }}
+# }
+
+# calls float[] =-> pointer
+#type float[] value-array {
+# # or should it be float[] ?
+# type {{ FloatArray }}
+# layout {{ MemoryLayout.sequenceLayout({len1}, Memory.FLOAT) }}
+# typei {{ float }}
+#}
+
+# type struct[] inline-array {
+# type {{ {baseType} }}
+# layout {{ MemoryLayout.sequenceLayout({len1}, {baseType}.LAYOUT) }}
+# }
+
+# type float[][] value-array2d {
+# type {{ FloatArray }}
+# typei {{ float }}
+# layout {{ MemoryLayout.sequenceLayout({len1}, MemoryLayout.sequenceLayout({len2}, Memory.FLOAT)) }}
+# }
+
+# select=len? or what?
+
+type pointer value {
+ carrier {{ MemoryAddress }}
+ layout {{ Memory.POINTER }}
+ type {{ MemoryAddress }}
+ sig {{ Ljdk/incubator/foreign/MemoryAddress; }}
+
+ invoke-arg {{ Memory.address({name}) }}
+}
+
+type void {
+ type {{ void }}
+ sig {{ V }}
+ java-arg {{ }}
+}
+
+type void* pointer;
+
+type funcpointer pointer {
+ type {{ NativeSymbol }}
+}
+
+# FIXME: clenaup, value-pointer does nothing
+type value-pointer pointer {
+}
+
+type uint8_t* value-pointer {
+ type ByteArray;
+}
+
+type uint32_t*,int32_t*,int* value-pointer {
+ type IntArray;
+}
+
+type uint64_t* value-pointer {
+ type LongArray;
+}
+
+type float* value-pointer {
+ type FloatArray;
+}
+
+type size_t* value-pointer {
+ type LongArray;
+}
+
+type pointer-length pointer {
+}
+
+type void*-length pointer-length {
+ type MemorySegment;
+}
+
+type uint8_t*-length pointer-length {
+ type ByteArray;
+}
+
+type uint32_t*-length,int32_t*-length pointer-length {
+ type IntArray;
+}
+
+type uint32_t[] pointer-length {
+ type IntArray;
+ length {{ {len1} }}
+}
+
+type uint64_t*-length pointer-length {
+ type LongArray;
+}
+
+type float*-length pointer-length {
+ type FloatArray;
+}
+
+type float[] pointer-length {
+ type FloatArray;
+ length {{ {len1} }}
+}
+
+# special handling for strings, will fail if it isn't
+type char* pointer need-frame {
+ type {{ String }}
+
+ invoke-arg {{ (Addressable)Memory.copyString({name}, frame$) }}
+
+ # null check?
+ trampoline-arg {{ {name}$.getUtf8String(0) }}
+
+ # this just verifies it's a string type
+ length eval {{
+ if ($v->{len} =~ m/null-terminated/) {
+ 1;
+ } else {
+ print "Warning: not sure if this is a string: $s->{name} $m->{name}\n";
+ }
+ }}
+
+}
+
+# type XXchar**-length pointer-length accessor=value-alloc {
+# type {{ String[] }}
+
+# java-set {{ {name}$VH.set(segment, Memory.copyStringArray({name}, alloc$)); {set-length} }}
+# java-get {{ Memory.copyStringArray((MemoryAddress){name}$VH.get(segment), {length}) }}
+
+# set-length eval {{
+# if ($v->{len} =~ m/(.*),null-terminated/) {
+# 'set'.ucfirst($1).'({name}.length)';
+# } else {
+# die Dumper($v, $s);
+# }
+# }}
+# }
+
+# FIXME: wrong
+type Xuint32_t** pointer {
+ type {{ HandleArray<IntArray> }}
+ typei {{ IntArray }}
+}
+
+type uint32_t**-length pointer {
+ type {{ HandleArray<IntArray> }}
+ typei {{ IntArray }}
+}
+
+type void** pointer {
+ type PointerArray;
+}
+
+type void**-length pointer-length {
+ type PointerArray;
+}
+
+type handle pointer {
+ type {{ {baseType} }}
+}
+
+type handle* pointer {
+ type {{ HandleArray<{typei}> }}
+ typei {{ {baseType} }}
+
+ invoke-arg {{ Memory.address({name}) }}
+}
+
+type handle*-length pointer-length {
+ type {{ HandleArray<{baseType}> }}
+ typei {{ {baseType} }}
+}
+
+#type struct inline {
+# type {{ {baseType} }}
+# layout {{ {baseType}.LAYOUT }}
+#}
+
+type struct* pointer trampoline-scope {
+ type {{ {baseType} }}
+
+ trampoline-arg {{ {baseType}.create({name}$, scope$$) }}
+}
+
+type struct*-length pointer-length {
+ type {{ {baseType} }}
+ typei {{ {baseType} }}
+}
+
+type struct**-length pointer-length {
+ type {{ HandleArray<{baseType}> }}
+ typei {{ {baseType} }}
+}
+
+type struct** pointer {
+}
+
+# xlib
+type XID,Window,VisualID uint64_t;
+
+type Display* handle {
+ type xlib.XDisplay;
+}
+
+# xcb
+type xcb_window_t uint32_t;
+type xcb_visualid_t uint32_t;
+type xcb_connection_t* handle {
+ type xcb.Connection;
+}
+
+# special types for call overrides
+type instance handle is-instance {
+ java-arg {{ }}
+ invoke-arg {{ (Addressable)self }}
+ native-arg {{ }}
+}
+
+# A pointer type which is always ignored/supressed, e.g. VkAllocationCallbacks *
+type struct*-ignore,void*-ignore void* {
+ java-arg {{ }}
+ invoke-arg {{ (Addressable)MemoryAddress.NULL }}
+ trampoline-arg {{ }}
+}
+
+type void*-return void* {
+ native-result-define {{ MemoryAddress result$; }}
+ native-result-assign {{ result$ = (MemoryAddress) }}
+ java-result-return {{ return result$; }}
+}
+
+type funcpointer-return funcpointer need-scope {
+ native-result-define {{ MemoryAddress result$; }}
+ native-result-assign {{ result$ = (MemoryAddress) }}
+ java-result-return {{ return NativeSymbol.ofAddress(pName, result$, scope$); }}
+}
+
+type uint32_t-return uint32_t {
+ native-result-define {{ int result$; }}
+ native-result-assign {{ result$ = (int) }}
+ java-result-return {{ return result$; /* uint32_t */ }}
+
+ trampoline-result-define {{ int result$$; }}
+ trampoline-result-assign {{ result$$ = (int) }}
+ trampoline-result-return {{ return result$$; /* uint32_t */ }}
+}
+
+type uint64_t-return,size_t-return uint64_t {
+ native-result-define {{ long result$; }}
+ native-result-assign {{ result$ = (long) }}
+ java-result-return {{ return result$; /* uint64_t */ }}
+}
+
+# for handle constructors
+type handle*-output handle* need-frame need-scope {
+ java-arg {{ }}
+ invoke-arg {{ (Addressable){name} }}
+
+ java-result {{ {baseType} }}
+ native-init {{ MemorySegment {name} = frame$.allocate(Memory.POINTER); }}
+ java-result-assign {{ {baseType} result$$ = {baseType}.create({name}.get(Memory.POINTER, 0), scope$); }}
+ java-result-return {{ return result$$; }}
+}
+
+type uint32_t*-output,int*-output uint32_t* need-frame {
+ java-arg {{ }}
+ invoke-arg {{ (Addressable){name}.address() }}
+
+ java-result {{ int }}
+ native-init {{ MemorySegment {name} = frame$.allocate(Memory.INT); }}
+ java-result-assign {{ int result$$ = {name}.getAtIndex(Memory.INT, 0); }}
+ java-result-return {{ return result$$; }}
+}
+
+type uint64_t*-output uint64_t* need-frame {
+ java-arg {{ }}
+ invoke-arg {{ (Addressable){name}.address() }}
+
+ java-result {{ long }}
+ native-init {{ MemorySegment {name} = frame$.allocate(Memory.LONG); }}
+ java-result-assign {{ long result$$ = {name}.getAtIndex(Memory.LONG, 0); }}
+ java-result-return {{ return result$$; }}
+}
+
+type void*-output handle*-output need-frame {
+ java-arg {{ }}
+ invoke-arg {{ (Addressable){name}.address() }}
+
+ java-result {{ MemoryAddress }}
+ native-init {{ MemorySegment {name} = frame$.allocate(Memory.POINTER); }}
+ java-result-assign {{ MemoryAddress result$$ = {name}.getAtIndex(Memory.POINTER, 0); }}
+ java-result-return {{ return result$$; }}
+}
+
+type VkBool32*-output uint32_t*-output {
+ java-result {{ boolean }}
+ java-result-return {{ return result$$ != 0; }}
+}
+
+# for handle constructors of dispatchable types
+type dispatch*-output handle*-output {
+ java-result-assign {{ {baseType} result$$ = {baseType}.create({name}.get(Memory.POINTER, 0), dispatch, scope$); }}
+}
+
+# for query and return types
+type handle*-length-query handle*-length need-alloc need-scope {
+ java-arg {{ }}
+ invoke-arg {{ (Addressable){name}.address() }}
+ query-arg {{ (Addressable)MemoryAddress.NULL }}
+
+ java-result {{ {type} }}
+ query-init {{ {type} {name} = {typei}.createArray({length}, alloc$, scope$); }}
+ java-result-return {{ return {name}; }}
+}
+
+type dispatch*-length-query handle*-length-query need-scope {
+ query-init {{ {type} {name} = {typei}.createArray({length}, alloc$, dispatch, scope$); }}
+}
+
+type struct*-length-query struct*-length need-alloc {
+ java-arg {{ }}
+ invoke-arg {{ (Addressable){name}.address() }}
+ query-arg {{ (Addressable)MemoryAddress.NULL }}
+
+ java-result {{ {type} }}
+ query-init {{ {type} {name} = {typei}.createArray({length}, alloc$); }}
+ java-result-return {{ return {name}; }}
+}
+
+type void*-length-query void*-length need-alloc {
+ java-arg {{ }}
+ invoke-arg {{ (Addressable){name} }}
+ query-arg {{ (Addressable)MemoryAddress.NULL }}
+
+ java-result {{ {type} }}
+ query-init {{ {type} {name} = alloc$.allocate({length}); }}
+ java-result-return {{ return {name}; }}
+}
+
+type uint32_t*-length-query uint32_t*-length need-alloc {
+ java-arg {{ }}
+ invoke-arg {{ (Addressable){name}.address() }}
+ query-arg {{ (Addressable)MemoryAddress.NULL }}
+
+ java-result {{ {type} }}
+ query-init {{ {type} {name} = IntArray.createArray({length}, alloc$); }}
+ java-result-return {{ return {name}; }}
+}
+
+type uint32_t*-querylen uint32_t* need-frame {
+ type {{ MemorySegment }}
+ java-arg {{ }}
+ invoke-arg {{ (Addressable){name}$ }}
+
+ native-init {{ {type} {name}$ = alloc$.allocate(Memory.INT, 0); }}
+ query-init {{ long {name} = {name}$.get(Memory.INT, 0); }}
+}
+
+type size_t*-querylen uint32_t* need-frame {
+ type {{ MemorySegment }}
+ java-arg {{ }}
+ invoke-arg {{ (Addressable){name}$ }}
+
+ native-init {{ {type} {name}$ = alloc$.allocate(Memory.LONG, 0); }}
+ query-init {{ long {name} = {name}$.get(Memory.LONG, 0); }}
+}
+
+type void**-output void** need-frame need-scope {
+ type {{ MemorySegment }}
+
+ java-arg {{ }}
+ invoke-arg {{ (Addressable){name} }}
+
+ native-init {{ MemorySegment {name} = frame$.allocate(Memory.POINTER); }}
+
+ java-result {{ {type} }}
+ java-result-assign {{ {type} result$$ = MemorySegment.ofAddress({name}.get(Memory.POINTER, 0), {length}, scope$); }}
+ java-result-return {{ return result$$; }}
+}
+
+type vkMapMemory-output void**-output {
+ length {{ size }}
+}
+
+# some tweaks that the auto-discovery code misses/isn't worth adding to
+override commands {
+ vkMapMemory device=type:instance ppData=type:vkMapMemory-output;
+
+ # Don't need userData
+ PFN_vkDebugUtilsMessengerCallbackEXT pUserData=type:void*-ignore;
+ PFN_vkDebugReportCallbackEXT pUserData=type:void*-ignore;
+ PFN_vkDeviceMemoryReportCallbackEXT pUserData=type:void*-ignore;
+
+ # Mapped to a NativeSymbol via 'funcpointer' type
+ PFN_vkVoidFunction ignore;
+
+ # Don't need VkAllocationCallbacks, don't need these
+ PFN_vkAllocationFunction ignore;
+ PFN_vkReallocationFunction ignore;
+ PFN_vkFreeFunction ignore;
+ PFN_vkInternalAllocationNotification ignore;
+ PFN_vkInternalFreeNotification ignore;
+}
--- /dev/null
+
+bin/status/notzed.vulkan.depjava: \
+ bin/status/notzed.vulkan.export
+
+bin/status/notzed.vulkan.export: \
+ $(NATIVEZ_HOME)/lib/config.pm \
+ $(NATIVEZ_HOME)/lib/tokenise.pm \
+ $(NATIVEZ_HOME)/lib/code.pm \
+ $(NATIVEZ_HOME)/lib/api.pm \
+ src/notzed.vulkan/gen/generate-vulkan \
+ src/notzed.vulkan/gen/vulkan.pm \
+ src/notzed.vulkan/gen/struct-types.api \
+ src/notzed.vulkan/gen/command-types.api
+
+bin/status/notzed.vulkan.export:
+ NATIVEZ_HOME=$(NATIVEZ_HOME) src/notzed.vulkan/gen/generate-vulkan -t vulkan -d bin/gen/notzed.vulkan/classes
+ mkdir -p $(@D)
+ touch $@
--- /dev/null
+#!/usr/bin/perl
+
+use Data::Dumper;
+
+use File::Path qw(make_path);
+use File::Basename;
+use Time::HiRes qw(clock_gettime CLOCK_REALTIME);
+
+use strict;
+
+use Carp 'verbose';
+use FindBin;
+use lib "$FindBin::Bin", 'bin/linux-amd64/lib', "$ENV{NATIVEZ_HOME}/lib";
+
+use vulkan;
+use config;
+use code;
+
+$SIG{__DIE__} = sub { Carp::confess( @_ ) };
+$SIG{'INT'} = sub { Carp::confess() };
+$Data::Dumper::Indent = 1;
+
+# ###################################################################### #
+
+my $enumInfo = {
+ 'uint32_t' => {
+ type => 'int'
+ },
+ 'uint64_t' => {
+ type => 'long',
+ suffix => 'L'
+ },
+ 'float' => {
+ type => 'float',
+ suffix => 'f'
+ },
+ 'const char *' => {
+ type => 'String'
+ },
+};
+
+my %primitiveMap = (
+ 'char' => 'byte',
+ 'uint8_t' => 'byte',
+ 'uint16_t' => 'short',
+ 'int32_t' => 'int',
+ 'uint32_t' => 'int',
+ 'int' => 'int',
+ 'int64_t' => 'long',
+ 'uint64_t' => 'long',
+ 'size_t' => 'long',
+ 'float' => 'float',
+ 'double' => 'double',
+ 'VkFlags' => 'int',
+ 'VkFlags64' => 'long'
+);
+
+# ###################################################################### #
+my $now = clock_gettime(CLOCK_REALTIME);
+my $next;
+my $sys = {};
+
+$sys->{output} = 'bin/gen/notzed.vulkan/classes';
+$sys->{package} = 'vulkan';
+$sys->{verbose} = 0;
+
+my $vk = new vulkan($sys);
+
+printf "%9.6f load registry\n", (($next = clock_gettime(CLOCK_REALTIME)) - $now); $now = $next;
+
+my $api = $vk->buildFeatures(
+ [ 'VK_VERSION_1_0', 'VK_VERSION_1_1', 'VK_VERSION_1_2', 'VK_VERSION_1_3' ],
+ [ 'xlib',
+ #'wayland',
+ 'xcb' ]);
+
+printf "%9.6f build api view\n", (($next = clock_gettime(CLOCK_REALTIME)) - $now); $now = $next;
+
+my $structTypes = loadTypes($api, 'struct-types.api');
+my $commandTypes = loadTypes($api, 'command-types.api');
+
+printf "%9.6f load templates\n", (($next = clock_gettime(CLOCK_REALTIME)) - $now); $now = $next;
+
+analyseTypes($vk, $api);
+
+printf "%9.6f analyse types\n", (($next = clock_gettime(CLOCK_REALTIME)) - $now); $now = $next;
+
+# Use some heuristics to create overrides for improving the api
+
+# - object constructor functions return values rather take pointer* values
+# - array query functions perform the query and return the array
+# - extension functions use a different invocation mechanism
+# - drop any 'ignore' types from argument lists
+
+# - [attempt to] determine which types need to be read/write/arrays
+
+# Scan structs
+my %defaultTemplate;
+
+foreach my $s (values %{$api->{types}}) {
+ my $overrides = $structTypes->{overrides};
+ my $types = $structTypes->{types};
+
+ next if (defined($overrides->{$s->{name}}));
+
+ foreach my $m (@{$s->{items}}) {
+ my $nstar = $m->{deref} =~ tr/*/*/;
+
+ if ($m->{deref} eq 'struct*-length') {
+ $defaultTemplate{$m->{baseType}}->{array} = 1;
+ } elsif ($m->{deref} eq 'struct[]') {
+ $defaultTemplate{$m->{baseType}}->{array} = 1;
+ }
+ }
+
+ $defaultTemplate{$s->{name}}->{name} = 'struct-readonly' if ($s->{returnedonly} eq 'true');
+}
+
+# build default overrides for commands
+foreach my $s (values %{$api->{commands}}) {
+ my $overrides = $commandTypes->{overrides};
+ my $types = $commandTypes->{types};
+ my $first = $s->{items}->[0];
+ my $last = $s->{items}->[$#{$s->{items}}];
+ my $llast = $s->{items}->[$#{$s->{items}}-1];
+ my $result = $s->{proto};
+ my $index = $s->{index};
+
+ # check type updates anyway
+ foreach my $m (@{$s->{items}}) {
+ if ($m->{deref} eq 'struct*-length') {
+ $defaultTemplate{$m->{baseType}}->{name} = 'struct-readwrite' if !($m->{fullType} =~ m/const/n) && $api->{types}->{$m->{baseType}}->{returnedonly} ne 'true';
+ $defaultTemplate{$m->{baseType}}->{array} = 1;
+ } elsif ($m->{deref} eq 'struct*') {
+ $defaultTemplate{$m->{baseType}}->{name} = 'struct-readwrite' if !($m->{fullType} =~ m/const/n) && $api->{types}->{$m->{baseType}}->{returnedonly} ne 'true';
+ }
+ }
+
+ next if (defined($overrides->{$s->{name}}));
+
+ my $override = {};
+
+ # force handles to be instance types
+ if ($first->{deref} eq 'handle') {
+ $override->{$first->{name}}->{type} = 'instance';
+ }
+
+ # extension function default template
+ if (defined($s->{extensions})) {
+ $override->{template} = 'method-extension';
+ }
+
+ # Constructor
+ if ($last->{deref} eq 'handle*') {
+ if (!$last->{len}) {
+ my $t = $api->{handles}->{$last->{baseType}};
+ print "constructor: $s->{name}\n" if $sys->{verbose};
+ $override->{$last->{name}}->{type} =
+ $t->{type} eq 'VK_DEFINE_HANDLE' && $t->{name} ne 'VkInstance' ?
+ 'dispatch*-output' : 'handle*-output';
+ } elsif ($index->{$last->{len}}) {
+ print "constructor?: $s->{name}\n";# if $sys->{verbose};
+ die;
+ } else {
+ print "allocate-constructor?: $s->{name} $last->{len}\n";# if $sys->{verbose};
+ }
+ }
+
+ # turn array-query functions into auto-allocate/return types
+ # ones we care about with output
+ # handle*-length
+ # struct*-length
+ # uint32_t*-length
+ # void*-length
+
+ if ($last->{deref} =~ m/-length$/ && (my $len = $index->{$last->{len}})) {
+ if (index($len->{deref}, '*') >= 0) {
+ my $protoa = "$result->{fullType} $s->{name}("
+ .join(', ', map { "$_->{fullType}" } @{$s->{items}})
+ .")";
+ print "array-constructor: $protoa\n" if $sys->{verbose} > 1;
+
+ my $otype = ($last->{deref} eq 'handle*-length' && $api->{handles}->{$last->{baseType}}->{type} eq 'VK_DEFINE_HANDLE')
+ ? 'dispatch*-length-query' : $last->{deref}.'-query';
+ my $ltype = $len->{deref}.'-querylen';
+
+ die "no template $otype" if !defined($commandTypes->{types}->{$otype});
+ die "no template $ltype" if !defined($commandTypes->{types}->{$ltype});
+
+ $override->{template} = defined($s->{extensions}) ? 'method-extension-query' : 'method-query';
+ $override->{$last->{name}}->{type} = $otype;
+ $override->{$len->{name}}->{type} = $ltype;
+ }
+ }
+
+ # A whole bunch of query functions
+ if ($s->{name} =~ m/^vkGet/ && !($last->{fullType} =~ m/const/n) && !(defined($override->{$last->{name}}) && defined($override->{$last->{name}}->{type}))) {
+ if ($last->{fullType} eq 'VkBool32 *') {
+ print "output: [$last->{fullType}] [$last->{deref}] $s->{name}\n" if $sys->{verbose};
+ $override->{$last->{name}}->{type} = 'VkBool32*-output';
+ } elsif ($last->{deref} =~ m/^(int|uint32_t|uint64_t|void)\*$/on) {
+ print "output: [$last->{fullType}] [$last->{deref}] $s->{name}\n" if $sys->{verbose};
+ $override->{$last->{name}}->{type} = $last->{deref}."-output";
+ } else {
+ print "output? [$last->{fullType}] [$last->{deref}] $s->{name}\n" if $sys->{verbose};
+ }
+ }
+
+ # other per-item things
+ foreach my $m (@{$s->{items}}) {
+ my $so = $structTypes->{overrides}->{$m->{baseType}};
+
+ if ($so->{ignore}) {
+ die "No type '$m->{deref}-ignore'" if !defined($types->{$m->{deref}.'-ignore'});
+ $override->{$m->{name}}->{type} = $m->{deref}.'-ignore';
+ }
+ }
+
+ $overrides->{$s->{name}} = $override if %{$override};
+}
+
+{
+ my $overrides = $structTypes->{overrides};
+ my $templates = $structTypes->{templates};
+
+ foreach my $k (keys %defaultTemplate) {
+ next if defined($overrides->{$k}) && defined($overrides->{$k}->{template});
+
+ my $t = $defaultTemplate{$k};
+ my $name = $t->{name} || "struct-writeonly";
+
+ $name .= "-array" if $t->{array};
+
+ print "$name: $k\n" if $sys->{verbose} > 1;
+ die "No override $k $name" if !$templates->{$name};
+ $overrides->{$k}->{template} = $name;
+ }
+}
+
+printf "%9.6f guess overrides\n", (($next = clock_gettime(CLOCK_REALTIME)) - $now); $now = $next;
+
+if (0) {
+ analyseAccessors($api);
+ exit 1;
+}
+
+if (0) {
+ open(my $f, '>', 'types.pm');
+ print $f Dumper($commandTypes, $structTypes);
+ close $f;
+}
+
+if (0) {
+ open(my $f, '>', 'api.pm');
+ print $f Dumper($api);
+ close $f;
+ print "Dumped api.pm\n";
+ exit 1;
+}
+
+if (0) {
+ open(my $f, '>', 'vk.pm');
+ print $f Dumper($vk);
+ close $f;
+ die;
+}
+
+exportVulkan($vk, $api, $structTypes);
+
+# dump out the extension function-pointer tables
+{
+ my $f = openOutput($sys, 'DispatchInstance');
+ my $template = $structTypes->{templates}->{dispatch};
+ my @init = ();
+ my @fieldInit = ();
+
+ foreach my $k (sort keys %{$api->{commands}}) {
+ my $c = $api->{commands}->{$k};
+
+ next if !defined($c->{extensions});
+
+ push @fieldInit, code::formatTemplate($template->{'field-init'}, $c);
+ push @init, code::formatTemplate($template->{'init'}, $c);
+
+ }
+
+ my $vars = {
+ package => 'vulkan',
+ Name => 'DispatchInstance',
+ init => join("\n\t\t", @init),
+ 'field-init' => join("\n\t", @fieldInit),
+ };
+ print $f code::formatTemplateStream($template->{class}, $vars);
+
+ closeOutput($sys, 'DispatchInstance', $f);
+}
+
+# structs and unions
+foreach my $k (sort keys %{$api->{types}}) {
+ my $s = $api->{data}->{$k};
+
+ die if !defined $s;
+ next if $s->{alias};
+
+ my $override = $structTypes->{overrides}->{$s->{name}};
+
+ next if $override->{ignore};
+
+ my $f = openOutput($sys, $s->{Name});
+ print $f formatStruct($vk, $api, $s);
+ closeOutput($sys, $s->{Name}, $f);
+}
+
+# handles
+foreach my $k (sort keys %{$api->{handles}}) {
+ my $s = $api->{data}->{$k};
+
+ die if !defined $s;
+ next if $s->{alias};
+
+ my $f = openOutput($sys, $s->{name});
+ print $f formatHandle($vk, $api, $s);
+ closeOutput($sys, $s->{name}, $f);
+}
+
+# upcalls
+foreach my $k (sort keys %{$api->{funcpointers}}) {
+ my $s = $api->{data}->{$k};
+
+ die if !defined $s;
+ next if $s->{alias};
+
+ my $override = $commandTypes->{overrides}->{$s->{name}};
+
+ next if $override->{ignore};
+
+ my $f = openOutput($sys, $s->{name});
+ print $f formatFunctionPointer($vk, $api, $s);
+ closeOutput($sys, $s->{name}, $f);
+}
+
+printf "%9.6f export classes\n", (($next = clock_gettime(CLOCK_REALTIME)) - $now); $now = $next;
+
+exit 0;
+
+# ###################################################################### #
+
+sub formatStructLayout {
+ my $types = shift;
+ my $s = shift;
+ my $offset = 0;
+ my @fields = ();
+
+ # This doens't need to worry about overrides
+
+ if ($s->{category} eq 'struct') {
+ foreach my $m (@{$s->{items}}) {
+ my $type = $types->{$m->{deref}};
+ my $diff = $m->{bitOffset} - $offset;
+
+ push @fields, "MemoryLayout.paddingLayout($diff)" if $diff;
+
+ if ($type) {
+ my $v = buildVars($s, $m, $type);
+
+ push @fields, code::formatTemplate($v->{layout}, $v).".withName(\"$m->{name}\") /* $m->{deref} $m->{fullType} */";
+ $offset = $m->{bitOffset} + $m->{bitSize};
+ } else {
+ push @fields, "/* Missing: $m->{deref} $m->{name} */";
+ }
+ }
+ } else {
+ foreach my $m (@{$s->{items}}) {
+ my $type = $types->{$m->{deref}};
+
+ if ($type) {
+ my $v = buildVars($s, $m, $type);
+
+ push @fields, code::formatTemplate($v->{layout}, $v).".withName(\"$m->{name}\") /* $m->{deref} $m->{fullType} */";
+ $offset = ($m->{bitOffset} + $m->{bitSize}) if ($m->{bitOffset} + $m->{bitSize}) > $offset;
+ } else {
+ push @fields, "/* Missing: $m->{deref} $m->{name} */";
+ }
+ }
+ }
+
+ my $diff = $s->{bitSize} - $offset;
+
+ push @fields, "MemoryLayout.paddingLayout($diff)" if $diff;
+
+ return "MemoryLayout.".$s->{category}."Layout(\n\t\t".join(",\n\t\t", @fields).").withName(\"$s->{name}\")";
+}
+
+# Experiment: see if sharing varhandles would be of any benefit
+# - analyse all pointer/int fields for cross-overs
+# for vulkan 1.3:
+# Total fields: 3370
+# Unique fields: 368
+# so very significant savings possible
+sub analyseAccessors {
+ my $api = shift;
+ my %handles;
+ my $total;
+ my %lookat;
+
+ map { $lookat{$_} = 1 } qw(Memory.POINTER Memory.BYTE Memory.SHORT Memory.INT Memory.LONG Memory.FLOAT Memory.DOUBLE);
+
+ foreach my $s (values %{$api->{types}}) {
+ my $override = $structTypes->{overrides}->{$s->{name}};
+
+ next if $s->{alias};
+ next if $override->{ignore};
+
+ foreach my $m (@{$s->{items}}) {
+ my $deref = $m->{deref};
+ my $type = $structTypes->{types}->{$deref};
+ my $v = buildVars($s, $m, $type);
+ my $layout = code::formatTemplate($v->{layout}, $v);
+ my $index = $m->{bitOffset} / 8;
+
+ die if ($m->{bitoffset} & ($m->{bitSize}-1));
+
+ if ($lookat{$layout}) {
+ $index = $m->{bitOffset} / $m->{bitSize};
+ }
+
+ my $k = sprintf "$layout \@ %03d", $index;
+
+ $handles{$k}++;
+ $total++;
+ }
+ }
+
+ print "Other unique handles =\n";
+ foreach my $h (sort keys %handles) {
+ $h =~ m/^(.*) \@/;
+ my $x = $lookat{$1};
+ if (!$lookat{$1}) {
+ printf " %5d $h\n", $handles{$h};
+ }
+ }
+ print "Unique handles of interest =\n";
+ foreach my $h (sort keys %handles) {
+ $h =~ m/^(.*) \@/;
+ if ($lookat{$1}) {
+ printf " %5d $h\n", $handles{$h};
+ }
+ }
+ my @keys = keys %handles;
+ print "Total fields: $total\n";
+ print "Unique fields: $#keys\n";
+}
+
+# ###################################################################### #
+
+sub loadTypes {
+ my $api = shift;
+ my $file = shift;
+ my $config = new config({ includes=>[ $FindBin::Bin ] }, "$FindBin::Bin/$file");
+
+ my $types = {};
+ my $templates = {};
+ my $overrides = {};
+
+ foreach my $t (@{$config->{objects}}) {
+ if ($t->{type} eq 'type') {
+ my $nopts = $#{$t->{options}};
+ my $type = {};
+
+ die ("No prototype provided/found for empty type ".Dumper($t)) if ($#{$t->{items}} < 0 && $#{$t->{options}} < 0);
+
+ # Check options / load inherited values
+ foreach my $o (@{$t->{options}}) {
+ if ($o =~ m/^accessor=(.*)$/o) {
+ die "No template $1" if !defined($templates->{$1});
+ $type->{accessor} = $templates->{$1};
+ } elsif ($o eq 'need-frame') {
+ $type->{'need-frame'} = 1;
+ } elsif ($o eq 'need-scope') {
+ $type->{'need-scope'} = 1;
+ } elsif ($o eq 'trampoline-scope') {
+ $type->{'trampoline-scope'} = 1;
+ } elsif ($o eq 'need-alloc') {
+ $type->{'need-alloc'} = 1;
+ } elsif ($o eq 'is-instance') {
+ $type->{'is-instance'} = 1;
+ } elsif (defined($types->{$o})) {
+ $type = { %$type, %{$types->{$o}} };
+ } else {
+ die "Unknown option '$o' in ".Dumper($t);
+ }
+ }
+
+ # Load the fields
+ foreach my $s (@{$t->{items}}) {
+ if (defined $s->{literal}) {
+ $type->{$s->{match}} = $s->{literal};
+ } elsif ($#{$s->{options}} >= 0) {
+ $type->{$s->{match}} = $s->{options}->[$#{$s->{options}}];
+ } else {
+ $type->{$s->{match}} = 0;
+ }
+
+ $type->{"$s->{match}:eval"} = 1 if config::optionFlag('eval', $s);
+ }
+
+ # Write to all aliases
+ foreach my $k (split /,/,$t->{name}) {
+ $types->{$k} = $type;
+ }
+ } elsif ($t->{type} eq 'code') {
+ my $code = {
+ insert => {},
+ };
+
+ foreach my $o (@{$t->{options}}) {
+ if ($o =~ m/insert=(.*)/) {
+ foreach my $x (split /,/,$1) {
+ if ($x =~ m/(.*):(.*)/) {
+ die "$x $t->{name} ".Dumper($templates->{$1}) if !defined $templates->{$1}->{$2};
+ $code->{insert}->{$2} = $templates->{$1}->{$2};
+ }
+ }
+ } elsif ($o =~ m/^fields=(.*)/) {
+ $code->{fields} = $1;
+ } elsif (defined($templates->{$o})) {
+ $code = { %$code, %{$templates->{$o}} };
+ } else {
+ die ("Unknown option '$o'");
+ }
+ }
+
+ foreach my $s (@{$t->{items}}) {
+ if (defined $s->{literal}) {
+ my $t = $s->{literal};
+
+ $t =~ s/^\t//gm;
+ $code->{$s->{match}} = $t;
+ } else {
+ delete $code->{$s->{match}};
+ }
+
+ $code->{"$s->{match}:eval"} = 1 if config::optionFlag('eval', $s);
+ }
+
+ $templates->{$t->{name}} = $code;
+ } elsif ($t->{type} eq 'override') {
+ foreach my $s (@{$t->{items}}) {
+ my $c = { };
+ foreach my $o (@{$s->{options}}) {
+ if ($o =~ m/^(.*)=type:(.*)/) {
+ die "No such type $s->{match} $2\n" if !defined $types->{$2};
+ $c->{$1}->{type} = $2;
+ } elsif ($o =~ m/^(.*)=accessor:(.*)/) {
+ die "No accessor template $o" if !defined($templates->{$2});
+ $c->{$1}->{accessor} = $templates->{$2};
+ } elsif ($o =~ m/^template=(.*)/) {
+ die "No template $o" if !defined($templates->{$1});
+ $c->{template} = $1;
+ } elsif ($o eq 'expand') {
+ $c->{expand} = 1;
+ } elsif ($o eq 'ignore') {
+ $c->{ignore} = 1;
+ } elsif ($o eq 'append') {
+ $c->{append} = $s->{literal};
+ }
+ }
+ $overrides->{$s->{match}} = $c;
+ }
+ }
+ }
+
+ # templates should probably just go in one
+ {
+ types => $types,
+ templates => $templates,
+ overrides => $overrides,
+ };
+}
+
+sub uniq {
+ my %seen;
+ return grep { !$seen{$_}++ } @_;
+}
+
+# generate Vulkan.java
+sub exportVulkan {
+ my $vk = shift;
+ my $api = shift;
+ my $structTypes = shift;
+ my $seen = {};
+ my $template = $structTypes->{templates}->{Vulkan};
+
+ my @constants = ();
+ my @defines = ();
+
+ # create error code->string mappings
+ {
+ my $s = $api->{enums}->{VkResult};
+ my @infos;
+
+ foreach my $m (sort { $a->{value} <=> $b->{value} } @{$s->{items}}) {
+ next if ($m->{alias});
+ push @infos, "new ErrorInfo($m->{value}, \"$m->{name}\")";
+ }
+ push @constants, "static final ErrorInfo errors[] = {";
+ push @constants, join(",\n\t\t", @infos);
+ push @constants, "};\n";
+ }
+
+ # special case for api constants
+ {
+ my $s = $api->{data}->{'API Constants'};
+
+ push @constants, "// API Constants\n";
+
+ foreach my $m (@{$s->{items}}) {
+ next if defined($m->{alias});
+ next if $seen->{$m->{name}}++;
+
+ my $i = $enumInfo->{$m->{type}};
+ my $v = $m->{value};
+
+ # convert to java
+ $v =~ s/[()ULF]+//gon if (!($v =~ m/^"/));
+
+ push @constants,"public final static $i->{type} $m->{name} = $v$i->{suffix};";
+ }
+ }
+
+ # include any defines we have a template for
+ foreach my $k (sort keys %{$api->{defines}}) {
+ if ($template->{$k}) {
+ push @defines, $template->{$k};
+ } else {
+ print "Ignored: $k\n";
+ }
+ }
+ foreach my $k (sort keys %{$api->{enums}}) {
+ my $s = $api->{data}->{$k};
+ my $type = $s->{fullType} ? $s->{fullType} : 'VkFlags';
+ my $i = $enumInfo->{$vk->{data}->{$type}->{type}};
+ my $ext;
+
+ next if $s->{alias};
+
+ push @constants, "";
+ push @constants, "// $s->{name} $type";
+
+ my $index = {};
+ map { $index->{$_->{name}} = $_ } (@{$s->{items}});
+
+ foreach my $m (@{$s->{items}}) {
+ next if defined($m->{alias});
+ next if $seen->{$m->{name}}++;
+
+ my $v = $m->{value};
+
+ $v = 1<<$m->{bitpos} if !defined($v) && defined($m->{bitpos});
+
+ die Dumper("Ca't work out value", $m, $s) if !defined($v);
+
+ if (defined($m->{extension}) && $m->{extension} ne $ext) {
+ $ext = $m->{extension};
+ push @constants, "// from $ext";
+ }
+
+ push @constants, "public final static $i->{type} $m->{name} = $v$i->{suffix};";
+ }
+ $ext = "";
+ foreach my $m (@{$s->{items}}) {
+ next if !defined($m->{alias});
+ next if $seen->{$m->{name}}++;
+ next if !defined($index->{$m->{alias}});
+
+ if (defined($m->{extension}) && $m->{extension} ne $ext) {
+ $ext = $m->{extension};
+ push @constants, "// from $ext";
+ }
+
+ push @constants, "public final static $i->{type} $m->{name} = $m->{alias};";
+ }
+ }
+
+ my $v = {
+ package => $sys->{package},
+ defines => join("\n\t", @defines),
+ constants => join("\n\t", @constants),
+ };
+
+ my $f = openOutput($sys, 'Vulkan');
+
+ print $f code::formatTemplateStream($template->{class}, $v);
+
+ closeOutput($sys, 'Vulkan', $f);
+}
+
+# ###################################################################### #
+# class.name to class/name.java
+sub classToPath {
+ my $sys = shift;
+ my $name = shift;
+
+ $name = $sys->{package}.'.'.$name;
+ $name =~ s@\.@/@g;
+ $name = $sys->{output}.'/'.$name.'.java';
+ $name;
+}
+
+sub closeOutput {
+ my $sys = shift;
+ my $name = shift;
+ my $f = shift;
+ my $path = classToPath($sys, $name);
+
+ close($f) || die;
+ rename($path.'~', $path) || die ("rename failed: $!");
+}
+
+sub openOutput {
+ my $sys = shift;
+ my $name = shift;
+
+ my $path = classToPath($sys, $name);
+ my $dir = dirname($path);
+
+ make_path($dir) if (!-d $dir);
+
+ open(my $f, ">", $path.'~') || die ("Cannot open '$path' for writing");
+ print "writing '$path'\n" if $sys->{verbose} > 0;
+ $f;
+}
+
+
+# Calculate canonical derefernce types for each field and parameter
+sub analyseFields {
+ my $vk = shift;
+ my $api = shift;
+ my $seen = shift;
+ my $s = shift;
+
+ # what about const?
+ # FIXME: bitfields
+
+ my $index = {};
+
+ map { $index->{$_->{name}} = $_ } @_;
+
+ $s->{index} = $index;
+
+ foreach my $m (@_) {
+ my $t = $api->{data}->{$m->{baseType}};
+ my $nstar = $m->{fullType} =~ tr/*/*/;
+ my $type;
+ my $array = '';
+
+ # Check array sizes
+ if ($m->{fullType} =~ m/\[(.*)\]\[(.*)\]$/o) {
+ $array = '[][]';
+ $m->{len1} = $1;
+ $m->{len2} = $2;
+ } elsif ($m->{fullType} =~ m/\[(.*)\]$/o) {
+ my $isize = $1;
+ my $size;
+ if ($isize =~ m/^\d+$/n) {
+ $size = $isize;
+ } else {
+ $size = $vk->{data}->{'API Constants'}->{index}->{$isize}->{value};
+ }
+ $array = '[]';
+ $m->{len1} = $size;
+ } elsif ($m->{fullType} =~ m/[\[\]]/on) {
+ die Dumper($m)
+ }
+
+ if (!defined($t)) {
+ # will be primitive or external
+ $type = $m->{baseType} if ($nstar == 0);
+ $type = "$m->{baseType}*" if ($nstar == 1);
+ $type = "$m->{baseType}**" if ($nstar == 2);
+ die if $nstar > 2;
+ } else {
+ # unmap aliases
+ while ($t->{alias}) {
+ print "alias $t->{name} -> $t->{alias}\n";
+ $t = $api->{data}->{$t->{alias}};
+ die if !defined $t;
+ $m->{baseType} = $t->{name};
+ }
+
+ if ($t->{category} eq 'enum') {
+ $t = $vk->{data}->{$t->{fullType}};
+ $type = $t->{type} if ($nstar == 0);
+ $type = "$t->{type}*" if ($nstar == 1);
+ die if $nstar > 1;
+ } elsif ($t->{category} =~ m/struct|union/on) {
+ $m->{type} = $t->{name};
+ $type = 'struct' if ($nstar == 0);
+ $type = 'struct*' if ($nstar == 1);
+ $type = 'struct**' if ($nstar == 2);
+ die if $nstar > 2;
+ } elsif ($t->{category} eq 'handle') {
+ $m->{type} = $t->{name};
+ #if ($t->{type} eq 'VK_DEFINE_HANDLE') {
+ # $type = 'dhandle' if ($nstar == 0);
+ # $type = 'dhandle*' if ($nstar == 1);
+ #} else {
+ $type = 'handle' if ($nstar == 0);
+ $type = 'handle*' if ($nstar == 1);
+ #}
+ die if $nstar > 1;
+ } elsif ($t->{category} eq 'basetype') {
+ # ??
+ $type = $t->{type} if ($nstar == 0);
+ $type = "$t->{type}*" if ($nstar == 1);
+ die Dumper($m, $t) if $nstar > 1;
+ } elsif ($t->{category} eq 'funcpointer') {
+ $m->{type} = $t->{name};
+ $type = "funcpointer" if ($nstar == 0);
+ die if $nstar > 0;
+ } else {
+ die Dumper($m, $t);
+ }
+ }
+
+ if ($s->{category} eq 'struct') {
+ my $mover = $structTypes->{overrides}->{$m->{baseType}};
+ $type .= "-expand" if $nstar == 0 && $mover->{expand};
+ } elsif ($s->{category} eq 'union') {
+ # VkClearValue - handled manually
+ }
+
+ # an array type with a length
+ if ($nstar > 0 && $m->{len}) {
+ if ($s->{category} =~ m/struct|union/on) {
+ if ($m->{altlen}) {
+ if ($m->{altlen} =~ m/^(.*)(VK_UUID_SIZE)(.*)$/) {
+ $m->{length} = $1.'Vulkan.'.$2.$3;
+ } elsif ($m->{altlen} =~ m/^([^a-zA-Z_]*)([a-zA-Z_]+)(.*)$/) {
+ my $len = $index->{$2};
+ if (defined $len) {
+ $m->{length} = $1.'get'.ucfirst($2).'()'.$3;
+ }
+ } else {
+ die "Unhandled len/altlen: ".Dumper($m);
+ }
+ } elsif ($m->{len} =~ m/(.*),null-terminated/) {
+ my $len = $index->{$1};
+ if (defined $len) {
+ $m->{length} = "get$len->{Name}()";
+ }
+ } elsif ($m->{len} eq 'null-terminated') {
+ # ignore
+ } elsif ($m->{len} =~ m/^(.*),(\d+)$/) {
+ # ignore?
+ } else {
+ my $len = $index->{$m->{len}};
+ if (defined $len) {
+ my $cast = ($len->{fullType} eq 'uint32_t') ? '(int)' : '';
+
+ die "Not simple type" if ($len->{fullType} ne $len->{baseType});
+ $m->{length} = "get$len->{Name}()";
+ } else {
+ die "what?".Dumper($m);
+ }
+ }
+ } elsif ($s->{category} eq 'command') {
+ if ($m->{altlen}) {
+ die;
+ } else {
+ $m->{length} = $m->{len} if $index->{$m->{len}};
+ $index->{$m->{len}}->{lengthfor} = $m->{name} if $index->{$m->{len}};
+ }
+ } else {
+ die Dumper($s);
+ }
+ $type = $type.'-length' if $m->{length};
+ }
+
+ $seen->{$m->{fullType}} = $type.$array;
+ $m->{deref} = $type.$array;
+
+ # Calculate name, with some fixup hacks
+ my $name = $m->{name};
+ #if ($s->{type} =~ m/struct|union/on)
+ {
+ # Strip leading 'p' for pointers
+ if ($name eq 'ppGeometries') { # && $s->{name} eq 'VkAccelerationStructureBuildGeometryInfoKHR') {
+ $name = 'PGeometries';
+ } elsif ($nstar > 0 && $name =~ m/^p{$nstar}/) {
+ my $strip = $nstar;
+
+ if ($t->{category} eq 'handle' && $type ne 'handle*-length') {
+ $strip -= 1;
+ }
+
+ $name = substr $name, $strip;
+ }
+
+ $name =~ s/^pfn//o if $type eq 'funcpointer';
+ # CamelCase
+ $name =~ s/(?:^|_)(.)/\U$1/og;
+ }
+ $m->{Name} = $name;
+ }
+}
+
+sub analyseTypes {
+ my $vk = shift;
+ my $api = shift;
+ my $seen = {};
+
+ foreach my $s (grep { $_->{items} } values %{$api->{types}}) {
+ analyseFields($vk, $api, $seen, $s, @{$s->{items}});
+
+ my $name = $s->{name};
+ $name =~ s/(?:^|_)(.)/\U$1/og;
+ $s->{Name} = $name;
+
+ my $first = $s->{items}->[0];
+ my $second = $s->{items}->[1];
+
+ if ($first->{name} eq 'sType' && $second && $second->{name} eq 'pNext') {
+ $first->{'no-setall'} = 1;
+ $second->{'no-setall'} = 1;
+ print "typed: $s->{name}\n" if $sys->{verbose} > 1;
+ } else {
+ print "untyped: $s->{name}\n" if $sys->{verbose} > 1;
+ }
+ }
+
+ foreach my $c (values %{$api->{funcpointers}}) {
+ analyseFields($vk, $api, $seen, $c, $c->{proto}, @{$c->{items}});
+ }
+
+ foreach my $c (values %{$api->{commands}}) {
+ $c->{proto}->{name} = 'result$';
+ $c->{proto}->{Name} = 'result$';
+ analyseFields($vk, $api, $seen, $c, $c->{proto}, @{$c->{items}});
+
+ # collect all member functions on handles
+ my $first = $c->{items}->[0];
+ my $last = $c->{items}->[$#{$c->{items}}];
+ if ($first->{deref} eq 'handle') {
+ my $t = $api->{handles}->{$first->{baseType}};
+ while ($t->{alias}) {
+ $t = $api->{handles}->{$t->{alias}};
+ }
+ die "No handle found ".Dumper($c) if !defined $t;
+ push @{$t->{commands}}, $c->{name};
+ } elsif ($c->{name} =~ m/vkEnumerateInstance|vkCreateInstance/) {
+ push @{$api->{handles}->{'VkInstance'}->{commands}}, $c->{name};
+ } else {
+ die "No owner for call ".Dumper($c);
+ }
+ }
+
+ if ($sys->{verbose}) {
+ print "Unique Types:\n";
+ my $base = {};
+ map { $base->{$_} = 1 } values %$seen;
+
+ foreach my $k (sort keys %$base) {
+ print " $k\n";
+ }
+ }
+}
+
+# what else?
+# vk? api?
+# this way-over-evaluates, probably only call once on every field and member instead
+sub buildVars {
+ my $s = shift;
+ my $m = shift;
+ my $type = shift;
+ my $v = { %{$m} };
+
+ foreach my $k (grep { index($_, ':') == -1 } keys %$type) {
+ my $t = $type->{$k};
+
+ if ($type->{"$k:eval"}) {
+ $v->{$k} = $t;
+ die "Eval failed: $! $@: ".Dumper($m, $type) if !defined($v->{$k});
+ } elsif ($t) {
+ $v->{$k} = $t;
+ }
+ }
+
+ $v;
+}
+
+sub formatStructLayout {
+ my $types = shift;
+ my $s = shift;
+ my $offset = 0;
+ my @fields = ();
+
+ # This doens't need to worry about overrides
+
+ if ($s->{category} eq 'struct') {
+ foreach my $m (@{$s->{items}}) {
+ my $type = $types->{$m->{deref}};
+ my $diff = $m->{bitOffset} - $offset;
+
+ push @fields, "MemoryLayout.paddingLayout($diff)" if $diff;
+
+ if ($type) {
+ my $v = buildVars($s, $m, $type);
+
+ push @fields, code::formatTemplate($v->{layout}, $v).".withName(\"$m->{name}\") /* $m->{deref} $m->{fullType} */";
+ $offset = $m->{bitOffset} + $m->{bitSize};
+ } else {
+ push @fields, "/* Missing: $m->{deref} $m->{name} */";
+ }
+ }
+ } else {
+ foreach my $m (@{$s->{items}}) {
+ my $type = $types->{$m->{deref}};
+
+ if ($type) {
+ my $v = buildVars($s, $m, $type);
+
+ push @fields, code::formatTemplate($v->{layout}, $v).".withName(\"$m->{name}\") /* $m->{deref} $m->{fullType} */";
+ $offset = ($m->{bitOffset} + $m->{bitSize}) if ($m->{bitOffset} + $m->{bitSize}) > $offset;
+ } else {
+ push @fields, "/* Missing: $m->{deref} $m->{name} */";
+ }
+ }
+ }
+
+ my $diff = $s->{bitSize} - $offset;
+
+ push @fields, "MemoryLayout.paddingLayout($diff)" if $diff;
+
+ return "MemoryLayout.".$s->{category}."Layout(\n\t\t".join(",\n\t\t", @fields).").withName(\"$s->{name}\")";
+}
+
+sub formatAccessorIf {
+ my $s = shift;
+ my $m = shift;
+ my $info = shift;
+ my $type = shift;
+ my $field = shift;
+ my $v = shift;
+ my $accessor = $type->{accessor};
+ my $template = $accessor->{$field};
+
+ if ($template) {
+ $template = eval($template) if ($accessor->{"$field:eval"});
+
+ die "Error executing template $field $accessor->{$field}: $@" if (!defined($template));
+
+ push @{$info->{$field}}, code::formatTemplate($template, $v) if $template;
+ }
+}
+
+sub formatStruct {
+ my $vk = shift;
+ my $api = shift;
+ my $s = shift;
+ my $templates = $structTypes->{templates};
+ my $types = $structTypes->{types};
+ my $overrides = $structTypes->{overrides};
+
+ my $override = $overrides->{$s->{name}};
+ my $tempname = $override->{template} ? $override->{template} : 'struct-writeonly';
+ my $template = $templates->{$tempname};
+ my @fields = split(/,/, $template->{fields});
+ my $info;
+
+ map { $info->{$_} = [] } @fields;
+
+ my $setall = defined $info->{'java-setall'};
+
+ # unions need multiple constructors
+ if ($setall) {
+ if ($s->{category} eq 'struct') {
+ $info->{create}->{create} = {
+ 'setall-arg' => [],
+ setall => [],
+ setallat => [],
+ };
+ } elsif ($s->{category} eq 'union') {
+ foreach my $m (@{$s->{items}}) {
+ $info->{create}->{"create$m->{Name}"} = {
+ 'setall-arg' => [],
+ setall => [],
+ setallat => [],
+ };
+ }
+ } else {
+ die;
+ }
+ }
+
+ my $needAlloc = 0;
+
+ # Collect all fields
+ foreach my $m (@{$s->{items}}) {
+ my $nstar = $m->{deref} =~ tr/*/*/;
+ my $mover = $override->{$m->{name}};
+ my $deref = defined($mover->{type}) ? $mover->{type} : $m->{deref};
+ my $type = $types->{$deref};
+
+ die "No type $deref ".Dumper($m, $s) if !$type;
+ die Dumper($mover, $type) if $mover->{accessor};
+
+ if ($type->{accessor}) {
+ my $v = buildVars($s, $m, $type);
+ my @todump;
+
+ if ($m->{values}) {
+ @todump = qw(init initat init-array set setat);
+ } else {
+ @todump = qw(get getat set setat getorset getorsetat);
+
+ if ($setall && !$m->{'no-setall'}) {
+ my $create = $s->{category} eq 'struct' ? $info->{create}->{create} : $info->{create}->{"create$m->{Name}"};
+ formatAccessorIf($s, $m, $create, $type, 'setall-arg', $v);
+ formatAccessorIf($s, $m, $create, $type, 'setall', $v);
+ formatAccessorIf($s, $m, $create, $type, 'setallat', $v);
+
+ $needAlloc = 1 if $type->{'need-alloc'};
+ }
+ }
+
+ push @{$info->{handle}}, code::formatTemplate($v->{handle}, $v)." /* $m->{name} $m->{fullType} ($m->{deref}) */" if $info->{handle} && $v->{handle};
+ push @{$info->{handleat}}, code::formatTemplate($v->{handleat}, $v) if $info->{handleat} && $v->{handleat};
+
+ foreach my $field (@todump) {
+ if ($info->{$field} && $type->{accessor}->{$field}) {
+ my $t = $type->{accessor}->{$field};
+
+ $t = eval $t if $type->{accessor}->{"$field:eval"};
+ die "$type->{accessor}->{$field}\n---\n$@" if !defined($t);
+
+ push @{$info->{$field}}, code::formatTemplate($t, $v) if $t;
+ }
+ }
+ }
+ }
+
+ # create constructors
+ my $v = {
+ package => 'vulkan',
+ name => $s->{name},
+ Name => $s->{Name},
+ layout => formatStructLayout($types, $s),
+ append => defined($override->{append}) ? $override->{append} : '',
+ };
+
+ foreach my $field (@fields) {
+ $v->{$field} = join("\n", @{$info->{$field}});
+ }
+
+ # build sub-components using the full $v
+ my @createAll = ();
+ foreach my $k (keys %{$template->{insert}}) {
+ my $t = $template->{insert}->{$k};
+
+ die if (!defined($t));
+
+ if ($k eq 'create-all' || $k eq 'set-all' || $k eq 'setat-all') {
+ if ($setall) {
+ foreach my $kk (keys %{$info->{create}}) {
+ my $create = $info->{create}->{$kk};
+
+ if ($#{$create->{'setall-arg'}} >= 0) {
+ my $v = {
+ create => $kk,
+ set => $kk =~ s/create/set/r,
+ Name => $s->{Name},
+ 'java-setall-arguments' => join (', ', @{$create->{'setall-arg'}}),
+ 'java-setall' => join ("\n\t\t", @{$create->{setall}}),
+ 'java-setallat' => join ("\n\t\t", @{$create->{setallat}}),
+ };
+ push @createAll, code::formatTemplateStream($t, $v);
+ }
+ }
+ }
+ } else {
+ $v->{$k} = code::formatTemplate($t, $v);
+ }
+ }
+ $v->{'create-all'} = join("\n", @createAll) if $setall;
+
+ #die Dumper($info, $v) if $s->{name} eq 'VkRect2D';
+
+ join("\n", map { '// '.$_ } split(/\n/,Dumper($s)))."\n".
+ code::formatTemplateStream($template->{class}, $v);
+}
+
+# TODO: the template here could be mapped from types.api perhaps?
+# also same for the various fields, init/getset/etc.
+sub formatHandle {
+ my $vk = shift;
+ my $api = shift;
+ my $s = shift;
+ my $templates = $structTypes->{templates};
+ my $overrides = $structTypes->{overrides};
+ my $override = $overrides->{$s->{name}};
+ my $tempname = $override->{template} ? $override->{template} : 'handle';
+ my $template = $templates->{$tempname};
+
+ my $info = {
+ init => [],
+ commands => [],
+ };
+
+ if (defined $s->{commands}) {
+ foreach my $k (sort @{$s->{commands}}) {
+ my $c = $api->{commands}->{$k};
+ push @{$info->{commands}}, formatFunction($api, $commandTypes, $c);
+ }
+ }
+
+ my $v = {
+ package => 'vulkan',
+ name => $s->{name},
+ Name => $s->{Name},
+ init => join ("\n", @{$info->{init}}),
+ commands => join ("\n", @{$info->{commands}}),
+ append => defined($override->{append}) ? $override->{append} : '',
+ };
+
+ code::formatTemplateStream($template->{class}, $v);
+}
+
+sub formatSignature {
+ my $s = shift;
+ my $types = $commandTypes->{types};
+ my $d = '(';
+
+ foreach my $m (@{$s->{items}}) {
+ my $x = $types->{$m->{deref}};
+
+ die "No sig defined ".Dumper($m) if !defined($x) || !defined($x->{sig});
+
+ $d .= $x->{sig};
+ }
+ $d .= ')';
+
+ my $m = $s->{proto};
+ my $x = $types->{$m->{deref}};
+ die "No sig defined ".Dumper($m) if !defined($x) || !defined($x->{sig});
+ $d .= $x->{sig};
+}
+
+# Forms all the parameter templates
+sub collectFunctionInfo {
+ my $api = shift;
+ my $ct = shift;
+ my $s = shift;
+ my $types = $ct->{types};
+ my $overrides = $ct->{overrides};
+ my $void = $s->{proto}->{fullType} eq 'void';
+ my $override = $overrides->{$s->{name}};
+
+ my @javaArgs = ();
+ my @invokeArgs = ();
+ my @nativeInit = ();
+ my @queryInit = ();
+ my @queryArgs = ();
+
+ my @nativeArgs = ();
+ my @trampArgs = ();
+
+ my $info = {
+ rename => $s->{name},
+ name => $s->{name},
+ 'function-descriptor' => formatFunctionDescriptor($ct, $s),
+ 'native-result-define' => '',
+ 'native-result-assign' => '',
+ 'native-result' => 'void',
+ 'trampoline-result-define' => '',
+ 'trampoline-result-assign' => '',
+ 'trampoline-scope' => '',
+ 'result-test' => '',
+ 'create-frame' => '',
+ 'java-result' => 'void',
+ 'java-result-assign' => '',
+ 'result-throw' => '',
+
+ 'java-result-return' => 'return;',
+ 'trampoline-result-return' => 'return;',
+ };
+
+ my $hasInstance = 0;
+ my $needFrame = 0;
+ my $needAlloc = 0;
+ my $needScope = 0;
+ my $trampScope = 0;
+
+ my @arrayFields = qw(java-arg invoke-arg native-init query-init query-arg native-arg trampoline-arg);
+ my @fixedFields = qw(java-result java-result-return java-result-assign);
+
+ map { $info->{$_} = [] } @arrayFields;
+
+ # Calculate parameters
+ foreach my $m (@{$s->{items}}) {
+ my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
+ my $type = $types->{$deref};
+
+ die "No type found ".Dumper($m, $s, $override) if !$type;
+
+ my $v = buildVars($s, $m, $type);
+
+ foreach my $field (@arrayFields) {
+ if ($v->{$field}) {
+ push @{$info->{$field}}, code::formatTemplate($v->{$field}, $v);
+ } elsif ($field eq 'query-arg') {
+ push @{$info->{$field}}, code::formatTemplate($v->{'invoke-arg'}, $v);
+ }
+ }
+
+ foreach my $field (@fixedFields) {
+ $info->{$field} = code::formatTemplate($v->{$field}, $v) if ($v->{$field});
+ }
+
+ $needScope = 1 if $type->{'need-scope'};
+ $needFrame = 1 if $type->{'need-frame'};
+ $needAlloc = 1 if $type->{'need-alloc'};
+ $hasInstance = 1 if $type->{'is-instance'};
+ $trampScope = 1 if $type->{'trampoline-scope'};
+ }
+
+ $info->{'static'} = $hasInstance ? '' : 'static ';
+
+ # Handle default return types, others are handled by the fixedFields above
+ if ($s->{successcodes}) {
+ my @codes = split(/,/,$s->{successcodes});
+
+ $info->{'native-result-define'} = 'int result$;';
+ $info->{'native-result-assign'} = 'result$ = (int)';
+ $info->{'result-test'} = 'if ('.join("||", map { '(result$ == Vulkan.'.$_.')' } @codes).')';
+ $info->{'result-throw'} = 'throw new RuntimeException(Vulkan.getErrorMessage(result$));';
+
+ if ($#codes > 0 && $info->{'java-result'} eq 'void') {
+ $info->{'java-result'} = 'int';
+ $info->{'java-result-return'} = 'return result$;';
+ }
+ } elsif ($s->{proto}->{fullType} ne 'void') {
+ my $m = $s->{proto};
+ my $type = defined($override->{$m->{name}}) ? $override->{$m->{name}}->{type} : $types->{$m->{deref}.'-return'};
+
+ die "No type '$m->{deref}-return' ".Dumper($m, $s) if !defined($type);
+ die Dumper($m, $s) if !defined($type->{'java-result-return'});
+
+ my $v = buildVars($s, $m, $type);
+
+ $info->{'native-result-define'} = code::formatTemplate($v->{'native-result-define'}, $v);
+ $info->{'native-result-assign'} = code::formatTemplate($v->{'native-result-assign'}, $v);
+ #$info->{'native-result-define'}.= join("", map { "// $_\n" } split(/\n/, Dumper($m)));
+ $info->{'java-result'} = code::formatTemplate($v->{type}, $v);
+ $info->{'java-result-return'} = code::formatTemplate($v->{'java-result-return'}, $v);
+
+ $info->{'native-result'} = code::formatTemplate($v->{'carrier'}, $v);
+ $info->{'trampoline-result-define'} = code::formatTemplate($v->{'trampoline-result-define'}, $v);
+ $info->{'trampoline-result-assign'} = code::formatTemplate($v->{'trampoline-result-assign'}, $v);
+ $info->{'trampoline-result-return'} = code::formatTemplate($v->{'trampoline-result-return'}, $v);
+
+ $needScope = 1 if $type->{'need-scope'};
+ }
+
+ $info->{'create-frame'} = '(Frame frame$ = Frame.frame())' if $needFrame;
+ $info->{'trampoline-scope'} = '(ResourceScope scope$$ = ResourceScope.newConfinedScope())' if $trampScope;
+
+ push @{$info->{'java-arg'}}, 'SegmentAllocator alloc$' if $needAlloc;
+ push @{$info->{'java-arg'}}, 'ResourceScope scope$' if $needScope;
+
+ foreach my $field (@arrayFields) {
+ my $with = $field =~ m/-arg$/n ? ",\n\t" : "\n\t";
+ $info->{$field} = join $with, @{$info->{$field}};
+ }
+
+ $info->{successcodes} = $s->{successcodes} ? $s->{successcodes} : '';
+ $info->{errorcodes} = $s->{errorcodes} ? $s->{errorcodes}: '';
+
+ if ($s->{category} eq 'funcpointer') {
+ $info->{'trampoline-signature'} = formatSignature($s);
+ }
+
+ $info;
+}
+
+sub formatFunctionPointer {
+ my $vk = shift;
+ my $api = shift;
+ my $s = shift;
+ my $template = $commandTypes->{templates}->{'funcpointer-readwrite'};
+ my $info = collectFunctionInfo($api, $commandTypes, $s);
+
+ my $v = {
+ package => 'vulkan',
+ name => $s->{name},
+ Name => $s->{Name},
+ };
+
+ foreach my $k (keys %{$template->{insert}}) {
+ my $t = $template->{insert}->{$k};
+
+ $v->{$k} = code::formatTemplate($t, $info);
+ }
+
+ code::formatTemplateStream($template->{class}, $v);
+}
+
+sub formatFunctionDescriptor {
+ my $ct = shift;
+ my $s = shift;
+ my $types = $ct->{types};
+ my @fields = ();
+ my $void = $s->{proto}->{fullType} eq 'void';
+ my $override = $ct->{overrides}->{$s->{name}};
+
+ foreach my $m ($void ? () : $s->{proto}, @{$s->{items}}) {
+ my $deref = defined($override->{$m->{name}}) && defined($override->{$m->{name}}->{type}) ? $override->{$m->{name}}->{type} : $m->{deref};
+ my $type = $types->{$deref};
+
+ die "No type '$deref' found ".Dumper($m, $s, $override) if !$type;
+
+ my $v = buildVars($s, $m, $type);
+
+ push @fields, code::formatTemplate($v->{layout}, $v)." /* $m->{deref} $m->{name} */";
+ }
+
+ return ($void ? 'FunctionDescriptor.ofVoid(' : 'FunctionDescriptor.of(')
+ .join(",\n\t\t", @fields).')';
+}
+
+sub formatFunction {
+ my $api = shift;
+ my $ct = shift;
+ my $s = shift;
+ my $void = $s->{proto}->{fullType} eq 'void';
+ my $override = $ct->{overrides}->{$s->{name}};
+ my $tempname = $override->{template} ? $override->{template} : 'method';
+ my $template = $ct->{templates}->{$tempname};
+
+ my $info = collectFunctionInfo($api, $ct, $s);
+
+ #join("\n", map { '// '.$_ } split(/\n/,Dumper($s)))."\n".
+ " /* template: $tempname */\n".
+ code::formatTemplate($template->{invoke}, $info);
+}
--- /dev/null
+# -*- Mode:text; tab-width:4; electric-indent-mode: nil; indent-line-function:insert-tab; -*-
+
+# types for structs and unions
+
+# ###################################################################### #
+
+#accessor=code template
+# {type} - java type
+# {java-get}
+# {java-set}
+# {init}*
+# {init-array}*
+# {setall-arg}
+# {setall}
+
+# ###################################################################### #
+
+code value {
+ get {{
+ /* {deref} */
+ public {type} get{Name}() {
+ return {java-get};
+ }
+ }}
+ set {{
+ /* {deref} */
+ public void set{Name}({type} {name}) {
+ {java-set};
+ }
+ }}
+ getat {{
+ public {type} get{Name}AtIndex(long i$) {
+ return {java-getat};
+ }
+ }}
+ setat {{
+ public void set{Name}AtIndex(long i$, {type} {name}) {
+ {java-setat};
+ }
+ }}
+
+ # Initialise the sType field if it has one, also include sub-
+ init eval {{
+ #if ($tempname =~ m/write/) {
+ my $list = [ 'self$.segment', $s->{bitSize} / 8, "Vulkan.$m->{values}" ];
+
+ foreach my $x (@{$s->{items}}) {
+ if ($x->{deref} eq 'struct') {
+ my $y = $api->{types}->{$x->{baseType}};
+ if ($#{$y->{items}} >= 0 && $y->{items}->[0]->{values}) {
+ my $z = $y->{items}->[0];
+ push @$list, ($x->{bitOffset} + $z->{bitOffset}) / 8, "Vulkan.$z->{values}";
+ }
+ }
+ }
+
+ 'Vulkan.initType('.join(", ", @$list).');';
+ #} else {
+ # ''
+ #}
+ }}
+
+ # for complex constructors
+ #setall-arg {{ {type} {name} }}
+ setall-arg {{ {type} {name} }}
+ setall {{ self$.set{Name}({name}); }}
+ setallat {{ self$.set{Name}AtIndex(index$, {name}); }}
+}
+
+# ###################################################################### #
+
+code value-array {
+ getorset {{
+ /* value-array.getorset {deref} */
+ public {type} get{Name}() {
+ try {
+ return {java-get};
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+ public {typei} get{Name}Element(int i$) {
+ return {java-geti};
+ }
+ public void set{Name}Element(int i$, {typei} {name}) {
+ {java-seti};
+ }
+ }}
+
+ getat {{
+ /* value-array.getat {deref} */
+ public {type} get{Name}AtIndex(long i$) {
+ try {
+ return {java-getat};
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+ }}
+
+ setall-arg eval {{
+ if ($m->{len1} <= 4) {
+ join ", ", map { '{typei} {name}$'.$_ } (0 .. $m->{len1}-1);
+ } else {
+ "{typei}[] {name} /* $m->{deref} $m->{len1} */";
+ }
+ }}
+ setall eval {{
+ if ($m->{len1} <= 4) {
+ join "\n\t", map { "self\$.set{Name}Element($_, {name}\$$_);" } (0 .. $m->{len1}-1);
+ } else {
+ <<END;
+ if ({name} != null) {
+ try {
+ ((MemorySegment){name}\$SH.invokeExact(self\$.segment)).copyFrom(MemorySegment.ofArray({name}));
+ } catch (Throwable t) {
+ System.err.println("Copy error: " + t.getLocalizedMessage());
+ }
+ }
+END
+ }
+ }}
+}
+
+# ###################################################################### #
+# don't like having to pass scope here, not sure what else to do though
+code handle-array {
+ getorset {{
+ /* value-array {deref} */
+ public {type} get{Name}(VkInstance instance$, ResourceScope scope$) {
+ try {
+ return {java-get};
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+ public {typei} get{Name}Element(int i$, VkInstance instance$, ResourceScope scope$) {
+ return {java-geti};
+ }
+ public void set{Name}Element(int i$, {typei} {name}) {
+ {java-seti};
+ }
+ }}
+}
+
+# ###################################################################### #
+
+code value-array2d {
+ getorset {{
+ /* value-array2d {deref} */
+ public {type} get{Name}() {
+ try {
+ return {java-get};
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+ public {typei} get{Name}Element(int i$, int j$) {
+ return {java-geti};
+ }
+ public void set{Name}Element(int i$, int j$, {typei} {name}) {
+ {java-seti};
+ }
+ }}
+}
+
+# ###################################################################### #
+
+code inline {
+ getorset {{
+ /* inline {deref} */
+ public {type} get{Name}() {
+ try {
+ return {java-get};
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+ }}
+ getorsetat {{
+ /* inline {deref} */
+ public {type} get{Name}AtIndex(long i$) {
+ try {
+ return {java-getat};
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+ }}
+}
+
+# ###################################################################### #
+# inline type that we also want to include expanded in initialiser
+# We also create expanded setters and a getter for each simple embedded field.
+
+code inline-expand {
+
+ # These are basic object based accessors
+
+ getorset {{
+ /* inline {deref} */
+ public {type} get{Name}() {
+ try {
+ return {java-get};
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+ }}
+
+ getorsetat {{
+ /* inline {deref} */
+ public {type} get{Name}AtIndex(long i$) {
+ try {
+ return {java-getat};
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+ }}
+
+ # subroutine to the all-args info, only eval if len1 == 0
+ # this will also include it's own inline struct's fields
+ analyse-args eval {{
+ use integer;
+ my $list = [];
+
+ foreach my $a (@{$api->{data}->{$m->{baseType}}->{items}}) {
+ my $name = "$m->{name}\$$a->{name}";
+ my $offset = ($m->{bitOffset} + $a->{bitOffset}) / 8;
+ my $atype = $primitiveMap{$a->{baseType}};
+
+ if ($atype) {
+ push @$list, {
+ name=> $name,
+ type => $atype,
+ offset => $offset,
+ };
+ } else {
+ my $as = $api->{data}->{$a->{baseType}};
+ if ($as->{category} eq 'struct') {
+ foreach my $b (@{$as->{items}}) {
+ my $btype = $primitiveMap{$b->{baseType}};
+ if ($btype) {
+ push @$list, {
+ name => "$name\$$b->{name}",
+ type => $btype,
+ offset => $offset + $b->{bitOffset} / 8
+ };
+ }
+ }
+ } elsif ($as->{category} eq 'enum') {
+ $atype = $primitiveMap{$as->{fullType}};
+ if ($atype) {
+ push @$list, {
+ name=> $name,
+ type => $atype,
+ offset => $offset,
+ };
+ }
+ }
+ }
+ }
+ $list;
+ }}
+
+ # setBlah(all-simple-blah-fields)
+ set eval {{
+ return 0 if $m->{len1};
+ my $setall_arg = eval($type->{accessor}->{'setall-arg'});
+ my $setall = eval($type->{accessor}->{setall});
+ <<END;
+ public void set{Name}($setall_arg) {
+ var self\$ = this;
+ $setall
+ }
+END
+ }}
+
+ # getBlah$field0(), getBlah$field1() etc.
+ get eval {{
+ die if ($m->{len1});
+
+ return 0 if $m->{len1};
+
+ my $list = eval($type->{accessor}->{'analyse-args'}); die "$@" if !defined $list;
+
+ join("\n", map {
+ my $tname = uc($_->{type});
+ my $fname = ucfirst($_->{name});
+ <<END;
+ public $_->{type} get$fname() {
+ return this.segment.get(Memory.$tname, $_->{offset});
+ }
+END
+ } @$list);
+ }}
+
+ # setBlahAtIndex(index, all-simple-blah-fields)
+ setat eval {{
+ return 0 if $m->{len1};
+ my $setall_arg = eval($type->{accessor}->{'setall-arg'});
+ my $setallat = eval($type->{accessor}->{setallat});
+ <<END;
+ public void set{Name}AtIndex(long index\$, $setall_arg) {
+ var self\$ = this;
+ $setallat
+ }
+END
+ }}
+
+ # create arg-list for setall template
+ setall-arg eval {{
+ return 0 if $m->{len1};
+
+ my $list = eval($type->{accessor}->{'analyse-args'}); die "$@" if !defined $list;
+
+ join(', ', map { "$_->{type} $_->{name}" } @$list);
+ }}
+
+ setall eval {{
+ return 0 if $m->{len1};
+
+ my $list = eval($type->{accessor}->{'analyse-args'}); die "$@" if !defined $list;
+
+ join("\n\t", map { 'self$.segment.set(Memory.'.uc($_->{type}).", $_->{offset}, $_->{name});" } @$list);
+ }}
+
+ setallat eval {{
+ use integer;
+
+ return 0 if $m->{len1};
+
+ my $list = eval($type->{accessor}->{'analyse-args'}); die "$@" if !defined $list;
+ my $stride = $s->{bitSize} / 8;
+
+ join("\n\t", map { 'self$.segment.set(Memory.'.uc($_->{type}).", index\$ * $stride + $_->{offset}, $_->{name});" } @$list);
+ }}
+}
+
+# ###################################################################### #
+
+# value with a SegmentAllocator passed to set()
+code value-alloc value {
+ set {{
+ /* {deref} */
+ public void set{Name}({type} {name}, SegmentAllocator alloc$) {
+ {java-set};
+ }
+ }}
+ setat {{
+ /* {deref} */
+ public void set{Name}AtIndex(long i$, {type} {name}, SegmentAllocator alloc$) {
+ {java-setat};
+ }
+ }}
+
+ setall {{ self$.set{Name}({name}, alloc$); }}
+ setallat {{ self$.set{Name}AtIndex(index$, {name}, alloc$); }}
+}
+
+# ###################################################################### #
+
+code Vulkan {
+ class {{
+ package {package};
+
+ import au.notzed.nativez.Memory;
+ import jdk.incubator.foreign.MemorySegment;
+ import java.util.Arrays;
+
+ public class Vulkan {
+
+ public static int VK_MAKE_API_VERSION(int variant, int major, int minor, int patch) {
+ return (variant << 29) | (major << 22) | (minor << 12) | patch;
+ }
+
+ /** Init stype fields of an object or array */
+ static void initType(MemorySegment segment, long size, int stype) {
+ for (long o = 0; o < segment.byteSize(); o += size)
+ segment.set(Memory.INT, o, stype);
+ }
+
+ /** Init stype fields of an object or an array with an embedded typed struct */
+ static void initType(MemorySegment segment, long size, int stype, int off1, int stype1) {
+ for (long o = 0; o < segment.byteSize(); o += size) {
+ segment.set(Memory.INT, o, stype);
+ segment.set(Memory.INT, o+off1, stype1);
+ }
+ }
+
+ static record ErrorInfo(int id, String name) {}
+
+ public static String getErrorMessage(int errorid) {
+ ErrorInfo q = new ErrorInfo(errorid, null);
+ int i = Arrays.binarySearch(errors, q, (a, b) -> a.id - b.id);
+
+ return i >= 0 ? errors[i].name : "Unknown Error";
+ }
+
+ {defines}
+
+ {constants}
+ }
+ }}
+ VK_API_VERSION_1_0 {{ public final static int VK_API_VERSION_1_0 = VK_MAKE_API_VERSION(0, 1, 0, 0); }}
+ VK_API_VERSION_1_1 {{ public final static int VK_API_VERSION_1_1 = VK_MAKE_API_VERSION(0, 1, 1, 0); }}
+ VK_API_VERSION_1_2 {{ public final static int VK_API_VERSION_1_2 = VK_MAKE_API_VERSION(0, 1, 2, 0); }}
+ VK_API_VERSION_1_3 {{ public final static int VK_API_VERSION_1_3 = VK_MAKE_API_VERSION(0, 1, 3, 0); }}
+}
+
+code dispatch {
+ class {{
+ // template: dispatch:class
+ package {package};
+ import jdk.incubator.foreign.*;
+ import java.lang.invoke.*;
+ import au.notzed.nativez.*;
+ class {Name} {
+
+ {field-init}
+
+ {Name}(VkInstance instance$, ResourceScope scope$) {
+ {init}
+ }
+ }
+ }}
+ field-init {{ final NativeSymbol {name}$NS; }}
+ init {{ {name}$NS = instance$.vkGetInstanceProcAddr("{name}", scope$); }}
+
+}
+
+# non-dispatchable handle
+code handle {
+ class {{
+ // template: handle:class
+ package {package};
+ import jdk.incubator.foreign.*;
+ import java.lang.invoke.*;
+ import au.notzed.nativez.*;
+
+ public class {name} implements Pointer {
+ final NativeSymbol self;
+
+ private {name}(MemoryAddress address, ResourceScope scope) {
+ this.self = NativeSymbol.ofAddress("{name}", address, scope);
+ {init}
+ }
+
+ public static {name} create(MemoryAddress address, ResourceScope scope) {
+ return address != MemoryAddress.NULL ? new {name}(address, scope) : null;
+ }
+
+ /** Allocate an array where the handle scope is independent of the array allocation */
+ public static HandleArray<{name}> createArray(long length, SegmentAllocator alloc, ResourceScope scope$) {
+ return HandleArray.createArray(length, alloc, (a, s) -> create(a, scope$));
+ }
+
+ /** Allocate an array where the handle scope matches the array allocation */
+ public static HandleArray<{name}> createArray(long length, SegmentAllocator alloc) {
+ return HandleArray.createArray(length, alloc, {name}::create);
+ }
+
+ public MemoryAddress address() {
+ return self.address();
+ }
+
+ public ResourceScope scope() {
+ return self.scope();
+ }
+
+ public String toString() {
+ return String.format("[%s %016x]", getClass().getSimpleName(), self.address().toRawLongValue());
+ }
+ }
+ }}
+}
+
+# VkInstance
+code handle-instance {
+ class {{
+ // template: handle-instance:class
+ package {package};
+ import jdk.incubator.foreign.*;
+ import java.lang.invoke.*;
+ import au.notzed.nativez.*;
+
+ public class {name} implements Pointer {
+ final NativeSymbol self;
+ final DispatchInstance dispatch;
+
+ private {name}(MemoryAddress address, ResourceScope scope) {
+ this.self = NativeSymbol.ofAddress("{name}", address, scope);
+ this.dispatch = new DispatchInstance(this, scope);
+ {init}
+ }
+
+ public static {name} create(MemoryAddress address, ResourceScope scope) {
+ return new {name}(address, scope);
+ }
+
+ public MemoryAddress address() {
+ return self.address();
+ }
+
+ public ResourceScope scope() {
+ return self.scope();
+ }
+
+ {commands}
+ }
+ }}
+}
+
+# dispatchable handle
+code handle-dispatch {
+ class {{
+ // template: handle-dispatch:class
+ package {package};
+ import jdk.incubator.foreign.*;
+ import java.lang.invoke.*;
+ import au.notzed.nativez.*;
+
+ public class {name} implements Pointer {
+ final NativeSymbol self;
+ final DispatchInstance dispatch;
+
+ private {name}(MemoryAddress address, DispatchInstance dispatch, ResourceScope scope) {
+ this.self = NativeSymbol.ofAddress("{name}", address, scope);
+ this.dispatch = dispatch;
+ {init}
+ }
+
+ public static {name} create(MemoryAddress address, DispatchInstance dispatch, ResourceScope scope) {
+ return new {name}(address, dispatch, scope);
+ }
+
+ // TODO: evaluate how scope fits here
+ public static HandleArray<{name}> createArray(long length, SegmentAllocator alloc, DispatchInstance dispatch, ResourceScope scope) {
+ return HandleArray.createArray(length, alloc, (a, s) -> create(a, dispatch, s), scope);
+ }
+
+ public static HandleArray<{name}> createArray(long length, SegmentAllocator alloc, VkInstance instance, ResourceScope scope) {
+ return HandleArray.createArray(length, alloc, (a, s) -> create(a, instance.dispatch, s), scope);
+ }
+
+ public MemoryAddress address() {
+ return self.address();
+ }
+
+ public ResourceScope scope() {
+ return self.scope();
+ }
+
+ {commands}
+
+ {append}
+ }
+ }}
+}
+
+# ###################################################################### #
+
+# shared struct components
+code struct {
+ header {{
+ public MemorySegment segment;
+
+ public static final GroupLayout LAYOUT = {layout};
+
+ private {Name}(MemorySegment segment) {
+ this.segment = segment;
+ }
+
+ public static {Name} create(MemorySegment segment) {
+ return new {Name}(segment);
+ }
+
+ public static {Name} create(MemoryAddress address, ResourceScope scope) {
+ return create(MemorySegment.ofAddress(address, LAYOUT.byteSize(), scope));
+ }
+
+ public static {Name} create(SegmentAllocator alloc) {
+ var self$ = create(alloc.allocate(LAYOUT));
+ init(self$);
+ return self$;
+ }
+
+ private static void init({Name} self$) {
+ {init}
+ }
+
+ public void reset() {
+ segment.fill((byte)0);
+ init(this);
+ }
+
+ // Pointer
+ @Override
+ public MemoryAddress address() {
+ return segment.address();
+ }
+
+ // Pointer
+ @Override
+ public ResourceScope scope() {
+ return segment.scope();
+ }
+
+ @Override
+ public String toString() {
+ return Memory.toString(segment, LAYOUT);
+ }
+ }}
+ create-all {{
+ public static {Name} {create}({java-setall-arguments}, SegmentAllocator alloc$) {
+ {Name} self$ = create(alloc$);
+
+ {java-setall}
+
+ return self$;
+ }
+ }}
+ set-all {{
+ public void {set}({java-setall-arguments}, SegmentAllocator alloc$) {
+ {Name} self$ = this;
+
+ {java-setall}
+ }
+ }}
+ setat-all {{
+ public void {set}AtIndex(long index$, {java-setall-arguments}, SegmentAllocator alloc$) {
+ {Name} self$ = this;
+
+ {java-setallat}
+ }
+ }}
+ array {{
+ static {Name} createArray(MemoryAddress addr, long length, ResourceScope scope) {
+ return create(MemorySegment.ofAddress(addr, length * LAYOUT.byteSize(), scope));
+ }
+
+ public static {Name} createArray(long length, SegmentAllocator alloc) {
+ var self$ = create(alloc.allocateArray(LAYOUT, length));
+ init(self$);
+ return self$;
+ }
+
+ public final static MethodHandle LAYOUT$SH = MemoryLayout.sequenceLayout(LAYOUT).sliceHandle(MemoryLayout.PathElement.sequenceElement());
+
+ // Array
+ @Override
+ public long length() {
+ return segment.byteSize() / LAYOUT.byteSize();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return segment.byteSize() == 0;
+ }
+
+ @Override
+ public {Name} getAtIndex(long index$) {
+ try {
+ return create((MemorySegment)LAYOUT$SH.invokeExact(this.segment, index$));
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+ }}
+}
+
+# default - writeonly struct
+code struct-writeonly insert=struct:header,struct:create-all
+ fields=init,set,getorset,handle,java-setall {
+ class {{
+ // template: struct-writeonly:class
+ package {package};
+ import jdk.incubator.foreign.*;
+ import java.lang.invoke.*;
+ import au.notzed.nativez.*;
+
+ public class {Name} implements Pointer {
+ {header}
+
+ {create-all}
+
+ {set}
+ {getorset}
+
+ {handle}
+ }
+ }}
+}
+
+code struct-writeonly-array insert=struct:header,struct:create-all,struct:array
+ fields=init,set,getorset,setat,getorsetat,handle,handleat,java-setall {
+ class {{
+ // template: struct-writeonly-array:class
+ package {package};
+ import jdk.incubator.foreign.*;
+ import java.lang.invoke.*;
+ import au.notzed.nativez.*;
+
+ public class {Name} implements Pointer, Array<{Name}> {
+ {header}
+ {array}
+
+ {create-all}
+
+ {set}
+ {getorset}
+
+ {setat}
+ {getorsetat}
+
+ {handle}
+ {handleat}
+
+ {append}
+ }
+ }}
+}
+
+code struct-readonly insert=struct:header
+ fields=init,get,getorset,handle {
+ class {{
+ // template: struct-readonly:class
+ package {package};
+ import jdk.incubator.foreign.*;
+ import java.lang.invoke.*;
+ import au.notzed.nativez.*;
+
+ public class {Name} implements Pointer {
+ {header}
+
+ {get}
+ {getorset}
+
+ {handle}
+
+ {append}
+ }
+ }}
+}
+
+code struct-readonly-array insert=struct:header,struct:array
+ fields=init,get,getorset,getat,getorsetat,handle,handleat {
+ class {{
+ // template: struct-readonly-array:class
+ package {package};
+ import jdk.incubator.foreign.*;
+ import java.lang.invoke.*;
+ import au.notzed.nativez.*;
+
+ public class {Name} implements Pointer, Array<{Name}> {
+ {header}
+ {array}
+
+ {get}
+ {getorset}
+
+ {getat}
+ {getorsetat}
+
+ {handle}
+ {handleat}
+
+ {append}
+ }
+ }}
+}
+
+code struct-readwrite insert=struct:header,struct:create-all
+ fields=init,get,set,getorset,handle,java-setall {
+ class {{
+ // template: struct-readwrite:class
+ package {package};
+ import jdk.incubator.foreign.*;
+ import java.lang.invoke.*;
+ import au.notzed.nativez.*;
+
+ public class {Name} implements Pointer {
+ {header}
+
+ {create-all}
+
+ {get}
+ {set}
+ {getorset}
+
+ {handle}
+
+ {append}
+ }
+ }}
+}
+
+code struct-readwrite-array insert=struct:header,struct:create-all,struct:array
+ fields=init,get,getat,set,setat,getorset,getorsetat,handle,handleat,java-setall {
+ class {{
+ // template: struct-readwrite-array:class
+ package {package};
+ import jdk.incubator.foreign.*;
+ import java.lang.invoke.*;
+ import au.notzed.nativez.*;
+
+ public class {Name} implements Pointer,Array<{Name}> {
+ {header}
+ {array}
+
+ {create-all}
+
+ {get}
+ {set}
+ {getorset}
+
+ {getat}
+ {setat}
+ {getorsetat}
+
+ {handle}
+ {handleat}
+
+ {append}
+ }
+ }}
+}
+
+# read-write with a 'set' method for all members
+code struct-readwrite-all insert=struct:header,struct:create-all,struct:set-all
+ fields=init,get,set,getorset,handle,java-setall {
+ class {{
+ // template: struct-readwrite-all:class
+ package {package};
+ import jdk.incubator.foreign.*;
+ import java.lang.invoke.*;
+ import au.notzed.nativez.*;
+
+ public class {Name} implements Pointer {
+ {header}
+
+ {create-all}
+
+ {get}
+ {set}
+ {getorset}
+
+ {handle}
+
+ {append}
+ }
+ }}
+}
+
+code struct-readwrite-array-all insert=struct:header,struct:create-all,struct:array,struct:set-all,struct:setat-all
+ fields=init,get,getat,set,setat,setallat,getorset,getorsetat,handle,handleat,java-setall,java-setallat {
+ class {{
+ // template: struct-readwrite-array-all:class
+ package {package};
+ import jdk.incubator.foreign.*;
+ import java.lang.invoke.*;
+ import au.notzed.nativez.*;
+
+ public class {Name} implements Pointer,Array<{Name}> {
+ {header}
+ {array}
+
+ {create-all}
+
+ {get}
+ {set}
+ {getorset}
+
+ {getat}
+ {setat}
+ {getorsetat}
+
+ {handle}
+ {handleat}
+ }
+ }}
+}
+
+code struct-writeonly-array-all insert=struct:header,struct:create-all,struct:array,struct:set-all,struct:setat-all
+ fields=init,set,setat,setallat,getorset,getorsetat,handle,handleat,java-setall,java-setallat {
+ class {{
+ // template: struct-writeonly-array-all:class
+ package {package};
+ import jdk.incubator.foreign.*;
+ import java.lang.invoke.*;
+ import au.notzed.nativez.*;
+
+ public class {Name} implements Pointer, Array<{Name}> {
+ {header}
+ {array}
+
+ {create-all}
+
+ {set}
+ {getorset}
+
+ {setat}
+ {getorsetat}
+
+ {handle}
+ {handleat}
+ }
+ }}
+}
+
+# ###################################################################### #
+
+# Basic value-based accessor
+type value accessor=value {
+ native-value {{ {name} }}
+
+ native-get {{ ({type}){name}$VH.get(this.segment) }}
+ handle {{ final static VarHandle {name}$VH = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("{name}")); }}
+
+ java-get {{ {native-get} }}
+ java-set {{ {name}$VH.set(this.segment, {native-value}) }}
+
+ native-getat {{ ({type}){name}$AH.get(this.segment, i$) }}
+ native-setat {{ {name}$AH.set(this.segment, i$, {native-value}) }}
+ handleat {{ final static VarHandle {name}$AH = MemoryLayout.sequenceLayout(LAYOUT).varHandle(MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.groupElement("{name}")); }}
+
+ java-getat {{ {native-getat} }}
+ java-setat {{ {native-setat} }}
+}
+
+type value-array accessor=value-array {
+ native-get {{ (MemorySegment){name}$SH.invokeExact(this.segment) }}
+ java-get {{ {type}.create({native-get}) }}
+
+ native-geti {{ {name}$EH.get(this.segment, i$) }}
+
+ java-geti {{ ({typei}){native-geti} }}
+ java-seti {{ {name}$EH.set(this.segment, i$, {name}) }}
+ handle {{
+ final static MethodHandle {name}$SH = LAYOUT.sliceHandle(MemoryLayout.PathElement.groupElement("{name}"));
+ final static VarHandle {name}$EH = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("{name}"), MemoryLayout.PathElement.sequenceElement());
+ }}
+
+ native-getat {{ (MemorySegment){name}$AH.invokeExact(this.segment, i$) }}
+ handleat {{
+ final static MethodHandle {name}$AH = MemoryLayout.sequenceLayout(LAYOUT).sliceHandle(MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.groupElement("{name}"));
+ }}
+ java-getat {{ {type}.create({native-getat}) }}
+}
+
+type value-array2d accessor=value-array2d {
+ native-get {{ (MemorySegment){name}$SH.invokeExact(this.segment) }}
+ java-get {{ {type}.create({native-get}) }}
+ java-geti {{ ({typei}){name}$EH.get(this.segment, i$, j$) }}
+ java-seti {{ {name}$EH.set(this.segment, i$, j$, {name}) }}
+ handle {{
+ final static MethodHandle {name}$SH = LAYOUT.sliceHandle(MemoryLayout.PathElement.groupElement("{name}"));
+ final static VarHandle {name}$EH = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("{name}"), MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.sequenceElement());
+ }}
+}
+
+type inline accessor=inline {
+ native-get {{ (MemorySegment){name}$SH.invokeExact(this.segment) }}
+ java-get {{ {type}.create({native-get}) }}
+ handle {{ final static MethodHandle {name}$SH = LAYOUT.sliceHandle(MemoryLayout.PathElement.groupElement("{name}")); }}
+
+ native-getat {{ (MemorySegment){name}$SA.invokeExact(this.segment, i$) }}
+ java-getat {{ {type}.create({native-getat}) }}
+ handleat {{ final static MethodHandle {name}$SA = MemoryLayout.sequenceLayout(LAYOUT).sliceHandle(MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.groupElement("{name}")); }}
+}
+
+type inline-array accessor=inline {
+ native-get {{ (MemorySegment){name}$SH.invokeExact(this.segment) }}
+ java-get {{ {type}.create({native-get}) }}
+ handle {{ final static MethodHandle {name}$SH = LAYOUT.sliceHandle(MemoryLayout.PathElement.groupElement("{name}")); }}
+
+ native-getat {{ (MemorySegment){name}$SA.invokeExact(this.segment, i$) }}
+ java-getat {{ {type}.create({native-getat}) }}
+ handleat {{ final static MethodHandle {name}$SA = MemoryLayout.sequenceLayout(LAYOUT).sliceHandle(MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.groupElement("{name}")); }}
+}
+
+type uint8_t,char value {
+ type {{ byte }}
+ layout {{ Memory.BYTE }}
+}
+
+type uint16_t value {
+ type {{ short }}
+ layout {{ Memory.SHORT }}
+}
+
+type uint32_t,int,int32_t value {
+ type {{ int }}
+ layout {{ Memory.INT }}
+}
+
+type uint64_t,int64_t,size_t value {
+ type {{ long }}
+ layout {{ Memory.LONG }}
+}
+
+type float value {
+ type {{ float }}
+ layout {{ Memory.FLOAT }}
+}
+
+type double value {
+ type {{ double }}
+ layout {{ Memory.DOUBLE }}
+}
+
+# ###################################################################### #
+
+type uint8_t[] value-array {
+ type {{ ByteArray }}
+ layout {{ MemoryLayout.sequenceLayout({len1}, Memory.BYTE) }}
+ typei {{ byte }}
+}
+
+# these are always embedded 0-terminated strings, so don't treat as array
+type char[] inline {
+ type {{ String }}
+ layout {{ MemoryLayout.sequenceLayout({len1}, Memory.BYTE) }}
+
+ java-get {{ ({native-get}).getUtf8String(0L) }}
+ java-getat {{ ({native-getat}).getUtf8String(0L) }}
+}
+
+type uint32_t[],int32_t[] value-array {
+ type {{ IntArray }}
+ layout {{ MemoryLayout.sequenceLayout({len1}, Memory.INT) }}
+ typei {{ int }}
+}
+
+type uint64_t[] value-array {
+ type {{ LongArray }}
+ layout {{ MemoryLayout.sequenceLayout({len1}, Memory.LONG) }}
+ typei {{ long }}
+}
+
+type float[] value-array {
+ type {{ FloatArray }}
+ layout {{ MemoryLayout.sequenceLayout({len1}, Memory.FLOAT) }}
+ typei {{ float }}
+}
+
+type struct[] inline-array {
+ type {{ {baseType} }}
+ layout {{ MemoryLayout.sequenceLayout({len1}, {baseType}.LAYOUT) }}
+}
+
+type struct-expand[] struct[] accessor=inline-expand;
+
+type float[][] value-array2d {
+ type {{ FloatArray }}
+ typei {{ float }}
+ layout {{ MemoryLayout.sequenceLayout({len1}, MemoryLayout.sequenceLayout({len2}, Memory.FLOAT)) }}
+}
+
+# select=len? or what?
+
+type pointer value {
+ layout {{ Memory.POINTER }}
+ type {{ MemoryAddress }}
+
+ native-value {{ Memory.address({name}) }}
+ native-get {{ (MemoryAddress){name}$VH.get(this.segment) }}
+
+# java-get {{ {native-get} }}
+# java-set {{ {name}$VH.set(this.segment, Memory.address({name})) }}
+}
+
+type void* pointer;
+
+type value-pointer pointer {
+ java-get {{ {type}.create((MemoryAddress){name}$VH.get(this.segment), segment.scope()) }}
+}
+
+type uint8_t* value-pointer {
+ type ByteArray;
+}
+
+type uint32_t*,int32_t*,int* value-pointer {
+ type IntArray;
+}
+
+type uint64_t* value-pointer {
+ type LongArray;
+}
+
+type float* value-pointer {
+ type FloatArray;
+}
+
+type size_t* value-pointer {
+ type LongArray;
+}
+
+type pointer-length pointer {
+ java-get {{ {type}.createArray({native-get}, {length}, this.segment.scope()) }}
+}
+
+type void*-length pointer-length {
+ type MemorySegment;
+ java-get {{ MemorySegment.ofAddress({native-get}, {length}, this.segment.scope()) }}
+}
+
+type uint8_t*-length pointer-length {
+ type ByteArray;
+}
+
+type uint32_t*-length,int32_t*-length pointer-length {
+ type IntArray;
+}
+
+type uint64_t*-length pointer-length {
+ type LongArray;
+}
+
+type float*-length pointer-length {
+ type FloatArray;
+}
+
+# special handling for strings, will fail if it isn't
+type char* pointer accessor=value-alloc need-alloc {
+ type {{ String }}
+
+ java-get {{ ({native-get}).getUtf8String(0) }}
+ native-value {{ Memory.copyString({name}, alloc$).address() }}
+
+ # this just verifies it's a string type
+ length eval {{
+ if ($v->{len} =~ m/null-terminated/) {
+ 1;
+ } else {
+ die Dumper($v, $s);
+ }
+ }}
+
+}
+
+type char**-length pointer-length accessor=value-alloc {
+ type {{ String[] }}
+
+ java-set {{ {name}$VH.set(this.segment, Memory.copyStringArray({name}, alloc$).address()); }}
+ java-get {{ Memory.copyStringArray((MemoryAddress){name}$VH.get(this.segment), {length}) }}
+}
+
+type funcpointer pointer {
+ type {{ FunctionPointer<{baseType}> }}
+ typei {{ {baseType} }}
+ java-get {{ {baseType}.downcall({native-get}, this.segment.scope()) }}
+}
+
+type void** pointer {
+}
+
+type void**-length pointer-length {
+ type PointerArray;
+}
+
+type handle pointer {
+ type {{ {baseType} }}
+ java-get {{ {type}.create({native-get}, this.segment.scope()) }}
+}
+
+type handle[] value-array accessor=handle-array {
+ type {{ HandleArray<{typei}> }}
+ typei {{ {baseType} }}
+ layout {{ MemoryLayout.sequenceLayout({len1}, Memory.POINTER) }}
+ java-get {{ HandleArray.create({native-get}, (a, s) -> {typei}.create(a, instance$.dispatch, s), scope$) }}
+
+ java-geti {{ {typei}.create((MemoryAddress){native-geti}, instance$.dispatch, scope$) }}
+}
+
+type handle* pointer {
+ type {{ HandleArray<{typei}> }}
+ typei {{ {baseType} }}
+ java-get {{ HandleArray.create({native-get}, {typei}::create) }}
+}
+
+type handle*-length pointer-length {
+ type {{ HandleArray<{baseType}> }}
+ typei {{ {baseType} }}
+ java-get {{ HandleArray.createArray({native-get}, {length}, {typei}::create, this.segment.scope()) }}
+ java-set {{ {name}$VH.set(this.segment, Memory.address({name})); }}
+}
+
+type struct inline {
+ type {{ {baseType} }}
+ layout {{ {baseType}.LAYOUT }}
+}
+
+type struct-expand inline accessor=inline-expand {
+ type {{ {baseType} }}
+ layout {{ {baseType}.LAYOUT }}
+}
+
+type struct* pointer {
+ type {{ {baseType} }}
+ java-get {{ {baseType}.create({native-get}, this.segment.scope()) }}
+}
+
+type struct*-length pointer-length {
+ type {{ {baseType} }}
+ typei {{ {baseType} }}
+}
+
+type struct** pointer {
+}
+
+# xlib
+type XID,Window,VisualID uint64_t;
+
+type Display* handle {
+ type xlib.XDisplay;
+}
+
+# xcb
+type xcb_window_t uint32_t;
+type xcb_visualid_t uint32_t;
+type xcb_connection_t* handle {
+ type xcb.Connection;
+}
+
+override structs {
+ VkInstance template=handle-instance;
+ VkPhysicalDevice template=handle-dispatch;
+ VkDevice template=handle-dispatch append {{
+ public HandleArray<VkPipeline> vkCreateGraphicsPipelines(
+ VkPipelineCache pipelineCache,
+ VkGraphicsPipelineCreateInfo pCreateInfos,
+ SegmentAllocator alloc$,
+ ResourceScope scope$) {
+ HandleArray<VkPipeline> pPipelines = VkPipeline.createArray(pCreateInfos.length(), alloc$, scope$);
+ vkCreateGraphicsPipelines(pipelineCache, (int)pCreateInfos.length(), pCreateInfos, pPipelines);
+ // Vulkan.VK_PIPELINE_COMPILE_REQUIRED_EXT ??
+ return pPipelines;
+ }
+
+ public VkPipeline vkCreateGraphicsPipeline(
+ VkPipelineCache pipelineCache,
+ VkGraphicsPipelineCreateInfo pCreateInfo,
+ ResourceScope scope) {
+ try (Frame alloc$ = Frame.frame()) {
+ HandleArray<VkPipeline> pPipelines = VkPipeline.createArray(1, alloc$, scope);
+ vkCreateGraphicsPipelines(pipelineCache, 1, pCreateInfo, pPipelines);
+ // Vulkan.VK_PIPELINE_COMPILE_REQUIRED_EXT ??
+ return pPipelines.get(0);
+ }
+ }
+
+ public HandleArray<VkCommandBuffer> vkAllocateCommandBuffers(
+ VkCommandBufferAllocateInfo pAllocateInfo,
+ SegmentAllocator alloc$,
+ ResourceScope scope$) {
+
+ var buffers = VkCommandBuffer.createArray(
+ (int)VkCommandBufferAllocateInfo.commandBufferCount$VH.get(pAllocateInfo.segment),
+ alloc$, dispatch, scope$);
+
+ vkAllocateCommandBuffers(pAllocateInfo, buffers);
+
+ return buffers;
+ }
+
+ public HandleArray<VkDescriptorSet> vkAllocateDescriptorSets(
+ VkDescriptorSetAllocateInfo pAllocateInfo,
+ SegmentAllocator alloc$,
+ ResourceScope scope) {
+
+ var buffers = VkDescriptorSet.createArray(
+ (int)VkDescriptorSetAllocateInfo.descriptorSetCount$VH.get(pAllocateInfo.segment),
+ alloc$, scope);
+
+ vkAllocateDescriptorSets(pAllocateInfo, buffers);
+
+ return buffers;
+ }
+
+ }}
+ VkCommandBuffer template=handle-dispatch;
+ VkQueue template=handle-dispatch;
+
+ VkAllocationCallbacks ignore;
+
+ # We want 'set(all fields) for these types and to include them expanded if inline
+ VkOffset2D expand template=struct-readwrite-array-all;
+ VkOffset3D expand template=struct-readwrite-array-all;
+ VkExtent2D expand template=struct-readwrite-all;
+ VkExtent3D expand template=struct-readwrite-all;
+ VkRect2D expand template=struct-readwrite-array-all;
+
+ VkStencilOpState template=struct-readwrite-all;
+ VkComponentMapping expand template=struct-readwrite-all;
+ VkImageSubresourceRange expand template=struct-readwrite-all;
+
+ # probably just want writeonly? here
+ VkClearColorValue expand template=struct-readwrite-all;
+ VkClearDepthStencilValue expand template=struct-readwrite-all;
+
+ # Yikes, is all this really worth it?
+ VkClearValue template=struct-writeonly-array append {{
+ public static VkClearValue createColour(float r, float g, float b, float a, SegmentAllocator alloc) {
+ var self = create(alloc);
+
+ VkClearColorValue.float32$EH.set(self.segment, 0, r);
+ VkClearColorValue.float32$EH.set(self.segment, 1, g);
+ VkClearColorValue.float32$EH.set(self.segment, 2, b);
+ VkClearColorValue.float32$EH.set(self.segment, 3, a);
+
+ return self;
+ }
+ public static VkClearValue createColour(int r, int g, int b, int a, SegmentAllocator alloc) {
+ var self = create(alloc);
+
+ VkClearColorValue.int32$EH.set(self.segment, 0, r);
+ VkClearColorValue.int32$EH.set(self.segment, 1, g);
+ VkClearColorValue.int32$EH.set(self.segment, 2, b);
+ VkClearColorValue.int32$EH.set(self.segment, 3, a);
+
+ return self;
+ }
+ public static VkClearValue createDepthStencil(float depth, int stencil, SegmentAllocator alloc) {
+ var self = create(alloc);
+
+ VkClearDepthStencilValue.depth$VH.set(self.segment, depth);
+ VkClearDepthStencilValue.stencil$VH.set(self.segment, stencil);
+
+ return self;
+ }
+
+ final static VarHandle colour$float32$EH = MemoryLayout.sequenceLayout(LAYOUT).varHandle(
+ MemoryLayout.PathElement.sequenceElement(),
+ MemoryLayout.PathElement.groupElement("color"),
+ MemoryLayout.PathElement.groupElement("float32"),
+ MemoryLayout.PathElement.sequenceElement());
+
+ final static VarHandle colour$int32$EH = MemoryLayout.sequenceLayout(LAYOUT).varHandle(
+ MemoryLayout.PathElement.sequenceElement(),
+ MemoryLayout.PathElement.groupElement("color"),
+ MemoryLayout.PathElement.groupElement("int32"),
+ MemoryLayout.PathElement.sequenceElement());
+
+ public void setColourAtIndex(int index, float r, float g, float b, float a) {
+ colour$float32$EH.set(segment, index, 0, r);
+ colour$float32$EH.set(segment, index, 1, g);
+ colour$float32$EH.set(segment, index, 2, b);
+ colour$float32$EH.set(segment, index, 3, a);
+ }
+ public void setColourAtIndex(int index, int r, int g, int b, int a) {
+ colour$int32$EH.set(segment, index, 0, r);
+ colour$int32$EH.set(segment, index, 1, g);
+ colour$int32$EH.set(segment, index, 2, b);
+ colour$int32$EH.set(segment, index, 3, a);
+ }
+
+ final static VarHandle depthStencil$depth$EH = MemoryLayout.sequenceLayout(LAYOUT).varHandle(
+ MemoryLayout.PathElement.sequenceElement(),
+ MemoryLayout.PathElement.groupElement("depthStencil"),
+ MemoryLayout.PathElement.groupElement("depth"));
+
+ final static VarHandle depthStencil$stencil$EH = MemoryLayout.sequenceLayout(LAYOUT).varHandle(
+ MemoryLayout.PathElement.sequenceElement(),
+ MemoryLayout.PathElement.groupElement("depthStencil"),
+ MemoryLayout.PathElement.groupElement("stencil"));
+
+ public void setDepthStencilAtIndex(int index, float depth, int stencil) {
+ depthStencil$depth$EH.set(segment, index, depth);
+ depthStencil$stencil$EH.set(segment, index, stencil);
+ }
+
+ }}
+
+ VkMemoryType template=struct-readonly-array;
+ VkMemoryHeap template=struct-readonly-array;
+ VkPhysicalDeviceMemoryProperties template=struct-readonly append {{
+
+ final static VarHandle memoryTypes$propertyFlags$EH = LAYOUT.varHandle(
+ MemoryLayout.PathElement.groupElement("memoryTypes"),
+ MemoryLayout.PathElement.sequenceElement(),
+ MemoryLayout.PathElement.groupElement("propertyFlags"));
+
+ final static VarHandle memoryTypes$heapIndex$EH = LAYOUT.varHandle(
+ MemoryLayout.PathElement.groupElement("memoryTypes"),
+ MemoryLayout.PathElement.sequenceElement(),
+ MemoryLayout.PathElement.groupElement("heapIndex"));
+
+ public int getMemoryTypes$propertyFlagsAtIndex(int index) {
+ return (int)memoryTypes$propertyFlags$EH.get(segment, index);
+ }
+
+ public int getMemoryTypes$heapIndexAtIndex(int index) {
+ return (int)memoryTypes$heapIndex$EH.get(segment, index);
+ }
+
+ final static VarHandle memoryHeaps$size$EH = LAYOUT.varHandle(
+ MemoryLayout.PathElement.groupElement("memoryHeaps"),
+ MemoryLayout.PathElement.sequenceElement(),
+ MemoryLayout.PathElement.groupElement("size"));
+
+ final static VarHandle memoryHeaps$flags$EH = LAYOUT.varHandle(
+ MemoryLayout.PathElement.groupElement("memoryHeaps"),
+ MemoryLayout.PathElement.sequenceElement(),
+ MemoryLayout.PathElement.groupElement("flags"));
+
+ public int getMemoryHeaps$sizeAtIndex(int index) {
+ return (int)memoryHeaps$size$EH.get(segment, index);
+ }
+
+ public int getMemoryHeaps$flagsAtIndex(int index) {
+ return (int)memoryHeaps$flags$EH.get(segment, index);
+ }
+ }}
+
+ # possibly way to auto-detect this - all simple types
+ VkAttachmentDescription template=struct-writeonly-array-all;
+ VkPipelineShaderStageCreateInfo template=struct-writeonly-array-all;
+ VkVertexInputAttributeDescription template=struct-writeonly-array-all;
+ VkVertexInputBindingDescription template=struct-writeonly-array-all;
+
+ # Override default read/write
+ VkDebugUtilsMessengerCallbackDataEXT template=struct-readonly;
+ VkDebugUtilsLabelEXT template=struct-readonly-array;
+ VkDebugUtilsObjectNameInfoEXT template=struct-readonly-array;
+
+ VkPhysicalDeviceFeatures template=struct-readwrite append {{
+ /**
+ * return true if every feature requested in query is present in this.
+ */
+ public boolean hasFeatures(VkPhysicalDeviceFeatures query) {
+ // s q
+ // 0 0 1
+ // 0 1 0
+ // 1 0 1
+ // 1 1 1
+ // = ((s & q) | ~q) & 1
+
+ // We know this is all just a list of VkBool32, so peek as an array
+ int ok = 1;
+ for (int i=0;ok != 0 && i<segment.byteSize() / 4; i++) {
+ int s = segment.getAtIndex(Memory.INT, i);
+ int q = query.segment.getAtIndex(Memory.INT, i);
+
+ ok &= (1 & ((s & q) | ~q));
+ }
+ return ok != 0;
+ }
+ }}
+
+# can't really work out what this is it's a void ** but it stays it's a pointer to uint8_t * in the spec
+ VkCuLaunchInfoNVX pParams=type:pointer pExtras=type:pointer;
+}
--- /dev/null
+
+# Routines for working with vulkan registry
+
+package vulkan;
+
+use strict;
+
+use Data::Dumper;
+use XML::Parser;
+
+sub new {
+ my $class = shift;
+ my $sys = shift;
+ my $self = {
+ sys => $sys,
+ data => {},
+ extensions => [],
+ handles => {},
+ types => {},
+ commands => {},
+ features => [],
+ funcpointers => {},
+ };
+
+ bless $self, $class;
+
+ loadRegistry($self);
+
+ # build various indices
+ my $data = $self->{data};
+ my $handles = $self->{handles};
+ my $types = $self->{types};
+ my $commands = $self->{commands};
+ my $extensions = $self->{extensions};
+ my $funcpointers = $self->{funcpointers};
+
+ foreach my $t (keys %{$data}) {
+ my $v = $data->{$t};
+ $handles->{$v->{name}} = $v if $v->{category} eq 'handle';
+ $types->{$v->{name}} = $v if $v->{category} =~ m/struct|union|platform/;
+ $commands->{$v->{name}} = $v if $v->{category} eq 'command';
+ $funcpointers->{$v->{name}} = $v if $v->{category} eq 'funcpointer';
+ }
+
+ # mark extension functions?
+ foreach my $e (@{$extensions}) {
+ foreach my $name (map { @{$_->{commands}} } @{$e->{require}}) {
+ my $r = $data->{$name};
+
+ die if !defined($r);
+
+ push @{$r->{extensions}}, $e->{name};
+ }
+ }
+
+ # Link up bitmask base types
+ foreach my $s (grep { $_->{category} eq 'enum' } values %{$data}) {
+ if ($s->{requires}) {
+ my $t = $data->{$s->{requires}};
+ die Dumper($s) if !defined $t;
+ die Dumper($s) if !defined $s->{fullType};
+ $t->{uses} = $s;
+ $t->{fullType} = $s->{fullType};
+ } elsif ($s->{bitvalues}) {
+ my $t = $data->{$s->{bitvalues}};
+ die Dumper($s) if !defined $t;
+ die Dumper($s) if !defined $s->{fullType};
+ $t->{uses} = $s;
+ $t->{fullType} = $s->{fullType};
+ } elsif (!defined $s->{fullType}) {
+ $s->{fullType} = 'VkFlags';
+ }
+ }
+
+ $self;
+}
+
+sub buildRequirement {
+ my $vk = shift;
+ my $data = shift;
+ my $req = shift;
+ my $ext = shift;
+ my $outconst = $data->{'API Constants'};
+ my $allconst = $vk->{data}->{'API Constants'};
+
+ # Find included types in this requirement
+ foreach my $c (@{$req->{commands}}, @{$req->{types}}) {
+ my $d = $vk->{data}->{$c};
+
+ if (defined $d) {
+ # for format change?
+ if ($d->{category} eq 'enum') {
+ # Copy all aliases across to data
+ while ($d->{alias}) {
+ $data->{$d->{name}} = $d;
+ $d = $vk->{data}->{$d->{alias}};
+ }
+ $d = { %$d };
+ $d->{items} = [ @{$d->{items}} ] if defined($d->{items});
+ $data->{$d->{name}} = $d;
+ } else {
+ $data->{$d->{name}} = $d;
+ }
+ } else {
+ $data->{$c} = {
+ name => $c,
+ category => 'define',
+ };
+ }
+ }
+
+ foreach my $c (@{$req->{enums}}) {
+ if ($c->{extends}) {
+ my $d = $data->{$c->{extends}};
+
+ if (defined($c->{value})) {
+ } elsif (defined($c->{bitpos})) {
+ $c->{value} = "".(1<<$c->{bitpos});
+ } elsif (defined($c->{extnumber})) {
+ $c->{value} = "".(1000000000
+ + 1000 * ($c->{extnumber} - 1)
+ + $c->{offset});
+ } elsif (defined($c->{offset})) {
+ $c->{value} = $c->{dir}."".(1000000000
+ + 1000 * ($ext->{number} - 1)
+ + $c->{offset});
+ } elsif (defined($c->{alias})) {
+ } else {
+ print Dumper($c);
+ die;
+ }
+
+ $c->{extension} = $ext->{name} if defined($ext);
+
+ push @{$d->{items}}, $c;
+ } elsif ($c->{value}) {
+ if ($c->{value} =~ m/^"/) {
+ if (!defined $outconst->{index}->{$c->{name}}) {
+ my $v = { %$c, type=>'const char *' };
+ push @{$outconst->{items}}, $v;
+ $outconst->{index}->{$v->{name}} = $v;
+ }
+ } else {
+ if (!defined $outconst->{index}->{$c->{name}}) {
+ my $v = { %$c, type=>'uint32_t' };
+ push @{$outconst->{items}}, $v;
+ $outconst->{index}->{$v->{name}} = $v;
+ }
+ }
+ } elsif (!$c->{alias}) {
+ if (!defined $outconst->{index}->{$c->{name}}) {
+ my $v = $allconst->{index}->{$c->{name}};
+
+ die Dumper($c) if !defined $v;
+
+ push @{$outconst->{items}}, $v;
+ $outconst->{index}->{$c->{name}} = $v;
+ }
+ }
+ }
+}
+
+# Ideally this builds a 'view' of the features
+# But it doesn't work properly if something is promoted and uses new names
+
+sub buildFeatures {
+ my $vk = shift;
+ my $vers = shift;
+ my $plat = shift;
+ my $data = {};
+ my $versions = {};
+ my $platform = {};
+
+ map { $versions->{$_} = 1 } @$vers;
+ map { $platform->{$_} = 1 } @$plat;
+
+ #print Dumper($vk->{features});
+
+ $data->{'API Constants'} = {
+ name => 'API Constants',
+ category => 'define',
+ items => [],
+ index => {},
+ };
+
+ # add constants that the api's dont reference (only 1 so far)
+ my $outconst = $data->{'API Constants'};
+ my $allconst = $vk->{data}->{'API Constants'};
+ foreach my $v (map {$allconst->{index}->{$_}} qw(VK_UUID_SIZE)) {
+ push @{$outconst->{items}}, $v;
+ $outconst->{index}->{$v->{name}} = $v;
+ }
+
+ foreach my $feature (grep { $versions->{$_->{name}} } @{$vk->{features}}) {
+ print "Feature $feature->{name}\n" if ($vk->{sys}->{verbose});
+ foreach my $req (@{$feature->{require}}) {
+ buildRequirement($vk, $data, $req);
+ }
+ }
+
+ foreach my $extension (grep { $_->{supported} eq 'vulkan' && (!defined($_->{platform}) || $platform->{$_->{platform}})
+ } @{$vk->{extensions}}) {
+ foreach my $req (grep { (!defined($_->{feature})) || $versions->{$_->{feature}} }
+ @{$extension->{require}}) {
+ print "Extension $extension->{name} $req->{feature}\n" if ($vk->{sys}->{verbose});
+ buildRequirement($vk, $data, $req, $extension);
+ }
+ }
+
+ #print "rest\n";
+ #print Dumper($data);
+
+ # TODO: need to remove aliases here?
+ my $handles = {};
+ my $types = {};
+ my $commands = {};
+ my $enums = {};
+ my $funcpointers = {};
+ my $defines = {};
+
+ foreach my $t (keys %{$data}) {
+ my $v = $data->{$t};
+ $handles->{$v->{name}} = $v if $v->{category} eq 'handle';
+ $types->{$v->{name}} = $v if $v->{category} =~ m/struct|union/on;
+ $commands->{$v->{name}} = $v if $v->{category} eq 'command';
+ $enums->{$v->{name}} = $v if $v->{category} eq 'enum';
+ $funcpointers->{$v->{name}} = $v if $v->{category} eq 'funcpointer';
+ $defines->{$v->{name}} = $v if $v->{category} eq 'define';
+ }
+
+ if (0) {
+ open(my $f, '>', 'features.pm');
+ print $f Dumper($data);
+ close $f;
+
+ open(my $f, '>', 'vk.pm');
+ print $f Dumper($vk);
+ close $f;
+ }
+
+ my $api = {
+ data => $data,
+ handles => $handles,
+ types => $types,
+ commands => $commands,
+ funcpointers => $funcpointers,
+ enums => $enums,
+ defines => $defines,
+ };
+
+ # create sizes for every struct of interest
+ foreach my $s (values %$types) {
+ next if $s->{alias};
+
+ if ($s->{category} eq 'struct') {
+ structSize($vk, $api, $s);
+ } elsif ($s->{category} eq 'union') {
+ unionSize($vk, $api, $s);
+ } else {
+ die;
+ }
+ }
+
+ return $api;
+}
+
+my $typeInfo = {
+ 'void *' => { bitSize => 64, bitAlign => 64 },
+ 'int' => { bitSize => 32, bitAlign => 32 },
+ 'char' => { bitSize => 8, bitAlign => 8 },
+ 'uint8_t' => { bitSize => 8, bitAlign => 8 },
+ 'uint16_t' => { bitSize => 16, bitAlign => 16 },
+ 'int32_t' => { bitSize => 32, bitAlign => 32 },
+ 'uint32_t' => { bitSize => 32, bitAlign => 32 },
+ 'int64_t' => { bitSize => 64, bitAlign => 64 },
+ 'uint64_t' => { bitSize => 64, bitAlign => 64 },
+ 'size_t' => { bitSize => 64, bitAlign => 64 },
+ 'float' => { bitSize => 32, bitAlign => 32 },
+ 'double' => { bitSize => 64, bitAlign => 64 },
+ 'size_t' => { bitSize => 64, bitAlign => 64 },
+ 'Window' => { bitSize => 64, bitAlign => 64 },
+ 'Display' => { bitSize => 64, bitAlign => 64 },
+ 'xcb_window_t' => { bitSize => 32, bitAlign => 32 },
+ 'xcb_connection_t' => { bitSize => 64, bitAlign => 64 },
+# 'VkFlags' => { bitSize => 32, bitAlign => 32 },
+# 'VkFlags64' => { bitSize => 64, bitAlign => 64 },
+};
+
+sub memberSize {
+ my $vk = shift;
+ my $api = shift;
+ my $m = shift;
+ my $t = $api->{data}->{$m->{baseType}};
+ my $nstar = $m->{fullType} =~ tr/*/*/;
+ my ($nbits) = $m->{fullType} =~ m/:(\d+)$/o;
+ my $array = 1;
+ my $info = $typeInfo->{'void *'};
+
+ # arrays and bitfields
+ if ($m->{fullType} =~ m/\[(.*)\]\[(.*)\]$/) {
+ $array = $1 * $2;
+ } elsif ($m->{fullType} =~ m/\[(\d+)\]$/o) {
+ $array = $1;
+ } elsif ($m->{fullType} =~ m/\[(.+)\]$/o) {
+ $array = $vk->{data}->{'API Constants'}->{index}->{$1}->{value};
+ }
+
+ if (!defined($t)) {
+ if ($nbits) {
+ die Dumper($m) if $nstar > 0;
+ $info = { bitSize => $nbits, bitAlign => 1 };
+ } else {
+ $info = $typeInfo->{$m->{baseType}} if ($nstar == 0);
+ }
+ } else {
+ while ($t->{alias}) {
+ $t = $api->{data}->{$t->{alias}};
+ }
+
+ die Dumper($m) if !defined $t;
+
+ if ($t->{category} =~ m/enum|bitmask/on) {
+ if ($nbits) {
+ die Dumper($m) if $nstar > 0;
+ $info = { bitSize => $nbits, bitAlign => 1 };
+ } else {
+ $t = $vk->{data}->{$t->{fullType}};
+ $info = $typeInfo->{$t->{type}} if ($nstar == 0);
+ }
+ } elsif ($t->{category} eq 'struct') {
+ $info = structSize($vk, $api, $t) if ($nstar == 0);
+ } elsif ($t->{category} eq 'union') {
+ $info = unionSize($vk, $api, $t) if ($nstar == 0);
+ } elsif ($t->{category} eq 'handle') {
+ # already set
+ } elsif ($t->{category} eq 'basetype') {
+ $info = $typeInfo->{$t->{type}} if ($nstar == 0);
+ } elsif ($t->{category} eq 'funcpointer') {
+ # already set
+ } else {
+ die Dumper($m, $t);
+ }
+ }
+
+ die Dumper($m, $t) if !defined($info);
+
+ #print Dumper($m, $t, $info);
+ #print "size $m->{name} $m->{fullType} = $info->{bitSize}\n";
+
+
+ return { bitSize => $info->{bitSize} * $array, bitAlign => $info->{bitAlign} };
+}
+
+sub align {
+ my $v = shift;
+ my $a = shift;
+
+ return ($v + $a - 1) & ~($a - 1);
+}
+
+sub structSize {
+ my $vk = shift;
+ my $api = shift;
+ my $s = shift;
+ my $bitSize = 0;
+ my $bitAlign = 8;
+
+ if (!defined($s->{bitSize})) {
+ foreach my $m (@{$s->{items}}) {
+ use integer;
+ my $info = memberSize($vk, $api, $m);
+
+ $bitSize = align($bitSize, $info->{bitAlign});
+
+ $m->{bitOffset} = $bitSize;
+ $m->{bitSize} = $info->{bitSize};
+
+ $bitSize = $bitSize + $info->{bitSize};
+ $bitAlign = $info->{bitAlign} if $info->{bitAlign} > $bitAlign;
+ }
+
+ $bitSize = align($bitSize, $bitAlign);
+
+ $s->{bitSize} = $bitSize;
+ $s->{bitAlign} = $bitAlign;
+ } else {
+ $bitSize = $s->{bitSize};
+ $bitAlign = $s->{bitAlign};
+ }
+
+ return { bitSize => $bitSize, bitAlign => $bitAlign };
+}
+
+sub unionSize {
+ my $vk = shift;
+ my $api = shift;
+ my $s = shift;
+ my $bitSize = 0;
+ my $bitAlign = 8;
+
+ if (!defined($s->{bitSize})) {
+ foreach my $m (@{$s->{items}}) {
+ use integer;
+ my $info = memberSize($vk, $api, $m);
+
+ $m->{bitOffset} = 0;
+ $m->{bitSize} = $info->{bitSize};
+
+ $bitSize = $info->{bitSize} if $info->{bitSize} > $bitSize;
+ $bitAlign = $info->{bitAlign} if $info->{bitAlign} > $bitAlign;
+ }
+
+ $bitSize = align($bitSize, $bitAlign);
+
+ $s->{bitSize} = $bitSize;
+ $s->{bitAlign} = $bitAlign;
+ } else {
+ $bitSize = $s->{bitSize};
+ $bitAlign = $s->{bitAlign};
+ }
+
+ return { bitSize => $bitSize, bitAlign => $bitAlign };
+}
+
+sub loadRegistry {
+ my $vk = shift;
+
+ my $xml = XML::Parser->new(Style => 'Tree');
+ my $doc = $xml->parsefile('/usr/share/vulkan/registry/vk.xml') || die "unable to parse vulkan registry";
+
+ #print Dumper($doc);
+
+ my $root = $doc->[1];
+ my $roota = shift @{$root};
+
+ my $data = $vk->{data};
+ my $alias = $vk->{alias};
+ my $extensions = $vk->{extensions};
+ my $features = $vk->{features};
+
+ # This destructively consumes the whole tree so must be one pass
+ while ($#{$root} >= 0) {
+ my $xt = shift @{$root};
+ my $xn = shift @{$root};
+
+ next if $xt eq '0';
+
+ my $xa = shift @{$xn};
+
+ if ($xt eq 'types') {
+ while ($#{$xn} >= 0) {
+ my $yt = shift @{$xn};
+ my $yn = shift @{$xn};
+
+ next if $yt ne 'type';
+
+ my $ya = $yn->[0];
+
+ if ($ya->{category} =~ m/struct|union/) {
+ if (!defined($ya->{alias})) {
+ my $s = $ya;
+
+ $s->{items} = [];
+
+ shift @{$yn};
+ while ($#{$yn} >= 0) {
+ my $mt = shift @{$yn};
+ my $mm = shift @{$yn};
+
+ push @{$s->{items}}, loadMember($mm) if $mt eq 'member';
+ }
+
+ $data->{$s->{name}} = $s;
+ } else {
+ $alias->{$ya->{name}} = $ya->{alias};
+ $data->{$ya->{name}} = $ya;
+ }
+ } elsif ($ya->{category} =~ m/^(handle|basetype|funcpointer|bitmask)$/n) {
+ if (!defined($ya->{alias})) {
+ my $info = loadMember($yn);
+ my $s = $ya;
+
+ $s->{name} = $info->{name};
+ $s->{type} = $info->{baseType} if defined $info->{baseType};
+
+ $s->{category} = 'enum' if $s->{category} eq 'bitmask';
+ analyseFunctionPointer($s) if ($s->{category} eq 'funcpointer');
+
+ $data->{$s->{name}} = $s;
+ } else {
+ $ya->{category} = 'enum' if $ya->{category} eq 'bitmask';
+ $alias->{$ya->{name}} = $ya->{alias};
+ $data->{$ya->{name}} = $ya;
+ }
+ } elsif ($ya->{category} eq 'enum') {
+ $data->{$ya->{name}} = $ya;
+ } elsif ($ya->{requires} eq 'vk_platform' || $ya->{name} eq 'int') {
+ # These are just primitive types, not sure what to do with them, could auto-map them to java i suppose
+ $ya->{category} = 'platform';
+ $data->{$ya->{name}} = $ya;
+ } else {
+ #noisy print "Unhandled: $ya->{name}\n";
+ }
+ }
+ } elsif ($xt eq 'enums') {
+ if ($xa->{type} =~ m/enum|bitmask/o) {
+ #print "enum: $xa->{name}\n";
+ # these are forward referenced from <types> block so re-use, or just overwrite?
+ my $e = $data->{$xa->{name}};
+
+ $e = { %{$xa}, category => "enum" } if (!defined($e));
+ $e->{items} = [];
+
+ while ($#{$xn} >= 0) {
+ my $yt = shift @{$xn};
+ my $yn = shift @{$xn};
+
+ next if $yt ne 'enum';
+
+ my $ya = shift @{$yn};
+
+ #next if $ya->{alias};
+
+ push @{$e->{items}}, $ya;
+ }
+
+ $data->{$e->{name}} = $e;
+ } elsif ($xa->{name} eq 'API Constants') {
+ my $d = { category => "define", name => $xa->{name}, items =>[], index=>{} };
+
+ $data->{$xa->{name}} = $d;
+
+ while ($#{$xn} >= 0) {
+ my $yt = shift @{$xn};
+ my $yn = shift @{$xn};
+
+ next if $yt ne 'enum';
+
+ my $ya = shift @{$yn};
+
+ #next if $ya->{alias};
+
+ push @{$d->{items}}, $ya;
+ $d->{index}->{$ya->{name}} = $ya;
+ }
+ }
+ } elsif ($xt eq 'commands') {
+ while ($#{$xn} >= 0) {
+ my $yt = shift @{$xn};
+ my $yn = shift @{$xn};
+
+ next if $yt ne 'command';
+
+ my $ya = shift @{$yn};
+
+ if (!defined($ya->{alias})) {
+ my $cmd = $ya;
+
+ $cmd->{category} = 'command';
+ $cmd->{items} = [];
+ $cmd->{proto} = {};
+
+ while ($#{$yn} >= 0) {
+ my $zt = shift @{$yn};
+ my $zn = shift @{$yn};
+
+ if ($zt eq 'proto') {
+ $cmd->{proto} = loadMember($zn);
+ } elsif ($zt eq 'param') {
+ push @{$cmd->{items}}, loadMember($zn);
+ }
+ }
+
+ my $name = $cmd->{proto}->{name};
+
+ # check we parsed it properly
+ if ($cmd->{proto}->{fullType} eq "") {
+ print Dumper([$ya, $yn]);
+ die();
+ }
+ $cmd->{name} = $name;
+
+ $data->{$name} = $cmd;
+ } else {
+ # want forward ref or not?
+ $alias->{$ya->{name}} = $ya->{alias};
+ $data->{$ya->{name}} = $ya;
+ }
+ }
+ } elsif ($xt eq 'feature') {
+ my $feature = $xa;
+
+ $feature->{require} = [];
+
+ while ($#{$xn} >= 0) {
+ my $yt = shift @{$xn};
+ my $yn = shift @{$xn};
+
+ next if $yt ne 'require';
+
+ push @{$feature->{require}}, loadRequire($data, $alias, $yn);
+ }
+
+ push @{$features}, $feature;
+ } elsif ($xt eq 'extensions') {
+ while ($#{$xn} >= 0) {
+ my $yt = shift @{$xn};
+ my $yn = shift @{$xn};
+
+ next if $yt ne 'extension';
+
+ my $ext = shift @{$yn};
+
+ $ext->{require} = [];
+
+ while ($#{$yn} >= 0) {
+ my $zt = shift @{$yn};
+ my $zn = shift @{$yn};
+
+ next if $zt ne 'require';
+
+ push @{$ext->{require}}, loadRequire($data, $alias, $zn);
+ }
+
+ push @{$extensions}, $ext;
+ }
+ } else {
+ print "vulkan.pm: Ignore node: $xt\n";
+ }
+ }
+}
+
+# find an object including via alias
+sub findData {
+ my $data = shift;
+ my $alias = shift;
+ my $name = shift;
+
+ do {
+ my $s = $data->{$name};
+ return $s if defined $s;
+ #print "alias $name => $alias->{$name}\n";
+ $name = $alias->{$name};
+ } while ($name);
+
+ die "No match for type '$name'";
+}
+
+sub makeParameter {
+ my $name = shift;
+ my $fullType = shift;
+ my $type = $fullType;
+
+ $type =~ s/const|\*|\s//gon;
+
+ $fullType =~ s/\s{2,}/ /go; # collapse all whitespace to ' '
+
+ # canonicalise spaces in c type
+ #$fullType =~ s/(?<!const)\s+//go; # strip all spaces except those following const
+ $fullType =~ s/(?<! )\*/ */go; # insert a space before * if there isn't one
+ $fullType =~ s/(?<=\*)(\S)/ \1/go;# insert a space after * if there isn't one
+
+ # fix brackets and trailing spaces
+ #$fullType =~ s/\( /(/go;
+ #$fullType =~ s/ \)/)/go;
+ #$fullType =~ s/ \[/[/go;
+ $fullType =~ s/^\s+|\s+$//go;
+
+ return {
+ name => $name,
+ Name => ucfirst($name),
+ fullType => $fullType,
+ baseType => $type,
+ type => $type,
+ };
+}
+
+# Convert function typedef into function info
+sub analyseFunctionPointer {
+ my $s = shift;
+
+ if ($s->{fullType} =~ m/^(.+)\s+\(VKAPI_PTR \*\)\((.*)\)$/o) {
+ my $rt = $1;
+ my @args = split /,/,$2;
+
+ $s->{proto} = makeParameter('result$', $rt);
+ $s->{items} = [];
+
+ if ($#args != 0 || $args[0] ne 'void') {
+ foreach my $a (@args) {
+ if (my ($fullType, $name) = $a =~ m/^(.*)\s+(\S+)$/o) {
+ push @{$s->{items}}, makeParameter($name, $fullType);
+ } else {
+ die "Unable to parse function pointer argument '$a'\n";
+ }
+ }
+ }
+ } else {
+ die "Unable to parse function pointer prototype '$s->{fullType}'\n";
+ }
+ $s->{Name} = $s->{name};
+
+ delete $s->{type};
+ delete $s->{baseType};
+ delete $s->{fullType};
+}
+
+sub loadMember {
+ my $nn = shift;
+ #my $x = (join '',split('\n',Dumper($nn))); $x =~ s/ +/ /g; print "load: $x\n";
+ my $m = shift @{$nn};
+ my $baseType = "";
+ my $fullType = "";
+ my $name = "";
+
+ while ($#{$nn} >= 0) {
+ my $pt = shift @{$nn};
+ my $pn = shift @{$nn};
+
+ if ($pt eq '0') {
+ $fullType .= $pn;
+ } elsif ($pt eq 'type') {
+ die if $pn->[1] != 0;
+ $baseType = $pn->[2];
+ $fullType .= $baseType;
+ } elsif ($pt eq 'name') {
+ die if $pn->[1] != 0;
+ $name = $pn->[2];
+ } elsif ($pt eq 'enum') {
+ die if $pn->[1] != 0;
+ $fullType .= $pn->[2];
+ }
+ }
+
+ $fullType =~ s/^typedef (.*);$/\1/os; # strip out 'typedef' part
+ $fullType =~ s/\s{2,}/ /go; # collapse all whitespace to ' '
+
+ # canonicalise spaces in c type
+ #$fullType =~ s/(?<!const)\s+//go; # strip all spaces except those following const
+ $fullType =~ s/(?<! )\*/ */go; # insert a space before * if there isn't one
+ $fullType =~ s/(?<=\*)(\S)/ \1/go;# insert a space after * if there isn't one
+
+ # fix brackets and trailing spaces
+ $fullType =~ s/\( /(/go;
+ $fullType =~ s/ \)/)/go;
+ $fullType =~ s/ \[/[/go;
+ $fullType =~ s/^\s+|\s+$//go;
+ $fullType =~ s/ :/:/go;
+
+ $m->{name} = $name;
+ $m->{baseType} = $baseType;
+ $m->{fullType} = $fullType;
+
+ $m;
+}
+
+sub loadRequire {
+ my $data = shift;
+ my $alias = shift;
+ my $nn = shift;
+ my $r = shift @{$nn};
+
+ $r->{enums} = [];
+ $r->{types} = [];
+ $r->{commands} = [];
+
+ while ($#{$nn} >= 0) {
+ my $mt = shift @{$nn};
+ my $mn = shift @{$nn};
+
+ if ($mt eq 'type') {
+ my $ma = shift @{$mn};
+ push @{$r->{types}}, $ma->{name};
+ } elsif ($mt eq 'command') {
+ my $ma = shift @{$mn};
+ push @{$r->{commands}}, $ma->{name};
+ } elsif ($mt eq 'enum') {
+ my $ma = shift @{$mn};
+ push @{$r->{enums}}, $ma;
+ }
+ }
+
+ $r;
+}
+
+sub findElements {
+ my $n = shift;
+ my $name = shift;
+ my @list;
+
+ while ($#{$n} >= 0) {
+ my $tag = shift @{$n};
+ my $con = shift @{$n};
+
+ if ($tag eq $name) {
+ push @list, [$tag, $con];
+ }
+ }
+ @list;
+}
+
+sub scanElements {
+ my $n = shift;
+
+ while ($#{$n} >= 0) {
+ my $tag = shift @{$n};
+ my $con = shift @{$n};
+
+ print "$#{$n} ";
+ print "tag $tag\n";
+ }
+}
+
+1;
--- /dev/null
+
+module notzed.xcb {
+ requires transitive notzed.nativez;
+
+ exports xcb;
+}
--- /dev/null
+
+package xcb;
+
+import jdk.incubator.foreign.*;
+import au.notzed.nativez.Pointer;
+
+/* small hack to get it to compile, unimplemented functions so far */
+
+public class Connection implements Pointer {
+ NativeSymbol symbol;
+
+ public Connection(MemoryAddress addr, ResourceScope scope) {
+ symbol = NativeSymbol.ofAddress("Connection", addr, scope);
+ }
+
+ public static Connection create(MemoryAddress addr, ResourceScope scope) {
+ return new Connection(addr, scope);
+ }
+
+ public MemoryAddress address() {
+ return symbol.address();
+ }
+
+ public ResourceScope scope() {
+ return symbol.scope();
+ }
+
+}
--- /dev/null
+
+module notzed.xlib {
+ requires notzed.nativez;
+
+ exports xlib;
+}
--- /dev/null
+
+notzed.xlib_API = xlib
+notzed.xlib_APIFLAGS = -t xlib -Isrc/notzed.xlib/gen
--- /dev/null
+# -*- Mode:text; tab-width:4; electric-indent-mode: nil; indent-line-function:insert-tab; -*-
+
+%include types.api;
+%include code.api;
+
+struct <default> default=all access=rw rename=s/^_// field:rename=studly-caps {
+ class rename=XClass;
+ visualid rename=VisualID;
+ xid rename=XID;
+}
+
+union <default> default=all access=rw rename=s/^_// field:rename=studly-caps {
+}
+
+struct _XPrivDisplay {
+ screens array array-size=nscreens access=r;
+}
+
+struct Screen access=rw
+ template=code:class=struct-array
+{
+}
+
+#struct Visual {
+# Class field:rename=XClass;
+#}
+
+#struct XVisualInfo {
+# Class rename=XClass;
+#}
+
+library XLib {
+ define:xlib;
+ func:XCreateColormap;
+ func:XCreateWindow;
+ func:XDestroyWindow;
+ func:XFlush;
+ func:XGetVisualInfo;
+ func:XInitThreads;
+ func:XInternAtom;
+ func:XMapWindow;
+ func:XOpenDisplay;
+ func:XCloseDisplay;
+ func:XSelectInput;
+
+ func:XSetWMProtocols;
+
+ func:XPending;
+ func:XNextEvent;
+ func:XWindowEvent;
+ func:XCheckWindowEvent;
+
+ func:XGetWindowAttributes;
+
+# #define DefaultScreen(dpy) (((_XPrivDisplay)(dpy))->default_screen)
+# #define RootWindow(dpy, scr) (ScreenOfDisplay(dpy,scr)->root)
+# #define ScreenOfDisplay(dpy, scr)(&((_XPrivDisplay)(dpy))->screens[scr])
+
+ code:<inline> {{
+ public static int DefaultScreen(XDisplay dpy) {
+ XPrivDisplay pdpy = XPrivDisplay.create(dpy.address, dpy.scope);
+ return pdpy.getDefaultScreen();
+ }
+
+ public static long RootWindow(XDisplay dpy, int scr) {
+ XPrivDisplay pdpy = XPrivDisplay.create(dpy.address, dpy.scope);
+ Screen screen = pdpy.getScreens().getAtIndex(scr);
+ return screen.getRoot();
+ }
+
+ }}
+
+}
+
+define xlib xlib.h {
+ /Pixel$|^Input|^CW|Mask$|^Alloc/ include;
+ /KeyPress|KeyRelease|ButtonPress|ButtonRelease|MotionNotify|EnterNotify|LeaveNotify|FocusIn|FocusOut|KeymapNotify|Expose|GraphicsExpose|NoExpose|VisibilityNotify|CreateNotify|DestroyNotify|UnmapNotify|MapNotify|MapRequest|ReparentNotify|ConfigureNotify|ConfigureRequest|GravityNotify|ResizeRequest|CirculateNotify|CirculateRequest|PropertyNotify|SelectionClear|SelectionRequest|SelectionNotify|ColormapNotify|ClientMessage|MappingNotify|GenericEvent/ include;
+
+}
--- /dev/null
+
+#include <X11/Xutil.h>