diff options
421 files changed, 12409 insertions, 5086 deletions
diff --git a/.ci/scripts/linux/docker.sh b/.ci/scripts/linux/docker.sh index 5559a527c..277775ef6 100755 --- a/.ci/scripts/linux/docker.sh +++ b/.ci/scripts/linux/docker.sh @@ -5,7 +5,7 @@ cd /yuzu ccache -s mkdir build || true && cd build -cmake .. -G Ninja -DDISPLAY_VERSION=$1 -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON +cmake .. -G Ninja -DDISPLAY_VERSION=$1 -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON ninja diff --git a/.ci/scripts/windows/docker.sh b/.ci/scripts/windows/docker.sh index d53281741..adfd636fa 100755 --- a/.ci/scripts/windows/docker.sh +++ b/.ci/scripts/windows/docker.sh @@ -5,7 +5,7 @@ cd /yuzu ccache -s mkdir build || true && cd build -cmake .. -G Ninja -DDISPLAY_VERSION=$1 -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DYUZU_USE_BUNDLED_UNICORN=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release +cmake .. -G Ninja -DDISPLAY_VERSION=$1 -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DYUZU_USE_BUNDLED_UNICORN=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_QT_TRANSLATION=ON ninja ccache -s diff --git a/CMakeLists.txt b/CMakeLists.txt index ce46a2c2b..7a49318aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,7 @@ project(yuzu) option(ENABLE_SDL2 "Enable the SDL2 frontend" ON) option(ENABLE_QT "Enable the Qt frontend" ON) +option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF) CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" ON "ENABLE_QT;MSVC" OFF) option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON) @@ -224,6 +225,10 @@ if(ENABLE_QT) if (YUZU_USE_QT_WEB_ENGINE) find_package(Qt5 COMPONENTS WebEngineCore WebEngineWidgets) endif() + + if (ENABLE_QT_TRANSLATION) + find_package(Qt5 REQUIRED COMPONENTS LinguistTools ${QT_PREFIX_HINT}) + endif() if (NOT Qt5_FOUND) list(APPEND CONAN_REQUIRED_LIBS "qt/5.14.1@bincrafters/stable") endif() @@ -24,6 +24,8 @@ Most of the development happens on GitHub. It's also where [our central reposito If you want to contribute please take a look at the [Contributor's Guide](https://github.com/yuzu-emu/yuzu/wiki/Contributing) and [Developer Information](https://github.com/yuzu-emu/yuzu/wiki/Developer-Information). You should also contact any of the developers on Discord in order to know about the current state of the emulator. +If you want to contribute to the user interface translation, please check out the [yuzu project on transifex](https://www.transifex.com/yuzu-emulator/yuzu). We centralize translation work there, and periodically upstream translations. + ### Building * __Windows__: [Windows Build](https://github.com/yuzu-emu/yuzu/wiki/Building-For-Windows) diff --git a/dist/languages/.gitignore b/dist/languages/.gitignore new file mode 100644 index 000000000..27e5a0158 --- /dev/null +++ b/dist/languages/.gitignore @@ -0,0 +1,2 @@ +# Ignore the source language file +en.ts diff --git a/dist/languages/.tx/config b/dist/languages/.tx/config new file mode 100644 index 000000000..0d9b512ea --- /dev/null +++ b/dist/languages/.tx/config @@ -0,0 +1,8 @@ +[main] +host = https://www.transifex.com + +[yuzu.emulator] +file_filter = <lang>.ts +source_file = en.ts +source_lang = en +type = QT diff --git a/dist/languages/README.md b/dist/languages/README.md new file mode 100644 index 000000000..61981ab1d --- /dev/null +++ b/dist/languages/README.md @@ -0,0 +1 @@ +This directory stores translation patches (TS files) for yuzu Qt frontend. This directory is linked with [yuzu project on transifex](https://www.transifex.com/yuzu-emulator/yuzu), so you can update the translation by executing `tx pull -a`. If you want to contribute to the translation, please go the transifex link and submit your translation there. This directory on the main repo will be synchronized with transifex periodically. Do not directly open PRs on github to modify the translation. diff --git a/dist/qt_themes/colorful_midnight_blue/icons/16x16/lock.png b/dist/qt_themes/colorful_midnight_blue/icons/16x16/lock.png Binary files differnew file mode 100644 index 000000000..32c505848 --- /dev/null +++ b/dist/qt_themes/colorful_midnight_blue/icons/16x16/lock.png diff --git a/dist/qt_themes/colorful_midnight_blue/icons/index.theme b/dist/qt_themes/colorful_midnight_blue/icons/index.theme new file mode 100644 index 000000000..e23bfe6f9 --- /dev/null +++ b/dist/qt_themes/colorful_midnight_blue/icons/index.theme @@ -0,0 +1,8 @@ +[Icon Theme] +Name=colorful_midnight_blue +Comment=Colorful theme (Midnight Blue style) +Inherits=default +Directories=16x16 + +[16x16] +Size=16 diff --git a/dist/qt_themes/colorful_midnight_blue/style.qrc b/dist/qt_themes/colorful_midnight_blue/style.qrc new file mode 100644 index 000000000..fd33bc850 --- /dev/null +++ b/dist/qt_themes/colorful_midnight_blue/style.qrc @@ -0,0 +1,57 @@ +<RCC> + <qresource prefix="icons/colorful_midnight_blue"> + <file alias="index.theme">icons/index.theme</file> + <file alias="16x16/lock.png">icons/16x16/lock.png</file> + <file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file> + <file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file> + <file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file> + <file alias="48x48/plus.png">../colorful/icons/48x48/plus.png</file> + <file alias="48x48/sd_card.png">../colorful/icons/48x48/sd_card.png</file> + <file alias="256x256/plus_folder.png">../colorful/icons/256x256/plus_folder.png</file> + </qresource> + + <qresource prefix="qss_icons"> + <file alias="rc/up_arrow_disabled.png">../qdarkstyle_midnight_blue/rc/up_arrow_disabled.png</file> + <file alias="rc/Hmovetoolbar.png">../qdarkstyle_midnight_blue/rc/Hmovetoolbar.png</file> + <file alias="rc/stylesheet-branch-end.png">../qdarkstyle_midnight_blue/rc/stylesheet-branch-end.png</file> + <file alias="rc/branch_closed-on.png">../qdarkstyle_midnight_blue/rc/branch_closed-on.png</file> + <file alias="rc/stylesheet-vline.png">../qdarkstyle_midnight_blue/rc/stylesheet-vline.png</file> + <file alias="rc/branch_closed.png">../qdarkstyle_midnight_blue/rc/branch_closed.png</file> + <file alias="rc/branch_open-on.png">../qdarkstyle_midnight_blue/rc/branch_open-on.png</file> + <file alias="rc/transparent.png">../qdarkstyle_midnight_blue/rc/transparent.png</file> + <file alias="rc/right_arrow_disabled.png">../qdarkstyle_midnight_blue/rc/right_arrow_disabled.png</file> + <file alias="rc/sizegrip.png">../qdarkstyle_midnight_blue/rc/sizegrip.png</file> + <file alias="rc/close.png">../qdarkstyle_midnight_blue/rc/close.png</file> + <file alias="rc/close-hover.png">../qdarkstyle_midnight_blue/rc/close-hover.png</file> + <file alias="rc/close-pressed.png">../qdarkstyle_midnight_blue/rc/close-pressed.png</file> + <file alias="rc/down_arrow.png">../qdarkstyle_midnight_blue/rc/down_arrow.png</file> + <file alias="rc/Vmovetoolbar.png">../qdarkstyle_midnight_blue/rc/Vmovetoolbar.png</file> + <file alias="rc/left_arrow.png">../qdarkstyle_midnight_blue/rc/left_arrow.png</file> + <file alias="rc/stylesheet-branch-more.png">../qdarkstyle_midnight_blue/rc/stylesheet-branch-more.png</file> + <file alias="rc/up_arrow.png">../qdarkstyle_midnight_blue/rc/up_arrow.png</file> + <file alias="rc/right_arrow.png">../qdarkstyle_midnight_blue/rc/right_arrow.png</file> + <file alias="rc/left_arrow_disabled.png">../qdarkstyle_midnight_blue/rc/left_arrow_disabled.png</file> + <file alias="rc/Hsepartoolbar.png">../qdarkstyle_midnight_blue/rc/Hsepartoolbar.png</file> + <file alias="rc/branch_open.png">../qdarkstyle_midnight_blue/rc/branch_open.png</file> + <file alias="rc/Vsepartoolbar.png">../qdarkstyle_midnight_blue/rc/Vsepartoolbar.png</file> + <file alias="rc/down_arrow_disabled.png">../qdarkstyle_midnight_blue/rc/down_arrow_disabled.png</file> + <file alias="rc/undock.png">../qdarkstyle_midnight_blue/rc/undock.png</file> + <file alias="rc/checkbox_checked_disabled.png">../qdarkstyle_midnight_blue/rc/checkbox_checked_disabled.png</file> + <file alias="rc/checkbox_checked_focus.png">../qdarkstyle_midnight_blue/rc/checkbox_checked_focus.png</file> + <file alias="rc/checkbox_checked.png">../qdarkstyle_midnight_blue/rc/checkbox_checked.png</file> + <file alias="rc/checkbox_indeterminate.png">../qdarkstyle_midnight_blue/rc/checkbox_indeterminate.png</file> + <file alias="rc/checkbox_indeterminate_focus.png">../qdarkstyle_midnight_blue/rc/checkbox_indeterminate_focus.png</file> + <file alias="rc/checkbox_unchecked_disabled.png">../qdarkstyle_midnight_blue/rc/checkbox_unchecked_disabled.png</file> + <file alias="rc/checkbox_unchecked_focus.png">../qdarkstyle_midnight_blue/rc/checkbox_unchecked_focus.png</file> + <file alias="rc/checkbox_unchecked.png">../qdarkstyle_midnight_blue/rc/checkbox_unchecked.png</file> + <file alias="rc/radio_checked_disabled.png">../qdarkstyle_midnight_blue/rc/radio_checked_disabled.png</file> + <file alias="rc/radio_checked_focus.png">../qdarkstyle_midnight_blue/rc/radio_checked_focus.png</file> + <file alias="rc/radio_checked.png">../qdarkstyle_midnight_blue/rc/radio_checked.png</file> + <file alias="rc/radio_unchecked_disabled.png">../qdarkstyle_midnight_blue/rc/radio_unchecked_disabled.png</file> + <file alias="rc/radio_unchecked_focus.png">../qdarkstyle_midnight_blue/rc/radio_unchecked_focus.png</file> + <file alias="rc/radio_unchecked.png">../qdarkstyle_midnight_blue/rc/radio_unchecked.png</file> + </qresource> + <qresource prefix="colorful_midnight_blue"> + <file alias="style.qss">../qdarkstyle_midnight_blue/style.qss</file> + </qresource> +</RCC> diff --git a/dist/qt_themes/qdarkstyle/rc/checkbox_checked.png b/dist/qt_themes/qdarkstyle/rc/checkbox_checked.png Binary files differindex 830cfee65..dd891298f 100644 --- a/dist/qt_themes/qdarkstyle/rc/checkbox_checked.png +++ b/dist/qt_themes/qdarkstyle/rc/checkbox_checked.png diff --git a/dist/qt_themes/qdarkstyle/rc/checkbox_checked_disabled.png b/dist/qt_themes/qdarkstyle/rc/checkbox_checked_disabled.png Binary files differindex cb63cc2fa..44bf145f8 100644 --- a/dist/qt_themes/qdarkstyle/rc/checkbox_checked_disabled.png +++ b/dist/qt_themes/qdarkstyle/rc/checkbox_checked_disabled.png diff --git a/dist/qt_themes/qdarkstyle/rc/checkbox_checked_focus.png b/dist/qt_themes/qdarkstyle/rc/checkbox_checked_focus.png Binary files differindex 671be273b..60238b21d 100644 --- a/dist/qt_themes/qdarkstyle/rc/checkbox_checked_focus.png +++ b/dist/qt_themes/qdarkstyle/rc/checkbox_checked_focus.png diff --git a/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate.png b/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate.png Binary files differindex 41024f768..830cfee65 100644 --- a/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate.png +++ b/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate.png diff --git a/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_disabled.png b/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_disabled.png Binary files differindex abdc01d90..cb63cc2fa 100644 --- a/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_disabled.png +++ b/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_disabled.png diff --git a/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_focus.png b/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_focus.png Binary files differindex 415f9b6e1..671be273b 100644 --- a/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_focus.png +++ b/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/LICENSE.rst b/dist/qt_themes/qdarkstyle_midnight_blue/LICENSE.rst new file mode 100644 index 000000000..e22b68735 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/LICENSE.rst @@ -0,0 +1,405 @@ +License +======= + +The MIT License (MIT) - Code +---------------------------- + +Copyright (c) 2013-2019 Colin Duquesnoy + +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. + + +Creative Commons Attribution International 4.0 - Images +------------------------------------------------------- + +QDarkStyle (c) 2013-2019 Colin Duquesnoy +QDarkStyle (c) 2019-2019 Daniel Cosmo Pizetta + +Creative Commons Corporation (“Creative Commons”) is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an “as-is” basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright and +certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + +- **Considerations for licensors:** Our public licenses are intended + for use by those authorized to give the public permission to use + material in ways otherwise restricted by copyright and certain other + rights. Our licenses are irrevocable. Licensors should read and + understand the terms and conditions of the license they choose before + applying it. Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the material as + expected. Licensors should clearly mark any material not subject to + the license. This includes other CC-licensed material, or material + used under an exception or limitation to copyright. `More + considerations for + licensors <http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors>`__. + +- **Considerations for the public:** By using one of our public + licenses, a licensor grants the public permission to use the licensed + material under specified terms and conditions. If the licensor’s + permission is not necessary for any reason–for example, because of + any applicable exception or limitation to copyright–then that use is + not regulated by the license. Our licenses grant only permissions + under copyright and certain other rights that a licensor has + authority to grant. Use of the licensed material may still be + restricted for other reasons, including because others have copyright + or other rights in the material. A licensor may make special + requests, such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to respect + those requests where reasonable. `More considerations for the + public <http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensees>`__. + + +Creative Commons Attribution 4.0 International Public License +------------------------------------------------------------- + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of these +terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the Licensed +Material available under these terms and conditions. + +Section 1 – Definitions +~~~~~~~~~~~~~~~~~~~~~~~ + +a. **Adapted Material** means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material and + in which the Licensed Material is translated, altered, arranged, + transformed, or otherwise modified in a manner requiring permission + under the Copyright and Similar Rights held by the Licensor. For + purposes of this Public License, where the Licensed Material is a + musical work, performance, or sound recording, Adapted Material is + always produced where the Licensed Material is synched in timed + relation with a moving image. + +b. **Adapter's License** means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + +c. **Copyright and Similar Rights** means copyright and/or similar + rights closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or categorized. + For purposes of this Public License, the rights specified in Section + 2(b)(1)-(2) are not Copyright and Similar Rights. + +d. **Effective Technological Measures** means those measures that, in + the absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright Treaty + adopted on December 20, 1996, and/or similar international + agreements. + +e. **Exceptions and Limitations** means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + +f. **Licensed Material** means the artistic or literary work, database, + or other material to which the Licensor applied this Public License. + +g. **Licensed Rights** means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to all + Copyright and Similar Rights that apply to Your use of the Licensed + Material and that the Licensor has authority to license. + +h. **Licensor** means the individual(s) or entity(ies) granting rights + under this Public License. + +i. **Share** means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such as + reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the public + may access the material from a place and at a time individually + chosen by them. + +j. **Sui Generis Database Rights** means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, as + amended and/or succeeded, as well as other essentially equivalent + rights anywhere in the world. + +k. **You** means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + +Section 2 – Scope +~~~~~~~~~~~~~~~~~ + +a. **License grant.** + +1. Subject to the terms and conditions of this Public License, the + Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to exercise the + Licensed Rights in the Licensed Material to: + + A. reproduce and Share the Licensed Material, in whole or in part; + and + + B. produce, reproduce, and Share Adapted Material. + +2. **Exceptions and Limitations.** For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public License + does not apply, and You do not need to comply with its terms and + conditions. + +3. **Term.** The term of this Public License is specified in Section + 6(a). + +4. **Media and formats; technical modifications allowed.** The Licensor + authorizes You to exercise the Licensed Rights in all media and + formats whether now known or hereafter created, and to make technical + modifications necessary to do so. The Licensor waives and/or agrees + not to assert any right or authority to forbid You from making + technical modifications necessary to exercise the Licensed Rights, + including technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, simply + making modifications authorized by this Section 2(a)(4) never + produces Adapted Material. + +5. **Downstream recipients.** + + A. **Offer from the Licensor – Licensed Material.** Every recipient + of the Licensed Material automatically receives an offer from the + Licensor to exercise the Licensed Rights under the terms and + conditions of this Public License. + + B. **No downstream restrictions.** You may not offer or impose any + additional or different terms or conditions on, or apply any + Effective Technological Measures to, the Licensed Material if doing + so restricts exercise of the Licensed Rights by any recipient of the + Licensed Material. + +6. **No endorsement.** Nothing in this Public License constitutes or may + be construed as permission to assert or imply that You are, or that + Your use of the Licensed Material is, connected with, or sponsored, + endorsed, or granted official status by, the Licensor or others + designated to receive attribution as provided in Section + 3(a)(1)(A)(i). + +b. **Other rights.** + +1. Moral rights, such as the right of integrity, are not licensed under + this Public License, nor are publicity, privacy, and/or other similar + personality rights; however, to the extent possible, the Licensor + waives and/or agrees not to assert any such rights held by the + Licensor to the limited extent necessary to allow You to exercise the + Licensed Rights, but not otherwise. + +2. Patent and trademark rights are not licensed under this Public + License. + +3. To the extent possible, the Licensor waives any right to collect + royalties from You for the exercise of the Licensed Rights, whether + directly or through a collecting society under any voluntary or + waivable statutory or compulsory licensing scheme. In all other cases + the Licensor expressly reserves any right to collect such royalties. + +Section 3 – License Conditions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + +a. **Attribution.** + +1. If You Share the Licensed Material (including in modified form), You + must: + + A. retain the following if it is supplied by the Licensor with the + Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any + others designated to receive attribution, in any reasonable manner + requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + B. indicate if You modified the Licensed Material and retain an + indication of any previous modifications; and + + C. indicate the Licensed Material is licensed under this Public + License, and include the text of, or the URI or hyperlink to, this + Public License. + +2. You may satisfy the conditions in Section 3(a)(1) in any reasonable + manner based on the medium, means, and context in which You Share the + Licensed Material. For example, it may be reasonable to satisfy the + conditions by providing a URI or hyperlink to a resource that + includes the required information. + +3. If requested by the Licensor, You must remove any of the information + required by Section 3(a)(1)(A) to the extent reasonably practicable. + +4. If You Share Adapted Material You produce, the Adapter's License You + apply must not prevent recipients of the Adapted Material from + complying with this Public License. + +Section 4 – Sui Generis Database Rights +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Where the Licensed Rights include Sui Generis Database Rights that apply +to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to + extract, reuse, reproduce, and Share all or a substantial portion of + the contents of the database; + +b. if You include all or a substantial portion of the database contents + in a database in which You have Sui Generis Database Rights, then the + database in which You have Sui Generis Database Rights (but not its + individual contents) is Adapted Material; and + +c. You must comply with the conditions in Section 3(a) if You Share all + or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + +Section 5 – Disclaimer of Warranties and Limitation of Liability +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +a. Unless otherwise separately undertaken by the Licensor, to the + extent possible, the Licensor offers the Licensed Material as-is and + as-available, and makes no representations or warranties of any kind + concerning the Licensed Material, whether express, implied, + statutory, or other. This includes, without limitation, warranties of + title, merchantability, fitness for a particular purpose, + non-infringement, absence of latent or other defects, accuracy, or + the presence or absence of errors, whether or not known or + discoverable. Where disclaimers of warranties are not allowed in full + or in part, this disclaimer may not apply to You. + +b. To the extent possible, in no event will the Licensor be liable to + You on any legal theory (including, without limitation, negligence) + or otherwise for any direct, special, indirect, incidental, + consequential, punitive, exemplary, or other losses, costs, expenses, + or damages arising out of this Public License or use of the Licensed + Material, even if the Licensor has been advised of the possibility of + such losses, costs, expenses, or damages. Where a limitation of + liability is not allowed in full or in part, this limitation may not + apply to You. + +c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent possible, + most closely approximates an absolute disclaimer and waiver of all + liability. + +Section 6 – Term and Termination +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +a. This Public License applies for the term of the Copyright and Similar + Rights licensed here. However, if You fail to comply with this Public + License, then Your rights under this Public License terminate + automatically. + +b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + +1. automatically as of the date the violation is cured, provided it is + cured within 30 days of Your discovery of the violation; or + +2. upon express reinstatement by the Licensor. + +For the avoidance of doubt, this Section 6(b) does not affect any right +the Licensor may have to seek remedies for Your violations of this +Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed + Material under separate terms or conditions or stop distributing the + Licensed Material at any time; however, doing so will not terminate + this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + +Section 7 – Other Terms and Conditions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +a. The Licensor shall not be bound by any additional or different terms + or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and independent + of the terms and conditions of this Public License. + +Section 8 – Interpretation +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +a. For the avoidance of doubt, this Public License does not, and shall + not be interpreted to, reduce, limit, restrict, or impose conditions + on any use of the Licensed Material that could lawfully be made + without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + +c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a + limitation upon, or waiver of, any privileges and immunities that + apply to the Licensor or You, including from the legal processes of + any jurisdiction or authority. + + Creative Commons is not a party to its public licenses. + Notwithstanding, Creative Commons may elect to apply one of its + public licenses to material it publishes and in those instances will + be considered the “Licensor.” Except for the limited purpose of + indicating that material is shared under a Creative Commons public + license or as otherwise permitted by the Creative Commons policies + published at + `creativecommons.org/policies <http://creativecommons.org/policies>`__, + Creative Commons does not authorize the use of the trademark + “Creative Commons” or any other trademark or logo of Creative + Commons without its prior written consent including, without + limitation, in connection with any unauthorized modifications to any + of its public licenses or any other arrangements, understandings, or + agreements concerning use of licensed material. For the avoidance of + doubt, this paragraph does not form part of the public licenses. + + Creative Commons may be contacted at creativecommons.org diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/lock.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/lock.png Binary files differnew file mode 100644 index 000000000..c750a39e8 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/lock.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/256x256/plus_folder.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/256x256/plus_folder.png Binary files differnew file mode 100644 index 000000000..303f9a321 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/icons/256x256/plus_folder.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/bad_folder.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/bad_folder.png Binary files differnew file mode 100644 index 000000000..4a9709623 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/bad_folder.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/chip.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/chip.png Binary files differnew file mode 100644 index 000000000..973fabd05 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/chip.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/folder.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/folder.png Binary files differnew file mode 100644 index 000000000..0f1e987d6 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/folder.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/plus.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/plus.png Binary files differnew file mode 100644 index 000000000..16cc8b4f4 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/plus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/sd_card.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/sd_card.png Binary files differnew file mode 100644 index 000000000..0291c6542 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/sd_card.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/index.theme b/dist/qt_themes/qdarkstyle_midnight_blue/icons/index.theme new file mode 100644 index 000000000..447a6c8be --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/icons/index.theme @@ -0,0 +1,14 @@ +[Icon Theme] +Name=qdarkstyle_midnight_blue +Comment=dark theme +Inherits=default +Directories=16x16,48x48,256x256 + +[16x16] +Size=16 + +[48x48] +Size=48 + +[256x256] +Size=256 diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/Hmovetoolbar.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/Hmovetoolbar.png Binary files differnew file mode 100644 index 000000000..cead99ed1 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/Hmovetoolbar.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/Hsepartoolbar.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/Hsepartoolbar.png Binary files differnew file mode 100644 index 000000000..7f183c8b3 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/Hsepartoolbar.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/Vmovetoolbar.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/Vmovetoolbar.png Binary files differnew file mode 100644 index 000000000..512edcecd --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/Vmovetoolbar.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/Vsepartoolbar.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/Vsepartoolbar.png Binary files differnew file mode 100644 index 000000000..d9dc1561b --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/Vsepartoolbar.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down.png Binary files differnew file mode 100644 index 000000000..c4e6894ba --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down@2x.png Binary files differnew file mode 100644 index 000000000..bb8cbed0d --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_disabled.png Binary files differnew file mode 100644 index 000000000..aa1d06c08 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_disabled@2x.png Binary files differnew file mode 100644 index 000000000..86bf434b8 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_focus.png Binary files differnew file mode 100644 index 000000000..1c42ee8f6 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_focus@2x.png Binary files differnew file mode 100644 index 000000000..7374637c5 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_pressed.png Binary files differnew file mode 100644 index 000000000..8139ee3e8 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_pressed@2x.png Binary files differnew file mode 100644 index 000000000..5e9d225ff --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left.png Binary files differnew file mode 100644 index 000000000..ef929fdf0 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left@2x.png Binary files differnew file mode 100644 index 000000000..c8923d6f4 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_disabled.png Binary files differnew file mode 100644 index 000000000..9c69561a7 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_disabled@2x.png Binary files differnew file mode 100644 index 000000000..e52114312 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_focus.png Binary files differnew file mode 100644 index 000000000..a1f070455 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_focus@2x.png Binary files differnew file mode 100644 index 000000000..c4267e856 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_pressed.png Binary files differnew file mode 100644 index 000000000..bd706cbdd --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_pressed@2x.png Binary files differnew file mode 100644 index 000000000..341b2e541 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right.png Binary files differnew file mode 100644 index 000000000..4f3388505 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right@2x.png Binary files differnew file mode 100644 index 000000000..94b260965 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_disabled.png Binary files differnew file mode 100644 index 000000000..0fbc6b04c --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_disabled@2x.png Binary files differnew file mode 100644 index 000000000..8e9272a5b --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_focus.png Binary files differnew file mode 100644 index 000000000..764940945 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_focus@2x.png Binary files differnew file mode 100644 index 000000000..6d52b5fa3 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_pressed.png Binary files differnew file mode 100644 index 000000000..a5f04522a --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_pressed@2x.png Binary files differnew file mode 100644 index 000000000..6f6a8130c --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up.png Binary files differnew file mode 100644 index 000000000..61d7574a4 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up@2x.png Binary files differnew file mode 100644 index 000000000..d711fae16 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_disabled.png Binary files differnew file mode 100644 index 000000000..18e8ecd8d --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_disabled@2x.png Binary files differnew file mode 100644 index 000000000..fb4defb52 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_focus.png Binary files differnew file mode 100644 index 000000000..a7acd9b66 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_focus@2x.png Binary files differnew file mode 100644 index 000000000..9cd982a1d --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_pressed.png Binary files differnew file mode 100644 index 000000000..390a80e21 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_pressed@2x.png Binary files differnew file mode 100644 index 000000000..dd352cff3 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon.png Binary files differnew file mode 100644 index 000000000..37a6158cc --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon@2x.png Binary files differnew file mode 100644 index 000000000..e6e5cb916 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_disabled.png Binary files differnew file mode 100644 index 000000000..37a6158cc --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_disabled@2x.png Binary files differnew file mode 100644 index 000000000..e6e5cb916 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_focus.png Binary files differnew file mode 100644 index 000000000..37a6158cc --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_focus@2x.png Binary files differnew file mode 100644 index 000000000..e6e5cb916 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_pressed.png Binary files differnew file mode 100644 index 000000000..37a6158cc --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_pressed@2x.png Binary files differnew file mode 100644 index 000000000..e6e5cb916 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed-on.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed-on.png Binary files differnew file mode 100644 index 000000000..d081e9b3b --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed-on.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed.png Binary files differnew file mode 100644 index 000000000..53e2c51f5 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed@2x.png Binary files differnew file mode 100644 index 000000000..06cdefa5f --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_disabled.png Binary files differnew file mode 100644 index 000000000..5106a1438 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_disabled@2x.png Binary files differnew file mode 100644 index 000000000..180bae9e6 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_focus.png Binary files differnew file mode 100644 index 000000000..c227f9f71 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_focus@2x.png Binary files differnew file mode 100644 index 000000000..ad23d0d33 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_pressed.png Binary files differnew file mode 100644 index 000000000..90845a81f --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_pressed@2x.png Binary files differnew file mode 100644 index 000000000..60aaeb7fb --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end.png Binary files differnew file mode 100644 index 000000000..08b5559b2 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end@2x.png Binary files differnew file mode 100644 index 000000000..ae6dbe991 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_disabled.png Binary files differnew file mode 100644 index 000000000..027a8894a --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_disabled@2x.png Binary files differnew file mode 100644 index 000000000..43c1b0c76 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_focus.png Binary files differnew file mode 100644 index 000000000..fdb3160bb --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_focus@2x.png Binary files differnew file mode 100644 index 000000000..3ca890449 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_pressed.png Binary files differnew file mode 100644 index 000000000..1c2432dd4 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_pressed@2x.png Binary files differnew file mode 100644 index 000000000..af0f8fa5a --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line.png Binary files differnew file mode 100644 index 000000000..a3a564e44 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line@2x.png Binary files differnew file mode 100644 index 000000000..1dbf71fc7 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_disabled.png Binary files differnew file mode 100644 index 000000000..ecc7e6d93 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_disabled@2x.png Binary files differnew file mode 100644 index 000000000..adc6446c9 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_focus.png Binary files differnew file mode 100644 index 000000000..0037f175a --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_focus@2x.png Binary files differnew file mode 100644 index 000000000..cb257a914 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_pressed.png Binary files differnew file mode 100644 index 000000000..2d0856527 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_pressed@2x.png Binary files differnew file mode 100644 index 000000000..803708fb4 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more.png Binary files differnew file mode 100644 index 000000000..31b6cee87 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more@2x.png Binary files differnew file mode 100644 index 000000000..f1f7a67f1 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_disabled.png Binary files differnew file mode 100644 index 000000000..d4b604905 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_disabled@2x.png Binary files differnew file mode 100644 index 000000000..3ef752108 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_focus.png Binary files differnew file mode 100644 index 000000000..943c13d0b --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_focus@2x.png Binary files differnew file mode 100644 index 000000000..9f53ef1fa --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_pressed.png Binary files differnew file mode 100644 index 000000000..9037ed3b3 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_pressed@2x.png Binary files differnew file mode 100644 index 000000000..675d52c76 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open-on.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open-on.png Binary files differnew file mode 100644 index 000000000..ec372b27d --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open-on.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open.png Binary files differnew file mode 100644 index 000000000..0861d0bc7 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open@2x.png Binary files differnew file mode 100644 index 000000000..8850f7367 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_disabled.png Binary files differnew file mode 100644 index 000000000..b6c80243b --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_disabled@2x.png Binary files differnew file mode 100644 index 000000000..15ce9f265 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_focus.png Binary files differnew file mode 100644 index 000000000..eadb0962a --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_focus@2x.png Binary files differnew file mode 100644 index 000000000..7dfcbbe8a --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_pressed.png Binary files differnew file mode 100644 index 000000000..2b22e8d08 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_pressed@2x.png Binary files differnew file mode 100644 index 000000000..269a0cbee --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked.png Binary files differnew file mode 100644 index 000000000..e7ed08081 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked@2x.png Binary files differnew file mode 100644 index 000000000..35f2ade58 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_disabled.png Binary files differnew file mode 100644 index 000000000..512b0a3e4 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_disabled@2x.png Binary files differnew file mode 100644 index 000000000..557383ec8 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_focus.png Binary files differnew file mode 100644 index 000000000..0b90412f2 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_focus@2x.png Binary files differnew file mode 100644 index 000000000..7aee03cbb --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_pressed.png Binary files differnew file mode 100644 index 000000000..3d4c869b7 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_pressed@2x.png Binary files differnew file mode 100644 index 000000000..bfbc14b94 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate.png Binary files differnew file mode 100644 index 000000000..c21ab99bf --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate@2x.png Binary files differnew file mode 100644 index 000000000..2fc29cee6 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_disabled.png Binary files differnew file mode 100644 index 000000000..1d3c21492 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_disabled@2x.png Binary files differnew file mode 100644 index 000000000..bb8e7a747 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_focus.png Binary files differnew file mode 100644 index 000000000..13ca4a7a4 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_focus@2x.png Binary files differnew file mode 100644 index 000000000..3907eb8d4 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_pressed.png Binary files differnew file mode 100644 index 000000000..12f83ceba --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_pressed@2x.png Binary files differnew file mode 100644 index 000000000..5ff4f6629 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked.png Binary files differnew file mode 100644 index 000000000..e2da452fa --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked@2x.png Binary files differnew file mode 100644 index 000000000..3732d5406 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_disabled.png Binary files differnew file mode 100644 index 000000000..c2e30c690 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_disabled@2x.png Binary files differnew file mode 100644 index 000000000..c4bddb6eb --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_focus.png Binary files differnew file mode 100644 index 000000000..c57f04d9f --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_focus@2x.png Binary files differnew file mode 100644 index 000000000..1776ad048 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_pressed.png Binary files differnew file mode 100644 index 000000000..be41236e1 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_pressed@2x.png Binary files differnew file mode 100644 index 000000000..b1ad7c72f --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/close-hover.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/close-hover.png Binary files differnew file mode 100644 index 000000000..657943a66 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/close-hover.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/close-pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/close-pressed.png Binary files differnew file mode 100644 index 000000000..937d00598 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/close-pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/close.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/close.png Binary files differnew file mode 100644 index 000000000..bc0f57610 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/close.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/down_arrow.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/down_arrow.png Binary files differnew file mode 100644 index 000000000..e271f7f90 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/down_arrow.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/down_arrow_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/down_arrow_disabled.png Binary files differnew file mode 100644 index 000000000..5805d9842 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/down_arrow_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/left_arrow.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/left_arrow.png Binary files differnew file mode 100644 index 000000000..f808d2d72 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/left_arrow.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/left_arrow_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/left_arrow_disabled.png Binary files differnew file mode 100644 index 000000000..f5b9af8a3 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/left_arrow_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal.png Binary files differnew file mode 100644 index 000000000..11bc5c003 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal@2x.png Binary files differnew file mode 100644 index 000000000..c229ac963 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_disabled.png Binary files differnew file mode 100644 index 000000000..204df8058 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_disabled@2x.png Binary files differnew file mode 100644 index 000000000..a4713c565 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_focus.png Binary files differnew file mode 100644 index 000000000..ecda0c10b --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_focus@2x.png Binary files differnew file mode 100644 index 000000000..84397efdb --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_pressed.png Binary files differnew file mode 100644 index 000000000..fd5d864ca --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_pressed@2x.png Binary files differnew file mode 100644 index 000000000..140552e4f --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical.png Binary files differnew file mode 100644 index 000000000..a3a564e44 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical@2x.png Binary files differnew file mode 100644 index 000000000..1dbf71fc7 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_disabled.png Binary files differnew file mode 100644 index 000000000..ecc7e6d93 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_disabled@2x.png Binary files differnew file mode 100644 index 000000000..adc6446c9 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_focus.png Binary files differnew file mode 100644 index 000000000..0037f175a --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_focus@2x.png Binary files differnew file mode 100644 index 000000000..cb257a914 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_pressed.png Binary files differnew file mode 100644 index 000000000..2d0856527 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_pressed@2x.png Binary files differnew file mode 100644 index 000000000..803708fb4 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked.png Binary files differnew file mode 100644 index 000000000..6f1fd6ca6 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked@2x.png Binary files differnew file mode 100644 index 000000000..228ffdbf2 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_disabled.png Binary files differnew file mode 100644 index 000000000..27788530d --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_disabled@2x.png Binary files differnew file mode 100644 index 000000000..930bfaf70 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_focus.png Binary files differnew file mode 100644 index 000000000..ca8e8bc9a --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_focus@2x.png Binary files differnew file mode 100644 index 000000000..aa0f1152b --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_pressed.png Binary files differnew file mode 100644 index 000000000..6e391a0ff --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_pressed@2x.png Binary files differnew file mode 100644 index 000000000..0512731ae --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked.png Binary files differnew file mode 100644 index 000000000..763306bdc --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked@2x.png Binary files differnew file mode 100644 index 000000000..28b6a0784 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_disabled.png Binary files differnew file mode 100644 index 000000000..fc0b12f78 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_disabled@2x.png Binary files differnew file mode 100644 index 000000000..d31f2b4b9 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_focus.png Binary files differnew file mode 100644 index 000000000..9c87b01e4 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_focus@2x.png Binary files differnew file mode 100644 index 000000000..4b4c7321d --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_pressed.png Binary files differnew file mode 100644 index 000000000..709e31633 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_pressed@2x.png Binary files differnew file mode 100644 index 000000000..b014de5f0 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/right_arrow.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/right_arrow.png Binary files differnew file mode 100644 index 000000000..9b0a4e6a7 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/right_arrow.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/right_arrow_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/right_arrow_disabled.png Binary files differnew file mode 100644 index 000000000..5c0bee402 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/right_arrow_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/sizegrip.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/sizegrip.png Binary files differnew file mode 100644 index 000000000..350583aaa --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/sizegrip.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/stylesheet-branch-end.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/stylesheet-branch-end.png Binary files differnew file mode 100644 index 000000000..cb5d3b51f --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/stylesheet-branch-end.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/stylesheet-branch-more.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/stylesheet-branch-more.png Binary files differnew file mode 100644 index 000000000..62711409d --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/stylesheet-branch-more.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/stylesheet-vline.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/stylesheet-vline.png Binary files differnew file mode 100644 index 000000000..87536cce1 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/stylesheet-vline.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal.png Binary files differnew file mode 100644 index 000000000..012ea2dfb --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal@2x.png Binary files differnew file mode 100644 index 000000000..520c34f98 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_disabled.png Binary files differnew file mode 100644 index 000000000..1f91df98f --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_disabled@2x.png Binary files differnew file mode 100644 index 000000000..738008f92 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_focus.png Binary files differnew file mode 100644 index 000000000..999b3c7d8 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_focus@2x.png Binary files differnew file mode 100644 index 000000000..f8e40b7d1 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_pressed.png Binary files differnew file mode 100644 index 000000000..c31b69deb --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_pressed@2x.png Binary files differnew file mode 100644 index 000000000..2f4cb41c7 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical.png Binary files differnew file mode 100644 index 000000000..16473bfd8 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical@2x.png Binary files differnew file mode 100644 index 000000000..90a5caee3 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_disabled.png Binary files differnew file mode 100644 index 000000000..2d240edb5 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_disabled@2x.png Binary files differnew file mode 100644 index 000000000..fd1df30f1 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_focus.png Binary files differnew file mode 100644 index 000000000..58cda1f80 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_focus@2x.png Binary files differnew file mode 100644 index 000000000..9222b4fd8 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_pressed.png Binary files differnew file mode 100644 index 000000000..e7d641926 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_pressed@2x.png Binary files differnew file mode 100644 index 000000000..9c438faf4 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal.png Binary files differnew file mode 100644 index 000000000..3c0acbdcc --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal@2x.png Binary files differnew file mode 100644 index 000000000..fb4e24c88 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_disabled.png Binary files differnew file mode 100644 index 000000000..32f7e8ca6 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_disabled@2x.png Binary files differnew file mode 100644 index 000000000..f7bec188b --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_focus.png Binary files differnew file mode 100644 index 000000000..91c19d65c --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_focus@2x.png Binary files differnew file mode 100644 index 000000000..c4829918d --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_pressed.png Binary files differnew file mode 100644 index 000000000..7a7f91737 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_pressed@2x.png Binary files differnew file mode 100644 index 000000000..d65773b48 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical.png Binary files differnew file mode 100644 index 000000000..4dde3f37f --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical@2x.png Binary files differnew file mode 100644 index 000000000..fe97c0de3 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_disabled.png Binary files differnew file mode 100644 index 000000000..7426ae2de --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_disabled@2x.png Binary files differnew file mode 100644 index 000000000..7acc6d33e --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_focus.png Binary files differnew file mode 100644 index 000000000..6e3c12143 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_focus@2x.png Binary files differnew file mode 100644 index 000000000..cac3a56c2 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_pressed.png Binary files differnew file mode 100644 index 000000000..b777784b8 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_pressed@2x.png Binary files differnew file mode 100644 index 000000000..7ed878fd3 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent.png Binary files differnew file mode 100644 index 000000000..8b241c4a4 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent@2x.png Binary files differnew file mode 100644 index 000000000..2c3df7a5e --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_disabled.png Binary files differnew file mode 100644 index 000000000..8b241c4a4 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_disabled@2x.png Binary files differnew file mode 100644 index 000000000..2c3df7a5e --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_focus.png Binary files differnew file mode 100644 index 000000000..8b241c4a4 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_focus@2x.png Binary files differnew file mode 100644 index 000000000..2c3df7a5e --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_pressed.png Binary files differnew file mode 100644 index 000000000..8b241c4a4 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_pressed@2x.png Binary files differnew file mode 100644 index 000000000..2c3df7a5e --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/undock.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/undock.png Binary files differnew file mode 100644 index 000000000..88691d779 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/undock.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/up_arrow.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/up_arrow.png Binary files differnew file mode 100644 index 000000000..abcc72452 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/up_arrow.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/up_arrow_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/up_arrow_disabled.png Binary files differnew file mode 100644 index 000000000..b9c8e3b53 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/up_arrow_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close.png Binary files differnew file mode 100644 index 000000000..6f55c3ae7 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close@2x.png Binary files differnew file mode 100644 index 000000000..ff644f2e8 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_disabled.png Binary files differnew file mode 100644 index 000000000..22694e31d --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_disabled@2x.png Binary files differnew file mode 100644 index 000000000..ebc97db70 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_focus.png Binary files differnew file mode 100644 index 000000000..f017eda31 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_focus@2x.png Binary files differnew file mode 100644 index 000000000..5a354d796 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_pressed.png Binary files differnew file mode 100644 index 000000000..04b922dd0 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_pressed@2x.png Binary files differnew file mode 100644 index 000000000..58c0bf592 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip.png Binary files differnew file mode 100644 index 000000000..0528049bb --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip@2x.png Binary files differnew file mode 100644 index 000000000..1ca1b073c --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_disabled.png Binary files differnew file mode 100644 index 000000000..15f55c056 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_disabled@2x.png Binary files differnew file mode 100644 index 000000000..33a4588e8 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_focus.png Binary files differnew file mode 100644 index 000000000..06e76c31f --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_focus@2x.png Binary files differnew file mode 100644 index 000000000..58c2d06e4 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_pressed.png Binary files differnew file mode 100644 index 000000000..b3a566cdb --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_pressed@2x.png Binary files differnew file mode 100644 index 000000000..e9da94049 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize.png Binary files differnew file mode 100644 index 000000000..f60981615 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize@2x.png Binary files differnew file mode 100644 index 000000000..30f728f02 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_disabled.png Binary files differnew file mode 100644 index 000000000..29db1c9b1 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_disabled@2x.png Binary files differnew file mode 100644 index 000000000..1572ca2fe --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_focus.png Binary files differnew file mode 100644 index 000000000..cb592f598 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_focus@2x.png Binary files differnew file mode 100644 index 000000000..6f6465169 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_pressed.png Binary files differnew file mode 100644 index 000000000..6962440ac --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_pressed@2x.png Binary files differnew file mode 100644 index 000000000..cb028272b --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock.png Binary files differnew file mode 100644 index 000000000..616da991a --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock@2x.png Binary files differnew file mode 100644 index 000000000..511036bf2 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_disabled.png Binary files differnew file mode 100644 index 000000000..a2b3d25b2 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_disabled.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_disabled@2x.png Binary files differnew file mode 100644 index 000000000..638ec8104 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_disabled@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_focus.png Binary files differnew file mode 100644 index 000000000..ae6dc4a60 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_focus.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_focus@2x.png Binary files differnew file mode 100644 index 000000000..d06dd1eac --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_focus@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_pressed.png Binary files differnew file mode 100644 index 000000000..e9142ded2 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_pressed.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_pressed@2x.png Binary files differnew file mode 100644 index 000000000..a597420f3 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_pressed@2x.png diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc b/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc new file mode 100644 index 000000000..1b7686f15 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc @@ -0,0 +1,225 @@ +<RCC> + <qresource prefix="icons/qdarkstyle_midnight_blue"> + <file alias="index.theme">icons/index.theme</file> + <file alias="16x16/lock.png">icons/16x16/lock.png</file> + <file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file> + <file alias="48x48/chip.png">icons/48x48/chip.png</file> + <file alias="48x48/folder.png">icons/48x48/folder.png</file> + <file alias="48x48/plus.png">icons/48x48/plus.png</file> + <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file> + <file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file> + </qresource> + <qresource prefix="qss_icons"> + <file>rc/arrow_down.png</file> + <file>rc/arrow_down@2x.png</file> + <file>rc/arrow_down_disabled.png</file> + <file>rc/arrow_down_disabled@2x.png</file> + <file>rc/arrow_down_focus.png</file> + <file>rc/arrow_down_focus@2x.png</file> + <file>rc/arrow_down_pressed.png</file> + <file>rc/arrow_down_pressed@2x.png</file> + <file>rc/arrow_left.png</file> + <file>rc/arrow_left@2x.png</file> + <file>rc/arrow_left_disabled.png</file> + <file>rc/arrow_left_disabled@2x.png</file> + <file>rc/arrow_left_focus.png</file> + <file>rc/arrow_left_focus@2x.png</file> + <file>rc/arrow_left_pressed.png</file> + <file>rc/arrow_left_pressed@2x.png</file> + <file>rc/arrow_right.png</file> + <file>rc/arrow_right@2x.png</file> + <file>rc/arrow_right_disabled.png</file> + <file>rc/arrow_right_disabled@2x.png</file> + <file>rc/arrow_right_focus.png</file> + <file>rc/arrow_right_focus@2x.png</file> + <file>rc/arrow_right_pressed.png</file> + <file>rc/arrow_right_pressed@2x.png</file> + <file>rc/arrow_up.png</file> + <file>rc/arrow_up@2x.png</file> + <file>rc/arrow_up_disabled.png</file> + <file>rc/arrow_up_disabled@2x.png</file> + <file>rc/arrow_up_focus.png</file> + <file>rc/arrow_up_focus@2x.png</file> + <file>rc/arrow_up_pressed.png</file> + <file>rc/arrow_up_pressed@2x.png</file> + <file>rc/base_icon.png</file> + <file>rc/base_icon@2x.png</file> + <file>rc/base_icon_disabled.png</file> + <file>rc/base_icon_disabled@2x.png</file> + <file>rc/base_icon_focus.png</file> + <file>rc/base_icon_focus@2x.png</file> + <file>rc/base_icon_pressed.png</file> + <file>rc/base_icon_pressed@2x.png</file> + <file>rc/branch_closed.png</file> + <file>rc/branch_closed@2x.png</file> + <file>rc/branch_closed_disabled.png</file> + <file>rc/branch_closed_disabled@2x.png</file> + <file>rc/branch_closed_focus.png</file> + <file>rc/branch_closed_focus@2x.png</file> + <file>rc/branch_closed_pressed.png</file> + <file>rc/branch_closed_pressed@2x.png</file> + <file>rc/branch_end.png</file> + <file>rc/branch_end@2x.png</file> + <file>rc/branch_end_disabled.png</file> + <file>rc/branch_end_disabled@2x.png</file> + <file>rc/branch_end_focus.png</file> + <file>rc/branch_end_focus@2x.png</file> + <file>rc/branch_end_pressed.png</file> + <file>rc/branch_end_pressed@2x.png</file> + <file>rc/branch_line.png</file> + <file>rc/branch_line@2x.png</file> + <file>rc/branch_line_disabled.png</file> + <file>rc/branch_line_disabled@2x.png</file> + <file>rc/branch_line_focus.png</file> + <file>rc/branch_line_focus@2x.png</file> + <file>rc/branch_line_pressed.png</file> + <file>rc/branch_line_pressed@2x.png</file> + <file>rc/branch_more.png</file> + <file>rc/branch_more@2x.png</file> + <file>rc/branch_more_disabled.png</file> + <file>rc/branch_more_disabled@2x.png</file> + <file>rc/branch_more_focus.png</file> + <file>rc/branch_more_focus@2x.png</file> + <file>rc/branch_more_pressed.png</file> + <file>rc/branch_more_pressed@2x.png</file> + <file>rc/branch_open.png</file> + <file>rc/branch_open@2x.png</file> + <file>rc/branch_open_disabled.png</file> + <file>rc/branch_open_disabled@2x.png</file> + <file>rc/branch_open_focus.png</file> + <file>rc/branch_open_focus@2x.png</file> + <file>rc/branch_open_pressed.png</file> + <file>rc/branch_open_pressed@2x.png</file> + <file>rc/checkbox_checked.png</file> + <file>rc/checkbox_checked@2x.png</file> + <file>rc/checkbox_checked_disabled.png</file> + <file>rc/checkbox_checked_disabled@2x.png</file> + <file>rc/checkbox_checked_focus.png</file> + <file>rc/checkbox_checked_focus@2x.png</file> + <file>rc/checkbox_checked_pressed.png</file> + <file>rc/checkbox_checked_pressed@2x.png</file> + <file>rc/checkbox_indeterminate.png</file> + <file>rc/checkbox_indeterminate@2x.png</file> + <file>rc/checkbox_indeterminate_disabled.png</file> + <file>rc/checkbox_indeterminate_disabled@2x.png</file> + <file>rc/checkbox_indeterminate_focus.png</file> + <file>rc/checkbox_indeterminate_focus@2x.png</file> + <file>rc/checkbox_indeterminate_pressed.png</file> + <file>rc/checkbox_indeterminate_pressed@2x.png</file> + <file>rc/checkbox_unchecked.png</file> + <file>rc/checkbox_unchecked@2x.png</file> + <file>rc/checkbox_unchecked_disabled.png</file> + <file>rc/checkbox_unchecked_disabled@2x.png</file> + <file>rc/checkbox_unchecked_focus.png</file> + <file>rc/checkbox_unchecked_focus@2x.png</file> + <file>rc/checkbox_unchecked_pressed.png</file> + <file>rc/checkbox_unchecked_pressed@2x.png</file> + <file>rc/line_horizontal.png</file> + <file>rc/line_horizontal@2x.png</file> + <file>rc/line_horizontal_disabled.png</file> + <file>rc/line_horizontal_disabled@2x.png</file> + <file>rc/line_horizontal_focus.png</file> + <file>rc/line_horizontal_focus@2x.png</file> + <file>rc/line_horizontal_pressed.png</file> + <file>rc/line_horizontal_pressed@2x.png</file> + <file>rc/line_vertical.png</file> + <file>rc/line_vertical@2x.png</file> + <file>rc/line_vertical_disabled.png</file> + <file>rc/line_vertical_disabled@2x.png</file> + <file>rc/line_vertical_focus.png</file> + <file>rc/line_vertical_focus@2x.png</file> + <file>rc/line_vertical_pressed.png</file> + <file>rc/line_vertical_pressed@2x.png</file> + <file>rc/radio_checked.png</file> + <file>rc/radio_checked@2x.png</file> + <file>rc/radio_checked_disabled.png</file> + <file>rc/radio_checked_disabled@2x.png</file> + <file>rc/radio_checked_focus.png</file> + <file>rc/radio_checked_focus@2x.png</file> + <file>rc/radio_checked_pressed.png</file> + <file>rc/radio_checked_pressed@2x.png</file> + <file>rc/radio_unchecked.png</file> + <file>rc/radio_unchecked@2x.png</file> + <file>rc/radio_unchecked_disabled.png</file> + <file>rc/radio_unchecked_disabled@2x.png</file> + <file>rc/radio_unchecked_focus.png</file> + <file>rc/radio_unchecked_focus@2x.png</file> + <file>rc/radio_unchecked_pressed.png</file> + <file>rc/radio_unchecked_pressed@2x.png</file> + <file>rc/toolbar_move_horizontal.png</file> + <file>rc/toolbar_move_horizontal@2x.png</file> + <file>rc/toolbar_move_horizontal_disabled.png</file> + <file>rc/toolbar_move_horizontal_disabled@2x.png</file> + <file>rc/toolbar_move_horizontal_focus.png</file> + <file>rc/toolbar_move_horizontal_focus@2x.png</file> + <file>rc/toolbar_move_horizontal_pressed.png</file> + <file>rc/toolbar_move_horizontal_pressed@2x.png</file> + <file>rc/toolbar_move_vertical.png</file> + <file>rc/toolbar_move_vertical@2x.png</file> + <file>rc/toolbar_move_vertical_disabled.png</file> + <file>rc/toolbar_move_vertical_disabled@2x.png</file> + <file>rc/toolbar_move_vertical_focus.png</file> + <file>rc/toolbar_move_vertical_focus@2x.png</file> + <file>rc/toolbar_move_vertical_pressed.png</file> + <file>rc/toolbar_move_vertical_pressed@2x.png</file> + <file>rc/toolbar_separator_horizontal.png</file> + <file>rc/toolbar_separator_horizontal@2x.png</file> + <file>rc/toolbar_separator_horizontal_disabled.png</file> + <file>rc/toolbar_separator_horizontal_disabled@2x.png</file> + <file>rc/toolbar_separator_horizontal_focus.png</file> + <file>rc/toolbar_separator_horizontal_focus@2x.png</file> + <file>rc/toolbar_separator_horizontal_pressed.png</file> + <file>rc/toolbar_separator_horizontal_pressed@2x.png</file> + <file>rc/toolbar_separator_vertical.png</file> + <file>rc/toolbar_separator_vertical@2x.png</file> + <file>rc/toolbar_separator_vertical_disabled.png</file> + <file>rc/toolbar_separator_vertical_disabled@2x.png</file> + <file>rc/toolbar_separator_vertical_focus.png</file> + <file>rc/toolbar_separator_vertical_focus@2x.png</file> + <file>rc/toolbar_separator_vertical_pressed.png</file> + <file>rc/toolbar_separator_vertical_pressed@2x.png</file> + <file>rc/transparent.png</file> + <file>rc/transparent@2x.png</file> + <file>rc/transparent_disabled.png</file> + <file>rc/transparent_disabled@2x.png</file> + <file>rc/transparent_focus.png</file> + <file>rc/transparent_focus@2x.png</file> + <file>rc/transparent_pressed.png</file> + <file>rc/transparent_pressed@2x.png</file> + <file>rc/window_close.png</file> + <file>rc/window_close@2x.png</file> + <file>rc/window_close_disabled.png</file> + <file>rc/window_close_disabled@2x.png</file> + <file>rc/window_close_focus.png</file> + <file>rc/window_close_focus@2x.png</file> + <file>rc/window_close_pressed.png</file> + <file>rc/window_close_pressed@2x.png</file> + <file>rc/window_grip.png</file> + <file>rc/window_grip@2x.png</file> + <file>rc/window_grip_disabled.png</file> + <file>rc/window_grip_disabled@2x.png</file> + <file>rc/window_grip_focus.png</file> + <file>rc/window_grip_focus@2x.png</file> + <file>rc/window_grip_pressed.png</file> + <file>rc/window_grip_pressed@2x.png</file> + <file>rc/window_minimize.png</file> + <file>rc/window_minimize@2x.png</file> + <file>rc/window_minimize_disabled.png</file> + <file>rc/window_minimize_disabled@2x.png</file> + <file>rc/window_minimize_focus.png</file> + <file>rc/window_minimize_focus@2x.png</file> + <file>rc/window_minimize_pressed.png</file> + <file>rc/window_minimize_pressed@2x.png</file> + <file>rc/window_undock.png</file> + <file>rc/window_undock@2x.png</file> + <file>rc/window_undock_disabled.png</file> + <file>rc/window_undock_disabled@2x.png</file> + <file>rc/window_undock_focus.png</file> + <file>rc/window_undock_focus@2x.png</file> + <file>rc/window_undock_pressed.png</file> + <file>rc/window_undock_pressed@2x.png</file> + </qresource> + <qresource prefix="qdarkstyle_midnight_blue"> + <file>style.qss</file> + </qresource> +</RCC> diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss new file mode 100644 index 000000000..be645c907 --- /dev/null +++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss @@ -0,0 +1,2175 @@ +/* --------------------------------------------------------------------------- + + Created by the qtsass compiler v0.1.1 + + The definitions are in the "qdarkstyle.qss._styles.scss" module + + WARNING! All changes made in this file will be lost! + +--------------------------------------------------------------------------- */ +/* QDarkStyleSheet ----------------------------------------------------------- + +This is the main style sheet, the palette has nine colors. + +It is based on three selecting colors, three greyish (background) colors +plus three whitish (foreground) colors. Each set of widgets of the same +type have a header like this: + + ------------------ + GroupName -------- + ------------------ + +And each widget is separated with a header like this: + + QWidgetName ------ + +This makes more easy to find and change some css field. The basic +configuration is described bellow. + + BACKGROUND ----------- + + Light (unpressed) + Normal (border, disabled, pressed, checked, toolbars, menus) + Dark (background) + + FOREGROUND ----------- + + Light (texts/labels) + Normal (not used yet) + Dark (disabled texts) + + SELECTION ------------ + + Light (selection/hover/active) + Normal (selected) + Dark (selected disabled) + +If a stranger configuration is required because of a bugfix or anything +else, keep the comment on the line above so nobody changes it, including the +issue number. + +*/ +/* + +See Qt documentation: + + - https://doc.qt.io/qt-5/stylesheet.html + - https://doc.qt.io/qt-5/stylesheet-reference.html + - https://doc.qt.io/qt-5/stylesheet-examples.html + +--------------------------------------------------------------------------- */ +/* QWidget ---------------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QWidget { + background-color: #19232D; + border: 0px solid #32414B; + padding: 0px; + color: #F0F0F0; + selection-background-color: #1464A0; + selection-color: #F0F0F0; +} + +QWidget:disabled { + background-color: #19232D; + color: #787878; + selection-background-color: #14506E; + selection-color: #787878; +} + +QWidget::item:selected { + background-color: #1464A0; +} + +QWidget::item:hover { + background-color: #148CD2; + color: #32414B; +} + +/* QMainWindow ------------------------------------------------------------ + +This adjusts the splitter in the dock widget, not qsplitter +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmainwindow + +--------------------------------------------------------------------------- */ +QMainWindow::separator { + background-color: #32414B; + border: 0px solid #19232D; + spacing: 0px; + padding: 2px; +} + +QMainWindow::separator:hover { + background-color: #505F69; + border: 0px solid #148CD2; +} + +QMainWindow::separator:horizontal { + width: 5px; + margin-top: 2px; + margin-bottom: 2px; + image: url(":/qss_icons/rc/toolbar_separator_vertical.png"); +} + +QMainWindow::separator:vertical { + height: 5px; + margin-left: 2px; + margin-right: 2px; + image: url(":/qss_icons/rc/toolbar_separator_horizontal.png"); +} + +/* QToolTip --------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtooltip + +--------------------------------------------------------------------------- */ +QToolTip { + background-color: #148CD2; + border: 1px solid #19232D; + color: #19232D; + /* Remove padding, for fix combo box tooltip */ + padding: 0px; + /* Remove opacity, fix #174 - may need to use RGBA */ +} + +/* QStatusBar ------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qstatusbar + +--------------------------------------------------------------------------- */ +QStatusBar { + border: 1px solid #32414B; + /* Fixes Spyder #9120, #9121 */ + background: #32414B; + /* Fixes #205, white vertical borders separating items */ +} + +QStatusBar::item { + border: none; +} + +QStatusBar QToolTip { + background-color: #148CD2; + border: 1px solid #19232D; + color: #19232D; + /* Remove padding, for fix combo box tooltip */ + padding: 0px; + /* Reducing transparency to read better */ + opacity: 230; +} + +QStatusBar QLabel { + /* Fixes Spyder #9120, #9121 */ + background: transparent; +} + +/* QCheckBox -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcheckbox + +--------------------------------------------------------------------------- */ +QCheckBox { + background-color: #19232D; + color: #F0F0F0; + spacing: 4px; + outline: none; + padding-top: 4px; + padding-bottom: 4px; +} + +QCheckBox:focus { + border: none; +} + +QCheckBox QWidget:disabled { + background-color: #19232D; + color: #787878; +} + +QCheckBox::indicator { + margin-left: 4px; + height: 16px; + width: 16px; +} + +QCheckBox::indicator:unchecked { + image: url(":/qss_icons/rc/checkbox_unchecked.png"); +} + +QCheckBox::indicator:unchecked:hover, QCheckBox::indicator:unchecked:focus, QCheckBox::indicator:unchecked:pressed { + border: none; + image: url(":/qss_icons/rc/checkbox_unchecked_focus.png"); +} + +QCheckBox::indicator:unchecked:disabled { + image: url(":/qss_icons/rc/checkbox_unchecked_disabled.png"); +} + +QCheckBox::indicator:checked { + image: url(":/qss_icons/rc/checkbox_checked.png"); +} + +QCheckBox::indicator:checked:hover, QCheckBox::indicator:checked:focus, QCheckBox::indicator:checked:pressed { + border: none; + image: url(":/qss_icons/rc/checkbox_checked_focus.png"); +} + +QCheckBox::indicator:checked:disabled { + image: url(":/qss_icons/rc/checkbox_checked_disabled.png"); +} + +QCheckBox::indicator:indeterminate { + image: url(":/qss_icons/rc/checkbox_indeterminate.png"); +} + +QCheckBox::indicator:indeterminate:disabled { + image: url(":/qss_icons/rc/checkbox_indeterminate_disabled.png"); +} + +QCheckBox::indicator:indeterminate:focus, QCheckBox::indicator:indeterminate:hover, QCheckBox::indicator:indeterminate:pressed { + image: url(":/qss_icons/rc/checkbox_indeterminate_focus.png"); +} + +/* QGroupBox -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox + +--------------------------------------------------------------------------- */ +QGroupBox { + font-weight: bold; + border: 1px solid #32414B; + border-radius: 4px; + padding: 4px; + margin-top: 16px; +} + +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; + left: 3px; + padding-left: 3px; + padding-right: 5px; + padding-top: 8px; + padding-bottom: 16px; +} + +QGroupBox::indicator { + margin-left: 2px; + height: 16px; + width: 16px; +} + +QGroupBox::indicator:unchecked { + border: none; + image: url(":/qss_icons/rc/checkbox_unchecked.png"); +} + +QGroupBox::indicator:unchecked:hover, QGroupBox::indicator:unchecked:focus, QGroupBox::indicator:unchecked:pressed { + border: none; + image: url(":/qss_icons/rc/checkbox_unchecked_focus.png"); +} + +QGroupBox::indicator:unchecked:disabled { + image: url(":/qss_icons/rc/checkbox_unchecked_disabled.png"); +} + +QGroupBox::indicator:checked { + border: none; + image: url(":/qss_icons/rc/checkbox_checked.png"); +} + +QGroupBox::indicator:checked:hover, QGroupBox::indicator:checked:focus, QGroupBox::indicator:checked:pressed { + border: none; + image: url(":/qss_icons/rc/checkbox_checked_focus.png"); +} + +QGroupBox::indicator:checked:disabled { + image: url(":/qss_icons/rc/checkbox_checked_disabled.png"); +} + +/* QRadioButton ----------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qradiobutton + +--------------------------------------------------------------------------- */ +QRadioButton { + background-color: #19232D; + color: #F0F0F0; + spacing: 4px; + padding: 0px; + border: none; + outline: none; +} + +QRadioButton:focus { + border: none; +} + +QRadioButton:disabled { + background-color: #19232D; + color: #787878; + border: none; + outline: none; +} + +QRadioButton QWidget { + background-color: #19232D; + color: #F0F0F0; + spacing: 0px; + padding: 0px; + outline: none; + border: none; +} + +QRadioButton::indicator { + border: none; + outline: none; + margin-left: 4px; + height: 16px; + width: 16px; +} + +QRadioButton::indicator:unchecked { + image: url(":/qss_icons/rc/radio_unchecked.png"); +} + +QRadioButton::indicator:unchecked:hover, QRadioButton::indicator:unchecked:focus, QRadioButton::indicator:unchecked:pressed { + border: none; + outline: none; + image: url(":/qss_icons/rc/radio_unchecked_focus.png"); +} + +QRadioButton::indicator:unchecked:disabled { + image: url(":/qss_icons/rc/radio_unchecked_disabled.png"); +} + +QRadioButton::indicator:checked { + border: none; + outline: none; + image: url(":/qss_icons/rc/radio_checked.png"); +} + +QRadioButton::indicator:checked:hover, QRadioButton::indicator:checked:focus, QRadioButton::indicator:checked:pressed { + border: none; + outline: none; + image: url(":/qss_icons/rc/radio_checked_focus.png"); +} + +QRadioButton::indicator:checked:disabled { + outline: none; + image: url(":/qss_icons/rc/radio_checked_disabled.png"); +} + +/* QMenuBar --------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenubar + +--------------------------------------------------------------------------- */ +QMenuBar { + background-color: #32414B; + padding: 2px; + border: 1px solid #19232D; + color: #F0F0F0; +} + +QMenuBar:focus { + border: 1px solid #148CD2; +} + +QMenuBar::item { + background: transparent; + padding: 4px; +} + +QMenuBar::item:selected { + padding: 4px; + background: transparent; + border: 0px solid #32414B; +} + +QMenuBar::item:pressed { + padding: 4px; + border: 0px solid #32414B; + background-color: #148CD2; + color: #F0F0F0; + margin-bottom: 0px; + padding-bottom: 0px; +} + +/* QMenu ------------------------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenu + +--------------------------------------------------------------------------- */ +QMenu { + border: 0px solid #32414B; + color: #F0F0F0; + margin: 0px; +} + +QMenu::separator { + height: 1px; + background-color: #505F69; + color: #F0F0F0; +} + +QMenu::icon { + margin: 0px; + padding-left: 8px; +} + +QMenu::item { + background-color: #32414B; + padding: 4px 24px 4px 24px; + /* Reserve space for selection border */ + border: 1px transparent #32414B; +} + +QMenu::item:selected { + color: #F0F0F0; +} + +QMenu::indicator { + width: 12px; + height: 12px; + padding-left: 6px; + /* non-exclusive indicator = check box style indicator (see QActionGroup::setExclusive) */ + /* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */ +} + +QMenu::indicator:non-exclusive:unchecked { + image: url(":/qss_icons/rc/checkbox_unchecked.png"); +} + +QMenu::indicator:non-exclusive:unchecked:selected { + image: url(":/qss_icons/rc/checkbox_unchecked_disabled.png"); +} + +QMenu::indicator:non-exclusive:checked { + image: url(":/qss_icons/rc/checkbox_checked.png"); +} + +QMenu::indicator:non-exclusive:checked:selected { + image: url(":/qss_icons/rc/checkbox_checked_disabled.png"); +} + +QMenu::indicator:exclusive:unchecked { + image: url(":/qss_icons/rc/radio_unchecked.png"); +} + +QMenu::indicator:exclusive:unchecked:selected { + image: url(":/qss_icons/rc/radio_unchecked_disabled.png"); +} + +QMenu::indicator:exclusive:checked { + image: url(":/qss_icons/rc/radio_checked.png"); +} + +QMenu::indicator:exclusive:checked:selected { + image: url(":/qss_icons/rc/radio_checked_disabled.png"); +} + +QMenu::right-arrow { + margin: 5px; + image: url(":/qss_icons/rc/arrow_right.png"); + height: 12px; + width: 12px; +} + +/* QAbstractItemView ------------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox + +--------------------------------------------------------------------------- */ +QAbstractItemView { + alternate-background-color: #19232D; + color: #F0F0F0; + border: 1px solid #32414B; + border-radius: 4px; +} + +QAbstractItemView QLineEdit { + padding: 2px; +} + +/* QAbstractScrollArea ---------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea + +--------------------------------------------------------------------------- */ +QAbstractScrollArea { + background-color: #19232D; + border: 1px solid #32414B; + border-radius: 4px; + padding: 2px; + /* fix #159 */ + min-height: 1.25em; + /* fix #159 */ + color: #F0F0F0; +} + +QAbstractScrollArea:disabled { + color: #787878; +} + +/* QScrollArea ------------------------------------------------------------ + +--------------------------------------------------------------------------- */ +QScrollArea QWidget QWidget:disabled { + background-color: #19232D; +} + +/* QScrollBar ------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qscrollbar + +--------------------------------------------------------------------------- */ +QScrollBar:horizontal { + height: 16px; + margin: 2px 16px 2px 16px; + border: 1px solid #32414B; + border-radius: 4px; + background-color: #19232D; +} + +QScrollBar:vertical { + background-color: #19232D; + width: 16px; + margin: 16px 2px 16px 2px; + border: 1px solid #32414B; + border-radius: 4px; +} + +QScrollBar::handle:horizontal { + background-color: #787878; + border: 1px solid #32414B; + border-radius: 4px; + min-width: 8px; +} + +QScrollBar::handle:horizontal:hover { + background-color: #148CD2; + border: 1px solid #148CD2; + border-radius: 4px; + min-width: 8px; +} + +QScrollBar::handle:horizontal:focus { + border: 1px solid #1464A0; +} + +QScrollBar::handle:vertical { + background-color: #787878; + border: 1px solid #32414B; + min-height: 8px; + border-radius: 4px; +} + +QScrollBar::handle:vertical:hover { + background-color: #148CD2; + border: 1px solid #148CD2; + border-radius: 4px; + min-height: 8px; +} + +QScrollBar::handle:vertical:focus { + border: 1px solid #1464A0; +} + +QScrollBar::add-line:horizontal { + margin: 0px 0px 0px 0px; + border-image: url(":/qss_icons/rc/arrow_right_disabled.png"); + height: 12px; + width: 12px; + subcontrol-position: right; + subcontrol-origin: margin; +} + +QScrollBar::add-line:horizontal:hover, QScrollBar::add-line:horizontal:on { + border-image: url(":/qss_icons/rc/arrow_right.png"); + height: 12px; + width: 12px; + subcontrol-position: right; + subcontrol-origin: margin; +} + +QScrollBar::add-line:vertical { + margin: 3px 0px 3px 0px; + border-image: url(":/qss_icons/rc/arrow_down_disabled.png"); + height: 12px; + width: 12px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on { + border-image: url(":/qss_icons/rc/arrow_down.png"); + height: 12px; + width: 12px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:horizontal { + margin: 0px 3px 0px 3px; + border-image: url(":/qss_icons/rc/arrow_left_disabled.png"); + height: 12px; + width: 12px; + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on { + border-image: url(":/qss_icons/rc/arrow_left.png"); + height: 12px; + width: 12px; + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:vertical { + margin: 3px 0px 3px 0px; + border-image: url(":/qss_icons/rc/arrow_up_disabled.png"); + height: 12px; + width: 12px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:vertical:hover, QScrollBar::sub-line:vertical:on { + border-image: url(":/qss_icons/rc/arrow_up.png"); + height: 12px; + width: 12px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal { + background: none; +} + +QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical { + background: none; +} + +QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { + background: none; +} + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + background: none; +} + +/* QTextEdit -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-specific-widgets + +--------------------------------------------------------------------------- */ +QTextEdit { + background-color: #19232D; + color: #F0F0F0; + border-radius: 4px; + border: 1px solid #32414B; +} + +QTextEdit:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QTextEdit:focus { + border: 1px solid #1464A0; +} + +QTextEdit:selected { + background: #1464A0; + color: #32414B; +} + +/* QPlainTextEdit --------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QPlainTextEdit { + background-color: #19232D; + color: #F0F0F0; + border-radius: 4px; + border: 1px solid #32414B; +} + +QPlainTextEdit:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QPlainTextEdit:focus { + border: 1px solid #1464A0; +} + +QPlainTextEdit:selected { + background: #1464A0; + color: #32414B; +} + +/* QSizeGrip -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsizegrip + +--------------------------------------------------------------------------- */ +QSizeGrip { + background: transparent; + width: 12px; + height: 12px; + image: url(":/qss_icons/rc/window_grip.png"); +} + +/* QStackedWidget --------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QStackedWidget { + padding: 2px; + border: 1px solid #32414B; + border: 1px solid #19232D; +} + +/* QToolBar --------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbar + +--------------------------------------------------------------------------- */ +QToolBar { + background-color: #32414B; + border-bottom: 1px solid #19232D; + padding: 2px; + font-weight: bold; + spacing: 2px; +} + +QToolBar QToolButton { + background-color: #32414B; + border: 1px solid #32414B; +} + +QToolBar QToolButton:hover { + border: 1px solid #148CD2; +} + +QToolBar QToolButton:checked { + border: 1px solid #19232D; + background-color: #19232D; +} + +QToolBar QToolButton:checked:hover { + border: 1px solid #148CD2; +} + +QToolBar::handle:horizontal { + width: 16px; + image: url(":/qss_icons/rc/toolbar_move_horizontal.png"); +} + +QToolBar::handle:vertical { + height: 16px; + image: url(":/qss_icons/rc/toolbar_move_vertical.png"); +} + +QToolBar::separator:horizontal { + width: 16px; + image: url(":/qss_icons/rc/toolbar_separator_horizontal.png"); +} + +QToolBar::separator:vertical { + height: 16px; + image: url(":/qss_icons/rc/toolbar_separator_vertical.png"); +} + +QToolButton#qt_toolbar_ext_button { + background: #32414B; + border: 0px; + color: #F0F0F0; + image: url(":/qss_icons/rc/arrow_right.png"); +} + +/* QAbstractSpinBox ------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QAbstractSpinBox { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + /* This fixes 103, 111 */ + padding-top: 2px; + /* This fixes 103, 111 */ + padding-bottom: 2px; + padding-left: 4px; + padding-right: 4px; + border-radius: 4px; + /* min-width: 5px; removed to fix 109 */ +} + +QAbstractSpinBox:up-button { + background-color: transparent #19232D; + subcontrol-origin: border; + subcontrol-position: top right; + border-left: 1px solid #32414B; + border-bottom: 1px solid #32414B; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + margin: 1px; + width: 12px; + margin-bottom: -1px; +} + +QAbstractSpinBox::up-arrow, QAbstractSpinBox::up-arrow:disabled, QAbstractSpinBox::up-arrow:off { + image: url(":/qss_icons/rc/arrow_up_disabled.png"); + height: 8px; + width: 8px; +} + +QAbstractSpinBox::up-arrow:hover { + image: url(":/qss_icons/rc/arrow_up.png"); +} + +QAbstractSpinBox:down-button { + background-color: transparent #19232D; + subcontrol-origin: border; + subcontrol-position: bottom right; + border-left: 1px solid #32414B; + border-top: 1px solid #32414B; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + margin: 1px; + width: 12px; + margin-top: -1px; +} + +QAbstractSpinBox::down-arrow, QAbstractSpinBox::down-arrow:disabled, QAbstractSpinBox::down-arrow:off { + image: url(":/qss_icons/rc/arrow_down_disabled.png"); + height: 8px; + width: 8px; +} + +QAbstractSpinBox::down-arrow:hover { + image: url(":/qss_icons/rc/arrow_down.png"); +} + +QAbstractSpinBox:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QAbstractSpinBox:focus { + border: 1px solid #1464A0; +} + +QAbstractSpinBox:selected { + background: #1464A0; + color: #32414B; +} + +/* ------------------------------------------------------------------------ */ +/* DISPLAYS --------------------------------------------------------------- */ +/* ------------------------------------------------------------------------ */ +/* QLabel ----------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe + +--------------------------------------------------------------------------- */ +QLabel { + background-color: #19232D; + border: 0px solid #32414B; + padding: 2px; + margin: 0px; + color: #F0F0F0; +} + +QLabel:disabled { + background-color: #19232D; + border: 0px solid #32414B; + color: #787878; +} + +/* QTextBrowser ----------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea + +--------------------------------------------------------------------------- */ +QTextBrowser { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + border-radius: 4px; +} + +QTextBrowser:disabled { + background-color: #19232D; + border: 1px solid #32414B; + color: #787878; + border-radius: 4px; +} + +QTextBrowser:hover, QTextBrowser:!hover, QTextBrowser:selected, QTextBrowser:pressed { + border: 1px solid #32414B; +} + +/* QGraphicsView ---------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QGraphicsView { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + border-radius: 4px; +} + +QGraphicsView:disabled { + background-color: #19232D; + border: 1px solid #32414B; + color: #787878; + border-radius: 4px; +} + +QGraphicsView:hover, QGraphicsView:!hover, QGraphicsView:selected, QGraphicsView:pressed { + border: 1px solid #32414B; +} + +/* QCalendarWidget -------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QCalendarWidget { + border: 1px solid #32414B; + border-radius: 4px; +} + +QCalendarWidget:disabled { + background-color: #19232D; + color: #787878; +} + +/* QLCDNumber ------------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QLCDNumber { + background-color: #19232D; + color: #F0F0F0; +} + +QLCDNumber:disabled { + background-color: #19232D; + color: #787878; +} + +/* QProgressBar ----------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qprogressbar + +--------------------------------------------------------------------------- */ +QProgressBar { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + border-radius: 4px; + text-align: center; +} + +QProgressBar:disabled { + background-color: #19232D; + border: 1px solid #32414B; + color: #787878; + border-radius: 4px; + text-align: center; +} + +QProgressBar::chunk { + background-color: #1464A0; + color: #19232D; + border-radius: 4px; +} + +QProgressBar::chunk:disabled { + background-color: #14506E; + color: #787878; + border-radius: 4px; +} + +/* ------------------------------------------------------------------------ */ +/* BUTTONS ---------------------------------------------------------------- */ +/* ------------------------------------------------------------------------ */ +/* QPushButton ------------------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qpushbutton + +--------------------------------------------------------------------------- */ +QPushButton { + background-color: #505F69; + border: 1px solid #32414B; + color: #F0F0F0; + border-radius: 4px; + padding: 3px; + outline: none; + /* Issue #194 - Special case of QPushButton inside dialogs, for better UI */ + min-width: 80px; +} + +QPushButton:disabled { + background-color: #32414B; + border: 1px solid #32414B; + color: #787878; + border-radius: 4px; + padding: 3px; +} + +QPushButton:checked { + background-color: #32414B; + border: 1px solid #32414B; + border-radius: 4px; + padding: 3px; + outline: none; +} + +QPushButton:checked:disabled { + background-color: #19232D; + border: 1px solid #32414B; + color: #787878; + border-radius: 4px; + padding: 3px; + outline: none; +} + +QPushButton:checked:selected { + background: #1464A0; + color: #32414B; +} + +QPushButton::menu-indicator { + subcontrol-origin: padding; + subcontrol-position: bottom right; + bottom: 4px; +} + +QPushButton:pressed { + background-color: #19232D; + border: 1px solid #19232D; +} + +QPushButton:pressed:hover { + border: 1px solid #148CD2; +} + +QPushButton:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QPushButton:selected { + background: #1464A0; + color: #32414B; +} + +QPushButton:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QPushButton:focus { + border: 1px solid #1464A0; +} + +/* QToolButton ------------------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbutton + +--------------------------------------------------------------------------- */ +QToolButton { + background-color: transparent; + border: 1px solid transparent; + border-radius: 4px; + margin: 0px; + padding: 2px; + /* The subcontrols below are used only in the DelayedPopup mode */ + /* The subcontrols below are used only in the MenuButtonPopup mode */ + /* The subcontrol below is used only in the InstantPopup or DelayedPopup mode */ +} + +QToolButton:checked { + background-color: transparent; + border: 1px solid #1464A0; +} + +QToolButton:checked:disabled { + border: 1px solid #14506E; +} + +QToolButton:pressed { + margin: 1px; + background-color: transparent; + border: 1px solid #1464A0; +} + +QToolButton:disabled { + border: none; +} + +QToolButton:hover { + border: 1px solid #148CD2; +} + +QToolButton[popupMode="0"] { + /* Only for DelayedPopup */ + padding-right: 2px; +} + +QToolButton[popupMode="1"] { + /* Only for MenuButtonPopup */ + padding-right: 20px; +} + +QToolButton[popupMode="1"]::menu-button { + border: none; +} + +QToolButton[popupMode="1"]::menu-button:hover { + border: none; + border-left: 1px solid #148CD2; + border-radius: 0; +} + +QToolButton[popupMode="2"] { + /* Only for InstantPopup */ + padding-right: 2px; +} + +QToolButton::menu-button { + padding: 2px; + border-radius: 4px; + border: 1px solid #32414B; + width: 12px; + outline: none; +} + +QToolButton::menu-button:hover { + border: 1px solid #148CD2; +} + +QToolButton::menu-button:checked:hover { + border: 1px solid #148CD2; +} + +QToolButton::menu-indicator { + image: url(":/qss_icons/rc/arrow_down.png"); + height: 8px; + width: 8px; + top: 0; + /* Exclude a shift for better image */ + left: -2px; + /* Shift it a bit */ +} + +QToolButton::menu-arrow { + image: url(":/qss_icons/rc/arrow_down.png"); + height: 8px; + width: 8px; +} + +QToolButton::menu-arrow:hover { + image: url(":/qss_icons/rc/arrow_down_focus.png"); +} + +/* QCommandLinkButton ----------------------------------------------------- + +--------------------------------------------------------------------------- */ +QCommandLinkButton { + background-color: transparent; + border: 1px solid #32414B; + color: #F0F0F0; + border-radius: 4px; + padding: 0px; + margin: 0px; +} + +QCommandLinkButton:disabled { + background-color: transparent; + color: #787878; +} + +/* ------------------------------------------------------------------------ */ +/* INPUTS - NO FIELDS ----------------------------------------------------- */ +/* ------------------------------------------------------------------------ */ +/* QComboBox -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox + +--------------------------------------------------------------------------- */ +QComboBox { + border: 1px solid #32414B; + border-radius: 4px; + selection-background-color: #1464A0; + padding-left: 4px; + padding-right: 36px; + /* 4 + 16*2 See scrollbar size */ + /* Fixes #103, #111 */ + min-height: 1.5em; + /* padding-top: 2px; removed to fix #132 */ + /* padding-bottom: 2px; removed to fix #132 */ + /* min-width: 75px; removed to fix #109 */ + /* Needed to remove indicator - fix #132 */ +} + +QComboBox QAbstractItemView { + border: 1px solid #32414B; + border-radius: 0; + background-color: #19232D; + selection-background-color: #1464A0; +} + +QComboBox QAbstractItemView:hover { + background-color: #19232D; + color: #F0F0F0; +} + +QComboBox QAbstractItemView:selected { + background: #1464A0; + color: #32414B; +} + +QComboBox QAbstractItemView:alternate { + background: #19232D; +} + +QComboBox:disabled { + background-color: #19232D; + color: #787878; +} + +QComboBox:hover { + border: 1px solid #148CD2; +} + +QComboBox:focus { + border: 1px solid #1464A0; +} + +QComboBox:on { + selection-background-color: #1464A0; +} + +QComboBox::indicator { + border: none; + border-radius: 0; + background-color: transparent; + selection-background-color: transparent; + color: transparent; + selection-color: transparent; + /* Needed to remove indicator - fix #132 */ +} + +QComboBox::indicator:alternate { + background: #19232D; +} + +QComboBox::item:alternate { + background: #19232D; +} + +QComboBox::item:checked { + font-weight: bold; +} + +QComboBox::item:selected { + border: 0px solid transparent; +} + +QComboBox::drop-down { + subcontrol-origin: padding; + subcontrol-position: top right; + width: 12px; + border-left: 1px solid #32414B; +} + +QComboBox::down-arrow { + image: url(":/qss_icons/rc/arrow_down_disabled.png"); + height: 8px; + width: 8px; +} + +QComboBox::down-arrow:on, QComboBox::down-arrow:hover, QComboBox::down-arrow:focus { + image: url(":/qss_icons/rc/arrow_down.png"); +} + +/* QSlider ---------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qslider + +--------------------------------------------------------------------------- */ +QSlider:disabled { + background: #19232D; +} + +QSlider:focus { + border: none; +} + +QSlider::groove:horizontal { + background: #32414B; + border: 1px solid #32414B; + height: 4px; + margin: 0px; + border-radius: 4px; +} + +QSlider::groove:vertical { + background: #32414B; + border: 1px solid #32414B; + width: 4px; + margin: 0px; + border-radius: 4px; +} + +QSlider::add-page:vertical { + background: #1464A0; + border: 1px solid #32414B; + width: 4px; + margin: 0px; + border-radius: 4px; +} + +QSlider::add-page:vertical :disabled { + background: #14506E; +} + +QSlider::sub-page:horizontal { + background: #1464A0; + border: 1px solid #32414B; + height: 4px; + margin: 0px; + border-radius: 4px; +} + +QSlider::sub-page:horizontal:disabled { + background: #14506E; +} + +QSlider::handle:horizontal { + background: #787878; + border: 1px solid #32414B; + width: 8px; + height: 8px; + margin: -8px 0px; + border-radius: 4px; +} + +QSlider::handle:horizontal:hover { + background: #148CD2; + border: 1px solid #148CD2; +} + +QSlider::handle:horizontal:focus { + border: 1px solid #1464A0; +} + +QSlider::handle:vertical { + background: #787878; + border: 1px solid #32414B; + width: 8px; + height: 8px; + margin: 0 -8px; + border-radius: 4px; +} + +QSlider::handle:vertical:hover { + background: #148CD2; + border: 1px solid #148CD2; +} + +QSlider::handle:vertical:focus { + border: 1px solid #1464A0; +} + +/* QLineEdit -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlineedit + +--------------------------------------------------------------------------- */ +QLineEdit { + background-color: #19232D; + padding-top: 2px; + /* This QLineEdit fix 103, 111 */ + padding-bottom: 2px; + /* This QLineEdit fix 103, 111 */ + padding-left: 4px; + padding-right: 4px; + border-style: solid; + border: 1px solid #32414B; + border-radius: 4px; + color: #F0F0F0; +} + +QLineEdit:disabled { + background-color: #19232D; + color: #787878; +} + +QLineEdit:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QLineEdit:focus { + border: 1px solid #1464A0; +} + +QLineEdit:selected { + background-color: #1464A0; + color: #32414B; +} + +/* QTabWiget -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar + +--------------------------------------------------------------------------- */ +QTabWidget { + padding: 2px; + selection-background-color: #32414B; +} + +QTabWidget QWidget { + /* Fixes #189 */ + border-radius: 4px; +} + +QTabWidget::pane { + border: 1px solid #32414B; + border-radius: 4px; + margin: 0px; + /* Fixes double border inside pane with pyqt5 */ + padding: 0px; +} + +QTabWidget::pane:selected { + background-color: #32414B; + border: 1px solid #1464A0; +} + +/* QTabBar ---------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar + +--------------------------------------------------------------------------- */ +QTabBar { + qproperty-drawBase: 0; + border-radius: 4px; + margin: 0px; + padding: 2px; + border: 0; + /* left: 5px; move to the right by 5px - removed for fix */ +} + +QTabBar::close-button { + border: 0; + margin: 2px; + padding: 2px; + image: url(":/qss_icons/rc/window_close.png"); +} + +QTabBar::close-button:hover { + image: url(":/qss_icons/rc/window_close_focus.png"); +} + +QTabBar::close-button:pressed { + image: url(":/qss_icons/rc/window_close_pressed.png"); +} + +/* QTabBar::tab - selected ------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar + +--------------------------------------------------------------------------- */ +QTabBar::tab { + /* !selected and disabled ----------------------------------------- */ + /* selected ------------------------------------------------------- */ +} + +QTabBar::tab:top:selected:disabled { + border-bottom: 3px solid #14506E; + color: #787878; + background-color: #32414B; +} + +QTabBar::tab:bottom:selected:disabled { + border-top: 3px solid #14506E; + color: #787878; + background-color: #32414B; +} + +QTabBar::tab:left:selected:disabled { + border-right: 3px solid #14506E; + color: #787878; + background-color: #32414B; +} + +QTabBar::tab:right:selected:disabled { + border-left: 3px solid #14506E; + color: #787878; + background-color: #32414B; +} + +QTabBar::tab:top:!selected:disabled { + border-bottom: 3px solid #19232D; + color: #787878; + background-color: #19232D; +} + +QTabBar::tab:bottom:!selected:disabled { + border-top: 3px solid #19232D; + color: #787878; + background-color: #19232D; +} + +QTabBar::tab:left:!selected:disabled { + border-right: 3px solid #19232D; + color: #787878; + background-color: #19232D; +} + +QTabBar::tab:right:!selected:disabled { + border-left: 3px solid #19232D; + color: #787878; + background-color: #19232D; +} + +QTabBar::tab:top:!selected { + border-bottom: 2px solid #19232D; + margin-top: 2px; +} + +QTabBar::tab:bottom:!selected { + border-top: 2px solid #19232D; + margin-bottom: 3px; +} + +QTabBar::tab:left:!selected { + border-left: 2px solid #19232D; + margin-right: 2px; +} + +QTabBar::tab:right:!selected { + border-right: 2px solid #19232D; + margin-left: 2px; +} + +QTabBar::tab:top { + background-color: #32414B; + color: #F0F0F0; + margin-left: 2px; + padding-left: 4px; + padding-right: 4px; + padding-top: 2px; + padding-bottom: 2px; + min-width: 5px; + border-bottom: 3px solid #32414B; + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} + +QTabBar::tab:top:selected { + background-color: #505F69; + color: #F0F0F0; + border-bottom: 3px solid #1464A0; + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} + +QTabBar::tab:top:!selected:hover { + border: 1px solid #148CD2; + border-bottom: 3px solid #148CD2; + /* Fixes spyder-ide/spyder#9766 */ + padding-left: 4px; + padding-right: 4px; +} + +QTabBar::tab:bottom { + color: #F0F0F0; + border-top: 3px solid #32414B; + background-color: #32414B; + margin-left: 2px; + padding-left: 4px; + padding-right: 4px; + padding-top: 2px; + padding-bottom: 2px; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; + min-width: 5px; +} + +QTabBar::tab:bottom:selected { + color: #F0F0F0; + background-color: #505F69; + border-top: 3px solid #1464A0; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; +} + +QTabBar::tab:bottom:!selected:hover { + border: 1px solid #148CD2; + border-top: 3px solid #148CD2; + /* Fixes spyder-ide/spyder#9766 */ + padding-left: 4px; + padding-right: 4px; +} + +QTabBar::tab:left { + color: #F0F0F0; + background-color: #32414B; + margin-top: 2px; + padding-left: 2px; + padding-right: 2px; + padding-top: 4px; + padding-bottom: 4px; + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; + min-height: 5px; +} + +QTabBar::tab:left:selected { + color: #F0F0F0; + background-color: #505F69; + border-right: 3px solid #1464A0; +} + +QTabBar::tab:left:!selected:hover { + border: 1px solid #148CD2; + border-right: 3px solid #148CD2; + padding: 0px; +} + +QTabBar::tab:right { + color: #F0F0F0; + background-color: #32414B; + margin-top: 2px; + padding-left: 2px; + padding-right: 2px; + padding-top: 4px; + padding-bottom: 4px; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + min-height: 5px; +} + +QTabBar::tab:right:selected { + color: #F0F0F0; + background-color: #505F69; + border-left: 3px solid #1464A0; +} + +QTabBar::tab:right:!selected:hover { + border: 1px solid #148CD2; + border-left: 3px solid #148CD2; + padding: 0px; +} + +QTabBar QToolButton { + /* Fixes #136 */ + background-color: #32414B; + height: 12px; + width: 12px; +} + +QTabBar QToolButton:pressed { + background-color: #32414B; +} + +QTabBar QToolButton:pressed:hover { + border: 1px solid #148CD2; +} + +QTabBar QToolButton::left-arrow:enabled { + image: url(":/qss_icons/rc/arrow_left.png"); +} + +QTabBar QToolButton::left-arrow:disabled { + image: url(":/qss_icons/rc/arrow_left_disabled.png"); +} + +QTabBar QToolButton::right-arrow:enabled { + image: url(":/qss_icons/rc/arrow_right.png"); +} + +QTabBar QToolButton::right-arrow:disabled { + image: url(":/qss_icons/rc/arrow_right_disabled.png"); +} + +/* QDockWiget ------------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QDockWidget { + outline: 1px solid #32414B; + background-color: #19232D; + border: 1px solid #32414B; + border-radius: 4px; + titlebar-close-icon: url(":/qss_icons/rc/window_close.png"); + titlebar-normal-icon: url(":/qss_icons/rc/window_undock.png"); +} + +QDockWidget::title { + /* Better size for title bar */ + padding: 6px; + spacing: 4px; + border: none; + background-color: #32414B; +} + +QDockWidget::close-button { + background-color: #32414B; + border-radius: 4px; + border: none; +} + +QDockWidget::close-button:hover { + image: url(":/qss_icons/rc/window_close_focus.png"); +} + +QDockWidget::close-button:pressed { + image: url(":/qss_icons/rc/window_close_pressed.png"); +} + +QDockWidget::float-button { + background-color: #32414B; + border-radius: 4px; + border: none; +} + +QDockWidget::float-button:hover { + image: url(":/qss_icons/rc/window_undock_focus.png"); +} + +QDockWidget::float-button:pressed { + image: url(":/qss_icons/rc/window_undock_pressed.png"); +} + +/* QTreeView QListView QTableView ----------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtreeview +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlistview +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtableview + +--------------------------------------------------------------------------- */ +QTreeView:branch:selected, QTreeView:branch:hover { + background: url(":/qss_icons/rc/transparent.png"); +} + +QTreeView:branch:has-siblings:!adjoins-item { + border-image: url(":/qss_icons/rc/branch_line.png") 0; +} + +QTreeView:branch:has-siblings:adjoins-item { + border-image: url(":/qss_icons/rc/branch_more.png") 0; +} + +QTreeView:branch:!has-children:!has-siblings:adjoins-item { + border-image: url(":/qss_icons/rc/branch_end.png") 0; +} + +QTreeView:branch:has-children:!has-siblings:closed, QTreeView:branch:closed:has-children:has-siblings { + border-image: none; + image: url(":/qss_icons/rc/branch_closed.png"); +} + +QTreeView:branch:open:has-children:!has-siblings, QTreeView:branch:open:has-children:has-siblings { + border-image: none; + image: url(":/qss_icons/rc/branch_open.png"); +} + +QTreeView:branch:has-children:!has-siblings:closed:hover, QTreeView:branch:closed:has-children:has-siblings:hover { + image: url(":/qss_icons/rc/branch_closed_focus.png"); +} + +QTreeView:branch:open:has-children:!has-siblings:hover, QTreeView:branch:open:has-children:has-siblings:hover { + image: url(":/qss_icons/rc/branch_open_focus.png"); +} + +QTreeView::indicator:checked, +QListView::indicator:checked { + image: url(":/qss_icons/rc/checkbox_checked.png"); +} + +QTreeView::indicator:checked:hover, QTreeView::indicator:checked:focus, QTreeView::indicator:checked:pressed, +QListView::indicator:checked:hover, +QListView::indicator:checked:focus, +QListView::indicator:checked:pressed { + image: url(":/qss_icons/rc/checkbox_checked_focus.png"); +} + +QTreeView::indicator:unchecked, +QListView::indicator:unchecked { + image: url(":/qss_icons/rc/checkbox_unchecked.png"); +} + +QTreeView::indicator:unchecked:hover, QTreeView::indicator:unchecked:focus, QTreeView::indicator:unchecked:pressed, +QListView::indicator:unchecked:hover, +QListView::indicator:unchecked:focus, +QListView::indicator:unchecked:pressed { + image: url(":/qss_icons/rc/checkbox_unchecked_focus.png"); +} + +QTreeView::indicator:indeterminate, +QListView::indicator:indeterminate { + image: url(":/qss_icons/rc/checkbox_indeterminate.png"); +} + +QTreeView::indicator:indeterminate:hover, QTreeView::indicator:indeterminate:focus, QTreeView::indicator:indeterminate:pressed, +QListView::indicator:indeterminate:hover, +QListView::indicator:indeterminate:focus, +QListView::indicator:indeterminate:pressed { + image: url(":/qss_icons/rc/checkbox_indeterminate_focus.png"); +} + +QTreeView, +QListView, +QTableView, +QColumnView { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + gridline-color: #32414B; + border-radius: 4px; +} + +QTreeView:disabled, +QListView:disabled, +QTableView:disabled, +QColumnView:disabled { + background-color: #19232D; + color: #787878; +} + +QTreeView:selected, +QListView:selected, +QTableView:selected, +QColumnView:selected { + background-color: #1464A0; + color: #32414B; +} + +QTreeView:hover, +QListView:hover, +QTableView:hover, +QColumnView:hover { + background-color: #19232D; + border: 1px solid #148CD2; +} + +QTreeView::item:pressed, +QListView::item:pressed, +QTableView::item:pressed, +QColumnView::item:pressed { + background-color: #1464A0; +} + +QTreeView::item:selected:hover, +QListView::item:selected:hover, +QTableView::item:selected:hover, +QColumnView::item:selected:hover { + background: #1464A0; + color: #19232D; +} + +QTreeView::item:selected:active, +QListView::item:selected:active, +QTableView::item:selected:active, +QColumnView::item:selected:active { + background-color: #1464A0; +} + +QTreeView::item:!selected:hover, +QListView::item:!selected:hover, +QTableView::item:!selected:hover, +QColumnView::item:!selected:hover { + outline: 0; + color: #148CD2; + background-color: #32414B; +} + +QTableCornerButton::section { + background-color: #19232D; + border: 1px transparent #32414B; + border-radius: 0px; +} + +/* QHeaderView ------------------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qheaderview + +--------------------------------------------------------------------------- */ +QHeaderView { + background-color: #32414B; + border: 0px transparent #32414B; + padding: 0px; + margin: 0px; + border-radius: 0px; +} + +QHeaderView:disabled { + background-color: #32414B; + border: 1px transparent #32414B; + padding: 2px; +} + +QHeaderView::section { + background-color: #32414B; + color: #F0F0F0; + padding: 2px; + border-radius: 0px; + text-align: left; +} + +QHeaderView::section:checked { + color: #F0F0F0; + background-color: #1464A0; +} + +QHeaderView::section:checked:disabled { + color: #787878; + background-color: #14506E; +} + +QHeaderView::section::horizontal { + padding-left: 4px; + padding-right: 4px; + border-left: 1px solid #19232D; +} + +QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one { + border-left: 1px solid #32414B; +} + +QHeaderView::section::horizontal:disabled { + color: #787878; +} + +QHeaderView::section::vertical { + padding-left: 4px; + padding-right: 4px; + border-top: 1px solid #19232D; +} + +QHeaderView::section::vertical::first, QHeaderView::section::vertical::only-one { + border-top: 1px solid #32414B; +} + +QHeaderView::section::vertical:disabled { + color: #787878; +} + +QHeaderView::down-arrow { + /* Those settings (border/width/height/background-color) solve bug */ + /* transparent arrow background and size */ + background-color: #32414B; + border: none; + height: 12px; + width: 12px; + padding-left: 2px; + padding-right: 2px; + image: url(":/qss_icons/rc/arrow_down.png"); +} + +QHeaderView::up-arrow { + background-color: #32414B; + border: none; + height: 12px; + width: 12px; + padding-left: 2px; + padding-right: 2px; + image: url(":/qss_icons/rc/arrow_up.png"); +} + +/* QToolBox -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbox + +--------------------------------------------------------------------------- */ +QToolBox { + padding: 0px; + border: 0px; + border: 1px solid #32414B; +} + +QToolBox:selected { + padding: 0px; + border: 2px solid #1464A0; +} + +QToolBox::tab { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + border-top-left-radius: 4px; + border-top-right-radius: 4px; +} + +QToolBox::tab:disabled { + color: #787878; +} + +QToolBox::tab:selected { + background-color: #505F69; + border-bottom: 2px solid #1464A0; +} + +QToolBox::tab:selected:disabled { + background-color: #32414B; + border-bottom: 2px solid #14506E; +} + +QToolBox::tab:!selected { + background-color: #32414B; + border-bottom: 2px solid #32414B; +} + +QToolBox::tab:!selected:disabled { + background-color: #19232D; +} + +QToolBox::tab:hover { + border-color: #148CD2; + border-bottom: 2px solid #148CD2; +} + +QToolBox QScrollArea QWidget QWidget { + padding: 0px; + border: 0px; + background-color: #19232D; +} + +/* QFrame ----------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe +https://doc.qt.io/qt-5/qframe.html#-prop +https://doc.qt.io/qt-5/qframe.html#details +https://stackoverflow.com/questions/14581498/qt-stylesheet-for-hline-vline-color + +--------------------------------------------------------------------------- */ +/* (dot) .QFrame fix #141, #126, #123 */ +.QFrame { + border-radius: 4px; + border: 1px solid #32414B; + /* No frame */ + /* HLine */ + /* HLine */ +} + +.QFrame[frameShape="0"] { + border-radius: 4px; + border: 1px transparent #32414B; +} + +.QFrame[frameShape="4"] { + max-height: 2px; + border: none; + background-color: #32414B; +} + +.QFrame[frameShape="5"] { + max-width: 2px; + border: none; + background-color: #32414B; +} + +/* QSplitter -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsplitter + +--------------------------------------------------------------------------- */ +QSplitter { + background-color: #32414B; + spacing: 0px; + padding: 0px; + margin: 0px; +} + +QSplitter::handle { + background-color: #32414B; + border: 0px solid #19232D; + spacing: 0px; + padding: 1px; + margin: 0px; +} + +QSplitter::handle:hover { + background-color: #787878; +} + +QSplitter::handle:horizontal { + width: 5px; + image: url(":/qss_icons/rc/line_vertical.png"); +} + +QSplitter::handle:vertical { + height: 5px; + image: url(":/qss_icons/rc/line_horizontal.png"); +} + +/* QDateEdit, QDateTimeEdit ----------------------------------------------- + +--------------------------------------------------------------------------- */ +QDateEdit, QDateTimeEdit { + selection-background-color: #1464A0; + border-style: solid; + border: 1px solid #32414B; + border-radius: 4px; + /* This fixes 103, 111 */ + padding-top: 2px; + /* This fixes 103, 111 */ + padding-bottom: 2px; + padding-left: 4px; + padding-right: 4px; + min-width: 10px; +} + +QDateEdit:on, QDateTimeEdit:on { + selection-background-color: #1464A0; +} + +QDateEdit::drop-down, QDateTimeEdit::drop-down { + subcontrol-origin: padding; + subcontrol-position: top right; + width: 12px; + border-left: 1px solid #32414B; +} + +QDateEdit::down-arrow, QDateTimeEdit::down-arrow { + image: url(":/qss_icons/rc/arrow_down_disabled.png"); + height: 8px; + width: 8px; +} + +QDateEdit::down-arrow:on, QDateEdit::down-arrow:hover, QDateEdit::down-arrow:focus, QDateTimeEdit::down-arrow:on, QDateTimeEdit::down-arrow:hover, QDateTimeEdit::down-arrow:focus { + image: url(":/qss_icons/rc/arrow_down.png"); +} + +QDateEdit QAbstractItemView, QDateTimeEdit QAbstractItemView { + background-color: #19232D; + border-radius: 4px; + border: 1px solid #32414B; + selection-background-color: #1464A0; +} + +/* QAbstractView ---------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QAbstractView:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QAbstractView:selected { + background: #1464A0; + color: #32414B; +} + +/* PlotWidget ------------------------------------------------------------- + +--------------------------------------------------------------------------- */ +PlotWidget { + /* Fix cut labels in plots #134 */ + padding: 0px; +} diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp index aab3e979a..f80ab92e4 100644 --- a/src/audio_core/stream.cpp +++ b/src/audio_core/stream.cpp @@ -38,7 +38,7 @@ Stream::Stream(Core::Timing::CoreTiming& core_timing, u32 sample_rate, Format fo sink_stream{sink_stream}, core_timing{core_timing}, name{std::move(name_)} { release_event = Core::Timing::CreateEvent( - name, [this](u64 userdata, s64 cycles_late) { ReleaseActiveBuffer(cycles_late); }); + name, [this](u64, std::chrono::nanoseconds ns_late) { ReleaseActiveBuffer(ns_late); }); } void Stream::Play() { @@ -59,11 +59,9 @@ Stream::State Stream::GetState() const { return state; } -s64 Stream::GetBufferReleaseNS(const Buffer& buffer) const { +std::chrono::nanoseconds Stream::GetBufferReleaseNS(const Buffer& buffer) const { const std::size_t num_samples{buffer.GetSamples().size() / GetNumChannels()}; - const auto ns = - std::chrono::nanoseconds((static_cast<u64>(num_samples) * 1000000000ULL) / sample_rate); - return ns.count(); + return std::chrono::nanoseconds((static_cast<u64>(num_samples) * 1000000000ULL) / sample_rate); } static void VolumeAdjustSamples(std::vector<s16>& samples, float game_volume) { @@ -80,7 +78,7 @@ static void VolumeAdjustSamples(std::vector<s16>& samples, float game_volume) { } } -void Stream::PlayNextBuffer(s64 cycles_late) { +void Stream::PlayNextBuffer(std::chrono::nanoseconds ns_late) { if (!IsPlaying()) { // Ensure we are in playing state before playing the next buffer sink_stream.Flush(); @@ -105,17 +103,18 @@ void Stream::PlayNextBuffer(s64 cycles_late) { sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples()); - core_timing.ScheduleEvent( - GetBufferReleaseNS(*active_buffer) - - (Settings::values.enable_audio_stretching.GetValue() ? 0 : cycles_late), - release_event, {}); + const auto time_stretch_delta = Settings::values.enable_audio_stretching.GetValue() + ? std::chrono::nanoseconds::zero() + : ns_late; + const auto future_time = GetBufferReleaseNS(*active_buffer) - time_stretch_delta; + core_timing.ScheduleEvent(future_time, release_event, {}); } -void Stream::ReleaseActiveBuffer(s64 cycles_late) { +void Stream::ReleaseActiveBuffer(std::chrono::nanoseconds ns_late) { ASSERT(active_buffer); released_buffers.push(std::move(active_buffer)); release_callback(); - PlayNextBuffer(cycles_late); + PlayNextBuffer(ns_late); } bool Stream::QueueBuffer(BufferPtr&& buffer) { diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h index 524376257..6437b8591 100644 --- a/src/audio_core/stream.h +++ b/src/audio_core/stream.h @@ -4,6 +4,7 @@ #pragma once +#include <chrono> #include <functional> #include <memory> #include <string> @@ -90,16 +91,13 @@ public: private: /// Plays the next queued buffer in the audio stream, starting playback if necessary - void PlayNextBuffer(s64 cycles_late = 0); + void PlayNextBuffer(std::chrono::nanoseconds ns_late = {}); /// Releases the actively playing buffer, signalling that it has been completed - void ReleaseActiveBuffer(s64 cycles_late = 0); + void ReleaseActiveBuffer(std::chrono::nanoseconds ns_late = {}); /// Gets the number of core cycles when the specified buffer will be released - s64 GetBufferReleaseNS(const Buffer& buffer) const; - - /// Gets the number of core cycles when the specified buffer will be released - s64 GetBufferReleaseNSHostTiming(const Buffer& buffer) const; + std::chrono::nanoseconds GetBufferReleaseNS(const Buffer& buffer) const; u32 sample_rate; ///< Sample rate of the stream Format format; ///< Format of the stream diff --git a/src/common/alignment.h b/src/common/alignment.h index b37044bb6..ef4d6f896 100644 --- a/src/common/alignment.h +++ b/src/common/alignment.h @@ -3,7 +3,7 @@ #pragma once #include <cstddef> -#include <memory> +#include <new> #include <type_traits> namespace Common { @@ -54,66 +54,28 @@ public: using size_type = std::size_t; using difference_type = std::ptrdiff_t; - using pointer = T*; - using const_pointer = const T*; - - using reference = T&; - using const_reference = const T&; - using propagate_on_container_copy_assignment = std::true_type; using propagate_on_container_move_assignment = std::true_type; using propagate_on_container_swap = std::true_type; using is_always_equal = std::true_type; -public: constexpr AlignmentAllocator() noexcept = default; template <typename T2> constexpr AlignmentAllocator(const AlignmentAllocator<T2, Align>&) noexcept {} - pointer address(reference r) noexcept { - return std::addressof(r); - } - - const_pointer address(const_reference r) const noexcept { - return std::addressof(r); - } - - pointer allocate(size_type n) { - return static_cast<pointer>(::operator new (n, std::align_val_t{Align})); - } - - void deallocate(pointer p, size_type) { - ::operator delete (p, std::align_val_t{Align}); + T* allocate(size_type n) { + return static_cast<T*>(::operator new (n * sizeof(T), std::align_val_t{Align})); } - void construct(pointer p, const value_type& wert) { - new (p) value_type(wert); - } - - void destroy(pointer p) { - p->~value_type(); - } - - size_type max_size() const noexcept { - return size_type(-1) / sizeof(value_type); + void deallocate(T* p, size_type n) { + ::operator delete (p, n * sizeof(T), std::align_val_t{Align}); } template <typename T2> struct rebind { using other = AlignmentAllocator<T2, Align>; }; - - bool operator!=(const AlignmentAllocator<T, Align>& other) const noexcept { - return !(*this == other); - } - - // Returns true if and only if storage allocated from *this - // can be deallocated from other, and vice versa. - // Always returns true for stateless allocators. - bool operator==(const AlignmentAllocator<T, Align>& other) const noexcept { - return true; - } }; } // namespace Common diff --git a/src/common/string_util.h b/src/common/string_util.h index 583fd05e6..023dff5dc 100644 --- a/src/common/string_util.h +++ b/src/common/string_util.h @@ -74,16 +74,4 @@ std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer, std::size_t max_len); -/** - * Attempts to trim an arbitrary prefix from `path`, leaving only the part starting at `root`. It's - * intended to be used to strip a system-specific build directory from the `__FILE__` macro, - * leaving only the path relative to the sources root. - * - * @param path The input file path as a null-terminated string - * @param root The name of the root source directory as a null-terminated string. Path up to and - * including the last occurrence of this name will be stripped - * @return A pointer to the same string passed as `path`, but starting at the trimmed portion - */ -const char* TrimSourcePath(const char* path, const char* root = "src"); - } // namespace Common diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index d1f173f42..c85c9485f 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -185,6 +185,7 @@ add_library(core STATIC hle/kernel/object.h hle/kernel/physical_core.cpp hle/kernel/physical_core.h + hle/kernel/physical_memory.h hle/kernel/process.cpp hle/kernel/process.h hle/kernel/process_capability.cpp @@ -398,10 +399,13 @@ add_library(core STATIC hle/service/lm/manager.h hle/service/mig/mig.cpp hle/service/mig/mig.h + hle/service/mii/manager.cpp + hle/service/mii/manager.h hle/service/mii/mii.cpp hle/service/mii/mii.h - hle/service/mii/mii_manager.cpp - hle/service/mii/mii_manager.h + hle/service/mii/raw_data.cpp + hle/service/mii/raw_data.h + hle/service/mii/types.h hle/service/mm/mm_u.cpp hle/service/mm/mm_u.h hle/service/ncm/ncm.cpp @@ -582,6 +586,9 @@ add_library(core STATIC memory/dmnt_cheat_vm.h memory.cpp memory.h + network/network.cpp + network/network.h + network/sockets.h perf_stats.cpp perf_stats.h reporter.cpp diff --git a/src/core/constants.h b/src/core/constants.h index 6d0ec022a..81c5cb279 100644 --- a/src/core/constants.h +++ b/src/core/constants.h @@ -4,6 +4,7 @@ #pragma once +#include <array> #include "common/common_types.h" // This is to consolidate system-wide constants that are used by multiple components of yuzu. diff --git a/src/core/core.cpp b/src/core/core.cpp index 69a1aa0a5..e598c0e2b 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -43,6 +43,7 @@ #include "core/loader/loader.h" #include "core/memory.h" #include "core/memory/cheat_engine.h" +#include "core/network/network.h" #include "core/perf_stats.h" #include "core/reporter.h" #include "core/settings.h" @@ -394,6 +395,9 @@ struct System::Impl { /// Telemetry session for this emulation session std::unique_ptr<Core::TelemetrySession> telemetry_session; + /// Network instance + Network::NetworkInstance network_instance; + ResultStatus status = ResultStatus::Success; std::string status_details = ""; diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index a63e60461..b5feb3f24 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -53,12 +53,12 @@ void CoreTiming::ThreadEntry(CoreTiming& instance) { instance.ThreadLoop(); } -void CoreTiming::Initialize(std::function<void(void)>&& on_thread_init_) { +void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) { on_thread_init = std::move(on_thread_init_); event_fifo_id = 0; shutting_down = false; ticks = 0; - const auto empty_timed_callback = [](u64, s64) {}; + const auto empty_timed_callback = [](u64, std::chrono::nanoseconds) {}; ev_lost = CreateEvent("_lost_event", empty_timed_callback); if (is_multicore) { timer_thread = std::make_unique<std::thread>(ThreadEntry, std::ref(*this)); @@ -106,11 +106,11 @@ bool CoreTiming::HasPendingEvents() const { return !(wait_set && event_queue.empty()); } -void CoreTiming::ScheduleEvent(s64 ns_into_future, const std::shared_ptr<EventType>& event_type, - u64 userdata) { +void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future, + const std::shared_ptr<EventType>& event_type, u64 userdata) { { std::scoped_lock scope{basic_lock}; - const u64 timeout = static_cast<u64>(GetGlobalTimeNs().count() + ns_into_future); + const u64 timeout = static_cast<u64>((GetGlobalTimeNs() + ns_into_future).count()); event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type}); @@ -195,8 +195,9 @@ std::optional<s64> CoreTiming::Advance() { event_queue.pop_back(); basic_lock.unlock(); - if (auto event_type{evt.type.lock()}) { - event_type->callback(evt.userdata, global_timer - evt.time); + if (const auto event_type{evt.type.lock()}) { + event_type->callback( + evt.userdata, std::chrono::nanoseconds{static_cast<s64>(global_timer - evt.time)}); } basic_lock.lock(); diff --git a/src/core/core_timing.h b/src/core/core_timing.h index 72faaab64..120c74e46 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -17,14 +17,12 @@ #include "common/common_types.h" #include "common/spin_lock.h" #include "common/thread.h" -#include "common/threadsafe_queue.h" #include "common/wall_clock.h" -#include "core/hardware_properties.h" namespace Core::Timing { /// A callback that may be scheduled for a particular core timing event. -using TimedCallback = std::function<void(u64 userdata, s64 cycles_late)>; +using TimedCallback = std::function<void(u64 userdata, std::chrono::nanoseconds ns_late)>; /// Contains the characteristics of a particular event. struct EventType { @@ -42,12 +40,12 @@ struct EventType { * in main CPU clock cycles. * * To schedule an event, you first have to register its type. This is where you pass in the - * callback. You then schedule events using the type id you get back. + * callback. You then schedule events using the type ID you get back. * - * The int cyclesLate that the callbacks get is how many cycles late it was. + * The s64 ns_late that the callbacks get is how many ns late it was. * So to schedule a new event on a regular basis: * inside callback: - * ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever") + * ScheduleEvent(period_in_ns - ns_late, callback, "whatever") */ class CoreTiming { public: @@ -62,7 +60,7 @@ public: /// CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is /// required to end slice - 1 and start slice 0 before the first cycle of code is executed. - void Initialize(std::function<void(void)>&& on_thread_init_); + void Initialize(std::function<void()>&& on_thread_init_); /// Tears down all timing related functionality. void Shutdown(); @@ -95,8 +93,8 @@ public: bool HasPendingEvents() const; /// Schedules an event in core timing - void ScheduleEvent(s64 ns_into_future, const std::shared_ptr<EventType>& event_type, - u64 userdata = 0); + void ScheduleEvent(std::chrono::nanoseconds ns_into_future, + const std::shared_ptr<EventType>& event_type, u64 userdata = 0); void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata); @@ -141,8 +139,6 @@ private: u64 global_timer = 0; - std::chrono::nanoseconds start_point; - // The queue is a min-heap using std::make_heap/push_heap/pop_heap. // We don't use std::priority_queue because we need to be able to serialize, unserialize and // erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't @@ -161,7 +157,7 @@ private: std::atomic<bool> wait_set{}; std::atomic<bool> shutting_down{}; std::atomic<bool> has_started{}; - std::function<void(void)> on_thread_init{}; + std::function<void()> on_thread_init{}; bool is_multicore{}; diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h index 35929ed94..17420c941 100644 --- a/src/core/cpu_manager.h +++ b/src/core/cpu_manager.h @@ -9,6 +9,9 @@ #include <functional> #include <memory> #include <thread> + +#include "common/fiber.h" +#include "common/thread.h" #include "core/hardware_properties.h" namespace Common { @@ -46,9 +49,9 @@ public: void Pause(bool paused); - std::function<void(void*)> GetGuestThreadStartFunc(); - std::function<void(void*)> GetIdleThreadStartFunc(); - std::function<void(void*)> GetSuspendThreadStartFunc(); + static std::function<void(void*)> GetGuestThreadStartFunc(); + static std::function<void(void*)> GetIdleThreadStartFunc(); + static std::function<void(void*)> GetSuspendThreadStartFunc(); void* GetStartFuncParamater(); void PreemptSingleCore(bool from_running_enviroment = true); @@ -97,7 +100,6 @@ private: bool is_async_gpu{}; bool is_multicore{}; std::atomic<std::size_t> current_core{}; - std::size_t preemption_count{}; std::size_t idle_count{}; static constexpr std::size_t max_cycle_runs = 5; diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp index d126ae8dd..2aff2708a 100644 --- a/src/core/file_sys/fsmitm_romfsbuild.cpp +++ b/src/core/file_sys/fsmitm_romfsbuild.cpp @@ -240,7 +240,7 @@ RomFSBuildContext::RomFSBuildContext(VirtualDir base_, VirtualDir ext_) RomFSBuildContext::~RomFSBuildContext() = default; -std::map<u64, VirtualFile> RomFSBuildContext::Build() { +std::multimap<u64, VirtualFile> RomFSBuildContext::Build() { const u64 dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs); const u64 file_hash_table_entry_count = romfs_get_hash_table_count(num_files); dir_hash_table_size = 4 * dir_hash_table_entry_count; @@ -294,7 +294,7 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() { cur_dir->parent->child = cur_dir; } - std::map<u64, VirtualFile> out; + std::multimap<u64, VirtualFile> out; // Populate file tables. for (const auto& it : files) { diff --git a/src/core/file_sys/fsmitm_romfsbuild.h b/src/core/file_sys/fsmitm_romfsbuild.h index a62502193..049de180b 100644 --- a/src/core/file_sys/fsmitm_romfsbuild.h +++ b/src/core/file_sys/fsmitm_romfsbuild.h @@ -43,7 +43,7 @@ public: ~RomFSBuildContext(); // This finalizes the context. - std::map<u64, VirtualFile> Build(); + std::multimap<u64, VirtualFile> Build(); private: VirtualDir base; diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp index 16d801c0c..e0ff70174 100644 --- a/src/core/file_sys/vfs_concat.cpp +++ b/src/core/file_sys/vfs_concat.cpp @@ -11,7 +11,7 @@ namespace FileSys { -static bool VerifyConcatenationMapContinuity(const std::map<u64, VirtualFile>& map) { +static bool VerifyConcatenationMapContinuity(const std::multimap<u64, VirtualFile>& map) { const auto last_valid = --map.end(); for (auto iter = map.begin(); iter != last_valid;) { const auto old = iter++; @@ -27,12 +27,12 @@ ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::s : name(std::move(name)) { std::size_t next_offset = 0; for (const auto& file : files_) { - files[next_offset] = file; + files.emplace(next_offset, file); next_offset += file->GetSize(); } } -ConcatenatedVfsFile::ConcatenatedVfsFile(std::map<u64, VirtualFile> files_, std::string name) +ConcatenatedVfsFile::ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files_, std::string name) : files(std::move(files_)), name(std::move(name)) { ASSERT(VerifyConcatenationMapContinuity(files)); } @@ -50,7 +50,7 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::vector<VirtualFile> f } VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte, - std::map<u64, VirtualFile> files, + std::multimap<u64, VirtualFile> files, std::string name) { if (files.empty()) return nullptr; diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h index c90f9d5d1..7a26343c0 100644 --- a/src/core/file_sys/vfs_concat.h +++ b/src/core/file_sys/vfs_concat.h @@ -15,7 +15,7 @@ namespace FileSys { // read-only. class ConcatenatedVfsFile : public VfsFile { ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name); - ConcatenatedVfsFile(std::map<u64, VirtualFile> files, std::string name); + ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files, std::string name); public: ~ConcatenatedVfsFile() override; @@ -25,7 +25,7 @@ public: /// Convenience function that turns a map of offsets to files into a concatenated file, filling /// gaps with a given filler byte. - static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::map<u64, VirtualFile> files, + static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::multimap<u64, VirtualFile> files, std::string name); std::string GetName() const override; @@ -40,7 +40,7 @@ public: private: // Maps starting offset to file -- more efficient. - std::map<u64, VirtualFile> files; + std::multimap<u64, VirtualFile> files; std::string name; }; diff --git a/src/core/hardware_interrupt_manager.cpp b/src/core/hardware_interrupt_manager.cpp index c629d9fa1..efc1030c1 100644 --- a/src/core/hardware_interrupt_manager.cpp +++ b/src/core/hardware_interrupt_manager.cpp @@ -11,19 +11,20 @@ namespace Core::Hardware { InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) { - gpu_interrupt_event = Core::Timing::CreateEvent("GPUInterrupt", [this](u64 message, s64) { - auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv"); - const u32 syncpt = static_cast<u32>(message >> 32); - const u32 value = static_cast<u32>(message); - nvdrv->SignalGPUInterruptSyncpt(syncpt, value); - }); + gpu_interrupt_event = + Core::Timing::CreateEvent("GPUInterrupt", [this](u64 message, std::chrono::nanoseconds) { + auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv"); + const u32 syncpt = static_cast<u32>(message >> 32); + const u32 value = static_cast<u32>(message); + nvdrv->SignalGPUInterruptSyncpt(syncpt, value); + }); } InterruptManager::~InterruptManager() = default; void InterruptManager::GPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) { const u64 msg = (static_cast<u64>(syncpoint_id) << 32ULL) | value; - system.CoreTiming().ScheduleEvent(10, gpu_interrupt_event, msg); + system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds{10}, gpu_interrupt_event, msg); } } // namespace Core::Hardware diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 4d2a9b35d..df0debe1b 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -24,7 +24,6 @@ namespace Kernel { // Wake up num_to_wake (or all) threads in a vector. void AddressArbiter::WakeThreads(const std::vector<std::shared_ptr<Thread>>& waiting_threads, s32 num_to_wake) { - auto& time_manager = system.Kernel().TimeManager(); // Only process up to 'target' threads, unless 'target' is <= 0, in which case process // them all. std::size_t last = waiting_threads.size(); diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index 35448b576..fb30b6f8b 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -8,7 +8,9 @@ #include "core/core.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" namespace Kernel { @@ -22,7 +24,7 @@ constexpr u16 GetGeneration(Handle handle) { } } // Anonymous namespace -HandleTable::HandleTable() { +HandleTable::HandleTable(KernelCore& kernel) : kernel{kernel} { Clear(); } @@ -103,9 +105,9 @@ bool HandleTable::IsValid(Handle handle) const { std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const { if (handle == CurrentThread) { - return SharedFrom(GetCurrentThread()); + return SharedFrom(kernel.CurrentScheduler().GetCurrentThread()); } else if (handle == CurrentProcess) { - return SharedFrom(Core::System::GetInstance().CurrentProcess()); + return SharedFrom(kernel.CurrentProcess()); } if (!IsValid(handle)) { diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h index 8029660ed..c9dab8cdd 100644 --- a/src/core/hle/kernel/handle_table.h +++ b/src/core/hle/kernel/handle_table.h @@ -14,6 +14,8 @@ namespace Kernel { +class KernelCore; + enum KernelHandle : Handle { InvalidHandle = 0, CurrentThread = 0xFFFF8000, @@ -48,7 +50,7 @@ public: /// This is the maximum limit of handles allowed per process in Horizon static constexpr std::size_t MAX_COUNT = 1024; - HandleTable(); + explicit HandleTable(KernelCore& kernel); ~HandleTable(); /** @@ -134,6 +136,9 @@ private: /// Head of the free slots linked list. u16 next_free_slot = 0; + + /// Underlying kernel instance that this handle table operates under. + KernelCore& kernel; }; } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1f2af7a1b..8dd4a2637 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -50,7 +50,8 @@ namespace Kernel { struct KernelCore::Impl { explicit Impl(Core::System& system, KernelCore& kernel) - : global_scheduler{kernel}, synchronization{system}, time_manager{system}, system{system} {} + : global_scheduler{kernel}, synchronization{system}, time_manager{system}, + global_handle_table{kernel}, system{system} {} void SetMulticore(bool is_multicore) { this->is_multicore = is_multicore; @@ -144,29 +145,32 @@ struct KernelCore::Impl { void InitializePreemption(KernelCore& kernel) { preemption_event = Core::Timing::CreateEvent( - "PreemptionCallback", [this, &kernel](u64 userdata, s64 cycles_late) { + "PreemptionCallback", [this, &kernel](u64, std::chrono::nanoseconds) { { SchedulerLock lock(kernel); global_scheduler.PreemptThreads(); } - s64 time_interval = Core::Timing::msToCycles(std::chrono::milliseconds(10)); + const auto time_interval = std::chrono::nanoseconds{ + Core::Timing::msToCycles(std::chrono::milliseconds(10))}; system.CoreTiming().ScheduleEvent(time_interval, preemption_event); }); - s64 time_interval = Core::Timing::msToCycles(std::chrono::milliseconds(10)); + const auto time_interval = + std::chrono::nanoseconds{Core::Timing::msToCycles(std::chrono::milliseconds(10))}; system.CoreTiming().ScheduleEvent(time_interval, preemption_event); } void InitializeSuspendThreads() { for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { std::string name = "Suspend Thread Id:" + std::to_string(i); - std::function<void(void*)> init_func = - system.GetCpuManager().GetSuspendThreadStartFunc(); + std::function<void(void*)> init_func = Core::CpuManager::GetSuspendThreadStartFunc(); void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); - ThreadType type = + const auto type = static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_SUSPEND); - auto thread_res = Thread::Create(system, type, name, 0, 0, 0, static_cast<u32>(i), 0, - nullptr, std::move(init_func), init_func_parameter); + auto thread_res = + Thread::Create(system, type, std::move(name), 0, 0, 0, static_cast<u32>(i), 0, + nullptr, std::move(init_func), init_func_parameter); + suspend_threads[i] = std::move(thread_res).Unwrap(); } } @@ -307,7 +311,7 @@ struct KernelCore::Impl { // This is the kernel's handle table or supervisor handle table which // stores all the objects in place. - Kernel::HandleTable global_handle_table; + HandleTable global_handle_table; /// Map of named ports managed by the kernel, which can be retrieved using /// the ConnectToPort SVC. diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 49bd47e89..16285c3f0 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -9,6 +9,7 @@ #include <string> #include <unordered_map> #include <vector> +#include "core/arm/cpu_interrupt_handler.h" #include "core/hardware_properties.h" #include "core/hle/kernel/memory/memory_types.h" #include "core/hle/kernel/object.h" diff --git a/src/core/hle/kernel/memory/address_space_info.cpp b/src/core/hle/kernel/memory/address_space_info.cpp index a523a2502..e4288cab4 100644 --- a/src/core/hle/kernel/memory/address_space_info.cpp +++ b/src/core/hle/kernel/memory/address_space_info.cpp @@ -29,40 +29,39 @@ enum : u64 { // clang-format off constexpr std::array<AddressSpaceInfo, 13> AddressSpaceInfos{{ - { 32 /*bit_width*/, Size_2_MB /*addr*/, Size_1_GB - Size_2_MB /*size*/, AddressSpaceInfo::Type::Is32Bit, }, - { 32 /*bit_width*/, Size_1_GB /*addr*/, Size_4_GB - Size_1_GB /*size*/, AddressSpaceInfo::Type::Small64Bit, }, - { 32 /*bit_width*/, Invalid /*addr*/, Size_1_GB /*size*/, AddressSpaceInfo::Type::Heap, }, - { 32 /*bit_width*/, Invalid /*addr*/, Size_1_GB /*size*/, AddressSpaceInfo::Type::Alias, }, - { 36 /*bit_width*/, Size_128_MB /*addr*/, Size_2_GB - Size_128_MB /*size*/, AddressSpaceInfo::Type::Is32Bit, }, - { 36 /*bit_width*/, Size_2_GB /*addr*/, Size_64_GB - Size_2_GB /*size*/, AddressSpaceInfo::Type::Small64Bit, }, - { 36 /*bit_width*/, Invalid /*addr*/, Size_6_GB /*size*/, AddressSpaceInfo::Type::Heap, }, - { 36 /*bit_width*/, Invalid /*addr*/, Size_6_GB /*size*/, AddressSpaceInfo::Type::Alias, }, - { 39 /*bit_width*/, Size_128_MB /*addr*/, Size_512_GB - Size_128_MB /*size*/, AddressSpaceInfo::Type::Large64Bit, }, - { 39 /*bit_width*/, Invalid /*addr*/, Size_64_GB /*size*/, AddressSpaceInfo::Type::Is32Bit }, - { 39 /*bit_width*/, Invalid /*addr*/, Size_6_GB /*size*/, AddressSpaceInfo::Type::Heap, }, - { 39 /*bit_width*/, Invalid /*addr*/, Size_64_GB /*size*/, AddressSpaceInfo::Type::Alias, }, - { 39 /*bit_width*/, Invalid /*addr*/, Size_2_GB /*size*/, AddressSpaceInfo::Type::Stack, }, + { .bit_width = 32, .address = Size_2_MB , .size = Size_1_GB - Size_2_MB , .type = AddressSpaceInfo::Type::Is32Bit, }, + { .bit_width = 32, .address = Size_1_GB , .size = Size_4_GB - Size_1_GB , .type = AddressSpaceInfo::Type::Small64Bit, }, + { .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = AddressSpaceInfo::Type::Heap, }, + { .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = AddressSpaceInfo::Type::Alias, }, + { .bit_width = 36, .address = Size_128_MB, .size = Size_2_GB - Size_128_MB, .type = AddressSpaceInfo::Type::Is32Bit, }, + { .bit_width = 36, .address = Size_2_GB , .size = Size_64_GB - Size_2_GB , .type = AddressSpaceInfo::Type::Small64Bit, }, + { .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = AddressSpaceInfo::Type::Heap, }, + { .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = AddressSpaceInfo::Type::Alias, }, + { .bit_width = 39, .address = Size_128_MB, .size = Size_512_GB - Size_128_MB, .type = AddressSpaceInfo::Type::Large64Bit, }, + { .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = AddressSpaceInfo::Type::Is32Bit }, + { .bit_width = 39, .address = Invalid , .size = Size_6_GB , .type = AddressSpaceInfo::Type::Heap, }, + { .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = AddressSpaceInfo::Type::Alias, }, + { .bit_width = 39, .address = Invalid , .size = Size_2_GB , .type = AddressSpaceInfo::Type::Stack, }, }}; // clang-format on constexpr bool IsAllowedIndexForAddress(std::size_t index) { - return index < std::size(AddressSpaceInfos) && AddressSpaceInfos[index].GetAddress() != Invalid; + return index < AddressSpaceInfos.size() && AddressSpaceInfos[index].address != Invalid; } -constexpr std::array<std::size_t, static_cast<std::size_t>(AddressSpaceInfo::Type::Count)> - AddressSpaceIndices32Bit{ - 0, 1, 0, 2, 0, 3, - }; +using IndexArray = std::array<std::size_t, static_cast<std::size_t>(AddressSpaceInfo::Type::Count)>; -constexpr std::array<std::size_t, static_cast<std::size_t>(AddressSpaceInfo::Type::Count)> - AddressSpaceIndices36Bit{ - 4, 5, 4, 6, 4, 7, - }; +constexpr IndexArray AddressSpaceIndices32Bit{ + 0, 1, 0, 2, 0, 3, +}; + +constexpr IndexArray AddressSpaceIndices36Bit{ + 4, 5, 4, 6, 4, 7, +}; -constexpr std::array<std::size_t, static_cast<std::size_t>(AddressSpaceInfo::Type::Count)> - AddressSpaceIndices39Bit{ - 9, 8, 8, 10, 12, 11, - }; +constexpr IndexArray AddressSpaceIndices39Bit{ + 9, 8, 8, 10, 12, 11, +}; constexpr bool IsAllowed32BitType(AddressSpaceInfo::Type type) { return type < AddressSpaceInfo::Type::Count && type != AddressSpaceInfo::Type::Large64Bit && @@ -80,37 +79,37 @@ constexpr bool IsAllowed39BitType(AddressSpaceInfo::Type type) { } // namespace -u64 AddressSpaceInfo::GetAddressSpaceStart(std::size_t width, AddressSpaceInfo::Type type) { +u64 AddressSpaceInfo::GetAddressSpaceStart(std::size_t width, Type type) { const std::size_t index{static_cast<std::size_t>(type)}; switch (width) { case 32: ASSERT(IsAllowed32BitType(type)); ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices32Bit[index])); - return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].GetAddress(); + return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].address; case 36: ASSERT(IsAllowed36BitType(type)); ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices36Bit[index])); - return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].GetAddress(); + return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].address; case 39: ASSERT(IsAllowed39BitType(type)); ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices39Bit[index])); - return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].GetAddress(); + return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].address; } UNREACHABLE(); } -std::size_t AddressSpaceInfo::GetAddressSpaceSize(std::size_t width, AddressSpaceInfo::Type type) { +std::size_t AddressSpaceInfo::GetAddressSpaceSize(std::size_t width, Type type) { const std::size_t index{static_cast<std::size_t>(type)}; switch (width) { case 32: ASSERT(IsAllowed32BitType(type)); - return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].GetSize(); + return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].size; case 36: ASSERT(IsAllowed36BitType(type)); - return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].GetSize(); + return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].size; case 39: ASSERT(IsAllowed39BitType(type)); - return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].GetSize(); + return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].size; } UNREACHABLE(); } diff --git a/src/core/hle/kernel/memory/address_space_info.h b/src/core/hle/kernel/memory/address_space_info.h index c479890be..a4e6e91e5 100644 --- a/src/core/hle/kernel/memory/address_space_info.h +++ b/src/core/hle/kernel/memory/address_space_info.h @@ -11,8 +11,7 @@ namespace Kernel::Memory { -class AddressSpaceInfo final : NonCopyable { -public: +struct AddressSpaceInfo final { enum class Type : u32 { Is32Bit = 0, Small64Bit = 1, @@ -23,31 +22,13 @@ public: Count, }; -private: - std::size_t bit_width{}; - std::size_t addr{}; - std::size_t size{}; - Type type{}; - -public: static u64 GetAddressSpaceStart(std::size_t width, Type type); static std::size_t GetAddressSpaceSize(std::size_t width, Type type); - constexpr AddressSpaceInfo(std::size_t bit_width, std::size_t addr, std::size_t size, Type type) - : bit_width{bit_width}, addr{addr}, size{size}, type{type} {} - - constexpr std::size_t GetWidth() const { - return bit_width; - } - constexpr std::size_t GetAddress() const { - return addr; - } - constexpr std::size_t GetSize() const { - return size; - } - constexpr Type GetType() const { - return type; - } + const std::size_t bit_width{}; + const std::size_t address{}; + const std::size_t size{}; + const Type type{}; }; } // namespace Kernel::Memory diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index c6fcb56ad..ff9d9248b 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -408,7 +408,7 @@ void Process::LoadModule(CodeSet code_set, VAddr base_addr) { Process::Process(Core::System& system) : SynchronizationObject{system.Kernel()}, page_table{std::make_unique<Memory::PageTable>( system)}, - address_arbiter{system}, mutex{system}, system{system} {} + handle_table{system.Kernel()}, address_arbiter{system}, mutex{system}, system{system} {} Process::~Process() = default; diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 9dabe3568..f45cb5674 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -382,12 +382,6 @@ private: /// List of threads waiting for a condition variable std::unordered_map<VAddr, std::list<std::shared_ptr<Thread>>> cond_var_threads; - /// System context - Core::System& system; - - /// Name of this process - std::string name; - /// Address of the top of the main thread's stack VAddr main_thread_stack_top{}; @@ -399,6 +393,12 @@ private: /// Process total image size std::size_t image_size{}; + + /// Name of this process + std::string name; + + /// System context + Core::System& system; }; } // namespace Kernel diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 7b929781c..f93e5e4b0 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -802,7 +802,7 @@ void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { void Scheduler::Initialize() { std::string name = "Idle Thread Id:" + std::to_string(core_id); - std::function<void(void*)> init_func = system.GetCpuManager().GetIdleThreadStartFunc(); + std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc(); void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); ThreadType type = static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_IDLE); auto thread_res = Thread::Create(system, type, name, 0, 64, 0, static_cast<u32>(core_id), 0, diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 7b23a6889..af22f4c33 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -34,7 +34,7 @@ ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kern std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)}; session->request_event = Core::Timing::CreateEvent( - name, [session](u64 userdata, s64 cycles_late) { session->CompleteSyncRequest(); }); + name, [session](u64, std::chrono::nanoseconds) { session->CompleteSyncRequest(); }); session->name = std::move(name); session->parent = std::move(parent); @@ -184,8 +184,8 @@ ResultCode ServerSession::CompleteSyncRequest() { ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory) { - ResultCode result = QueueSyncRequest(std::move(thread), memory); - const u64 delay = kernel.IsMulticore() ? 0U : 20000U; + const ResultCode result = QueueSyncRequest(std::move(thread), memory); + const auto delay = std::chrono::nanoseconds{kernel.IsMulticore() ? 0 : 20000}; Core::System::GetInstance().CoreTiming().ScheduleEvent(delay, request_event, {}); return result; } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 5db19dcf3..01ae57053 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -458,9 +458,7 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr return ERR_OUT_OF_RANGE; } - auto* const thread = system.CurrentScheduler().GetCurrentThread(); auto& kernel = system.Kernel(); - using ObjectPtr = Thread::ThreadSynchronizationObjects::value_type; Thread::ThreadSynchronizationObjects objects(handle_count); const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); @@ -1750,9 +1748,9 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ // Only process up to 'target' threads, unless 'target' is less equal 0, in which case process // them all. std::size_t last = waiting_threads.size(); - if (target > 0) + if (target > 0) { last = std::min(waiting_threads.size(), static_cast<std::size_t>(target)); - auto& time_manager = kernel.TimeManager(); + } for (std::size_t index = 0; index < last; ++index) { auto& thread = waiting_threads[index]; @@ -1763,7 +1761,6 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ const std::size_t current_core = system.CurrentCoreIndex(); auto& monitor = system.Monitor(); - auto& memory = system.Memory(); // Atomically read the value of the mutex. u32 mutex_val = 0; diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp index 851b702a5..8b875d853 100644 --- a/src/core/hle/kernel/synchronization.cpp +++ b/src/core/hle/kernel/synchronization.cpp @@ -19,7 +19,6 @@ Synchronization::Synchronization(Core::System& system) : system{system} {} void Synchronization::SignalObject(SynchronizationObject& obj) const { auto& kernel = system.Kernel(); SchedulerLock lock(kernel); - auto& time_manager = kernel.TimeManager(); if (obj.IsSignaled()) { for (auto thread : obj.GetWaitingThreads()) { if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) { diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 2b1092697..d132aba34 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -13,16 +13,8 @@ #include "common/logging/log.h" #include "common/thread_queue_list.h" #include "core/arm/arm_interface.h" -#ifdef ARCHITECTURE_x86_64 -#include "core/arm/dynarmic/arm_dynarmic_32.h" -#include "core/arm/dynarmic/arm_dynarmic_64.h" -#endif -#include "core/arm/cpu_interrupt_handler.h" -#include "core/arm/exclusive_monitor.h" #include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" -#include "core/core_timing.h" -#include "core/core_timing_util.h" #include "core/cpu_manager.h" #include "core/hardware_properties.h" #include "core/hle/kernel/errors.h" @@ -36,6 +28,11 @@ #include "core/hle/result.h" #include "core/memory.h" +#ifdef ARCHITECTURE_x86_64 +#include "core/arm/dynarmic/arm_dynarmic_32.h" +#include "core/arm/dynarmic/arm_dynarmic_64.h" +#endif + namespace Kernel { bool Thread::ShouldWait(const Thread* thread) const { @@ -158,7 +155,7 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy std::string name, VAddr entry_point, u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process) { - std::function<void(void*)> init_func = system.GetCpuManager().GetGuestThreadStartFunc(); + std::function<void(void*)> init_func = Core::CpuManager::GetGuestThreadStartFunc(); void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); return Create(system, type_flags, name, entry_point, priority, arg, processor_id, stack_top, owner_process, std::move(init_func), init_func_parameter); @@ -540,13 +537,4 @@ ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { return RESULT_SUCCESS; } -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * Gets the current thread - */ -Thread* GetCurrentThread() { - return Core::System::GetInstance().CurrentScheduler().GetCurrentThread(); -} - } // namespace Kernel diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index c0342c462..8daf79fac 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -583,8 +583,6 @@ private: void SetCurrentPriority(u32 new_priority); - void AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core); - Common::SpinLock context_guard{}; ThreadContext32 context_32{}; ThreadContext64 context_64{}; @@ -680,9 +678,4 @@ private: std::string name; }; -/** - * Gets the current thread - */ -Thread* GetCurrentThread(); - } // namespace Kernel diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index 941305e8e..88b01b751 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp @@ -16,7 +16,7 @@ namespace Kernel { TimeManager::TimeManager(Core::System& system_) : system{system_} { time_manager_event_type = Core::Timing::CreateEvent( - "Kernel::TimeManagerCallback", [this](u64 thread_handle, [[maybe_unused]] s64 cycles_late) { + "Kernel::TimeManagerCallback", [this](u64 thread_handle, std::chrono::nanoseconds) { SchedulerLock lock(system.Kernel()); Handle proper_handle = static_cast<Handle>(thread_handle); if (cancelled_events[proper_handle]) { @@ -34,7 +34,8 @@ void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 ASSERT(timetask); ASSERT(timetask->GetStatus() != ThreadStatus::Ready); ASSERT(timetask->GetStatus() != ThreadStatus::WaitMutex); - system.CoreTiming().ScheduleEvent(nanoseconds, time_manager_event_type, event_handle); + system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds{nanoseconds}, + time_manager_event_type, event_handle); } else { event_handle = InvalidHandle; } diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index fbe3686ae..289da2619 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -13,11 +13,23 @@ namespace Service::AM::Applets { +namespace { +enum class Request : u32 { + Finalize = 0x4, + SetUserWordInfo = 0x6, + SetCustomizeDic = 0x7, + Calc = 0xa, + SetCustomizedDictionaries = 0xb, + UnsetCustomizedDictionaries = 0xc, + UnknownD = 0xd, + UnknownE = 0xe, +}; +constexpr std::size_t SWKBD_INLINE_INIT_SIZE = 0x8; constexpr std::size_t SWKBD_OUTPUT_BUFFER_SIZE = 0x7D8; constexpr std::size_t SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE = 0x7D4; constexpr std::size_t DEFAULT_MAX_LENGTH = 500; constexpr bool INTERACTIVE_STATUS_OK = false; - +} // Anonymous namespace static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters( KeyboardConfig config, std::u16string initial_text) { Core::Frontend::SoftwareKeyboardParameters params{}; @@ -47,6 +59,7 @@ SoftwareKeyboard::~SoftwareKeyboard() = default; void SoftwareKeyboard::Initialize() { complete = false; + is_inline = false; initial_text.clear(); final_data.clear(); @@ -56,6 +69,11 @@ void SoftwareKeyboard::Initialize() { ASSERT(keyboard_config_storage != nullptr); const auto& keyboard_config = keyboard_config_storage->GetData(); + if (keyboard_config.size() == SWKBD_INLINE_INIT_SIZE) { + is_inline = true; + return; + } + ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig)); std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig)); @@ -87,16 +105,32 @@ void SoftwareKeyboard::ExecuteInteractive() { const auto storage = broker.PopInteractiveDataToApplet(); ASSERT(storage != nullptr); const auto data = storage->GetData(); - const auto status = static_cast<bool>(data[0]); - - if (status == INTERACTIVE_STATUS_OK) { - complete = true; + if (!is_inline) { + const auto status = static_cast<bool>(data[0]); + if (status == INTERACTIVE_STATUS_OK) { + complete = true; + } else { + std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string; + std::memcpy(string.data(), data.data() + 4, string.size() * 2); + frontend.SendTextCheckDialog( + Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()), + [this] { broker.SignalStateChanged(); }); + } } else { - std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string; - std::memcpy(string.data(), data.data() + 4, string.size() * 2); - frontend.SendTextCheckDialog( - Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()), - [this] { broker.SignalStateChanged(); }); + Request request{}; + std::memcpy(&request, data.data(), sizeof(Request)); + + switch (request) { + case Request::Calc: { + broker.PushNormalDataFromApplet( + std::make_shared<IStorage>(std::move(std::vector<u8>{1}))); + broker.SignalStateChanged(); + break; + } + default: + UNIMPLEMENTED_MSG("Request {:X} is not implemented", request); + break; + } } } @@ -108,9 +142,10 @@ void SoftwareKeyboard::Execute() { } const auto parameters = ConvertToFrontendParameters(config, initial_text); - - frontend.RequestText([this](std::optional<std::u16string> text) { WriteText(std::move(text)); }, - parameters); + if (!is_inline) { + frontend.RequestText( + [this](std::optional<std::u16string> text) { WriteText(std::move(text)); }, parameters); + } } void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) { diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h index ef4801fc6..5a3824b5a 100644 --- a/src/core/hle/service/am/applets/software_keyboard.h +++ b/src/core/hle/service/am/applets/software_keyboard.h @@ -78,6 +78,7 @@ private: KeyboardConfig config; std::u16string initial_text; bool complete = false; + bool is_inline = false; std::vector<u8> final_data; }; diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index cadc03805..c66124998 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -55,6 +55,10 @@ std::string VfsDirectoryServiceWrapper::GetName() const { ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size) const { std::string path(FileUtil::SanitizePath(path_)); auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); + // dir can be nullptr if path contains subdirectories, create those prior to creating the file. + if (dir == nullptr) { + dir = backing->CreateSubdirectory(FileUtil::GetParentPath(path)); + } auto file = dir->CreateFile(FileUtil::GetFilename(path)); if (file == nullptr) { // TODO(DarkLordZach): Find a better error code for this diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index e9020e0dc..680290cbd 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -39,9 +39,10 @@ namespace Service::HID { // Updating period for each HID device. // TODO(ogniK): Find actual polling rate of hid -constexpr s64 pad_update_ticks = static_cast<s64>(1000000000 / 66); -[[maybe_unused]] constexpr s64 accelerometer_update_ticks = static_cast<s64>(1000000000 / 100); -[[maybe_unused]] constexpr s64 gyroscope_update_ticks = static_cast<s64>(1000000000 / 100); +constexpr auto pad_update_ns = std::chrono::nanoseconds{1000000000 / 66}; +[[maybe_unused]] constexpr auto accelerometer_update_ns = + std::chrono::nanoseconds{1000000000 / 100}; +[[maybe_unused]] constexpr auto gyroscope_update_ticks = std::chrono::nanoseconds{1000000000 / 100}; constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; IAppletResource::IAppletResource(Core::System& system) @@ -75,14 +76,14 @@ IAppletResource::IAppletResource(Core::System& system) GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000); // Register update callbacks - pad_update_event = - Core::Timing::CreateEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 ns_late) { + pad_update_event = Core::Timing::CreateEvent( + "HID::UpdatePadCallback", [this](u64 userdata, std::chrono::nanoseconds ns_late) { UpdateControllers(userdata, ns_late); }); // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) - system.CoreTiming().ScheduleEvent(pad_update_ticks, pad_update_event); + system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event); ReloadInputDevices(); } @@ -107,7 +108,7 @@ void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { rb.PushCopyObjects(shared_mem); } -void IAppletResource::UpdateControllers(u64 userdata, s64 ns_late) { +void IAppletResource::UpdateControllers(u64 userdata, std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); @@ -118,7 +119,7 @@ void IAppletResource::UpdateControllers(u64 userdata, s64 ns_late) { controller->OnUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE); } - core_timing.ScheduleEvent(pad_update_ticks - ns_late, pad_update_event); + core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event); } class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 6fb048360..c6f0a2584 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -4,10 +4,9 @@ #pragma once -#include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/service.h" +#include <chrono> -#include "controllers/controller_base.h" +#include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/service.h" namespace Core::Timing { @@ -65,7 +64,7 @@ private: } void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); - void UpdateControllers(u64 userdata, s64 cycles_late); + void UpdateControllers(u64 userdata, std::chrono::nanoseconds ns_late); std::shared_ptr<Kernel::SharedMemory> shared_mem; diff --git a/src/core/hle/service/mii/manager.cpp b/src/core/hle/service/mii/manager.cpp new file mode 100644 index 000000000..4730070cb --- /dev/null +++ b/src/core/hle/service/mii/manager.cpp @@ -0,0 +1,484 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <cstring> +#include <random> + +#include "common/assert.h" +#include "common/file_util.h" +#include "common/logging/log.h" +#include "common/string_util.h" + +#include "core/hle/service/acc/profile_manager.h" +#include "core/hle/service/mii/manager.h" +#include "core/hle/service/mii/raw_data.h" +#include "core/hle/service/mii/types.h" + +namespace Service::Mii { + +namespace { + +constexpr ResultCode ERROR_CANNOT_FIND_ENTRY{ErrorModule::Mii, 4}; + +constexpr std::size_t DefaultMiiCount{sizeof(RawData::DefaultMii) / sizeof(DefaultMii)}; + +constexpr MiiStoreData::Name DefaultMiiName{u'y', u'u', u'z', u'u'}; +constexpr std::array<u8, 8> HairColorLookup{8, 1, 2, 3, 4, 5, 6, 7}; +constexpr std::array<u8, 6> EyeColorLookup{8, 9, 10, 11, 12, 13}; +constexpr std::array<u8, 5> MouthColorLookup{19, 20, 21, 22, 23}; +constexpr std::array<u8, 7> GlassesColorLookup{8, 14, 15, 16, 17, 18, 0}; +constexpr std::array<u8, 62> EyeRotateLookup{ + {0x03, 0x04, 0x04, 0x04, 0x03, 0x04, 0x04, 0x04, 0x03, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x04, + 0x04, 0x04, 0x03, 0x03, 0x04, 0x03, 0x04, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x03, 0x04, 0x04, + 0x04, 0x03, 0x03, 0x03, 0x04, 0x04, 0x03, 0x03, 0x03, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x03, 0x04, 0x04, 0x03, 0x04, 0x04}}; +constexpr std::array<u8, 24> EyebrowRotateLookup{{0x06, 0x06, 0x05, 0x07, 0x06, 0x07, 0x06, 0x07, + 0x04, 0x07, 0x06, 0x08, 0x05, 0x05, 0x06, 0x06, + 0x07, 0x07, 0x06, 0x06, 0x05, 0x06, 0x07, 0x05}}; + +template <typename T, std::size_t SourceArraySize, std::size_t DestArraySize> +std::array<T, DestArraySize> ResizeArray(const std::array<T, SourceArraySize>& in) { + std::array<T, DestArraySize> out{}; + std::memcpy(out.data(), in.data(), sizeof(T) * std::min(SourceArraySize, DestArraySize)); + return out; +} + +MiiInfo ConvertStoreDataToInfo(const MiiStoreData& data) { + MiiStoreBitFields bf; + std::memcpy(&bf, data.data.data.data(), sizeof(MiiStoreBitFields)); + + return { + .uuid = data.data.uuid, + .name = ResizeArray<char16_t, 10, 11>(data.data.name), + .font_region = static_cast<u8>(bf.font_region.Value()), + .favorite_color = static_cast<u8>(bf.favorite_color.Value()), + .gender = static_cast<u8>(bf.gender.Value()), + .height = static_cast<u8>(bf.height.Value()), + .build = static_cast<u8>(bf.build.Value()), + .type = static_cast<u8>(bf.type.Value()), + .region_move = static_cast<u8>(bf.region_move.Value()), + .faceline_type = static_cast<u8>(bf.faceline_type.Value()), + .faceline_color = static_cast<u8>(bf.faceline_color.Value()), + .faceline_wrinkle = static_cast<u8>(bf.faceline_wrinkle.Value()), + .faceline_make = static_cast<u8>(bf.faceline_makeup.Value()), + .hair_type = static_cast<u8>(bf.hair_type.Value()), + .hair_color = static_cast<u8>(bf.hair_color.Value()), + .hair_flip = static_cast<u8>(bf.hair_flip.Value()), + .eye_type = static_cast<u8>(bf.eye_type.Value()), + .eye_color = static_cast<u8>(bf.eye_color.Value()), + .eye_scale = static_cast<u8>(bf.eye_scale.Value()), + .eye_aspect = static_cast<u8>(bf.eye_aspect.Value()), + .eye_rotate = static_cast<u8>(bf.eye_rotate.Value()), + .eye_x = static_cast<u8>(bf.eye_x.Value()), + .eye_y = static_cast<u8>(bf.eye_y.Value()), + .eyebrow_type = static_cast<u8>(bf.eyebrow_type.Value()), + .eyebrow_color = static_cast<u8>(bf.eyebrow_color.Value()), + .eyebrow_scale = static_cast<u8>(bf.eyebrow_scale.Value()), + .eyebrow_aspect = static_cast<u8>(bf.eyebrow_aspect.Value()), + .eyebrow_rotate = static_cast<u8>(bf.eyebrow_rotate.Value()), + .eyebrow_x = static_cast<u8>(bf.eyebrow_x.Value()), + .eyebrow_y = static_cast<u8>(bf.eyebrow_y.Value() + 3), + .nose_type = static_cast<u8>(bf.nose_type.Value()), + .nose_scale = static_cast<u8>(bf.nose_scale.Value()), + .nose_y = static_cast<u8>(bf.nose_y.Value()), + .mouth_type = static_cast<u8>(bf.mouth_type.Value()), + .mouth_color = static_cast<u8>(bf.mouth_color.Value()), + .mouth_scale = static_cast<u8>(bf.mouth_scale.Value()), + .mouth_aspect = static_cast<u8>(bf.mouth_aspect.Value()), + .mouth_y = static_cast<u8>(bf.mouth_y.Value()), + .beard_color = static_cast<u8>(bf.beard_color.Value()), + .beard_type = static_cast<u8>(bf.beard_type.Value()), + .mustache_type = static_cast<u8>(bf.mustache_type.Value()), + .mustache_scale = static_cast<u8>(bf.mustache_scale.Value()), + .mustache_y = static_cast<u8>(bf.mustache_y.Value()), + .glasses_type = static_cast<u8>(bf.glasses_type.Value()), + .glasses_color = static_cast<u8>(bf.glasses_color.Value()), + .glasses_scale = static_cast<u8>(bf.glasses_scale.Value()), + .glasses_y = static_cast<u8>(bf.glasses_y.Value()), + .mole_type = static_cast<u8>(bf.mole_type.Value()), + .mole_scale = static_cast<u8>(bf.mole_scale.Value()), + .mole_x = static_cast<u8>(bf.mole_x.Value()), + .mole_y = static_cast<u8>(bf.mole_y.Value()), + }; +} + +u16 GenerateCrc16(const void* data, std::size_t size) { + s32 crc{}; + for (std::size_t i = 0; i < size; i++) { + crc ^= static_cast<const u8*>(data)[i] << 8; + for (std::size_t j = 0; j < 8; j++) { + crc <<= 1; + if ((crc & 0x10000) != 0) { + crc = (crc ^ 0x1021) & 0xFFFF; + } + } + } + return Common::swap16(static_cast<u16>(crc)); +} + +Common::UUID GenerateValidUUID() { + auto uuid{Common::UUID::Generate()}; + + // Bit 7 must be set, and bit 6 unset for the UUID to be valid + uuid.uuid[1] &= 0xFFFFFFFFFFFFFF3FULL; + uuid.uuid[1] |= 0x0000000000000080ULL; + + return uuid; +} + +template <typename T> +T GetRandomValue(T min, T max) { + std::random_device device; + std::mt19937 gen(device()); + std::uniform_int_distribution<u64> distribution(0, static_cast<u64>(max)); + return static_cast<T>(distribution(gen)); +} + +template <typename T> +T GetRandomValue(T max) { + return GetRandomValue<T>({}, max); +} + +template <typename T> +T GetArrayValue(const u8* data, std::size_t index) { + T result{}; + std::memcpy(&result, &data[index * sizeof(T)], sizeof(T)); + return result; +} + +MiiStoreData BuildRandomStoreData(Age age, Gender gender, Race race, const Common::UUID& user_id) { + MiiStoreBitFields bf{}; + + if (gender == Gender::All) { + gender = GetRandomValue<Gender>(Gender::Maximum); + } + + bf.gender.Assign(gender); + bf.favorite_color.Assign(GetRandomValue<u8>(11)); + bf.region_move.Assign(0); + bf.font_region.Assign(FontRegion::Standard); + bf.type.Assign(0); + bf.height.Assign(64); + bf.build.Assign(64); + + if (age == Age::All) { + const auto temp{GetRandomValue<int>(10)}; + if (temp >= 8) { + age = Age::Old; + } else if (temp >= 4) { + age = Age::Normal; + } else { + age = Age::Young; + } + } + + if (race == Race::All) { + const auto temp{GetRandomValue<int>(10)}; + if (temp >= 8) { + race = Race::Black; + } else if (temp >= 4) { + race = Race::White; + } else { + race = Race::Asian; + } + } + + u32 axis_y{}; + if (gender == Gender::Female && age == Age::Young) { + axis_y = GetRandomValue<u32>(3); + } + + const std::size_t index{3 * static_cast<std::size_t>(age) + + 9 * static_cast<std::size_t>(gender) + static_cast<std::size_t>(race)}; + + const auto faceline_type_info{ + GetArrayValue<RandomMiiData4>(&RawData::RandomMiiFaceline[0], index)}; + const auto faceline_color_info{GetArrayValue<RandomMiiData3>( + RawData::RandomMiiFacelineColor.data(), + 3 * static_cast<std::size_t>(gender) + static_cast<std::size_t>(race))}; + const auto faceline_wrinkle_info{ + GetArrayValue<RandomMiiData4>(RawData::RandomMiiFacelineWrinkle.data(), index)}; + const auto faceline_makeup_info{ + GetArrayValue<RandomMiiData4>(RawData::RandomMiiFacelineMakeup.data(), index)}; + const auto hair_type_info{ + GetArrayValue<RandomMiiData4>(RawData::RandomMiiHairType.data(), index)}; + const auto hair_color_info{GetArrayValue<RandomMiiData3>(RawData::RandomMiiHairColor.data(), + 3 * static_cast<std::size_t>(race) + + static_cast<std::size_t>(age))}; + const auto eye_type_info{ + GetArrayValue<RandomMiiData4>(RawData::RandomMiiEyeType.data(), index)}; + const auto eye_color_info{GetArrayValue<RandomMiiData2>(RawData::RandomMiiEyeColor.data(), + static_cast<std::size_t>(race))}; + const auto eyebrow_type_info{ + GetArrayValue<RandomMiiData4>(RawData::RandomMiiEyebrowType.data(), index)}; + const auto nose_type_info{ + GetArrayValue<RandomMiiData4>(RawData::RandomMiiNoseType.data(), index)}; + const auto mouth_type_info{ + GetArrayValue<RandomMiiData4>(RawData::RandomMiiMouthType.data(), index)}; + const auto glasses_type_info{GetArrayValue<RandomMiiData2>(RawData::RandomMiiGlassType.data(), + static_cast<std::size_t>(age))}; + + bf.faceline_type.Assign( + faceline_type_info.values[GetRandomValue<std::size_t>(faceline_type_info.values_count)]); + bf.faceline_color.Assign( + faceline_color_info.values[GetRandomValue<std::size_t>(faceline_color_info.values_count)]); + bf.faceline_wrinkle.Assign( + faceline_wrinkle_info + .values[GetRandomValue<std::size_t>(faceline_wrinkle_info.values_count)]); + bf.faceline_makeup.Assign( + faceline_makeup_info + .values[GetRandomValue<std::size_t>(faceline_makeup_info.values_count)]); + + bf.hair_type.Assign( + hair_type_info.values[GetRandomValue<std::size_t>(hair_type_info.values_count)]); + bf.hair_color.Assign( + HairColorLookup[hair_color_info + .values[GetRandomValue<std::size_t>(hair_color_info.values_count)]]); + bf.hair_flip.Assign(GetRandomValue<HairFlip>(HairFlip::Maximum)); + + bf.eye_type.Assign( + eye_type_info.values[GetRandomValue<std::size_t>(eye_type_info.values_count)]); + + const auto eye_rotate_1{gender != Gender::Male ? 4 : 2}; + const auto eye_rotate_2{gender != Gender::Male ? 3 : 4}; + const auto eye_rotate_offset{32 - EyeRotateLookup[eye_rotate_1] + eye_rotate_2}; + const auto eye_rotate{32 - EyeRotateLookup[bf.eye_type]}; + + bf.eye_color.Assign( + EyeColorLookup[eye_color_info + .values[GetRandomValue<std::size_t>(eye_color_info.values_count)]]); + bf.eye_scale.Assign(4); + bf.eye_aspect.Assign(3); + bf.eye_rotate.Assign(eye_rotate_offset - eye_rotate); + bf.eye_x.Assign(2); + bf.eye_y.Assign(axis_y + 12); + + bf.eyebrow_type.Assign( + eyebrow_type_info.values[GetRandomValue<std::size_t>(eyebrow_type_info.values_count)]); + + const auto eyebrow_rotate_1{race == Race::Asian ? 6 : 0}; + const auto eyebrow_y{race == Race::Asian ? 9 : 10}; + const auto eyebrow_rotate_offset{32 - EyebrowRotateLookup[eyebrow_rotate_1] + 6}; + const auto eyebrow_rotate{ + 32 - EyebrowRotateLookup[static_cast<std::size_t>(bf.eyebrow_type.Value())]}; + + bf.eyebrow_color.Assign(bf.hair_color); + bf.eyebrow_scale.Assign(4); + bf.eyebrow_aspect.Assign(3); + bf.eyebrow_rotate.Assign(eyebrow_rotate_offset - eyebrow_rotate); + bf.eyebrow_x.Assign(2); + bf.eyebrow_y.Assign(axis_y + eyebrow_y); + + const auto nose_scale{gender == Gender::Female ? 3 : 4}; + + bf.nose_type.Assign( + nose_type_info.values[GetRandomValue<std::size_t>(nose_type_info.values_count)]); + bf.nose_scale.Assign(nose_scale); + bf.nose_y.Assign(axis_y + 9); + + const auto mouth_color{gender == Gender::Female ? GetRandomValue<int>(4) : 0}; + + bf.mouth_type.Assign( + mouth_type_info.values[GetRandomValue<std::size_t>(mouth_type_info.values_count)]); + bf.mouth_color.Assign(MouthColorLookup[mouth_color]); + bf.mouth_scale.Assign(4); + bf.mouth_aspect.Assign(3); + bf.mouth_y.Assign(axis_y + 13); + + bf.beard_color.Assign(bf.hair_color); + bf.mustache_scale.Assign(4); + + if (gender == Gender::Male && age != Age::Young && GetRandomValue<int>(10) < 2) { + const auto mustache_and_beard_flag{ + GetRandomValue<BeardAndMustacheFlag>(BeardAndMustacheFlag::All)}; + + auto beard_type{BeardType::None}; + auto mustache_type{MustacheType::None}; + + if ((mustache_and_beard_flag & BeardAndMustacheFlag::Beard) == + BeardAndMustacheFlag::Beard) { + beard_type = GetRandomValue<BeardType>(BeardType::Beard1, BeardType::Beard5); + } + + if ((mustache_and_beard_flag & BeardAndMustacheFlag::Mustache) == + BeardAndMustacheFlag::Mustache) { + mustache_type = + GetRandomValue<MustacheType>(MustacheType::Mustache1, MustacheType::Mustache5); + } + + bf.mustache_type.Assign(mustache_type); + bf.beard_type.Assign(beard_type); + bf.mustache_y.Assign(10); + } else { + bf.mustache_type.Assign(MustacheType::None); + bf.beard_type.Assign(BeardType::None); + bf.mustache_y.Assign(axis_y + 10); + } + + const auto glasses_type_start{GetRandomValue<std::size_t>(100)}; + u8 glasses_type{}; + while (glasses_type_start < glasses_type_info.values[glasses_type]) { + if (++glasses_type >= glasses_type_info.values_count) { + UNREACHABLE(); + break; + } + } + + bf.glasses_type.Assign(glasses_type); + bf.glasses_color.Assign(GlassesColorLookup[0]); + bf.glasses_scale.Assign(4); + bf.glasses_y.Assign(axis_y + 10); + + bf.mole_type.Assign(0); + bf.mole_scale.Assign(4); + bf.mole_x.Assign(2); + bf.mole_y.Assign(20); + + return {DefaultMiiName, bf, user_id}; +} + +MiiStoreData BuildDefaultStoreData(const DefaultMii& info, const Common::UUID& user_id) { + MiiStoreBitFields bf{}; + + bf.font_region.Assign(info.font_region); + bf.favorite_color.Assign(info.favorite_color); + bf.gender.Assign(info.gender); + bf.height.Assign(info.height); + bf.build.Assign(info.weight); + bf.type.Assign(info.type); + bf.region_move.Assign(info.region); + bf.faceline_type.Assign(info.face_type); + bf.faceline_color.Assign(info.face_color); + bf.faceline_wrinkle.Assign(info.face_wrinkle); + bf.faceline_makeup.Assign(info.face_makeup); + bf.hair_type.Assign(info.hair_type); + bf.hair_color.Assign(HairColorLookup[info.hair_color]); + bf.hair_flip.Assign(static_cast<HairFlip>(info.hair_flip)); + bf.eye_type.Assign(info.eye_type); + bf.eye_color.Assign(EyeColorLookup[info.eye_color]); + bf.eye_scale.Assign(info.eye_scale); + bf.eye_aspect.Assign(info.eye_aspect); + bf.eye_rotate.Assign(info.eye_rotate); + bf.eye_x.Assign(info.eye_x); + bf.eye_y.Assign(info.eye_y); + bf.eyebrow_type.Assign(info.eyebrow_type); + bf.eyebrow_color.Assign(HairColorLookup[info.eyebrow_color]); + bf.eyebrow_scale.Assign(info.eyebrow_scale); + bf.eyebrow_aspect.Assign(info.eyebrow_aspect); + bf.eyebrow_rotate.Assign(info.eyebrow_rotate); + bf.eyebrow_x.Assign(info.eyebrow_x); + bf.eyebrow_y.Assign(info.eyebrow_y - 3); + bf.nose_type.Assign(info.nose_type); + bf.nose_scale.Assign(info.nose_scale); + bf.nose_y.Assign(info.nose_y); + bf.mouth_type.Assign(info.mouth_type); + bf.mouth_color.Assign(MouthColorLookup[info.mouth_color]); + bf.mouth_scale.Assign(info.mouth_scale); + bf.mouth_aspect.Assign(info.mouth_aspect); + bf.mouth_y.Assign(info.mouth_y); + bf.beard_color.Assign(HairColorLookup[info.beard_color]); + bf.beard_type.Assign(static_cast<BeardType>(info.beard_type)); + bf.mustache_type.Assign(static_cast<MustacheType>(info.mustache_type)); + bf.mustache_scale.Assign(info.mustache_scale); + bf.mustache_y.Assign(info.mustache_y); + bf.glasses_type.Assign(info.glasses_type); + bf.glasses_color.Assign(GlassesColorLookup[info.glasses_color]); + bf.glasses_scale.Assign(info.glasses_scale); + bf.glasses_y.Assign(info.glasses_y); + bf.mole_type.Assign(info.mole_type); + bf.mole_scale.Assign(info.mole_scale); + bf.mole_x.Assign(info.mole_x); + bf.mole_y.Assign(info.mole_y); + + return {DefaultMiiName, bf, user_id}; +} + +} // namespace + +MiiStoreData::MiiStoreData() = default; + +MiiStoreData::MiiStoreData(const MiiStoreData::Name& name, const MiiStoreBitFields& bit_fields, + const Common::UUID& user_id) { + data.name = name; + data.uuid = GenerateValidUUID(); + + std::memcpy(data.data.data(), &bit_fields, sizeof(MiiStoreBitFields)); + data_crc = GenerateCrc16(data.data.data(), sizeof(data)); + device_crc = GenerateCrc16(&user_id, sizeof(Common::UUID)); +} + +MiiManager::MiiManager() : user_id{Service::Account::ProfileManager().GetLastOpenedUser()} {} + +bool MiiManager::CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter) { + if ((source_flag & SourceFlag::Database) == SourceFlag::None) { + return false; + } + + const bool result{current_update_counter != update_counter}; + + current_update_counter = update_counter; + + return result; +} + +bool MiiManager::IsFullDatabase() const { + // TODO(bunnei): We don't implement the Mii database, so it cannot be full + return false; +} + +u32 MiiManager::GetCount(SourceFlag source_flag) const { + u32 count{}; + if ((source_flag & SourceFlag::Database) != SourceFlag::None) { + // TODO(bunnei): We don't implement the Mii database, but when we do, update this + count += 0; + } + if ((source_flag & SourceFlag::Default) != SourceFlag::None) { + count += DefaultMiiCount; + } + return count; +} + +ResultVal<MiiInfo> MiiManager::UpdateLatest([[maybe_unused]] const MiiInfo& info, + SourceFlag source_flag) { + if ((source_flag & SourceFlag::Database) == SourceFlag::None) { + return ERROR_CANNOT_FIND_ENTRY; + } + + // TODO(bunnei): We don't implement the Mii database, so we can't have an entry + return ERROR_CANNOT_FIND_ENTRY; +} + +MiiInfo MiiManager::BuildRandom(Age age, Gender gender, Race race) { + return ConvertStoreDataToInfo(BuildRandomStoreData(age, gender, race, user_id)); +} + +MiiInfo MiiManager::BuildDefault(std::size_t index) { + return ConvertStoreDataToInfo(BuildDefaultStoreData( + GetArrayValue<DefaultMii>(RawData::DefaultMii.data(), index), user_id)); +} + +ResultVal<std::vector<MiiInfoElement>> MiiManager::GetDefault(SourceFlag source_flag) { + std::vector<MiiInfoElement> result; + + if ((source_flag & SourceFlag::Default) == SourceFlag::None) { + return MakeResult(std::move(result)); + } + + for (std::size_t index = 0; index < DefaultMiiCount; index++) { + result.emplace_back(BuildDefault(index), Source::Default); + } + + return MakeResult(std::move(result)); +} + +ResultCode MiiManager::GetIndex([[maybe_unused]] const MiiInfo& info, u32& index) { + constexpr u32 INVALID_INDEX{0xFFFFFFFF}; + + index = INVALID_INDEX; + + // TODO(bunnei): We don't implement the Mii database, so we can't have an index + return ERROR_CANNOT_FIND_ENTRY; +} + +} // namespace Service::Mii diff --git a/src/core/hle/service/mii/manager.h b/src/core/hle/service/mii/manager.h new file mode 100644 index 000000000..927451dea --- /dev/null +++ b/src/core/hle/service/mii/manager.h @@ -0,0 +1,331 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/bit_field.h" +#include "common/common_funcs.h" +#include "common/uuid.h" +#include "core/hle/result.h" +#include "core/hle/service/mii/types.h" + +namespace Service::Mii { + +enum class Source : u32 { + Database = 0, + Default = 1, + Account = 2, + Friend = 3, +}; + +enum class SourceFlag : u32 { + None = 0, + Database = 1 << 0, + Default = 1 << 1, +}; +DECLARE_ENUM_FLAG_OPERATORS(SourceFlag); + +struct MiiInfo { + Common::UUID uuid{Common::INVALID_UUID}; + std::array<char16_t, 11> name{}; + u8 font_region{}; + u8 favorite_color{}; + u8 gender{}; + u8 height{}; + u8 build{}; + u8 type{}; + u8 region_move{}; + u8 faceline_type{}; + u8 faceline_color{}; + u8 faceline_wrinkle{}; + u8 faceline_make{}; + u8 hair_type{}; + u8 hair_color{}; + u8 hair_flip{}; + u8 eye_type{}; + u8 eye_color{}; + u8 eye_scale{}; + u8 eye_aspect{}; + u8 eye_rotate{}; + u8 eye_x{}; + u8 eye_y{}; + u8 eyebrow_type{}; + u8 eyebrow_color{}; + u8 eyebrow_scale{}; + u8 eyebrow_aspect{}; + u8 eyebrow_rotate{}; + u8 eyebrow_x{}; + u8 eyebrow_y{}; + u8 nose_type{}; + u8 nose_scale{}; + u8 nose_y{}; + u8 mouth_type{}; + u8 mouth_color{}; + u8 mouth_scale{}; + u8 mouth_aspect{}; + u8 mouth_y{}; + u8 beard_color{}; + u8 beard_type{}; + u8 mustache_type{}; + u8 mustache_scale{}; + u8 mustache_y{}; + u8 glasses_type{}; + u8 glasses_color{}; + u8 glasses_scale{}; + u8 glasses_y{}; + u8 mole_type{}; + u8 mole_scale{}; + u8 mole_x{}; + u8 mole_y{}; + INSERT_PADDING_BYTES(1); + + std::u16string Name() const; +}; +static_assert(sizeof(MiiInfo) == 0x58, "MiiInfo has incorrect size."); +static_assert(std::has_unique_object_representations_v<MiiInfo>, + "All bits of MiiInfo must contribute to its value."); + +#pragma pack(push, 4) + +struct MiiInfoElement { + MiiInfoElement(const MiiInfo& info, Source source) : info{info}, source{source} {} + + MiiInfo info{}; + Source source{}; +}; +static_assert(sizeof(MiiInfoElement) == 0x5c, "MiiInfoElement has incorrect size."); + +struct MiiStoreBitFields { + union { + u32 word_0{}; + + BitField<0, 8, u32> hair_type; + BitField<8, 7, u32> height; + BitField<15, 1, u32> mole_type; + BitField<16, 7, u32> build; + BitField<23, 1, HairFlip> hair_flip; + BitField<24, 7, u32> hair_color; + BitField<31, 1, u32> type; + }; + + union { + u32 word_1{}; + + BitField<0, 7, u32> eye_color; + BitField<7, 1, Gender> gender; + BitField<8, 7, u32> eyebrow_color; + BitField<16, 7, u32> mouth_color; + BitField<24, 7, u32> beard_color; + }; + + union { + u32 word_2{}; + + BitField<0, 7, u32> glasses_color; + BitField<8, 6, u32> eye_type; + BitField<14, 2, u32> region_move; + BitField<16, 6, u32> mouth_type; + BitField<22, 2, FontRegion> font_region; + BitField<24, 5, u32> eye_y; + BitField<29, 3, u32> glasses_scale; + }; + + union { + u32 word_3{}; + + BitField<0, 5, u32> eyebrow_type; + BitField<5, 3, MustacheType> mustache_type; + BitField<8, 5, u32> nose_type; + BitField<13, 3, BeardType> beard_type; + BitField<16, 5, u32> nose_y; + BitField<21, 3, u32> mouth_aspect; + BitField<24, 5, u32> mouth_y; + BitField<29, 3, u32> eyebrow_aspect; + }; + + union { + u32 word_4{}; + + BitField<0, 5, u32> mustache_y; + BitField<5, 3, u32> eye_rotate; + BitField<8, 5, u32> glasses_y; + BitField<13, 3, u32> eye_aspect; + BitField<16, 5, u32> mole_x; + BitField<21, 3, u32> eye_scale; + BitField<24, 5, u32> mole_y; + }; + + union { + u32 word_5{}; + + BitField<0, 5, u32> glasses_type; + BitField<8, 4, u32> favorite_color; + BitField<12, 4, u32> faceline_type; + BitField<16, 4, u32> faceline_color; + BitField<20, 4, u32> faceline_wrinkle; + BitField<24, 4, u32> faceline_makeup; + BitField<28, 4, u32> eye_x; + }; + + union { + u32 word_6{}; + + BitField<0, 4, u32> eyebrow_scale; + BitField<4, 4, u32> eyebrow_rotate; + BitField<8, 4, u32> eyebrow_x; + BitField<12, 4, u32> eyebrow_y; + BitField<16, 4, u32> nose_scale; + BitField<20, 4, u32> mouth_scale; + BitField<24, 4, u32> mustache_scale; + BitField<28, 4, u32> mole_scale; + }; +}; +static_assert(sizeof(MiiStoreBitFields) == 0x1c, "MiiStoreBitFields has incorrect size."); +static_assert(std::is_trivially_copyable_v<MiiStoreBitFields>, + "MiiStoreBitFields is not trivially copyable."); + +struct MiiStoreData { + using Name = std::array<char16_t, 10>; + + MiiStoreData(); + MiiStoreData(const Name& name, const MiiStoreBitFields& bit_fields, + const Common::UUID& user_id); + + // This corresponds to the above structure MiiStoreBitFields. I did it like this because the + // BitField<> type makes this (and any thing that contains it) not trivially copyable, which is + // not suitable for our uses. + struct { + std::array<u8, 0x1C> data{}; + static_assert(sizeof(MiiStoreBitFields) == sizeof(data), "data field has incorrect size."); + + Name name{}; + Common::UUID uuid{Common::INVALID_UUID}; + } data; + + u16 data_crc{}; + u16 device_crc{}; +}; +static_assert(sizeof(MiiStoreData) == 0x44, "MiiStoreData has incorrect size."); + +struct MiiStoreDataElement { + MiiStoreData data{}; + Source source{}; +}; +static_assert(sizeof(MiiStoreDataElement) == 0x48, "MiiStoreDataElement has incorrect size."); + +struct MiiDatabase { + u32 magic{}; // 'NFDB' + std::array<MiiStoreData, 0x64> miis{}; + INSERT_PADDING_BYTES(1); + u8 count{}; + u16 crc{}; +}; +static_assert(sizeof(MiiDatabase) == 0x1A98, "MiiDatabase has incorrect size."); + +struct RandomMiiValues { + std::array<u8, 0xbc> values{}; +}; +static_assert(sizeof(RandomMiiValues) == 0xbc, "RandomMiiValues has incorrect size."); + +struct RandomMiiData4 { + Gender gender{}; + Age age{}; + Race race{}; + u32 values_count{}; + std::array<u8, 0xbc> values{}; +}; +static_assert(sizeof(RandomMiiData4) == 0xcc, "RandomMiiData4 has incorrect size."); + +struct RandomMiiData3 { + u32 arg_1; + u32 arg_2; + u32 values_count; + std::array<u8, 0xbc> values{}; +}; +static_assert(sizeof(RandomMiiData3) == 0xc8, "RandomMiiData3 has incorrect size."); + +struct RandomMiiData2 { + u32 arg_1; + u32 values_count; + std::array<u8, 0xbc> values{}; +}; +static_assert(sizeof(RandomMiiData2) == 0xc4, "RandomMiiData2 has incorrect size."); + +struct DefaultMii { + u32 face_type{}; + u32 face_color{}; + u32 face_wrinkle{}; + u32 face_makeup{}; + u32 hair_type{}; + u32 hair_color{}; + u32 hair_flip{}; + u32 eye_type{}; + u32 eye_color{}; + u32 eye_scale{}; + u32 eye_aspect{}; + u32 eye_rotate{}; + u32 eye_x{}; + u32 eye_y{}; + u32 eyebrow_type{}; + u32 eyebrow_color{}; + u32 eyebrow_scale{}; + u32 eyebrow_aspect{}; + u32 eyebrow_rotate{}; + u32 eyebrow_x{}; + u32 eyebrow_y{}; + u32 nose_type{}; + u32 nose_scale{}; + u32 nose_y{}; + u32 mouth_type{}; + u32 mouth_color{}; + u32 mouth_scale{}; + u32 mouth_aspect{}; + u32 mouth_y{}; + u32 mustache_type{}; + u32 beard_type{}; + u32 beard_color{}; + u32 mustache_scale{}; + u32 mustache_y{}; + u32 glasses_type{}; + u32 glasses_color{}; + u32 glasses_scale{}; + u32 glasses_y{}; + u32 mole_type{}; + u32 mole_scale{}; + u32 mole_x{}; + u32 mole_y{}; + u32 height{}; + u32 weight{}; + Gender gender{}; + u32 favorite_color{}; + u32 region{}; + FontRegion font_region{}; + u32 type{}; + INSERT_PADDING_WORDS(5); +}; +static_assert(sizeof(DefaultMii) == 0xd8, "MiiStoreData has incorrect size."); + +#pragma pack(pop) + +// The Mii manager is responsible for loading and storing the Miis to the database in NAND along +// with providing an easy interface for HLE emulation of the mii service. +class MiiManager { +public: + MiiManager(); + + bool CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter); + bool IsFullDatabase() const; + u32 GetCount(SourceFlag source_flag) const; + ResultVal<MiiInfo> UpdateLatest(const MiiInfo& info, SourceFlag source_flag); + MiiInfo BuildRandom(Age age, Gender gender, Race race); + MiiInfo BuildDefault(std::size_t index); + ResultVal<std::vector<MiiInfoElement>> GetDefault(SourceFlag source_flag); + ResultCode GetIndex(const MiiInfo& info, u32& index); + +private: + const Common::UUID user_id; + u64 update_counter{}; +}; + +}; // namespace Service::Mii diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp index a128edb43..b81bf6277 100644 --- a/src/core/hle/service/mii/mii.cpp +++ b/src/core/hle/service/mii/mii.cpp @@ -4,22 +4,17 @@ #include <memory> -#include <fmt/ostream.h> - #include "common/logging/log.h" -#include "common/string_util.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/hle_ipc.h" +#include "core/hle/service/mii/manager.h" #include "core/hle/service/mii/mii.h" -#include "core/hle/service/mii/mii_manager.h" #include "core/hle/service/service.h" #include "core/hle/service/sm/sm.h" namespace Service::Mii { constexpr ResultCode ERROR_INVALID_ARGUMENT{ErrorModule::Mii, 1}; -constexpr ResultCode ERROR_CANNOT_FIND_ENTRY{ErrorModule::Mii, 4}; -constexpr ResultCode ERROR_NOT_IN_TEST_MODE{ErrorModule::Mii, 99}; class IDatabaseService final : public ServiceFramework<IDatabaseService> { public: @@ -31,19 +26,19 @@ public: {2, &IDatabaseService::GetCount, "GetCount"}, {3, &IDatabaseService::Get, "Get"}, {4, &IDatabaseService::Get1, "Get1"}, - {5, nullptr, "UpdateLatest"}, + {5, &IDatabaseService::UpdateLatest, "UpdateLatest"}, {6, &IDatabaseService::BuildRandom, "BuildRandom"}, {7, &IDatabaseService::BuildDefault, "BuildDefault"}, - {8, &IDatabaseService::Get2, "Get2"}, - {9, &IDatabaseService::Get3, "Get3"}, + {8, nullptr, "Get2"}, + {9, nullptr, "Get3"}, {10, nullptr, "UpdateLatest1"}, - {11, &IDatabaseService::FindIndex, "FindIndex"}, - {12, &IDatabaseService::Move, "Move"}, - {13, &IDatabaseService::AddOrReplace, "AddOrReplace"}, - {14, &IDatabaseService::Delete, "Delete"}, - {15, &IDatabaseService::DestroyFile, "DestroyFile"}, - {16, &IDatabaseService::DeleteFile, "DeleteFile"}, - {17, &IDatabaseService::Format, "Format"}, + {11, nullptr, "FindIndex"}, + {12, nullptr, "Move"}, + {13, nullptr, "AddOrReplace"}, + {14, nullptr, "Delete"}, + {15, nullptr, "DestroyFile"}, + {16, nullptr, "DeleteFile"}, + {17, nullptr, "Format"}, {18, nullptr, "Import"}, {19, nullptr, "Export"}, {20, nullptr, "IsBrokenDatabaseWithClearFlag"}, @@ -59,31 +54,26 @@ public: } private: - template <typename OutType> - std::vector<u8> SerializeArray(OutType (MiiManager::*getter)(u32) const, u32 offset, - u32 requested_size, u32& read_size) { - read_size = std::min(requested_size, db.Size() - offset); - - std::vector<u8> out(read_size * sizeof(OutType)); - - for (u32 i = 0; i < read_size; ++i) { - const auto obj = (db.*getter)(offset + i); - std::memcpy(out.data() + i * sizeof(OutType), &obj, sizeof(OutType)); + template <typename T> + std::vector<u8> SerializeArray(const std::vector<T>& values) { + std::vector<u8> out(values.size() * sizeof(T)); + std::size_t offset{}; + for (const auto& value : values) { + std::memcpy(out.data() + offset, &value, sizeof(T)); + offset += sizeof(T); } - return out; } void IsUpdated(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto source{rp.PopRaw<Source>()}; + const auto source_flag{rp.PopRaw<SourceFlag>()}; - LOG_DEBUG(Service_Mii, "called with source={}", source); + LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push(db.CheckUpdatedFlag()); - db.ResetUpdatedFlag(); + rb.Push(manager.CheckAndResetUpdateCounter(source_flag, current_update_counter)); } void IsFullDatabase(Kernel::HLERequestContext& ctx) { @@ -91,264 +81,149 @@ private: IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push(db.Full()); + rb.Push(manager.IsFullDatabase()); } void GetCount(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto source{rp.PopRaw<Source>()}; + const auto source_flag{rp.PopRaw<SourceFlag>()}; - LOG_DEBUG(Service_Mii, "called with source={}", source); + LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u32>(db.Size()); + rb.Push<u32>(manager.GetCount(source_flag)); } - // Gets Miis from database at offset and index in format MiiInfoElement void Get(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto size{rp.PopRaw<u32>()}; - const auto source{rp.PopRaw<Source>()}; - - LOG_DEBUG(Service_Mii, "called with size={:08X}, offset={:08X}, source={}", size, - offsets[0], source); - - u32 read_size{}; - ctx.WriteBuffer(SerializeArray(&MiiManager::GetInfoElement, offsets[0], size, read_size)); - offsets[0] += read_size; - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(RESULT_SUCCESS); - rb.Push<u32>(read_size); - } + const auto source_flag{rp.PopRaw<SourceFlag>()}; - // Gets Miis from database at offset and index in format MiiInfo - void Get1(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto size{rp.PopRaw<u32>()}; - const auto source{rp.PopRaw<Source>()}; + LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); - LOG_DEBUG(Service_Mii, "called with size={:08X}, offset={:08X}, source={}", size, - offsets[1], source); + const auto result{manager.GetDefault(source_flag)}; + if (result.Failed()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result.Code()); + return; + } - u32 read_size{}; - ctx.WriteBuffer(SerializeArray(&MiiManager::GetInfo, offsets[1], size, read_size)); - offsets[1] += read_size; + if (result->size() > 0) { + ctx.WriteBuffer(SerializeArray(*result)); + } IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u32>(read_size); + rb.Push<u32>(static_cast<u32>(result->size())); } - void BuildRandom(Kernel::HLERequestContext& ctx) { + void Get1(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto [unknown1, unknown2, unknown3] = rp.PopRaw<RandomParameters>(); + const auto source_flag{rp.PopRaw<SourceFlag>()}; - if (unknown1 > 3) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_INVALID_ARGUMENT); - LOG_ERROR(Service_Mii, "Invalid unknown1 value: {}", unknown1); - return; - } + LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); - if (unknown2 > 2) { + const auto result{manager.GetDefault(source_flag)}; + if (result.Failed()) { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_INVALID_ARGUMENT); - LOG_ERROR(Service_Mii, "Invalid unknown2 value: {}", unknown2); + rb.Push(result.Code()); return; } - if (unknown3 > 3) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_INVALID_ARGUMENT); - LOG_ERROR(Service_Mii, "Invalid unknown3 value: {}", unknown3); - return; + std::vector<MiiInfo> values; + for (const auto& element : *result) { + values.emplace_back(element.info); } - LOG_DEBUG(Service_Mii, "called with param_1={:08X}, param_2={:08X}, param_3={:08X}", - unknown1, unknown2, unknown3); + ctx.WriteBuffer(SerializeArray(values)); - const auto info = db.CreateRandom({unknown1, unknown2, unknown3}); - IPC::ResponseBuilder rb{ctx, 2 + sizeof(MiiInfo) / sizeof(u32)}; + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.PushRaw<MiiInfo>(info); + rb.Push<u32>(static_cast<u32>(result->size())); } - void BuildDefault(Kernel::HLERequestContext& ctx) { + void UpdateLatest(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto index{rp.PopRaw<u32>()}; + const auto info{rp.PopRaw<MiiInfo>()}; + const auto source_flag{rp.PopRaw<SourceFlag>()}; - if (index > 5) { - LOG_ERROR(Service_Mii, "invalid argument, index cannot be greater than 5 but is {:08X}", - index); + LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); + + const auto result{manager.UpdateLatest(info, source_flag)}; + if (result.Failed()) { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_INVALID_ARGUMENT); + rb.Push(result.Code()); return; } - LOG_DEBUG(Service_Mii, "called with index={:08X}", index); - - const auto info = db.CreateDefault(index); IPC::ResponseBuilder rb{ctx, 2 + sizeof(MiiInfo) / sizeof(u32)}; rb.Push(RESULT_SUCCESS); - rb.PushRaw<MiiInfo>(info); + rb.PushRaw<MiiInfo>(*result); } - // Gets Miis from database at offset and index in format MiiStoreDataElement - void Get2(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto size{rp.PopRaw<u32>()}; - const auto source{rp.PopRaw<Source>()}; - - LOG_DEBUG(Service_Mii, "called with size={:08X}, offset={:08X}, source={}", size, - offsets[2], source); - - u32 read_size{}; - ctx.WriteBuffer( - SerializeArray(&MiiManager::GetStoreDataElement, offsets[2], size, read_size)); - offsets[2] += read_size; - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(RESULT_SUCCESS); - rb.Push<u32>(read_size); - } - - // Gets Miis from database at offset and index in format MiiStoreData - void Get3(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto size{rp.PopRaw<u32>()}; - const auto source{rp.PopRaw<Source>()}; - - LOG_DEBUG(Service_Mii, "called with size={:08X}, offset={:08X}, source={}", size, - offsets[3], source); - - u32 read_size{}; - ctx.WriteBuffer(SerializeArray(&MiiManager::GetStoreData, offsets[3], size, read_size)); - offsets[3] += read_size; - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(RESULT_SUCCESS); - rb.Push<u32>(read_size); - } - - void FindIndex(Kernel::HLERequestContext& ctx) { + void BuildRandom(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto uuid{rp.PopRaw<Common::UUID>()}; - const auto unknown{rp.PopRaw<bool>()}; - LOG_DEBUG(Service_Mii, "called with uuid={}, unknown={}", uuid.FormatSwitch(), unknown); + const auto age{rp.PopRaw<Age>()}; + const auto gender{rp.PopRaw<Gender>()}; + const auto race{rp.PopRaw<Race>()}; - IPC::ResponseBuilder rb{ctx, 3}; + LOG_DEBUG(Service_Mii, "called with age={}, gender={}, race={}", age, gender, race); - const auto index = db.IndexOf(uuid); - if (index > MAX_MIIS) { - // TODO(DarkLordZach): Find a better error code - rb.Push(RESULT_UNKNOWN); - rb.Push(index); - } else { - rb.Push(RESULT_SUCCESS); - rb.Push(index); + if (age > Age::All) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_ARGUMENT); + LOG_ERROR(Service_Mii, "invalid age={}", age); + return; } - } - void Move(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto uuid{rp.PopRaw<Common::UUID>()}; - const auto index{rp.PopRaw<s32>()}; - - if (index < 0) { - LOG_ERROR(Service_Mii, "Index cannot be negative but is {:08X}!", index); + if (gender > Gender::All) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERROR_INVALID_ARGUMENT); + LOG_ERROR(Service_Mii, "invalid gender={}", gender); return; } - LOG_DEBUG(Service_Mii, "called with uuid={}, index={:08X}", uuid.FormatSwitch(), index); - - const auto success = db.Move(uuid, index); - - IPC::ResponseBuilder rb{ctx, 2}; - // TODO(DarkLordZach): Find a better error code - rb.Push(success ? RESULT_SUCCESS : RESULT_UNKNOWN); - } - - void AddOrReplace(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto data{rp.PopRaw<MiiStoreData>()}; - - LOG_DEBUG(Service_Mii, "called with Mii data uuid={}, name={}", data.uuid.FormatSwitch(), - Common::UTF16ToUTF8(data.Name())); - - const auto success = db.AddOrReplace(data); - - IPC::ResponseBuilder rb{ctx, 2}; - // TODO(DarkLordZach): Find a better error code - rb.Push(success ? RESULT_SUCCESS : RESULT_UNKNOWN); - } - - void Delete(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto uuid{rp.PopRaw<Common::UUID>()}; - - LOG_DEBUG(Service_Mii, "called with uuid={}", uuid.FormatSwitch()); - - const auto success = db.Remove(uuid); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(success ? RESULT_SUCCESS : ERROR_CANNOT_FIND_ENTRY); - } - - void DestroyFile(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_Mii, "called"); - - if (!db.IsTestModeEnabled()) { - LOG_ERROR(Service_Mii, "Database is not in test mode -- cannot destory database file."); + if (race > Race::All) { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_NOT_IN_TEST_MODE); + rb.Push(ERROR_INVALID_ARGUMENT); + LOG_ERROR(Service_Mii, "invalid race={}", race); return; } - IPC::ResponseBuilder rb{ctx, 3}; + IPC::ResponseBuilder rb{ctx, 2 + sizeof(MiiInfo) / sizeof(u32)}; rb.Push(RESULT_SUCCESS); - rb.Push(db.DestroyFile()); + rb.PushRaw<MiiInfo>(manager.BuildRandom(age, gender, race)); } - void DeleteFile(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_Mii, "called"); + void BuildDefault(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto index{rp.Pop<u32>()}; + + LOG_DEBUG(Service_Mii, "called with index={}", index); - if (!db.IsTestModeEnabled()) { - LOG_ERROR(Service_Mii, "Database is not in test mode -- cannot delete database file."); + if (index > 5) { + LOG_ERROR(Service_Mii, "invalid argument, index cannot be greater than 5 but is {:08X}", + index); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_NOT_IN_TEST_MODE); + rb.Push(ERROR_INVALID_ARGUMENT); return; } - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(RESULT_SUCCESS); - rb.Push(db.DeleteFile()); - } - - void Format(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_Mii, "called"); - - db.Clear(); - - IPC::ResponseBuilder rb{ctx, 2}; + IPC::ResponseBuilder rb{ctx, 2 + sizeof(MiiInfo) / sizeof(u32)}; rb.Push(RESULT_SUCCESS); + rb.PushRaw<MiiInfo>(manager.BuildDefault(index)); } void GetIndex(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto info{rp.PopRaw<MiiInfo>()}; - LOG_DEBUG(Service_Mii, "called with Mii info uuid={}, name={}", info.uuid.FormatSwitch(), - Common::UTF16ToUTF8(info.Name())); - - const auto index = db.IndexOf(info); + LOG_DEBUG(Service_Mii, "called"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); + u32 index{}; + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(manager.GetIndex(info, index)); rb.Push(index); } @@ -364,12 +239,14 @@ private: rb.Push(RESULT_SUCCESS); } - MiiManager db; + constexpr bool IsInterfaceVersionSupported(u32 interface_version) const { + return current_interface_version >= interface_version; + } - u32 current_interface_version = 0; + MiiManager manager; - // Last read offsets of Get functions - std::array<u32, 4> offsets{}; + u32 current_interface_version{}; + u64 current_update_counter{}; }; class MiiDBModule final : public ServiceFramework<MiiDBModule> { diff --git a/src/core/hle/service/mii/mii_manager.cpp b/src/core/hle/service/mii/mii_manager.cpp deleted file mode 100644 index 8d0353075..000000000 --- a/src/core/hle/service/mii/mii_manager.cpp +++ /dev/null @@ -1,420 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <algorithm> -#include <cstring> -#include "common/assert.h" -#include "common/file_util.h" -#include "common/logging/log.h" -#include "common/string_util.h" -#include "core/hle/service/mii/mii_manager.h" - -namespace Service::Mii { - -namespace { - -constexpr char MII_SAVE_DATABASE_PATH[] = "/system/save/8000000000000030/MiiDatabase.dat"; -constexpr std::array<char16_t, 11> DEFAULT_MII_NAME = {u'y', u'u', u'z', u'u', u'\0'}; - -// This value was retrieved from HW test -constexpr MiiStoreData DEFAULT_MII = { - { - 0x21, 0x40, 0x40, 0x01, 0x08, 0x01, 0x13, 0x08, 0x08, 0x02, 0x17, 0x8C, 0x06, 0x01, - 0x69, 0x6D, 0x8A, 0x6A, 0x82, 0x14, 0x00, 0x00, 0x00, 0x20, 0x64, 0x72, 0x44, 0x44, - }, - {'y', 'u', 'z', 'u', '\0'}, - Common::UUID{1, 0}, - 0, - 0, -}; - -// Default values taken from multiple real databases -const MiiDatabase DEFAULT_MII_DATABASE{Common::MakeMagic('N', 'F', 'D', 'B'), {}, {1}, 0, 0}; - -constexpr std::array<const char*, 4> SOURCE_NAMES{ - "Database", - "Default", - "Account", - "Friend", -}; - -template <typename T, std::size_t SourceArraySize, std::size_t DestArraySize> -std::array<T, DestArraySize> ResizeArray(const std::array<T, SourceArraySize>& in) { - std::array<T, DestArraySize> out{}; - std::memcpy(out.data(), in.data(), sizeof(T) * std::min(SourceArraySize, DestArraySize)); - return out; -} - -MiiInfo ConvertStoreDataToInfo(const MiiStoreData& data) { - MiiStoreBitFields bf{}; - std::memcpy(&bf, data.data.data(), sizeof(MiiStoreBitFields)); - return { - data.uuid, - ResizeArray<char16_t, 10, 11>(data.name), - static_cast<u8>(bf.font_region.Value()), - static_cast<u8>(bf.favorite_color.Value()), - static_cast<u8>(bf.gender.Value()), - static_cast<u8>(bf.height.Value()), - static_cast<u8>(bf.weight.Value()), - static_cast<u8>(bf.mii_type.Value()), - static_cast<u8>(bf.mii_region.Value()), - static_cast<u8>(bf.face_type.Value()), - static_cast<u8>(bf.face_color.Value()), - static_cast<u8>(bf.face_wrinkle.Value()), - static_cast<u8>(bf.face_makeup.Value()), - static_cast<u8>(bf.hair_type.Value()), - static_cast<u8>(bf.hair_color.Value()), - static_cast<bool>(bf.hair_flip.Value()), - static_cast<u8>(bf.eye_type.Value()), - static_cast<u8>(bf.eye_color.Value()), - static_cast<u8>(bf.eye_scale.Value()), - static_cast<u8>(bf.eye_aspect.Value()), - static_cast<u8>(bf.eye_rotate.Value()), - static_cast<u8>(bf.eye_x.Value()), - static_cast<u8>(bf.eye_y.Value()), - static_cast<u8>(bf.eyebrow_type.Value()), - static_cast<u8>(bf.eyebrow_color.Value()), - static_cast<u8>(bf.eyebrow_scale.Value()), - static_cast<u8>(bf.eyebrow_aspect.Value()), - static_cast<u8>(bf.eyebrow_rotate.Value()), - static_cast<u8>(bf.eyebrow_x.Value()), - static_cast<u8>(bf.eyebrow_y.Value()), - static_cast<u8>(bf.nose_type.Value()), - static_cast<u8>(bf.nose_scale.Value()), - static_cast<u8>(bf.nose_y.Value()), - static_cast<u8>(bf.mouth_type.Value()), - static_cast<u8>(bf.mouth_color.Value()), - static_cast<u8>(bf.mouth_scale.Value()), - static_cast<u8>(bf.mouth_aspect.Value()), - static_cast<u8>(bf.mouth_y.Value()), - static_cast<u8>(bf.facial_hair_color.Value()), - static_cast<u8>(bf.beard_type.Value()), - static_cast<u8>(bf.mustache_type.Value()), - static_cast<u8>(bf.mustache_scale.Value()), - static_cast<u8>(bf.mustache_y.Value()), - static_cast<u8>(bf.glasses_type.Value()), - static_cast<u8>(bf.glasses_color.Value()), - static_cast<u8>(bf.glasses_scale.Value()), - static_cast<u8>(bf.glasses_y.Value()), - static_cast<u8>(bf.mole_type.Value()), - static_cast<u8>(bf.mole_scale.Value()), - static_cast<u8>(bf.mole_x.Value()), - static_cast<u8>(bf.mole_y.Value()), - 0x00, - }; -} -MiiStoreData ConvertInfoToStoreData(const MiiInfo& info) { - MiiStoreData out{}; - out.name = ResizeArray<char16_t, 11, 10>(info.name); - out.uuid = info.uuid; - - MiiStoreBitFields bf{}; - - bf.hair_type.Assign(info.hair_type); - bf.mole_type.Assign(info.mole_type); - bf.height.Assign(info.height); - bf.hair_flip.Assign(info.hair_flip); - bf.weight.Assign(info.weight); - bf.hair_color.Assign(info.hair_color); - - bf.gender.Assign(info.gender); - bf.eye_color.Assign(info.eye_color); - bf.eyebrow_color.Assign(info.eyebrow_color); - bf.mouth_color.Assign(info.mouth_color); - bf.facial_hair_color.Assign(info.facial_hair_color); - - bf.mii_type.Assign(info.mii_type); - bf.glasses_color.Assign(info.glasses_color); - bf.font_region.Assign(info.font_region); - bf.eye_type.Assign(info.eye_type); - bf.mii_region.Assign(info.mii_region); - bf.mouth_type.Assign(info.mouth_type); - bf.glasses_scale.Assign(info.glasses_scale); - bf.eye_y.Assign(info.eye_y); - - bf.mustache_type.Assign(info.mustache_type); - bf.eyebrow_type.Assign(info.eyebrow_type); - bf.beard_type.Assign(info.beard_type); - bf.nose_type.Assign(info.nose_type); - bf.mouth_aspect.Assign(info.mouth_aspect_ratio); - bf.nose_y.Assign(info.nose_y); - bf.eyebrow_aspect.Assign(info.eyebrow_aspect_ratio); - bf.mouth_y.Assign(info.mouth_y); - - bf.eye_rotate.Assign(info.eye_rotate); - bf.mustache_y.Assign(info.mustache_y); - bf.eye_aspect.Assign(info.eye_aspect_ratio); - bf.glasses_y.Assign(info.glasses_y); - bf.eye_scale.Assign(info.eye_scale); - bf.mole_x.Assign(info.mole_x); - bf.mole_y.Assign(info.mole_y); - - bf.glasses_type.Assign(info.glasses_type); - bf.face_type.Assign(info.face_type); - bf.favorite_color.Assign(info.favorite_color); - bf.face_wrinkle.Assign(info.face_wrinkle); - bf.face_color.Assign(info.face_color); - bf.eye_x.Assign(info.eye_x); - bf.face_makeup.Assign(info.face_makeup); - - bf.eyebrow_rotate.Assign(info.eyebrow_rotate); - bf.eyebrow_scale.Assign(info.eyebrow_scale); - bf.eyebrow_y.Assign(info.eyebrow_y); - bf.eyebrow_x.Assign(info.eyebrow_x); - bf.mouth_scale.Assign(info.mouth_scale); - bf.nose_scale.Assign(info.nose_scale); - bf.mole_scale.Assign(info.mole_scale); - bf.mustache_scale.Assign(info.mustache_scale); - - std::memcpy(out.data.data(), &bf, sizeof(MiiStoreBitFields)); - - return out; -} - -} // namespace - -std::ostream& operator<<(std::ostream& os, Source source) { - if (static_cast<std::size_t>(source) >= SOURCE_NAMES.size()) { - return os << "[UNKNOWN SOURCE]"; - } - - os << SOURCE_NAMES.at(static_cast<std::size_t>(source)); - return os; -} - -std::u16string MiiInfo::Name() const { - return Common::UTF16StringFromFixedZeroTerminatedBuffer(name.data(), name.size()); -} - -bool operator==(const MiiInfo& lhs, const MiiInfo& rhs) { - return std::memcmp(&lhs, &rhs, sizeof(MiiInfo)) == 0; -} - -bool operator!=(const MiiInfo& lhs, const MiiInfo& rhs) { - return !operator==(lhs, rhs); -} - -std::u16string MiiStoreData::Name() const { - return Common::UTF16StringFromFixedZeroTerminatedBuffer(name.data(), name.size()); -} - -MiiManager::MiiManager() = default; - -MiiManager::~MiiManager() = default; - -MiiInfo MiiManager::CreateRandom(RandomParameters params) { - LOG_WARNING(Service_Mii, - "(STUBBED) called with params={:08X}{:08X}{:08X}, returning default Mii", - params.unknown_1, params.unknown_2, params.unknown_3); - - return ConvertStoreDataToInfo(CreateMiiWithUniqueUUID()); -} - -MiiInfo MiiManager::CreateDefault(u32 index) { - const auto new_mii = CreateMiiWithUniqueUUID(); - - database.miis.at(index) = new_mii; - - EnsureDatabasePartition(); - return ConvertStoreDataToInfo(new_mii); -} - -bool MiiManager::CheckUpdatedFlag() const { - return updated_flag; -} - -void MiiManager::ResetUpdatedFlag() { - updated_flag = false; -} - -bool MiiManager::IsTestModeEnabled() const { - return is_test_mode_enabled; -} - -bool MiiManager::Empty() const { - return Size() == 0; -} - -bool MiiManager::Full() const { - return Size() == MAX_MIIS; -} - -void MiiManager::Clear() { - updated_flag = true; - std::fill(database.miis.begin(), database.miis.end(), MiiStoreData{}); -} - -u32 MiiManager::Size() const { - return static_cast<u32>(std::count_if(database.miis.begin(), database.miis.end(), - [](const MiiStoreData& elem) { return elem.uuid; })); -} - -MiiInfo MiiManager::GetInfo(u32 index) const { - return ConvertStoreDataToInfo(GetStoreData(index)); -} - -MiiInfoElement MiiManager::GetInfoElement(u32 index) const { - return {GetInfo(index), Source::Database}; -} - -MiiStoreData MiiManager::GetStoreData(u32 index) const { - return database.miis.at(index); -} - -MiiStoreDataElement MiiManager::GetStoreDataElement(u32 index) const { - return {GetStoreData(index), Source::Database}; -} - -bool MiiManager::Remove(Common::UUID uuid) { - const auto iter = std::find_if(database.miis.begin(), database.miis.end(), - [uuid](const MiiStoreData& elem) { return elem.uuid == uuid; }); - - if (iter == database.miis.end()) - return false; - - updated_flag = true; - *iter = MiiStoreData{}; - EnsureDatabasePartition(); - return true; -} - -u32 MiiManager::IndexOf(Common::UUID uuid) const { - const auto iter = std::find_if(database.miis.begin(), database.miis.end(), - [uuid](const MiiStoreData& elem) { return elem.uuid == uuid; }); - - if (iter == database.miis.end()) - return INVALID_INDEX; - - return static_cast<u32>(std::distance(database.miis.begin(), iter)); -} - -u32 MiiManager::IndexOf(const MiiInfo& info) const { - const auto iter = - std::find_if(database.miis.begin(), database.miis.end(), [&info](const MiiStoreData& elem) { - return ConvertStoreDataToInfo(elem) == info; - }); - - if (iter == database.miis.end()) - return INVALID_INDEX; - - return static_cast<u32>(std::distance(database.miis.begin(), iter)); -} - -bool MiiManager::Move(Common::UUID uuid, u32 new_index) { - const auto index = IndexOf(uuid); - - if (index == INVALID_INDEX || new_index >= MAX_MIIS) - return false; - - updated_flag = true; - const auto moving = database.miis[index]; - const auto replacing = database.miis[new_index]; - if (replacing.uuid) { - database.miis[index] = replacing; - database.miis[new_index] = moving; - } else { - database.miis[index] = MiiStoreData{}; - database.miis[new_index] = moving; - } - - EnsureDatabasePartition(); - return true; -} - -bool MiiManager::AddOrReplace(const MiiStoreData& data) { - const auto index = IndexOf(data.uuid); - - updated_flag = true; - if (index == INVALID_INDEX) { - const auto size = Size(); - if (size == MAX_MIIS) - return false; - database.miis[size] = data; - } else { - database.miis[index] = data; - } - - return true; -} - -bool MiiManager::DestroyFile() { - database = DEFAULT_MII_DATABASE; - updated_flag = false; - return DeleteFile(); -} - -bool MiiManager::DeleteFile() { - const auto path = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + MII_SAVE_DATABASE_PATH; - return FileUtil::Exists(path) && FileUtil::Delete(path); -} - -void MiiManager::WriteToFile() { - const auto raw_path = - FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + "/system/save/8000000000000030"; - if (FileUtil::Exists(raw_path) && !FileUtil::IsDirectory(raw_path)) - FileUtil::Delete(raw_path); - - const auto path = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + MII_SAVE_DATABASE_PATH; - - if (!FileUtil::CreateFullPath(path)) { - LOG_WARNING(Service_Mii, - "Failed to create full path of MiiDatabase.dat. Create the directory " - "nand/system/save/8000000000000030 to mitigate this " - "issue."); - return; - } - - FileUtil::IOFile save(path, "wb"); - - if (!save.IsOpen()) { - LOG_WARNING(Service_Mii, "Failed to write save data to file... No changes to user data " - "made in current session will be saved."); - return; - } - - save.Resize(sizeof(MiiDatabase)); - if (save.WriteBytes(&database, sizeof(MiiDatabase)) != sizeof(MiiDatabase)) { - LOG_WARNING(Service_Mii, "Failed to write all data to save file... Data may be malformed " - "and/or regenerated on next run."); - save.Resize(0); - } -} - -void MiiManager::ReadFromFile() { - FileUtil::IOFile save( - FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + MII_SAVE_DATABASE_PATH, "rb"); - - if (!save.IsOpen()) { - LOG_WARNING(Service_ACC, "Failed to load profile data from save data... Generating new " - "blank Mii database with no Miis."); - std::memcpy(&database, &DEFAULT_MII_DATABASE, sizeof(MiiDatabase)); - return; - } - - if (save.ReadBytes(&database, sizeof(MiiDatabase)) != sizeof(MiiDatabase)) { - LOG_WARNING(Service_ACC, "MiiDatabase.dat is smaller than expected... Generating new blank " - "Mii database with no Miis."); - std::memcpy(&database, &DEFAULT_MII_DATABASE, sizeof(MiiDatabase)); - return; - } - - EnsureDatabasePartition(); -} - -MiiStoreData MiiManager::CreateMiiWithUniqueUUID() const { - auto new_mii = DEFAULT_MII; - - do { - new_mii.uuid = Common::UUID::Generate(); - } while (IndexOf(new_mii.uuid) != INVALID_INDEX); - - return new_mii; -} - -void MiiManager::EnsureDatabasePartition() { - std::stable_partition(database.miis.begin(), database.miis.end(), - [](const MiiStoreData& elem) { return elem.uuid; }); -} - -} // namespace Service::Mii diff --git a/src/core/hle/service/mii/mii_manager.h b/src/core/hle/service/mii/mii_manager.h deleted file mode 100644 index fc742816a..000000000 --- a/src/core/hle/service/mii/mii_manager.h +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "common/bit_field.h" -#include "common/common_funcs.h" -#include "common/uuid.h" - -namespace Service::Mii { - -constexpr std::size_t MAX_MIIS{100}; -constexpr u32 INVALID_INDEX{0xFFFFFFFF}; - -struct RandomParameters { - u32 unknown_1{}; - u32 unknown_2{}; - u32 unknown_3{}; -}; -static_assert(sizeof(RandomParameters) == 0xC, "RandomParameters has incorrect size."); - -enum class Source : u32 { - Database = 0, - Default = 1, - Account = 2, - Friend = 3, -}; - -std::ostream& operator<<(std::ostream& os, Source source); - -struct MiiInfo { - Common::UUID uuid{Common::INVALID_UUID}; - std::array<char16_t, 11> name{}; - u8 font_region{}; - u8 favorite_color{}; - u8 gender{}; - u8 height{}; - u8 weight{}; - u8 mii_type{}; - u8 mii_region{}; - u8 face_type{}; - u8 face_color{}; - u8 face_wrinkle{}; - u8 face_makeup{}; - u8 hair_type{}; - u8 hair_color{}; - bool hair_flip{}; - u8 eye_type{}; - u8 eye_color{}; - u8 eye_scale{}; - u8 eye_aspect_ratio{}; - u8 eye_rotate{}; - u8 eye_x{}; - u8 eye_y{}; - u8 eyebrow_type{}; - u8 eyebrow_color{}; - u8 eyebrow_scale{}; - u8 eyebrow_aspect_ratio{}; - u8 eyebrow_rotate{}; - u8 eyebrow_x{}; - u8 eyebrow_y{}; - u8 nose_type{}; - u8 nose_scale{}; - u8 nose_y{}; - u8 mouth_type{}; - u8 mouth_color{}; - u8 mouth_scale{}; - u8 mouth_aspect_ratio{}; - u8 mouth_y{}; - u8 facial_hair_color{}; - u8 beard_type{}; - u8 mustache_type{}; - u8 mustache_scale{}; - u8 mustache_y{}; - u8 glasses_type{}; - u8 glasses_color{}; - u8 glasses_scale{}; - u8 glasses_y{}; - u8 mole_type{}; - u8 mole_scale{}; - u8 mole_x{}; - u8 mole_y{}; - INSERT_PADDING_BYTES(1); - - std::u16string Name() const; -}; -static_assert(sizeof(MiiInfo) == 0x58, "MiiInfo has incorrect size."); -static_assert(std::has_unique_object_representations_v<MiiInfo>, - "All bits of MiiInfo must contribute to its value."); - -bool operator==(const MiiInfo& lhs, const MiiInfo& rhs); -bool operator!=(const MiiInfo& lhs, const MiiInfo& rhs); - -#pragma pack(push, 4) -struct MiiInfoElement { - MiiInfo info{}; - Source source{}; -}; -static_assert(sizeof(MiiInfoElement) == 0x5C, "MiiInfoElement has incorrect size."); - -struct MiiStoreBitFields { - union { - u32 word_0{}; - - BitField<24, 8, u32> hair_type; - BitField<23, 1, u32> mole_type; - BitField<16, 7, u32> height; - BitField<15, 1, u32> hair_flip; - BitField<8, 7, u32> weight; - BitField<0, 7, u32> hair_color; - }; - - union { - u32 word_1{}; - - BitField<31, 1, u32> gender; - BitField<24, 7, u32> eye_color; - BitField<16, 7, u32> eyebrow_color; - BitField<8, 7, u32> mouth_color; - BitField<0, 7, u32> facial_hair_color; - }; - - union { - u32 word_2{}; - - BitField<31, 1, u32> mii_type; - BitField<24, 7, u32> glasses_color; - BitField<22, 2, u32> font_region; - BitField<16, 6, u32> eye_type; - BitField<14, 2, u32> mii_region; - BitField<8, 6, u32> mouth_type; - BitField<5, 3, u32> glasses_scale; - BitField<0, 5, u32> eye_y; - }; - - union { - u32 word_3{}; - - BitField<29, 3, u32> mustache_type; - BitField<24, 5, u32> eyebrow_type; - BitField<21, 3, u32> beard_type; - BitField<16, 5, u32> nose_type; - BitField<13, 3, u32> mouth_aspect; - BitField<8, 5, u32> nose_y; - BitField<5, 3, u32> eyebrow_aspect; - BitField<0, 5, u32> mouth_y; - }; - - union { - u32 word_4{}; - - BitField<29, 3, u32> eye_rotate; - BitField<24, 5, u32> mustache_y; - BitField<21, 3, u32> eye_aspect; - BitField<16, 5, u32> glasses_y; - BitField<13, 3, u32> eye_scale; - BitField<8, 5, u32> mole_x; - BitField<0, 5, u32> mole_y; - }; - - union { - u32 word_5{}; - - BitField<24, 5, u32> glasses_type; - BitField<20, 4, u32> face_type; - BitField<16, 4, u32> favorite_color; - BitField<12, 4, u32> face_wrinkle; - BitField<8, 4, u32> face_color; - BitField<4, 4, u32> eye_x; - BitField<0, 4, u32> face_makeup; - }; - - union { - u32 word_6{}; - - BitField<28, 4, u32> eyebrow_rotate; - BitField<24, 4, u32> eyebrow_scale; - BitField<20, 4, u32> eyebrow_y; - BitField<16, 4, u32> eyebrow_x; - BitField<12, 4, u32> mouth_scale; - BitField<8, 4, u32> nose_scale; - BitField<4, 4, u32> mole_scale; - BitField<0, 4, u32> mustache_scale; - }; -}; -static_assert(sizeof(MiiStoreBitFields) == 0x1C, "MiiStoreBitFields has incorrect size."); -static_assert(std::is_trivially_copyable_v<MiiStoreBitFields>, - "MiiStoreBitFields is not trivially copyable."); - -struct MiiStoreData { - // This corresponds to the above structure MiiStoreBitFields. I did it like this because the - // BitField<> type makes this (and any thing that contains it) not trivially copyable, which is - // not suitable for our uses. - std::array<u8, 0x1C> data{}; - static_assert(sizeof(MiiStoreBitFields) == sizeof(data), "data field has incorrect size."); - - std::array<char16_t, 10> name{}; - Common::UUID uuid{Common::INVALID_UUID}; - u16 crc_1{}; - u16 crc_2{}; - - std::u16string Name() const; -}; -static_assert(sizeof(MiiStoreData) == 0x44, "MiiStoreData has incorrect size."); - -struct MiiStoreDataElement { - MiiStoreData data{}; - Source source{}; -}; -static_assert(sizeof(MiiStoreDataElement) == 0x48, "MiiStoreDataElement has incorrect size."); - -struct MiiDatabase { - u32 magic{}; // 'NFDB' - std::array<MiiStoreData, MAX_MIIS> miis{}; - INSERT_PADDING_BYTES(1); - u8 count{}; - u16 crc{}; -}; -static_assert(sizeof(MiiDatabase) == 0x1A98, "MiiDatabase has incorrect size."); -#pragma pack(pop) - -// The Mii manager is responsible for loading and storing the Miis to the database in NAND along -// with providing an easy interface for HLE emulation of the mii service. -class MiiManager { -public: - MiiManager(); - ~MiiManager(); - - MiiInfo CreateRandom(RandomParameters params); - MiiInfo CreateDefault(u32 index); - - bool CheckUpdatedFlag() const; - void ResetUpdatedFlag(); - - bool IsTestModeEnabled() const; - - bool Empty() const; - bool Full() const; - - void Clear(); - - u32 Size() const; - - MiiInfo GetInfo(u32 index) const; - MiiInfoElement GetInfoElement(u32 index) const; - MiiStoreData GetStoreData(u32 index) const; - MiiStoreDataElement GetStoreDataElement(u32 index) const; - - bool Remove(Common::UUID uuid); - u32 IndexOf(Common::UUID uuid) const; - u32 IndexOf(const MiiInfo& info) const; - - bool Move(Common::UUID uuid, u32 new_index); - bool AddOrReplace(const MiiStoreData& data); - - bool DestroyFile(); - bool DeleteFile(); - -private: - void WriteToFile(); - void ReadFromFile(); - - MiiStoreData CreateMiiWithUniqueUUID() const; - - void EnsureDatabasePartition(); - - MiiDatabase database; - bool updated_flag{}; - bool is_test_mode_enabled{}; -}; - -}; // namespace Service::Mii diff --git a/src/core/hle/service/mii/raw_data.cpp b/src/core/hle/service/mii/raw_data.cpp new file mode 100644 index 000000000..25d7bae0c --- /dev/null +++ b/src/core/hle/service/mii/raw_data.cpp @@ -0,0 +1,2261 @@ +// MIT License +// +// Copyright (c) Ryujinx Team and Contributors +// +// 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. +// + +#include "core/hle/service/mii/raw_data.h" + +namespace Service::Mii::RawData { + +const std::array<u8, 1728> DefaultMii{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x20, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6d, 0x00, + 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x6f, 0x00, + 0x20, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x20, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6d, 0x00, + 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x6f, 0x00, + 0x20, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x20, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6d, 0x00, + 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x6f, 0x00, + 0x20, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +const std::array<u8, 3672> RandomMiiFaceline{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +const std::array<u8, 1200> RandomMiiFacelineColor{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +const std::array<u8, 3672> RandomMiiFacelineWrinkle{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +const std::array<u8, 3672> RandomMiiFacelineMakeup{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +const std::array<u8, 3672> RandomMiiHairType{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x56, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x36, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x42, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, + 0x56, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, + 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x2d, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, + 0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, + 0x49, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, + 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x26, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, + 0x2f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, + 0x33, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, + 0x37, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, + 0x3c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, + 0x43, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, + 0x51, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, + 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, + 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, + 0x46, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, + 0x56, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, + 0x2d, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, + 0x36, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, + 0x41, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, + 0x2d, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, + 0x36, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, + 0x41, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x25, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, + 0x2f, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, + 0x37, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, + 0x43, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, + 0x3e, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x53, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x2e, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, + 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x4a, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, + 0x53, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, + 0x32, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, + 0x4d, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x2a, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x3e, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x51, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, + 0x3a, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x4a, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, + 0x53, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, + 0x1b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, + 0x3c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, + 0x4f, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x3a, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, + 0x3e, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x51, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, + 0x53, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +const std::array<u8, 1800> RandomMiiHairColor{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +const std::array<u8, 3672> RandomMiiEyeType{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x1b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, + 0x35, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, + 0x1d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, + 0x2f, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, + 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, + 0x1d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, + 0x2f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, + 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, + 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, + 0x35, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x1b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, + 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x2f, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, + 0x37, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, + 0x1d, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, + 0x29, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, + 0x29, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, + 0x35, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, + 0x37, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, + 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x25, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, + 0x35, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x1d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, + 0x2f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, + 0x39, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, + 0x2a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, + 0x2a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, + 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, + 0x2a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, + 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x1d, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, + 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, + 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, + 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, + 0x36, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, + 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, + 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, + 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, + 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +const std::array<u8, 588> RandomMiiEyeColor{ + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +const std::array<u8, 3672> RandomMiiEyebrowType{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +const std::array<u8, 3672> RandomMiiNoseType{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +const std::array<u8, 3672> RandomMiiMouthType{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x1d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +const std::array<u8, 588> RandomMiiGlassType{ + 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, + 0x56, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x4e, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +} // namespace Service::Mii::RawData diff --git a/src/core/hle/service/mii/raw_data.h b/src/core/hle/service/mii/raw_data.h new file mode 100644 index 000000000..a02a5c0fd --- /dev/null +++ b/src/core/hle/service/mii/raw_data.h @@ -0,0 +1,27 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> + +#include "common/common_types.h" + +namespace Service::Mii::RawData { + +extern const std::array<u8, 1728> DefaultMii; +extern const std::array<u8, 3672> RandomMiiFaceline; +extern const std::array<u8, 1200> RandomMiiFacelineColor; +extern const std::array<u8, 3672> RandomMiiFacelineWrinkle; +extern const std::array<u8, 3672> RandomMiiFacelineMakeup; +extern const std::array<u8, 3672> RandomMiiHairType; +extern const std::array<u8, 1800> RandomMiiHairColor; +extern const std::array<u8, 3672> RandomMiiEyeType; +extern const std::array<u8, 588> RandomMiiEyeColor; +extern const std::array<u8, 3672> RandomMiiEyebrowType; +extern const std::array<u8, 3672> RandomMiiNoseType; +extern const std::array<u8, 3672> RandomMiiMouthType; +extern const std::array<u8, 588> RandomMiiGlassType; + +} // namespace Service::Mii::RawData diff --git a/src/core/hle/service/mii/types.h b/src/core/hle/service/mii/types.h new file mode 100644 index 000000000..d65a1055e --- /dev/null +++ b/src/core/hle/service/mii/types.h @@ -0,0 +1,67 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_funcs.h" +#include "common/common_types.h" + +namespace Service::Mii { + +enum class Age : u32 { + Young, + Normal, + Old, + All, +}; + +enum class BeardType : u32 { + None, + Beard1, + Beard2, + Beard3, + Beard4, + Beard5, +}; + +enum class BeardAndMustacheFlag : u32 { Beard = 1, Mustache, All = Beard | Mustache }; +DECLARE_ENUM_FLAG_OPERATORS(BeardAndMustacheFlag); + +enum class FontRegion : u32 { + Standard, + China, + Korea, + Taiwan, +}; + +enum class Gender : u32 { + Male, + Female, + All, + Maximum = Female, +}; + +enum class HairFlip : u32 { + Left, + Right, + Maximum = Right, +}; + +enum class MustacheType : u32 { + None, + Mustache1, + Mustache2, + Mustache3, + Mustache4, + Mustache5, +}; + +enum class Race : u32 { + Black, + White, + Asian, + All, +}; + +} // namespace Service::Mii diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 2f44d3779..789856118 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -28,8 +28,7 @@ namespace Service::NVFlinger { -constexpr s64 frame_ticks = static_cast<s64>(1000000000 / 60); -constexpr s64 frame_ticks_30fps = static_cast<s64>(1000000000 / 30); +constexpr auto frame_ns = std::chrono::nanoseconds{1000000000 / 60}; void NVFlinger::VSyncThread(NVFlinger& nv_flinger) { nv_flinger.SplitVSync(); @@ -67,20 +66,24 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) { guard = std::make_shared<std::mutex>(); // Schedule the screen composition events - composition_event = - Core::Timing::CreateEvent("ScreenComposition", [this](u64 userdata, s64 ns_late) { + composition_event = Core::Timing::CreateEvent( + "ScreenComposition", [this](u64, std::chrono::nanoseconds ns_late) { Lock(); Compose(); - const auto ticks = GetNextTicks(); - this->system.CoreTiming().ScheduleEvent(std::max<s64>(0LL, ticks - ns_late), - composition_event); + + const auto ticks = std::chrono::nanoseconds{GetNextTicks()}; + const auto ticks_delta = ticks - ns_late; + const auto future_ns = std::max(std::chrono::nanoseconds::zero(), ticks_delta); + + this->system.CoreTiming().ScheduleEvent(future_ns, composition_event); }); + if (system.IsMulticore()) { is_running = true; wait_event = std::make_unique<Common::Event>(); vsync_thread = std::make_unique<std::thread>(VSyncThread, std::ref(*this)); } else { - system.CoreTiming().ScheduleEvent(frame_ticks, composition_event); + system.CoreTiming().ScheduleEvent(frame_ns, composition_event); } } diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index 53d27859b..ced41b1fe 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp @@ -20,7 +20,7 @@ namespace Core::Memory { -constexpr s64 CHEAT_ENGINE_TICKS = static_cast<s64>(1000000000 / 12); +constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12}; constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF; StandardVmCallbacks::StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata) @@ -188,10 +188,12 @@ CheatEngine::~CheatEngine() { } void CheatEngine::Initialize() { - event = Core::Timing::CreateEvent( - "CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id), - [this](u64 userdata, s64 ns_late) { FrameCallback(userdata, ns_late); }); - core_timing.ScheduleEvent(CHEAT_ENGINE_TICKS, event); + event = Core::Timing::CreateEvent("CheatEngine::FrameCallback::" + + Common::HexToString(metadata.main_nso_build_id), + [this](u64 userdata, std::chrono::nanoseconds ns_late) { + FrameCallback(userdata, ns_late); + }); + core_timing.ScheduleEvent(CHEAT_ENGINE_NS, event); metadata.process_id = system.CurrentProcess()->GetProcessID(); metadata.title_id = system.CurrentProcess()->GetTitleID(); @@ -217,7 +219,7 @@ void CheatEngine::Reload(std::vector<CheatEntry> cheats) { MICROPROFILE_DEFINE(Cheat_Engine, "Add-Ons", "Cheat Engine", MP_RGB(70, 200, 70)); -void CheatEngine::FrameCallback(u64 userdata, s64 ns_late) { +void CheatEngine::FrameCallback(u64, std::chrono::nanoseconds ns_late) { if (is_pending_reload.exchange(false)) { vm.LoadProgram(cheats); } @@ -230,7 +232,7 @@ void CheatEngine::FrameCallback(u64 userdata, s64 ns_late) { vm.Execute(metadata); - core_timing.ScheduleEvent(CHEAT_ENGINE_TICKS - ns_late, event); + core_timing.ScheduleEvent(CHEAT_ENGINE_NS - ns_late, event); } } // namespace Core::Memory diff --git a/src/core/memory/cheat_engine.h b/src/core/memory/cheat_engine.h index 2649423f8..d4068cf84 100644 --- a/src/core/memory/cheat_engine.h +++ b/src/core/memory/cheat_engine.h @@ -5,6 +5,7 @@ #pragma once #include <atomic> +#include <chrono> #include <memory> #include <vector> #include "common/common_types.h" @@ -71,7 +72,7 @@ public: void Reload(std::vector<CheatEntry> cheats); private: - void FrameCallback(u64 userdata, s64 cycles_late); + void FrameCallback(u64 userdata, std::chrono::nanoseconds ns_late); DmntCheatVm vm; CheatProcessMetadata metadata; diff --git a/src/core/memory/dmnt_cheat_vm.cpp b/src/core/memory/dmnt_cheat_vm.cpp index fb9f36bfd..2e7da23fe 100644 --- a/src/core/memory/dmnt_cheat_vm.cpp +++ b/src/core/memory/dmnt_cheat_vm.cpp @@ -190,6 +190,15 @@ void DmntCheatVm::LogOpcode(const CheatVmOpcode& opcode) { callbacks->CommandLog( fmt::format("Act[{:02X}]: {:d}", i, save_restore_regmask->should_operate[i])); } + } else if (auto rw_static_reg = std::get_if<ReadWriteStaticRegisterOpcode>(&opcode.opcode)) { + callbacks->CommandLog("Opcode: Read/Write Static Register"); + if (rw_static_reg->static_idx < NumReadableStaticRegisters) { + callbacks->CommandLog("Op Type: ReadStaticRegister"); + } else { + callbacks->CommandLog("Op Type: WriteStaticRegister"); + } + callbacks->CommandLog(fmt::format("Reg Idx {:X}", rw_static_reg->idx)); + callbacks->CommandLog(fmt::format("Stc Idx {:X}", rw_static_reg->static_idx)); } else if (auto debug_log = std::get_if<DebugLogOpcode>(&opcode.opcode)) { callbacks->CommandLog("Opcode: Debug Log"); callbacks->CommandLog(fmt::format("Bit Width: {:X}", debug_log->bit_width)); @@ -544,6 +553,16 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) { } opcode.opcode = save_restore_regmask; } break; + case CheatVmOpcodeType::ReadWriteStaticRegister: { + ReadWriteStaticRegisterOpcode rw_static_reg{}; + // C3000XXx + // C3 = opcode 0xC3. + // XX = static register index. + // x = register index. + rw_static_reg.static_idx = ((first_dword >> 4) & 0xFF); + rw_static_reg.idx = (first_dword & 0xF); + opcode.opcode = rw_static_reg; + } break; case CheatVmOpcodeType::DebugLog: { DebugLogOpcode debug_log{}; // FFFTIX## @@ -667,6 +686,7 @@ void DmntCheatVm::ResetState() { registers.fill(0); saved_values.fill(0); loop_tops.fill(0); + static_registers.fill(0); instruction_ptr = 0; condition_depth = 0; decode_success = true; @@ -1153,6 +1173,15 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) { } } } + } else if (auto rw_static_reg = + std::get_if<ReadWriteStaticRegisterOpcode>(&cur_opcode.opcode)) { + if (rw_static_reg->static_idx < NumReadableStaticRegisters) { + // Load a register with a static register. + registers[rw_static_reg->idx] = static_registers[rw_static_reg->static_idx]; + } else { + // Store a register to a static register. + static_registers[rw_static_reg->static_idx] = registers[rw_static_reg->idx]; + } } else if (auto debug_log = std::get_if<DebugLogOpcode>(&cur_opcode.opcode)) { // Read value from memory. u64 log_value = 0; diff --git a/src/core/memory/dmnt_cheat_vm.h b/src/core/memory/dmnt_cheat_vm.h index 8351fd798..21b86b72c 100644 --- a/src/core/memory/dmnt_cheat_vm.h +++ b/src/core/memory/dmnt_cheat_vm.h @@ -56,6 +56,7 @@ enum class CheatVmOpcodeType : u32 { BeginRegisterConditionalBlock = 0xC0, SaveRestoreRegister = 0xC1, SaveRestoreRegisterMask = 0xC2, + ReadWriteStaticRegister = 0xC3, // This is a meta entry, and not a real opcode. // This is to facilitate multi-nybble instruction decoding. @@ -237,6 +238,11 @@ struct SaveRestoreRegisterMaskOpcode { std::array<bool, 0x10> should_operate{}; }; +struct ReadWriteStaticRegisterOpcode { + u32 static_idx{}; + u32 idx{}; +}; + struct DebugLogOpcode { u32 bit_width{}; u32 log_id{}; @@ -259,7 +265,8 @@ struct CheatVmOpcode { PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode, PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode, BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode, - SaveRestoreRegisterMaskOpcode, DebugLogOpcode, UnrecognizedInstruction> + SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, DebugLogOpcode, + UnrecognizedInstruction> opcode{}; }; @@ -281,6 +288,10 @@ public: static constexpr std::size_t MaximumProgramOpcodeCount = 0x400; static constexpr std::size_t NumRegisters = 0x10; + static constexpr std::size_t NumReadableStaticRegisters = 0x80; + static constexpr std::size_t NumWritableStaticRegisters = 0x80; + static constexpr std::size_t NumStaticRegisters = + NumReadableStaticRegisters + NumWritableStaticRegisters; explicit DmntCheatVm(std::unique_ptr<Callbacks> callbacks); ~DmntCheatVm(); @@ -302,6 +313,7 @@ private: std::array<u32, MaximumProgramOpcodeCount> program{}; std::array<u64, NumRegisters> registers{}; std::array<u64, NumRegisters> saved_values{}; + std::array<u64, NumStaticRegisters> static_registers{}; std::array<std::size_t, NumRegisters> loop_tops{}; bool DecodeNextOpcode(CheatVmOpcode& out); diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp new file mode 100644 index 000000000..56d173b5e --- /dev/null +++ b/src/core/network/network.cpp @@ -0,0 +1,654 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include <cstring> +#include <limits> +#include <utility> +#include <vector> + +#ifdef _WIN32 +#define _WINSOCK_DEPRECATED_NO_WARNINGS // gethostname +#include <winsock2.h> +#elif __unix__ +#include <errno.h> +#include <fcntl.h> +#include <netdb.h> +#include <netinet/in.h> +#include <poll.h> +#include <sys/socket.h> +#include <unistd.h> +#else +#error "Unimplemented platform" +#endif + +#include "common/assert.h" +#include "common/common_types.h" +#include "common/logging/log.h" +#include "core/network/network.h" +#include "core/network/sockets.h" + +namespace Network { + +namespace { + +#ifdef _WIN32 + +using socklen_t = int; + +void Initialize() { + WSADATA wsa_data; + (void)WSAStartup(MAKEWORD(2, 2), &wsa_data); +} + +void Finalize() { + WSACleanup(); +} + +constexpr IPv4Address TranslateIPv4(in_addr addr) { + auto& bytes = addr.S_un.S_un_b; + return IPv4Address{bytes.s_b1, bytes.s_b2, bytes.s_b3, bytes.s_b4}; +} + +sockaddr TranslateFromSockAddrIn(SockAddrIn input) { + sockaddr_in result; + +#ifdef __unix__ + result.sin_len = sizeof(result); +#endif + + switch (static_cast<Domain>(input.family)) { + case Domain::INET: + result.sin_family = AF_INET; + break; + default: + UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", static_cast<int>(input.family)); + result.sin_family = AF_INET; + break; + } + + result.sin_port = htons(input.portno); + + auto& ip = result.sin_addr.S_un.S_un_b; + ip.s_b1 = input.ip[0]; + ip.s_b2 = input.ip[1]; + ip.s_b3 = input.ip[2]; + ip.s_b4 = input.ip[3]; + + sockaddr addr; + std::memcpy(&addr, &result, sizeof(addr)); + return addr; +} + +LINGER MakeLinger(bool enable, u32 linger_value) { + ASSERT(linger_value <= std::numeric_limits<u_short>::max()); + + LINGER value; + value.l_onoff = enable ? 1 : 0; + value.l_linger = static_cast<u_short>(linger_value); + return value; +} + +int LastError() { + return WSAGetLastError(); +} + +bool EnableNonBlock(SOCKET fd, bool enable) { + u_long value = enable ? 1 : 0; + return ioctlsocket(fd, FIONBIO, &value) != SOCKET_ERROR; +} + +#elif __unix__ // ^ _WIN32 v __unix__ + +using SOCKET = int; +using WSAPOLLFD = pollfd; +using ULONG = u64; + +constexpr SOCKET INVALID_SOCKET = -1; +constexpr SOCKET SOCKET_ERROR = -1; + +constexpr int WSAEWOULDBLOCK = EAGAIN; +constexpr int WSAENOTCONN = ENOTCONN; + +constexpr int SD_RECEIVE = SHUT_RD; +constexpr int SD_SEND = SHUT_WR; +constexpr int SD_BOTH = SHUT_RDWR; + +void Initialize() {} + +void Finalize() {} + +constexpr IPv4Address TranslateIPv4(in_addr addr) { + const u32 bytes = addr.s_addr; + return IPv4Address{static_cast<u8>(bytes), static_cast<u8>(bytes >> 8), + static_cast<u8>(bytes >> 16), static_cast<u8>(bytes >> 24)}; +} + +sockaddr TranslateFromSockAddrIn(SockAddrIn input) { + sockaddr_in result; + + switch (static_cast<Domain>(input.family)) { + case Domain::INET: + result.sin_family = AF_INET; + break; + default: + UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", static_cast<int>(input.family)); + result.sin_family = AF_INET; + break; + } + + result.sin_port = htons(input.portno); + + result.sin_addr.s_addr = input.ip[0] | input.ip[1] << 8 | input.ip[2] << 16 | input.ip[3] << 24; + + sockaddr addr; + std::memcpy(&addr, &result, sizeof(addr)); + return addr; +} + +int WSAPoll(WSAPOLLFD* fds, ULONG nfds, int timeout) { + return poll(fds, nfds, timeout); +} + +int closesocket(SOCKET fd) { + return close(fd); +} + +linger MakeLinger(bool enable, u32 linger_value) { + linger value; + value.l_onoff = enable ? 1 : 0; + value.l_linger = linger_value; + return value; +} + +int LastError() { + return errno; +} + +bool EnableNonBlock(int fd, bool enable) { + int flags = fcntl(fd, F_GETFD); + if (flags == -1) { + return false; + } + if (enable) { + flags |= O_NONBLOCK; + } else { + flags &= ~O_NONBLOCK; + } + return fcntl(fd, F_SETFD, flags) == 0; +} + +#endif + +int TranslateDomain(Domain domain) { + switch (domain) { + case Domain::INET: + return AF_INET; + default: + UNIMPLEMENTED_MSG("Unimplemented domain={}", static_cast<int>(domain)); + return 0; + } +} + +int TranslateType(Type type) { + switch (type) { + case Type::STREAM: + return SOCK_STREAM; + case Type::DGRAM: + return SOCK_DGRAM; + default: + UNIMPLEMENTED_MSG("Unimplemented type={}", static_cast<int>(type)); + return 0; + } +} + +int TranslateProtocol(Protocol protocol) { + switch (protocol) { + case Protocol::TCP: + return IPPROTO_TCP; + case Protocol::UDP: + return IPPROTO_UDP; + default: + UNIMPLEMENTED_MSG("Unimplemented protocol={}", static_cast<int>(protocol)); + return 0; + } +} + +SockAddrIn TranslateToSockAddrIn(sockaddr input_) { + sockaddr_in input; + std::memcpy(&input, &input_, sizeof(input)); + + SockAddrIn result; + + switch (input.sin_family) { + case AF_INET: + result.family = Domain::INET; + break; + default: + UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", input.sin_family); + result.family = Domain::INET; + break; + } + + result.portno = ntohs(input.sin_port); + + result.ip = TranslateIPv4(input.sin_addr); + + return result; +} + +u16 TranslatePollEvents(u16 events) { + u16 result = 0; + + if (events & POLL_IN) { + events &= ~POLL_IN; + result |= POLLIN; + } + if (events & POLL_PRI) { + events &= ~POLL_PRI; +#ifdef _WIN32 + LOG_WARNING(Service, "Winsock doesn't support POLLPRI"); +#else + result |= POLL_PRI; +#endif + } + if (events & POLL_OUT) { + events &= ~POLL_OUT; + result |= POLLOUT; + } + + UNIMPLEMENTED_IF_MSG(events != 0, "Unhandled guest events=0x{:x}", events); + + return result; +} + +u16 TranslatePollRevents(u16 revents) { + u16 result = 0; + const auto translate = [&result, &revents](int host, unsigned guest) { + if (revents & host) { + revents &= ~host; + result |= guest; + } + }; + + translate(POLLIN, POLL_IN); + translate(POLLPRI, POLL_PRI); + translate(POLLOUT, POLL_OUT); + translate(POLLERR, POLL_ERR); + translate(POLLHUP, POLL_HUP); + + UNIMPLEMENTED_IF_MSG(revents != 0, "Unhandled host revents=0x{:x}", revents); + + return result; +} + +template <typename T> +Errno SetSockOpt(SOCKET fd, int option, T value) { + const int result = + setsockopt(fd, SOL_SOCKET, option, reinterpret_cast<const char*>(&value), sizeof(value)); + if (result != SOCKET_ERROR) { + return Errno::SUCCESS; + } + const int ec = LastError(); + UNREACHABLE_MSG("Unhandled host socket error={}", ec); + return Errno::SUCCESS; +} + +} // Anonymous namespace + +NetworkInstance::NetworkInstance() { + Initialize(); +} + +NetworkInstance::~NetworkInstance() { + Finalize(); +} + +std::pair<IPv4Address, Errno> GetHostIPv4Address() { + std::array<char, 256> name{}; + if (gethostname(name.data(), static_cast<int>(name.size()) - 1) == SOCKET_ERROR) { + UNIMPLEMENTED_MSG("Unhandled gethostname error"); + return {IPv4Address{}, Errno::SUCCESS}; + } + + hostent* const ent = gethostbyname(name.data()); + if (!ent) { + UNIMPLEMENTED_MSG("Unhandled gethostbyname error"); + return {IPv4Address{}, Errno::SUCCESS}; + } + if (ent->h_addr_list == nullptr) { + UNIMPLEMENTED_MSG("No addr provided in hostent->h_addr_list"); + return {IPv4Address{}, Errno::SUCCESS}; + } + if (ent->h_length != sizeof(in_addr)) { + UNIMPLEMENTED_MSG("Unexpected size={} in hostent->h_length", ent->h_length); + } + + in_addr addr; + std::memcpy(&addr, ent->h_addr_list[0], sizeof(addr)); + return {TranslateIPv4(addr), Errno::SUCCESS}; +} + +std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) { + const size_t num = pollfds.size(); + + std::vector<WSAPOLLFD> host_pollfds(pollfds.size()); + std::transform(pollfds.begin(), pollfds.end(), host_pollfds.begin(), [](PollFD fd) { + WSAPOLLFD result; + result.fd = fd.socket->fd; + result.events = TranslatePollEvents(fd.events); + result.revents = 0; + return result; + }); + + const int result = WSAPoll(host_pollfds.data(), static_cast<ULONG>(num), timeout); + if (result == 0) { + ASSERT(std::all_of(host_pollfds.begin(), host_pollfds.end(), + [](WSAPOLLFD fd) { return fd.revents == 0; })); + return {0, Errno::SUCCESS}; + } + + for (size_t i = 0; i < num; ++i) { + pollfds[i].revents = TranslatePollRevents(host_pollfds[i].revents); + } + + if (result > 0) { + return {result, Errno::SUCCESS}; + } + + ASSERT(result == SOCKET_ERROR); + + const int ec = LastError(); + UNREACHABLE_MSG("Unhandled host socket error={}", ec); + return {-1, Errno::SUCCESS}; +} + +Socket::~Socket() { + if (fd == INVALID_SOCKET) { + return; + } + (void)closesocket(fd); + fd = INVALID_SOCKET; +} + +Socket::Socket(Socket&& rhs) noexcept : fd{std::exchange(rhs.fd, INVALID_SOCKET)} {} + +Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) { + fd = socket(TranslateDomain(domain), TranslateType(type), TranslateProtocol(protocol)); + if (fd != INVALID_SOCKET) { + return Errno::SUCCESS; + } + + const int ec = LastError(); + UNREACHABLE_MSG("Unhandled host socket error={}", ec); + return Errno::SUCCESS; +} + +std::pair<Socket::AcceptResult, Errno> Socket::Accept() { + sockaddr addr; + socklen_t addrlen = sizeof(addr); + const SOCKET new_socket = accept(fd, &addr, &addrlen); + + if (new_socket == INVALID_SOCKET) { + const int ec = LastError(); + UNREACHABLE_MSG("Unhandled host socket error={}", ec); + return {AcceptResult{}, Errno::SUCCESS}; + } + + AcceptResult result; + result.socket = std::make_unique<Socket>(); + result.socket->fd = new_socket; + + ASSERT(addrlen == sizeof(sockaddr_in)); + result.sockaddr_in = TranslateToSockAddrIn(addr); + + return {std::move(result), Errno::SUCCESS}; +} + +Errno Socket::Connect(SockAddrIn addr_in) { + const sockaddr host_addr_in = TranslateFromSockAddrIn(addr_in); + if (connect(fd, &host_addr_in, sizeof(host_addr_in)) != INVALID_SOCKET) { + return Errno::SUCCESS; + } + + switch (const int ec = LastError()) { + case WSAEWOULDBLOCK: + LOG_DEBUG(Service, "EAGAIN generated"); + return Errno::AGAIN; + default: + UNREACHABLE_MSG("Unhandled host socket error={}", ec); + return Errno::SUCCESS; + } +} + +std::pair<SockAddrIn, Errno> Socket::GetPeerName() { + sockaddr addr; + socklen_t addrlen = sizeof(addr); + if (getpeername(fd, &addr, &addrlen) == SOCKET_ERROR) { + const int ec = LastError(); + UNREACHABLE_MSG("Unhandled host socket error={}", ec); + return {SockAddrIn{}, Errno::SUCCESS}; + } + + ASSERT(addrlen == sizeof(sockaddr_in)); + return {TranslateToSockAddrIn(addr), Errno::SUCCESS}; +} + +std::pair<SockAddrIn, Errno> Socket::GetSockName() { + sockaddr addr; + socklen_t addrlen = sizeof(addr); + if (getsockname(fd, &addr, &addrlen) == SOCKET_ERROR) { + const int ec = LastError(); + UNREACHABLE_MSG("Unhandled host socket error={}", ec); + return {SockAddrIn{}, Errno::SUCCESS}; + } + + ASSERT(addrlen == sizeof(sockaddr_in)); + return {TranslateToSockAddrIn(addr), Errno::SUCCESS}; +} + +Errno Socket::Bind(SockAddrIn addr) { + const sockaddr addr_in = TranslateFromSockAddrIn(addr); + if (bind(fd, &addr_in, sizeof(addr_in)) != SOCKET_ERROR) { + return Errno::SUCCESS; + } + + const int ec = LastError(); + UNREACHABLE_MSG("Unhandled host socket error={}", ec); + return Errno::SUCCESS; +} + +Errno Socket::Listen(s32 backlog) { + if (listen(fd, backlog) != SOCKET_ERROR) { + return Errno::SUCCESS; + } + + const int ec = LastError(); + UNREACHABLE_MSG("Unhandled host socket error={}", ec); + return Errno::SUCCESS; +} + +Errno Socket::Shutdown(ShutdownHow how) { + int host_how = 0; + switch (how) { + case ShutdownHow::RD: + host_how = SD_RECEIVE; + break; + case ShutdownHow::WR: + host_how = SD_SEND; + break; + case ShutdownHow::RDWR: + host_how = SD_BOTH; + break; + default: + UNIMPLEMENTED_MSG("Unimplemented flag how={}", static_cast<int>(how)); + return Errno::SUCCESS; + } + if (shutdown(fd, host_how) != SOCKET_ERROR) { + return Errno::SUCCESS; + } + + switch (const int ec = LastError()) { + case WSAENOTCONN: + LOG_ERROR(Service, "ENOTCONN generated"); + return Errno::NOTCONN; + default: + UNREACHABLE_MSG("Unhandled host socket error={}", ec); + return Errno::SUCCESS; + } +} + +std::pair<s32, Errno> Socket::Recv(int flags, std::vector<u8>& message) { + ASSERT(flags == 0); + ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); + + const int result = + recv(fd, reinterpret_cast<char*>(message.data()), static_cast<int>(message.size()), 0); + if (result != SOCKET_ERROR) { + return {result, Errno::SUCCESS}; + } + + switch (const int ec = LastError()) { + case WSAEWOULDBLOCK: + LOG_DEBUG(Service, "EAGAIN generated"); + return {-1, Errno::AGAIN}; + case WSAENOTCONN: + LOG_ERROR(Service, "ENOTCONN generated"); + return {-1, Errno::NOTCONN}; + default: + UNREACHABLE_MSG("Unhandled host socket error={}", ec); + return {0, Errno::SUCCESS}; + } +} + +std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) { + ASSERT(flags == 0); + ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); + + sockaddr addr_in{}; + socklen_t addrlen = sizeof(addr_in); + socklen_t* const p_addrlen = addr ? &addrlen : nullptr; + sockaddr* const p_addr_in = addr ? &addr_in : nullptr; + + const int result = recvfrom(fd, reinterpret_cast<char*>(message.data()), + static_cast<int>(message.size()), 0, p_addr_in, p_addrlen); + if (result != SOCKET_ERROR) { + if (addr) { + ASSERT(addrlen == sizeof(addr_in)); + *addr = TranslateToSockAddrIn(addr_in); + } + return {result, Errno::SUCCESS}; + } + + switch (const int ec = LastError()) { + case WSAEWOULDBLOCK: + LOG_DEBUG(Service, "EAGAIN generated"); + return {-1, Errno::AGAIN}; + case WSAENOTCONN: + LOG_ERROR(Service, "ENOTCONN generated"); + return {-1, Errno::NOTCONN}; + default: + UNREACHABLE_MSG("Unhandled host socket error={}", ec); + return {-1, Errno::SUCCESS}; + } +} + +std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) { + ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); + ASSERT(flags == 0); + + const int result = send(fd, reinterpret_cast<const char*>(message.data()), + static_cast<int>(message.size()), 0); + if (result != SOCKET_ERROR) { + return {result, Errno::SUCCESS}; + } + + const int ec = LastError(); + switch (ec) { + case WSAEWOULDBLOCK: + LOG_DEBUG(Service, "EAGAIN generated"); + return {-1, Errno::AGAIN}; + case WSAENOTCONN: + LOG_ERROR(Service, "ENOTCONN generated"); + return {-1, Errno::NOTCONN}; + default: + UNREACHABLE_MSG("Unhandled host socket error={}", ec); + return {-1, Errno::SUCCESS}; + } +} + +std::pair<s32, Errno> Socket::SendTo(u32 flags, const std::vector<u8>& message, + const SockAddrIn* addr) { + ASSERT(flags == 0); + + const sockaddr* to = nullptr; + const int tolen = addr ? 0 : sizeof(sockaddr); + sockaddr host_addr_in; + + if (addr) { + host_addr_in = TranslateFromSockAddrIn(*addr); + to = &host_addr_in; + } + + const int result = sendto(fd, reinterpret_cast<const char*>(message.data()), + static_cast<int>(message.size()), 0, to, tolen); + if (result != SOCKET_ERROR) { + return {result, Errno::SUCCESS}; + } + + const int ec = LastError(); + UNREACHABLE_MSG("Unhandled host socket error={}", ec); + return {-1, Errno::SUCCESS}; +} + +Errno Socket::Close() { + [[maybe_unused]] const int result = closesocket(fd); + ASSERT(result == 0); + fd = INVALID_SOCKET; + + return Errno::SUCCESS; +} + +Errno Socket::SetLinger(bool enable, u32 linger) { + return SetSockOpt(fd, SO_LINGER, MakeLinger(enable, linger)); +} + +Errno Socket::SetReuseAddr(bool enable) { + return SetSockOpt<u32>(fd, SO_REUSEADDR, enable ? 1 : 0); +} + +Errno Socket::SetBroadcast(bool enable) { + return SetSockOpt<u32>(fd, SO_BROADCAST, enable ? 1 : 0); +} + +Errno Socket::SetSndBuf(u32 value) { + return SetSockOpt(fd, SO_SNDBUF, value); +} + +Errno Socket::SetRcvBuf(u32 value) { + return SetSockOpt(fd, SO_RCVBUF, value); +} + +Errno Socket::SetSndTimeo(u32 value) { + return SetSockOpt(fd, SO_SNDTIMEO, value); +} + +Errno Socket::SetRcvTimeo(u32 value) { + return SetSockOpt(fd, SO_RCVTIMEO, value); +} + +Errno Socket::SetNonBlock(bool enable) { + if (EnableNonBlock(fd, enable)) { + return Errno::SUCCESS; + } + const int ec = LastError(); + UNREACHABLE_MSG("Unhandled host socket error={}", ec); + return Errno::SUCCESS; +} + +bool Socket::IsOpened() const { + return fd != INVALID_SOCKET; +} + +} // namespace Network diff --git a/src/core/network/network.h b/src/core/network/network.h new file mode 100644 index 000000000..0622e4593 --- /dev/null +++ b/src/core/network/network.h @@ -0,0 +1,87 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> +#include <utility> + +#include "common/common_types.h" + +namespace Network { + +class Socket; + +/// Error code for network functions +enum class Errno { + SUCCESS, + BADF, + INVAL, + MFILE, + NOTCONN, + AGAIN, +}; + +/// Address families +enum class Domain { + INET, ///< Address family for IPv4 +}; + +/// Socket types +enum class Type { + STREAM, + DGRAM, + RAW, + SEQPACKET, +}; + +/// Protocol values for sockets +enum class Protocol { + ICMP, + TCP, + UDP, +}; + +/// Shutdown mode +enum class ShutdownHow { + RD, + WR, + RDWR, +}; + +/// Array of IPv4 address +using IPv4Address = std::array<u8, 4>; + +/// Cross-platform sockaddr structure +struct SockAddrIn { + Domain family; + IPv4Address ip; + u16 portno; +}; + +/// Cross-platform poll fd structure +struct PollFD { + Socket* socket; + u16 events; + u16 revents; +}; + +constexpr u16 POLL_IN = 1 << 0; +constexpr u16 POLL_PRI = 1 << 1; +constexpr u16 POLL_OUT = 1 << 2; +constexpr u16 POLL_ERR = 1 << 3; +constexpr u16 POLL_HUP = 1 << 4; +constexpr u16 POLL_NVAL = 1 << 5; + +class NetworkInstance { +public: + explicit NetworkInstance(); + ~NetworkInstance(); +}; + +/// @brief Returns host's IPv4 address +/// @return Pair of an array of human ordered IPv4 address (e.g. 192.168.0.1) and an error code +std::pair<IPv4Address, Errno> GetHostIPv4Address(); + +} // namespace Network diff --git a/src/core/network/sockets.h b/src/core/network/sockets.h new file mode 100644 index 000000000..7bdff0fe4 --- /dev/null +++ b/src/core/network/sockets.h @@ -0,0 +1,94 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include <utility> + +#if defined(_WIN32) +#include <winsock.h> +#elif !defined(__unix__) +#error "Platform not implemented" +#endif + +#include "common/common_types.h" +#include "core/network/network.h" + +// TODO: C++20 Replace std::vector usages with std::span + +namespace Network { + +class Socket { +public: + struct AcceptResult { + std::unique_ptr<Socket> socket; + SockAddrIn sockaddr_in; + }; + + explicit Socket() = default; + ~Socket(); + + Socket(const Socket&) = delete; + Socket& operator=(const Socket&) = delete; + + Socket(Socket&& rhs) noexcept; + + // Avoid closing sockets implicitly + Socket& operator=(Socket&&) noexcept = delete; + + Errno Initialize(Domain domain, Type type, Protocol protocol); + + Errno Close(); + + std::pair<AcceptResult, Errno> Accept(); + + Errno Connect(SockAddrIn addr_in); + + std::pair<SockAddrIn, Errno> GetPeerName(); + + std::pair<SockAddrIn, Errno> GetSockName(); + + Errno Bind(SockAddrIn addr); + + Errno Listen(s32 backlog); + + Errno Shutdown(ShutdownHow how); + + std::pair<s32, Errno> Recv(int flags, std::vector<u8>& message); + + std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr); + + std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags); + + std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message, const SockAddrIn* addr); + + Errno SetLinger(bool enable, u32 linger); + + Errno SetReuseAddr(bool enable); + + Errno SetBroadcast(bool enable); + + Errno SetSndBuf(u32 value); + + Errno SetRcvBuf(u32 value); + + Errno SetSndTimeo(u32 value); + + Errno SetRcvTimeo(u32 value); + + Errno SetNonBlock(bool enable); + + bool IsOpened() const; + +#if defined(_WIN32) + SOCKET fd = INVALID_SOCKET; +#elif defined(__unix__) + int fd = -1; +#endif +}; + +std::pair<s32, Errno> Poll(std::vector<PollFD>& poll_fds, s32 timeout); + +} // namespace Network diff --git a/src/core/settings.cpp b/src/core/settings.cpp index d3886c4ec..44252dd81 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <string_view> + #include "common/file_util.h" #include "core/core.h" #include "core/gdbstub/gdbstub.h" @@ -65,18 +67,18 @@ Values values = {}; bool configuring_global = true; std::string GetTimeZoneString() { - static constexpr std::array<const char*, 46> timezones{{ + static constexpr std::array timezones{ "auto", "default", "CET", "CST6CDT", "Cuba", "EET", "Egypt", "Eire", "EST", "EST5EDT", "GB", "GB-Eire", "GMT", "GMT+0", "GMT-0", "GMT0", "Greenwich", "Hongkong", "HST", "Iceland", "Iran", "Israel", "Jamaica", "Japan", "Kwajalein", "Libya", "MET", "MST", "MST7MDT", "Navajo", "NZ", "NZ-CHAT", "Poland", "Portugal", "PRC", "PST8PDT", "ROC", "ROK", "Singapore", "Turkey", "UCT", "Universal", "UTC", "W-SU", "WET", "Zulu", - }}; - - ASSERT(Settings::values.time_zone_index.GetValue() < timezones.size()); + }; - return timezones[Settings::values.time_zone_index.GetValue()]; + const auto time_zone_index = static_cast<std::size_t>(values.time_zone_index.GetValue()); + ASSERT(time_zone_index < timezones.size()); + return timezones[time_zone_index]; } void Apply() { @@ -91,41 +93,41 @@ void Apply() { Service::HID::ReloadInputDevices(); } -template <typename T> -void LogSetting(const std::string& name, const T& value) { - LOG_INFO(Config, "{}: {}", name, value); -} - void LogSettings() { + const auto log_setting = [](std::string_view name, const auto& value) { + LOG_INFO(Config, "{}: {}", name, value); + }; + LOG_INFO(Config, "yuzu Configuration:"); - LogSetting("Controls_UseDockedMode", Settings::values.use_docked_mode); - LogSetting("System_RngSeed", Settings::values.rng_seed.GetValue().value_or(0)); - LogSetting("System_CurrentUser", Settings::values.current_user); - LogSetting("System_LanguageIndex", Settings::values.language_index.GetValue()); - LogSetting("System_RegionIndex", Settings::values.region_index.GetValue()); - LogSetting("System_TimeZoneIndex", Settings::values.time_zone_index.GetValue()); - LogSetting("Core_UseMultiCore", Settings::values.use_multi_core.GetValue()); - LogSetting("Renderer_UseResolutionFactor", Settings::values.resolution_factor.GetValue()); - LogSetting("Renderer_UseFrameLimit", Settings::values.use_frame_limit.GetValue()); - LogSetting("Renderer_FrameLimit", Settings::values.frame_limit.GetValue()); - LogSetting("Renderer_UseDiskShaderCache", Settings::values.use_disk_shader_cache.GetValue()); - LogSetting("Renderer_GPUAccuracyLevel", Settings::values.gpu_accuracy.GetValue()); - LogSetting("Renderer_UseAsynchronousGpuEmulation", - Settings::values.use_asynchronous_gpu_emulation.GetValue()); - LogSetting("Renderer_UseVsync", Settings::values.use_vsync.GetValue()); - LogSetting("Renderer_UseAssemblyShaders", Settings::values.use_assembly_shaders.GetValue()); - LogSetting("Renderer_AnisotropicFilteringLevel", Settings::values.max_anisotropy.GetValue()); - LogSetting("Audio_OutputEngine", Settings::values.sink_id); - LogSetting("Audio_EnableAudioStretching", Settings::values.enable_audio_stretching.GetValue()); - LogSetting("Audio_OutputDevice", Settings::values.audio_device_id); - LogSetting("DataStorage_UseVirtualSd", Settings::values.use_virtual_sd); - LogSetting("DataStorage_NandDir", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)); - LogSetting("DataStorage_SdmcDir", FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)); - LogSetting("Debugging_UseGdbstub", Settings::values.use_gdbstub); - LogSetting("Debugging_GdbstubPort", Settings::values.gdbstub_port); - LogSetting("Debugging_ProgramArgs", Settings::values.program_args); - LogSetting("Services_BCATBackend", Settings::values.bcat_backend); - LogSetting("Services_BCATBoxcatLocal", Settings::values.bcat_boxcat_local); + log_setting("Controls_UseDockedMode", values.use_docked_mode); + log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0)); + log_setting("System_CurrentUser", values.current_user); + log_setting("System_LanguageIndex", values.language_index.GetValue()); + log_setting("System_RegionIndex", values.region_index.GetValue()); + log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue()); + log_setting("Core_UseMultiCore", values.use_multi_core.GetValue()); + log_setting("Renderer_UseResolutionFactor", values.resolution_factor.GetValue()); + log_setting("Renderer_UseFrameLimit", values.use_frame_limit.GetValue()); + log_setting("Renderer_FrameLimit", values.frame_limit.GetValue()); + log_setting("Renderer_UseDiskShaderCache", values.use_disk_shader_cache.GetValue()); + log_setting("Renderer_GPUAccuracyLevel", values.gpu_accuracy.GetValue()); + log_setting("Renderer_UseAsynchronousGpuEmulation", + values.use_asynchronous_gpu_emulation.GetValue()); + log_setting("Renderer_UseVsync", values.use_vsync.GetValue()); + log_setting("Renderer_UseAssemblyShaders", values.use_assembly_shaders.GetValue()); + log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue()); + log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue()); + log_setting("Audio_OutputEngine", values.sink_id); + log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching.GetValue()); + log_setting("Audio_OutputDevice", values.audio_device_id); + log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd); + log_setting("DataStorage_NandDir", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)); + log_setting("DataStorage_SdmcDir", FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)); + log_setting("Debugging_UseGdbstub", values.use_gdbstub); + log_setting("Debugging_GdbstubPort", values.gdbstub_port); + log_setting("Debugging_ProgramArgs", values.program_args); + log_setting("Services_BCATBackend", values.bcat_backend); + log_setting("Services_BCATBoxcatLocal", values.bcat_boxcat_local); } float Volume() { @@ -169,6 +171,7 @@ void RestoreGlobalState() { values.use_asynchronous_gpu_emulation.SetGlobal(true); values.use_vsync.SetGlobal(true); values.use_assembly_shaders.SetGlobal(true); + values.use_asynchronous_shaders.SetGlobal(true); values.use_fast_gpu_time.SetGlobal(true); values.force_30fps_mode.SetGlobal(true); values.bg_red.SetGlobal(true); @@ -184,4 +187,9 @@ void RestoreGlobalState() { values.sound_index.SetGlobal(true); } +void Sanitize() { + values.use_asynchronous_gpu_emulation.SetValue( + values.use_asynchronous_gpu_emulation.GetValue() || values.use_multi_core.GetValue()); +} + } // namespace Settings diff --git a/src/core/settings.h b/src/core/settings.h index 3eb336f75..386233fdf 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -434,6 +434,7 @@ struct Values { Setting<bool> use_asynchronous_gpu_emulation; Setting<bool> use_vsync; Setting<bool> use_assembly_shaders; + Setting<bool> use_asynchronous_shaders; Setting<bool> force_30fps_mode; Setting<bool> use_fast_gpu_time; @@ -526,4 +527,7 @@ void LogSettings(); // Restore the global state of all applicable settings in the Values struct void RestoreGlobalState(); +// Fixes settings that are known to cause issues with the emulator +void Sanitize(); + } // namespace Settings diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 78915e6db..5a30c75da 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -207,6 +207,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) { AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync.GetValue()); AddField(field_type, "Renderer_UseAssemblyShaders", Settings::values.use_assembly_shaders.GetValue()); + AddField(field_type, "Renderer_UseAsynchronousShaders", + Settings::values.use_asynchronous_shaders.GetValue()); AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode); } diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp index 8b0c50d11..27b894b51 100644 --- a/src/core/tools/freezer.cpp +++ b/src/core/tools/freezer.cpp @@ -14,7 +14,7 @@ namespace Tools { namespace { -constexpr s64 MEMORY_FREEZER_TICKS = static_cast<s64>(1000000000 / 60); +constexpr auto memory_freezer_ns = std::chrono::nanoseconds{1000000000 / 60}; u64 MemoryReadWidth(Core::Memory::Memory& memory, u32 width, VAddr addr) { switch (width) { @@ -55,10 +55,11 @@ void MemoryWriteWidth(Core::Memory::Memory& memory, u32 width, VAddr addr, u64 v Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& memory_) : core_timing{core_timing_}, memory{memory_} { - event = Core::Timing::CreateEvent( - "MemoryFreezer::FrameCallback", - [this](u64 userdata, s64 ns_late) { FrameCallback(userdata, ns_late); }); - core_timing.ScheduleEvent(MEMORY_FREEZER_TICKS, event); + event = Core::Timing::CreateEvent("MemoryFreezer::FrameCallback", + [this](u64 userdata, std::chrono::nanoseconds ns_late) { + FrameCallback(userdata, ns_late); + }); + core_timing.ScheduleEvent(memory_freezer_ns, event); } Freezer::~Freezer() { @@ -68,7 +69,7 @@ Freezer::~Freezer() { void Freezer::SetActive(bool active) { if (!this->active.exchange(active)) { FillEntryReads(); - core_timing.ScheduleEvent(MEMORY_FREEZER_TICKS, event); + core_timing.ScheduleEvent(memory_freezer_ns, event); LOG_DEBUG(Common_Memory, "Memory freezer activated!"); } else { LOG_DEBUG(Common_Memory, "Memory freezer deactivated!"); @@ -158,7 +159,7 @@ std::vector<Freezer::Entry> Freezer::GetEntries() const { return entries; } -void Freezer::FrameCallback(u64 userdata, s64 ns_late) { +void Freezer::FrameCallback(u64, std::chrono::nanoseconds ns_late) { if (!IsActive()) { LOG_DEBUG(Common_Memory, "Memory freezer has been deactivated, ending callback events."); return; @@ -173,7 +174,7 @@ void Freezer::FrameCallback(u64 userdata, s64 ns_late) { MemoryWriteWidth(memory, entry.width, entry.address, entry.value); } - core_timing.ScheduleEvent(MEMORY_FREEZER_TICKS - ns_late, event); + core_timing.ScheduleEvent(memory_freezer_ns - ns_late, event); } void Freezer::FillEntryReads() { diff --git a/src/core/tools/freezer.h b/src/core/tools/freezer.h index 62fc6aa6c..8438783d5 100644 --- a/src/core/tools/freezer.h +++ b/src/core/tools/freezer.h @@ -5,6 +5,7 @@ #pragma once #include <atomic> +#include <chrono> #include <memory> #include <mutex> #include <optional> @@ -72,7 +73,7 @@ public: std::vector<Entry> GetEntries() const; private: - void FrameCallback(u64 userdata, s64 cycles_late); + void FrameCallback(u64 userdata, std::chrono::nanoseconds ns_late); void FillEntryReads(); std::atomic_bool active{false}; diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp index 38210ffcb..02d06876f 100644 --- a/src/input_common/gcadapter/gc_adapter.cpp +++ b/src/input_common/gcadapter/gc_adapter.cpp @@ -24,11 +24,9 @@ Adapter::Adapter() { } LOG_INFO(Input, "GC Adapter Initialization started"); - current_status = NO_ADAPTER_DETECTED; - const int init_res = libusb_init(&libusb_ctx); if (init_res == LIBUSB_SUCCESS) { - StartScanThread(); + Setup(); } else { LOG_ERROR(Input, "libusb could not be initialized. failed with error = {}", init_res); } @@ -36,14 +34,9 @@ Adapter::Adapter() { GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload) { GCPadStatus pad = {}; - bool get_origin = false; - - ControllerTypes type = ControllerTypes(adapter_payload[1 + (9 * port)] >> 4); - if (type != ControllerTypes::None) { - get_origin = true; - } + const std::size_t offset = 1 + (9 * port); - adapter_controllers_status[port] = type; + adapter_controllers_status[port] = static_cast<ControllerTypes>(adapter_payload[offset] >> 4); static constexpr std::array<PadButton, 8> b1_buttons{ PadButton::PAD_BUTTON_A, PadButton::PAD_BUTTON_B, PadButton::PAD_BUTTON_X, @@ -58,9 +51,19 @@ GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& ad PadButton::PAD_TRIGGER_L, }; + static constexpr std::array<PadAxes, 6> axes{ + PadAxes::StickX, PadAxes::StickY, PadAxes::SubstickX, + PadAxes::SubstickY, PadAxes::TriggerLeft, PadAxes::TriggerRight, + }; + + if (adapter_controllers_status[port] == ControllerTypes::None && !get_origin[port]) { + // Controller may have been disconnected, recalibrate if reconnected. + get_origin[port] = true; + } + if (adapter_controllers_status[port] != ControllerTypes::None) { - const u8 b1 = adapter_payload[1 + (9 * port) + 1]; - const u8 b2 = adapter_payload[1 + (9 * port) + 2]; + const u8 b1 = adapter_payload[offset + 1]; + const u8 b2 = adapter_payload[offset + 2]; for (std::size_t i = 0; i < b1_buttons.size(); ++i) { if ((b1 & (1U << i)) != 0) { @@ -73,17 +76,15 @@ GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& ad pad.button |= static_cast<u16>(b2_buttons[j]); } } - - if (get_origin) { - pad.button |= PAD_GET_ORIGIN; + for (PadAxes axis : axes) { + const std::size_t index = static_cast<std::size_t>(axis); + pad.axis_values[index] = adapter_payload[offset + 3 + index]; } - pad.stick_x = adapter_payload[1 + (9 * port) + 3]; - pad.stick_y = adapter_payload[1 + (9 * port) + 4]; - pad.substick_x = adapter_payload[1 + (9 * port) + 5]; - pad.substick_y = adapter_payload[1 + (9 * port) + 6]; - pad.trigger_left = adapter_payload[1 + (9 * port) + 7]; - pad.trigger_right = adapter_payload[1 + (9 * port) + 8]; + if (get_origin[port]) { + origin_status[port].axis_values = pad.axis_values; + get_origin[port] = false; + } } return pad; } @@ -94,82 +95,47 @@ void Adapter::PadToState(const GCPadStatus& pad, GCState& state) { state.buttons.insert_or_assign(button_value, pad.button & button_value); } - state.axes.insert_or_assign(static_cast<u8>(PadAxes::StickX), pad.stick_x); - state.axes.insert_or_assign(static_cast<u8>(PadAxes::StickY), pad.stick_y); - state.axes.insert_or_assign(static_cast<u8>(PadAxes::SubstickX), pad.substick_x); - state.axes.insert_or_assign(static_cast<u8>(PadAxes::SubstickY), pad.substick_y); - state.axes.insert_or_assign(static_cast<u8>(PadAxes::TriggerLeft), pad.trigger_left); - state.axes.insert_or_assign(static_cast<u8>(PadAxes::TriggerRight), pad.trigger_right); + for (size_t i = 0; i < pad.axis_values.size(); ++i) { + state.axes.insert_or_assign(static_cast<u8>(i), pad.axis_values[i]); + } } void Adapter::Read() { LOG_DEBUG(Input, "GC Adapter Read() thread started"); - int payload_size_in, payload_size_copy; + int payload_size; std::array<u8, 37> adapter_payload; - std::array<u8, 37> adapter_payload_copy; std::array<GCPadStatus, 4> pads; while (adapter_thread_running) { libusb_interrupt_transfer(usb_adapter_handle, input_endpoint, adapter_payload.data(), - sizeof(adapter_payload), &payload_size_in, 16); - payload_size_copy = 0; - // this mutex might be redundant? - { - std::lock_guard<std::mutex> lk(s_mutex); - std::copy(std::begin(adapter_payload), std::end(adapter_payload), - std::begin(adapter_payload_copy)); - payload_size_copy = payload_size_in; - } + sizeof(adapter_payload), &payload_size, 16); - if (payload_size_copy != sizeof(adapter_payload_copy) || - adapter_payload_copy[0] != LIBUSB_DT_HID) { - LOG_ERROR(Input, "error reading payload (size: {}, type: {:02x})", payload_size_copy, - adapter_payload_copy[0]); + if (payload_size != sizeof(adapter_payload) || adapter_payload[0] != LIBUSB_DT_HID) { + LOG_ERROR(Input, + "Error reading payload (size: {}, type: {:02x}) Is the adapter connected?", + payload_size, adapter_payload[0]); adapter_thread_running = false; // error reading from adapter, stop reading. break; } for (std::size_t port = 0; port < pads.size(); ++port) { - pads[port] = GetPadStatus(port, adapter_payload_copy); + pads[port] = GetPadStatus(port, adapter_payload); if (DeviceConnected(port) && configuring) { - if (pads[port].button != PAD_GET_ORIGIN) { + if (pads[port].button != 0) { pad_queue[port].Push(pads[port]); } - // Accounting for a threshold here because of some controller variance - if (pads[port].stick_x > pads[port].MAIN_STICK_CENTER_X + pads[port].THRESHOLD || - pads[port].stick_x < pads[port].MAIN_STICK_CENTER_X - pads[port].THRESHOLD) { - pads[port].axis = GCAdapter::PadAxes::StickX; - pads[port].axis_value = pads[port].stick_x; - pad_queue[port].Push(pads[port]); - } - if (pads[port].stick_y > pads[port].MAIN_STICK_CENTER_Y + pads[port].THRESHOLD || - pads[port].stick_y < pads[port].MAIN_STICK_CENTER_Y - pads[port].THRESHOLD) { - pads[port].axis = GCAdapter::PadAxes::StickY; - pads[port].axis_value = pads[port].stick_y; - pad_queue[port].Push(pads[port]); - } - if (pads[port].substick_x > pads[port].C_STICK_CENTER_X + pads[port].THRESHOLD || - pads[port].substick_x < pads[port].C_STICK_CENTER_X - pads[port].THRESHOLD) { - pads[port].axis = GCAdapter::PadAxes::SubstickX; - pads[port].axis_value = pads[port].substick_x; - pad_queue[port].Push(pads[port]); - } - if (pads[port].substick_y > pads[port].C_STICK_CENTER_Y + pads[port].THRESHOLD || - pads[port].substick_y < pads[port].C_STICK_CENTER_Y - pads[port].THRESHOLD) { - pads[port].axis = GCAdapter::PadAxes::SubstickY; - pads[port].axis_value = pads[port].substick_y; - pad_queue[port].Push(pads[port]); - } - if (pads[port].trigger_left > pads[port].TRIGGER_THRESHOLD) { - pads[port].axis = GCAdapter::PadAxes::TriggerLeft; - pads[port].axis_value = pads[port].trigger_left; - pad_queue[port].Push(pads[port]); - } - if (pads[port].trigger_right > pads[port].TRIGGER_THRESHOLD) { - pads[port].axis = GCAdapter::PadAxes::TriggerRight; - pads[port].axis_value = pads[port].trigger_right; - pad_queue[port].Push(pads[port]); + // Accounting for a threshold here to ensure an intentional press + for (size_t i = 0; i < pads[port].axis_values.size(); ++i) { + const u8 value = pads[port].axis_values[i]; + const u8 origin = origin_status[port].axis_values[i]; + + if (value > origin + pads[port].THRESHOLD || + value < origin - pads[port].THRESHOLD) { + pads[port].axis = static_cast<PadAxes>(i); + pads[port].axis_value = pads[port].axis_values[i]; + pad_queue[port].Push(pads[port]); + } } } PadToState(pads[port], state[port]); @@ -178,42 +144,11 @@ void Adapter::Read() { } } -void Adapter::ScanThreadFunc() { - LOG_INFO(Input, "GC Adapter scanning thread started"); - - while (detect_thread_running) { - if (usb_adapter_handle == nullptr) { - std::lock_guard<std::mutex> lk(initialization_mutex); - Setup(); - } - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - } -} - -void Adapter::StartScanThread() { - if (detect_thread_running) { - return; - } - if (!libusb_ctx) { - return; - } - - detect_thread_running = true; - detect_thread = std::thread(&Adapter::ScanThreadFunc, this); -} - -void Adapter::StopScanThread() { - detect_thread_running = false; - detect_thread.join(); -} - void Adapter::Setup() { - // Reset the error status in case the adapter gets unplugged - if (current_status < 0) { - current_status = NO_ADAPTER_DETECTED; - } - + // Initialize all controllers as unplugged adapter_controllers_status.fill(ControllerTypes::None); + // Initialize all ports to store axis origin values + get_origin.fill(true); // pointer to list of connected usb devices libusb_device** devices{}; @@ -222,8 +157,6 @@ void Adapter::Setup() { const ssize_t device_count = libusb_get_device_list(libusb_ctx, &devices); if (device_count < 0) { LOG_ERROR(Input, "libusb_get_device_list failed with error: {}", device_count); - detect_thread_running = false; // Stop the loop constantly checking for gc adapter - // TODO: For hotplug+gc adapter checkbox implementation, revert this. return; } @@ -321,31 +254,21 @@ void Adapter::GetGCEndpoint(libusb_device* device) { sizeof(clear_payload), nullptr, 16); adapter_thread_running = true; - current_status = ADAPTER_DETECTED; adapter_input_thread = std::thread([=] { Read(); }); // Read input } Adapter::~Adapter() { - StopScanThread(); Reset(); } void Adapter::Reset() { - std::unique_lock<std::mutex> lock(initialization_mutex, std::defer_lock); - if (!lock.try_lock()) { - return; - } - if (current_status != ADAPTER_DETECTED) { - return; - } - if (adapter_thread_running) { adapter_thread_running = false; } adapter_input_thread.join(); adapter_controllers_status.fill(ControllerTypes::None); - current_status = NO_ADAPTER_DETECTED; + get_origin.fill(true); if (usb_adapter_handle) { libusb_release_interface(usb_adapter_handle, 1); @@ -367,6 +290,7 @@ void Adapter::ResetDeviceType(std::size_t port) { } void Adapter::BeginConfiguration() { + get_origin.fill(true); for (auto& pq : pad_queue) { pq.Clear(); } @@ -396,4 +320,8 @@ const std::array<GCState, 4>& Adapter::GetPadState() const { return state; } +int Adapter::GetOriginValue(int port, int axis) const { + return origin_status[port].axis_values[axis]; +} + } // namespace GCAdapter diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h index e2cdd6255..bed81915c 100644 --- a/src/input_common/gcadapter/gc_adapter.h +++ b/src/input_common/gcadapter/gc_adapter.h @@ -17,12 +17,6 @@ struct libusb_device_handle; namespace GCAdapter { -enum { - PAD_USE_ORIGIN = 0x0080, - PAD_GET_ORIGIN = 0x2000, - PAD_ERR_STATUS = 0x8000, -}; - enum class PadButton { PAD_BUTTON_LEFT = 0x0001, PAD_BUTTON_RIGHT = 0x0002, @@ -53,24 +47,10 @@ enum class PadAxes : u8 { }; struct GCPadStatus { - u16 button{}; // Or-ed PAD_BUTTON_* and PAD_TRIGGER_* bits - u8 stick_x{}; // 0 <= stick_x <= 255 - u8 stick_y{}; // 0 <= stick_y <= 255 - u8 substick_x{}; // 0 <= substick_x <= 255 - u8 substick_y{}; // 0 <= substick_y <= 255 - u8 trigger_left{}; // 0 <= trigger_left <= 255 - u8 trigger_right{}; // 0 <= trigger_right <= 255 - - static constexpr u8 MAIN_STICK_CENTER_X = 0x80; - static constexpr u8 MAIN_STICK_CENTER_Y = 0x80; - static constexpr u8 MAIN_STICK_RADIUS = 0x7f; - static constexpr u8 C_STICK_CENTER_X = 0x80; - static constexpr u8 C_STICK_CENTER_Y = 0x80; - static constexpr u8 C_STICK_RADIUS = 0x7f; - static constexpr u8 THRESHOLD = 10; - - // 256/4, at least a quarter press to count as a press. For polling mostly - static constexpr u8 TRIGGER_THRESHOLD = 64; + u16 button{}; // Or-ed PAD_BUTTON_* and PAD_TRIGGER_* bits + + std::array<u8, 6> axis_values{}; // Triggers and sticks, following indices defined in PadAxes + static constexpr u8 THRESHOLD = 50; // Threshold for axis press for polling u8 port{}; PadAxes axis{PadAxes::Undefined}; @@ -84,11 +64,6 @@ struct GCState { enum class ControllerTypes { None, Wired, Wireless }; -enum { - NO_ADAPTER_DETECTED = 0, - ADAPTER_DETECTED = 1, -}; - class Adapter { public: /// Initialize the GC Adapter capture and read sequence @@ -109,18 +84,14 @@ public: std::array<GCState, 4>& GetPadState(); const std::array<GCState, 4>& GetPadState() const; + int GetOriginValue(int port, int axis) const; + private: GCPadStatus GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload); void PadToState(const GCPadStatus& pad, GCState& state); void Read(); - void ScanThreadFunc(); - /// Begin scanning for the GC Adapter. - void StartScanThread(); - - /// Stop scanning for the adapter - void StopScanThread(); /// Resets status of device connected to port void ResetDeviceType(std::size_t port); @@ -137,19 +108,11 @@ private: /// For use in initialization, querying devices to find the adapter void Setup(); - int current_status = NO_ADAPTER_DETECTED; libusb_device_handle* usb_adapter_handle = nullptr; - std::array<ControllerTypes, 4> adapter_controllers_status{}; - - std::mutex s_mutex; std::thread adapter_input_thread; bool adapter_thread_running; - std::mutex initialization_mutex; - std::thread detect_thread; - bool detect_thread_running = false; - libusb_context* libusb_ctx; u8 input_endpoint = 0; @@ -157,8 +120,11 @@ private: bool configuring = false; - std::array<Common::SPSCQueue<GCPadStatus>, 4> pad_queue; std::array<GCState, 4> state; + std::array<bool, 4> get_origin; + std::array<GCPadStatus, 4> origin_status; + std::array<Common::SPSCQueue<GCPadStatus>, 4> pad_queue; + std::array<ControllerTypes, 4> adapter_controllers_status{}; }; } // namespace GCAdapter diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp index b20419ec3..96e22d3ad 100644 --- a/src/input_common/gcadapter/gc_poller.cpp +++ b/src/input_common/gcadapter/gc_poller.cpp @@ -38,18 +38,12 @@ public: explicit GCAxisButton(int port_, int axis_, float threshold_, bool trigger_if_greater_, GCAdapter::Adapter* adapter) : port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_), - gcadapter(adapter) { - // L/R triggers range is only in positive direction beginning near 0 - // 0.0 threshold equates to near half trigger press, but threshold accounts for variability. - if (axis > 3) { - threshold *= -0.5; - } - } + gcadapter(adapter), origin_value(adapter->GetOriginValue(port_, axis_)) {} bool GetStatus() const override { if (gcadapter->DeviceConnected(port)) { - const float axis_value = - (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 128.0f; + const float current_axis_value = gcadapter->GetPadState()[port].axes.at(axis); + const float axis_value = (current_axis_value - origin_value) / 128.0f; if (trigger_if_greater) { // TODO: Might be worthwile to set a slider for the trigger threshold. It is // currently always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick @@ -66,6 +60,7 @@ private: float threshold; bool trigger_if_greater; GCAdapter::Adapter* gcadapter; + const float origin_value; }; GCButtonFactory::GCButtonFactory(std::shared_ptr<GCAdapter::Adapter> adapter_) @@ -155,15 +150,18 @@ void GCButtonFactory::EndConfiguration() { class GCAnalog final : public Input::AnalogDevice { public: GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter) - : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter) {} + : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter), + origin_value_x(adapter->GetOriginValue(port_, axis_x_)), + origin_value_y(adapter->GetOriginValue(port_, axis_y_)) {} float GetAxis(int axis) const { if (gcadapter->DeviceConnected(port)) { std::lock_guard lock{mutex}; + const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y; // division is not by a perfect 128 to account for some variance in center location // e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range // [20-230] - return (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 95.0f; + return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / 95.0f; } return 0.0f; } @@ -215,8 +213,10 @@ private: const int axis_x; const int axis_y; const float deadzone; - mutable std::mutex mutex; GCAdapter::Adapter* gcadapter; + const float origin_value_x; + const float origin_value_y; + mutable std::mutex mutex; }; /// An analog device factory that creates analog devices from GC Adapter diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp index e66db1940..244463a47 100644 --- a/src/tests/core/core_timing.cpp +++ b/src/tests/core/core_timing.cpp @@ -6,6 +6,7 @@ #include <array> #include <bitset> +#include <chrono> #include <cstdlib> #include <memory> #include <string> @@ -17,7 +18,6 @@ namespace { // Numbers are chosen randomly to make sure the correct one is given. constexpr std::array<u64, 5> CB_IDS{{42, 144, 93, 1026, UINT64_C(0xFFFF7FFFF7FFFF)}}; -constexpr int MAX_SLICE_LENGTH = 10000; // Copied from CoreTiming internals constexpr std::array<u64, 5> calls_order{{2, 0, 1, 4, 3}}; std::array<s64, 5> delays{}; @@ -25,12 +25,12 @@ std::bitset<CB_IDS.size()> callbacks_ran_flags; u64 expected_callback = 0; template <unsigned int IDX> -void HostCallbackTemplate(u64 userdata, s64 nanoseconds_late) { +void HostCallbackTemplate(u64 userdata, std::chrono::nanoseconds ns_late) { static_assert(IDX < CB_IDS.size(), "IDX out of range"); callbacks_ran_flags.set(IDX); REQUIRE(CB_IDS[IDX] == userdata); REQUIRE(CB_IDS[IDX] == CB_IDS[calls_order[expected_callback]]); - delays[IDX] = nanoseconds_late; + delays[IDX] = ns_late.count(); ++expected_callback; } @@ -77,10 +77,12 @@ TEST_CASE("CoreTiming[BasicOrder]", "[core]") { core_timing.SyncPause(true); - u64 one_micro = 1000U; + const u64 one_micro = 1000U; for (std::size_t i = 0; i < events.size(); i++) { - u64 order = calls_order[i]; - core_timing.ScheduleEvent(i * one_micro + 100U, events[order], CB_IDS[order]); + const u64 order = calls_order[i]; + const auto future_ns = std::chrono::nanoseconds{static_cast<s64>(i * one_micro + 100)}; + + core_timing.ScheduleEvent(future_ns, events[order], CB_IDS[order]); } /// test pause REQUIRE(callbacks_ran_flags.none()); @@ -116,13 +118,16 @@ TEST_CASE("CoreTiming[BasicOrderNoPausing]", "[core]") { expected_callback = 0; - u64 start = core_timing.GetGlobalTimeNs().count(); - u64 one_micro = 1000U; + const u64 start = core_timing.GetGlobalTimeNs().count(); + const u64 one_micro = 1000U; + for (std::size_t i = 0; i < events.size(); i++) { - u64 order = calls_order[i]; - core_timing.ScheduleEvent(i * one_micro + 100U, events[order], CB_IDS[order]); + const u64 order = calls_order[i]; + const auto future_ns = std::chrono::nanoseconds{static_cast<s64>(i * one_micro + 100)}; + core_timing.ScheduleEvent(future_ns, events[order], CB_IDS[order]); } - u64 end = core_timing.GetGlobalTimeNs().count(); + + const u64 end = core_timing.GetGlobalTimeNs().count(); const double scheduling_time = static_cast<double>(end - start); const double timer_time = static_cast<double>(TestTimerSpeed(core_timing)); diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 21c46a567..3cd896a0f 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -98,6 +98,8 @@ add_library(video_core STATIC sampler_cache.cpp sampler_cache.h shader_cache.h + shader_notify.cpp + shader_notify.h shader/decode/arithmetic.cpp shader/decode/arithmetic_immediate.cpp shader/decode/bfe.cpp @@ -128,6 +130,8 @@ add_library(video_core STATIC shader/decode/other.cpp shader/ast.cpp shader/ast.h + shader/async_shaders.cpp + shader/async_shaders.h shader/compiler_settings.cpp shader/compiler_settings.h shader/control_flow.cpp diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index dd7ce8c99..b5dc68902 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -524,11 +524,8 @@ private: void MarkRegionAsWritten(VAddr start, VAddr end) { const u64 page_end = end >> WRITE_PAGE_BIT; for (u64 page_start = start >> WRITE_PAGE_BIT; page_start <= page_end; ++page_start) { - auto it = written_pages.find(page_start); - if (it != written_pages.end()) { - it->second = it->second + 1; - } else { - written_pages.insert_or_assign(page_start, 1); + if (const auto [it, inserted] = written_pages.emplace(page_start, 1); !inserted) { + ++it->second; } } } @@ -539,7 +536,7 @@ private: auto it = written_pages.find(page_start); if (it != written_pages.end()) { if (it->second > 1) { - it->second = it->second - 1; + --it->second; } else { written_pages.erase(it); } diff --git a/src/video_core/compatible_formats.cpp b/src/video_core/compatible_formats.cpp index 6c426b035..b06c32c84 100644 --- a/src/video_core/compatible_formats.cpp +++ b/src/video_core/compatible_formats.cpp @@ -17,101 +17,94 @@ namespace { // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_view.txt constexpr std::array VIEW_CLASS_128_BITS = { - PixelFormat::RGBA32F, - PixelFormat::RGBA32UI, + PixelFormat::R32G32B32A32_FLOAT, + PixelFormat::R32G32B32A32_UINT, + PixelFormat::R32G32B32A32_SINT, }; -// Missing formats: -// PixelFormat::RGBA32I constexpr std::array VIEW_CLASS_96_BITS = { - PixelFormat::RGB32F, + PixelFormat::R32G32B32_FLOAT, }; // Missing formats: // PixelFormat::RGB32UI, // PixelFormat::RGB32I, constexpr std::array VIEW_CLASS_64_BITS = { - PixelFormat::RGBA16F, PixelFormat::RG32F, PixelFormat::RGBA16UI, PixelFormat::RG32UI, - PixelFormat::RGBA16U, PixelFormat::RGBA16F, PixelFormat::RGBA16S, + PixelFormat::R32G32_FLOAT, PixelFormat::R32G32_UINT, + PixelFormat::R32G32_SINT, PixelFormat::R16G16B16A16_FLOAT, + PixelFormat::R16G16B16A16_UNORM, PixelFormat::R16G16B16A16_SNORM, + PixelFormat::R16G16B16A16_UINT, PixelFormat::R16G16B16A16_SINT, }; -// Missing formats: -// PixelFormat::RGBA16I -// PixelFormat::RG32I // TODO: How should we handle 48 bits? constexpr std::array VIEW_CLASS_32_BITS = { - PixelFormat::RG16F, PixelFormat::R11FG11FB10F, PixelFormat::R32F, - PixelFormat::A2B10G10R10U, PixelFormat::RG16UI, PixelFormat::R32UI, - PixelFormat::RG16I, PixelFormat::R32I, PixelFormat::ABGR8U, - PixelFormat::RG16, PixelFormat::ABGR8S, PixelFormat::RG16S, - PixelFormat::RGBA8_SRGB, PixelFormat::E5B9G9R9F, PixelFormat::BGRA8, - PixelFormat::BGRA8_SRGB, + PixelFormat::R16G16_FLOAT, PixelFormat::B10G11R11_FLOAT, PixelFormat::R32_FLOAT, + PixelFormat::A2B10G10R10_UNORM, PixelFormat::R16G16_UINT, PixelFormat::R32_UINT, + PixelFormat::R16G16_SINT, PixelFormat::R32_SINT, PixelFormat::A8B8G8R8_UNORM, + PixelFormat::R16G16_UNORM, PixelFormat::A8B8G8R8_SNORM, PixelFormat::R16G16_SNORM, + PixelFormat::A8B8G8R8_SRGB, PixelFormat::E5B9G9R9_FLOAT, PixelFormat::B8G8R8A8_UNORM, + PixelFormat::B8G8R8A8_SRGB, PixelFormat::A8B8G8R8_UINT, PixelFormat::A8B8G8R8_SINT, + PixelFormat::A2B10G10R10_UINT, }; -// Missing formats: -// PixelFormat::RGBA8UI -// PixelFormat::RGBA8I -// PixelFormat::RGB10_A2_UI // TODO: How should we handle 24 bits? constexpr std::array VIEW_CLASS_16_BITS = { - PixelFormat::R16F, PixelFormat::RG8UI, PixelFormat::R16UI, PixelFormat::R16I, - PixelFormat::RG8U, PixelFormat::R16U, PixelFormat::RG8S, PixelFormat::R16S, + PixelFormat::R16_FLOAT, PixelFormat::R8G8_UINT, PixelFormat::R16_UINT, + PixelFormat::R16_SINT, PixelFormat::R8G8_UNORM, PixelFormat::R16_UNORM, + PixelFormat::R8G8_SNORM, PixelFormat::R16_SNORM, PixelFormat::R8G8_SINT, }; -// Missing formats: -// PixelFormat::RG8I constexpr std::array VIEW_CLASS_8_BITS = { - PixelFormat::R8UI, - PixelFormat::R8U, + PixelFormat::R8_UINT, + PixelFormat::R8_UNORM, + PixelFormat::R8_SINT, + PixelFormat::R8_SNORM, }; -// Missing formats: -// PixelFormat::R8I -// PixelFormat::R8S constexpr std::array VIEW_CLASS_RGTC1_RED = { - PixelFormat::DXN1, + PixelFormat::BC4_UNORM, + PixelFormat::BC4_SNORM, }; -// Missing formats: -// COMPRESSED_SIGNED_RED_RGTC1 constexpr std::array VIEW_CLASS_RGTC2_RG = { - PixelFormat::DXN2UNORM, - PixelFormat::DXN2SNORM, + PixelFormat::BC5_UNORM, + PixelFormat::BC5_SNORM, }; constexpr std::array VIEW_CLASS_BPTC_UNORM = { - PixelFormat::BC7U, - PixelFormat::BC7U_SRGB, + PixelFormat::BC7_UNORM, + PixelFormat::BC7_SRGB, }; constexpr std::array VIEW_CLASS_BPTC_FLOAT = { - PixelFormat::BC6H_SF16, - PixelFormat::BC6H_UF16, + PixelFormat::BC6H_SFLOAT, + PixelFormat::BC6H_UFLOAT, }; // Compatibility table taken from Table 4.X.1 in: // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_copy_image.txt constexpr std::array COPY_CLASS_128_BITS = { - PixelFormat::RGBA32UI, PixelFormat::RGBA32F, PixelFormat::DXT23, - PixelFormat::DXT23_SRGB, PixelFormat::DXT45, PixelFormat::DXT45_SRGB, - PixelFormat::DXN2SNORM, PixelFormat::BC7U, PixelFormat::BC7U_SRGB, - PixelFormat::BC6H_SF16, PixelFormat::BC6H_UF16, + PixelFormat::R32G32B32A32_UINT, PixelFormat::R32G32B32A32_FLOAT, PixelFormat::R32G32B32A32_SINT, + PixelFormat::BC2_UNORM, PixelFormat::BC2_SRGB, PixelFormat::BC3_UNORM, + PixelFormat::BC3_SRGB, PixelFormat::BC5_UNORM, PixelFormat::BC5_SNORM, + PixelFormat::BC7_UNORM, PixelFormat::BC7_SRGB, PixelFormat::BC6H_SFLOAT, + PixelFormat::BC6H_UFLOAT, }; // Missing formats: // PixelFormat::RGBA32I // COMPRESSED_RG_RGTC2 constexpr std::array COPY_CLASS_64_BITS = { - PixelFormat::RGBA16F, PixelFormat::RG32F, PixelFormat::RGBA16UI, PixelFormat::RG32UI, - PixelFormat::RGBA16U, PixelFormat::RGBA16S, PixelFormat::DXT1_SRGB, PixelFormat::DXT1, - + PixelFormat::R16G16B16A16_FLOAT, PixelFormat::R16G16B16A16_UINT, + PixelFormat::R16G16B16A16_UNORM, PixelFormat::R16G16B16A16_SNORM, + PixelFormat::R16G16B16A16_SINT, PixelFormat::R32G32_UINT, + PixelFormat::R32G32_FLOAT, PixelFormat::R32G32_SINT, + PixelFormat::BC1_RGBA_UNORM, PixelFormat::BC1_RGBA_SRGB, }; // Missing formats: -// PixelFormat::RGBA16I -// PixelFormat::RG32I, // COMPRESSED_RGB_S3TC_DXT1_EXT // COMPRESSED_SRGB_S3TC_DXT1_EXT // COMPRESSED_RGBA_S3TC_DXT1_EXT diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 758bfe148..8e19c3373 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -20,6 +20,7 @@ #include "video_core/gpu.h" #include "video_core/memory_manager.h" #include "video_core/renderer_base.h" +#include "video_core/shader_notify.h" #include "video_core/video_core.h" namespace Tegra { @@ -36,6 +37,7 @@ GPU::GPU(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& render kepler_compute = std::make_unique<Engines::KeplerCompute>(system, rasterizer, *memory_manager); maxwell_dma = std::make_unique<Engines::MaxwellDMA>(system, *memory_manager); kepler_memory = std::make_unique<Engines::KeplerMemory>(system, *memory_manager); + shader_notify = std::make_unique<VideoCore::ShaderNotify>(); } GPU::~GPU() = default; diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 2c42483bd..19a34c402 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -33,59 +33,68 @@ class System; namespace VideoCore { class RendererBase; +class ShaderNotify; } // namespace VideoCore namespace Tegra { enum class RenderTargetFormat : u32 { NONE = 0x0, - RGBA32_FLOAT = 0xC0, - RGBA32_UINT = 0xC2, - RGBA16_UNORM = 0xC6, - RGBA16_SNORM = 0xC7, - RGBA16_UINT = 0xC9, - RGBA16_FLOAT = 0xCA, - RG32_FLOAT = 0xCB, - RG32_UINT = 0xCD, - RGBX16_FLOAT = 0xCE, - BGRA8_UNORM = 0xCF, - BGRA8_SRGB = 0xD0, - RGB10_A2_UNORM = 0xD1, - RGBA8_UNORM = 0xD5, - RGBA8_SRGB = 0xD6, - RGBA8_SNORM = 0xD7, - RGBA8_UINT = 0xD9, - RG16_UNORM = 0xDA, - RG16_SNORM = 0xDB, - RG16_SINT = 0xDC, - RG16_UINT = 0xDD, - RG16_FLOAT = 0xDE, - R11G11B10_FLOAT = 0xE0, + R32B32G32A32_FLOAT = 0xC0, + R32G32B32A32_SINT = 0xC1, + R32G32B32A32_UINT = 0xC2, + R16G16B16A16_UNORM = 0xC6, + R16G16B16A16_SNORM = 0xC7, + R16G16B16A16_SINT = 0xC8, + R16G16B16A16_UINT = 0xC9, + R16G16B16A16_FLOAT = 0xCA, + R32G32_FLOAT = 0xCB, + R32G32_SINT = 0xCC, + R32G32_UINT = 0xCD, + R16G16B16X16_FLOAT = 0xCE, + B8G8R8A8_UNORM = 0xCF, + B8G8R8A8_SRGB = 0xD0, + A2B10G10R10_UNORM = 0xD1, + A2B10G10R10_UINT = 0xD2, + A8B8G8R8_UNORM = 0xD5, + A8B8G8R8_SRGB = 0xD6, + A8B8G8R8_SNORM = 0xD7, + A8B8G8R8_SINT = 0xD8, + A8B8G8R8_UINT = 0xD9, + R16G16_UNORM = 0xDA, + R16G16_SNORM = 0xDB, + R16G16_SINT = 0xDC, + R16G16_UINT = 0xDD, + R16G16_FLOAT = 0xDE, + B10G11R11_FLOAT = 0xE0, R32_SINT = 0xE3, R32_UINT = 0xE4, R32_FLOAT = 0xE5, - B5G6R5_UNORM = 0xE8, - BGR5A1_UNORM = 0xE9, - RG8_UNORM = 0xEA, - RG8_SNORM = 0xEB, - RG8_UINT = 0xED, + R5G6B5_UNORM = 0xE8, + A1R5G5B5_UNORM = 0xE9, + R8G8_UNORM = 0xEA, + R8G8_SNORM = 0xEB, + R8G8_SINT = 0xEC, + R8G8_UINT = 0xED, R16_UNORM = 0xEE, R16_SNORM = 0xEF, R16_SINT = 0xF0, R16_UINT = 0xF1, R16_FLOAT = 0xF2, R8_UNORM = 0xF3, + R8_SNORM = 0xF4, + R8_SINT = 0xF5, R8_UINT = 0xF6, }; enum class DepthFormat : u32 { - Z32_FLOAT = 0xA, - Z16_UNORM = 0x13, - S8_Z24_UNORM = 0x14, - Z24_X8_UNORM = 0x15, - Z24_S8_UNORM = 0x16, - Z24_C8_UNORM = 0x18, - Z32_S8_X24_FLOAT = 0x19, + D32_FLOAT = 0xA, + D16_UNORM = 0x13, + S8_UINT_Z24_UNORM = 0x14, + D24X8_UNORM = 0x15, + D24S8_UNORM = 0x16, + D24C8_UNORM = 0x18, + D32_FLOAT_S8X24_UINT = 0x19, }; struct CommandListHeader; @@ -96,9 +105,9 @@ class DebugContext; */ struct FramebufferConfig { enum class PixelFormat : u32 { - ABGR8 = 1, - RGB565 = 4, - BGRA8 = 5, + A8B8G8R8_UNORM = 1, + RGB565_UNORM = 4, + B8G8R8A8_UNORM = 5, }; VAddr address; @@ -207,6 +216,14 @@ public: return *renderer; } + VideoCore::ShaderNotify& ShaderNotify() { + return *shader_notify; + } + + const VideoCore::ShaderNotify& ShaderNotify() const { + return *shader_notify; + } + // Waits for the GPU to finish working virtual void WaitIdle() const = 0; @@ -347,6 +364,8 @@ private: std::unique_ptr<Engines::MaxwellDMA> maxwell_dma; /// Inline memory engine std::unique_ptr<Engines::KeplerMemory> kepler_memory; + /// Shader build notifier + std::unique_ptr<VideoCore::ShaderNotify> shader_notify; std::array<std::atomic<u32>, Service::Nvidia::MaxSyncPoints> syncpoints{}; diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index 738c6f0c1..bf761abf2 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.cpp @@ -44,9 +44,9 @@ static void RunThread(Core::System& system, VideoCore::RendererBase& renderer, dma_pusher.DispatchCalls(); } else if (const auto data = std::get_if<SwapBuffersCommand>(&next.data)) { renderer.SwapBuffers(data->framebuffer ? &*data->framebuffer : nullptr); - } else if (const auto data = std::get_if<OnCommandListEndCommand>(&next.data)) { + } else if (std::holds_alternative<OnCommandListEndCommand>(next.data)) { renderer.Rasterizer().ReleaseFences(); - } else if (const auto data = std::get_if<GPUTickCommand>(&next.data)) { + } else if (std::holds_alternative<GPUTickCommand>(next.data)) { system.GPU().TickWork(); } else if (const auto data = std::get_if<FlushRegionCommand>(&next.data)) { renderer.Rasterizer().FlushRegion(data->addr, data->size); diff --git a/src/video_core/macro/macro.h b/src/video_core/macro/macro.h index 4d00b84b0..31ee3440a 100644 --- a/src/video_core/macro/macro.h +++ b/src/video_core/macro/macro.h @@ -103,8 +103,9 @@ public: virtual ~CachedMacro() = default; /** * Executes the macro code with the specified input parameters. - * @param code The macro byte code to execute + * * @param parameters The parameters of the macro + * @param method The method to execute */ virtual void Execute(const std::vector<u32>& parameters, u32 method) = 0; }; diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp index 410f99018..0c9ff59a4 100644 --- a/src/video_core/macro/macro_hle.cpp +++ b/src/video_core/macro/macro_hle.cpp @@ -12,13 +12,11 @@ namespace Tegra { namespace { // HLE'd functions -static void HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d, - const std::vector<u32>& parameters) { +void HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { const u32 instance_count = parameters[2] & maxwell3d.GetRegisterValue(0xD1B); maxwell3d.regs.draw.topology.Assign( - static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & - ~(0x3ffffff << 26))); + static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0x3ffffff)); maxwell3d.regs.vb_base_instance = parameters[5]; maxwell3d.mme_draw.instance_count = instance_count; maxwell3d.regs.vb_element_base = parameters[3]; @@ -33,8 +31,7 @@ static void HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d, maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined; } -static void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d, - const std::vector<u32>& parameters) { +void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { const u32 count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); maxwell3d.regs.vertex_buffer.first = parameters[3]; @@ -52,8 +49,7 @@ static void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d, maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined; } -static void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, - const std::vector<u32>& parameters) { +void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); const u32 element_base = parameters[4]; const u32 base_instance = parameters[5]; @@ -81,12 +77,12 @@ static void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, maxwell3d.CallMethodFromMME(0x8e5, 0x0); maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined; } -} // namespace +} // Anonymous namespace constexpr std::array<std::pair<u64, HLEFunction>, 3> hle_funcs{{ - std::make_pair<u64, HLEFunction>(0x771BB18C62444DA0, &HLE_771BB18C62444DA0), - std::make_pair<u64, HLEFunction>(0x0D61FC9FAAC9FCAD, &HLE_0D61FC9FAAC9FCAD), - std::make_pair<u64, HLEFunction>(0x0217920100488FF7, &HLE_0217920100488FF7), + {0x771BB18C62444DA0, &HLE_771BB18C62444DA0}, + {0x0D61FC9FAAC9FCAD, &HLE_0D61FC9FAAC9FCAD}, + {0x0217920100488FF7, &HLE_0217920100488FF7}, }}; HLEMacro::HLEMacro(Engines::Maxwell3D& maxwell3d) : maxwell3d(maxwell3d) {} diff --git a/src/video_core/macro/macro_jit_x64.cpp b/src/video_core/macro/macro_jit_x64.cpp index 07292702f..c1b9e4ad9 100644 --- a/src/video_core/macro/macro_jit_x64.cpp +++ b/src/video_core/macro/macro_jit_x64.cpp @@ -419,7 +419,6 @@ void Tegra::MacroJITx64Impl::Optimizer_ScanFlags() { void MacroJITx64Impl::Compile() { MICROPROFILE_SCOPE(MacroJitCompile); - bool keep_executing = true; labels.fill(Xbyak::Label()); Common::X64::ABI_PushRegistersAndAdjustStack(*this, Common::X64::ABI_ALL_CALLEE_SAVED, 8); diff --git a/src/video_core/morton.cpp b/src/video_core/morton.cpp index 836b25c1d..9da9fb4ff 100644 --- a/src/video_core/morton.cpp +++ b/src/video_core/morton.cpp @@ -41,146 +41,168 @@ static void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth } static constexpr ConversionArray morton_to_linear_fns = { - MortonCopy<true, PixelFormat::ABGR8U>, - MortonCopy<true, PixelFormat::ABGR8S>, - MortonCopy<true, PixelFormat::ABGR8UI>, - MortonCopy<true, PixelFormat::B5G6R5U>, - MortonCopy<true, PixelFormat::A2B10G10R10U>, - MortonCopy<true, PixelFormat::A1B5G5R5U>, - MortonCopy<true, PixelFormat::R8U>, - MortonCopy<true, PixelFormat::R8UI>, - MortonCopy<true, PixelFormat::RGBA16F>, - MortonCopy<true, PixelFormat::RGBA16U>, - MortonCopy<true, PixelFormat::RGBA16S>, - MortonCopy<true, PixelFormat::RGBA16UI>, - MortonCopy<true, PixelFormat::R11FG11FB10F>, - MortonCopy<true, PixelFormat::RGBA32UI>, - MortonCopy<true, PixelFormat::DXT1>, - MortonCopy<true, PixelFormat::DXT23>, - MortonCopy<true, PixelFormat::DXT45>, - MortonCopy<true, PixelFormat::DXN1>, - MortonCopy<true, PixelFormat::DXN2UNORM>, - MortonCopy<true, PixelFormat::DXN2SNORM>, - MortonCopy<true, PixelFormat::BC7U>, - MortonCopy<true, PixelFormat::BC6H_UF16>, - MortonCopy<true, PixelFormat::BC6H_SF16>, - MortonCopy<true, PixelFormat::ASTC_2D_4X4>, - MortonCopy<true, PixelFormat::BGRA8>, - MortonCopy<true, PixelFormat::RGBA32F>, - MortonCopy<true, PixelFormat::RG32F>, - MortonCopy<true, PixelFormat::R32F>, - MortonCopy<true, PixelFormat::R16F>, - MortonCopy<true, PixelFormat::R16U>, - MortonCopy<true, PixelFormat::R16S>, - MortonCopy<true, PixelFormat::R16UI>, - MortonCopy<true, PixelFormat::R16I>, - MortonCopy<true, PixelFormat::RG16>, - MortonCopy<true, PixelFormat::RG16F>, - MortonCopy<true, PixelFormat::RG16UI>, - MortonCopy<true, PixelFormat::RG16I>, - MortonCopy<true, PixelFormat::RG16S>, - MortonCopy<true, PixelFormat::RGB32F>, - MortonCopy<true, PixelFormat::RGBA8_SRGB>, - MortonCopy<true, PixelFormat::RG8U>, - MortonCopy<true, PixelFormat::RG8S>, - MortonCopy<true, PixelFormat::RG8UI>, - MortonCopy<true, PixelFormat::RG32UI>, - MortonCopy<true, PixelFormat::RGBX16F>, - MortonCopy<true, PixelFormat::R32UI>, - MortonCopy<true, PixelFormat::R32I>, - MortonCopy<true, PixelFormat::ASTC_2D_8X8>, - MortonCopy<true, PixelFormat::ASTC_2D_8X5>, - MortonCopy<true, PixelFormat::ASTC_2D_5X4>, - MortonCopy<true, PixelFormat::BGRA8_SRGB>, - MortonCopy<true, PixelFormat::DXT1_SRGB>, - MortonCopy<true, PixelFormat::DXT23_SRGB>, - MortonCopy<true, PixelFormat::DXT45_SRGB>, - MortonCopy<true, PixelFormat::BC7U_SRGB>, - MortonCopy<true, PixelFormat::R4G4B4A4U>, + MortonCopy<true, PixelFormat::A8B8G8R8_UNORM>, + MortonCopy<true, PixelFormat::A8B8G8R8_SNORM>, + MortonCopy<true, PixelFormat::A8B8G8R8_SINT>, + MortonCopy<true, PixelFormat::A8B8G8R8_UINT>, + MortonCopy<true, PixelFormat::R5G6B5_UNORM>, + MortonCopy<true, PixelFormat::B5G6R5_UNORM>, + MortonCopy<true, PixelFormat::A1R5G5B5_UNORM>, + MortonCopy<true, PixelFormat::A2B10G10R10_UNORM>, + MortonCopy<true, PixelFormat::A2B10G10R10_UINT>, + MortonCopy<true, PixelFormat::A1B5G5R5_UNORM>, + MortonCopy<true, PixelFormat::R8_UNORM>, + MortonCopy<true, PixelFormat::R8_SNORM>, + MortonCopy<true, PixelFormat::R8_SINT>, + MortonCopy<true, PixelFormat::R8_UINT>, + MortonCopy<true, PixelFormat::R16G16B16A16_FLOAT>, + MortonCopy<true, PixelFormat::R16G16B16A16_UNORM>, + MortonCopy<true, PixelFormat::R16G16B16A16_SNORM>, + MortonCopy<true, PixelFormat::R16G16B16A16_SINT>, + MortonCopy<true, PixelFormat::R16G16B16A16_UINT>, + MortonCopy<true, PixelFormat::B10G11R11_FLOAT>, + MortonCopy<true, PixelFormat::R32G32B32A32_UINT>, + MortonCopy<true, PixelFormat::BC1_RGBA_UNORM>, + MortonCopy<true, PixelFormat::BC2_UNORM>, + MortonCopy<true, PixelFormat::BC3_UNORM>, + MortonCopy<true, PixelFormat::BC4_UNORM>, + MortonCopy<true, PixelFormat::BC4_SNORM>, + MortonCopy<true, PixelFormat::BC5_UNORM>, + MortonCopy<true, PixelFormat::BC5_SNORM>, + MortonCopy<true, PixelFormat::BC7_UNORM>, + MortonCopy<true, PixelFormat::BC6H_UFLOAT>, + MortonCopy<true, PixelFormat::BC6H_SFLOAT>, + MortonCopy<true, PixelFormat::ASTC_2D_4X4_UNORM>, + MortonCopy<true, PixelFormat::B8G8R8A8_UNORM>, + MortonCopy<true, PixelFormat::R32G32B32A32_FLOAT>, + MortonCopy<true, PixelFormat::R32G32B32A32_SINT>, + MortonCopy<true, PixelFormat::R32G32_FLOAT>, + MortonCopy<true, PixelFormat::R32G32_SINT>, + MortonCopy<true, PixelFormat::R32_FLOAT>, + MortonCopy<true, PixelFormat::R16_FLOAT>, + MortonCopy<true, PixelFormat::R16_UNORM>, + MortonCopy<true, PixelFormat::R16_SNORM>, + MortonCopy<true, PixelFormat::R16_UINT>, + MortonCopy<true, PixelFormat::R16_SINT>, + MortonCopy<true, PixelFormat::R16G16_UNORM>, + MortonCopy<true, PixelFormat::R16G16_FLOAT>, + MortonCopy<true, PixelFormat::R16G16_UINT>, + MortonCopy<true, PixelFormat::R16G16_SINT>, + MortonCopy<true, PixelFormat::R16G16_SNORM>, + MortonCopy<true, PixelFormat::R32G32B32_FLOAT>, + MortonCopy<true, PixelFormat::A8B8G8R8_SRGB>, + MortonCopy<true, PixelFormat::R8G8_UNORM>, + MortonCopy<true, PixelFormat::R8G8_SNORM>, + MortonCopy<true, PixelFormat::R8G8_SINT>, + MortonCopy<true, PixelFormat::R8G8_UINT>, + MortonCopy<true, PixelFormat::R32G32_UINT>, + MortonCopy<true, PixelFormat::R16G16B16X16_FLOAT>, + MortonCopy<true, PixelFormat::R32_UINT>, + MortonCopy<true, PixelFormat::R32_SINT>, + MortonCopy<true, PixelFormat::ASTC_2D_8X8_UNORM>, + MortonCopy<true, PixelFormat::ASTC_2D_8X5_UNORM>, + MortonCopy<true, PixelFormat::ASTC_2D_5X4_UNORM>, + MortonCopy<true, PixelFormat::B8G8R8A8_SRGB>, + MortonCopy<true, PixelFormat::BC1_RGBA_SRGB>, + MortonCopy<true, PixelFormat::BC2_SRGB>, + MortonCopy<true, PixelFormat::BC3_SRGB>, + MortonCopy<true, PixelFormat::BC7_SRGB>, + MortonCopy<true, PixelFormat::A4B4G4R4_UNORM>, MortonCopy<true, PixelFormat::ASTC_2D_4X4_SRGB>, MortonCopy<true, PixelFormat::ASTC_2D_8X8_SRGB>, MortonCopy<true, PixelFormat::ASTC_2D_8X5_SRGB>, MortonCopy<true, PixelFormat::ASTC_2D_5X4_SRGB>, - MortonCopy<true, PixelFormat::ASTC_2D_5X5>, + MortonCopy<true, PixelFormat::ASTC_2D_5X5_UNORM>, MortonCopy<true, PixelFormat::ASTC_2D_5X5_SRGB>, - MortonCopy<true, PixelFormat::ASTC_2D_10X8>, + MortonCopy<true, PixelFormat::ASTC_2D_10X8_UNORM>, MortonCopy<true, PixelFormat::ASTC_2D_10X8_SRGB>, - MortonCopy<true, PixelFormat::ASTC_2D_6X6>, + MortonCopy<true, PixelFormat::ASTC_2D_6X6_UNORM>, MortonCopy<true, PixelFormat::ASTC_2D_6X6_SRGB>, - MortonCopy<true, PixelFormat::ASTC_2D_10X10>, + MortonCopy<true, PixelFormat::ASTC_2D_10X10_UNORM>, MortonCopy<true, PixelFormat::ASTC_2D_10X10_SRGB>, - MortonCopy<true, PixelFormat::ASTC_2D_12X12>, + MortonCopy<true, PixelFormat::ASTC_2D_12X12_UNORM>, MortonCopy<true, PixelFormat::ASTC_2D_12X12_SRGB>, - MortonCopy<true, PixelFormat::ASTC_2D_8X6>, + MortonCopy<true, PixelFormat::ASTC_2D_8X6_UNORM>, MortonCopy<true, PixelFormat::ASTC_2D_8X6_SRGB>, - MortonCopy<true, PixelFormat::ASTC_2D_6X5>, + MortonCopy<true, PixelFormat::ASTC_2D_6X5_UNORM>, MortonCopy<true, PixelFormat::ASTC_2D_6X5_SRGB>, - MortonCopy<true, PixelFormat::E5B9G9R9F>, - MortonCopy<true, PixelFormat::Z32F>, - MortonCopy<true, PixelFormat::Z16>, - MortonCopy<true, PixelFormat::Z24S8>, - MortonCopy<true, PixelFormat::S8Z24>, - MortonCopy<true, PixelFormat::Z32FS8>, + MortonCopy<true, PixelFormat::E5B9G9R9_FLOAT>, + MortonCopy<true, PixelFormat::D32_FLOAT>, + MortonCopy<true, PixelFormat::D16_UNORM>, + MortonCopy<true, PixelFormat::D24_UNORM_S8_UINT>, + MortonCopy<true, PixelFormat::S8_UINT_D24_UNORM>, + MortonCopy<true, PixelFormat::D32_FLOAT_S8_UINT>, }; static constexpr ConversionArray linear_to_morton_fns = { - MortonCopy<false, PixelFormat::ABGR8U>, - MortonCopy<false, PixelFormat::ABGR8S>, - MortonCopy<false, PixelFormat::ABGR8UI>, - MortonCopy<false, PixelFormat::B5G6R5U>, - MortonCopy<false, PixelFormat::A2B10G10R10U>, - MortonCopy<false, PixelFormat::A1B5G5R5U>, - MortonCopy<false, PixelFormat::R8U>, - MortonCopy<false, PixelFormat::R8UI>, - MortonCopy<false, PixelFormat::RGBA16F>, - MortonCopy<false, PixelFormat::RGBA16S>, - MortonCopy<false, PixelFormat::RGBA16U>, - MortonCopy<false, PixelFormat::RGBA16UI>, - MortonCopy<false, PixelFormat::R11FG11FB10F>, - MortonCopy<false, PixelFormat::RGBA32UI>, - MortonCopy<false, PixelFormat::DXT1>, - MortonCopy<false, PixelFormat::DXT23>, - MortonCopy<false, PixelFormat::DXT45>, - MortonCopy<false, PixelFormat::DXN1>, - MortonCopy<false, PixelFormat::DXN2UNORM>, - MortonCopy<false, PixelFormat::DXN2SNORM>, - MortonCopy<false, PixelFormat::BC7U>, - MortonCopy<false, PixelFormat::BC6H_UF16>, - MortonCopy<false, PixelFormat::BC6H_SF16>, + MortonCopy<false, PixelFormat::A8B8G8R8_UNORM>, + MortonCopy<false, PixelFormat::A8B8G8R8_SNORM>, + MortonCopy<false, PixelFormat::A8B8G8R8_SINT>, + MortonCopy<false, PixelFormat::A8B8G8R8_UINT>, + MortonCopy<false, PixelFormat::R5G6B5_UNORM>, + MortonCopy<false, PixelFormat::B5G6R5_UNORM>, + MortonCopy<false, PixelFormat::A1R5G5B5_UNORM>, + MortonCopy<false, PixelFormat::A2B10G10R10_UNORM>, + MortonCopy<false, PixelFormat::A2B10G10R10_UINT>, + MortonCopy<false, PixelFormat::A1B5G5R5_UNORM>, + MortonCopy<false, PixelFormat::R8_UNORM>, + MortonCopy<false, PixelFormat::R8_SNORM>, + MortonCopy<false, PixelFormat::R8_SINT>, + MortonCopy<false, PixelFormat::R8_UINT>, + MortonCopy<false, PixelFormat::R16G16B16A16_FLOAT>, + MortonCopy<false, PixelFormat::R16G16B16A16_SNORM>, + MortonCopy<false, PixelFormat::R16G16B16A16_SINT>, + MortonCopy<false, PixelFormat::R16G16B16A16_UNORM>, + MortonCopy<false, PixelFormat::R16G16B16A16_UINT>, + MortonCopy<false, PixelFormat::B10G11R11_FLOAT>, + MortonCopy<false, PixelFormat::R32G32B32A32_UINT>, + MortonCopy<false, PixelFormat::BC1_RGBA_UNORM>, + MortonCopy<false, PixelFormat::BC2_UNORM>, + MortonCopy<false, PixelFormat::BC3_UNORM>, + MortonCopy<false, PixelFormat::BC4_UNORM>, + MortonCopy<false, PixelFormat::BC4_SNORM>, + MortonCopy<false, PixelFormat::BC5_UNORM>, + MortonCopy<false, PixelFormat::BC5_SNORM>, + MortonCopy<false, PixelFormat::BC7_UNORM>, + MortonCopy<false, PixelFormat::BC6H_UFLOAT>, + MortonCopy<false, PixelFormat::BC6H_SFLOAT>, // TODO(Subv): Swizzling ASTC formats are not supported nullptr, - MortonCopy<false, PixelFormat::BGRA8>, - MortonCopy<false, PixelFormat::RGBA32F>, - MortonCopy<false, PixelFormat::RG32F>, - MortonCopy<false, PixelFormat::R32F>, - MortonCopy<false, PixelFormat::R16F>, - MortonCopy<false, PixelFormat::R16U>, - MortonCopy<false, PixelFormat::R16S>, - MortonCopy<false, PixelFormat::R16UI>, - MortonCopy<false, PixelFormat::R16I>, - MortonCopy<false, PixelFormat::RG16>, - MortonCopy<false, PixelFormat::RG16F>, - MortonCopy<false, PixelFormat::RG16UI>, - MortonCopy<false, PixelFormat::RG16I>, - MortonCopy<false, PixelFormat::RG16S>, - MortonCopy<false, PixelFormat::RGB32F>, - MortonCopy<false, PixelFormat::RGBA8_SRGB>, - MortonCopy<false, PixelFormat::RG8U>, - MortonCopy<false, PixelFormat::RG8S>, - MortonCopy<false, PixelFormat::RG8UI>, - MortonCopy<false, PixelFormat::RG32UI>, - MortonCopy<false, PixelFormat::RGBX16F>, - MortonCopy<false, PixelFormat::R32UI>, - MortonCopy<false, PixelFormat::R32I>, + MortonCopy<false, PixelFormat::B8G8R8A8_UNORM>, + MortonCopy<false, PixelFormat::R32G32B32A32_FLOAT>, + MortonCopy<false, PixelFormat::R32G32B32A32_SINT>, + MortonCopy<false, PixelFormat::R32G32_FLOAT>, + MortonCopy<false, PixelFormat::R32G32_SINT>, + MortonCopy<false, PixelFormat::R32_FLOAT>, + MortonCopy<false, PixelFormat::R16_FLOAT>, + MortonCopy<false, PixelFormat::R16_UNORM>, + MortonCopy<false, PixelFormat::R16_SNORM>, + MortonCopy<false, PixelFormat::R16_UINT>, + MortonCopy<false, PixelFormat::R16_SINT>, + MortonCopy<false, PixelFormat::R16G16_UNORM>, + MortonCopy<false, PixelFormat::R16G16_FLOAT>, + MortonCopy<false, PixelFormat::R16G16_UINT>, + MortonCopy<false, PixelFormat::R16G16_SINT>, + MortonCopy<false, PixelFormat::R16G16_SNORM>, + MortonCopy<false, PixelFormat::R32G32B32_FLOAT>, + MortonCopy<false, PixelFormat::A8B8G8R8_SRGB>, + MortonCopy<false, PixelFormat::R8G8_UNORM>, + MortonCopy<false, PixelFormat::R8G8_SNORM>, + MortonCopy<false, PixelFormat::R8G8_SINT>, + MortonCopy<false, PixelFormat::R8G8_UINT>, + MortonCopy<false, PixelFormat::R32G32_UINT>, + MortonCopy<false, PixelFormat::R16G16B16X16_FLOAT>, + MortonCopy<false, PixelFormat::R32_UINT>, + MortonCopy<false, PixelFormat::R32_SINT>, nullptr, nullptr, nullptr, - MortonCopy<false, PixelFormat::BGRA8_SRGB>, - MortonCopy<false, PixelFormat::DXT1_SRGB>, - MortonCopy<false, PixelFormat::DXT23_SRGB>, - MortonCopy<false, PixelFormat::DXT45_SRGB>, - MortonCopy<false, PixelFormat::BC7U_SRGB>, - MortonCopy<false, PixelFormat::R4G4B4A4U>, + MortonCopy<false, PixelFormat::B8G8R8A8_SRGB>, + MortonCopy<false, PixelFormat::BC1_RGBA_SRGB>, + MortonCopy<false, PixelFormat::BC2_SRGB>, + MortonCopy<false, PixelFormat::BC3_SRGB>, + MortonCopy<false, PixelFormat::BC7_SRGB>, + MortonCopy<false, PixelFormat::A4B4G4R4_UNORM>, nullptr, nullptr, nullptr, @@ -199,12 +221,12 @@ static constexpr ConversionArray linear_to_morton_fns = { nullptr, nullptr, nullptr, - MortonCopy<false, PixelFormat::E5B9G9R9F>, - MortonCopy<false, PixelFormat::Z32F>, - MortonCopy<false, PixelFormat::Z16>, - MortonCopy<false, PixelFormat::Z24S8>, - MortonCopy<false, PixelFormat::S8Z24>, - MortonCopy<false, PixelFormat::Z32FS8>, + MortonCopy<false, PixelFormat::E5B9G9R9_FLOAT>, + MortonCopy<false, PixelFormat::D32_FLOAT>, + MortonCopy<false, PixelFormat::D16_UNORM>, + MortonCopy<false, PixelFormat::D24_UNORM_S8_UINT>, + MortonCopy<false, PixelFormat::S8_UINT_D24_UNORM>, + MortonCopy<false, PixelFormat::D32_FLOAT_S8_UINT>, }; static MortonCopyFn GetSwizzleFunction(MortonSwizzleMode mode, Surface::PixelFormat format) { diff --git a/src/video_core/renderer_opengl/gl_arb_decompiler.cpp b/src/video_core/renderer_opengl/gl_arb_decompiler.cpp index eb5158407..b7e9ed2e9 100644 --- a/src/video_core/renderer_opengl/gl_arb_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_arb_decompiler.cpp @@ -185,10 +185,6 @@ std::string TextureType(const MetaTexture& meta) { return type; } -std::string GlobalMemoryName(const GlobalMemoryBase& base) { - return fmt::format("gmem{}_{}", base.cbuf_index, base.cbuf_offset); -} - class ARBDecompiler final { public: explicit ARBDecompiler(const Device& device, const ShaderIR& ir, const Registry& registry, @@ -199,6 +195,8 @@ public: } private: + void DefineGlobalMemory(); + void DeclareHeader(); void DeclareVertex(); void DeclareGeometry(); @@ -228,6 +226,7 @@ private: std::pair<std::string, std::size_t> BuildCoords(Operation); std::string BuildAoffi(Operation); + std::string GlobalMemoryPointer(const GmemNode& gmem); void Exit(); std::string Assign(Operation); @@ -378,10 +377,8 @@ private: std::string address; std::string_view opname; if (const auto gmem = std::get_if<GmemNode>(&*operation[0])) { - AddLine("SUB.U {}, {}, {};", temporary, Visit(gmem->GetRealAddress()), - Visit(gmem->GetBaseAddress())); - address = fmt::format("{}[{}]", GlobalMemoryName(gmem->GetDescriptor()), temporary); - opname = "ATOMB"; + address = GlobalMemoryPointer(*gmem); + opname = "ATOM"; } else if (const auto smem = std::get_if<SmemNode>(&*operation[0])) { address = fmt::format("shared_mem[{}]", Visit(smem->GetAddress())); opname = "ATOMS"; @@ -456,9 +453,13 @@ private: shader_source += '\n'; } - std::string AllocTemporary() { - max_temporaries = std::max(max_temporaries, num_temporaries + 1); - return fmt::format("T{}.x", num_temporaries++); + std::string AllocLongVectorTemporary() { + max_long_temporaries = std::max(max_long_temporaries, num_long_temporaries + 1); + return fmt::format("L{}", num_long_temporaries++); + } + + std::string AllocLongTemporary() { + return fmt::format("{}.x", AllocLongVectorTemporary()); } std::string AllocVectorTemporary() { @@ -466,8 +467,13 @@ private: return fmt::format("T{}", num_temporaries++); } + std::string AllocTemporary() { + return fmt::format("{}.x", AllocVectorTemporary()); + } + void ResetTemporaries() noexcept { num_temporaries = 0; + num_long_temporaries = 0; } const Device& device; @@ -478,6 +484,11 @@ private: std::size_t num_temporaries = 0; std::size_t max_temporaries = 0; + std::size_t num_long_temporaries = 0; + std::size_t max_long_temporaries = 0; + + std::map<GlobalMemoryBase, u32> global_memory_names; + std::string shader_source; static constexpr std::string_view ADD_F32 = "ADD.F32"; @@ -784,6 +795,8 @@ private: ARBDecompiler::ARBDecompiler(const Device& device, const ShaderIR& ir, const Registry& registry, ShaderType stage, std::string_view identifier) : device{device}, ir{ir}, registry{registry}, stage{stage} { + DefineGlobalMemory(); + AddLine("TEMP RC;"); AddLine("TEMP FSWZA[4];"); AddLine("TEMP FSWZB[4];"); @@ -829,12 +842,20 @@ std::string_view HeaderStageName(ShaderType stage) { } } +void ARBDecompiler::DefineGlobalMemory() { + u32 binding = 0; + for (const auto& pair : ir.GetGlobalMemory()) { + const GlobalMemoryBase base = pair.first; + global_memory_names.emplace(base, binding); + ++binding; + } +} + void ARBDecompiler::DeclareHeader() { AddLine("!!NV{}5.0", HeaderStageName(stage)); // Enabling this allows us to cheat on some instructions like TXL with SHADOWARRAY2D AddLine("OPTION NV_internal;"); AddLine("OPTION NV_gpu_program_fp64;"); - AddLine("OPTION NV_shader_storage_buffer;"); AddLine("OPTION NV_shader_thread_group;"); if (ir.UsesWarps() && device.HasWarpIntrinsics()) { AddLine("OPTION NV_shader_thread_shuffle;"); @@ -892,11 +913,19 @@ void ARBDecompiler::DeclareCompute() { const ComputeInfo& info = registry.GetComputeInfo(); AddLine("GROUP_SIZE {} {} {};", info.workgroup_size[0], info.workgroup_size[1], info.workgroup_size[2]); - if (info.shared_memory_size_in_words > 0) { - const u32 size_in_bytes = info.shared_memory_size_in_words * 4; - AddLine("SHARED_MEMORY {};", size_in_bytes); - AddLine("SHARED shared_mem[] = {{program.sharedmem}};"); + if (info.shared_memory_size_in_words == 0) { + return; + } + const u32 limit = device.GetMaxComputeSharedMemorySize(); + u32 size_in_bytes = info.shared_memory_size_in_words * 4; + if (size_in_bytes > limit) { + LOG_ERROR(Render_OpenGL, "Shared memory size {} is clamped to host's limit {}", + size_in_bytes, limit); + size_in_bytes = limit; } + + AddLine("SHARED_MEMORY {};", size_in_bytes); + AddLine("SHARED shared_mem[] = {{program.sharedmem}};"); } void ARBDecompiler::DeclareInputAttributes() { @@ -951,11 +980,10 @@ void ARBDecompiler::DeclareLocalMemory() { } void ARBDecompiler::DeclareGlobalMemory() { - u32 binding = 0; // device.GetBaseBindings(stage).shader_storage_buffer; - for (const auto& pair : ir.GetGlobalMemory()) { - const auto& base = pair.first; - AddLine("STORAGE {}[] = {{ program.storage[{}] }};", GlobalMemoryName(base), binding); - ++binding; + const std::size_t num_entries = ir.GetGlobalMemory().size(); + if (num_entries > 0) { + const std::size_t num_vectors = Common::AlignUp(num_entries, 2) / 2; + AddLine("PARAM c[{}] = {{ program.local[0..{}] }};", num_vectors, num_vectors - 1); } } @@ -977,6 +1005,9 @@ void ARBDecompiler::DeclareTemporaries() { for (std::size_t i = 0; i < max_temporaries; ++i) { AddLine("TEMP T{};", i); } + for (std::size_t i = 0; i < max_long_temporaries; ++i) { + AddLine("LONG TEMP L{};", i); + } } void ARBDecompiler::DeclarePredicates() { @@ -1260,13 +1291,6 @@ std::string ARBDecompiler::Visit(const Node& node) { return "{0, 0, 0, 0}.x"; } - const auto buffer_index = [this, &abuf]() -> std::string { - if (stage != ShaderType::Geometry) { - return ""; - } - return fmt::format("[{}]", Visit(abuf->GetBuffer())); - }; - const Attribute::Index index = abuf->GetIndex(); const u32 element = abuf->GetElement(); const char swizzle = Swizzle(element); @@ -1339,10 +1363,7 @@ std::string ARBDecompiler::Visit(const Node& node) { if (const auto gmem = std::get_if<GmemNode>(&*node)) { std::string temporary = AllocTemporary(); - AddLine("SUB.U {}, {}, {};", temporary, Visit(gmem->GetRealAddress()), - Visit(gmem->GetBaseAddress())); - AddLine("LDB.U32 {}, {}[{}];", temporary, GlobalMemoryName(gmem->GetDescriptor()), - temporary); + AddLine("LOAD.U32 {}, {};", temporary, GlobalMemoryPointer(*gmem)); return temporary; } @@ -1375,7 +1396,7 @@ std::string ARBDecompiler::Visit(const Node& node) { return {}; } - if (const auto cmt = std::get_if<CommentNode>(&*node)) { + if ([[maybe_unused]] const auto cmt = std::get_if<CommentNode>(&*node)) { // Uncommenting this will generate invalid code. GLASM lacks comments. // AddLine("// {}", cmt->GetText()); return {}; @@ -1419,6 +1440,22 @@ std::string ARBDecompiler::BuildAoffi(Operation operation) { return fmt::format(", offset({})", temporary); } +std::string ARBDecompiler::GlobalMemoryPointer(const GmemNode& gmem) { + const u32 binding = global_memory_names.at(gmem.GetDescriptor()); + const char result_swizzle = binding % 2 == 0 ? 'x' : 'y'; + + const std::string pointer = AllocLongVectorTemporary(); + std::string temporary = AllocTemporary(); + + const u32 local_index = binding / 2; + AddLine("PK64.U {}, c[{}];", pointer, local_index); + AddLine("SUB.U {}, {}, {};", temporary, Visit(gmem.GetRealAddress()), + Visit(gmem.GetBaseAddress())); + AddLine("CVT.U64.U32 {}.z, {};", pointer, temporary); + AddLine("ADD.U64 {}.x, {}.{}, {}.z;", pointer, pointer, result_swizzle, pointer); + return fmt::format("{}.x", pointer); +} + void ARBDecompiler::Exit() { if (stage != ShaderType::Fragment) { AddLine("RET;"); @@ -1515,11 +1552,7 @@ std::string ARBDecompiler::Assign(Operation operation) { ResetTemporaries(); return {}; } else if (const auto gmem = std::get_if<GmemNode>(&*dest)) { - const std::string temporary = AllocTemporary(); - AddLine("SUB.U {}, {}, {};", temporary, Visit(gmem->GetRealAddress()), - Visit(gmem->GetBaseAddress())); - AddLine("STB.U32 {}, {}[{}];", Visit(src), GlobalMemoryName(gmem->GetDescriptor()), - temporary); + AddLine("STORE.U32 {}, {};", Visit(src), GlobalMemoryPointer(*gmem)); ResetTemporaries(); return {}; } else { @@ -1671,7 +1704,7 @@ std::string ARBDecompiler::HCastFloat(Operation operation) { } std::string ARBDecompiler::HUnpack(Operation operation) { - const std::string operand = Visit(operation[0]); + std::string operand = Visit(operation[0]); switch (std::get<Tegra::Shader::HalfType>(operation.GetMeta())) { case Tegra::Shader::HalfType::H0_H1: return operand; @@ -2021,7 +2054,7 @@ std::string ARBDecompiler::InvocationId(Operation) { std::string ARBDecompiler::YNegate(Operation) { LOG_WARNING(Render_OpenGL, "(STUBBED)"); - const std::string temporary = AllocTemporary(); + std::string temporary = AllocTemporary(); AddLine("MOV.F {}, 1;", temporary); return temporary; } @@ -2044,10 +2077,6 @@ std::string ARBDecompiler::ShuffleIndexed(Operation operation) { } std::string ARBDecompiler::Barrier(Operation) { - if (!ir.IsDecompiled()) { - LOG_ERROR(Render_OpenGL, "BAR used but shader is not decompiled"); - return {}; - } AddLine("BAR;"); return {}; } diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp index e461e4c70..e866d8f2f 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp @@ -26,7 +26,7 @@ Buffer::Buffer(const Device& device, VAddr cpu_addr, std::size_t size) : VideoCommon::BufferBlock{cpu_addr, size} { gl_buffer.Create(); glNamedBufferData(gl_buffer.handle, static_cast<GLsizeiptr>(size), nullptr, GL_DYNAMIC_DRAW); - if (device.HasVertexBufferUnifiedMemory()) { + if (device.UseAssemblyShaders() || device.HasVertexBufferUnifiedMemory()) { glMakeNamedBufferResidentNV(gl_buffer.handle, GL_READ_WRITE); glGetNamedBufferParameterui64vNV(gl_buffer.handle, GL_BUFFER_GPU_ADDRESS_NV, &gpu_address); } diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index c1f20f0ab..e7d95149f 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp @@ -212,6 +212,7 @@ Device::Device() shader_storage_alignment = GetInteger<std::size_t>(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT); max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS); max_varyings = GetInteger<u32>(GL_MAX_VARYING_VECTORS); + max_compute_shared_memory_size = GetInteger<u32>(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE); has_warp_intrinsics = GLAD_GL_NV_gpu_shader5 && GLAD_GL_NV_shader_thread_group && GLAD_GL_NV_shader_thread_shuffle; has_shader_ballot = GLAD_GL_ARB_shader_ballot; @@ -233,6 +234,8 @@ Device::Device() GLAD_GL_NV_gpu_program5 && GLAD_GL_NV_compute_program5 && GLAD_GL_NV_transform_feedback && GLAD_GL_NV_transform_feedback2; + use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue(); + LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi); LOG_INFO(Render_OpenGL, "Renderer_ComponentIndexingBug: {}", has_component_indexing_bug); LOG_INFO(Render_OpenGL, "Renderer_PreciseBug: {}", has_precise_bug); @@ -248,6 +251,7 @@ Device::Device(std::nullptr_t) { shader_storage_alignment = 4; max_vertex_attributes = 16; max_varyings = 15; + max_compute_shared_memory_size = 0x10000; has_warp_intrinsics = true; has_shader_ballot = true; has_vertex_viewport_layer = true; diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h index e1d811966..8a4b6b9fc 100644 --- a/src/video_core/renderer_opengl/gl_device.h +++ b/src/video_core/renderer_opengl/gl_device.h @@ -52,6 +52,10 @@ public: return max_varyings; } + u32 GetMaxComputeSharedMemorySize() const { + return max_compute_shared_memory_size; + } + bool HasWarpIntrinsics() const { return has_warp_intrinsics; } @@ -104,6 +108,10 @@ public: return use_assembly_shaders; } + bool UseAsynchronousShaders() const { + return use_asynchronous_shaders; + } + private: static bool TestVariableAoffi(); static bool TestPreciseBug(); @@ -114,6 +122,7 @@ private: std::size_t shader_storage_alignment{}; u32 max_vertex_attributes{}; u32 max_varyings{}; + u32 max_compute_shared_memory_size{}; bool has_warp_intrinsics{}; bool has_shader_ballot{}; bool has_vertex_viewport_layer{}; @@ -127,6 +136,7 @@ private: bool has_fast_buffer_sub_data{}; bool has_nv_viewport_array2{}; bool use_assembly_shaders{}; + bool use_asynchronous_shaders{}; }; } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index e960a0ef1..03e82c599 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -139,6 +139,18 @@ void oglEnable(GLenum cap, bool state) { (state ? glEnable : glDisable)(cap); } +void UpdateBindlessPointers(GLenum target, GLuint64EXT* pointers, std::size_t num_entries) { + if (num_entries == 0) { + return; + } + if (num_entries % 2 == 1) { + pointers[num_entries] = 0; + } + const GLsizei num_vectors = static_cast<GLsizei>((num_entries + 1) / 2); + glProgramLocalParametersI4uivNV(target, 0, num_vectors, + reinterpret_cast<const GLuint*>(pointers)); +} + } // Anonymous namespace RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, @@ -149,7 +161,8 @@ RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWind shader_cache{*this, system, emu_window, device}, query_cache{system, *this}, buffer_cache{*this, system, device, STREAM_BUFFER_SIZE}, fence_manager{system, *this, texture_cache, buffer_cache, query_cache}, system{system}, - screen_info{info}, program_manager{program_manager}, state_tracker{state_tracker} { + screen_info{info}, program_manager{program_manager}, state_tracker{state_tracker}, + async_shaders{emu_window} { CheckExtensions(); unified_uniform_buffer.Create(); @@ -162,6 +175,23 @@ RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWind nullptr, 0); } } + + if (device.UseAsynchronousShaders()) { + // Max worker threads we should allow + constexpr auto MAX_THREADS = 2u; + // Amount of threads we should reserve for other parts of yuzu + constexpr auto RESERVED_THREADS = 6u; + // Get the amount of threads we can use(this can return zero) + const auto cpu_thread_count = + std::max(RESERVED_THREADS, std::thread::hardware_concurrency()); + // Deduce how many "extra" threads we have to use. + const auto max_threads_unused = cpu_thread_count - RESERVED_THREADS; + // Always allow at least 1 thread regardless of our settings + const auto max_worker_count = std::max(1u, max_threads_unused); + // Don't use more than MAX_THREADS + const auto worker_count = std::min(max_worker_count, MAX_THREADS); + async_shaders.AllocateWorkers(worker_count); + } } RasterizerOpenGL::~RasterizerOpenGL() { @@ -306,7 +336,6 @@ GLintptr RasterizerOpenGL::SetupIndexBuffer() { void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { MICROPROFILE_SCOPE(OpenGL_Shader); auto& gpu = system.GPU().Maxwell3D(); - std::size_t num_ssbos = 0; u32 clip_distances = 0; for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { @@ -329,31 +358,15 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { } // Currently this stages are not supported in the OpenGL backend. - // Todo(Blinkhawk): Port tesselation shaders from Vulkan to OpenGL - if (program == Maxwell::ShaderProgram::TesselationControl) { - continue; - } else if (program == Maxwell::ShaderProgram::TesselationEval) { + // TODO(Blinkhawk): Port tesselation shaders from Vulkan to OpenGL + if (program == Maxwell::ShaderProgram::TesselationControl || + program == Maxwell::ShaderProgram::TesselationEval) { continue; } - Shader* const shader = shader_cache.GetStageProgram(program); - - if (device.UseAssemblyShaders()) { - // Check for ARB limitation. We only have 16 SSBOs per context state. To workaround this - // all stages share the same bindings. - const std::size_t num_stage_ssbos = shader->GetEntries().global_memory_entries.size(); - ASSERT_MSG(num_stage_ssbos == 0 || num_ssbos == 0, "SSBOs on more than one stage"); - num_ssbos += num_stage_ssbos; - } + Shader* const shader = shader_cache.GetStageProgram(program, async_shaders); - // Stage indices are 0 - 5 - const std::size_t stage = index == 0 ? 0 : index - 1; - SetupDrawConstBuffers(stage, shader); - SetupDrawGlobalMemory(stage, shader); - SetupDrawTextures(stage, shader); - SetupDrawImages(stage, shader); - - const GLuint program_handle = shader->GetHandle(); + const GLuint program_handle = shader->IsBuilt() ? shader->GetHandle() : 0; switch (program) { case Maxwell::ShaderProgram::VertexA: case Maxwell::ShaderProgram::VertexB: @@ -370,6 +383,13 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { shader_config.enable.Value(), shader_config.offset); } + // Stage indices are 0 - 5 + const std::size_t stage = index == 0 ? 0 : index - 1; + SetupDrawConstBuffers(stage, shader); + SetupDrawGlobalMemory(stage, shader); + SetupDrawTextures(stage, shader); + SetupDrawImages(stage, shader); + // Workaround for Intel drivers. // When a clip distance is enabled but not set in the shader it crops parts of the screen // (sometimes it's half the screen, sometimes three quarters). To avoid this, enable the @@ -731,6 +751,8 @@ void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) { current_cbuf = 0; auto kernel = shader_cache.GetComputeKernel(code_addr); + program_manager.BindCompute(kernel->GetHandle()); + SetupComputeTextures(kernel); SetupComputeImages(kernel); @@ -745,7 +767,6 @@ void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) { buffer_cache.Unmap(); const auto& launch_desc = system.GPU().KeplerCompute().launch_description; - program_manager.BindCompute(kernel->GetHandle()); glDispatchCompute(launch_desc.grid_dim_x, launch_desc.grid_dim_y, launch_desc.grid_dim_z); ++num_queued_commands; } @@ -1005,40 +1026,66 @@ void RasterizerOpenGL::SetupConstBuffer(GLenum stage, u32 binding, } void RasterizerOpenGL::SetupDrawGlobalMemory(std::size_t stage_index, Shader* shader) { + static constexpr std::array TARGET_LUT = { + GL_VERTEX_PROGRAM_NV, GL_TESS_CONTROL_PROGRAM_NV, GL_TESS_EVALUATION_PROGRAM_NV, + GL_GEOMETRY_PROGRAM_NV, GL_FRAGMENT_PROGRAM_NV, + }; + auto& gpu{system.GPU()}; auto& memory_manager{gpu.MemoryManager()}; - const auto cbufs{gpu.Maxwell3D().state.shader_stages[stage_index]}; + const auto& cbufs{gpu.Maxwell3D().state.shader_stages[stage_index]}; + const auto& entries{shader->GetEntries().global_memory_entries}; + + std::array<GLuint64EXT, 32> pointers; + ASSERT(entries.size() < pointers.size()); - u32 binding = - device.UseAssemblyShaders() ? 0 : device.GetBaseBindings(stage_index).shader_storage_buffer; - for (const auto& entry : shader->GetEntries().global_memory_entries) { + const bool assembly_shaders = device.UseAssemblyShaders(); + u32 binding = assembly_shaders ? 0 : device.GetBaseBindings(stage_index).shader_storage_buffer; + for (const auto& entry : entries) { const GPUVAddr addr{cbufs.const_buffers[entry.cbuf_index].address + entry.cbuf_offset}; const GPUVAddr gpu_addr{memory_manager.Read<u64>(addr)}; const u32 size{memory_manager.Read<u32>(addr + 8)}; - SetupGlobalMemory(binding++, entry, gpu_addr, size); + SetupGlobalMemory(binding, entry, gpu_addr, size, &pointers[binding]); + ++binding; + } + if (assembly_shaders) { + UpdateBindlessPointers(TARGET_LUT[stage_index], pointers.data(), entries.size()); } } void RasterizerOpenGL::SetupComputeGlobalMemory(Shader* kernel) { auto& gpu{system.GPU()}; auto& memory_manager{gpu.MemoryManager()}; - const auto cbufs{gpu.KeplerCompute().launch_description.const_buffer_config}; + const auto& cbufs{gpu.KeplerCompute().launch_description.const_buffer_config}; + const auto& entries{kernel->GetEntries().global_memory_entries}; + + std::array<GLuint64EXT, 32> pointers; + ASSERT(entries.size() < pointers.size()); u32 binding = 0; - for (const auto& entry : kernel->GetEntries().global_memory_entries) { - const auto addr{cbufs[entry.cbuf_index].Address() + entry.cbuf_offset}; - const auto gpu_addr{memory_manager.Read<u64>(addr)}; - const auto size{memory_manager.Read<u32>(addr + 8)}; - SetupGlobalMemory(binding++, entry, gpu_addr, size); + for (const auto& entry : entries) { + const GPUVAddr addr{cbufs[entry.cbuf_index].Address() + entry.cbuf_offset}; + const GPUVAddr gpu_addr{memory_manager.Read<u64>(addr)}; + const u32 size{memory_manager.Read<u32>(addr + 8)}; + SetupGlobalMemory(binding, entry, gpu_addr, size, &pointers[binding]); + ++binding; + } + if (device.UseAssemblyShaders()) { + UpdateBindlessPointers(GL_COMPUTE_PROGRAM_NV, pointers.data(), entries.size()); } } void RasterizerOpenGL::SetupGlobalMemory(u32 binding, const GlobalMemoryEntry& entry, - GPUVAddr gpu_addr, std::size_t size) { - const auto alignment{device.GetShaderStorageBufferAlignment()}; + GPUVAddr gpu_addr, std::size_t size, + GLuint64EXT* pointer) { + const std::size_t alignment{device.GetShaderStorageBufferAlignment()}; const auto info = buffer_cache.UploadMemory(gpu_addr, size, alignment, entry.is_written); - glBindBufferRange(GL_SHADER_STORAGE_BUFFER, binding, info.handle, info.offset, - static_cast<GLsizeiptr>(size)); + if (device.UseAssemblyShaders()) { + *pointer = info.address + info.offset; + } else { + glBindBufferRange(GL_SHADER_STORAGE_BUFFER, binding, info.handle, info.offset, + static_cast<GLsizeiptr>(size)); + } } void RasterizerOpenGL::SetupDrawTextures(std::size_t stage_index, Shader* shader) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 4f082592f..ccc6f50f6 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -33,6 +33,7 @@ #include "video_core/renderer_opengl/gl_state_tracker.h" #include "video_core/renderer_opengl/gl_texture_cache.h" #include "video_core/renderer_opengl/utils.h" +#include "video_core/shader/async_shaders.h" #include "video_core/textures/texture.h" namespace Core { @@ -91,6 +92,14 @@ public: return num_queued_commands > 0; } + VideoCommon::Shader::AsyncShaders& GetAsyncShaders() { + return async_shaders; + } + + const VideoCommon::Shader::AsyncShaders& GetAsyncShaders() const { + return async_shaders; + } + private: /// Configures the color and depth framebuffer states. void ConfigureFramebuffers(); @@ -115,9 +124,9 @@ private: /// Configures the current global memory entries to use for the kernel invocation. void SetupComputeGlobalMemory(Shader* kernel); - /// Configures a constant buffer. + /// Configures a global memory buffer. void SetupGlobalMemory(u32 binding, const GlobalMemoryEntry& entry, GPUVAddr gpu_addr, - std::size_t size); + std::size_t size, GLuint64EXT* pointer); /// Configures the current textures to use for the draw command. void SetupDrawTextures(std::size_t stage_index, Shader* shader); @@ -242,6 +251,7 @@ private: ScreenInfo& screen_info; ProgramManager& program_manager; StateTracker& state_tracker; + VideoCommon::Shader::AsyncShaders async_shaders; static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h index f8b322227..b05cb641c 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.h +++ b/src/video_core/renderer_opengl/gl_resource_manager.h @@ -177,6 +177,12 @@ public: Release(); } + OGLAssemblyProgram& operator=(OGLAssemblyProgram&& o) noexcept { + Release(); + handle = std::exchange(o.handle, 0); + return *this; + } + /// Deletes the internal OpenGL resource void Release(); diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index c6a3bf3a1..be71e1733 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -31,6 +31,7 @@ #include "video_core/shader/registry.h" #include "video_core/shader/shader_ir.h" #include "video_core/shader_cache.h" +#include "video_core/shader_notify.h" namespace OpenGL { @@ -125,7 +126,7 @@ std::shared_ptr<Registry> MakeRegistry(const ShaderDiskCacheEntry& entry) { const VideoCore::GuestDriverProfile guest_profile{entry.texture_handler_size}; const VideoCommon::Shader::SerializedRegistryInfo info{guest_profile, entry.bound_buffer, entry.graphics_info, entry.compute_info}; - const auto registry = std::make_shared<Registry>(entry.type, info); + auto registry = std::make_shared<Registry>(entry.type, info); for (const auto& [address, value] : entry.keys) { const auto [buffer, offset] = address; registry->InsertKey(buffer, offset, value); @@ -140,9 +141,24 @@ std::shared_ptr<Registry> MakeRegistry(const ShaderDiskCacheEntry& entry) { return registry; } +std::unordered_set<GLenum> GetSupportedFormats() { + GLint num_formats; + glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &num_formats); + + std::vector<GLint> formats(num_formats); + glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, formats.data()); + + std::unordered_set<GLenum> supported_formats; + for (const GLint format : formats) { + supported_formats.insert(static_cast<GLenum>(format)); + } + return supported_formats; +} + +} // Anonymous namespace + ProgramSharedPtr BuildShader(const Device& device, ShaderType shader_type, u64 unique_identifier, - const ShaderIR& ir, const Registry& registry, - bool hint_retrievable = false) { + const ShaderIR& ir, const Registry& registry, bool hint_retrievable) { const std::string shader_id = MakeShaderID(unique_identifier, shader_type); LOG_INFO(Render_OpenGL, "{}", shader_id); @@ -181,30 +197,17 @@ ProgramSharedPtr BuildShader(const Device& device, ShaderType shader_type, u64 u return program; } -std::unordered_set<GLenum> GetSupportedFormats() { - GLint num_formats; - glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &num_formats); - - std::vector<GLint> formats(num_formats); - glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, formats.data()); - - std::unordered_set<GLenum> supported_formats; - for (const GLint format : formats) { - supported_formats.insert(static_cast<GLenum>(format)); - } - return supported_formats; -} - -} // Anonymous namespace - Shader::Shader(std::shared_ptr<VideoCommon::Shader::Registry> registry_, ShaderEntries entries_, - ProgramSharedPtr program_) - : registry{std::move(registry_)}, entries{std::move(entries_)}, program{std::move(program_)} { + ProgramSharedPtr program_, bool is_built) + : registry{std::move(registry_)}, entries{std::move(entries_)}, program{std::move(program_)}, + is_built(is_built) { handle = program->assembly_program.handle; if (handle == 0) { handle = program->source_program.handle; } - ASSERT(handle != 0); + if (is_built) { + ASSERT(handle != 0); + } } Shader::~Shader() = default; @@ -214,42 +217,79 @@ GLuint Shader::GetHandle() const { return handle; } -std::unique_ptr<Shader> Shader::CreateStageFromMemory(const ShaderParameters& params, - Maxwell::ShaderProgram program_type, - ProgramCode code, ProgramCode code_b) { +bool Shader::IsBuilt() const { + return is_built; +} + +void Shader::AsyncOpenGLBuilt(OGLProgram new_program) { + program->source_program = std::move(new_program); + handle = program->source_program.handle; + is_built = true; +} + +void Shader::AsyncGLASMBuilt(OGLAssemblyProgram new_program) { + program->assembly_program = std::move(new_program); + handle = program->assembly_program.handle; + is_built = true; +} + +std::unique_ptr<Shader> Shader::CreateStageFromMemory( + const ShaderParameters& params, Maxwell::ShaderProgram program_type, ProgramCode code, + ProgramCode code_b, VideoCommon::Shader::AsyncShaders& async_shaders, VAddr cpu_addr) { const auto shader_type = GetShaderType(program_type); - const std::size_t size_in_bytes = code.size() * sizeof(u64); - auto registry = std::make_shared<Registry>(shader_type, params.system.GPU().Maxwell3D()); - const ShaderIR ir(code, STAGE_MAIN_OFFSET, COMPILER_SETTINGS, *registry); - // TODO(Rodrigo): Handle VertexA shaders - // std::optional<ShaderIR> ir_b; - // if (!code_b.empty()) { - // ir_b.emplace(code_b, STAGE_MAIN_OFFSET); - // } - auto program = BuildShader(params.device, shader_type, params.unique_identifier, ir, *registry); + auto& gpu = params.system.GPU(); + gpu.ShaderNotify().MarkSharderBuilding(); + + auto registry = std::make_shared<Registry>(shader_type, gpu.Maxwell3D()); + if (!async_shaders.IsShaderAsync(params.system.GPU()) || + !params.device.UseAsynchronousShaders()) { + const ShaderIR ir(code, STAGE_MAIN_OFFSET, COMPILER_SETTINGS, *registry); + // TODO(Rodrigo): Handle VertexA shaders + // std::optional<ShaderIR> ir_b; + // if (!code_b.empty()) { + // ir_b.emplace(code_b, STAGE_MAIN_OFFSET); + // } + auto program = + BuildShader(params.device, shader_type, params.unique_identifier, ir, *registry); + ShaderDiskCacheEntry entry; + entry.type = shader_type; + entry.code = std::move(code); + entry.code_b = std::move(code_b); + entry.unique_identifier = params.unique_identifier; + entry.bound_buffer = registry->GetBoundBuffer(); + entry.graphics_info = registry->GetGraphicsInfo(); + entry.keys = registry->GetKeys(); + entry.bound_samplers = registry->GetBoundSamplers(); + entry.bindless_samplers = registry->GetBindlessSamplers(); + params.disk_cache.SaveEntry(std::move(entry)); + + gpu.ShaderNotify().MarkShaderComplete(); + + return std::unique_ptr<Shader>(new Shader(std::move(registry), + MakeEntries(params.device, ir, shader_type), + std::move(program), true)); + } else { + // Required for entries + const ShaderIR ir(code, STAGE_MAIN_OFFSET, COMPILER_SETTINGS, *registry); + auto entries = MakeEntries(params.device, ir, shader_type); - ShaderDiskCacheEntry entry; - entry.type = shader_type; - entry.code = std::move(code); - entry.code_b = std::move(code_b); - entry.unique_identifier = params.unique_identifier; - entry.bound_buffer = registry->GetBoundBuffer(); - entry.graphics_info = registry->GetGraphicsInfo(); - entry.keys = registry->GetKeys(); - entry.bound_samplers = registry->GetBoundSamplers(); - entry.bindless_samplers = registry->GetBindlessSamplers(); - params.disk_cache.SaveEntry(std::move(entry)); + async_shaders.QueueOpenGLShader(params.device, shader_type, params.unique_identifier, + std::move(code), std::move(code_b), STAGE_MAIN_OFFSET, + COMPILER_SETTINGS, *registry, cpu_addr); - return std::unique_ptr<Shader>(new Shader( - std::move(registry), MakeEntries(params.device, ir, shader_type), std::move(program))); + auto program = std::make_shared<ProgramHandle>(); + return std::unique_ptr<Shader>( + new Shader(std::move(registry), std::move(entries), std::move(program), false)); + } } std::unique_ptr<Shader> Shader::CreateKernelFromMemory(const ShaderParameters& params, ProgramCode code) { - const std::size_t size_in_bytes = code.size() * sizeof(u64); + auto& gpu = params.system.GPU(); + gpu.ShaderNotify().MarkSharderBuilding(); - auto& engine = params.system.GPU().KeplerCompute(); + auto& engine = gpu.KeplerCompute(); auto registry = std::make_shared<Registry>(ShaderType::Compute, engine); const ShaderIR ir(code, KERNEL_MAIN_OFFSET, COMPILER_SETTINGS, *registry); const u64 uid = params.unique_identifier; @@ -266,6 +306,8 @@ std::unique_ptr<Shader> Shader::CreateKernelFromMemory(const ShaderParameters& p entry.bindless_samplers = registry->GetBindlessSamplers(); params.disk_cache.SaveEntry(std::move(entry)); + gpu.ShaderNotify().MarkShaderComplete(); + return std::unique_ptr<Shader>(new Shader(std::move(registry), MakeEntries(params.device, ir, ShaderType::Compute), std::move(program))); @@ -436,14 +478,51 @@ ProgramSharedPtr ShaderCacheOpenGL::GeneratePrecompiledProgram( return program; } -Shader* ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) { +Shader* ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program, + VideoCommon::Shader::AsyncShaders& async_shaders) { if (!system.GPU().Maxwell3D().dirty.flags[Dirty::Shaders]) { - return last_shaders[static_cast<std::size_t>(program)]; + auto* last_shader = last_shaders[static_cast<std::size_t>(program)]; + if (last_shader->IsBuilt()) { + return last_shader; + } } auto& memory_manager{system.GPU().MemoryManager()}; const GPUVAddr address{GetShaderAddress(system, program)}; + if (device.UseAsynchronousShaders() && async_shaders.HasCompletedWork()) { + auto completed_work = async_shaders.GetCompletedWork(); + for (auto& work : completed_work) { + Shader* shader = TryGet(work.cpu_address); + auto& gpu = system.GPU(); + gpu.ShaderNotify().MarkShaderComplete(); + if (shader == nullptr) { + continue; + } + using namespace VideoCommon::Shader; + if (work.backend == AsyncShaders::Backend::OpenGL) { + shader->AsyncOpenGLBuilt(std::move(work.program.opengl)); + } else if (work.backend == AsyncShaders::Backend::GLASM) { + shader->AsyncGLASMBuilt(std::move(work.program.glasm)); + } + + ShaderDiskCacheEntry entry; + entry.type = work.shader_type; + entry.code = std::move(work.code); + entry.code_b = std::move(work.code_b); + entry.unique_identifier = work.uid; + + auto& registry = shader->GetRegistry(); + + entry.bound_buffer = registry.GetBoundBuffer(); + entry.graphics_info = registry.GetGraphicsInfo(); + entry.keys = registry.GetKeys(); + entry.bound_samplers = registry.GetBoundSamplers(); + entry.bindless_samplers = registry.GetBindlessSamplers(); + disk_cache.SaveEntry(std::move(entry)); + } + } + // Look up shader in the cache based on address const auto cpu_addr{memory_manager.GpuToCpuAddress(address)}; if (Shader* const shader{cpu_addr ? TryGet(*cpu_addr) : null_shader.get()}) { @@ -471,7 +550,8 @@ Shader* ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) { std::unique_ptr<Shader> shader; const auto found = runtime_cache.find(unique_identifier); if (found == runtime_cache.end()) { - shader = Shader::CreateStageFromMemory(params, program, std::move(code), std::move(code_b)); + shader = Shader::CreateStageFromMemory(params, program, std::move(code), std::move(code_b), + async_shaders, cpu_addr.value_or(0)); } else { shader = Shader::CreateFromCache(params, found->second); } diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h index 994aaeaf2..7528ac686 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_cache.h @@ -33,6 +33,10 @@ namespace Core::Frontend { class EmuWindow; } +namespace VideoCommon::Shader { +class AsyncShaders; +} + namespace OpenGL { class Device; @@ -61,6 +65,11 @@ struct ShaderParameters { u64 unique_identifier; }; +ProgramSharedPtr BuildShader(const Device& device, Tegra::Engines::ShaderType shader_type, + u64 unique_identifier, const VideoCommon::Shader::ShaderIR& ir, + const VideoCommon::Shader::Registry& registry, + bool hint_retrievable = false); + class Shader final { public: ~Shader(); @@ -68,15 +77,28 @@ public: /// Gets the GL program handle for the shader GLuint GetHandle() const; + bool IsBuilt() const; + /// Gets the shader entries for the shader const ShaderEntries& GetEntries() const { return entries; } - static std::unique_ptr<Shader> CreateStageFromMemory(const ShaderParameters& params, - Maxwell::ShaderProgram program_type, - ProgramCode program_code, - ProgramCode program_code_b); + const VideoCommon::Shader::Registry& GetRegistry() const { + return *registry; + } + + /// Mark a OpenGL shader as built + void AsyncOpenGLBuilt(OGLProgram new_program); + + /// Mark a GLASM shader as built + void AsyncGLASMBuilt(OGLAssemblyProgram new_program); + + static std::unique_ptr<Shader> CreateStageFromMemory( + const ShaderParameters& params, Maxwell::ShaderProgram program_type, + ProgramCode program_code, ProgramCode program_code_b, + VideoCommon::Shader::AsyncShaders& async_shaders, VAddr cpu_addr); + static std::unique_ptr<Shader> CreateKernelFromMemory(const ShaderParameters& params, ProgramCode code); @@ -85,12 +107,13 @@ public: private: explicit Shader(std::shared_ptr<VideoCommon::Shader::Registry> registry, ShaderEntries entries, - ProgramSharedPtr program); + ProgramSharedPtr program, bool is_built = true); std::shared_ptr<VideoCommon::Shader::Registry> registry; ShaderEntries entries; ProgramSharedPtr program; GLuint handle = 0; + bool is_built{}; }; class ShaderCacheOpenGL final : public VideoCommon::ShaderCache<Shader> { @@ -104,7 +127,8 @@ public: const VideoCore::DiskResourceLoadCallback& callback); /// Gets the current specified shader stage program - Shader* GetStageProgram(Maxwell::ShaderProgram program); + Shader* GetStageProgram(Maxwell::ShaderProgram program, + VideoCommon::Shader::AsyncShaders& async_shaders); /// Gets a compute kernel in the passed address Shader* GetComputeKernel(GPUVAddr code_addr); diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 2c49aeaac..3f75fcd2b 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -602,8 +602,15 @@ private: return; } const auto& info = registry.GetComputeInfo(); - if (const u32 size = info.shared_memory_size_in_words; size > 0) { - code.AddLine("shared uint smem[{}];", size); + if (u32 size = info.shared_memory_size_in_words * 4; size > 0) { + const u32 limit = device.GetMaxComputeSharedMemorySize(); + if (size > limit) { + LOG_ERROR(Render_OpenGL, "Shared memory size {} is clamped to host's limit {}", + size, limit); + size = limit; + } + + code.AddLine("shared uint smem[{}];", size / 4); code.AddNewLine(); } code.AddLine("layout (local_size_x = {}, local_size_y = {}, local_size_z = {}) in;", @@ -1912,7 +1919,7 @@ private: Expression Comparison(Operation operation) { static_assert(!unordered || type == Type::Float); - const Expression expr = GenerateBinaryInfix(operation, op, Type::Bool, type, type); + Expression expr = GenerateBinaryInfix(operation, op, Type::Bool, type, type); if constexpr (op.compare("!=") == 0 && type == Type::Float && !unordered) { // GLSL's operator!=(float, float) doesn't seem be ordered. This happens on both AMD's @@ -1952,10 +1959,6 @@ private: return {fmt::format("({} != 0)", carry), Type::Bool}; } - Expression LogicalFIsNan(Operation operation) { - return GenerateUnary(operation, "isnan", Type::Bool, Type::Float); - } - Expression LogicalAssign(Operation operation) { const Node& dest = operation[0]; const Node& src = operation[1]; @@ -2771,15 +2774,6 @@ private: return std::min<u32>(device.GetMaxVaryings(), Maxwell::NumVaryings); } - bool IsRenderTargetEnabled(u32 render_target) const { - for (u32 component = 0; component < 4; ++component) { - if (header.ps.IsColorComponentOutputEnabled(render_target, component)) { - return true; - } - } - return false; - } - const Device& device; const ShaderIR& ir; const Registry& registry; diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index 8e754fa90..691c6c79b 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp @@ -11,8 +11,30 @@ namespace OpenGL { -ProgramManager::ProgramManager(const Device& device) { - use_assembly_programs = device.UseAssemblyShaders(); +namespace { + +void BindProgram(GLenum stage, GLuint current, GLuint old, bool& enabled) { + if (current == old) { + return; + } + if (current == 0) { + if (enabled) { + enabled = false; + glDisable(stage); + } + return; + } + if (!enabled) { + enabled = true; + glEnable(stage); + } + glBindProgramARB(stage, current); +} + +} // Anonymous namespace + +ProgramManager::ProgramManager(const Device& device) + : use_assembly_programs{device.UseAssemblyShaders()} { if (use_assembly_programs) { glEnable(GL_COMPUTE_PROGRAM_NV); } else { @@ -33,9 +55,7 @@ void ProgramManager::BindCompute(GLuint program) { } void ProgramManager::BindGraphicsPipeline() { - if (use_assembly_programs) { - UpdateAssemblyPrograms(); - } else { + if (!use_assembly_programs) { UpdateSourcePrograms(); } } @@ -63,32 +83,25 @@ void ProgramManager::RestoreGuestPipeline() { } } -void ProgramManager::UpdateAssemblyPrograms() { - const auto update_state = [](GLenum stage, bool& enabled, GLuint current, GLuint old) { - if (current == old) { - return; - } - if (current == 0) { - if (enabled) { - enabled = false; - glDisable(stage); - } - return; - } - if (!enabled) { - enabled = true; - glEnable(stage); - } - glBindProgramARB(stage, current); - }; +void ProgramManager::UseVertexShader(GLuint program) { + if (use_assembly_programs) { + BindProgram(GL_VERTEX_PROGRAM_NV, program, current_state.vertex, vertex_enabled); + } + current_state.vertex = program; +} - update_state(GL_VERTEX_PROGRAM_NV, vertex_enabled, current_state.vertex, old_state.vertex); - update_state(GL_GEOMETRY_PROGRAM_NV, geometry_enabled, current_state.geometry, - old_state.geometry); - update_state(GL_FRAGMENT_PROGRAM_NV, fragment_enabled, current_state.fragment, - old_state.fragment); +void ProgramManager::UseGeometryShader(GLuint program) { + if (use_assembly_programs) { + BindProgram(GL_GEOMETRY_PROGRAM_NV, program, current_state.vertex, geometry_enabled); + } + current_state.geometry = program; +} - old_state = current_state; +void ProgramManager::UseFragmentShader(GLuint program) { + if (use_assembly_programs) { + BindProgram(GL_FRAGMENT_PROGRAM_NV, program, current_state.vertex, fragment_enabled); + } + current_state.fragment = program; } void ProgramManager::UpdateSourcePrograms() { diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index 0f03b4f12..950e0dfcb 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h @@ -45,17 +45,9 @@ public: /// Rewinds BindHostPipeline state changes. void RestoreGuestPipeline(); - void UseVertexShader(GLuint program) { - current_state.vertex = program; - } - - void UseGeometryShader(GLuint program) { - current_state.geometry = program; - } - - void UseFragmentShader(GLuint program) { - current_state.fragment = program; - } + void UseVertexShader(GLuint program); + void UseGeometryShader(GLuint program); + void UseFragmentShader(GLuint program); private: struct PipelineState { @@ -64,9 +56,6 @@ private: GLuint fragment = 0; }; - /// Update NV_gpu_program5 programs. - void UpdateAssemblyPrograms(); - /// Update GLSL programs. void UpdateSourcePrograms(); diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.cpp b/src/video_core/renderer_opengl/gl_stream_buffer.cpp index 3655ff629..887995cf4 100644 --- a/src/video_core/renderer_opengl/gl_stream_buffer.cpp +++ b/src/video_core/renderer_opengl/gl_stream_buffer.cpp @@ -35,7 +35,7 @@ OGLStreamBuffer::OGLStreamBuffer(const Device& device, GLsizeiptr size, bool ver mapped_ptr = static_cast<u8*>( glMapNamedBufferRange(gl_buffer.handle, 0, buffer_size, flags | GL_MAP_FLUSH_EXPLICIT_BIT)); - if (device.HasVertexBufferUnifiedMemory()) { + if (device.UseAssemblyShaders() || device.HasVertexBufferUnifiedMemory()) { glMakeNamedBufferResidentNV(gl_buffer.handle, GL_READ_ONLY); glGetNamedBufferParameterui64vNV(gl_buffer.handle, GL_BUFFER_GPU_ADDRESS_NV, &gpu_address); } diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 61505879b..0a7bc9e2b 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp @@ -41,91 +41,103 @@ struct FormatTuple { }; constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format_tuples = {{ - {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV}, // ABGR8U - {GL_RGBA8_SNORM, GL_RGBA, GL_BYTE}, // ABGR8S - {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE}, // ABGR8UI - {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV}, // B5G6R5U - {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV}, // A2B10G10R10U - {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV}, // A1B5G5R5U - {GL_R8, GL_RED, GL_UNSIGNED_BYTE}, // R8U - {GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE}, // R8UI - {GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT}, // RGBA16F - {GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT}, // RGBA16U - {GL_RGBA16_SNORM, GL_RGBA, GL_SHORT}, // RGBA16S - {GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT}, // RGBA16UI - {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV}, // R11FG11FB10F - {GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT}, // RGBA32UI - {GL_COMPRESSED_RGBA_S3TC_DXT1_EXT}, // DXT1 - {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT}, // DXT23 - {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT}, // DXT45 - {GL_COMPRESSED_RED_RGTC1}, // DXN1 - {GL_COMPRESSED_RG_RGTC2}, // DXN2UNORM - {GL_COMPRESSED_SIGNED_RG_RGTC2}, // DXN2SNORM - {GL_COMPRESSED_RGBA_BPTC_UNORM}, // BC7U - {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT}, // BC6H_UF16 - {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT}, // BC6H_SF16 - {GL_COMPRESSED_RGBA_ASTC_4x4_KHR}, // ASTC_2D_4X4 - {GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE}, // BGRA8 - {GL_RGBA32F, GL_RGBA, GL_FLOAT}, // RGBA32F - {GL_RG32F, GL_RG, GL_FLOAT}, // RG32F - {GL_R32F, GL_RED, GL_FLOAT}, // R32F - {GL_R16F, GL_RED, GL_HALF_FLOAT}, // R16F - {GL_R16, GL_RED, GL_UNSIGNED_SHORT}, // R16U - {GL_R16_SNORM, GL_RED, GL_SHORT}, // R16S - {GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT}, // R16UI - {GL_R16I, GL_RED_INTEGER, GL_SHORT}, // R16I - {GL_RG16, GL_RG, GL_UNSIGNED_SHORT}, // RG16 - {GL_RG16F, GL_RG, GL_HALF_FLOAT}, // RG16F - {GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT}, // RG16UI - {GL_RG16I, GL_RG_INTEGER, GL_SHORT}, // RG16I - {GL_RG16_SNORM, GL_RG, GL_SHORT}, // RG16S - {GL_RGB32F, GL_RGB, GL_FLOAT}, // RGB32F - {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV}, // RGBA8_SRGB - {GL_RG8, GL_RG, GL_UNSIGNED_BYTE}, // RG8U - {GL_RG8_SNORM, GL_RG, GL_BYTE}, // RG8S - {GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_INT}, // RG8UI - {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT}, // RG32UI - {GL_RGB16F, GL_RGBA, GL_HALF_FLOAT}, // RGBX16F - {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT}, // R32UI - {GL_R32I, GL_RED_INTEGER, GL_INT}, // R32I - {GL_COMPRESSED_RGBA_ASTC_8x8_KHR}, // ASTC_2D_8X8 - {GL_COMPRESSED_RGBA_ASTC_8x5_KHR}, // ASTC_2D_8X5 - {GL_COMPRESSED_RGBA_ASTC_5x4_KHR}, // ASTC_2D_5X4 - {GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_BYTE}, // BGRA8 + {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV}, // A8B8G8R8_UNORM + {GL_RGBA8_SNORM, GL_RGBA, GL_BYTE}, // A8B8G8R8_SNORM + {GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE}, // A8B8G8R8_SINT + {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE}, // A8B8G8R8_UINT + {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, // R5G6B5_UNORM + {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV}, // B5G6R5_UNORM + {GL_RGB5_A1, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV}, // A1R5G5B5_UNORM + {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV}, // A2B10G10R10_UNORM + {GL_RGB10_A2UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV}, // A2B10G10R10_UINT + {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV}, // A1B5G5R5_UNORM + {GL_R8, GL_RED, GL_UNSIGNED_BYTE}, // R8_UNORM + {GL_R8_SNORM, GL_RED, GL_BYTE}, // R8_SNORM + {GL_R8I, GL_RED_INTEGER, GL_BYTE}, // R8_SINT + {GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE}, // R8_UINT + {GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT}, // R16G16B16A16_FLOAT + {GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT}, // R16G16B16A16_UNORM + {GL_RGBA16_SNORM, GL_RGBA, GL_SHORT}, // R16G16B16A16_SNORM + {GL_RGBA16I, GL_RGBA_INTEGER, GL_SHORT}, // R16G16B16A16_SINT + {GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT}, // R16G16B16A16_UINT + {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV}, // B10G11R11_FLOAT + {GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT}, // R32G32B32A32_UINT + {GL_COMPRESSED_RGBA_S3TC_DXT1_EXT}, // BC1_RGBA_UNORM + {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT}, // BC2_UNORM + {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT}, // BC3_UNORM + {GL_COMPRESSED_RED_RGTC1}, // BC4_UNORM + {GL_COMPRESSED_SIGNED_RED_RGTC1}, // BC4_SNORM + {GL_COMPRESSED_RG_RGTC2}, // BC5_UNORM + {GL_COMPRESSED_SIGNED_RG_RGTC2}, // BC5_SNORM + {GL_COMPRESSED_RGBA_BPTC_UNORM}, // BC7_UNORM + {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT}, // BC6H_UFLOAT + {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT}, // BC6H_SFLOAT + {GL_COMPRESSED_RGBA_ASTC_4x4_KHR}, // ASTC_2D_4X4_UNORM + {GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE}, // B8G8R8A8_UNORM + {GL_RGBA32F, GL_RGBA, GL_FLOAT}, // R32G32B32A32_FLOAT + {GL_RGBA32I, GL_RGBA_INTEGER, GL_INT}, // R32G32B32A32_SINT + {GL_RG32F, GL_RG, GL_FLOAT}, // R32G32_FLOAT + {GL_RG32I, GL_RG_INTEGER, GL_INT}, // R32G32_SINT + {GL_R32F, GL_RED, GL_FLOAT}, // R32_FLOAT + {GL_R16F, GL_RED, GL_HALF_FLOAT}, // R16_FLOAT + {GL_R16, GL_RED, GL_UNSIGNED_SHORT}, // R16_UNORM + {GL_R16_SNORM, GL_RED, GL_SHORT}, // R16_SNORM + {GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT}, // R16_UINT + {GL_R16I, GL_RED_INTEGER, GL_SHORT}, // R16_SINT + {GL_RG16, GL_RG, GL_UNSIGNED_SHORT}, // R16G16_UNORM + {GL_RG16F, GL_RG, GL_HALF_FLOAT}, // R16G16_FLOAT + {GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT}, // R16G16_UINT + {GL_RG16I, GL_RG_INTEGER, GL_SHORT}, // R16G16_SINT + {GL_RG16_SNORM, GL_RG, GL_SHORT}, // R16G16_SNORM + {GL_RGB32F, GL_RGB, GL_FLOAT}, // R32G32B32_FLOAT + {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV}, // A8B8G8R8_SRGB + {GL_RG8, GL_RG, GL_UNSIGNED_BYTE}, // R8G8_UNORM + {GL_RG8_SNORM, GL_RG, GL_BYTE}, // R8G8_SNORM + {GL_RG8I, GL_RG_INTEGER, GL_BYTE}, // R8G8_SINT + {GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE}, // R8G8_UINT + {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT}, // R32G32_UINT + {GL_RGB16F, GL_RGBA, GL_HALF_FLOAT}, // R16G16B16X16_FLOAT + {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT}, // R32_UINT + {GL_R32I, GL_RED_INTEGER, GL_INT}, // R32_SINT + {GL_COMPRESSED_RGBA_ASTC_8x8_KHR}, // ASTC_2D_8X8_UNORM + {GL_COMPRESSED_RGBA_ASTC_8x5_KHR}, // ASTC_2D_8X5_UNORM + {GL_COMPRESSED_RGBA_ASTC_5x4_KHR}, // ASTC_2D_5X4_UNORM + {GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_BYTE}, // B8G8R8A8_UNORM // Compressed sRGB formats - {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT}, // DXT1_SRGB - {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT}, // DXT23_SRGB - {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT}, // DXT45_SRGB - {GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM}, // BC7U_SRGB - {GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV}, // R4G4B4A4U + {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT}, // BC1_RGBA_SRGB + {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT}, // BC2_SRGB + {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT}, // BC3_SRGB + {GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM}, // BC7_SRGB + {GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV}, // A4B4G4R4_UNORM {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR}, // ASTC_2D_4X4_SRGB {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR}, // ASTC_2D_8X8_SRGB {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR}, // ASTC_2D_8X5_SRGB {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR}, // ASTC_2D_5X4_SRGB - {GL_COMPRESSED_RGBA_ASTC_5x5_KHR}, // ASTC_2D_5X5 + {GL_COMPRESSED_RGBA_ASTC_5x5_KHR}, // ASTC_2D_5X5_UNORM {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR}, // ASTC_2D_5X5_SRGB - {GL_COMPRESSED_RGBA_ASTC_10x8_KHR}, // ASTC_2D_10X8 + {GL_COMPRESSED_RGBA_ASTC_10x8_KHR}, // ASTC_2D_10X8_UNORM {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR}, // ASTC_2D_10X8_SRGB - {GL_COMPRESSED_RGBA_ASTC_6x6_KHR}, // ASTC_2D_6X6 + {GL_COMPRESSED_RGBA_ASTC_6x6_KHR}, // ASTC_2D_6X6_UNORM {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR}, // ASTC_2D_6X6_SRGB - {GL_COMPRESSED_RGBA_ASTC_10x10_KHR}, // ASTC_2D_10X10 + {GL_COMPRESSED_RGBA_ASTC_10x10_KHR}, // ASTC_2D_10X10_UNORM {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR}, // ASTC_2D_10X10_SRGB - {GL_COMPRESSED_RGBA_ASTC_12x12_KHR}, // ASTC_2D_12X12 + {GL_COMPRESSED_RGBA_ASTC_12x12_KHR}, // ASTC_2D_12X12_UNORM {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR}, // ASTC_2D_12X12_SRGB - {GL_COMPRESSED_RGBA_ASTC_8x6_KHR}, // ASTC_2D_8X6 + {GL_COMPRESSED_RGBA_ASTC_8x6_KHR}, // ASTC_2D_8X6_UNORM {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR}, // ASTC_2D_8X6_SRGB - {GL_COMPRESSED_RGBA_ASTC_6x5_KHR}, // ASTC_2D_6X5 + {GL_COMPRESSED_RGBA_ASTC_6x5_KHR}, // ASTC_2D_6X5_UNORM {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR}, // ASTC_2D_6X5_SRGB - {GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV}, // E5B9G9R9F + {GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV}, // E5B9G9R9_FLOAT // Depth formats - {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT}, // Z32F - {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // Z16 + {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT}, // D32_FLOAT + {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16_UNORM // DepthStencil formats - {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // Z24S8 - {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // S8Z24 - {GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV}, // Z32FS8 + {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // D24_UNORM_S8_UINT + {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // S8_UINT_D24_UNORM + {GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, + GL_FLOAT_32_UNSIGNED_INT_24_8_REV}, // D32_FLOAT_S8_UINT }}; const FormatTuple& GetFormatTuple(PixelFormat pixel_format) { @@ -178,10 +190,10 @@ GLint GetSwizzleSource(SwizzleSource source) { GLenum GetComponent(PixelFormat format, bool is_first) { switch (format) { - case PixelFormat::Z24S8: - case PixelFormat::Z32FS8: + case PixelFormat::D24_UNORM_S8_UINT: + case PixelFormat::D32_FLOAT_S8_UINT: return is_first ? GL_DEPTH_COMPONENT : GL_STENCIL_INDEX; - case PixelFormat::S8Z24: + case PixelFormat::S8_UINT_D24_UNORM: return is_first ? GL_STENCIL_INDEX : GL_DEPTH_COMPONENT; default: UNREACHABLE(); @@ -482,9 +494,9 @@ GLuint CachedSurfaceView::GetTexture(SwizzleSource x_source, SwizzleSource y_sou std::array swizzle{x_source, y_source, z_source, w_source}; switch (const PixelFormat format = GetSurfaceParams().pixel_format) { - case PixelFormat::Z24S8: - case PixelFormat::Z32FS8: - case PixelFormat::S8Z24: + case PixelFormat::D24_UNORM_S8_UINT: + case PixelFormat::D32_FLOAT_S8_UINT: + case PixelFormat::S8_UINT_D24_UNORM: UNIMPLEMENTED_IF(x_source != SwizzleSource::R && x_source != SwizzleSource::G); glTextureParameteri(view.handle, GL_DEPTH_STENCIL_TEXTURE_MODE, GetComponent(format, x_source == SwizzleSource::R)); diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index e66cdc083..52e9e8250 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -535,12 +535,12 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, GLint internal_format; switch (framebuffer.pixel_format) { - case Tegra::FramebufferConfig::PixelFormat::ABGR8: + case Tegra::FramebufferConfig::PixelFormat::A8B8G8R8_UNORM: internal_format = GL_RGBA8; texture.gl_format = GL_RGBA; texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; break; - case Tegra::FramebufferConfig::PixelFormat::RGB565: + case Tegra::FramebufferConfig::PixelFormat::RGB565_UNORM: internal_format = GL_RGB565; texture.gl_format = GL_RGB; texture.gl_type = GL_UNSIGNED_SHORT_5_6_5; diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp index d1f0ea932..81a39a3b8 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp @@ -40,7 +40,6 @@ constexpr std::array POLYGON_OFFSET_ENABLE_LUT = { } // Anonymous namespace void FixedPipelineState::Fill(const Maxwell& regs, bool has_extended_dynamic_state) { - const auto& clip = regs.view_volume_clip_control; const std::array enabled_lut = {regs.polygon_offset_point_enable, regs.polygon_offset_line_enable, regs.polygon_offset_fill_enable}; diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index d7f1ae89f..f8c77f4fa 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp @@ -117,90 +117,101 @@ struct FormatTuple { VkFormat format; ///< Vulkan format int usage = 0; ///< Describes image format usage } constexpr tex_format_tuples[] = { - {VK_FORMAT_A8B8G8R8_UNORM_PACK32, Attachable | Storage}, // ABGR8U - {VK_FORMAT_A8B8G8R8_SNORM_PACK32, Attachable | Storage}, // ABGR8S - {VK_FORMAT_A8B8G8R8_UINT_PACK32, Attachable | Storage}, // ABGR8UI - {VK_FORMAT_B5G6R5_UNORM_PACK16}, // B5G6R5U - {VK_FORMAT_A2B10G10R10_UNORM_PACK32, Attachable | Storage}, // A2B10G10R10U - {VK_FORMAT_A1R5G5B5_UNORM_PACK16, Attachable}, // A1B5G5R5U (flipped with swizzle) - {VK_FORMAT_R8_UNORM, Attachable | Storage}, // R8U - {VK_FORMAT_R8_UINT, Attachable | Storage}, // R8UI - {VK_FORMAT_R16G16B16A16_SFLOAT, Attachable | Storage}, // RGBA16F - {VK_FORMAT_R16G16B16A16_UNORM, Attachable | Storage}, // RGBA16U - {VK_FORMAT_R16G16B16A16_SNORM, Attachable | Storage}, // RGBA16S - {VK_FORMAT_R16G16B16A16_UINT, Attachable | Storage}, // RGBA16UI - {VK_FORMAT_B10G11R11_UFLOAT_PACK32, Attachable | Storage}, // R11FG11FB10F - {VK_FORMAT_R32G32B32A32_UINT, Attachable | Storage}, // RGBA32UI - {VK_FORMAT_BC1_RGBA_UNORM_BLOCK}, // DXT1 - {VK_FORMAT_BC2_UNORM_BLOCK}, // DXT23 - {VK_FORMAT_BC3_UNORM_BLOCK}, // DXT45 - {VK_FORMAT_BC4_UNORM_BLOCK}, // DXN1 - {VK_FORMAT_BC5_UNORM_BLOCK}, // DXN2UNORM - {VK_FORMAT_BC5_SNORM_BLOCK}, // DXN2SNORM - {VK_FORMAT_BC7_UNORM_BLOCK}, // BC7U - {VK_FORMAT_BC6H_UFLOAT_BLOCK}, // BC6H_UF16 - {VK_FORMAT_BC6H_SFLOAT_BLOCK}, // BC6H_SF16 - {VK_FORMAT_ASTC_4x4_UNORM_BLOCK}, // ASTC_2D_4X4 - {VK_FORMAT_B8G8R8A8_UNORM, Attachable}, // BGRA8 - {VK_FORMAT_R32G32B32A32_SFLOAT, Attachable | Storage}, // RGBA32F - {VK_FORMAT_R32G32_SFLOAT, Attachable | Storage}, // RG32F - {VK_FORMAT_R32_SFLOAT, Attachable | Storage}, // R32F - {VK_FORMAT_R16_SFLOAT, Attachable | Storage}, // R16F - {VK_FORMAT_R16_UNORM, Attachable | Storage}, // R16U - {VK_FORMAT_UNDEFINED}, // R16S - {VK_FORMAT_R16_UINT, Attachable | Storage}, // R16UI - {VK_FORMAT_UNDEFINED}, // R16I - {VK_FORMAT_R16G16_UNORM, Attachable | Storage}, // RG16 - {VK_FORMAT_R16G16_SFLOAT, Attachable | Storage}, // RG16F - {VK_FORMAT_UNDEFINED}, // RG16UI - {VK_FORMAT_UNDEFINED}, // RG16I - {VK_FORMAT_R16G16_SNORM, Attachable | Storage}, // RG16S - {VK_FORMAT_UNDEFINED}, // RGB32F - {VK_FORMAT_R8G8B8A8_SRGB, Attachable}, // RGBA8_SRGB - {VK_FORMAT_R8G8_UNORM, Attachable | Storage}, // RG8U - {VK_FORMAT_R8G8_SNORM, Attachable | Storage}, // RG8S - {VK_FORMAT_R8G8_UINT, Attachable | Storage}, // RG8UI - {VK_FORMAT_R32G32_UINT, Attachable | Storage}, // RG32UI - {VK_FORMAT_UNDEFINED}, // RGBX16F - {VK_FORMAT_R32_UINT, Attachable | Storage}, // R32UI - {VK_FORMAT_R32_SINT, Attachable | Storage}, // R32I - {VK_FORMAT_ASTC_8x8_UNORM_BLOCK}, // ASTC_2D_8X8 - {VK_FORMAT_UNDEFINED}, // ASTC_2D_8X5 - {VK_FORMAT_UNDEFINED}, // ASTC_2D_5X4 - {VK_FORMAT_B8G8R8A8_SRGB, Attachable}, // BGRA8_SRGB - {VK_FORMAT_BC1_RGBA_SRGB_BLOCK}, // DXT1_SRGB - {VK_FORMAT_BC2_SRGB_BLOCK}, // DXT23_SRGB - {VK_FORMAT_BC3_SRGB_BLOCK}, // DXT45_SRGB - {VK_FORMAT_BC7_SRGB_BLOCK}, // BC7U_SRGB - {VK_FORMAT_R4G4B4A4_UNORM_PACK16, Attachable}, // R4G4B4A4U - {VK_FORMAT_ASTC_4x4_SRGB_BLOCK}, // ASTC_2D_4X4_SRGB - {VK_FORMAT_ASTC_8x8_SRGB_BLOCK}, // ASTC_2D_8X8_SRGB - {VK_FORMAT_ASTC_8x5_SRGB_BLOCK}, // ASTC_2D_8X5_SRGB - {VK_FORMAT_ASTC_5x4_SRGB_BLOCK}, // ASTC_2D_5X4_SRGB - {VK_FORMAT_ASTC_5x5_UNORM_BLOCK}, // ASTC_2D_5X5 - {VK_FORMAT_ASTC_5x5_SRGB_BLOCK}, // ASTC_2D_5X5_SRGB - {VK_FORMAT_ASTC_10x8_UNORM_BLOCK}, // ASTC_2D_10X8 - {VK_FORMAT_ASTC_10x8_SRGB_BLOCK}, // ASTC_2D_10X8_SRGB - {VK_FORMAT_ASTC_6x6_UNORM_BLOCK}, // ASTC_2D_6X6 - {VK_FORMAT_ASTC_6x6_SRGB_BLOCK}, // ASTC_2D_6X6_SRGB - {VK_FORMAT_ASTC_10x10_UNORM_BLOCK}, // ASTC_2D_10X10 - {VK_FORMAT_ASTC_10x10_SRGB_BLOCK}, // ASTC_2D_10X10_SRGB - {VK_FORMAT_ASTC_12x12_UNORM_BLOCK}, // ASTC_2D_12X12 - {VK_FORMAT_ASTC_12x12_SRGB_BLOCK}, // ASTC_2D_12X12_SRGB - {VK_FORMAT_ASTC_8x6_UNORM_BLOCK}, // ASTC_2D_8X6 - {VK_FORMAT_ASTC_8x6_SRGB_BLOCK}, // ASTC_2D_8X6_SRGB - {VK_FORMAT_ASTC_6x5_UNORM_BLOCK}, // ASTC_2D_6X5 - {VK_FORMAT_ASTC_6x5_SRGB_BLOCK}, // ASTC_2D_6X5_SRGB - {VK_FORMAT_E5B9G9R9_UFLOAT_PACK32}, // E5B9G9R9F + {VK_FORMAT_A8B8G8R8_UNORM_PACK32, Attachable | Storage}, // A8B8G8R8_UNORM + {VK_FORMAT_A8B8G8R8_SNORM_PACK32, Attachable | Storage}, // A8B8G8R8_SNORM + {VK_FORMAT_A8B8G8R8_SINT_PACK32, Attachable | Storage}, // A8B8G8R8_SINT + {VK_FORMAT_A8B8G8R8_UINT_PACK32, Attachable | Storage}, // A8B8G8R8_UINT + {VK_FORMAT_R5G6B5_UNORM_PACK16, Attachable}, // R5G6B5_UNORM + {VK_FORMAT_B5G6R5_UNORM_PACK16, Attachable}, // B5G6R5_UNORM + {VK_FORMAT_A1R5G5B5_UNORM_PACK16, Attachable}, // A1R5G5B5_UNORM + {VK_FORMAT_A2B10G10R10_UNORM_PACK32, Attachable | Storage}, // A2B10G10R10_UNORM + {VK_FORMAT_A2B10G10R10_UINT_PACK32, Attachable | Storage}, // A2B10G10R10_UINT + {VK_FORMAT_A1R5G5B5_UNORM_PACK16, Attachable}, // A1B5G5R5_UNORM (flipped with swizzle) + {VK_FORMAT_R8_UNORM, Attachable | Storage}, // R8_UNORM + {VK_FORMAT_R8_SNORM, Attachable | Storage}, // R8_SNORM + {VK_FORMAT_R8_SINT, Attachable | Storage}, // R8_SINT + {VK_FORMAT_R8_UINT, Attachable | Storage}, // R8_UINT + {VK_FORMAT_R16G16B16A16_SFLOAT, Attachable | Storage}, // R16G16B16A16_FLOAT + {VK_FORMAT_R16G16B16A16_UNORM, Attachable | Storage}, // R16G16B16A16_UNORM + {VK_FORMAT_R16G16B16A16_SNORM, Attachable | Storage}, // R16G16B16A16_SNORM + {VK_FORMAT_R16G16B16A16_SINT, Attachable | Storage}, // R16G16B16A16_SINT + {VK_FORMAT_R16G16B16A16_UINT, Attachable | Storage}, // R16G16B16A16_UINT + {VK_FORMAT_B10G11R11_UFLOAT_PACK32, Attachable | Storage}, // B10G11R11_FLOAT + {VK_FORMAT_R32G32B32A32_UINT, Attachable | Storage}, // R32G32B32A32_UINT + {VK_FORMAT_BC1_RGBA_UNORM_BLOCK}, // BC1_RGBA_UNORM + {VK_FORMAT_BC2_UNORM_BLOCK}, // BC2_UNORM + {VK_FORMAT_BC3_UNORM_BLOCK}, // BC3_UNORM + {VK_FORMAT_BC4_UNORM_BLOCK}, // BC4_UNORM + {VK_FORMAT_BC4_SNORM_BLOCK}, // BC4_SNORM + {VK_FORMAT_BC5_UNORM_BLOCK}, // BC5_UNORM + {VK_FORMAT_BC5_SNORM_BLOCK}, // BC5_SNORM + {VK_FORMAT_BC7_UNORM_BLOCK}, // BC7_UNORM + {VK_FORMAT_BC6H_UFLOAT_BLOCK}, // BC6H_UFLOAT + {VK_FORMAT_BC6H_SFLOAT_BLOCK}, // BC6H_SFLOAT + {VK_FORMAT_ASTC_4x4_UNORM_BLOCK}, // ASTC_2D_4X4_UNORM + {VK_FORMAT_B8G8R8A8_UNORM, Attachable}, // B8G8R8A8_UNORM + {VK_FORMAT_R32G32B32A32_SFLOAT, Attachable | Storage}, // R32G32B32A32_FLOAT + {VK_FORMAT_R32G32B32A32_SINT, Attachable | Storage}, // R32G32B32A32_SINT + {VK_FORMAT_R32G32_SFLOAT, Attachable | Storage}, // R32G32_FLOAT + {VK_FORMAT_R32G32_SINT, Attachable | Storage}, // R32G32_SINT + {VK_FORMAT_R32_SFLOAT, Attachable | Storage}, // R32_FLOAT + {VK_FORMAT_R16_SFLOAT, Attachable | Storage}, // R16_FLOAT + {VK_FORMAT_R16_UNORM, Attachable | Storage}, // R16_UNORM + {VK_FORMAT_UNDEFINED}, // R16_SNORM + {VK_FORMAT_R16_UINT, Attachable | Storage}, // R16_UINT + {VK_FORMAT_UNDEFINED}, // R16_SINT + {VK_FORMAT_R16G16_UNORM, Attachable | Storage}, // R16G16_UNORM + {VK_FORMAT_R16G16_SFLOAT, Attachable | Storage}, // R16G16_FLOAT + {VK_FORMAT_UNDEFINED}, // R16G16_UINT + {VK_FORMAT_UNDEFINED}, // R16G16_SINT + {VK_FORMAT_R16G16_SNORM, Attachable | Storage}, // R16G16_SNORM + {VK_FORMAT_UNDEFINED}, // R32G32B32_FLOAT + {VK_FORMAT_R8G8B8A8_SRGB, Attachable}, // A8B8G8R8_SRGB + {VK_FORMAT_R8G8_UNORM, Attachable | Storage}, // R8G8_UNORM + {VK_FORMAT_R8G8_SNORM, Attachable | Storage}, // R8G8_SNORM + {VK_FORMAT_R8G8_SINT, Attachable | Storage}, // R8G8_SINT + {VK_FORMAT_R8G8_UINT, Attachable | Storage}, // R8G8_UINT + {VK_FORMAT_R32G32_UINT, Attachable | Storage}, // R32G32_UINT + {VK_FORMAT_UNDEFINED}, // R16G16B16X16_FLOAT + {VK_FORMAT_R32_UINT, Attachable | Storage}, // R32_UINT + {VK_FORMAT_R32_SINT, Attachable | Storage}, // R32_SINT + {VK_FORMAT_ASTC_8x8_UNORM_BLOCK}, // ASTC_2D_8X8_UNORM + {VK_FORMAT_UNDEFINED}, // ASTC_2D_8X5_UNORM + {VK_FORMAT_UNDEFINED}, // ASTC_2D_5X4_UNORM + {VK_FORMAT_B8G8R8A8_SRGB, Attachable}, // B8G8R8A8_SRGB + {VK_FORMAT_BC1_RGBA_SRGB_BLOCK}, // BC1_RGBA_SRGB + {VK_FORMAT_BC2_SRGB_BLOCK}, // BC2_SRGB + {VK_FORMAT_BC3_SRGB_BLOCK}, // BC3_SRGB + {VK_FORMAT_BC7_SRGB_BLOCK}, // BC7_SRGB + {VK_FORMAT_R4G4B4A4_UNORM_PACK16, Attachable}, // A4B4G4R4_UNORM + {VK_FORMAT_ASTC_4x4_SRGB_BLOCK}, // ASTC_2D_4X4_SRGB + {VK_FORMAT_ASTC_8x8_SRGB_BLOCK}, // ASTC_2D_8X8_SRGB + {VK_FORMAT_ASTC_8x5_SRGB_BLOCK}, // ASTC_2D_8X5_SRGB + {VK_FORMAT_ASTC_5x4_SRGB_BLOCK}, // ASTC_2D_5X4_SRGB + {VK_FORMAT_ASTC_5x5_UNORM_BLOCK}, // ASTC_2D_5X5_UNORM + {VK_FORMAT_ASTC_5x5_SRGB_BLOCK}, // ASTC_2D_5X5_SRGB + {VK_FORMAT_ASTC_10x8_UNORM_BLOCK}, // ASTC_2D_10X8_UNORM + {VK_FORMAT_ASTC_10x8_SRGB_BLOCK}, // ASTC_2D_10X8_SRGB + {VK_FORMAT_ASTC_6x6_UNORM_BLOCK}, // ASTC_2D_6X6_UNORM + {VK_FORMAT_ASTC_6x6_SRGB_BLOCK}, // ASTC_2D_6X6_SRGB + {VK_FORMAT_ASTC_10x10_UNORM_BLOCK}, // ASTC_2D_10X10_UNORM + {VK_FORMAT_ASTC_10x10_SRGB_BLOCK}, // ASTC_2D_10X10_SRGB + {VK_FORMAT_ASTC_12x12_UNORM_BLOCK}, // ASTC_2D_12X12_UNORM + {VK_FORMAT_ASTC_12x12_SRGB_BLOCK}, // ASTC_2D_12X12_SRGB + {VK_FORMAT_ASTC_8x6_UNORM_BLOCK}, // ASTC_2D_8X6_UNORM + {VK_FORMAT_ASTC_8x6_SRGB_BLOCK}, // ASTC_2D_8X6_SRGB + {VK_FORMAT_ASTC_6x5_UNORM_BLOCK}, // ASTC_2D_6X5_UNORM + {VK_FORMAT_ASTC_6x5_SRGB_BLOCK}, // ASTC_2D_6X5_SRGB + {VK_FORMAT_E5B9G9R9_UFLOAT_PACK32}, // E5B9G9R9_FLOAT // Depth formats - {VK_FORMAT_D32_SFLOAT, Attachable}, // Z32F - {VK_FORMAT_D16_UNORM, Attachable}, // Z16 + {VK_FORMAT_D32_SFLOAT, Attachable}, // D32_FLOAT + {VK_FORMAT_D16_UNORM, Attachable}, // D16_UNORM // DepthStencil formats - {VK_FORMAT_D24_UNORM_S8_UINT, Attachable}, // Z24S8 - {VK_FORMAT_D24_UNORM_S8_UINT, Attachable}, // S8Z24 (emulated) - {VK_FORMAT_D32_SFLOAT_S8_UINT, Attachable}, // Z32FS8 + {VK_FORMAT_D24_UNORM_S8_UINT, Attachable}, // D24_UNORM_S8_UINT + {VK_FORMAT_D24_UNORM_S8_UINT, Attachable}, // S8_UINT_D24_UNORM (emulated) + {VK_FORMAT_D32_SFLOAT_S8_UINT, Attachable}, // D32_FLOAT_S8_UINT }; static_assert(std::size(tex_format_tuples) == VideoCore::Surface::MaxPixelFormat); @@ -221,7 +232,7 @@ FormatInfo SurfaceFormat(const VKDevice& device, FormatType format_type, PixelFo return {VK_FORMAT_A8B8G8R8_UNORM_PACK32, true, true}; } - // Use ABGR8 on hardware that doesn't support ASTC natively + // Use A8B8G8R8_UNORM on hardware that doesn't support ASTC natively if (!device.IsOptimalAstcSupported() && VideoCore::Surface::IsPixelFormatASTC(pixel_format)) { tuple.format = VideoCore::Surface::IsPixelFormatSRGB(pixel_format) ? VK_FORMAT_A8B8G8R8_SRGB_PACK32 diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index fbd406f2b..ce53e5a6b 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -141,24 +141,28 @@ struct ScreenRectVertex { std::array<f32, 2> tex_coord; static VkVertexInputBindingDescription GetDescription() { - VkVertexInputBindingDescription description; - description.binding = 0; - description.stride = sizeof(ScreenRectVertex); - description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - return description; + return { + .binding = 0, + .stride = sizeof(ScreenRectVertex), + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, + }; } static std::array<VkVertexInputAttributeDescription, 2> GetAttributes() { - std::array<VkVertexInputAttributeDescription, 2> attributes; - attributes[0].location = 0; - attributes[0].binding = 0; - attributes[0].format = VK_FORMAT_R32G32_SFLOAT; - attributes[0].offset = offsetof(ScreenRectVertex, position); - attributes[1].location = 1; - attributes[1].binding = 0; - attributes[1].format = VK_FORMAT_R32G32_SFLOAT; - attributes[1].offset = offsetof(ScreenRectVertex, tex_coord); - return attributes; + return {{ + { + .location = 0, + .binding = 0, + .format = VK_FORMAT_R32G32_SFLOAT, + .offset = offsetof(ScreenRectVertex, position), + }, + { + .location = 1, + .binding = 0, + .format = VK_FORMAT_R32G32_SFLOAT, + .offset = offsetof(ScreenRectVertex, tex_coord), + }, + }}; } }; @@ -183,9 +187,9 @@ std::size_t GetSizeInBytes(const Tegra::FramebufferConfig& framebuffer) { VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) { switch (framebuffer.pixel_format) { - case Tegra::FramebufferConfig::PixelFormat::ABGR8: + case Tegra::FramebufferConfig::PixelFormat::A8B8G8R8_UNORM: return VK_FORMAT_A8B8G8R8_UNORM_PACK32; - case Tegra::FramebufferConfig::PixelFormat::RGB565: + case Tegra::FramebufferConfig::PixelFormat::RGB565_UNORM: return VK_FORMAT_R5G6B5_UNORM_PACK16; default: UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}", @@ -267,20 +271,25 @@ std::tuple<VKFence&, VkSemaphore> VKBlitScreen::Draw(const Tegra::FramebufferCon blit_image->Transition(0, 1, 0, 1, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - VkBufferImageCopy copy; - copy.bufferOffset = image_offset; - copy.bufferRowLength = 0; - copy.bufferImageHeight = 0; - copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copy.imageSubresource.mipLevel = 0; - copy.imageSubresource.baseArrayLayer = 0; - copy.imageSubresource.layerCount = 1; - copy.imageOffset.x = 0; - copy.imageOffset.y = 0; - copy.imageOffset.z = 0; - copy.imageExtent.width = framebuffer.width; - copy.imageExtent.height = framebuffer.height; - copy.imageExtent.depth = 1; + const VkBufferImageCopy copy{ + .bufferOffset = image_offset, + .bufferRowLength = 0, + .bufferImageHeight = 0, + .imageSubresource = + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1, + }, + .imageOffset = {.x = 0, .y = 0, .z = 0}, + .imageExtent = + { + .width = framebuffer.width, + .height = framebuffer.height, + .depth = 1, + }, + }; scheduler.Record( [buffer = *buffer, image = *blit_image->GetHandle(), copy](vk::CommandBuffer cmdbuf) { cmdbuf.CopyBufferToImage(buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy); @@ -295,11 +304,9 @@ std::tuple<VKFence&, VkSemaphore> VKBlitScreen::Draw(const Tegra::FramebufferCon descriptor_set = descriptor_sets[image_index], buffer = *buffer, size = swapchain.GetSize(), pipeline = *pipeline, layout = *pipeline_layout](vk::CommandBuffer cmdbuf) { - VkClearValue clear_color; - clear_color.color.float32[0] = 0.0f; - clear_color.color.float32[1] = 0.0f; - clear_color.color.float32[2] = 0.0f; - clear_color.color.float32[3] = 0.0f; + const VkClearValue clear_color{ + .color = {.float32 = {0.0f, 0.0f, 0.0f, 0.0f}}, + }; VkRenderPassBeginInfo renderpass_bi; renderpass_bi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; @@ -379,93 +386,109 @@ void VKBlitScreen::CreateSemaphores() { } void VKBlitScreen::CreateDescriptorPool() { - std::array<VkDescriptorPoolSize, 2> pool_sizes; - pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - pool_sizes[0].descriptorCount = static_cast<u32>(image_count); - pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - pool_sizes[1].descriptorCount = static_cast<u32>(image_count); - - VkDescriptorPoolCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - ci.maxSets = static_cast<u32>(image_count); - ci.poolSizeCount = static_cast<u32>(pool_sizes.size()); - ci.pPoolSizes = pool_sizes.data(); + const std::array<VkDescriptorPoolSize, 2> pool_sizes{{ + { + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = static_cast<u32>(image_count), + }, + { + .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .descriptorCount = static_cast<u32>(image_count), + }, + }}; + + const VkDescriptorPoolCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .pNext = nullptr, + .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, + .maxSets = static_cast<u32>(image_count), + .poolSizeCount = static_cast<u32>(pool_sizes.size()), + .pPoolSizes = pool_sizes.data(), + }; descriptor_pool = device.GetLogical().CreateDescriptorPool(ci); } void VKBlitScreen::CreateRenderPass() { - VkAttachmentDescription color_attachment; - color_attachment.flags = 0; - color_attachment.format = swapchain.GetImageFormat(); - color_attachment.samples = VK_SAMPLE_COUNT_1_BIT; - color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - - VkAttachmentReference color_attachment_ref; - color_attachment_ref.attachment = 0; - color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - VkSubpassDescription subpass_description; - subpass_description.flags = 0; - subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass_description.inputAttachmentCount = 0; - subpass_description.pInputAttachments = nullptr; - subpass_description.colorAttachmentCount = 1; - subpass_description.pColorAttachments = &color_attachment_ref; - subpass_description.pResolveAttachments = nullptr; - subpass_description.pDepthStencilAttachment = nullptr; - subpass_description.preserveAttachmentCount = 0; - subpass_description.pPreserveAttachments = nullptr; - - VkSubpassDependency dependency; - dependency.srcSubpass = VK_SUBPASS_EXTERNAL; - dependency.dstSubpass = 0; - dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.srcAccessMask = 0; - dependency.dstAccessMask = - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dependency.dependencyFlags = 0; - - VkRenderPassCreateInfo renderpass_ci; - renderpass_ci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - renderpass_ci.pNext = nullptr; - renderpass_ci.flags = 0; - renderpass_ci.attachmentCount = 1; - renderpass_ci.pAttachments = &color_attachment; - renderpass_ci.subpassCount = 1; - renderpass_ci.pSubpasses = &subpass_description; - renderpass_ci.dependencyCount = 1; - renderpass_ci.pDependencies = &dependency; + const VkAttachmentDescription color_attachment{ + .flags = 0, + .format = swapchain.GetImageFormat(), + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + }; + + const VkAttachmentReference color_attachment_ref{ + .attachment = 0, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + }; + + const VkSubpassDescription subpass_description{ + .flags = 0, + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .inputAttachmentCount = 0, + .pInputAttachments = nullptr, + .colorAttachmentCount = 1, + .pColorAttachments = &color_attachment_ref, + .pResolveAttachments = nullptr, + .pDepthStencilAttachment = nullptr, + .preserveAttachmentCount = 0, + .pPreserveAttachments = nullptr, + }; + + const VkSubpassDependency dependency{ + .srcSubpass = VK_SUBPASS_EXTERNAL, + .dstSubpass = 0, + .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .srcAccessMask = 0, + .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dependencyFlags = 0, + }; + + const VkRenderPassCreateInfo renderpass_ci{ + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .attachmentCount = 1, + .pAttachments = &color_attachment, + .subpassCount = 1, + .pSubpasses = &subpass_description, + .dependencyCount = 1, + .pDependencies = &dependency, + }; renderpass = device.GetLogical().CreateRenderPass(renderpass_ci); } void VKBlitScreen::CreateDescriptorSetLayout() { - std::array<VkDescriptorSetLayoutBinding, 2> layout_bindings; - layout_bindings[0].binding = 0; - layout_bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - layout_bindings[0].descriptorCount = 1; - layout_bindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - layout_bindings[0].pImmutableSamplers = nullptr; - layout_bindings[1].binding = 1; - layout_bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - layout_bindings[1].descriptorCount = 1; - layout_bindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - layout_bindings[1].pImmutableSamplers = nullptr; - - VkDescriptorSetLayoutCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.bindingCount = static_cast<u32>(layout_bindings.size()); - ci.pBindings = layout_bindings.data(); + const std::array<VkDescriptorSetLayoutBinding, 2> layout_bindings{{ + { + .binding = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, + .pImmutableSamplers = nullptr, + }, + { + .binding = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers = nullptr, + }, + }}; + + const VkDescriptorSetLayoutCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .bindingCount = static_cast<u32>(layout_bindings.size()), + .pBindings = layout_bindings.data(), + }; descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout(ci); } @@ -473,175 +496,192 @@ void VKBlitScreen::CreateDescriptorSetLayout() { void VKBlitScreen::CreateDescriptorSets() { const std::vector layouts(image_count, *descriptor_set_layout); - VkDescriptorSetAllocateInfo ai; - ai.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - ai.pNext = nullptr; - ai.descriptorPool = *descriptor_pool; - ai.descriptorSetCount = static_cast<u32>(image_count); - ai.pSetLayouts = layouts.data(); + const VkDescriptorSetAllocateInfo ai{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .pNext = nullptr, + .descriptorPool = *descriptor_pool, + .descriptorSetCount = static_cast<u32>(image_count), + .pSetLayouts = layouts.data(), + }; + descriptor_sets = descriptor_pool.Allocate(ai); } void VKBlitScreen::CreatePipelineLayout() { - VkPipelineLayoutCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.setLayoutCount = 1; - ci.pSetLayouts = descriptor_set_layout.address(); - ci.pushConstantRangeCount = 0; - ci.pPushConstantRanges = nullptr; + const VkPipelineLayoutCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .setLayoutCount = 1, + .pSetLayouts = descriptor_set_layout.address(), + .pushConstantRangeCount = 0, + .pPushConstantRanges = nullptr, + }; pipeline_layout = device.GetLogical().CreatePipelineLayout(ci); } void VKBlitScreen::CreateGraphicsPipeline() { - std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages; - shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - shader_stages[0].pNext = nullptr; - shader_stages[0].flags = 0; - shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; - shader_stages[0].module = *vertex_shader; - shader_stages[0].pName = "main"; - shader_stages[0].pSpecializationInfo = nullptr; - shader_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - shader_stages[1].pNext = nullptr; - shader_stages[1].flags = 0; - shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; - shader_stages[1].module = *fragment_shader; - shader_stages[1].pName = "main"; - shader_stages[1].pSpecializationInfo = nullptr; + const std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages{{ + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .module = *vertex_shader, + .pName = "main", + .pSpecializationInfo = nullptr, + }, + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + .module = *fragment_shader, + .pName = "main", + .pSpecializationInfo = nullptr, + }, + }}; const auto vertex_binding_description = ScreenRectVertex::GetDescription(); const auto vertex_attrs_description = ScreenRectVertex::GetAttributes(); - VkPipelineVertexInputStateCreateInfo vertex_input_ci; - vertex_input_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertex_input_ci.pNext = nullptr; - vertex_input_ci.flags = 0; - vertex_input_ci.vertexBindingDescriptionCount = 1; - vertex_input_ci.pVertexBindingDescriptions = &vertex_binding_description; - vertex_input_ci.vertexAttributeDescriptionCount = u32{vertex_attrs_description.size()}; - vertex_input_ci.pVertexAttributeDescriptions = vertex_attrs_description.data(); - - VkPipelineInputAssemblyStateCreateInfo input_assembly_ci; - input_assembly_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - input_assembly_ci.pNext = nullptr; - input_assembly_ci.flags = 0; - input_assembly_ci.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; - input_assembly_ci.primitiveRestartEnable = VK_FALSE; - - VkPipelineViewportStateCreateInfo viewport_state_ci; - viewport_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewport_state_ci.pNext = nullptr; - viewport_state_ci.flags = 0; - viewport_state_ci.viewportCount = 1; - viewport_state_ci.pViewports = nullptr; - viewport_state_ci.scissorCount = 1; - viewport_state_ci.pScissors = nullptr; - - VkPipelineRasterizationStateCreateInfo rasterization_ci; - rasterization_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterization_ci.pNext = nullptr; - rasterization_ci.flags = 0; - rasterization_ci.depthClampEnable = VK_FALSE; - rasterization_ci.rasterizerDiscardEnable = VK_FALSE; - rasterization_ci.polygonMode = VK_POLYGON_MODE_FILL; - rasterization_ci.cullMode = VK_CULL_MODE_NONE; - rasterization_ci.frontFace = VK_FRONT_FACE_CLOCKWISE; - rasterization_ci.depthBiasEnable = VK_FALSE; - rasterization_ci.depthBiasConstantFactor = 0.0f; - rasterization_ci.depthBiasClamp = 0.0f; - rasterization_ci.depthBiasSlopeFactor = 0.0f; - rasterization_ci.lineWidth = 1.0f; - - VkPipelineMultisampleStateCreateInfo multisampling_ci; - multisampling_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampling_ci.pNext = nullptr; - multisampling_ci.flags = 0; - multisampling_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - multisampling_ci.sampleShadingEnable = VK_FALSE; - multisampling_ci.minSampleShading = 0.0f; - multisampling_ci.pSampleMask = nullptr; - multisampling_ci.alphaToCoverageEnable = VK_FALSE; - multisampling_ci.alphaToOneEnable = VK_FALSE; - - VkPipelineColorBlendAttachmentState color_blend_attachment; - color_blend_attachment.blendEnable = VK_FALSE; - color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ZERO; - color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; - color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; - color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; - color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | - VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - - VkPipelineColorBlendStateCreateInfo color_blend_ci; - color_blend_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - color_blend_ci.flags = 0; - color_blend_ci.pNext = nullptr; - color_blend_ci.logicOpEnable = VK_FALSE; - color_blend_ci.logicOp = VK_LOGIC_OP_COPY; - color_blend_ci.attachmentCount = 1; - color_blend_ci.pAttachments = &color_blend_attachment; - color_blend_ci.blendConstants[0] = 0.0f; - color_blend_ci.blendConstants[1] = 0.0f; - color_blend_ci.blendConstants[2] = 0.0f; - color_blend_ci.blendConstants[3] = 0.0f; - - static constexpr std::array dynamic_states = {VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR}; - VkPipelineDynamicStateCreateInfo dynamic_state_ci; - dynamic_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamic_state_ci.pNext = nullptr; - dynamic_state_ci.flags = 0; - dynamic_state_ci.dynamicStateCount = static_cast<u32>(dynamic_states.size()); - dynamic_state_ci.pDynamicStates = dynamic_states.data(); - - VkGraphicsPipelineCreateInfo pipeline_ci; - pipeline_ci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipeline_ci.pNext = nullptr; - pipeline_ci.flags = 0; - pipeline_ci.stageCount = static_cast<u32>(shader_stages.size()); - pipeline_ci.pStages = shader_stages.data(); - pipeline_ci.pVertexInputState = &vertex_input_ci; - pipeline_ci.pInputAssemblyState = &input_assembly_ci; - pipeline_ci.pTessellationState = nullptr; - pipeline_ci.pViewportState = &viewport_state_ci; - pipeline_ci.pRasterizationState = &rasterization_ci; - pipeline_ci.pMultisampleState = &multisampling_ci; - pipeline_ci.pDepthStencilState = nullptr; - pipeline_ci.pColorBlendState = &color_blend_ci; - pipeline_ci.pDynamicState = &dynamic_state_ci; - pipeline_ci.layout = *pipeline_layout; - pipeline_ci.renderPass = *renderpass; - pipeline_ci.subpass = 0; - pipeline_ci.basePipelineHandle = 0; - pipeline_ci.basePipelineIndex = 0; + const VkPipelineVertexInputStateCreateInfo vertex_input_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .vertexBindingDescriptionCount = 1, + .pVertexBindingDescriptions = &vertex_binding_description, + .vertexAttributeDescriptionCount = u32{vertex_attrs_description.size()}, + .pVertexAttributeDescriptions = vertex_attrs_description.data(), + }; + + const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, + .primitiveRestartEnable = VK_FALSE, + }; + + const VkPipelineViewportStateCreateInfo viewport_state_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .viewportCount = 1, + .pViewports = nullptr, + .scissorCount = 1, + .pScissors = nullptr, + }; + + const VkPipelineRasterizationStateCreateInfo rasterization_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .depthClampEnable = VK_FALSE, + .rasterizerDiscardEnable = VK_FALSE, + .polygonMode = VK_POLYGON_MODE_FILL, + .cullMode = VK_CULL_MODE_NONE, + .frontFace = VK_FRONT_FACE_CLOCKWISE, + .depthBiasEnable = VK_FALSE, + .depthBiasConstantFactor = 0.0f, + .depthBiasClamp = 0.0f, + .depthBiasSlopeFactor = 0.0f, + .lineWidth = 1.0f, + }; + + const VkPipelineMultisampleStateCreateInfo multisampling_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, + .sampleShadingEnable = VK_FALSE, + .minSampleShading = 0.0f, + .pSampleMask = nullptr, + .alphaToCoverageEnable = VK_FALSE, + .alphaToOneEnable = VK_FALSE, + }; + + const VkPipelineColorBlendAttachmentState color_blend_attachment{ + .blendEnable = VK_FALSE, + .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO, + .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, + .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, + .alphaBlendOp = VK_BLEND_OP_ADD, + .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, + }; + + const VkPipelineColorBlendStateCreateInfo color_blend_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .logicOpEnable = VK_FALSE, + .logicOp = VK_LOGIC_OP_COPY, + .attachmentCount = 1, + .pAttachments = &color_blend_attachment, + .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, + }; + + static constexpr std::array dynamic_states{ + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + }; + const VkPipelineDynamicStateCreateInfo dynamic_state_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .dynamicStateCount = static_cast<u32>(dynamic_states.size()), + .pDynamicStates = dynamic_states.data(), + }; + + const VkGraphicsPipelineCreateInfo pipeline_ci{ + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .stageCount = static_cast<u32>(shader_stages.size()), + .pStages = shader_stages.data(), + .pVertexInputState = &vertex_input_ci, + .pInputAssemblyState = &input_assembly_ci, + .pTessellationState = nullptr, + .pViewportState = &viewport_state_ci, + .pRasterizationState = &rasterization_ci, + .pMultisampleState = &multisampling_ci, + .pDepthStencilState = nullptr, + .pColorBlendState = &color_blend_ci, + .pDynamicState = &dynamic_state_ci, + .layout = *pipeline_layout, + .renderPass = *renderpass, + .subpass = 0, + .basePipelineHandle = 0, + .basePipelineIndex = 0, + }; pipeline = device.GetLogical().CreateGraphicsPipeline(pipeline_ci); } void VKBlitScreen::CreateSampler() { - VkSamplerCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.magFilter = VK_FILTER_LINEAR; - ci.minFilter = VK_FILTER_NEAREST; - ci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - ci.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - ci.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - ci.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - ci.mipLodBias = 0.0f; - ci.anisotropyEnable = VK_FALSE; - ci.maxAnisotropy = 0.0f; - ci.compareEnable = VK_FALSE; - ci.compareOp = VK_COMPARE_OP_NEVER; - ci.minLod = 0.0f; - ci.maxLod = 0.0f; - ci.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; - ci.unnormalizedCoordinates = VK_FALSE; + const VkSamplerCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .magFilter = VK_FILTER_LINEAR, + .minFilter = VK_FILTER_NEAREST, + .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, + .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, + .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, + .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, + .mipLodBias = 0.0f, + .anisotropyEnable = VK_FALSE, + .maxAnisotropy = 0.0f, + .compareEnable = VK_FALSE, + .compareOp = VK_COMPARE_OP_NEVER, + .minLod = 0.0f, + .maxLod = 0.0f, + .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK, + .unnormalizedCoordinates = VK_FALSE, + }; sampler = device.GetLogical().CreateSampler(ci); } @@ -650,15 +690,16 @@ void VKBlitScreen::CreateFramebuffers() { const VkExtent2D size{swapchain.GetSize()}; framebuffers.resize(image_count); - VkFramebufferCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.renderPass = *renderpass; - ci.attachmentCount = 1; - ci.width = size.width; - ci.height = size.height; - ci.layers = 1; + VkFramebufferCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .renderPass = *renderpass, + .attachmentCount = 1, + .width = size.width, + .height = size.height, + .layers = 1, + }; for (std::size_t i = 0; i < image_count; ++i) { const VkImageView image_view{swapchain.GetImageViewIndex(i)}; @@ -678,16 +719,17 @@ void VKBlitScreen::ReleaseRawImages() { } void VKBlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { - VkBufferCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.size = CalculateBufferSize(framebuffer); - ci.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - ci.queueFamilyIndexCount = 0; - ci.pQueueFamilyIndices = nullptr; + const VkBufferCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .size = CalculateBufferSize(framebuffer), + .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + }; buffer = device.GetLogical().CreateBuffer(ci); buffer_commit = memory_manager.Commit(buffer, true); @@ -697,24 +739,28 @@ void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) raw_images.resize(image_count); raw_buffer_commits.resize(image_count); - VkImageCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.imageType = VK_IMAGE_TYPE_2D; - ci.format = GetFormat(framebuffer); - ci.extent.width = framebuffer.width; - ci.extent.height = framebuffer.height; - ci.extent.depth = 1; - ci.mipLevels = 1; - ci.arrayLayers = 1; - ci.samples = VK_SAMPLE_COUNT_1_BIT; - ci.tiling = VK_IMAGE_TILING_LINEAR; - ci.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - ci.queueFamilyIndexCount = 0; - ci.pQueueFamilyIndices = nullptr; - ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + const VkImageCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .imageType = VK_IMAGE_TYPE_2D, + .format = GetFormat(framebuffer), + .extent = + { + .width = framebuffer.width, + .height = framebuffer.height, + .depth = 1, + }, + .mipLevels = 1, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_LINEAR, + .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }; for (std::size_t i = 0; i < image_count; ++i) { raw_images[i] = std::make_unique<VKImage>(device, scheduler, ci, VK_IMAGE_ASPECT_COLOR_BIT); @@ -723,39 +769,43 @@ void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) } void VKBlitScreen::UpdateDescriptorSet(std::size_t image_index, VkImageView image_view) const { - VkDescriptorBufferInfo buffer_info; - buffer_info.buffer = *buffer; - buffer_info.offset = offsetof(BufferData, uniform); - buffer_info.range = sizeof(BufferData::uniform); - - VkWriteDescriptorSet ubo_write; - ubo_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - ubo_write.pNext = nullptr; - ubo_write.dstSet = descriptor_sets[image_index]; - ubo_write.dstBinding = 0; - ubo_write.dstArrayElement = 0; - ubo_write.descriptorCount = 1; - ubo_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - ubo_write.pImageInfo = nullptr; - ubo_write.pBufferInfo = &buffer_info; - ubo_write.pTexelBufferView = nullptr; - - VkDescriptorImageInfo image_info; - image_info.sampler = *sampler; - image_info.imageView = image_view; - image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - VkWriteDescriptorSet sampler_write; - sampler_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - sampler_write.pNext = nullptr; - sampler_write.dstSet = descriptor_sets[image_index]; - sampler_write.dstBinding = 1; - sampler_write.dstArrayElement = 0; - sampler_write.descriptorCount = 1; - sampler_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - sampler_write.pImageInfo = &image_info; - sampler_write.pBufferInfo = nullptr; - sampler_write.pTexelBufferView = nullptr; + const VkDescriptorBufferInfo buffer_info{ + .buffer = *buffer, + .offset = offsetof(BufferData, uniform), + .range = sizeof(BufferData::uniform), + }; + + const VkWriteDescriptorSet ubo_write{ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = nullptr, + .dstSet = descriptor_sets[image_index], + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .pImageInfo = nullptr, + .pBufferInfo = &buffer_info, + .pTexelBufferView = nullptr, + }; + + const VkDescriptorImageInfo image_info{ + .sampler = *sampler, + .imageView = image_view, + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }; + + const VkWriteDescriptorSet sampler_write{ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = nullptr, + .dstSet = descriptor_sets[image_index], + .dstBinding = 1, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .pImageInfo = &image_info, + .pBufferInfo = nullptr, + .pTexelBufferView = nullptr, + }; device.GetLogical().UpdateDescriptorSets(std::array{ubo_write, sampler_write}, {}); } diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 2be38d419..1d2f8b557 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -39,16 +39,17 @@ std::unique_ptr<VKStreamBuffer> CreateStreamBuffer(const VKDevice& device, VKSch Buffer::Buffer(const VKDevice& device, VKMemoryManager& memory_manager, VKScheduler& scheduler_, VKStagingBufferPool& staging_pool_, VAddr cpu_addr, std::size_t size) - : VideoCommon::BufferBlock{cpu_addr, size}, scheduler{scheduler_}, staging_pool{staging_pool_} { - VkBufferCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.size = static_cast<VkDeviceSize>(size); - ci.usage = BUFFER_USAGE | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - ci.queueFamilyIndexCount = 0; - ci.pQueueFamilyIndices = nullptr; + : BufferBlock{cpu_addr, size}, scheduler{scheduler_}, staging_pool{staging_pool_} { + const VkBufferCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .size = static_cast<VkDeviceSize>(size), + .usage = BUFFER_USAGE | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + }; buffer.handle = device.GetLogical().CreateBuffer(ci); buffer.commit = memory_manager.Commit(buffer.handle, false); @@ -66,16 +67,17 @@ void Buffer::Upload(std::size_t offset, std::size_t size, const u8* data) { scheduler.Record([staging = *staging.handle, handle, offset, size](vk::CommandBuffer cmdbuf) { cmdbuf.CopyBuffer(staging, handle, VkBufferCopy{0, offset, size}); - VkBufferMemoryBarrier barrier; - barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; - barrier.pNext = nullptr; - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstAccessMask = UPLOAD_ACCESS_BARRIERS; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.buffer = handle; - barrier.offset = offset; - barrier.size = size; + const VkBufferMemoryBarrier barrier{ + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = UPLOAD_ACCESS_BARRIERS, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = handle, + .offset = offset, + .size = size, + }; cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, UPLOAD_PIPELINE_STAGE, 0, {}, barrier, {}); }); @@ -87,16 +89,17 @@ void Buffer::Download(std::size_t offset, std::size_t size, u8* data) { const VkBuffer handle = Handle(); scheduler.Record([staging = *staging.handle, handle, offset, size](vk::CommandBuffer cmdbuf) { - VkBufferMemoryBarrier barrier; - barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; - barrier.pNext = nullptr; - barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.buffer = handle; - barrier.offset = offset; - barrier.size = size; + const VkBufferMemoryBarrier barrier{ + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = handle, + .offset = offset, + .size = size, + }; cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp index da71e710c..182461ed9 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp @@ -115,32 +115,32 @@ constexpr u8 quad_array[] = { 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00}; VkDescriptorSetLayoutBinding BuildQuadArrayPassDescriptorSetLayoutBinding() { - VkDescriptorSetLayoutBinding binding; - binding.binding = 0; - binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - binding.descriptorCount = 1; - binding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - binding.pImmutableSamplers = nullptr; - return binding; + return { + .binding = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, + .pImmutableSamplers = nullptr, + }; } VkDescriptorUpdateTemplateEntryKHR BuildQuadArrayPassDescriptorUpdateTemplateEntry() { - VkDescriptorUpdateTemplateEntryKHR entry; - entry.dstBinding = 0; - entry.dstArrayElement = 0; - entry.descriptorCount = 1; - entry.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - entry.offset = 0; - entry.stride = sizeof(DescriptorUpdateEntry); - return entry; + return { + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .offset = 0, + .stride = sizeof(DescriptorUpdateEntry), + }; } VkPushConstantRange BuildComputePushConstantRange(std::size_t size) { - VkPushConstantRange range; - range.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - range.offset = 0; - range.size = static_cast<u32>(size); - return range; + return { + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, + .offset = 0, + .size = static_cast<u32>(size), + }; } // Uint8 SPIR-V module. Generated from the "shaders/" directory. @@ -344,29 +344,33 @@ constexpr u8 QUAD_INDEXED_SPV[] = { 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00}; std::array<VkDescriptorSetLayoutBinding, 2> BuildInputOutputDescriptorSetBindings() { - std::array<VkDescriptorSetLayoutBinding, 2> bindings; - bindings[0].binding = 0; - bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - bindings[0].descriptorCount = 1; - bindings[0].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - bindings[0].pImmutableSamplers = nullptr; - bindings[1].binding = 1; - bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - bindings[1].descriptorCount = 1; - bindings[1].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - bindings[1].pImmutableSamplers = nullptr; - return bindings; + return {{ + { + .binding = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, + .pImmutableSamplers = nullptr, + }, + { + .binding = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, + .pImmutableSamplers = nullptr, + }, + }}; } VkDescriptorUpdateTemplateEntryKHR BuildInputOutputDescriptorUpdateTemplate() { - VkDescriptorUpdateTemplateEntryKHR entry; - entry.dstBinding = 0; - entry.dstArrayElement = 0; - entry.descriptorCount = 2; - entry.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - entry.offset = 0; - entry.stride = sizeof(DescriptorUpdateEntry); - return entry; + return { + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorCount = 2, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .offset = 0, + .stride = sizeof(DescriptorUpdateEntry), + }; } } // Anonymous namespace @@ -376,37 +380,37 @@ VKComputePass::VKComputePass(const VKDevice& device, VKDescriptorPool& descripto vk::Span<VkDescriptorUpdateTemplateEntryKHR> templates, vk::Span<VkPushConstantRange> push_constants, std::size_t code_size, const u8* code) { - VkDescriptorSetLayoutCreateInfo descriptor_layout_ci; - descriptor_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - descriptor_layout_ci.pNext = nullptr; - descriptor_layout_ci.flags = 0; - descriptor_layout_ci.bindingCount = bindings.size(); - descriptor_layout_ci.pBindings = bindings.data(); - descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout(descriptor_layout_ci); - - VkPipelineLayoutCreateInfo pipeline_layout_ci; - pipeline_layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipeline_layout_ci.pNext = nullptr; - pipeline_layout_ci.flags = 0; - pipeline_layout_ci.setLayoutCount = 1; - pipeline_layout_ci.pSetLayouts = descriptor_set_layout.address(); - pipeline_layout_ci.pushConstantRangeCount = push_constants.size(); - pipeline_layout_ci.pPushConstantRanges = push_constants.data(); - layout = device.GetLogical().CreatePipelineLayout(pipeline_layout_ci); + descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout({ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .bindingCount = bindings.size(), + .pBindings = bindings.data(), + }); + + layout = device.GetLogical().CreatePipelineLayout({ + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .setLayoutCount = 1, + .pSetLayouts = descriptor_set_layout.address(), + .pushConstantRangeCount = push_constants.size(), + .pPushConstantRanges = push_constants.data(), + }); if (!templates.empty()) { - VkDescriptorUpdateTemplateCreateInfoKHR template_ci; - template_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR; - template_ci.pNext = nullptr; - template_ci.flags = 0; - template_ci.descriptorUpdateEntryCount = templates.size(); - template_ci.pDescriptorUpdateEntries = templates.data(); - template_ci.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR; - template_ci.descriptorSetLayout = *descriptor_set_layout; - template_ci.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - template_ci.pipelineLayout = *layout; - template_ci.set = 0; - descriptor_template = device.GetLogical().CreateDescriptorUpdateTemplateKHR(template_ci); + descriptor_template = device.GetLogical().CreateDescriptorUpdateTemplateKHR({ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR, + .pNext = nullptr, + .flags = 0, + .descriptorUpdateEntryCount = templates.size(), + .pDescriptorUpdateEntries = templates.data(), + .templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR, + .descriptorSetLayout = *descriptor_set_layout, + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .pipelineLayout = *layout, + .set = 0, + }); descriptor_allocator.emplace(descriptor_pool, *descriptor_set_layout); } @@ -414,32 +418,32 @@ VKComputePass::VKComputePass(const VKDevice& device, VKDescriptorPool& descripto auto code_copy = std::make_unique<u32[]>(code_size / sizeof(u32) + 1); std::memcpy(code_copy.get(), code, code_size); - VkShaderModuleCreateInfo module_ci; - module_ci.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - module_ci.pNext = nullptr; - module_ci.flags = 0; - module_ci.codeSize = code_size; - module_ci.pCode = code_copy.get(); - module = device.GetLogical().CreateShaderModule(module_ci); - - VkComputePipelineCreateInfo pipeline_ci; - pipeline_ci.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; - pipeline_ci.pNext = nullptr; - pipeline_ci.flags = 0; - pipeline_ci.layout = *layout; - pipeline_ci.basePipelineHandle = nullptr; - pipeline_ci.basePipelineIndex = 0; - - VkPipelineShaderStageCreateInfo& stage_ci = pipeline_ci.stage; - stage_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stage_ci.pNext = nullptr; - stage_ci.flags = 0; - stage_ci.stage = VK_SHADER_STAGE_COMPUTE_BIT; - stage_ci.module = *module; - stage_ci.pName = "main"; - stage_ci.pSpecializationInfo = nullptr; - - pipeline = device.GetLogical().CreateComputePipeline(pipeline_ci); + module = device.GetLogical().CreateShaderModule({ + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .codeSize = code_size, + .pCode = code_copy.get(), + }); + + pipeline = device.GetLogical().CreateComputePipeline({ + .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .stage = + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .stage = VK_SHADER_STAGE_COMPUTE_BIT, + .module = *module, + .pName = "main", + .pSpecializationInfo = nullptr, + }, + .layout = *layout, + .basePipelineHandle = nullptr, + .basePipelineIndex = 0, + }); } VKComputePass::~VKComputePass() = default; diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index 281bf9ac3..ed9d2991c 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -43,12 +43,13 @@ vk::DescriptorSetLayout VKComputePipeline::CreateDescriptorSetLayout() const { const auto add_bindings = [&](VkDescriptorType descriptor_type, std::size_t num_entries) { // TODO(Rodrigo): Maybe make individual bindings here? for (u32 bindpoint = 0; bindpoint < static_cast<u32>(num_entries); ++bindpoint) { - VkDescriptorSetLayoutBinding& entry = bindings.emplace_back(); - entry.binding = binding++; - entry.descriptorType = descriptor_type; - entry.descriptorCount = 1; - entry.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - entry.pImmutableSamplers = nullptr; + bindings.push_back({ + .binding = binding++, + .descriptorType = descriptor_type, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, + .pImmutableSamplers = nullptr, + }); } }; add_bindings(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, entries.const_buffers.size()); @@ -58,25 +59,25 @@ vk::DescriptorSetLayout VKComputePipeline::CreateDescriptorSetLayout() const { add_bindings(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, entries.storage_texels.size()); add_bindings(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, entries.images.size()); - VkDescriptorSetLayoutCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.bindingCount = static_cast<u32>(bindings.size()); - ci.pBindings = bindings.data(); - return device.GetLogical().CreateDescriptorSetLayout(ci); + return device.GetLogical().CreateDescriptorSetLayout({ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .bindingCount = static_cast<u32>(bindings.size()), + .pBindings = bindings.data(), + }); } vk::PipelineLayout VKComputePipeline::CreatePipelineLayout() const { - VkPipelineLayoutCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.setLayoutCount = 1; - ci.pSetLayouts = descriptor_set_layout.address(); - ci.pushConstantRangeCount = 0; - ci.pPushConstantRanges = nullptr; - return device.GetLogical().CreatePipelineLayout(ci); + return device.GetLogical().CreatePipelineLayout({ + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .setLayoutCount = 1, + .pSetLayouts = descriptor_set_layout.address(), + .pushConstantRangeCount = 0, + .pPushConstantRanges = nullptr, + }); } vk::DescriptorUpdateTemplateKHR VKComputePipeline::CreateDescriptorUpdateTemplate() const { @@ -89,59 +90,63 @@ vk::DescriptorUpdateTemplateKHR VKComputePipeline::CreateDescriptorUpdateTemplat return {}; } - VkDescriptorUpdateTemplateCreateInfoKHR ci; - ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR; - ci.pNext = nullptr; - ci.flags = 0; - ci.descriptorUpdateEntryCount = static_cast<u32>(template_entries.size()); - ci.pDescriptorUpdateEntries = template_entries.data(); - ci.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR; - ci.descriptorSetLayout = *descriptor_set_layout; - ci.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - ci.pipelineLayout = *layout; - ci.set = DESCRIPTOR_SET; - return device.GetLogical().CreateDescriptorUpdateTemplateKHR(ci); + return device.GetLogical().CreateDescriptorUpdateTemplateKHR({ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR, + .pNext = nullptr, + .flags = 0, + .descriptorUpdateEntryCount = static_cast<u32>(template_entries.size()), + .pDescriptorUpdateEntries = template_entries.data(), + .templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR, + .descriptorSetLayout = *descriptor_set_layout, + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .pipelineLayout = *layout, + .set = DESCRIPTOR_SET, + }); } vk::ShaderModule VKComputePipeline::CreateShaderModule(const std::vector<u32>& code) const { device.SaveShader(code); - VkShaderModuleCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.codeSize = code.size() * sizeof(u32); - ci.pCode = code.data(); - return device.GetLogical().CreateShaderModule(ci); + return device.GetLogical().CreateShaderModule({ + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .codeSize = code.size() * sizeof(u32), + .pCode = code.data(), + }); } vk::Pipeline VKComputePipeline::CreatePipeline() const { - VkComputePipelineCreateInfo ci; - VkPipelineShaderStageCreateInfo& stage_ci = ci.stage; - stage_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stage_ci.pNext = nullptr; - stage_ci.flags = 0; - stage_ci.stage = VK_SHADER_STAGE_COMPUTE_BIT; - stage_ci.module = *shader_module; - stage_ci.pName = "main"; - stage_ci.pSpecializationInfo = nullptr; - - VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT subgroup_size_ci; - subgroup_size_ci.sType = - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT; - subgroup_size_ci.pNext = nullptr; - subgroup_size_ci.requiredSubgroupSize = GuestWarpSize; + + VkComputePipelineCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .stage = + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .stage = VK_SHADER_STAGE_COMPUTE_BIT, + .module = *shader_module, + .pName = "main", + .pSpecializationInfo = nullptr, + }, + .layout = *layout, + .basePipelineHandle = nullptr, + .basePipelineIndex = 0, + }; + + const VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT subgroup_size_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT, + .pNext = nullptr, + .requiredSubgroupSize = GuestWarpSize, + }; if (entries.uses_warps && device.IsGuestWarpSizeSupported(VK_SHADER_STAGE_COMPUTE_BIT)) { - stage_ci.pNext = &subgroup_size_ci; + ci.stage.pNext = &subgroup_size_ci; } - ci.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.layout = *layout; - ci.basePipelineHandle = nullptr; - ci.basePipelineIndex = 0; return device.GetLogical().CreateComputePipeline(ci); } diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp index 9259b618d..ac4a0884e 100644 --- a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp @@ -43,27 +43,30 @@ vk::DescriptorPool* VKDescriptorPool::AllocateNewPool() { {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, num_sets * 64}, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, num_sets * 64}, {VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, num_sets * 64}, - {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, num_sets * 40}}; - - VkDescriptorPoolCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - ci.maxSets = num_sets; - ci.poolSizeCount = static_cast<u32>(std::size(pool_sizes)); - ci.pPoolSizes = std::data(pool_sizes); + {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, num_sets * 40}, + }; + + const VkDescriptorPoolCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .pNext = nullptr, + .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, + .maxSets = num_sets, + .poolSizeCount = static_cast<u32>(std::size(pool_sizes)), + .pPoolSizes = std::data(pool_sizes), + }; return &pools.emplace_back(device.GetLogical().CreateDescriptorPool(ci)); } vk::DescriptorSets VKDescriptorPool::AllocateDescriptors(VkDescriptorSetLayout layout, std::size_t count) { const std::vector layout_copies(count, layout); - VkDescriptorSetAllocateInfo ai; - ai.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - ai.pNext = nullptr; - ai.descriptorPool = **active_pool; - ai.descriptorSetCount = static_cast<u32>(count); - ai.pSetLayouts = layout_copies.data(); + VkDescriptorSetAllocateInfo ai{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .pNext = nullptr, + .descriptorPool = **active_pool, + .descriptorSetCount = static_cast<u32>(count), + .pSetLayouts = layout_copies.data(), + }; vk::DescriptorSets sets = active_pool->Allocate(ai); if (!sets.IsOutOfPoolMemory()) { diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp index fdaea4210..6245e0d78 100644 --- a/src/video_core/renderer_vulkan/vk_device.cpp +++ b/src/video_core/renderer_vulkan/vk_device.cpp @@ -22,14 +22,21 @@ namespace { namespace Alternatives { -constexpr std::array Depth24UnormS8_UINT = {VK_FORMAT_D32_SFLOAT_S8_UINT, - VK_FORMAT_D16_UNORM_S8_UINT, VkFormat{}}; -constexpr std::array Depth16UnormS8_UINT = {VK_FORMAT_D24_UNORM_S8_UINT, - VK_FORMAT_D32_SFLOAT_S8_UINT, VkFormat{}}; +constexpr std::array Depth24UnormS8_UINT{ + VK_FORMAT_D32_SFLOAT_S8_UINT, + VK_FORMAT_D16_UNORM_S8_UINT, + VkFormat{}, +}; + +constexpr std::array Depth16UnormS8_UINT{ + VK_FORMAT_D24_UNORM_S8_UINT, + VK_FORMAT_D32_SFLOAT_S8_UINT, + VkFormat{}, +}; } // namespace Alternatives -constexpr std::array REQUIRED_EXTENSIONS = { +constexpr std::array REQUIRED_EXTENSIONS{ VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_KHR_16BIT_STORAGE_EXTENSION_NAME, VK_KHR_8BIT_STORAGE_EXTENSION_NAME, @@ -77,14 +84,19 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties( VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_FORMAT_A8B8G8R8_UINT_PACK32, VK_FORMAT_A8B8G8R8_SNORM_PACK32, + VK_FORMAT_A8B8G8R8_SINT_PACK32, VK_FORMAT_A8B8G8R8_SRGB_PACK32, VK_FORMAT_B5G6R5_UNORM_PACK16, VK_FORMAT_A2B10G10R10_UNORM_PACK32, + VK_FORMAT_A2B10G10R10_UINT_PACK32, VK_FORMAT_A1R5G5B5_UNORM_PACK16, VK_FORMAT_R32G32B32A32_SFLOAT, + VK_FORMAT_R32G32B32A32_SINT, VK_FORMAT_R32G32B32A32_UINT, VK_FORMAT_R32G32_SFLOAT, + VK_FORMAT_R32G32_SINT, VK_FORMAT_R32G32_UINT, + VK_FORMAT_R16G16B16A16_SINT, VK_FORMAT_R16G16B16A16_UINT, VK_FORMAT_R16G16B16A16_SNORM, VK_FORMAT_R16G16B16A16_UNORM, @@ -96,8 +108,11 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties( VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_R8G8_UNORM, VK_FORMAT_R8G8_SNORM, + VK_FORMAT_R8G8_SINT, VK_FORMAT_R8G8_UINT, VK_FORMAT_R8_UNORM, + VK_FORMAT_R8_SNORM, + VK_FORMAT_R8_SINT, VK_FORMAT_R8_UINT, VK_FORMAT_B10G11R11_UFLOAT_PACK32, VK_FORMAT_R32_SFLOAT, @@ -117,6 +132,7 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties( VK_FORMAT_BC2_UNORM_BLOCK, VK_FORMAT_BC3_UNORM_BLOCK, VK_FORMAT_BC4_UNORM_BLOCK, + VK_FORMAT_BC4_SNORM_BLOCK, VK_FORMAT_BC5_UNORM_BLOCK, VK_FORMAT_BC5_SNORM_BLOCK, VK_FORMAT_BC7_UNORM_BLOCK, @@ -169,97 +185,104 @@ bool VKDevice::Create() { const auto queue_cis = GetDeviceQueueCreateInfos(); const std::vector extensions = LoadExtensions(); - VkPhysicalDeviceFeatures2 features2; - features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features2.pNext = nullptr; + VkPhysicalDeviceFeatures2 features2{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, + .pNext = nullptr, + }; const void* first_next = &features2; void** next = &features2.pNext; - auto& features = features2.features; - features.robustBufferAccess = false; - features.fullDrawIndexUint32 = false; - features.imageCubeArray = false; - features.independentBlend = true; - features.geometryShader = true; - features.tessellationShader = true; - features.sampleRateShading = false; - features.dualSrcBlend = false; - features.logicOp = false; - features.multiDrawIndirect = false; - features.drawIndirectFirstInstance = false; - features.depthClamp = true; - features.depthBiasClamp = true; - features.fillModeNonSolid = false; - features.depthBounds = false; - features.wideLines = false; - features.largePoints = true; - features.alphaToOne = false; - features.multiViewport = true; - features.samplerAnisotropy = true; - features.textureCompressionETC2 = false; - features.textureCompressionASTC_LDR = is_optimal_astc_supported; - features.textureCompressionBC = false; - features.occlusionQueryPrecise = true; - features.pipelineStatisticsQuery = false; - features.vertexPipelineStoresAndAtomics = true; - features.fragmentStoresAndAtomics = true; - features.shaderTessellationAndGeometryPointSize = false; - features.shaderImageGatherExtended = true; - features.shaderStorageImageExtendedFormats = false; - features.shaderStorageImageMultisample = false; - features.shaderStorageImageReadWithoutFormat = is_formatless_image_load_supported; - features.shaderStorageImageWriteWithoutFormat = true; - features.shaderUniformBufferArrayDynamicIndexing = false; - features.shaderSampledImageArrayDynamicIndexing = false; - features.shaderStorageBufferArrayDynamicIndexing = false; - features.shaderStorageImageArrayDynamicIndexing = false; - features.shaderClipDistance = false; - features.shaderCullDistance = false; - features.shaderFloat64 = false; - features.shaderInt64 = false; - features.shaderInt16 = false; - features.shaderResourceResidency = false; - features.shaderResourceMinLod = false; - features.sparseBinding = false; - features.sparseResidencyBuffer = false; - features.sparseResidencyImage2D = false; - features.sparseResidencyImage3D = false; - features.sparseResidency2Samples = false; - features.sparseResidency4Samples = false; - features.sparseResidency8Samples = false; - features.sparseResidency16Samples = false; - features.sparseResidencyAliased = false; - features.variableMultisampleRate = false; - features.inheritedQueries = false; - - VkPhysicalDevice16BitStorageFeaturesKHR bit16_storage; - bit16_storage.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR; - bit16_storage.pNext = nullptr; - bit16_storage.storageBuffer16BitAccess = false; - bit16_storage.uniformAndStorageBuffer16BitAccess = true; - bit16_storage.storagePushConstant16 = false; - bit16_storage.storageInputOutput16 = false; + features2.features = { + .robustBufferAccess = false, + .fullDrawIndexUint32 = false, + .imageCubeArray = false, + .independentBlend = true, + .geometryShader = true, + .tessellationShader = true, + .sampleRateShading = false, + .dualSrcBlend = false, + .logicOp = false, + .multiDrawIndirect = false, + .drawIndirectFirstInstance = false, + .depthClamp = true, + .depthBiasClamp = true, + .fillModeNonSolid = false, + .depthBounds = false, + .wideLines = false, + .largePoints = true, + .alphaToOne = false, + .multiViewport = true, + .samplerAnisotropy = true, + .textureCompressionETC2 = false, + .textureCompressionASTC_LDR = is_optimal_astc_supported, + .textureCompressionBC = false, + .occlusionQueryPrecise = true, + .pipelineStatisticsQuery = false, + .vertexPipelineStoresAndAtomics = true, + .fragmentStoresAndAtomics = true, + .shaderTessellationAndGeometryPointSize = false, + .shaderImageGatherExtended = true, + .shaderStorageImageExtendedFormats = false, + .shaderStorageImageMultisample = false, + .shaderStorageImageReadWithoutFormat = is_formatless_image_load_supported, + .shaderStorageImageWriteWithoutFormat = true, + .shaderUniformBufferArrayDynamicIndexing = false, + .shaderSampledImageArrayDynamicIndexing = false, + .shaderStorageBufferArrayDynamicIndexing = false, + .shaderStorageImageArrayDynamicIndexing = false, + .shaderClipDistance = false, + .shaderCullDistance = false, + .shaderFloat64 = false, + .shaderInt64 = false, + .shaderInt16 = false, + .shaderResourceResidency = false, + .shaderResourceMinLod = false, + .sparseBinding = false, + .sparseResidencyBuffer = false, + .sparseResidencyImage2D = false, + .sparseResidencyImage3D = false, + .sparseResidency2Samples = false, + .sparseResidency4Samples = false, + .sparseResidency8Samples = false, + .sparseResidency16Samples = false, + .sparseResidencyAliased = false, + .variableMultisampleRate = false, + .inheritedQueries = false, + }; + + VkPhysicalDevice16BitStorageFeaturesKHR bit16_storage{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR, + .pNext = nullptr, + .storageBuffer16BitAccess = false, + .uniformAndStorageBuffer16BitAccess = true, + .storagePushConstant16 = false, + .storageInputOutput16 = false, + }; SetNext(next, bit16_storage); - VkPhysicalDevice8BitStorageFeaturesKHR bit8_storage; - bit8_storage.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR; - bit8_storage.pNext = nullptr; - bit8_storage.storageBuffer8BitAccess = false; - bit8_storage.uniformAndStorageBuffer8BitAccess = true; - bit8_storage.storagePushConstant8 = false; + VkPhysicalDevice8BitStorageFeaturesKHR bit8_storage{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR, + .pNext = nullptr, + .storageBuffer8BitAccess = false, + .uniformAndStorageBuffer8BitAccess = true, + .storagePushConstant8 = false, + }; SetNext(next, bit8_storage); - VkPhysicalDeviceHostQueryResetFeaturesEXT host_query_reset; - host_query_reset.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT; - host_query_reset.hostQueryReset = true; + VkPhysicalDeviceHostQueryResetFeaturesEXT host_query_reset{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT, + .hostQueryReset = true, + }; SetNext(next, host_query_reset); VkPhysicalDeviceFloat16Int8FeaturesKHR float16_int8; if (is_float16_supported) { - float16_int8.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR; - float16_int8.pNext = nullptr; - float16_int8.shaderFloat16 = true; - float16_int8.shaderInt8 = false; + float16_int8 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR, + .pNext = nullptr, + .shaderFloat16 = true, + .shaderInt8 = false, + }; SetNext(next, float16_int8); } else { LOG_INFO(Render_Vulkan, "Device doesn't support float16 natively"); @@ -271,10 +294,11 @@ bool VKDevice::Create() { VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR std430_layout; if (khr_uniform_buffer_standard_layout) { - std430_layout.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR; - std430_layout.pNext = nullptr; - std430_layout.uniformBufferStandardLayout = true; + std430_layout = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR, + .pNext = nullptr, + .uniformBufferStandardLayout = true, + }; SetNext(next, std430_layout); } else { LOG_INFO(Render_Vulkan, "Device doesn't support packed UBOs"); @@ -282,9 +306,11 @@ bool VKDevice::Create() { VkPhysicalDeviceIndexTypeUint8FeaturesEXT index_type_uint8; if (ext_index_type_uint8) { - index_type_uint8.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT; - index_type_uint8.pNext = nullptr; - index_type_uint8.indexTypeUint8 = true; + index_type_uint8 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT, + .pNext = nullptr, + .indexTypeUint8 = true, + }; SetNext(next, index_type_uint8); } else { LOG_INFO(Render_Vulkan, "Device doesn't support uint8 indexes"); @@ -292,11 +318,12 @@ bool VKDevice::Create() { VkPhysicalDeviceTransformFeedbackFeaturesEXT transform_feedback; if (ext_transform_feedback) { - transform_feedback.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT; - transform_feedback.pNext = nullptr; - transform_feedback.transformFeedback = true; - transform_feedback.geometryStreams = true; + transform_feedback = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT, + .pNext = nullptr, + .transformFeedback = true, + .geometryStreams = true, + }; SetNext(next, transform_feedback); } else { LOG_INFO(Render_Vulkan, "Device doesn't support transform feedbacks"); @@ -304,10 +331,12 @@ bool VKDevice::Create() { VkPhysicalDeviceCustomBorderColorFeaturesEXT custom_border; if (ext_custom_border_color) { - custom_border.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT; - custom_border.pNext = nullptr; - custom_border.customBorderColors = VK_TRUE; - custom_border.customBorderColorWithoutFormat = VK_TRUE; + custom_border = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT, + .pNext = nullptr, + .customBorderColors = VK_TRUE, + .customBorderColorWithoutFormat = VK_TRUE, + }; SetNext(next, custom_border); } else { LOG_INFO(Render_Vulkan, "Device doesn't support custom border colors"); @@ -315,9 +344,11 @@ bool VKDevice::Create() { VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynamic_state; if (ext_extended_dynamic_state) { - dynamic_state.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; - dynamic_state.pNext = nullptr; - dynamic_state.extendedDynamicState = VK_TRUE; + dynamic_state = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT, + .pNext = nullptr, + .extendedDynamicState = VK_TRUE, + }; SetNext(next, dynamic_state); } else { LOG_INFO(Render_Vulkan, "Device doesn't support extended dynamic state"); @@ -331,11 +362,13 @@ bool VKDevice::Create() { if (nv_device_diagnostics_config) { nsight_aftermath_tracker.Initialize(); - diagnostics_nv.sType = VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV; - diagnostics_nv.pNext = &features2; - diagnostics_nv.flags = VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV | - VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV | - VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV; + diagnostics_nv = { + .sType = VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV, + .pNext = &features2, + .flags = VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV | + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV | + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV, + }; first_next = &diagnostics_nv; } @@ -704,13 +737,15 @@ void VKDevice::SetupFeatures() { } void VKDevice::CollectTelemetryParameters() { - VkPhysicalDeviceDriverPropertiesKHR driver; - driver.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR; - driver.pNext = nullptr; + VkPhysicalDeviceDriverPropertiesKHR driver{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR, + .pNext = nullptr, + }; - VkPhysicalDeviceProperties2KHR properties; - properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR; - properties.pNext = &driver; + VkPhysicalDeviceProperties2KHR properties{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR, + .pNext = &driver, + }; physical.GetProperties2KHR(properties); driver_id = driver.driverID; @@ -719,22 +754,24 @@ void VKDevice::CollectTelemetryParameters() { const std::vector extensions = physical.EnumerateDeviceExtensionProperties(); reported_extensions.reserve(std::size(extensions)); for (const auto& extension : extensions) { - reported_extensions.push_back(extension.extensionName); + reported_extensions.emplace_back(extension.extensionName); } } std::vector<VkDeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() const { static constexpr float QUEUE_PRIORITY = 1.0f; - std::unordered_set<u32> unique_queue_families = {graphics_family, present_family}; + std::unordered_set<u32> unique_queue_families{graphics_family, present_family}; std::vector<VkDeviceQueueCreateInfo> queue_cis; + queue_cis.reserve(unique_queue_families.size()); for (const u32 queue_family : unique_queue_families) { - VkDeviceQueueCreateInfo& ci = queue_cis.emplace_back(); - ci.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.queueFamilyIndex = queue_family; + auto& ci = queue_cis.emplace_back(VkDeviceQueueCreateInfo{ + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .queueFamilyIndex = queue_family, + }); ci.queueCount = 1; ci.pQueuePriorities = &QUEUE_PRIORITY; } diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h index ae5c21baa..529744f2d 100644 --- a/src/video_core/renderer_vulkan/vk_device.h +++ b/src/video_core/renderer_vulkan/vk_device.h @@ -122,6 +122,11 @@ public: return properties.limits.maxPushConstantsSize; } + /// Returns the maximum size for shared memory. + u32 GetMaxComputeSharedMemorySize() const { + return properties.limits.maxComputeSharedMemorySize; + } + /// Returns true if ASTC is natively supported. bool IsOptimalAstcSupported() const { return is_optimal_astc_supported; diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 844445105..aaf930b90 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -28,15 +28,15 @@ namespace { template <class StencilFace> VkStencilOpState GetStencilFaceState(const StencilFace& face) { - VkStencilOpState state; - state.failOp = MaxwellToVK::StencilOp(face.ActionStencilFail()); - state.passOp = MaxwellToVK::StencilOp(face.ActionDepthPass()); - state.depthFailOp = MaxwellToVK::StencilOp(face.ActionDepthFail()); - state.compareOp = MaxwellToVK::ComparisonOp(face.TestFunc()); - state.compareMask = 0; - state.writeMask = 0; - state.reference = 0; - return state; + return { + .failOp = MaxwellToVK::StencilOp(face.ActionStencilFail()), + .passOp = MaxwellToVK::StencilOp(face.ActionDepthPass()), + .depthFailOp = MaxwellToVK::StencilOp(face.ActionDepthFail()), + .compareOp = MaxwellToVK::ComparisonOp(face.TestFunc()), + .compareMask = 0, + .writeMask = 0, + .reference = 0, + }; } bool SupportsPrimitiveRestart(VkPrimitiveTopology topology) { @@ -52,20 +52,21 @@ bool SupportsPrimitiveRestart(VkPrimitiveTopology topology) { } VkViewportSwizzleNV UnpackViewportSwizzle(u16 swizzle) { - union { + union Swizzle { u32 raw; BitField<0, 3, Maxwell::ViewportSwizzle> x; BitField<4, 3, Maxwell::ViewportSwizzle> y; BitField<8, 3, Maxwell::ViewportSwizzle> z; BitField<12, 3, Maxwell::ViewportSwizzle> w; - } const unpacked{swizzle}; - - VkViewportSwizzleNV result; - result.x = MaxwellToVK::ViewportSwizzle(unpacked.x); - result.y = MaxwellToVK::ViewportSwizzle(unpacked.y); - result.z = MaxwellToVK::ViewportSwizzle(unpacked.z); - result.w = MaxwellToVK::ViewportSwizzle(unpacked.w); - return result; + }; + const Swizzle unpacked{swizzle}; + + return { + .x = MaxwellToVK::ViewportSwizzle(unpacked.x), + .y = MaxwellToVK::ViewportSwizzle(unpacked.y), + .z = MaxwellToVK::ViewportSwizzle(unpacked.z), + .w = MaxwellToVK::ViewportSwizzle(unpacked.w), + }; } } // Anonymous namespace @@ -100,24 +101,26 @@ VkDescriptorSet VKGraphicsPipeline::CommitDescriptorSet() { vk::DescriptorSetLayout VKGraphicsPipeline::CreateDescriptorSetLayout( vk::Span<VkDescriptorSetLayoutBinding> bindings) const { - VkDescriptorSetLayoutCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.bindingCount = bindings.size(); - ci.pBindings = bindings.data(); + const VkDescriptorSetLayoutCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .bindingCount = bindings.size(), + .pBindings = bindings.data(), + }; return device.GetLogical().CreateDescriptorSetLayout(ci); } vk::PipelineLayout VKGraphicsPipeline::CreatePipelineLayout() const { - VkPipelineLayoutCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.setLayoutCount = 1; - ci.pSetLayouts = descriptor_set_layout.address(); - ci.pushConstantRangeCount = 0; - ci.pPushConstantRanges = nullptr; + const VkPipelineLayoutCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .setLayoutCount = 1, + .pSetLayouts = descriptor_set_layout.address(), + .pushConstantRangeCount = 0, + .pPushConstantRanges = nullptr, + }; return device.GetLogical().CreatePipelineLayout(ci); } @@ -136,26 +139,28 @@ vk::DescriptorUpdateTemplateKHR VKGraphicsPipeline::CreateDescriptorUpdateTempla return {}; } - VkDescriptorUpdateTemplateCreateInfoKHR ci; - ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR; - ci.pNext = nullptr; - ci.flags = 0; - ci.descriptorUpdateEntryCount = static_cast<u32>(template_entries.size()); - ci.pDescriptorUpdateEntries = template_entries.data(); - ci.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR; - ci.descriptorSetLayout = *descriptor_set_layout; - ci.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - ci.pipelineLayout = *layout; - ci.set = DESCRIPTOR_SET; + const VkDescriptorUpdateTemplateCreateInfoKHR ci{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR, + .pNext = nullptr, + .flags = 0, + .descriptorUpdateEntryCount = static_cast<u32>(template_entries.size()), + .pDescriptorUpdateEntries = template_entries.data(), + .templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR, + .descriptorSetLayout = *descriptor_set_layout, + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .pipelineLayout = *layout, + .set = DESCRIPTOR_SET, + }; return device.GetLogical().CreateDescriptorUpdateTemplateKHR(ci); } std::vector<vk::ShaderModule> VKGraphicsPipeline::CreateShaderModules( const SPIRVProgram& program) const { - VkShaderModuleCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; + VkShaderModuleCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + }; std::vector<vk::ShaderModule> modules; modules.reserve(Maxwell::MaxShaderStage); @@ -204,15 +209,17 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa const bool instanced = state.binding_divisors[index] != 0; const auto rate = instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; - auto& vertex_binding = vertex_bindings.emplace_back(); - vertex_binding.binding = static_cast<u32>(index); - vertex_binding.stride = binding.stride; - vertex_binding.inputRate = rate; + vertex_bindings.push_back({ + .binding = static_cast<u32>(index), + .stride = binding.stride, + .inputRate = rate, + }); if (instanced) { - auto& binding_divisor = vertex_binding_divisors.emplace_back(); - binding_divisor.binding = static_cast<u32>(index); - binding_divisor.divisor = state.binding_divisors[index]; + vertex_binding_divisors.push_back({ + .binding = static_cast<u32>(index), + .divisor = state.binding_divisors[index], + }); } } @@ -227,116 +234,132 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa // Skip attributes not used by the vertex shaders. continue; } - auto& vertex_attribute = vertex_attributes.emplace_back(); - vertex_attribute.location = static_cast<u32>(index); - vertex_attribute.binding = attribute.buffer; - vertex_attribute.format = MaxwellToVK::VertexFormat(attribute.Type(), attribute.Size()); - vertex_attribute.offset = attribute.offset; + vertex_attributes.push_back({ + .location = static_cast<u32>(index), + .binding = attribute.buffer, + .format = MaxwellToVK::VertexFormat(attribute.Type(), attribute.Size()), + .offset = attribute.offset, + }); } - VkPipelineVertexInputStateCreateInfo vertex_input_ci; - vertex_input_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertex_input_ci.pNext = nullptr; - vertex_input_ci.flags = 0; - vertex_input_ci.vertexBindingDescriptionCount = static_cast<u32>(vertex_bindings.size()); - vertex_input_ci.pVertexBindingDescriptions = vertex_bindings.data(); - vertex_input_ci.vertexAttributeDescriptionCount = static_cast<u32>(vertex_attributes.size()); - vertex_input_ci.pVertexAttributeDescriptions = vertex_attributes.data(); - - VkPipelineVertexInputDivisorStateCreateInfoEXT input_divisor_ci; - input_divisor_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT; - input_divisor_ci.pNext = nullptr; - input_divisor_ci.vertexBindingDivisorCount = static_cast<u32>(vertex_binding_divisors.size()); - input_divisor_ci.pVertexBindingDivisors = vertex_binding_divisors.data(); + VkPipelineVertexInputStateCreateInfo vertex_input_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .vertexBindingDescriptionCount = static_cast<u32>(vertex_bindings.size()), + .pVertexBindingDescriptions = vertex_bindings.data(), + .vertexAttributeDescriptionCount = static_cast<u32>(vertex_attributes.size()), + .pVertexAttributeDescriptions = vertex_attributes.data(), + }; + + const VkPipelineVertexInputDivisorStateCreateInfoEXT input_divisor_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT, + .pNext = nullptr, + .vertexBindingDivisorCount = static_cast<u32>(vertex_binding_divisors.size()), + .pVertexBindingDivisors = vertex_binding_divisors.data(), + }; if (!vertex_binding_divisors.empty()) { vertex_input_ci.pNext = &input_divisor_ci; } - VkPipelineInputAssemblyStateCreateInfo input_assembly_ci; - input_assembly_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - input_assembly_ci.pNext = nullptr; - input_assembly_ci.flags = 0; - input_assembly_ci.topology = MaxwellToVK::PrimitiveTopology(device, dynamic.Topology()); - input_assembly_ci.primitiveRestartEnable = - state.primitive_restart_enable != 0 && SupportsPrimitiveRestart(input_assembly_ci.topology); - - VkPipelineTessellationStateCreateInfo tessellation_ci; - tessellation_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; - tessellation_ci.pNext = nullptr; - tessellation_ci.flags = 0; - tessellation_ci.patchControlPoints = state.patch_control_points_minus_one.Value() + 1; - - VkPipelineViewportStateCreateInfo viewport_ci; - viewport_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewport_ci.pNext = nullptr; - viewport_ci.flags = 0; - viewport_ci.viewportCount = Maxwell::NumViewports; - viewport_ci.pViewports = nullptr; - viewport_ci.scissorCount = Maxwell::NumViewports; - viewport_ci.pScissors = nullptr; + const auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, dynamic.Topology()); + const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .topology = MaxwellToVK::PrimitiveTopology(device, dynamic.Topology()), + .primitiveRestartEnable = state.primitive_restart_enable != 0 && + SupportsPrimitiveRestart(input_assembly_topology), + }; + + const VkPipelineTessellationStateCreateInfo tessellation_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .patchControlPoints = state.patch_control_points_minus_one.Value() + 1, + }; + + VkPipelineViewportStateCreateInfo viewport_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .viewportCount = Maxwell::NumViewports, + .pViewports = nullptr, + .scissorCount = Maxwell::NumViewports, + .pScissors = nullptr, + }; std::array<VkViewportSwizzleNV, Maxwell::NumViewports> swizzles; std::transform(viewport_swizzles.begin(), viewport_swizzles.end(), swizzles.begin(), UnpackViewportSwizzle); - VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci; - swizzle_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV; - swizzle_ci.pNext = nullptr; - swizzle_ci.flags = 0; - swizzle_ci.viewportCount = Maxwell::NumViewports; - swizzle_ci.pViewportSwizzles = swizzles.data(); + VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV, + .pNext = nullptr, + .flags = 0, + .viewportCount = Maxwell::NumViewports, + .pViewportSwizzles = swizzles.data(), + }; if (device.IsNvViewportSwizzleSupported()) { viewport_ci.pNext = &swizzle_ci; } - VkPipelineRasterizationStateCreateInfo rasterization_ci; - rasterization_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterization_ci.pNext = nullptr; - rasterization_ci.flags = 0; - rasterization_ci.depthClampEnable = state.depth_clamp_disabled == 0 ? VK_TRUE : VK_FALSE; - rasterization_ci.rasterizerDiscardEnable = state.rasterize_enable == 0 ? VK_TRUE : VK_FALSE; - rasterization_ci.polygonMode = VK_POLYGON_MODE_FILL; - rasterization_ci.cullMode = - dynamic.cull_enable ? MaxwellToVK::CullFace(dynamic.CullFace()) : VK_CULL_MODE_NONE; - rasterization_ci.frontFace = MaxwellToVK::FrontFace(dynamic.FrontFace()); - rasterization_ci.depthBiasEnable = state.depth_bias_enable; - rasterization_ci.depthBiasConstantFactor = 0.0f; - rasterization_ci.depthBiasClamp = 0.0f; - rasterization_ci.depthBiasSlopeFactor = 0.0f; - rasterization_ci.lineWidth = 1.0f; - - VkPipelineMultisampleStateCreateInfo multisample_ci; - multisample_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisample_ci.pNext = nullptr; - multisample_ci.flags = 0; - multisample_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - multisample_ci.sampleShadingEnable = VK_FALSE; - multisample_ci.minSampleShading = 0.0f; - multisample_ci.pSampleMask = nullptr; - multisample_ci.alphaToCoverageEnable = VK_FALSE; - multisample_ci.alphaToOneEnable = VK_FALSE; - - VkPipelineDepthStencilStateCreateInfo depth_stencil_ci; - depth_stencil_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depth_stencil_ci.pNext = nullptr; - depth_stencil_ci.flags = 0; - depth_stencil_ci.depthTestEnable = dynamic.depth_test_enable; - depth_stencil_ci.depthWriteEnable = dynamic.depth_write_enable; - depth_stencil_ci.depthCompareOp = dynamic.depth_test_enable - ? MaxwellToVK::ComparisonOp(dynamic.DepthTestFunc()) - : VK_COMPARE_OP_ALWAYS; - depth_stencil_ci.depthBoundsTestEnable = dynamic.depth_bounds_enable; - depth_stencil_ci.stencilTestEnable = dynamic.stencil_enable; - depth_stencil_ci.front = GetStencilFaceState(dynamic.front); - depth_stencil_ci.back = GetStencilFaceState(dynamic.back); - depth_stencil_ci.minDepthBounds = 0.0f; - depth_stencil_ci.maxDepthBounds = 0.0f; + const VkPipelineRasterizationStateCreateInfo rasterization_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .depthClampEnable = + static_cast<VkBool32>(state.depth_clamp_disabled == 0 ? VK_TRUE : VK_FALSE), + .rasterizerDiscardEnable = + static_cast<VkBool32>(state.rasterize_enable == 0 ? VK_TRUE : VK_FALSE), + .polygonMode = VK_POLYGON_MODE_FILL, + .cullMode = + dynamic.cull_enable ? MaxwellToVK::CullFace(dynamic.CullFace()) : VK_CULL_MODE_NONE, + .frontFace = MaxwellToVK::FrontFace(dynamic.FrontFace()), + .depthBiasEnable = state.depth_bias_enable, + .depthBiasConstantFactor = 0.0f, + .depthBiasClamp = 0.0f, + .depthBiasSlopeFactor = 0.0f, + .lineWidth = 1.0f, + }; + + const VkPipelineMultisampleStateCreateInfo multisample_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, + .sampleShadingEnable = VK_FALSE, + .minSampleShading = 0.0f, + .pSampleMask = nullptr, + .alphaToCoverageEnable = VK_FALSE, + .alphaToOneEnable = VK_FALSE, + }; + + const VkPipelineDepthStencilStateCreateInfo depth_stencil_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .depthTestEnable = dynamic.depth_test_enable, + .depthWriteEnable = dynamic.depth_write_enable, + .depthCompareOp = dynamic.depth_test_enable + ? MaxwellToVK::ComparisonOp(dynamic.DepthTestFunc()) + : VK_COMPARE_OP_ALWAYS, + .depthBoundsTestEnable = dynamic.depth_bounds_enable, + .stencilTestEnable = dynamic.stencil_enable, + .front = GetStencilFaceState(dynamic.front), + .back = GetStencilFaceState(dynamic.back), + .minDepthBounds = 0.0f, + .maxDepthBounds = 0.0f, + }; std::array<VkPipelineColorBlendAttachmentState, Maxwell::NumRenderTargets> cb_attachments; const auto num_attachments = static_cast<std::size_t>(renderpass_params.num_color_attachments); for (std::size_t index = 0; index < num_attachments; ++index) { - static constexpr std::array COMPONENT_TABLE = { - VK_COLOR_COMPONENT_R_BIT, VK_COLOR_COMPONENT_G_BIT, VK_COLOR_COMPONENT_B_BIT, - VK_COLOR_COMPONENT_A_BIT}; + static constexpr std::array COMPONENT_TABLE{ + VK_COLOR_COMPONENT_R_BIT, + VK_COLOR_COMPONENT_G_BIT, + VK_COLOR_COMPONENT_B_BIT, + VK_COLOR_COMPONENT_A_BIT, + }; const auto& blend = state.attachments[index]; VkColorComponentFlags color_components = 0; @@ -346,35 +369,36 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa } } - VkPipelineColorBlendAttachmentState& attachment = cb_attachments[index]; - attachment.blendEnable = blend.enable != 0; - attachment.srcColorBlendFactor = MaxwellToVK::BlendFactor(blend.SourceRGBFactor()); - attachment.dstColorBlendFactor = MaxwellToVK::BlendFactor(blend.DestRGBFactor()); - attachment.colorBlendOp = MaxwellToVK::BlendEquation(blend.EquationRGB()); - attachment.srcAlphaBlendFactor = MaxwellToVK::BlendFactor(blend.SourceAlphaFactor()); - attachment.dstAlphaBlendFactor = MaxwellToVK::BlendFactor(blend.DestAlphaFactor()); - attachment.alphaBlendOp = MaxwellToVK::BlendEquation(blend.EquationAlpha()); - attachment.colorWriteMask = color_components; + cb_attachments[index] = { + .blendEnable = blend.enable != 0, + .srcColorBlendFactor = MaxwellToVK::BlendFactor(blend.SourceRGBFactor()), + .dstColorBlendFactor = MaxwellToVK::BlendFactor(blend.DestRGBFactor()), + .colorBlendOp = MaxwellToVK::BlendEquation(blend.EquationRGB()), + .srcAlphaBlendFactor = MaxwellToVK::BlendFactor(blend.SourceAlphaFactor()), + .dstAlphaBlendFactor = MaxwellToVK::BlendFactor(blend.DestAlphaFactor()), + .alphaBlendOp = MaxwellToVK::BlendEquation(blend.EquationAlpha()), + .colorWriteMask = color_components, + }; } - VkPipelineColorBlendStateCreateInfo color_blend_ci; - color_blend_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - color_blend_ci.pNext = nullptr; - color_blend_ci.flags = 0; - color_blend_ci.logicOpEnable = VK_FALSE; - color_blend_ci.logicOp = VK_LOGIC_OP_COPY; - color_blend_ci.attachmentCount = static_cast<u32>(num_attachments); - color_blend_ci.pAttachments = cb_attachments.data(); - std::memset(color_blend_ci.blendConstants, 0, sizeof(color_blend_ci.blendConstants)); - - std::vector dynamic_states = { + const VkPipelineColorBlendStateCreateInfo color_blend_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .logicOpEnable = VK_FALSE, + .logicOp = VK_LOGIC_OP_COPY, + .attachmentCount = static_cast<u32>(num_attachments), + .pAttachments = cb_attachments.data(), + }; + + std::vector dynamic_states{ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_BLEND_CONSTANTS, VK_DYNAMIC_STATE_DEPTH_BOUNDS, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE, }; if (device.IsExtExtendedDynamicStateSupported()) { - static constexpr std::array extended = { + static constexpr std::array extended{ VK_DYNAMIC_STATE_CULL_MODE_EXT, VK_DYNAMIC_STATE_FRONT_FACE_EXT, VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT, @@ -389,18 +413,19 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa dynamic_states.insert(dynamic_states.end(), extended.begin(), extended.end()); } - VkPipelineDynamicStateCreateInfo dynamic_state_ci; - dynamic_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamic_state_ci.pNext = nullptr; - dynamic_state_ci.flags = 0; - dynamic_state_ci.dynamicStateCount = static_cast<u32>(dynamic_states.size()); - dynamic_state_ci.pDynamicStates = dynamic_states.data(); + const VkPipelineDynamicStateCreateInfo dynamic_state_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .dynamicStateCount = static_cast<u32>(dynamic_states.size()), + .pDynamicStates = dynamic_states.data(), + }; - VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT subgroup_size_ci; - subgroup_size_ci.sType = - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT; - subgroup_size_ci.pNext = nullptr; - subgroup_size_ci.requiredSubgroupSize = GuestWarpSize; + const VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT subgroup_size_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT, + .pNext = nullptr, + .requiredSubgroupSize = GuestWarpSize, + }; std::vector<VkPipelineShaderStageCreateInfo> shader_stages; std::size_t module_index = 0; @@ -408,6 +433,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa if (!program[stage]) { continue; } + VkPipelineShaderStageCreateInfo& stage_ci = shader_stages.emplace_back(); stage_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; stage_ci.pNext = nullptr; @@ -422,26 +448,27 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa } } - VkGraphicsPipelineCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.stageCount = static_cast<u32>(shader_stages.size()); - ci.pStages = shader_stages.data(); - ci.pVertexInputState = &vertex_input_ci; - ci.pInputAssemblyState = &input_assembly_ci; - ci.pTessellationState = &tessellation_ci; - ci.pViewportState = &viewport_ci; - ci.pRasterizationState = &rasterization_ci; - ci.pMultisampleState = &multisample_ci; - ci.pDepthStencilState = &depth_stencil_ci; - ci.pColorBlendState = &color_blend_ci; - ci.pDynamicState = &dynamic_state_ci; - ci.layout = *layout; - ci.renderPass = renderpass; - ci.subpass = 0; - ci.basePipelineHandle = nullptr; - ci.basePipelineIndex = 0; + const VkGraphicsPipelineCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .stageCount = static_cast<u32>(shader_stages.size()), + .pStages = shader_stages.data(), + .pVertexInputState = &vertex_input_ci, + .pInputAssemblyState = &input_assembly_ci, + .pTessellationState = &tessellation_ci, + .pViewportState = &viewport_ci, + .pRasterizationState = &rasterization_ci, + .pMultisampleState = &multisample_ci, + .pDepthStencilState = &depth_stencil_ci, + .pColorBlendState = &color_blend_ci, + .pDynamicState = &dynamic_state_ci, + .layout = *layout, + .renderPass = renderpass, + .subpass = 0, + .basePipelineHandle = nullptr, + .basePipelineIndex = 0, + }; return device.GetLogical().CreateGraphicsPipeline(ci); } diff --git a/src/video_core/renderer_vulkan/vk_image.cpp b/src/video_core/renderer_vulkan/vk_image.cpp index 9bceb3861..1c418ea17 100644 --- a/src/video_core/renderer_vulkan/vk_image.cpp +++ b/src/video_core/renderer_vulkan/vk_image.cpp @@ -102,21 +102,29 @@ bool VKImage::HasChanged(u32 base_layer, u32 num_layers, u32 base_level, u32 num void VKImage::CreatePresentView() { // Image type has to be 2D to be presented. - VkImageViewCreateInfo image_view_ci; - image_view_ci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - image_view_ci.pNext = nullptr; - image_view_ci.flags = 0; - image_view_ci.image = *image; - image_view_ci.viewType = VK_IMAGE_VIEW_TYPE_2D; - image_view_ci.format = format; - image_view_ci.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}; - image_view_ci.subresourceRange.aspectMask = aspect_mask; - image_view_ci.subresourceRange.baseMipLevel = 0; - image_view_ci.subresourceRange.levelCount = 1; - image_view_ci.subresourceRange.baseArrayLayer = 0; - image_view_ci.subresourceRange.layerCount = 1; - present_view = device.GetLogical().CreateImageView(image_view_ci); + present_view = device.GetLogical().CreateImageView({ + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .image = *image, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = format, + .components = + { + .r = VK_COMPONENT_SWIZZLE_IDENTITY, + .g = VK_COMPONENT_SWIZZLE_IDENTITY, + .b = VK_COMPONENT_SWIZZLE_IDENTITY, + .a = VK_COMPONENT_SWIZZLE_IDENTITY, + }, + .subresourceRange = + { + .aspectMask = aspect_mask, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }); } VKImage::SubrangeState& VKImage::GetSubrangeState(u32 layer, u32 level) noexcept { diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.cpp b/src/video_core/renderer_vulkan/vk_memory_manager.cpp index b4c650a63..24c8960ac 100644 --- a/src/video_core/renderer_vulkan/vk_memory_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_memory_manager.cpp @@ -178,13 +178,12 @@ bool VKMemoryManager::AllocMemory(VkMemoryPropertyFlags wanted_properties, u32 t }(); // Try to allocate found type. - VkMemoryAllocateInfo memory_ai; - memory_ai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memory_ai.pNext = nullptr; - memory_ai.allocationSize = size; - memory_ai.memoryTypeIndex = type; - - vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory(memory_ai); + vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({ + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = nullptr, + .allocationSize = size, + .memoryTypeIndex = type, + }); if (!memory) { LOG_CRITICAL(Render_Vulkan, "Device allocation failed!"); return false; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 3da835324..42b3a744c 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -88,12 +88,13 @@ void AddBindings(std::vector<VkDescriptorSetLayoutBinding>& bindings, u32& bindi // Combined image samplers can be arrayed. count = container[i].size; } - VkDescriptorSetLayoutBinding& entry = bindings.emplace_back(); - entry.binding = binding++; - entry.descriptorType = descriptor_type; - entry.descriptorCount = count; - entry.stageFlags = stage_flags; - entry.pImmutableSamplers = nullptr; + bindings.push_back({ + .binding = binding++, + .descriptorType = descriptor_type, + .descriptorCount = count, + .stageFlags = stage_flags, + .pImmutableSamplers = nullptr, + }); } } @@ -259,10 +260,10 @@ VKComputePipeline& VKPipelineCache::GetComputePipeline(const ComputePipelineCach } } - Specialization specialization; - specialization.workgroup_size = key.workgroup_size; - specialization.shared_memory_size = key.shared_memory_size; - + const Specialization specialization{ + .workgroup_size = key.workgroup_size, + .shared_memory_size = key.shared_memory_size, + }; const SPIRVShader spirv_shader{Decompile(device, shader->GetIR(), ShaderType::Compute, shader->GetRegistry(), specialization), shader->GetEntries()}; @@ -370,13 +371,14 @@ void AddEntry(std::vector<VkDescriptorUpdateTemplateEntry>& template_entries, u3 if constexpr (descriptor_type == COMBINED_IMAGE_SAMPLER) { for (u32 i = 0; i < count; ++i) { const u32 num_samplers = container[i].size; - VkDescriptorUpdateTemplateEntry& entry = template_entries.emplace_back(); - entry.dstBinding = binding; - entry.dstArrayElement = 0; - entry.descriptorCount = num_samplers; - entry.descriptorType = descriptor_type; - entry.offset = offset; - entry.stride = entry_size; + template_entries.push_back({ + .dstBinding = binding, + .dstArrayElement = 0, + .descriptorCount = num_samplers, + .descriptorType = descriptor_type, + .offset = offset, + .stride = entry_size, + }); ++binding; offset += num_samplers * entry_size; @@ -389,22 +391,24 @@ void AddEntry(std::vector<VkDescriptorUpdateTemplateEntry>& template_entries, u3 // Nvidia has a bug where updating multiple texels at once causes the driver to crash. // Note: Fixed in driver Windows 443.24, Linux 440.66.15 for (u32 i = 0; i < count; ++i) { - VkDescriptorUpdateTemplateEntry& entry = template_entries.emplace_back(); - entry.dstBinding = binding + i; - entry.dstArrayElement = 0; - entry.descriptorCount = 1; - entry.descriptorType = descriptor_type; - entry.offset = static_cast<std::size_t>(offset + i * entry_size); - entry.stride = entry_size; + template_entries.push_back({ + .dstBinding = binding + i, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = descriptor_type, + .offset = static_cast<std::size_t>(offset + i * entry_size), + .stride = entry_size, + }); } } else if (count > 0) { - VkDescriptorUpdateTemplateEntry& entry = template_entries.emplace_back(); - entry.dstBinding = binding; - entry.dstArrayElement = 0; - entry.descriptorCount = count; - entry.descriptorType = descriptor_type; - entry.offset = offset; - entry.stride = entry_size; + template_entries.push_back({ + .dstBinding = binding, + .dstArrayElement = 0, + .descriptorCount = count, + .descriptorType = descriptor_type, + .offset = offset, + .stride = entry_size, + }); } offset += count * entry_size; binding += count; diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp index bc91c48cc..6cd63d090 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp @@ -47,14 +47,14 @@ std::pair<VkQueryPool, u32> QueryPool::Commit(VKFence& fence) { void QueryPool::Allocate(std::size_t begin, std::size_t end) { usage.resize(end); - VkQueryPoolCreateInfo query_pool_ci; - query_pool_ci.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; - query_pool_ci.pNext = nullptr; - query_pool_ci.flags = 0; - query_pool_ci.queryType = GetTarget(type); - query_pool_ci.queryCount = static_cast<u32>(end - begin); - query_pool_ci.pipelineStatistics = 0; - pools.push_back(device->GetLogical().CreateQueryPool(query_pool_ci)); + pools.push_back(device->GetLogical().CreateQueryPool({ + .sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .queryType = GetTarget(type), + .queryCount = static_cast<u32>(end - begin), + .pipelineStatistics = 0, + })); } void QueryPool::Reserve(std::pair<VkQueryPool, u32> query) { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 7625871c2..2ed2004f0 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -64,20 +64,22 @@ VkViewport GetViewportState(const VKDevice& device, const Maxwell& regs, std::si const auto& src = regs.viewport_transform[index]; const float width = src.scale_x * 2.0f; const float height = src.scale_y * 2.0f; + const float reduce_z = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne ? 1.0f : 0.0f; - VkViewport viewport; - viewport.x = src.translate_x - src.scale_x; - viewport.y = src.translate_y - src.scale_y; - viewport.width = width != 0.0f ? width : 1.0f; - viewport.height = height != 0.0f ? height : 1.0f; + VkViewport viewport{ + .x = src.translate_x - src.scale_x, + .y = src.translate_y - src.scale_y, + .width = width != 0.0f ? width : 1.0f, + .height = height != 0.0f ? height : 1.0f, + .minDepth = src.translate_z - src.scale_z * reduce_z, + .maxDepth = src.translate_z + src.scale_z, + }; - const float reduce_z = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne ? 1.0f : 0.0f; - viewport.minDepth = src.translate_z - src.scale_z * reduce_z; - viewport.maxDepth = src.translate_z + src.scale_z; if (!device.IsExtDepthRangeUnrestrictedSupported()) { viewport.minDepth = std::clamp(viewport.minDepth, 0.0f, 1.0f); viewport.maxDepth = std::clamp(viewport.maxDepth, 0.0f, 1.0f); } + return viewport; } @@ -508,10 +510,11 @@ void RasterizerVulkan::Clear() { const u32 color_attachment = regs.clear_buffers.RT; scheduler.Record([color_attachment, clear_value, clear_rect](vk::CommandBuffer cmdbuf) { - VkClearAttachment attachment; - attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - attachment.colorAttachment = color_attachment; - attachment.clearValue = clear_value; + const VkClearAttachment attachment{ + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .colorAttachment = color_attachment, + .clearValue = clear_value, + }; cmdbuf.ClearAttachments(attachment, clear_rect); }); } @@ -529,10 +532,6 @@ void RasterizerVulkan::Clear() { scheduler.Record([clear_depth = regs.clear_depth, clear_stencil = regs.clear_stencil, clear_rect, aspect_flags](vk::CommandBuffer cmdbuf) { - VkClearValue clear_value; - clear_value.depthStencil.depth = clear_depth; - clear_value.depthStencil.stencil = clear_stencil; - VkClearAttachment attachment; attachment.aspectMask = aspect_flags; attachment.colorAttachment = 0; @@ -551,13 +550,16 @@ void RasterizerVulkan::DispatchCompute(GPUVAddr code_addr) { query_cache.UpdateCounters(); const auto& launch_desc = system.GPU().KeplerCompute().launch_description; - ComputePipelineCacheKey key; - key.shader = code_addr; - key.shared_memory_size = launch_desc.shared_alloc; - key.workgroup_size = {launch_desc.block_dim_x, launch_desc.block_dim_y, - launch_desc.block_dim_z}; - - auto& pipeline = pipeline_cache.GetComputePipeline(key); + auto& pipeline = pipeline_cache.GetComputePipeline({ + .shader = code_addr, + .shared_memory_size = launch_desc.shared_alloc, + .workgroup_size = + { + launch_desc.block_dim_x, + launch_desc.block_dim_y, + launch_desc.block_dim_z, + }, + }); // Compute dispatches can't be executed inside a renderpass scheduler.RequestOutsideRenderPassOperationContext(); @@ -841,17 +843,17 @@ std::tuple<VkFramebuffer, VkExtent2D> RasterizerVulkan::ConfigureFramebuffers( const auto [fbentry, is_cache_miss] = framebuffer_cache.try_emplace(key); auto& framebuffer = fbentry->second; if (is_cache_miss) { - VkFramebufferCreateInfo framebuffer_ci; - framebuffer_ci.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebuffer_ci.pNext = nullptr; - framebuffer_ci.flags = 0; - framebuffer_ci.renderPass = key.renderpass; - framebuffer_ci.attachmentCount = static_cast<u32>(key.views.size()); - framebuffer_ci.pAttachments = key.views.data(); - framebuffer_ci.width = key.width; - framebuffer_ci.height = key.height; - framebuffer_ci.layers = key.layers; - framebuffer = device.GetLogical().CreateFramebuffer(framebuffer_ci); + framebuffer = device.GetLogical().CreateFramebuffer({ + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .renderPass = key.renderpass, + .attachmentCount = static_cast<u32>(key.views.size()), + .pAttachments = key.views.data(), + .width = key.width, + .height = key.height, + .layers = key.layers, + }); } return {*framebuffer, VkExtent2D{key.width, key.height}}; @@ -1553,17 +1555,17 @@ VkBuffer RasterizerVulkan::DefaultBuffer() { return *default_buffer; } - VkBufferCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.size = DEFAULT_BUFFER_SIZE; - ci.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - ci.queueFamilyIndexCount = 0; - ci.pQueueFamilyIndices = nullptr; - default_buffer = device.GetLogical().CreateBuffer(ci); + default_buffer = device.GetLogical().CreateBuffer({ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .size = DEFAULT_BUFFER_SIZE, + .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + }); default_buffer_commit = memory_manager.Commit(default_buffer, false); scheduler.RequestOutsideRenderPassOperationContext(); diff --git a/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp b/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp index 3f71d005e..80284cf92 100644 --- a/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_renderpass_cache.cpp @@ -39,10 +39,14 @@ VkRenderPass VKRenderPassCache::GetRenderPass(const RenderPassParams& params) { vk::RenderPass VKRenderPassCache::CreateRenderPass(const RenderPassParams& params) const { using namespace VideoCore::Surface; + const std::size_t num_attachments = static_cast<std::size_t>(params.num_color_attachments); + std::vector<VkAttachmentDescription> descriptors; + descriptors.reserve(num_attachments); + std::vector<VkAttachmentReference> color_references; + color_references.reserve(num_attachments); - const std::size_t num_attachments = static_cast<std::size_t>(params.num_color_attachments); for (std::size_t rt = 0; rt < num_attachments; ++rt) { const auto guest_format = static_cast<Tegra::RenderTargetFormat>(params.color_formats[rt]); const PixelFormat pixel_format = PixelFormatFromRenderTargetFormat(guest_format); @@ -54,20 +58,22 @@ vk::RenderPass VKRenderPassCache::CreateRenderPass(const RenderPassParams& param const VkImageLayout color_layout = ((params.texceptions >> rt) & 1) != 0 ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - VkAttachmentDescription& descriptor = descriptors.emplace_back(); - descriptor.flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT; - descriptor.format = format.format; - descriptor.samples = VK_SAMPLE_COUNT_1_BIT; - descriptor.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - descriptor.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - descriptor.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - descriptor.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - descriptor.initialLayout = color_layout; - descriptor.finalLayout = color_layout; - - VkAttachmentReference& reference = color_references.emplace_back(); - reference.attachment = static_cast<u32>(rt); - reference.layout = color_layout; + descriptors.push_back({ + .flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT, + .format = format.format, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = color_layout, + .finalLayout = color_layout, + }); + + color_references.push_back({ + .attachment = static_cast<u32>(rt), + .layout = color_layout, + }); } VkAttachmentReference zeta_attachment_ref; @@ -82,32 +88,36 @@ vk::RenderPass VKRenderPassCache::CreateRenderPass(const RenderPassParams& param const VkImageLayout zeta_layout = params.zeta_texception != 0 ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - VkAttachmentDescription& descriptor = descriptors.emplace_back(); - descriptor.flags = 0; - descriptor.format = format.format; - descriptor.samples = VK_SAMPLE_COUNT_1_BIT; - descriptor.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - descriptor.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - descriptor.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - descriptor.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; - descriptor.initialLayout = zeta_layout; - descriptor.finalLayout = zeta_layout; - - zeta_attachment_ref.attachment = static_cast<u32>(num_attachments); - zeta_attachment_ref.layout = zeta_layout; + descriptors.push_back({ + .flags = 0, + .format = format.format, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE, + .initialLayout = zeta_layout, + .finalLayout = zeta_layout, + }); + + zeta_attachment_ref = { + .attachment = static_cast<u32>(num_attachments), + .layout = zeta_layout, + }; } - VkSubpassDescription subpass_description; - subpass_description.flags = 0; - subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass_description.inputAttachmentCount = 0; - subpass_description.pInputAttachments = nullptr; - subpass_description.colorAttachmentCount = static_cast<u32>(color_references.size()); - subpass_description.pColorAttachments = color_references.data(); - subpass_description.pResolveAttachments = nullptr; - subpass_description.pDepthStencilAttachment = has_zeta ? &zeta_attachment_ref : nullptr; - subpass_description.preserveAttachmentCount = 0; - subpass_description.pPreserveAttachments = nullptr; + const VkSubpassDescription subpass_description{ + .flags = 0, + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .inputAttachmentCount = 0, + .pInputAttachments = nullptr, + .colorAttachmentCount = static_cast<u32>(color_references.size()), + .pColorAttachments = color_references.data(), + .pResolveAttachments = nullptr, + .pDepthStencilAttachment = has_zeta ? &zeta_attachment_ref : nullptr, + .preserveAttachmentCount = 0, + .pPreserveAttachments = nullptr, + }; VkAccessFlags access = 0; VkPipelineStageFlags stage = 0; @@ -122,26 +132,27 @@ vk::RenderPass VKRenderPassCache::CreateRenderPass(const RenderPassParams& param stage |= VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; } - VkSubpassDependency subpass_dependency; - subpass_dependency.srcSubpass = VK_SUBPASS_EXTERNAL; - subpass_dependency.dstSubpass = 0; - subpass_dependency.srcStageMask = stage; - subpass_dependency.dstStageMask = stage; - subpass_dependency.srcAccessMask = 0; - subpass_dependency.dstAccessMask = access; - subpass_dependency.dependencyFlags = 0; - - VkRenderPassCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.attachmentCount = static_cast<u32>(descriptors.size()); - ci.pAttachments = descriptors.data(); - ci.subpassCount = 1; - ci.pSubpasses = &subpass_description; - ci.dependencyCount = 1; - ci.pDependencies = &subpass_dependency; - return device.GetLogical().CreateRenderPass(ci); + const VkSubpassDependency subpass_dependency{ + .srcSubpass = VK_SUBPASS_EXTERNAL, + .dstSubpass = 0, + .srcStageMask = stage, + .dstStageMask = stage, + .srcAccessMask = 0, + .dstAccessMask = access, + .dependencyFlags = 0, + }; + + return device.GetLogical().CreateRenderPass({ + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .attachmentCount = static_cast<u32>(descriptors.size()), + .pAttachments = descriptors.data(), + .subpassCount = 1, + .pSubpasses = &subpass_description, + .dependencyCount = 1, + .pDependencies = &subpass_dependency, + }); } } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.cpp b/src/video_core/renderer_vulkan/vk_resource_manager.cpp index dc06f545a..f19330a36 100644 --- a/src/video_core/renderer_vulkan/vk_resource_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_resource_manager.cpp @@ -18,33 +18,32 @@ namespace { constexpr std::size_t COMMAND_BUFFER_POOL_SIZE = 0x1000; constexpr std::size_t FENCES_GROW_STEP = 0x40; -VkFenceCreateInfo BuildFenceCreateInfo() { - VkFenceCreateInfo fence_ci; - fence_ci.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fence_ci.pNext = nullptr; - fence_ci.flags = 0; - return fence_ci; +constexpr VkFenceCreateInfo BuildFenceCreateInfo() { + return { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + }; } } // Anonymous namespace class CommandBufferPool final : public VKFencedPool { public: - CommandBufferPool(const VKDevice& device) + explicit CommandBufferPool(const VKDevice& device) : VKFencedPool(COMMAND_BUFFER_POOL_SIZE), device{device} {} void Allocate(std::size_t begin, std::size_t end) override { // Command buffers are going to be commited, recorded, executed every single usage cycle. // They are also going to be reseted when commited. - VkCommandPoolCreateInfo command_pool_ci; - command_pool_ci.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - command_pool_ci.pNext = nullptr; - command_pool_ci.flags = - VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - command_pool_ci.queueFamilyIndex = device.GetGraphicsFamily(); - Pool& pool = pools.emplace_back(); - pool.handle = device.GetLogical().CreateCommandPool(command_pool_ci); + pool.handle = device.GetLogical().CreateCommandPool({ + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .pNext = nullptr, + .flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | + VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, + .queueFamilyIndex = device.GetGraphicsFamily(), + }); pool.cmdbufs = pool.handle.Allocate(COMMAND_BUFFER_POOL_SIZE); } diff --git a/src/video_core/renderer_vulkan/vk_sampler_cache.cpp b/src/video_core/renderer_vulkan/vk_sampler_cache.cpp index 616eacc36..2d5460776 100644 --- a/src/video_core/renderer_vulkan/vk_sampler_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_sampler_cache.cpp @@ -44,32 +44,35 @@ vk::Sampler VKSamplerCache::CreateSampler(const Tegra::Texture::TSCEntry& tsc) c const bool arbitrary_borders = device.IsExtCustomBorderColorSupported(); const std::array color = tsc.GetBorderColor(); - VkSamplerCustomBorderColorCreateInfoEXT border; - border.sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT; - border.pNext = nullptr; - border.format = VK_FORMAT_UNDEFINED; + VkSamplerCustomBorderColorCreateInfoEXT border{ + .sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT, + .pNext = nullptr, + .format = VK_FORMAT_UNDEFINED, + }; std::memcpy(&border.customBorderColor, color.data(), sizeof(color)); - VkSamplerCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - ci.pNext = arbitrary_borders ? &border : nullptr; - ci.flags = 0; - ci.magFilter = MaxwellToVK::Sampler::Filter(tsc.mag_filter); - ci.minFilter = MaxwellToVK::Sampler::Filter(tsc.min_filter); - ci.mipmapMode = MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter); - ci.addressModeU = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_u, tsc.mag_filter); - ci.addressModeV = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_v, tsc.mag_filter); - ci.addressModeW = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_p, tsc.mag_filter); - ci.mipLodBias = tsc.GetLodBias(); - ci.anisotropyEnable = tsc.GetMaxAnisotropy() > 1.0f ? VK_TRUE : VK_FALSE; - ci.maxAnisotropy = tsc.GetMaxAnisotropy(); - ci.compareEnable = tsc.depth_compare_enabled; - ci.compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func); - ci.minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.GetMinLod(); - ci.maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.GetMaxLod(); - ci.borderColor = arbitrary_borders ? VK_BORDER_COLOR_INT_CUSTOM_EXT : ConvertBorderColor(color); - ci.unnormalizedCoordinates = VK_FALSE; - return device.GetLogical().CreateSampler(ci); + return device.GetLogical().CreateSampler({ + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .pNext = arbitrary_borders ? &border : nullptr, + .flags = 0, + .magFilter = MaxwellToVK::Sampler::Filter(tsc.mag_filter), + .minFilter = MaxwellToVK::Sampler::Filter(tsc.min_filter), + .mipmapMode = MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter), + .addressModeU = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_u, tsc.mag_filter), + .addressModeV = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_v, tsc.mag_filter), + .addressModeW = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_p, tsc.mag_filter), + .mipLodBias = tsc.GetLodBias(), + .anisotropyEnable = + static_cast<VkBool32>(tsc.GetMaxAnisotropy() > 1.0f ? VK_TRUE : VK_FALSE), + .maxAnisotropy = tsc.GetMaxAnisotropy(), + .compareEnable = tsc.depth_compare_enabled, + .compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func), + .minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.GetMinLod(), + .maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.GetMaxLod(), + .borderColor = + arbitrary_borders ? VK_BORDER_COLOR_INT_CUSTOM_EXT : ConvertBorderColor(color), + .unnormalizedCoordinates = VK_FALSE, + }); } VkSampler VKSamplerCache::ToSamplerType(const vk::Sampler& sampler) const { diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 56524e6f3..dbbd0961a 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -100,16 +100,19 @@ void VKScheduler::RequestRenderpass(VkRenderPass renderpass, VkFramebuffer frame state.framebuffer = framebuffer; state.render_area = render_area; - VkRenderPassBeginInfo renderpass_bi; - renderpass_bi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderpass_bi.pNext = nullptr; - renderpass_bi.renderPass = renderpass; - renderpass_bi.framebuffer = framebuffer; - renderpass_bi.renderArea.offset.x = 0; - renderpass_bi.renderArea.offset.y = 0; - renderpass_bi.renderArea.extent = render_area; - renderpass_bi.clearValueCount = 0; - renderpass_bi.pClearValues = nullptr; + const VkRenderPassBeginInfo renderpass_bi{ + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .pNext = nullptr, + .renderPass = renderpass, + .framebuffer = framebuffer, + .renderArea = + { + .offset = {.x = 0, .y = 0}, + .extent = render_area, + }, + .clearValueCount = 0, + .pClearValues = nullptr, + }; Record([renderpass_bi, end_renderpass](vk::CommandBuffer cmdbuf) { if (end_renderpass) { @@ -157,16 +160,17 @@ void VKScheduler::SubmitExecution(VkSemaphore semaphore) { current_cmdbuf.End(); - VkSubmitInfo submit_info; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.pNext = nullptr; - submit_info.waitSemaphoreCount = 0; - submit_info.pWaitSemaphores = nullptr; - submit_info.pWaitDstStageMask = nullptr; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = current_cmdbuf.address(); - submit_info.signalSemaphoreCount = semaphore ? 1 : 0; - submit_info.pSignalSemaphores = &semaphore; + const VkSubmitInfo submit_info{ + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .pNext = nullptr, + .waitSemaphoreCount = 0, + .pWaitSemaphores = nullptr, + .pWaitDstStageMask = nullptr, + .commandBufferCount = 1, + .pCommandBuffers = current_cmdbuf.address(), + .signalSemaphoreCount = semaphore ? 1U : 0U, + .pSignalSemaphores = &semaphore, + }; switch (const VkResult result = device.GetGraphicsQueue().Submit(submit_info, *current_fence)) { case VK_SUCCESS: break; @@ -181,19 +185,18 @@ void VKScheduler::SubmitExecution(VkSemaphore semaphore) { void VKScheduler::AllocateNewContext() { ++ticks; - VkCommandBufferBeginInfo cmdbuf_bi; - cmdbuf_bi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - cmdbuf_bi.pNext = nullptr; - cmdbuf_bi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - cmdbuf_bi.pInheritanceInfo = nullptr; - std::unique_lock lock{mutex}; current_fence = next_fence; next_fence = &resource_manager.CommitFence(); current_cmdbuf = vk::CommandBuffer(resource_manager.CommitCommandBuffer(*current_fence), device.GetDispatchLoader()); - current_cmdbuf.Begin(cmdbuf_bi); + current_cmdbuf.Begin({ + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .pNext = nullptr, + .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + .pInheritanceInfo = nullptr, + }); // Enable counters once again. These are disabled when a command buffer is finished. if (query_cache) { diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 97429cc59..cd7d7a4e4 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp @@ -685,13 +685,19 @@ private: } t_smem_uint = TypePointer(spv::StorageClass::Workgroup, t_uint); - const u32 smem_size = specialization.shared_memory_size; + u32 smem_size = specialization.shared_memory_size * 4; if (smem_size == 0) { // Avoid declaring an empty array. return; } - const auto element_count = static_cast<u32>(Common::AlignUp(smem_size, 4) / 4); - const Id type_array = TypeArray(t_uint, Constant(t_uint, element_count)); + const u32 limit = device.GetMaxComputeSharedMemorySize(); + if (smem_size > limit) { + LOG_ERROR(Render_Vulkan, "Shared memory size {} is clamped to host's limit {}", + smem_size, limit); + smem_size = limit; + } + + const Id type_array = TypeArray(t_uint, Constant(t_uint, smem_size / 4)); const Id type_pointer = TypePointer(spv::StorageClass::Workgroup, type_array); Name(type_pointer, "SharedMemory"); @@ -700,9 +706,9 @@ private: } void DeclareInternalFlags() { - constexpr std::array names = {"zero", "sign", "carry", "overflow"}; + static constexpr std::array names{"zero", "sign", "carry", "overflow"}; + for (std::size_t flag = 0; flag < INTERNAL_FLAGS_COUNT; ++flag) { - const auto flag_code = static_cast<InternalFlag>(flag); const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false); internal_flags[flag] = AddGlobalVariable(Name(id, names[flag])); } @@ -2798,7 +2804,6 @@ private: std::map<GlobalMemoryBase, Id> global_buffers; std::map<u32, TexelBuffer> uniform_texels; std::map<u32, SampledImage> sampled_images; - std::map<u32, TexelBuffer> storage_texels; std::map<u32, StorageImage> images; std::array<Id, Maxwell::NumRenderTargets> frag_colors{}; diff --git a/src/video_core/renderer_vulkan/vk_shader_util.cpp b/src/video_core/renderer_vulkan/vk_shader_util.cpp index 112df9c71..c1a218d76 100644 --- a/src/video_core/renderer_vulkan/vk_shader_util.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_util.cpp @@ -19,13 +19,13 @@ vk::ShaderModule BuildShader(const VKDevice& device, std::size_t code_size, cons const auto data = std::make_unique<u32[]>(code_size / sizeof(u32)); std::memcpy(data.get(), code_data, code_size); - VkShaderModuleCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.codeSize = code_size; - ci.pCode = data.get(); - return device.GetLogical().CreateShaderModule(ci); + return device.GetLogical().CreateShaderModule({ + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .codeSize = code_size, + .pCode = data.get(), + }); } } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp index 45c180221..5eca0ab91 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp @@ -71,20 +71,19 @@ VKBuffer* VKStagingBufferPool::TryGetReservedBuffer(std::size_t size, bool host_ VKBuffer& VKStagingBufferPool::CreateStagingBuffer(std::size_t size, bool host_visible) { const u32 log2 = Common::Log2Ceil64(size); - VkBufferCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.size = 1ULL << log2; - ci.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | - VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - ci.queueFamilyIndexCount = 0; - ci.pQueueFamilyIndices = nullptr; - auto buffer = std::make_unique<VKBuffer>(); - buffer->handle = device.GetLogical().CreateBuffer(ci); + buffer->handle = device.GetLogical().CreateBuffer({ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .size = 1ULL << log2, + .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + }); buffer->commit = memory_manager.Commit(buffer->handle, host_visible); auto& entries = GetCache(host_visible)[log2].entries; diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.cpp b/src/video_core/renderer_vulkan/vk_state_tracker.cpp index e5a583dd5..9151d9fb1 100644 --- a/src/video_core/renderer_vulkan/vk_state_tracker.cpp +++ b/src/video_core/renderer_vulkan/vk_state_tracker.cpp @@ -158,6 +158,7 @@ void StateTracker::Initialize() { SetupDirtyFrontFace(tables); SetupDirtyPrimitiveTopology(tables); SetupDirtyStencilOp(tables); + SetupDirtyStencilTestEnable(tables); } void StateTracker::InvalidateCommandBufferState() { diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp index 2d28a6c47..a5526a3f5 100644 --- a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp +++ b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp @@ -122,30 +122,27 @@ void VKStreamBuffer::CreateBuffers(VkBufferUsageFlags usage) { // Substract from the preferred heap size some bytes to avoid getting out of memory. const VkDeviceSize heap_size = memory_properties.memoryHeaps[preferred_heap].size; const VkDeviceSize allocable_size = heap_size - 9 * 1024 * 1024; - - VkBufferCreateInfo buffer_ci; - buffer_ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buffer_ci.pNext = nullptr; - buffer_ci.flags = 0; - buffer_ci.size = std::min(PREFERRED_STREAM_BUFFER_SIZE, allocable_size); - buffer_ci.usage = usage; - buffer_ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - buffer_ci.queueFamilyIndexCount = 0; - buffer_ci.pQueueFamilyIndices = nullptr; - - buffer = device.GetLogical().CreateBuffer(buffer_ci); + buffer = device.GetLogical().CreateBuffer({ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .size = std::min(PREFERRED_STREAM_BUFFER_SIZE, allocable_size), + .usage = usage, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + }); const auto requirements = device.GetLogical().GetBufferMemoryRequirements(*buffer); const u32 required_flags = requirements.memoryTypeBits; stream_buffer_size = static_cast<u64>(requirements.size); - VkMemoryAllocateInfo memory_ai; - memory_ai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memory_ai.pNext = nullptr; - memory_ai.allocationSize = requirements.size; - memory_ai.memoryTypeIndex = GetMemoryType(memory_properties, required_flags); - - memory = device.GetLogical().AllocateMemory(memory_ai); + memory = device.GetLogical().AllocateMemory({ + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = nullptr, + .allocationSize = requirements.size, + .memoryTypeIndex = GetMemoryType(memory_properties, required_flags), + }); buffer.BindMemory(*memory, 0); } diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index bffd8f32a..c25e312b6 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -95,15 +95,16 @@ bool VKSwapchain::Present(VkSemaphore render_semaphore, VKFence& fence) { const auto present_queue{device.GetPresentQueue()}; bool recreated = false; - VkPresentInfoKHR present_info; - present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - present_info.pNext = nullptr; - present_info.waitSemaphoreCount = render_semaphore ? 2U : 1U; - present_info.pWaitSemaphores = semaphores.data(); - present_info.swapchainCount = 1; - present_info.pSwapchains = swapchain.address(); - present_info.pImageIndices = &image_index; - present_info.pResults = nullptr; + const VkPresentInfoKHR present_info{ + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + .pNext = nullptr, + .waitSemaphoreCount = render_semaphore ? 2U : 1U, + .pWaitSemaphores = semaphores.data(), + .swapchainCount = 1, + .pSwapchains = swapchain.address(), + .pImageIndices = &image_index, + .pResults = nullptr, + }; switch (const VkResult result = present_queue.Present(present_info)) { case VK_SUCCESS: @@ -147,24 +148,25 @@ void VKSwapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, requested_image_count = capabilities.maxImageCount; } - VkSwapchainCreateInfoKHR swapchain_ci; - swapchain_ci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - swapchain_ci.pNext = nullptr; - swapchain_ci.flags = 0; - swapchain_ci.surface = surface; - swapchain_ci.minImageCount = requested_image_count; - swapchain_ci.imageFormat = surface_format.format; - swapchain_ci.imageColorSpace = surface_format.colorSpace; - swapchain_ci.imageArrayLayers = 1; - swapchain_ci.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - swapchain_ci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - swapchain_ci.queueFamilyIndexCount = 0; - swapchain_ci.pQueueFamilyIndices = nullptr; - swapchain_ci.preTransform = capabilities.currentTransform; - swapchain_ci.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - swapchain_ci.presentMode = present_mode; - swapchain_ci.clipped = VK_FALSE; - swapchain_ci.oldSwapchain = nullptr; + VkSwapchainCreateInfoKHR swapchain_ci{ + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + .pNext = nullptr, + .flags = 0, + .surface = surface, + .minImageCount = requested_image_count, + .imageFormat = surface_format.format, + .imageColorSpace = surface_format.colorSpace, + .imageArrayLayers = 1, + .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + .preTransform = capabilities.currentTransform, + .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + .presentMode = present_mode, + .clipped = VK_FALSE, + .oldSwapchain = nullptr, + }; const u32 graphics_family{device.GetGraphicsFamily()}; const u32 present_family{device.GetPresentFamily()}; @@ -173,8 +175,6 @@ void VKSwapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, swapchain_ci.imageSharingMode = VK_SHARING_MODE_CONCURRENT; swapchain_ci.queueFamilyIndexCount = static_cast<u32>(queue_indices.size()); swapchain_ci.pQueueFamilyIndices = queue_indices.data(); - } else { - swapchain_ci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; } // Request the size again to reduce the possibility of a TOCTOU race condition. @@ -200,20 +200,28 @@ void VKSwapchain::CreateSemaphores() { } void VKSwapchain::CreateImageViews() { - VkImageViewCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - // ci.image - ci.viewType = VK_IMAGE_VIEW_TYPE_2D; - ci.format = image_format; - ci.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}; - ci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - ci.subresourceRange.baseMipLevel = 0; - ci.subresourceRange.levelCount = 1; - ci.subresourceRange.baseArrayLayer = 0; - ci.subresourceRange.layerCount = 1; + VkImageViewCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = image_format, + .components = + { + .r = VK_COMPONENT_SWIZZLE_IDENTITY, + .g = VK_COMPONENT_SWIZZLE_IDENTITY, + .b = VK_COMPONENT_SWIZZLE_IDENTITY, + .a = VK_COMPONENT_SWIZZLE_IDENTITY, + }, + .subresourceRange = + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; image_views.resize(image_count); for (std::size_t i = 0; i < image_count; i++) { diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 430031665..d102e6d27 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -95,17 +95,18 @@ VkImageViewType GetImageViewType(SurfaceTarget target) { vk::Buffer CreateBuffer(const VKDevice& device, const SurfaceParams& params, std::size_t host_memory_size) { // TODO(Rodrigo): Move texture buffer creation to the buffer cache - VkBufferCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.size = static_cast<VkDeviceSize>(host_memory_size); - ci.usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - ci.queueFamilyIndexCount = 0; - ci.pQueueFamilyIndices = nullptr; - return device.GetLogical().CreateBuffer(ci); + return device.GetLogical().CreateBuffer({ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .size = static_cast<VkDeviceSize>(host_memory_size), + .usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | + VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + }); } VkBufferViewCreateInfo GenerateBufferViewCreateInfo(const VKDevice& device, @@ -113,15 +114,16 @@ VkBufferViewCreateInfo GenerateBufferViewCreateInfo(const VKDevice& device, std::size_t host_memory_size) { ASSERT(params.IsBuffer()); - VkBufferViewCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.buffer = buffer; - ci.format = MaxwellToVK::SurfaceFormat(device, FormatType::Buffer, params.pixel_format).format; - ci.offset = 0; - ci.range = static_cast<VkDeviceSize>(host_memory_size); - return ci; + return { + .sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .buffer = buffer, + .format = + MaxwellToVK::SurfaceFormat(device, FormatType::Buffer, params.pixel_format).format, + .offset = 0, + .range = static_cast<VkDeviceSize>(host_memory_size), + }; } VkImageCreateInfo GenerateImageCreateInfo(const VKDevice& device, const SurfaceParams& params) { @@ -130,23 +132,23 @@ VkImageCreateInfo GenerateImageCreateInfo(const VKDevice& device, const SurfaceP const auto [format, attachable, storage] = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, params.pixel_format); - VkImageCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.imageType = SurfaceTargetToImage(params.target); - ci.format = format; - ci.mipLevels = params.num_levels; - ci.arrayLayers = static_cast<u32>(params.GetNumLayers()); - ci.samples = VK_SAMPLE_COUNT_1_BIT; - ci.tiling = VK_IMAGE_TILING_OPTIMAL; - ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - ci.queueFamilyIndexCount = 0; - ci.pQueueFamilyIndices = nullptr; - ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - ci.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + VkImageCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .imageType = SurfaceTargetToImage(params.target), + .format = format, + .mipLevels = params.num_levels, + .arrayLayers = static_cast<u32>(params.GetNumLayers()), + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }; if (attachable) { ci.usage |= params.IsPixelFormatZeta() ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT : VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; @@ -233,7 +235,7 @@ void CachedSurface::UploadTexture(const std::vector<u8>& staging_buffer) { void CachedSurface::DownloadTexture(std::vector<u8>& staging_buffer) { UNIMPLEMENTED_IF(params.IsBuffer()); - if (params.pixel_format == VideoCore::Surface::PixelFormat::A1B5G5R5U) { + if (params.pixel_format == VideoCore::Surface::PixelFormat::A1B5G5R5_UNORM) { LOG_WARNING(Render_Vulkan, "A1B5G5R5 flushing is stubbed"); } @@ -281,12 +283,10 @@ void CachedSurface::UploadBuffer(const std::vector<u8>& staging_buffer) { VkBufferMemoryBarrier barrier; barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; barrier.pNext = nullptr; - barrier.srcAccessMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - barrier.dstAccessMask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT; - barrier.srcQueueFamilyIndex = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstQueueFamilyIndex = VK_ACCESS_SHADER_READ_BIT; - barrier.srcQueueFamilyIndex = 0; - barrier.dstQueueFamilyIndex = 0; + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // They'll be ignored anyway + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.buffer = dst_buffer; barrier.offset = 0; barrier.size = size; @@ -323,22 +323,25 @@ void CachedSurface::UploadImage(const std::vector<u8>& staging_buffer) { } VkBufferImageCopy CachedSurface::GetBufferImageCopy(u32 level) const { - VkBufferImageCopy copy; - copy.bufferOffset = params.GetHostMipmapLevelOffset(level, is_converted); - copy.bufferRowLength = 0; - copy.bufferImageHeight = 0; - copy.imageSubresource.aspectMask = image->GetAspectMask(); - copy.imageSubresource.mipLevel = level; - copy.imageSubresource.baseArrayLayer = 0; - copy.imageSubresource.layerCount = static_cast<u32>(params.GetNumLayers()); - copy.imageOffset.x = 0; - copy.imageOffset.y = 0; - copy.imageOffset.z = 0; - copy.imageExtent.width = params.GetMipWidth(level); - copy.imageExtent.height = params.GetMipHeight(level); - copy.imageExtent.depth = - params.target == SurfaceTarget::Texture3D ? params.GetMipDepth(level) : 1; - return copy; + return { + .bufferOffset = params.GetHostMipmapLevelOffset(level, is_converted), + .bufferRowLength = 0, + .bufferImageHeight = 0, + .imageSubresource = + { + .aspectMask = image->GetAspectMask(), + .mipLevel = level, + .baseArrayLayer = 0, + .layerCount = static_cast<u32>(params.GetNumLayers()), + }, + .imageOffset = {.x = 0, .y = 0, .z = 0}, + .imageExtent = + { + .width = params.GetMipWidth(level), + .height = params.GetMipHeight(level), + .depth = params.target == SurfaceTarget::Texture3D ? params.GetMipDepth(level) : 1U, + }, + }; } VkImageSubresourceRange CachedSurface::GetImageSubresourceRange() const { @@ -382,7 +385,7 @@ VkImageView CachedSurfaceView::GetImageView(SwizzleSource x_source, SwizzleSourc std::array swizzle{MaxwellToVK::SwizzleSource(x_source), MaxwellToVK::SwizzleSource(y_source), MaxwellToVK::SwizzleSource(z_source), MaxwellToVK::SwizzleSource(w_source)}; - if (params.pixel_format == VideoCore::Surface::PixelFormat::A1B5G5R5U) { + if (params.pixel_format == VideoCore::Surface::PixelFormat::A1B5G5R5_UNORM) { // A1B5G5R5 is implemented as A1R5G5B5, we have to change the swizzle here. std::swap(swizzle[0], swizzle[2]); } @@ -394,11 +397,11 @@ VkImageView CachedSurfaceView::GetImageView(SwizzleSource x_source, SwizzleSourc UNIMPLEMENTED_IF(x_source != SwizzleSource::R && x_source != SwizzleSource::G); const bool is_first = x_source == SwizzleSource::R; switch (params.pixel_format) { - case VideoCore::Surface::PixelFormat::Z24S8: - case VideoCore::Surface::PixelFormat::Z32FS8: + case VideoCore::Surface::PixelFormat::D24_UNORM_S8_UINT: + case VideoCore::Surface::PixelFormat::D32_FLOAT_S8_UINT: aspect = is_first ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT; break; - case VideoCore::Surface::PixelFormat::S8Z24: + case VideoCore::Surface::PixelFormat::S8_UINT_D24_UNORM: aspect = is_first ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; break; default: @@ -418,20 +421,29 @@ VkImageView CachedSurfaceView::GetImageView(SwizzleSource x_source, SwizzleSourc ASSERT(num_slices == params.depth); } - VkImageViewCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.image = surface.GetImageHandle(); - ci.viewType = image_view_type; - ci.format = surface.GetImage().GetFormat(); - ci.components = {swizzle[0], swizzle[1], swizzle[2], swizzle[3]}; - ci.subresourceRange.aspectMask = aspect; - ci.subresourceRange.baseMipLevel = base_level; - ci.subresourceRange.levelCount = num_levels; - ci.subresourceRange.baseArrayLayer = base_layer; - ci.subresourceRange.layerCount = num_layers; - image_view = device.GetLogical().CreateImageView(ci); + image_view = device.GetLogical().CreateImageView({ + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .image = surface.GetImageHandle(), + .viewType = image_view_type, + .format = surface.GetImage().GetFormat(), + .components = + { + .r = swizzle[0], + .g = swizzle[1], + .b = swizzle[2], + .a = swizzle[3], + }, + .subresourceRange = + { + .aspectMask = aspect, + .baseMipLevel = base_level, + .levelCount = num_levels, + .baseArrayLayer = base_layer, + .layerCount = num_layers, + }, + }); return last_image_view = *image_view; } @@ -441,17 +453,26 @@ VkImageView CachedSurfaceView::GetAttachment() { return *render_target; } - VkImageViewCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.image = surface.GetImageHandle(); - ci.format = surface.GetImage().GetFormat(); - ci.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}; - ci.subresourceRange.aspectMask = aspect_mask; - ci.subresourceRange.baseMipLevel = base_level; - ci.subresourceRange.levelCount = num_levels; + VkImageViewCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .image = surface.GetImageHandle(), + .format = surface.GetImage().GetFormat(), + .components = + { + .r = VK_COMPONENT_SWIZZLE_IDENTITY, + .g = VK_COMPONENT_SWIZZLE_IDENTITY, + .b = VK_COMPONENT_SWIZZLE_IDENTITY, + .a = VK_COMPONENT_SWIZZLE_IDENTITY, + }, + .subresourceRange = + { + .aspectMask = aspect_mask, + .baseMipLevel = base_level, + .levelCount = num_levels, + }, + }; if (image_view_type == VK_IMAGE_VIEW_TYPE_3D) { ci.viewType = num_slices > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D; ci.subresourceRange.baseArrayLayer = base_slice; @@ -504,24 +525,40 @@ void VKTextureCache::ImageCopy(Surface& src_surface, Surface& dst_surface, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - VkImageCopy copy; - copy.srcSubresource.aspectMask = src_surface->GetAspectMask(); - copy.srcSubresource.mipLevel = copy_params.source_level; - copy.srcSubresource.baseArrayLayer = copy_params.source_z; - copy.srcSubresource.layerCount = num_layers; - copy.srcOffset.x = copy_params.source_x; - copy.srcOffset.y = copy_params.source_y; - copy.srcOffset.z = 0; - copy.dstSubresource.aspectMask = dst_surface->GetAspectMask(); - copy.dstSubresource.mipLevel = copy_params.dest_level; - copy.dstSubresource.baseArrayLayer = dst_base_layer; - copy.dstSubresource.layerCount = num_layers; - copy.dstOffset.x = copy_params.dest_x; - copy.dstOffset.y = copy_params.dest_y; - copy.dstOffset.z = dst_offset_z; - copy.extent.width = copy_params.width; - copy.extent.height = copy_params.height; - copy.extent.depth = extent_z; + const VkImageCopy copy{ + .srcSubresource = + { + .aspectMask = src_surface->GetAspectMask(), + .mipLevel = copy_params.source_level, + .baseArrayLayer = copy_params.source_z, + .layerCount = num_layers, + }, + .srcOffset = + { + .x = static_cast<s32>(copy_params.source_x), + .y = static_cast<s32>(copy_params.source_y), + .z = 0, + }, + .dstSubresource = + { + .aspectMask = dst_surface->GetAspectMask(), + .mipLevel = copy_params.dest_level, + .baseArrayLayer = dst_base_layer, + .layerCount = num_layers, + }, + .dstOffset = + { + .x = static_cast<s32>(copy_params.dest_x), + .y = static_cast<s32>(copy_params.dest_y), + .z = static_cast<s32>(dst_offset_z), + }, + .extent = + { + .width = copy_params.width, + .height = copy_params.height, + .depth = extent_z, + }, + }; const VkImage src_image = src_surface->GetImageHandle(); const VkImage dst_image = dst_surface->GetImageHandle(); diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp index 051298cc8..14cac38ea 100644 --- a/src/video_core/renderer_vulkan/wrapper.cpp +++ b/src/video_core/renderer_vulkan/wrapper.cpp @@ -377,24 +377,26 @@ VkResult Free(VkDevice device, VkCommandPool handle, Span<VkCommandBuffer> buffe Instance Instance::Create(Span<const char*> layers, Span<const char*> extensions, InstanceDispatch& dld) noexcept { - VkApplicationInfo application_info; - application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - application_info.pNext = nullptr; - application_info.pApplicationName = "yuzu Emulator"; - application_info.applicationVersion = VK_MAKE_VERSION(0, 1, 0); - application_info.pEngineName = "yuzu Emulator"; - application_info.engineVersion = VK_MAKE_VERSION(0, 1, 0); - application_info.apiVersion = VK_API_VERSION_1_1; - - VkInstanceCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.pApplicationInfo = &application_info; - ci.enabledLayerCount = layers.size(); - ci.ppEnabledLayerNames = layers.data(); - ci.enabledExtensionCount = extensions.size(); - ci.ppEnabledExtensionNames = extensions.data(); + static constexpr VkApplicationInfo application_info{ + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pNext = nullptr, + .pApplicationName = "yuzu Emulator", + .applicationVersion = VK_MAKE_VERSION(0, 1, 0), + .pEngineName = "yuzu Emulator", + .engineVersion = VK_MAKE_VERSION(0, 1, 0), + .apiVersion = VK_API_VERSION_1_1, + }; + + const VkInstanceCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .pApplicationInfo = &application_info, + .enabledLayerCount = layers.size(), + .ppEnabledLayerNames = layers.data(), + .enabledExtensionCount = extensions.size(), + .ppEnabledExtensionNames = extensions.data(), + }; VkInstance instance; if (dld.vkCreateInstance(&ci, nullptr, &instance) != VK_SUCCESS) { @@ -425,19 +427,20 @@ std::optional<std::vector<VkPhysicalDevice>> Instance::EnumeratePhysicalDevices( DebugCallback Instance::TryCreateDebugCallback( PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept { - VkDebugUtilsMessengerCreateInfoEXT ci; - ci.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; - ci.pNext = nullptr; - ci.flags = 0; - ci.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT; - ci.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; - ci.pfnUserCallback = callback; - ci.pUserData = nullptr; + const VkDebugUtilsMessengerCreateInfoEXT ci{ + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .pNext = nullptr, + .flags = 0, + .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT, + .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, + .pfnUserCallback = callback, + .pUserData = nullptr, + }; VkDebugUtilsMessengerEXT messenger; if (dld->vkCreateDebugUtilsMessengerEXT(handle, &ci, nullptr, &messenger) != VK_SUCCESS) { @@ -468,12 +471,13 @@ DescriptorSets DescriptorPool::Allocate(const VkDescriptorSetAllocateInfo& ai) c } CommandBuffers CommandPool::Allocate(std::size_t num_buffers, VkCommandBufferLevel level) const { - VkCommandBufferAllocateInfo ai; - ai.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - ai.pNext = nullptr; - ai.commandPool = handle; - ai.level = level; - ai.commandBufferCount = static_cast<u32>(num_buffers); + const VkCommandBufferAllocateInfo ai{ + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .pNext = nullptr, + .commandPool = handle, + .level = level, + .commandBufferCount = static_cast<u32>(num_buffers), + }; std::unique_ptr buffers = std::make_unique<VkCommandBuffer[]>(num_buffers); switch (const VkResult result = dld->vkAllocateCommandBuffers(owner, &ai, buffers.get())) { @@ -497,17 +501,18 @@ std::vector<VkImage> SwapchainKHR::GetImages() const { Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci, Span<const char*> enabled_extensions, const void* next, DeviceDispatch& dld) noexcept { - VkDeviceCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - ci.pNext = next; - ci.flags = 0; - ci.queueCreateInfoCount = queues_ci.size(); - ci.pQueueCreateInfos = queues_ci.data(); - ci.enabledLayerCount = 0; - ci.ppEnabledLayerNames = nullptr; - ci.enabledExtensionCount = enabled_extensions.size(); - ci.ppEnabledExtensionNames = enabled_extensions.data(); - ci.pEnabledFeatures = nullptr; + const VkDeviceCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .pNext = next, + .flags = 0, + .queueCreateInfoCount = queues_ci.size(), + .pQueueCreateInfos = queues_ci.data(), + .enabledLayerCount = 0, + .ppEnabledLayerNames = nullptr, + .enabledExtensionCount = enabled_extensions.size(), + .ppEnabledExtensionNames = enabled_extensions.data(), + .pEnabledFeatures = nullptr, + }; VkDevice device; if (dld.vkCreateDevice(physical_device, &ci, nullptr, &device) != VK_SUCCESS) { @@ -548,10 +553,11 @@ ImageView Device::CreateImageView(const VkImageViewCreateInfo& ci) const { } Semaphore Device::CreateSemaphore() const { - VkSemaphoreCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; + static constexpr VkSemaphoreCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + }; VkSemaphore object; Check(dld->vkCreateSemaphore(handle, &ci, nullptr, &object)); @@ -639,10 +645,12 @@ ShaderModule Device::CreateShaderModule(const VkShaderModuleCreateInfo& ci) cons } Event Device::CreateEvent() const { - VkEventCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; + static constexpr VkEventCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + }; + VkEvent object; Check(dld->vkCreateEvent(handle, &ci, nullptr, &object)); return Event(object, handle, *dld); diff --git a/src/video_core/shader/async_shaders.cpp b/src/video_core/shader/async_shaders.cpp new file mode 100644 index 000000000..b7f66d7ee --- /dev/null +++ b/src/video_core/shader/async_shaders.cpp @@ -0,0 +1,181 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <chrono> +#include <condition_variable> +#include <mutex> +#include <thread> +#include <vector> +#include "video_core/engines/maxwell_3d.h" +#include "video_core/renderer_base.h" +#include "video_core/renderer_opengl/gl_shader_cache.h" +#include "video_core/shader/async_shaders.h" + +namespace VideoCommon::Shader { + +AsyncShaders::AsyncShaders(Core::Frontend::EmuWindow& emu_window) : emu_window(emu_window) {} + +AsyncShaders::~AsyncShaders() { + KillWorkers(); +} + +void AsyncShaders::AllocateWorkers(std::size_t num_workers) { + // If we're already have workers queued or don't want to queue workers, ignore + if (num_workers == worker_threads.size() || num_workers == 0) { + return; + } + + // If workers already exist, clear them + if (!worker_threads.empty()) { + FreeWorkers(); + } + + // Create workers + for (std::size_t i = 0; i < num_workers; i++) { + context_list.push_back(emu_window.CreateSharedContext()); + worker_threads.push_back(std::move( + std::thread(&AsyncShaders::ShaderCompilerThread, this, context_list[i].get()))); + } +} + +void AsyncShaders::FreeWorkers() { + // Mark all threads to quit + is_thread_exiting.store(true); + cv.notify_all(); + for (auto& thread : worker_threads) { + thread.join(); + } + // Clear our shared contexts + context_list.clear(); + + // Clear our worker threads + worker_threads.clear(); +} + +void AsyncShaders::KillWorkers() { + is_thread_exiting.store(true); + for (auto& thread : worker_threads) { + thread.detach(); + } + // Clear our shared contexts + context_list.clear(); + + // Clear our worker threads + worker_threads.clear(); +} + +bool AsyncShaders::HasWorkQueued() { + return !pending_queue.empty(); +} + +bool AsyncShaders::HasCompletedWork() { + std::shared_lock lock{completed_mutex}; + return !finished_work.empty(); +} + +bool AsyncShaders::IsShaderAsync(const Tegra::GPU& gpu) const { + const auto& regs = gpu.Maxwell3D().regs; + + // If something is using depth, we can assume that games are not rendering anything which will + // be used one time. + if (regs.zeta_enable) { + return true; + } + + // If games are using a small index count, we can assume these are full screen quads. Usually + // these shaders are only used once for building textures so we can assume they can't be built + // async + if (regs.index_array.count <= 6 || regs.vertex_buffer.count <= 6) { + return false; + } + + return true; +} + +std::vector<AsyncShaders::Result> AsyncShaders::GetCompletedWork() { + std::vector<AsyncShaders::Result> results; + { + std::unique_lock lock{completed_mutex}; + results.assign(std::make_move_iterator(finished_work.begin()), + std::make_move_iterator(finished_work.end())); + finished_work.clear(); + } + return results; +} + +void AsyncShaders::QueueOpenGLShader(const OpenGL::Device& device, + Tegra::Engines::ShaderType shader_type, u64 uid, + std::vector<u64> code, std::vector<u64> code_b, + u32 main_offset, + VideoCommon::Shader::CompilerSettings compiler_settings, + const VideoCommon::Shader::Registry& registry, + VAddr cpu_addr) { + WorkerParams params{device.UseAssemblyShaders() ? AsyncShaders::Backend::GLASM + : AsyncShaders::Backend::OpenGL, + device, + shader_type, + uid, + std::move(code), + std::move(code_b), + main_offset, + compiler_settings, + registry, + cpu_addr}; + std::unique_lock lock(queue_mutex); + pending_queue.push_back(std::move(params)); + cv.notify_one(); +} + +void AsyncShaders::ShaderCompilerThread(Core::Frontend::GraphicsContext* context) { + using namespace std::chrono_literals; + while (!is_thread_exiting.load(std::memory_order_relaxed)) { + std::unique_lock lock{queue_mutex}; + cv.wait(lock, [this] { return HasWorkQueued() || is_thread_exiting; }); + if (is_thread_exiting) { + return; + } + + // Partial lock to allow all threads to read at the same time + if (!HasWorkQueued()) { + continue; + } + // Another thread beat us, just unlock and wait for the next load + if (pending_queue.empty()) { + continue; + } + // Pull work from queue + WorkerParams work = std::move(pending_queue.front()); + pending_queue.pop_front(); + + lock.unlock(); + + if (work.backend == AsyncShaders::Backend::OpenGL || + work.backend == AsyncShaders::Backend::GLASM) { + const ShaderIR ir(work.code, work.main_offset, work.compiler_settings, work.registry); + const auto scope = context->Acquire(); + auto program = + OpenGL::BuildShader(work.device, work.shader_type, work.uid, ir, work.registry); + Result result{}; + result.backend = work.backend; + result.cpu_address = work.cpu_address; + result.uid = work.uid; + result.code = std::move(work.code); + result.code_b = std::move(work.code_b); + result.shader_type = work.shader_type; + + if (work.backend == AsyncShaders::Backend::OpenGL) { + result.program.opengl = std::move(program->source_program); + } else if (work.backend == AsyncShaders::Backend::GLASM) { + result.program.glasm = std::move(program->assembly_program); + } + + { + std::unique_lock complete_lock(completed_mutex); + finished_work.push_back(std::move(result)); + } + } + } +} + +} // namespace VideoCommon::Shader diff --git a/src/video_core/shader/async_shaders.h b/src/video_core/shader/async_shaders.h new file mode 100644 index 000000000..2f5ee94ad --- /dev/null +++ b/src/video_core/shader/async_shaders.h @@ -0,0 +1,109 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <condition_variable> +#include <deque> +#include <memory> +#include <shared_mutex> +#include <thread> +#include "common/bit_field.h" +#include "common/common_types.h" +#include "video_core/renderer_opengl/gl_device.h" +#include "video_core/renderer_opengl/gl_resource_manager.h" +#include "video_core/renderer_opengl/gl_shader_decompiler.h" + +namespace Core::Frontend { +class EmuWindow; +class GraphicsContext; +} // namespace Core::Frontend + +namespace Tegra { +class GPU; +} + +namespace VideoCommon::Shader { + +class AsyncShaders { +public: + enum class Backend { + OpenGL, + GLASM, + }; + + struct ResultPrograms { + OpenGL::OGLProgram opengl; + OpenGL::OGLAssemblyProgram glasm; + }; + + struct Result { + u64 uid; + VAddr cpu_address; + Backend backend; + ResultPrograms program; + std::vector<u64> code; + std::vector<u64> code_b; + Tegra::Engines::ShaderType shader_type; + }; + + explicit AsyncShaders(Core::Frontend::EmuWindow& emu_window); + ~AsyncShaders(); + + /// Start up shader worker threads + void AllocateWorkers(std::size_t num_workers); + + /// Clear the shader queue and kill all worker threads + void FreeWorkers(); + + // Force end all threads + void KillWorkers(); + + /// Check to see if any shaders have actually been compiled + bool HasCompletedWork(); + + /// Deduce if a shader can be build on another thread of MUST be built in sync. We cannot build + /// every shader async as some shaders are only built and executed once. We try to "guess" which + /// shader would be used only once + bool IsShaderAsync(const Tegra::GPU& gpu) const; + + /// Pulls completed compiled shaders + std::vector<Result> GetCompletedWork(); + + void QueueOpenGLShader(const OpenGL::Device& device, Tegra::Engines::ShaderType shader_type, + u64 uid, std::vector<u64> code, std::vector<u64> code_b, u32 main_offset, + VideoCommon::Shader::CompilerSettings compiler_settings, + const VideoCommon::Shader::Registry& registry, VAddr cpu_addr); + +private: + void ShaderCompilerThread(Core::Frontend::GraphicsContext* context); + + /// Check our worker queue to see if we have any work queued already + bool HasWorkQueued(); + + struct WorkerParams { + AsyncShaders::Backend backend; + OpenGL::Device device; + Tegra::Engines::ShaderType shader_type; + u64 uid; + std::vector<u64> code; + std::vector<u64> code_b; + u32 main_offset; + VideoCommon::Shader::CompilerSettings compiler_settings; + VideoCommon::Shader::Registry registry; + VAddr cpu_address; + }; + + std::condition_variable cv; + std::mutex queue_mutex; + std::shared_mutex completed_mutex; + std::atomic<bool> is_thread_exiting{}; + std::vector<std::unique_ptr<Core::Frontend::GraphicsContext>> context_list; + std::vector<std::thread> worker_threads; + std::deque<WorkerParams> pending_queue; + std::vector<AsyncShaders::Result> finished_work; + Core::Frontend::EmuWindow& emu_window; +}; + +} // namespace VideoCommon::Shader diff --git a/src/video_core/shader/decode/arithmetic_integer.cpp b/src/video_core/shader/decode/arithmetic_integer.cpp index a041519b7..73155966f 100644 --- a/src/video_core/shader/decode/arithmetic_integer.cpp +++ b/src/video_core/shader/decode/arithmetic_integer.cpp @@ -98,12 +98,12 @@ u32 ShaderIR::DecodeArithmeticInteger(NodeBlock& bb, u32 pc) { op_b = GetOperandAbsNegInteger(op_b, false, instr.iadd3.neg_b, true); op_c = GetOperandAbsNegInteger(op_c, false, instr.iadd3.neg_c, true); - const Node value = [&]() { - const Node add_ab = Operation(OperationCode::IAdd, NO_PRECISE, op_a, op_b); + const Node value = [&] { + Node add_ab = Operation(OperationCode::IAdd, NO_PRECISE, op_a, op_b); if (opcode->get().GetId() != OpCode::Id::IADD3_R) { return Operation(OperationCode::IAdd, NO_PRECISE, add_ab, op_c); } - const Node shifted = [&]() { + const Node shifted = [&] { switch (instr.iadd3.mode) { case Tegra::Shader::IAdd3Mode::RightShift: // TODO(tech4me): According to diff --git a/src/video_core/shader/decode/image.cpp b/src/video_core/shader/decode/image.cpp index 07778dc3e..e75ca4fdb 100644 --- a/src/video_core/shader/decode/image.cpp +++ b/src/video_core/shader/decode/image.cpp @@ -31,11 +31,11 @@ ComponentType GetComponentType(Tegra::Engines::SamplerDescriptor descriptor, std::size_t component) { const TextureFormat format{descriptor.format}; switch (format) { - case TextureFormat::R16_G16_B16_A16: - case TextureFormat::R32_G32_B32_A32: - case TextureFormat::R32_G32_B32: - case TextureFormat::R32_G32: - case TextureFormat::R16_G16: + case TextureFormat::R16G16B16A16: + case TextureFormat::R32G32B32A32: + case TextureFormat::R32G32B32: + case TextureFormat::R32G32: + case TextureFormat::R16G16: case TextureFormat::R32: case TextureFormat::R16: case TextureFormat::R8: @@ -97,7 +97,7 @@ ComponentType GetComponentType(Tegra::Engines::SamplerDescriptor descriptor, break; case TextureFormat::B5G6R5: case TextureFormat::B6G5R5: - case TextureFormat::BF10GF11RF11: + case TextureFormat::B10G11R11: if (component == 0) { return descriptor.b_type; } @@ -108,9 +108,9 @@ ComponentType GetComponentType(Tegra::Engines::SamplerDescriptor descriptor, return descriptor.r_type; } break; - case TextureFormat::G8R24: - case TextureFormat::G24R8: - case TextureFormat::G8R8: + case TextureFormat::R24G8: + case TextureFormat::R8G24: + case TextureFormat::R8G8: case TextureFormat::G4R4: if (component == 0) { return descriptor.g_type; @@ -137,15 +137,15 @@ bool IsComponentEnabled(std::size_t component_mask, std::size_t component) { u32 GetComponentSize(TextureFormat format, std::size_t component) { switch (format) { - case TextureFormat::R32_G32_B32_A32: + case TextureFormat::R32G32B32A32: return 32; - case TextureFormat::R16_G16_B16_A16: + case TextureFormat::R16G16B16A16: return 16; - case TextureFormat::R32_G32_B32: + case TextureFormat::R32G32B32: return component <= 2 ? 32 : 0; - case TextureFormat::R32_G32: + case TextureFormat::R32G32: return component <= 1 ? 32 : 0; - case TextureFormat::R16_G16: + case TextureFormat::R16G16: return component <= 1 ? 16 : 0; case TextureFormat::R32: return component == 0 ? 32 : 0; @@ -192,7 +192,7 @@ u32 GetComponentSize(TextureFormat format, std::size_t component) { return 6; } return 0; - case TextureFormat::BF10GF11RF11: + case TextureFormat::B10G11R11: if (component == 1 || component == 2) { return 11; } @@ -200,7 +200,7 @@ u32 GetComponentSize(TextureFormat format, std::size_t component) { return 10; } return 0; - case TextureFormat::G8R24: + case TextureFormat::R24G8: if (component == 0) { return 8; } @@ -208,7 +208,7 @@ u32 GetComponentSize(TextureFormat format, std::size_t component) { return 24; } return 0; - case TextureFormat::G24R8: + case TextureFormat::R8G24: if (component == 0) { return 8; } @@ -216,7 +216,7 @@ u32 GetComponentSize(TextureFormat format, std::size_t component) { return 24; } return 0; - case TextureFormat::G8R8: + case TextureFormat::R8G8: return (component == 0 || component == 1) ? 8 : 0; case TextureFormat::G4R4: return (component == 0 || component == 1) ? 4 : 0; @@ -231,25 +231,25 @@ std::size_t GetImageComponentMask(TextureFormat format) { constexpr u8 B = 0b0100; constexpr u8 A = 0b1000; switch (format) { - case TextureFormat::R32_G32_B32_A32: - case TextureFormat::R16_G16_B16_A16: + case TextureFormat::R32G32B32A32: + case TextureFormat::R16G16B16A16: case TextureFormat::A8R8G8B8: case TextureFormat::A2B10G10R10: case TextureFormat::A4B4G4R4: case TextureFormat::A5B5G5R1: case TextureFormat::A1B5G5R5: return std::size_t{R | G | B | A}; - case TextureFormat::R32_G32_B32: + case TextureFormat::R32G32B32: case TextureFormat::R32_B24G8: case TextureFormat::B5G6R5: case TextureFormat::B6G5R5: - case TextureFormat::BF10GF11RF11: + case TextureFormat::B10G11R11: return std::size_t{R | G | B}; - case TextureFormat::R32_G32: - case TextureFormat::R16_G16: - case TextureFormat::G8R24: - case TextureFormat::G24R8: - case TextureFormat::G8R8: + case TextureFormat::R32G32: + case TextureFormat::R16G16: + case TextureFormat::R24G8: + case TextureFormat::R8G24: + case TextureFormat::R8G8: case TextureFormat::G4R4: return std::size_t{R | G}; case TextureFormat::R32: diff --git a/src/video_core/shader/decode/other.cpp b/src/video_core/shader/decode/other.cpp index c0a8f233f..29a7cfbfe 100644 --- a/src/video_core/shader/decode/other.cpp +++ b/src/video_core/shader/decode/other.cpp @@ -75,8 +75,7 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { const Node value = [this, instr] { switch (instr.sys20) { case SystemVariable::LaneId: - LOG_WARNING(HW_GPU, "S2R instruction with LaneId is incomplete"); - return Immediate(0U); + return Operation(OperationCode::ThreadId); case SystemVariable::InvocationId: return Operation(OperationCode::InvocationId); case SystemVariable::Ydirection: diff --git a/src/video_core/shader/decode/video.cpp b/src/video_core/shader/decode/video.cpp index 64ba60ea2..1c0957277 100644 --- a/src/video_core/shader/decode/video.cpp +++ b/src/video_core/shader/decode/video.cpp @@ -91,29 +91,28 @@ u32 ShaderIR::DecodeVideo(NodeBlock& bb, u32 pc) { return pc; } -Node ShaderIR::GetVideoOperand(Node op, bool is_chunk, bool is_signed, - Tegra::Shader::VideoType type, u64 byte_height) { +Node ShaderIR::GetVideoOperand(Node op, bool is_chunk, bool is_signed, VideoType type, + u64 byte_height) { if (!is_chunk) { return BitfieldExtract(op, static_cast<u32>(byte_height * 8), 8); } - const Node zero = Immediate(0); switch (type) { - case Tegra::Shader::VideoType::Size16_Low: + case VideoType::Size16_Low: return BitfieldExtract(op, 0, 16); - case Tegra::Shader::VideoType::Size16_High: + case VideoType::Size16_High: return BitfieldExtract(op, 16, 16); - case Tegra::Shader::VideoType::Size32: + case VideoType::Size32: // TODO(Rodrigo): From my hardware tests it becomes a bit "mad" when this type is used // (1 * 1 + 0 == 0x5b800000). Until a better explanation is found: abort. UNIMPLEMENTED(); - return zero; - case Tegra::Shader::VideoType::Invalid: + return Immediate(0); + case VideoType::Invalid: UNREACHABLE_MSG("Invalid instruction encoding"); - return zero; + return Immediate(0); default: UNREACHABLE(); - return zero; + return Immediate(0); } } diff --git a/src/video_core/shader/decode/xmad.cpp b/src/video_core/shader/decode/xmad.cpp index c83dc6615..233b8fa42 100644 --- a/src/video_core/shader/decode/xmad.cpp +++ b/src/video_core/shader/decode/xmad.cpp @@ -81,20 +81,21 @@ u32 ShaderIR::DecodeXmad(NodeBlock& bb, u32 pc) { SetTemporary(bb, 0, product); product = GetTemporary(0); - const Node original_c = op_c; + Node original_c = op_c; const Tegra::Shader::XmadMode set_mode = mode; // Workaround to clang compile error - op_c = [&]() { + op_c = [&] { switch (set_mode) { case Tegra::Shader::XmadMode::None: return original_c; case Tegra::Shader::XmadMode::CLo: - return BitfieldExtract(original_c, 0, 16); + return BitfieldExtract(std::move(original_c), 0, 16); case Tegra::Shader::XmadMode::CHi: - return BitfieldExtract(original_c, 16, 16); + return BitfieldExtract(std::move(original_c), 16, 16); case Tegra::Shader::XmadMode::CBcc: { - const Node shifted_b = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed_b, - original_b, Immediate(16)); - return SignedOperation(OperationCode::IAdd, is_signed_c, original_c, shifted_b); + Node shifted_b = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed_b, + original_b, Immediate(16)); + return SignedOperation(OperationCode::IAdd, is_signed_c, std::move(original_c), + std::move(shifted_b)); } case Tegra::Shader::XmadMode::CSfu: { const Node comp_a = diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp index e322c3402..29d794b34 100644 --- a/src/video_core/shader/shader_ir.cpp +++ b/src/video_core/shader/shader_ir.cpp @@ -112,9 +112,9 @@ Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buff } Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) const { - const Node node = MakeNode<InternalFlagNode>(flag); + Node node = MakeNode<InternalFlagNode>(flag); if (negated) { - return Operation(OperationCode::LogicalNegate, node); + return Operation(OperationCode::LogicalNegate, std::move(node)); } return node; } diff --git a/src/video_core/shader_cache.h b/src/video_core/shader_cache.h index b7608fc7b..015a789d6 100644 --- a/src/video_core/shader_cache.h +++ b/src/video_core/shader_cache.h @@ -209,11 +209,11 @@ private: } // Remove them from the cache - const auto is_removed = [&removed_shaders](std::unique_ptr<T>& shader) { + const auto is_removed = [&removed_shaders](const std::unique_ptr<T>& shader) { return std::find(removed_shaders.begin(), removed_shaders.end(), shader.get()) != removed_shaders.end(); }; - storage.erase(std::remove_if(storage.begin(), storage.end(), is_removed), storage.end()); + std::erase_if(storage, is_removed); } /// @brief Creates a new entry in the lookup cache and returns its pointer diff --git a/src/video_core/shader_notify.cpp b/src/video_core/shader_notify.cpp new file mode 100644 index 000000000..c3c71657d --- /dev/null +++ b/src/video_core/shader_notify.cpp @@ -0,0 +1,42 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "video_core/shader_notify.h" + +using namespace std::chrono_literals; + +namespace VideoCore { +namespace { +constexpr auto UPDATE_TICK = 32ms; +} + +ShaderNotify::ShaderNotify() = default; +ShaderNotify::~ShaderNotify() = default; + +std::size_t ShaderNotify::GetShadersBuilding() { + const auto now = std::chrono::high_resolution_clock::now(); + const auto diff = now - last_update; + if (diff > UPDATE_TICK) { + std::shared_lock lock(mutex); + last_updated_count = accurate_count; + } + return last_updated_count; +} + +std::size_t ShaderNotify::GetShadersBuildingAccurate() { + std::shared_lock lock{mutex}; + return accurate_count; +} + +void ShaderNotify::MarkShaderComplete() { + std::unique_lock lock{mutex}; + accurate_count--; +} + +void ShaderNotify::MarkSharderBuilding() { + std::unique_lock lock{mutex}; + accurate_count++; +} + +} // namespace VideoCore diff --git a/src/video_core/shader_notify.h b/src/video_core/shader_notify.h new file mode 100644 index 000000000..a9c92d179 --- /dev/null +++ b/src/video_core/shader_notify.h @@ -0,0 +1,29 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <chrono> +#include <shared_mutex> +#include "common/common_types.h" + +namespace VideoCore { +class ShaderNotify { +public: + ShaderNotify(); + ~ShaderNotify(); + + std::size_t GetShadersBuilding(); + std::size_t GetShadersBuildingAccurate(); + + void MarkShaderComplete(); + void MarkSharderBuilding(); + +private: + std::size_t last_updated_count{}; + std::size_t accurate_count{}; + std::shared_mutex mutex; + std::chrono::high_resolution_clock::time_point last_update{}; +}; +} // namespace VideoCore diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp index bbe93903c..1688267bb 100644 --- a/src/video_core/surface.cpp +++ b/src/video_core/surface.cpp @@ -74,117 +74,131 @@ bool SurfaceTargetIsArray(SurfaceTarget target) { PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format) { switch (format) { - case Tegra::DepthFormat::S8_Z24_UNORM: - return PixelFormat::S8Z24; - case Tegra::DepthFormat::Z24_S8_UNORM: - return PixelFormat::Z24S8; - case Tegra::DepthFormat::Z32_FLOAT: - return PixelFormat::Z32F; - case Tegra::DepthFormat::Z16_UNORM: - return PixelFormat::Z16; - case Tegra::DepthFormat::Z32_S8_X24_FLOAT: - return PixelFormat::Z32FS8; + case Tegra::DepthFormat::S8_UINT_Z24_UNORM: + return PixelFormat::S8_UINT_D24_UNORM; + case Tegra::DepthFormat::D24S8_UNORM: + return PixelFormat::D24_UNORM_S8_UINT; + case Tegra::DepthFormat::D32_FLOAT: + return PixelFormat::D32_FLOAT; + case Tegra::DepthFormat::D16_UNORM: + return PixelFormat::D16_UNORM; + case Tegra::DepthFormat::D32_FLOAT_S8X24_UINT: + return PixelFormat::D32_FLOAT_S8_UINT; default: - LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); - UNREACHABLE(); - return PixelFormat::S8Z24; + UNIMPLEMENTED_MSG("Unimplemented format={}", static_cast<u32>(format)); + return PixelFormat::S8_UINT_D24_UNORM; } } PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) { switch (format) { - case Tegra::RenderTargetFormat::RGBA8_SRGB: - return PixelFormat::RGBA8_SRGB; - case Tegra::RenderTargetFormat::RGBA8_UNORM: - return PixelFormat::ABGR8U; - case Tegra::RenderTargetFormat::RGBA8_SNORM: - return PixelFormat::ABGR8S; - case Tegra::RenderTargetFormat::RGBA8_UINT: - return PixelFormat::ABGR8UI; - case Tegra::RenderTargetFormat::BGRA8_SRGB: - return PixelFormat::BGRA8_SRGB; - case Tegra::RenderTargetFormat::BGRA8_UNORM: - return PixelFormat::BGRA8; - case Tegra::RenderTargetFormat::RGB10_A2_UNORM: - return PixelFormat::A2B10G10R10U; - case Tegra::RenderTargetFormat::RGBA16_FLOAT: - return PixelFormat::RGBA16F; - case Tegra::RenderTargetFormat::RGBA16_UNORM: - return PixelFormat::RGBA16U; - case Tegra::RenderTargetFormat::RGBA16_SNORM: - return PixelFormat::RGBA16S; - case Tegra::RenderTargetFormat::RGBA16_UINT: - return PixelFormat::RGBA16UI; - case Tegra::RenderTargetFormat::RGBA32_FLOAT: - return PixelFormat::RGBA32F; - case Tegra::RenderTargetFormat::RG32_FLOAT: - return PixelFormat::RG32F; - case Tegra::RenderTargetFormat::R11G11B10_FLOAT: - return PixelFormat::R11FG11FB10F; - case Tegra::RenderTargetFormat::B5G6R5_UNORM: - return PixelFormat::B5G6R5U; - case Tegra::RenderTargetFormat::BGR5A1_UNORM: - return PixelFormat::A1B5G5R5U; - case Tegra::RenderTargetFormat::RGBA32_UINT: - return PixelFormat::RGBA32UI; - case Tegra::RenderTargetFormat::R8_UNORM: - return PixelFormat::R8U; - case Tegra::RenderTargetFormat::R8_UINT: - return PixelFormat::R8UI; - case Tegra::RenderTargetFormat::RG16_FLOAT: - return PixelFormat::RG16F; - case Tegra::RenderTargetFormat::RG16_UINT: - return PixelFormat::RG16UI; - case Tegra::RenderTargetFormat::RG16_SINT: - return PixelFormat::RG16I; - case Tegra::RenderTargetFormat::RG16_UNORM: - return PixelFormat::RG16; - case Tegra::RenderTargetFormat::RG16_SNORM: - return PixelFormat::RG16S; - case Tegra::RenderTargetFormat::RG8_UNORM: - return PixelFormat::RG8U; - case Tegra::RenderTargetFormat::RG8_SNORM: - return PixelFormat::RG8S; - case Tegra::RenderTargetFormat::RG8_UINT: - return PixelFormat::RG8UI; - case Tegra::RenderTargetFormat::R16_FLOAT: - return PixelFormat::R16F; + case Tegra::RenderTargetFormat::R32B32G32A32_FLOAT: + return PixelFormat::R32G32B32A32_FLOAT; + case Tegra::RenderTargetFormat::R32G32B32A32_SINT: + return PixelFormat::R32G32B32A32_SINT; + case Tegra::RenderTargetFormat::R32G32B32A32_UINT: + return PixelFormat::R32G32B32A32_UINT; + case Tegra::RenderTargetFormat::R16G16B16A16_UNORM: + return PixelFormat::R16G16B16A16_UNORM; + case Tegra::RenderTargetFormat::R16G16B16A16_SNORM: + return PixelFormat::R16G16B16A16_SNORM; + case Tegra::RenderTargetFormat::R16G16B16A16_SINT: + return PixelFormat::R16G16B16A16_SINT; + case Tegra::RenderTargetFormat::R16G16B16A16_UINT: + return PixelFormat::R16G16B16A16_UINT; + case Tegra::RenderTargetFormat::R16G16B16A16_FLOAT: + return PixelFormat::R16G16B16A16_FLOAT; + case Tegra::RenderTargetFormat::R32G32_FLOAT: + return PixelFormat::R32G32_FLOAT; + case Tegra::RenderTargetFormat::R32G32_SINT: + return PixelFormat::R32G32_SINT; + case Tegra::RenderTargetFormat::R32G32_UINT: + return PixelFormat::R32G32_UINT; + case Tegra::RenderTargetFormat::R16G16B16X16_FLOAT: + return PixelFormat::R16G16B16X16_FLOAT; + case Tegra::RenderTargetFormat::B8G8R8A8_UNORM: + return PixelFormat::B8G8R8A8_UNORM; + case Tegra::RenderTargetFormat::B8G8R8A8_SRGB: + return PixelFormat::B8G8R8A8_SRGB; + case Tegra::RenderTargetFormat::A2B10G10R10_UNORM: + return PixelFormat::A2B10G10R10_UNORM; + case Tegra::RenderTargetFormat::A2B10G10R10_UINT: + return PixelFormat::A2B10G10R10_UINT; + case Tegra::RenderTargetFormat::A8B8G8R8_UNORM: + return PixelFormat::A8B8G8R8_UNORM; + case Tegra::RenderTargetFormat::A8B8G8R8_SRGB: + return PixelFormat::A8B8G8R8_SRGB; + case Tegra::RenderTargetFormat::A8B8G8R8_SNORM: + return PixelFormat::A8B8G8R8_SNORM; + case Tegra::RenderTargetFormat::A8B8G8R8_SINT: + return PixelFormat::A8B8G8R8_SINT; + case Tegra::RenderTargetFormat::A8B8G8R8_UINT: + return PixelFormat::A8B8G8R8_UINT; + case Tegra::RenderTargetFormat::R16G16_UNORM: + return PixelFormat::R16G16_UNORM; + case Tegra::RenderTargetFormat::R16G16_SNORM: + return PixelFormat::R16G16_SNORM; + case Tegra::RenderTargetFormat::R16G16_SINT: + return PixelFormat::R16G16_SINT; + case Tegra::RenderTargetFormat::R16G16_UINT: + return PixelFormat::R16G16_UINT; + case Tegra::RenderTargetFormat::R16G16_FLOAT: + return PixelFormat::R16G16_FLOAT; + case Tegra::RenderTargetFormat::B10G11R11_FLOAT: + return PixelFormat::B10G11R11_FLOAT; + case Tegra::RenderTargetFormat::R32_SINT: + return PixelFormat::R32_SINT; + case Tegra::RenderTargetFormat::R32_UINT: + return PixelFormat::R32_UINT; + case Tegra::RenderTargetFormat::R32_FLOAT: + return PixelFormat::R32_FLOAT; + case Tegra::RenderTargetFormat::R5G6B5_UNORM: + return PixelFormat::R5G6B5_UNORM; + case Tegra::RenderTargetFormat::A1R5G5B5_UNORM: + return PixelFormat::A1R5G5B5_UNORM; + case Tegra::RenderTargetFormat::R8G8_UNORM: + return PixelFormat::R8G8_UNORM; + case Tegra::RenderTargetFormat::R8G8_SNORM: + return PixelFormat::R8G8_SNORM; + case Tegra::RenderTargetFormat::R8G8_SINT: + return PixelFormat::R8G8_SINT; + case Tegra::RenderTargetFormat::R8G8_UINT: + return PixelFormat::R8G8_UINT; case Tegra::RenderTargetFormat::R16_UNORM: - return PixelFormat::R16U; + return PixelFormat::R16_UNORM; case Tegra::RenderTargetFormat::R16_SNORM: - return PixelFormat::R16S; - case Tegra::RenderTargetFormat::R16_UINT: - return PixelFormat::R16UI; + return PixelFormat::R16_SNORM; case Tegra::RenderTargetFormat::R16_SINT: - return PixelFormat::R16I; - case Tegra::RenderTargetFormat::R32_FLOAT: - return PixelFormat::R32F; - case Tegra::RenderTargetFormat::R32_SINT: - return PixelFormat::R32I; - case Tegra::RenderTargetFormat::R32_UINT: - return PixelFormat::R32UI; - case Tegra::RenderTargetFormat::RG32_UINT: - return PixelFormat::RG32UI; - case Tegra::RenderTargetFormat::RGBX16_FLOAT: - return PixelFormat::RGBX16F; + return PixelFormat::R16_SINT; + case Tegra::RenderTargetFormat::R16_UINT: + return PixelFormat::R16_UINT; + case Tegra::RenderTargetFormat::R16_FLOAT: + return PixelFormat::R16_FLOAT; + case Tegra::RenderTargetFormat::R8_UNORM: + return PixelFormat::R8_UNORM; + case Tegra::RenderTargetFormat::R8_SNORM: + return PixelFormat::R8_SNORM; + case Tegra::RenderTargetFormat::R8_SINT: + return PixelFormat::R8_SINT; + case Tegra::RenderTargetFormat::R8_UINT: + return PixelFormat::R8_UINT; default: - LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); - UNREACHABLE(); - return PixelFormat::RGBA8_SRGB; + UNIMPLEMENTED_MSG("Unimplemented format={}", static_cast<int>(format)); + return PixelFormat::A8B8G8R8_UNORM; } } PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) { switch (format) { - case Tegra::FramebufferConfig::PixelFormat::ABGR8: - return PixelFormat::ABGR8U; - case Tegra::FramebufferConfig::PixelFormat::RGB565: - return PixelFormat::B5G6R5U; - case Tegra::FramebufferConfig::PixelFormat::BGRA8: - return PixelFormat::BGRA8; + case Tegra::FramebufferConfig::PixelFormat::A8B8G8R8_UNORM: + return PixelFormat::A8B8G8R8_UNORM; + case Tegra::FramebufferConfig::PixelFormat::RGB565_UNORM: + return PixelFormat::R5G6B5_UNORM; + case Tegra::FramebufferConfig::PixelFormat::B8G8R8A8_UNORM: + return PixelFormat::B8G8R8A8_UNORM; default: UNIMPLEMENTED_MSG("Unimplemented format={}", static_cast<u32>(format)); - return PixelFormat::ABGR8U; + return PixelFormat::A8B8G8R8_UNORM; } } @@ -212,27 +226,27 @@ SurfaceType GetFormatType(PixelFormat pixel_format) { bool IsPixelFormatASTC(PixelFormat format) { switch (format) { - case PixelFormat::ASTC_2D_4X4: - case PixelFormat::ASTC_2D_5X4: - case PixelFormat::ASTC_2D_5X5: - case PixelFormat::ASTC_2D_8X8: - case PixelFormat::ASTC_2D_8X5: + case PixelFormat::ASTC_2D_4X4_UNORM: + case PixelFormat::ASTC_2D_5X4_UNORM: + case PixelFormat::ASTC_2D_5X5_UNORM: + case PixelFormat::ASTC_2D_8X8_UNORM: + case PixelFormat::ASTC_2D_8X5_UNORM: case PixelFormat::ASTC_2D_4X4_SRGB: case PixelFormat::ASTC_2D_5X4_SRGB: case PixelFormat::ASTC_2D_5X5_SRGB: case PixelFormat::ASTC_2D_8X8_SRGB: case PixelFormat::ASTC_2D_8X5_SRGB: - case PixelFormat::ASTC_2D_10X8: + case PixelFormat::ASTC_2D_10X8_UNORM: case PixelFormat::ASTC_2D_10X8_SRGB: - case PixelFormat::ASTC_2D_6X6: + case PixelFormat::ASTC_2D_6X6_UNORM: case PixelFormat::ASTC_2D_6X6_SRGB: - case PixelFormat::ASTC_2D_10X10: + case PixelFormat::ASTC_2D_10X10_UNORM: case PixelFormat::ASTC_2D_10X10_SRGB: - case PixelFormat::ASTC_2D_12X12: + case PixelFormat::ASTC_2D_12X12_UNORM: case PixelFormat::ASTC_2D_12X12_SRGB: - case PixelFormat::ASTC_2D_8X6: + case PixelFormat::ASTC_2D_8X6_UNORM: case PixelFormat::ASTC_2D_8X6_SRGB: - case PixelFormat::ASTC_2D_6X5: + case PixelFormat::ASTC_2D_6X5_UNORM: case PixelFormat::ASTC_2D_6X5_SRGB: return true; default: @@ -242,12 +256,12 @@ bool IsPixelFormatASTC(PixelFormat format) { bool IsPixelFormatSRGB(PixelFormat format) { switch (format) { - case PixelFormat::RGBA8_SRGB: - case PixelFormat::BGRA8_SRGB: - case PixelFormat::DXT1_SRGB: - case PixelFormat::DXT23_SRGB: - case PixelFormat::DXT45_SRGB: - case PixelFormat::BC7U_SRGB: + case PixelFormat::A8B8G8R8_SRGB: + case PixelFormat::B8G8R8A8_SRGB: + case PixelFormat::BC1_RGBA_SRGB: + case PixelFormat::BC2_SRGB: + case PixelFormat::BC3_SRGB: + case PixelFormat::BC7_SRGB: case PixelFormat::ASTC_2D_4X4_SRGB: case PixelFormat::ASTC_2D_8X8_SRGB: case PixelFormat::ASTC_2D_8X5_SRGB: @@ -269,25 +283,4 @@ std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) { return {GetDefaultBlockWidth(format), GetDefaultBlockHeight(format)}; } -bool IsFormatBCn(PixelFormat format) { - switch (format) { - case PixelFormat::DXT1: - case PixelFormat::DXT23: - case PixelFormat::DXT45: - case PixelFormat::DXN1: - case PixelFormat::DXN2SNORM: - case PixelFormat::DXN2UNORM: - case PixelFormat::BC7U: - case PixelFormat::BC6H_UF16: - case PixelFormat::BC6H_SF16: - case PixelFormat::DXT1_SRGB: - case PixelFormat::DXT23_SRGB: - case PixelFormat::DXT45_SRGB: - case PixelFormat::BC7U_SRGB: - return true; - default: - return false; - } -} - } // namespace VideoCore::Surface diff --git a/src/video_core/surface.h b/src/video_core/surface.h index 6da6a1b97..cfd12fa61 100644 --- a/src/video_core/surface.h +++ b/src/video_core/surface.h @@ -15,94 +15,105 @@ namespace VideoCore::Surface { enum class PixelFormat { - ABGR8U = 0, - ABGR8S = 1, - ABGR8UI = 2, - B5G6R5U = 3, - A2B10G10R10U = 4, - A1B5G5R5U = 5, - R8U = 6, - R8UI = 7, - RGBA16F = 8, - RGBA16U = 9, - RGBA16S = 10, - RGBA16UI = 11, - R11FG11FB10F = 12, - RGBA32UI = 13, - DXT1 = 14, - DXT23 = 15, - DXT45 = 16, - DXN1 = 17, // This is also known as BC4 - DXN2UNORM = 18, - DXN2SNORM = 19, - BC7U = 20, - BC6H_UF16 = 21, - BC6H_SF16 = 22, - ASTC_2D_4X4 = 23, - BGRA8 = 24, - RGBA32F = 25, - RG32F = 26, - R32F = 27, - R16F = 28, - R16U = 29, - R16S = 30, - R16UI = 31, - R16I = 32, - RG16 = 33, - RG16F = 34, - RG16UI = 35, - RG16I = 36, - RG16S = 37, - RGB32F = 38, - RGBA8_SRGB = 39, - RG8U = 40, - RG8S = 41, - RG8UI = 42, - RG32UI = 43, - RGBX16F = 44, - R32UI = 45, - R32I = 46, - ASTC_2D_8X8 = 47, - ASTC_2D_8X5 = 48, - ASTC_2D_5X4 = 49, - BGRA8_SRGB = 50, - DXT1_SRGB = 51, - DXT23_SRGB = 52, - DXT45_SRGB = 53, - BC7U_SRGB = 54, - R4G4B4A4U = 55, - ASTC_2D_4X4_SRGB = 56, - ASTC_2D_8X8_SRGB = 57, - ASTC_2D_8X5_SRGB = 58, - ASTC_2D_5X4_SRGB = 59, - ASTC_2D_5X5 = 60, - ASTC_2D_5X5_SRGB = 61, - ASTC_2D_10X8 = 62, - ASTC_2D_10X8_SRGB = 63, - ASTC_2D_6X6 = 64, - ASTC_2D_6X6_SRGB = 65, - ASTC_2D_10X10 = 66, - ASTC_2D_10X10_SRGB = 67, - ASTC_2D_12X12 = 68, - ASTC_2D_12X12_SRGB = 69, - ASTC_2D_8X6 = 70, - ASTC_2D_8X6_SRGB = 71, - ASTC_2D_6X5 = 72, - ASTC_2D_6X5_SRGB = 73, - E5B9G9R9F = 74, + A8B8G8R8_UNORM, + A8B8G8R8_SNORM, + A8B8G8R8_SINT, + A8B8G8R8_UINT, + R5G6B5_UNORM, + B5G6R5_UNORM, + A1R5G5B5_UNORM, + A2B10G10R10_UNORM, + A2B10G10R10_UINT, + A1B5G5R5_UNORM, + R8_UNORM, + R8_SNORM, + R8_SINT, + R8_UINT, + R16G16B16A16_FLOAT, + R16G16B16A16_UNORM, + R16G16B16A16_SNORM, + R16G16B16A16_SINT, + R16G16B16A16_UINT, + B10G11R11_FLOAT, + R32G32B32A32_UINT, + BC1_RGBA_UNORM, + BC2_UNORM, + BC3_UNORM, + BC4_UNORM, + BC4_SNORM, + BC5_UNORM, + BC5_SNORM, + BC7_UNORM, + BC6H_UFLOAT, + BC6H_SFLOAT, + ASTC_2D_4X4_UNORM, + B8G8R8A8_UNORM, + R32G32B32A32_FLOAT, + R32G32B32A32_SINT, + R32G32_FLOAT, + R32G32_SINT, + R32_FLOAT, + R16_FLOAT, + R16_UNORM, + R16_SNORM, + R16_UINT, + R16_SINT, + R16G16_UNORM, + R16G16_FLOAT, + R16G16_UINT, + R16G16_SINT, + R16G16_SNORM, + R32G32B32_FLOAT, + A8B8G8R8_SRGB, + R8G8_UNORM, + R8G8_SNORM, + R8G8_SINT, + R8G8_UINT, + R32G32_UINT, + R16G16B16X16_FLOAT, + R32_UINT, + R32_SINT, + ASTC_2D_8X8_UNORM, + ASTC_2D_8X5_UNORM, + ASTC_2D_5X4_UNORM, + B8G8R8A8_SRGB, + BC1_RGBA_SRGB, + BC2_SRGB, + BC3_SRGB, + BC7_SRGB, + A4B4G4R4_UNORM, + ASTC_2D_4X4_SRGB, + ASTC_2D_8X8_SRGB, + ASTC_2D_8X5_SRGB, + ASTC_2D_5X4_SRGB, + ASTC_2D_5X5_UNORM, + ASTC_2D_5X5_SRGB, + ASTC_2D_10X8_UNORM, + ASTC_2D_10X8_SRGB, + ASTC_2D_6X6_UNORM, + ASTC_2D_6X6_SRGB, + ASTC_2D_10X10_UNORM, + ASTC_2D_10X10_SRGB, + ASTC_2D_12X12_UNORM, + ASTC_2D_12X12_SRGB, + ASTC_2D_8X6_UNORM, + ASTC_2D_8X6_SRGB, + ASTC_2D_6X5_UNORM, + ASTC_2D_6X5_SRGB, + E5B9G9R9_FLOAT, MaxColorFormat, // Depth formats - Z32F = 75, - Z16 = 76, + D32_FLOAT = MaxColorFormat, + D16_UNORM, MaxDepthFormat, // DepthStencil formats - Z24S8 = 77, - S8Z24 = 78, - Z32FS8 = 79, + D24_UNORM_S8_UINT = MaxDepthFormat, + S8_UINT_D24_UNORM, + D32_FLOAT_S8_UINT, MaxDepthStencilFormat, @@ -130,86 +141,97 @@ enum class SurfaceTarget { }; constexpr std::array<u32, MaxPixelFormat> compression_factor_shift_table = {{ - 0, // ABGR8U - 0, // ABGR8S - 0, // ABGR8UI - 0, // B5G6R5U - 0, // A2B10G10R10U - 0, // A1B5G5R5U - 0, // R8U - 0, // R8UI - 0, // RGBA16F - 0, // RGBA16U - 0, // RGBA16S - 0, // RGBA16UI - 0, // R11FG11FB10F - 0, // RGBA32UI - 2, // DXT1 - 2, // DXT23 - 2, // DXT45 - 2, // DXN1 - 2, // DXN2UNORM - 2, // DXN2SNORM - 2, // BC7U - 2, // BC6H_UF16 - 2, // BC6H_SF16 - 2, // ASTC_2D_4X4 - 0, // BGRA8 - 0, // RGBA32F - 0, // RG32F - 0, // R32F - 0, // R16F - 0, // R16U - 0, // R16S - 0, // R16UI - 0, // R16I - 0, // RG16 - 0, // RG16F - 0, // RG16UI - 0, // RG16I - 0, // RG16S - 0, // RGB32F - 0, // RGBA8_SRGB - 0, // RG8U - 0, // RG8S - 0, // RG8UI - 0, // RG32UI - 0, // RGBX16F - 0, // R32UI - 0, // R32I - 2, // ASTC_2D_8X8 - 2, // ASTC_2D_8X5 - 2, // ASTC_2D_5X4 - 0, // BGRA8_SRGB - 2, // DXT1_SRGB - 2, // DXT23_SRGB - 2, // DXT45_SRGB - 2, // BC7U_SRGB - 0, // R4G4B4A4U + 0, // A8B8G8R8_UNORM + 0, // A8B8G8R8_SNORM + 0, // A8B8G8R8_SINT + 0, // A8B8G8R8_UINT + 0, // R5G6B5_UNORM + 0, // B5G6R5_UNORM + 0, // A1R5G5B5_UNORM + 0, // A2B10G10R10_UNORM + 0, // A2B10G10R10_UINT + 0, // A1B5G5R5_UNORM + 0, // R8_UNORM + 0, // R8_SNORM + 0, // R8_SINT + 0, // R8_UINT + 0, // R16G16B16A16_FLOAT + 0, // R16G16B16A16_UNORM + 0, // R16G16B16A16_SNORM + 0, // R16G16B16A16_SINT + 0, // R16G16B16A16_UINT + 0, // B10G11R11_FLOAT + 0, // R32G32B32A32_UINT + 2, // BC1_RGBA_UNORM + 2, // BC2_UNORM + 2, // BC3_UNORM + 2, // BC4_UNORM + 2, // BC4_SNORM + 2, // BC5_UNORM + 2, // BC5_SNORM + 2, // BC7_UNORM + 2, // BC6H_UFLOAT + 2, // BC6H_SFLOAT + 2, // ASTC_2D_4X4_UNORM + 0, // B8G8R8A8_UNORM + 0, // R32G32B32A32_FLOAT + 0, // R32G32B32A32_SINT + 0, // R32G32_FLOAT + 0, // R32G32_SINT + 0, // R32_FLOAT + 0, // R16_FLOAT + 0, // R16_UNORM + 0, // R16_SNORM + 0, // R16_UINT + 0, // R16_SINT + 0, // R16G16_UNORM + 0, // R16G16_FLOAT + 0, // R16G16_UINT + 0, // R16G16_SINT + 0, // R16G16_SNORM + 0, // R32G32B32_FLOAT + 0, // A8B8G8R8_SRGB + 0, // R8G8_UNORM + 0, // R8G8_SNORM + 0, // R8G8_SINT + 0, // R8G8_UINT + 0, // R32G32_UINT + 0, // R16G16B16X16_FLOAT + 0, // R32_UINT + 0, // R32_SINT + 2, // ASTC_2D_8X8_UNORM + 2, // ASTC_2D_8X5_UNORM + 2, // ASTC_2D_5X4_UNORM + 0, // B8G8R8A8_SRGB + 2, // BC1_RGBA_SRGB + 2, // BC2_SRGB + 2, // BC3_SRGB + 2, // BC7_SRGB + 0, // A4B4G4R4_UNORM 2, // ASTC_2D_4X4_SRGB 2, // ASTC_2D_8X8_SRGB 2, // ASTC_2D_8X5_SRGB 2, // ASTC_2D_5X4_SRGB - 2, // ASTC_2D_5X5 + 2, // ASTC_2D_5X5_UNORM 2, // ASTC_2D_5X5_SRGB - 2, // ASTC_2D_10X8 + 2, // ASTC_2D_10X8_UNORM 2, // ASTC_2D_10X8_SRGB - 2, // ASTC_2D_6X6 + 2, // ASTC_2D_6X6_UNORM 2, // ASTC_2D_6X6_SRGB - 2, // ASTC_2D_10X10 + 2, // ASTC_2D_10X10_UNORM 2, // ASTC_2D_10X10_SRGB - 2, // ASTC_2D_12X12 + 2, // ASTC_2D_12X12_UNORM 2, // ASTC_2D_12X12_SRGB - 2, // ASTC_2D_8X6 + 2, // ASTC_2D_8X6_UNORM 2, // ASTC_2D_8X6_SRGB - 2, // ASTC_2D_6X5 + 2, // ASTC_2D_6X5_UNORM 2, // ASTC_2D_6X5_SRGB - 0, // E5B9G9R9F - 0, // Z32F - 0, // Z16 - 0, // Z24S8 - 0, // S8Z24 - 0, // Z32FS8 + 0, // E5B9G9R9_FLOAT + 0, // D32_FLOAT + 0, // D16_UNORM + 0, // D24_UNORM_S8_UINT + 0, // S8_UINT_D24_UNORM + 0, // D32_FLOAT_S8_UINT }}; /** @@ -229,86 +251,97 @@ inline constexpr u32 GetCompressionFactor(PixelFormat format) { } constexpr std::array<u32, MaxPixelFormat> block_width_table = {{ - 1, // ABGR8U - 1, // ABGR8S - 1, // ABGR8UI - 1, // B5G6R5U - 1, // A2B10G10R10U - 1, // A1B5G5R5U - 1, // R8U - 1, // R8UI - 1, // RGBA16F - 1, // RGBA16U - 1, // RGBA16S - 1, // RGBA16UI - 1, // R11FG11FB10F - 1, // RGBA32UI - 4, // DXT1 - 4, // DXT23 - 4, // DXT45 - 4, // DXN1 - 4, // DXN2UNORM - 4, // DXN2SNORM - 4, // BC7U - 4, // BC6H_UF16 - 4, // BC6H_SF16 - 4, // ASTC_2D_4X4 - 1, // BGRA8 - 1, // RGBA32F - 1, // RG32F - 1, // R32F - 1, // R16F - 1, // R16U - 1, // R16S - 1, // R16UI - 1, // R16I - 1, // RG16 - 1, // RG16F - 1, // RG16UI - 1, // RG16I - 1, // RG16S - 1, // RGB32F - 1, // RGBA8_SRGB - 1, // RG8U - 1, // RG8S - 1, // RG8UI - 1, // RG32UI - 1, // RGBX16F - 1, // R32UI - 1, // R32I - 8, // ASTC_2D_8X8 - 8, // ASTC_2D_8X5 - 5, // ASTC_2D_5X4 - 1, // BGRA8_SRGB - 4, // DXT1_SRGB - 4, // DXT23_SRGB - 4, // DXT45_SRGB - 4, // BC7U_SRGB - 1, // R4G4B4A4U + 1, // A8B8G8R8_UNORM + 1, // A8B8G8R8_SNORM + 1, // A8B8G8R8_SINT + 1, // A8B8G8R8_UINT + 1, // R5G6B5_UNORM + 1, // B5G6R5_UNORM + 1, // A1R5G5B5_UNORM + 1, // A2B10G10R10_UNORM + 1, // A2B10G10R10_UINT + 1, // A1B5G5R5_UNORM + 1, // R8_UNORM + 1, // R8_SNORM + 1, // R8_SINT + 1, // R8_UINT + 1, // R16G16B16A16_FLOAT + 1, // R16G16B16A16_UNORM + 1, // R16G16B16A16_SNORM + 1, // R16G16B16A16_SINT + 1, // R16G16B16A16_UINT + 1, // B10G11R11_FLOAT + 1, // R32G32B32A32_UINT + 4, // BC1_RGBA_UNORM + 4, // BC2_UNORM + 4, // BC3_UNORM + 4, // BC4_UNORM + 4, // BC4_SNORM + 4, // BC5_UNORM + 4, // BC5_SNORM + 4, // BC7_UNORM + 4, // BC6H_UFLOAT + 4, // BC6H_SFLOAT + 4, // ASTC_2D_4X4_UNORM + 1, // B8G8R8A8_UNORM + 1, // R32G32B32A32_FLOAT + 1, // R32G32B32A32_SINT + 1, // R32G32_FLOAT + 1, // R32G32_SINT + 1, // R32_FLOAT + 1, // R16_FLOAT + 1, // R16_UNORM + 1, // R16_SNORM + 1, // R16_UINT + 1, // R16_SINT + 1, // R16G16_UNORM + 1, // R16G16_FLOAT + 1, // R16G16_UINT + 1, // R16G16_SINT + 1, // R16G16_SNORM + 1, // R32G32B32_FLOAT + 1, // A8B8G8R8_SRGB + 1, // R8G8_UNORM + 1, // R8G8_SNORM + 1, // R8G8_SINT + 1, // R8G8_UINT + 1, // R32G32_UINT + 1, // R16G16B16X16_FLOAT + 1, // R32_UINT + 1, // R32_SINT + 8, // ASTC_2D_8X8_UNORM + 8, // ASTC_2D_8X5_UNORM + 5, // ASTC_2D_5X4_UNORM + 1, // B8G8R8A8_SRGB + 4, // BC1_RGBA_SRGB + 4, // BC2_SRGB + 4, // BC3_SRGB + 4, // BC7_SRGB + 1, // A4B4G4R4_UNORM 4, // ASTC_2D_4X4_SRGB 8, // ASTC_2D_8X8_SRGB 8, // ASTC_2D_8X5_SRGB 5, // ASTC_2D_5X4_SRGB - 5, // ASTC_2D_5X5 + 5, // ASTC_2D_5X5_UNORM 5, // ASTC_2D_5X5_SRGB - 10, // ASTC_2D_10X8 + 10, // ASTC_2D_10X8_UNORM 10, // ASTC_2D_10X8_SRGB - 6, // ASTC_2D_6X6 + 6, // ASTC_2D_6X6_UNORM 6, // ASTC_2D_6X6_SRGB - 10, // ASTC_2D_10X10 + 10, // ASTC_2D_10X10_UNORM 10, // ASTC_2D_10X10_SRGB - 12, // ASTC_2D_12X12 + 12, // ASTC_2D_12X12_UNORM 12, // ASTC_2D_12X12_SRGB - 8, // ASTC_2D_8X6 + 8, // ASTC_2D_8X6_UNORM 8, // ASTC_2D_8X6_SRGB - 6, // ASTC_2D_6X5 + 6, // ASTC_2D_6X5_UNORM 6, // ASTC_2D_6X5_SRGB - 1, // E5B9G9R9F - 1, // Z32F - 1, // Z16 - 1, // Z24S8 - 1, // S8Z24 - 1, // Z32FS8 + 1, // E5B9G9R9_FLOAT + 1, // D32_FLOAT + 1, // D16_UNORM + 1, // D24_UNORM_S8_UINT + 1, // S8_UINT_D24_UNORM + 1, // D32_FLOAT_S8_UINT }}; static constexpr u32 GetDefaultBlockWidth(PixelFormat format) { @@ -320,86 +353,97 @@ static constexpr u32 GetDefaultBlockWidth(PixelFormat format) { } constexpr std::array<u32, MaxPixelFormat> block_height_table = {{ - 1, // ABGR8U - 1, // ABGR8S - 1, // ABGR8UI - 1, // B5G6R5U - 1, // A2B10G10R10U - 1, // A1B5G5R5U - 1, // R8U - 1, // R8UI - 1, // RGBA16F - 1, // RGBA16U - 1, // RGBA16S - 1, // RGBA16UI - 1, // R11FG11FB10F - 1, // RGBA32UI - 4, // DXT1 - 4, // DXT23 - 4, // DXT45 - 4, // DXN1 - 4, // DXN2UNORM - 4, // DXN2SNORM - 4, // BC7U - 4, // BC6H_UF16 - 4, // BC6H_SF16 - 4, // ASTC_2D_4X4 - 1, // BGRA8 - 1, // RGBA32F - 1, // RG32F - 1, // R32F - 1, // R16F - 1, // R16U - 1, // R16S - 1, // R16UI - 1, // R16I - 1, // RG16 - 1, // RG16F - 1, // RG16UI - 1, // RG16I - 1, // RG16S - 1, // RGB32F - 1, // RGBA8_SRGB - 1, // RG8U - 1, // RG8S - 1, // RG8UI - 1, // RG32UI - 1, // RGBX16F - 1, // R32UI - 1, // R32I - 8, // ASTC_2D_8X8 - 5, // ASTC_2D_8X5 - 4, // ASTC_2D_5X4 - 1, // BGRA8_SRGB - 4, // DXT1_SRGB - 4, // DXT23_SRGB - 4, // DXT45_SRGB - 4, // BC7U_SRGB - 1, // R4G4B4A4U + 1, // A8B8G8R8_UNORM + 1, // A8B8G8R8_SNORM + 1, // A8B8G8R8_SINT + 1, // A8B8G8R8_UINT + 1, // R5G6B5_UNORM + 1, // B5G6R5_UNORM + 1, // A1R5G5B5_UNORM + 1, // A2B10G10R10_UNORM + 1, // A2B10G10R10_UINT + 1, // A1B5G5R5_UNORM + 1, // R8_UNORM + 1, // R8_SNORM + 1, // R8_SINT + 1, // R8_UINT + 1, // R16G16B16A16_FLOAT + 1, // R16G16B16A16_UNORM + 1, // R16G16B16A16_SNORM + 1, // R16G16B16A16_SINT + 1, // R16G16B16A16_UINT + 1, // B10G11R11_FLOAT + 1, // R32G32B32A32_UINT + 4, // BC1_RGBA_UNORM + 4, // BC2_UNORM + 4, // BC3_UNORM + 4, // BC4_UNORM + 4, // BC4_SNORM + 4, // BC5_UNORM + 4, // BC5_SNORM + 4, // BC7_UNORM + 4, // BC6H_UFLOAT + 4, // BC6H_SFLOAT + 4, // ASTC_2D_4X4_UNORM + 1, // B8G8R8A8_UNORM + 1, // R32G32B32A32_FLOAT + 1, // R32G32B32A32_SINT + 1, // R32G32_FLOAT + 1, // R32G32_SINT + 1, // R32_FLOAT + 1, // R16_FLOAT + 1, // R16_UNORM + 1, // R16_SNORM + 1, // R16_UINT + 1, // R16_SINT + 1, // R16G16_UNORM + 1, // R16G16_FLOAT + 1, // R16G16_UINT + 1, // R16G16_SINT + 1, // R16G16_SNORM + 1, // R32G32B32_FLOAT + 1, // A8B8G8R8_SRGB + 1, // R8G8_UNORM + 1, // R8G8_SNORM + 1, // R8G8_SINT + 1, // R8G8_UINT + 1, // R32G32_UINT + 1, // R16G16B16X16_FLOAT + 1, // R32_UINT + 1, // R32_SINT + 8, // ASTC_2D_8X8_UNORM + 5, // ASTC_2D_8X5_UNORM + 4, // ASTC_2D_5X4_UNORM + 1, // B8G8R8A8_SRGB + 4, // BC1_RGBA_SRGB + 4, // BC2_SRGB + 4, // BC3_SRGB + 4, // BC7_SRGB + 1, // A4B4G4R4_UNORM 4, // ASTC_2D_4X4_SRGB 8, // ASTC_2D_8X8_SRGB 5, // ASTC_2D_8X5_SRGB 4, // ASTC_2D_5X4_SRGB - 5, // ASTC_2D_5X5 + 5, // ASTC_2D_5X5_UNORM 5, // ASTC_2D_5X5_SRGB - 8, // ASTC_2D_10X8 + 8, // ASTC_2D_10X8_UNORM 8, // ASTC_2D_10X8_SRGB - 6, // ASTC_2D_6X6 + 6, // ASTC_2D_6X6_UNORM 6, // ASTC_2D_6X6_SRGB - 10, // ASTC_2D_10X10 + 10, // ASTC_2D_10X10_UNORM 10, // ASTC_2D_10X10_SRGB - 12, // ASTC_2D_12X12 + 12, // ASTC_2D_12X12_UNORM 12, // ASTC_2D_12X12_SRGB - 6, // ASTC_2D_8X6 + 6, // ASTC_2D_8X6_UNORM 6, // ASTC_2D_8X6_SRGB - 5, // ASTC_2D_6X5 + 5, // ASTC_2D_6X5_UNORM 5, // ASTC_2D_6X5_SRGB - 1, // E5B9G9R9F - 1, // Z32F - 1, // Z16 - 1, // Z24S8 - 1, // S8Z24 - 1, // Z32FS8 + 1, // E5B9G9R9_FLOAT + 1, // D32_FLOAT + 1, // D16_UNORM + 1, // D24_UNORM_S8_UINT + 1, // S8_UINT_D24_UNORM + 1, // D32_FLOAT_S8_UINT }}; static constexpr u32 GetDefaultBlockHeight(PixelFormat format) { @@ -411,86 +455,97 @@ static constexpr u32 GetDefaultBlockHeight(PixelFormat format) { } constexpr std::array<u32, MaxPixelFormat> bpp_table = {{ - 32, // ABGR8U - 32, // ABGR8S - 32, // ABGR8UI - 16, // B5G6R5U - 32, // A2B10G10R10U - 16, // A1B5G5R5U - 8, // R8U - 8, // R8UI - 64, // RGBA16F - 64, // RGBA16U - 64, // RGBA16S - 64, // RGBA16UI - 32, // R11FG11FB10F - 128, // RGBA32UI - 64, // DXT1 - 128, // DXT23 - 128, // DXT45 - 64, // DXN1 - 128, // DXN2UNORM - 128, // DXN2SNORM - 128, // BC7U - 128, // BC6H_UF16 - 128, // BC6H_SF16 - 128, // ASTC_2D_4X4 - 32, // BGRA8 - 128, // RGBA32F - 64, // RG32F - 32, // R32F - 16, // R16F - 16, // R16U - 16, // R16S - 16, // R16UI - 16, // R16I - 32, // RG16 - 32, // RG16F - 32, // RG16UI - 32, // RG16I - 32, // RG16S - 96, // RGB32F - 32, // RGBA8_SRGB - 16, // RG8U - 16, // RG8S - 16, // RG8UI - 64, // RG32UI - 64, // RGBX16F - 32, // R32UI - 32, // R32I - 128, // ASTC_2D_8X8 - 128, // ASTC_2D_8X5 - 128, // ASTC_2D_5X4 - 32, // BGRA8_SRGB - 64, // DXT1_SRGB - 128, // DXT23_SRGB - 128, // DXT45_SRGB - 128, // BC7U - 16, // R4G4B4A4U + 32, // A8B8G8R8_UNORM + 32, // A8B8G8R8_SNORM + 32, // A8B8G8R8_SINT + 32, // A8B8G8R8_UINT + 16, // R5G6B5_UNORM + 16, // B5G6R5_UNORM + 16, // A1R5G5B5_UNORM + 32, // A2B10G10R10_UNORM + 32, // A2B10G10R10_UINT + 16, // A1B5G5R5_UNORM + 8, // R8_UNORM + 8, // R8_SNORM + 8, // R8_SINT + 8, // R8_UINT + 64, // R16G16B16A16_FLOAT + 64, // R16G16B16A16_UNORM + 64, // R16G16B16A16_SNORM + 64, // R16G16B16A16_SINT + 64, // R16G16B16A16_UINT + 32, // B10G11R11_FLOAT + 128, // R32G32B32A32_UINT + 64, // BC1_RGBA_UNORM + 128, // BC2_UNORM + 128, // BC3_UNORM + 64, // BC4_UNORM + 64, // BC4_SNORM + 128, // BC5_UNORM + 128, // BC5_SNORM + 128, // BC7_UNORM + 128, // BC6H_UFLOAT + 128, // BC6H_SFLOAT + 128, // ASTC_2D_4X4_UNORM + 32, // B8G8R8A8_UNORM + 128, // R32G32B32A32_FLOAT + 128, // R32G32B32A32_SINT + 64, // R32G32_FLOAT + 64, // R32G32_SINT + 32, // R32_FLOAT + 16, // R16_FLOAT + 16, // R16_UNORM + 16, // R16_SNORM + 16, // R16_UINT + 16, // R16_SINT + 32, // R16G16_UNORM + 32, // R16G16_FLOAT + 32, // R16G16_UINT + 32, // R16G16_SINT + 32, // R16G16_SNORM + 96, // R32G32B32_FLOAT + 32, // A8B8G8R8_SRGB + 16, // R8G8_UNORM + 16, // R8G8_SNORM + 16, // R8G8_SINT + 16, // R8G8_UINT + 64, // R32G32_UINT + 64, // R16G16B16X16_FLOAT + 32, // R32_UINT + 32, // R32_SINT + 128, // ASTC_2D_8X8_UNORM + 128, // ASTC_2D_8X5_UNORM + 128, // ASTC_2D_5X4_UNORM + 32, // B8G8R8A8_SRGB + 64, // BC1_RGBA_SRGB + 128, // BC2_SRGB + 128, // BC3_SRGB + 128, // BC7_UNORM + 16, // A4B4G4R4_UNORM 128, // ASTC_2D_4X4_SRGB 128, // ASTC_2D_8X8_SRGB 128, // ASTC_2D_8X5_SRGB 128, // ASTC_2D_5X4_SRGB - 128, // ASTC_2D_5X5 + 128, // ASTC_2D_5X5_UNORM 128, // ASTC_2D_5X5_SRGB - 128, // ASTC_2D_10X8 + 128, // ASTC_2D_10X8_UNORM 128, // ASTC_2D_10X8_SRGB - 128, // ASTC_2D_6X6 + 128, // ASTC_2D_6X6_UNORM 128, // ASTC_2D_6X6_SRGB - 128, // ASTC_2D_10X10 + 128, // ASTC_2D_10X10_UNORM 128, // ASTC_2D_10X10_SRGB - 128, // ASTC_2D_12X12 + 128, // ASTC_2D_12X12_UNORM 128, // ASTC_2D_12X12_SRGB - 128, // ASTC_2D_8X6 + 128, // ASTC_2D_8X6_UNORM 128, // ASTC_2D_8X6_SRGB - 128, // ASTC_2D_6X5 + 128, // ASTC_2D_6X5_UNORM 128, // ASTC_2D_6X5_SRGB - 32, // E5B9G9R9F - 32, // Z32F - 16, // Z16 - 32, // Z24S8 - 32, // S8Z24 - 64, // Z32FS8 + 32, // E5B9G9R9_FLOAT + 32, // D32_FLOAT + 16, // D16_UNORM + 32, // D24_UNORM_S8_UINT + 32, // S8_UINT_D24_UNORM + 64, // D32_FLOAT_S8_UINT }}; static constexpr u32 GetFormatBpp(PixelFormat format) { @@ -529,7 +584,4 @@ bool IsPixelFormatSRGB(PixelFormat format); std::pair<u32, u32> GetASTCBlockSize(PixelFormat format); -/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN -bool IsFormatBCn(PixelFormat format); - } // namespace VideoCore::Surface diff --git a/src/video_core/texture_cache/format_lookup_table.cpp b/src/video_core/texture_cache/format_lookup_table.cpp index f476f03b0..7d5a75648 100644 --- a/src/video_core/texture_cache/format_lookup_table.cpp +++ b/src/video_core/texture_cache/format_lookup_table.cpp @@ -19,8 +19,6 @@ constexpr auto SNORM = ComponentType::SNORM; constexpr auto UNORM = ComponentType::UNORM; constexpr auto SINT = ComponentType::SINT; constexpr auto UINT = ComponentType::UINT; -constexpr auto SNORM_FORCE_FP16 = ComponentType::SNORM_FORCE_FP16; -constexpr auto UNORM_FORCE_FP16 = ComponentType::UNORM_FORCE_FP16; constexpr auto FLOAT = ComponentType::FLOAT; constexpr bool C = false; // Normal color constexpr bool S = true; // Srgb @@ -41,119 +39,126 @@ struct Table { ComponentType alpha_component; bool is_srgb; }; -constexpr std::array<Table, 78> DefinitionTable = {{ - {TextureFormat::A8R8G8B8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ABGR8U}, - {TextureFormat::A8R8G8B8, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::ABGR8S}, - {TextureFormat::A8R8G8B8, C, UINT, UINT, UINT, UINT, PixelFormat::ABGR8UI}, - {TextureFormat::A8R8G8B8, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::RGBA8_SRGB}, +constexpr std::array<Table, 86> DefinitionTable = {{ + {TextureFormat::A8R8G8B8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::A8B8G8R8_UNORM}, + {TextureFormat::A8R8G8B8, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::A8B8G8R8_SNORM}, + {TextureFormat::A8R8G8B8, C, UINT, UINT, UINT, UINT, PixelFormat::A8B8G8R8_UINT}, + {TextureFormat::A8R8G8B8, C, SINT, SINT, SINT, SINT, PixelFormat::A8B8G8R8_SINT}, + {TextureFormat::A8R8G8B8, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::A8B8G8R8_SRGB}, - {TextureFormat::B5G6R5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::B5G6R5U}, + {TextureFormat::B5G6R5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::B5G6R5_UNORM}, - {TextureFormat::A2B10G10R10, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::A2B10G10R10U}, + {TextureFormat::A2B10G10R10, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::A2B10G10R10_UNORM}, + {TextureFormat::A2B10G10R10, C, UINT, UINT, UINT, UINT, PixelFormat::A2B10G10R10_UINT}, - {TextureFormat::A1B5G5R5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::A1B5G5R5U}, + {TextureFormat::A1B5G5R5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::A1B5G5R5_UNORM}, - {TextureFormat::A4B4G4R4, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::R4G4B4A4U}, + {TextureFormat::A4B4G4R4, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::A4B4G4R4_UNORM}, - {TextureFormat::R8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::R8U}, - {TextureFormat::R8, C, UINT, UINT, UINT, UINT, PixelFormat::R8UI}, + {TextureFormat::R8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::R8_UNORM}, + {TextureFormat::R8, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::R8_SNORM}, + {TextureFormat::R8, C, UINT, UINT, UINT, UINT, PixelFormat::R8_UINT}, + {TextureFormat::R8, C, SINT, SINT, SINT, SINT, PixelFormat::R8_SINT}, - {TextureFormat::G8R8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::RG8U}, - {TextureFormat::G8R8, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::RG8S}, - {TextureFormat::G8R8, C, UINT, UINT, UINT, UINT, PixelFormat::RG8UI}, + {TextureFormat::R8G8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::R8G8_UNORM}, + {TextureFormat::R8G8, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::R8G8_SNORM}, + {TextureFormat::R8G8, C, UINT, UINT, UINT, UINT, PixelFormat::R8G8_UINT}, + {TextureFormat::R8G8, C, SINT, SINT, SINT, SINT, PixelFormat::R8G8_SINT}, - {TextureFormat::R16_G16_B16_A16, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::RGBA16S}, - {TextureFormat::R16_G16_B16_A16, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::RGBA16U}, - {TextureFormat::R16_G16_B16_A16, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::RGBA16F}, - {TextureFormat::R16_G16_B16_A16, C, UINT, UINT, UINT, UINT, PixelFormat::RGBA16UI}, + {TextureFormat::R16G16B16A16, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::R16G16B16A16_SNORM}, + {TextureFormat::R16G16B16A16, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::R16G16B16A16_UNORM}, + {TextureFormat::R16G16B16A16, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R16G16B16A16_FLOAT}, + {TextureFormat::R16G16B16A16, C, UINT, UINT, UINT, UINT, PixelFormat::R16G16B16A16_UINT}, + {TextureFormat::R16G16B16A16, C, SINT, SINT, SINT, SINT, PixelFormat::R16G16B16A16_SINT}, - {TextureFormat::R16_G16, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::RG16F}, - {TextureFormat::R16_G16, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::RG16}, - {TextureFormat::R16_G16, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::RG16S}, - {TextureFormat::R16_G16, C, UINT, UINT, UINT, UINT, PixelFormat::RG16UI}, - {TextureFormat::R16_G16, C, SINT, SINT, SINT, SINT, PixelFormat::RG16I}, + {TextureFormat::R16G16, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R16G16_FLOAT}, + {TextureFormat::R16G16, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::R16G16_UNORM}, + {TextureFormat::R16G16, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::R16G16_SNORM}, + {TextureFormat::R16G16, C, UINT, UINT, UINT, UINT, PixelFormat::R16G16_UINT}, + {TextureFormat::R16G16, C, SINT, SINT, SINT, SINT, PixelFormat::R16G16_SINT}, - {TextureFormat::R16, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R16F}, - {TextureFormat::R16, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::R16U}, - {TextureFormat::R16, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::R16S}, - {TextureFormat::R16, C, UINT, UINT, UINT, UINT, PixelFormat::R16UI}, - {TextureFormat::R16, C, SINT, SINT, SINT, SINT, PixelFormat::R16I}, + {TextureFormat::R16, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R16_FLOAT}, + {TextureFormat::R16, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::R16_UNORM}, + {TextureFormat::R16, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::R16_SNORM}, + {TextureFormat::R16, C, UINT, UINT, UINT, UINT, PixelFormat::R16_UINT}, + {TextureFormat::R16, C, SINT, SINT, SINT, SINT, PixelFormat::R16_SINT}, - {TextureFormat::BF10GF11RF11, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R11FG11FB10F}, + {TextureFormat::B10G11R11, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::B10G11R11_FLOAT}, - {TextureFormat::R32_G32_B32_A32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::RGBA32F}, - {TextureFormat::R32_G32_B32_A32, C, UINT, UINT, UINT, UINT, PixelFormat::RGBA32UI}, + {TextureFormat::R32G32B32A32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R32G32B32A32_FLOAT}, + {TextureFormat::R32G32B32A32, C, UINT, UINT, UINT, UINT, PixelFormat::R32G32B32A32_UINT}, + {TextureFormat::R32G32B32A32, C, SINT, SINT, SINT, SINT, PixelFormat::R32G32B32A32_SINT}, - {TextureFormat::R32_G32_B32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::RGB32F}, + {TextureFormat::R32G32B32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R32G32B32_FLOAT}, - {TextureFormat::R32_G32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::RG32F}, - {TextureFormat::R32_G32, C, UINT, UINT, UINT, UINT, PixelFormat::RG32UI}, + {TextureFormat::R32G32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R32G32_FLOAT}, + {TextureFormat::R32G32, C, UINT, UINT, UINT, UINT, PixelFormat::R32G32_UINT}, + {TextureFormat::R32G32, C, SINT, SINT, SINT, SINT, PixelFormat::R32G32_SINT}, - {TextureFormat::R32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R32F}, - {TextureFormat::R32, C, UINT, UINT, UINT, UINT, PixelFormat::R32UI}, - {TextureFormat::R32, C, SINT, SINT, SINT, SINT, PixelFormat::R32I}, + {TextureFormat::R32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::R32_FLOAT}, + {TextureFormat::R32, C, UINT, UINT, UINT, UINT, PixelFormat::R32_UINT}, + {TextureFormat::R32, C, SINT, SINT, SINT, SINT, PixelFormat::R32_SINT}, - {TextureFormat::E5B9G9R9_SHAREDEXP, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::E5B9G9R9F}, + {TextureFormat::E5B9G9R9, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::E5B9G9R9_FLOAT}, - {TextureFormat::ZF32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::Z32F}, - {TextureFormat::Z16, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::Z16}, - {TextureFormat::S8Z24, C, UINT, UNORM, UNORM, UNORM, PixelFormat::S8Z24}, - {TextureFormat::G24R8, C, UINT, UNORM, UNORM, UNORM, PixelFormat::S8Z24}, - {TextureFormat::ZF32_X24S8, C, FLOAT, UINT, UNORM, UNORM, PixelFormat::Z32FS8}, + {TextureFormat::D32, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::D32_FLOAT}, + {TextureFormat::D16, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::D16_UNORM}, + {TextureFormat::S8D24, C, UINT, UNORM, UNORM, UNORM, PixelFormat::S8_UINT_D24_UNORM}, + {TextureFormat::R8G24, C, UINT, UNORM, UNORM, UNORM, PixelFormat::S8_UINT_D24_UNORM}, + {TextureFormat::D32S8, C, FLOAT, UINT, UNORM, UNORM, PixelFormat::D32_FLOAT_S8_UINT}, - {TextureFormat::DXT1, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXT1}, - {TextureFormat::DXT1, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXT1_SRGB}, + {TextureFormat::BC1_RGBA, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC1_RGBA_UNORM}, + {TextureFormat::BC1_RGBA, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC1_RGBA_SRGB}, - {TextureFormat::DXT23, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXT23}, - {TextureFormat::DXT23, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXT23_SRGB}, + {TextureFormat::BC2, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC2_UNORM}, + {TextureFormat::BC2, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC2_SRGB}, - {TextureFormat::DXT45, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXT45}, - {TextureFormat::DXT45, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXT45_SRGB}, + {TextureFormat::BC3, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC3_UNORM}, + {TextureFormat::BC3, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC3_SRGB}, - // TODO: Use a different pixel format for SNORM - {TextureFormat::DXN1, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXN1}, - {TextureFormat::DXN1, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::DXN1}, + {TextureFormat::BC4, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC4_UNORM}, + {TextureFormat::BC4, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::BC4_SNORM}, - {TextureFormat::DXN2, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::DXN2UNORM}, - {TextureFormat::DXN2, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::DXN2SNORM}, + {TextureFormat::BC5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC5_UNORM}, + {TextureFormat::BC5, C, SNORM, SNORM, SNORM, SNORM, PixelFormat::BC5_SNORM}, - {TextureFormat::BC7U, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC7U}, - {TextureFormat::BC7U, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC7U_SRGB}, + {TextureFormat::BC7, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC7_UNORM}, + {TextureFormat::BC7, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::BC7_SRGB}, - {TextureFormat::BC6H_SF16, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::BC6H_SF16}, - {TextureFormat::BC6H_UF16, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::BC6H_UF16}, + {TextureFormat::BC6H_SFLOAT, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::BC6H_SFLOAT}, + {TextureFormat::BC6H_UFLOAT, C, FLOAT, FLOAT, FLOAT, FLOAT, PixelFormat::BC6H_UFLOAT}, - {TextureFormat::ASTC_2D_4X4, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_4X4}, + {TextureFormat::ASTC_2D_4X4, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_4X4_UNORM}, {TextureFormat::ASTC_2D_4X4, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_4X4_SRGB}, - {TextureFormat::ASTC_2D_5X4, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_5X4}, + {TextureFormat::ASTC_2D_5X4, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_5X4_UNORM}, {TextureFormat::ASTC_2D_5X4, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_5X4_SRGB}, - {TextureFormat::ASTC_2D_5X5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_5X5}, + {TextureFormat::ASTC_2D_5X5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_5X5_UNORM}, {TextureFormat::ASTC_2D_5X5, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_5X5_SRGB}, - {TextureFormat::ASTC_2D_8X8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X8}, + {TextureFormat::ASTC_2D_8X8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X8_UNORM}, {TextureFormat::ASTC_2D_8X8, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X8_SRGB}, - {TextureFormat::ASTC_2D_8X5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X5}, + {TextureFormat::ASTC_2D_8X5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X5_UNORM}, {TextureFormat::ASTC_2D_8X5, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X5_SRGB}, - {TextureFormat::ASTC_2D_10X8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_10X8}, + {TextureFormat::ASTC_2D_10X8, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_10X8_UNORM}, {TextureFormat::ASTC_2D_10X8, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_10X8_SRGB}, - {TextureFormat::ASTC_2D_6X6, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_6X6}, + {TextureFormat::ASTC_2D_6X6, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_6X6_UNORM}, {TextureFormat::ASTC_2D_6X6, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_6X6_SRGB}, - {TextureFormat::ASTC_2D_10X10, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_10X10}, + {TextureFormat::ASTC_2D_10X10, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_10X10_UNORM}, {TextureFormat::ASTC_2D_10X10, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_10X10_SRGB}, - {TextureFormat::ASTC_2D_12X12, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_12X12}, + {TextureFormat::ASTC_2D_12X12, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_12X12_UNORM}, {TextureFormat::ASTC_2D_12X12, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_12X12_SRGB}, - {TextureFormat::ASTC_2D_8X6, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X6}, + {TextureFormat::ASTC_2D_8X6, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X6_UNORM}, {TextureFormat::ASTC_2D_8X6, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_8X6_SRGB}, - {TextureFormat::ASTC_2D_6X5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_6X5}, + {TextureFormat::ASTC_2D_6X5, C, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_6X5_UNORM}, {TextureFormat::ASTC_2D_6X5, S, UNORM, UNORM, UNORM, UNORM, PixelFormat::ASTC_2D_6X5_SRGB}, }}; @@ -184,7 +189,7 @@ PixelFormat FormatLookupTable::GetPixelFormat(TextureFormat format, bool is_srgb static_cast<int>(format), is_srgb, static_cast<int>(red_component), static_cast<int>(green_component), static_cast<int>(blue_component), static_cast<int>(alpha_component)); - return PixelFormat::ABGR8U; + return PixelFormat::A8B8G8R8_UNORM; } void FormatLookupTable::Set(TextureFormat format, bool is_srgb, ComponentType red_component, diff --git a/src/video_core/texture_cache/surface_base.cpp b/src/video_core/texture_cache/surface_base.cpp index 0caf3b4f0..dfcf36e0b 100644 --- a/src/video_core/texture_cache/surface_base.cpp +++ b/src/video_core/texture_cache/surface_base.cpp @@ -228,7 +228,7 @@ void SurfaceBaseImpl::LoadBuffer(Tegra::MemoryManager& memory_manager, } } - if (!is_converted && params.pixel_format != PixelFormat::S8Z24) { + if (!is_converted && params.pixel_format != PixelFormat::S8_UINT_D24_UNORM) { return; } diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index 921562c1f..9e5fe2374 100644 --- a/src/video_core/texture_cache/surface_params.cpp +++ b/src/video_core/texture_cache/surface_params.cpp @@ -83,12 +83,12 @@ SurfaceParams SurfaceParams::CreateForTexture(const FormatLookupTable& lookup_ta params.type = GetFormatType(params.pixel_format); if (entry.is_shadow && params.type == SurfaceType::ColorTexture) { switch (params.pixel_format) { - case PixelFormat::R16U: - case PixelFormat::R16F: - params.pixel_format = PixelFormat::Z16; + case PixelFormat::R16_UNORM: + case PixelFormat::R16_FLOAT: + params.pixel_format = PixelFormat::D16_UNORM; break; - case PixelFormat::R32F: - params.pixel_format = PixelFormat::Z32F; + case PixelFormat::R32_FLOAT: + params.pixel_format = PixelFormat::D32_FLOAT; break; default: UNIMPLEMENTED_MSG("Unimplemented shadow convert format: {}", @@ -195,8 +195,8 @@ SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::siz SurfaceParams params; params.is_tiled = config.memory_layout.type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear; - params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB || - config.format == Tegra::RenderTargetFormat::RGBA8_SRGB; + params.srgb_conversion = config.format == Tegra::RenderTargetFormat::B8G8R8A8_SRGB || + config.format == Tegra::RenderTargetFormat::A8B8G8R8_SRGB; params.block_width = config.memory_layout.block_width; params.block_height = config.memory_layout.block_height; params.block_depth = config.memory_layout.block_depth; @@ -235,8 +235,8 @@ SurfaceParams SurfaceParams::CreateForFermiCopySurface( const Tegra::Engines::Fermi2D::Regs::Surface& config) { SurfaceParams params{}; params.is_tiled = !config.linear; - params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB || - config.format == Tegra::RenderTargetFormat::RGBA8_SRGB; + params.srgb_conversion = config.format == Tegra::RenderTargetFormat::B8G8R8A8_SRGB || + config.format == Tegra::RenderTargetFormat::A8B8G8R8_SRGB; params.block_width = params.is_tiled ? std::min(config.BlockWidth(), 5U) : 0, params.block_height = params.is_tiled ? std::min(config.BlockHeight(), 5U) : 0, params.block_depth = params.is_tiled ? std::min(config.BlockDepth(), 5U) : 0, diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index cdcddb225..96c4e4cc2 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -373,9 +373,9 @@ protected: siblings_table[static_cast<std::size_t>(b)] = a; }; std::fill(siblings_table.begin(), siblings_table.end(), PixelFormat::Invalid); - make_siblings(PixelFormat::Z16, PixelFormat::R16U); - make_siblings(PixelFormat::Z32F, PixelFormat::R32F); - make_siblings(PixelFormat::Z32FS8, PixelFormat::RG32F); + make_siblings(PixelFormat::D16_UNORM, PixelFormat::R16_UNORM); + make_siblings(PixelFormat::D32_FLOAT, PixelFormat::R32_FLOAT); + make_siblings(PixelFormat::D32_FLOAT_S8_UINT, PixelFormat::R32G32_FLOAT); sampled_textures.reserve(64); } @@ -1031,7 +1031,7 @@ private: params.pitch = 4; params.num_levels = 1; params.emulated_levels = 1; - params.pixel_format = VideoCore::Surface::PixelFormat::R8U; + params.pixel_format = VideoCore::Surface::PixelFormat::R8_UNORM; params.type = VideoCore::Surface::SurfaceType::ColorTexture; auto surface = CreateSurface(0ULL, params); invalid_memory.resize(surface->GetHostSizeInBytes(), 0U); diff --git a/src/video_core/textures/convert.cpp b/src/video_core/textures/convert.cpp index f3efa7eb0..962921483 100644 --- a/src/video_core/textures/convert.cpp +++ b/src/video_core/textures/convert.cpp @@ -35,7 +35,7 @@ void SwapS8Z24ToZ24S8(u8* data, u32 width, u32 height) { S8Z24 s8z24_pixel{}; Z24S8 z24s8_pixel{}; constexpr auto bpp{ - VideoCore::Surface::GetBytesPerPixel(VideoCore::Surface::PixelFormat::S8Z24)}; + VideoCore::Surface::GetBytesPerPixel(VideoCore::Surface::PixelFormat::S8_UINT_D24_UNORM)}; for (std::size_t y = 0; y < height; ++y) { for (std::size_t x = 0; x < width; ++x) { const std::size_t offset{bpp * (y * width + x)}; @@ -73,7 +73,7 @@ void ConvertFromGuestToHost(u8* in_data, u8* out_data, PixelFormat pixel_format, in_data, width, height, depth, block_width, block_height); std::copy(rgba8_data.begin(), rgba8_data.end(), out_data); - } else if (convert_s8z24 && pixel_format == PixelFormat::S8Z24) { + } else if (convert_s8z24 && pixel_format == PixelFormat::S8_UINT_D24_UNORM) { Tegra::Texture::ConvertS8Z24ToZ24S8(in_data, width, height); } } @@ -85,7 +85,7 @@ void ConvertFromHostToGuest(u8* data, PixelFormat pixel_format, u32 width, u32 h static_cast<u32>(pixel_format)); UNREACHABLE(); - } else if (convert_s8z24 && pixel_format == PixelFormat::S8Z24) { + } else if (convert_s8z24 && pixel_format == PixelFormat::S8_UINT_D24_UNORM) { Tegra::Texture::ConvertZ24S8ToS8Z24(data, width, height); } } diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index 98beabef1..474ae620a 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp @@ -184,53 +184,6 @@ void CopySwizzledData(u32 width, u32 height, u32 depth, u32 bytes_per_pixel, } } -u32 BytesPerPixel(TextureFormat format) { - switch (format) { - case TextureFormat::DXT1: - case TextureFormat::DXN1: - // In this case a 'pixel' actually refers to a 4x4 tile. - return 8; - case TextureFormat::DXT23: - case TextureFormat::DXT45: - case TextureFormat::DXN2: - case TextureFormat::BC7U: - case TextureFormat::BC6H_UF16: - case TextureFormat::BC6H_SF16: - // In this case a 'pixel' actually refers to a 4x4 tile. - return 16; - case TextureFormat::R32_G32_B32: - return 12; - case TextureFormat::ASTC_2D_4X4: - case TextureFormat::ASTC_2D_5X4: - case TextureFormat::ASTC_2D_8X8: - case TextureFormat::ASTC_2D_8X5: - case TextureFormat::ASTC_2D_10X8: - case TextureFormat::ASTC_2D_5X5: - case TextureFormat::A8R8G8B8: - case TextureFormat::A2B10G10R10: - case TextureFormat::BF10GF11RF11: - case TextureFormat::R32: - case TextureFormat::R16_G16: - return 4; - case TextureFormat::A1B5G5R5: - case TextureFormat::B5G6R5: - case TextureFormat::G8R8: - case TextureFormat::R16: - return 2; - case TextureFormat::R8: - return 1; - case TextureFormat::R16_G16_B16_A16: - return 8; - case TextureFormat::R32_G32_B32_A32: - return 16; - case TextureFormat::R32_G32: - return 8; - default: - UNIMPLEMENTED_MSG("Format not implemented"); - return 1; - } -} - void UnswizzleTexture(u8* const unswizzled_data, u8* address, u32 tile_size_x, u32 tile_size_y, u32 bytes_per_pixel, u32 width, u32 height, u32 depth, u32 block_height, u32 block_depth, u32 width_spacing) { @@ -348,48 +301,6 @@ void SwizzleKepler(const u32 width, const u32 height, const u32 dst_x, const u32 } } -std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat format, u32 width, - u32 height) { - std::vector<u8> rgba_data; - - // TODO(Subv): Implement. - switch (format) { - case TextureFormat::DXT1: - case TextureFormat::DXT23: - case TextureFormat::DXT45: - case TextureFormat::DXN1: - case TextureFormat::DXN2: - case TextureFormat::BC7U: - case TextureFormat::BC6H_UF16: - case TextureFormat::BC6H_SF16: - case TextureFormat::ASTC_2D_4X4: - case TextureFormat::ASTC_2D_8X8: - case TextureFormat::ASTC_2D_5X5: - case TextureFormat::ASTC_2D_10X8: - case TextureFormat::A8R8G8B8: - case TextureFormat::A2B10G10R10: - case TextureFormat::A1B5G5R5: - case TextureFormat::B5G6R5: - case TextureFormat::R8: - case TextureFormat::G8R8: - case TextureFormat::BF10GF11RF11: - case TextureFormat::R32_G32_B32_A32: - case TextureFormat::R32_G32: - case TextureFormat::R32: - case TextureFormat::R16: - case TextureFormat::R16_G16: - case TextureFormat::R32_G32_B32: - // TODO(Subv): For the time being just forward the same data without any decoding. - rgba_data = texture_data; - break; - default: - UNIMPLEMENTED_MSG("Format not implemented"); - break; - } - - return rgba_data; -} - std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth, u32 block_height, u32 block_depth) { if (tiled) { diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h index 232b696b3..d6fe35d37 100644 --- a/src/video_core/textures/decoders.h +++ b/src/video_core/textures/decoders.h @@ -38,10 +38,6 @@ void CopySwizzledData(u32 width, u32 height, u32 depth, u32 bytes_per_pixel, u32 out_bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, bool unswizzle, u32 block_height, u32 block_depth, u32 width_spacing); -/// Decodes an unswizzled texture into a A8R8G8B8 texture. -std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat format, u32 width, - u32 height); - /// This function calculates the correct size of a texture depending if it's tiled or not. std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth, u32 block_height, u32 block_depth); diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h index eba05aced..0574fef12 100644 --- a/src/video_core/textures/texture.h +++ b/src/video_core/textures/texture.h @@ -12,10 +12,10 @@ namespace Tegra::Texture { enum class TextureFormat : u32 { - R32_G32_B32_A32 = 0x01, - R32_G32_B32 = 0x02, - R16_G16_B16_A16 = 0x03, - R32_G32 = 0x04, + R32G32B32A32 = 0x01, + R32G32B32 = 0x02, + R16G16B16A16 = 0x03, + R32G32 = 0x04, R32_B24G8 = 0x05, ETC2_RGB = 0x06, X8B8G8R8 = 0x07, @@ -23,19 +23,19 @@ enum class TextureFormat : u32 { A2B10G10R10 = 0x09, ETC2_RGB_PTA = 0x0a, ETC2_RGBA = 0x0b, - R16_G16 = 0x0c, - G8R24 = 0x0d, - G24R8 = 0x0e, + R16G16 = 0x0c, + R24G8 = 0x0d, + R8G24 = 0x0e, R32 = 0x0f, - BC6H_SF16 = 0x10, - BC6H_UF16 = 0x11, + BC6H_SFLOAT = 0x10, + BC6H_UFLOAT = 0x11, A4B4G4R4 = 0x12, A5B5G5R1 = 0x13, A1B5G5R5 = 0x14, B5G6R5 = 0x15, B6G5R5 = 0x16, - BC7U = 0x17, - G8R8 = 0x18, + BC7 = 0x17, + R8G8 = 0x18, EAC = 0x19, EACX2 = 0x1a, R16 = 0x1b, @@ -43,23 +43,23 @@ enum class TextureFormat : u32 { R8 = 0x1d, G4R4 = 0x1e, R1 = 0x1f, - E5B9G9R9_SHAREDEXP = 0x20, - BF10GF11RF11 = 0x21, + E5B9G9R9 = 0x20, + B10G11R11 = 0x21, G8B8G8R8 = 0x22, B8G8R8G8 = 0x23, - DXT1 = 0x24, - DXT23 = 0x25, - DXT45 = 0x26, - DXN1 = 0x27, - DXN2 = 0x28, - S8Z24 = 0x29, + BC1_RGBA = 0x24, + BC2 = 0x25, + BC3 = 0x26, + BC4 = 0x27, + BC5 = 0x28, + S8D24 = 0x29, X8Z24 = 0x2a, - Z24S8 = 0x2b, + D24S8 = 0x2b, X4V4Z24__COV4R4V = 0x2c, X4V4Z24__COV8R8V = 0x2d, V8Z24__COV4R12V = 0x2e, - ZF32 = 0x2f, - ZF32_X24S8 = 0x30, + D32 = 0x2f, + D32S8 = 0x30, X8Z24_X20V4S8__COV4R4V = 0x31, X8Z24_X20V4S8__COV8R8V = 0x32, ZF32_X20V4X8__COV4R4V = 0x33, @@ -69,7 +69,7 @@ enum class TextureFormat : u32 { X8Z24_X16V8S8__COV4R12V = 0x37, ZF32_X16V8X8__COV4R12V = 0x38, ZF32_X16V8S8__COV4R12V = 0x39, - Z16 = 0x3a, + D16 = 0x3a, V8Z24__COV8R24V = 0x3b, X8Z24_X16V8S8__COV8R24V = 0x3c, ZF32_X16V8X8__COV8R24V = 0x3d, @@ -375,7 +375,4 @@ struct FullTextureInfo { TSCEntry tsc; }; -/// Returns the number of bytes per pixel of the input texture format. -u32 BytesPerPixel(TextureFormat format); - } // namespace Tegra::Texture diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index a862b2610..656096c9f 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -133,11 +133,44 @@ file(GLOB COMPAT_LIST file(GLOB_RECURSE ICONS ${PROJECT_SOURCE_DIR}/dist/icons/*) file(GLOB_RECURSE THEMES ${PROJECT_SOURCE_DIR}/dist/qt_themes/*) +if (ENABLE_QT_TRANSLATION) + set(YUZU_QT_LANGUAGES "${PROJECT_SOURCE_DIR}/dist/languages" CACHE PATH "Path to the translation bundle for the Qt frontend") + option(GENERATE_QT_TRANSLATION "Generate en.ts as the translation source file" OFF) + + # Update source TS file if enabled + if (GENERATE_QT_TRANSLATION) + get_target_property(SRCS yuzu SOURCES) + qt5_create_translation(QM_FILES ${SRCS} ${UIS} ${YUZU_QT_LANGUAGES}/en.ts) + add_custom_target(translation ALL DEPENDS ${YUZU_QT_LANGUAGES}/en.ts) + endif() + + # Find all TS files except en.ts + file(GLOB_RECURSE LANGUAGES_TS ${YUZU_QT_LANGUAGES}/*.ts) + list(REMOVE_ITEM LANGUAGES_TS ${YUZU_QT_LANGUAGES}/en.ts) + + # Compile TS files to QM files + qt5_add_translation(LANGUAGES_QM ${LANGUAGES_TS}) + + # Build a QRC file from the QM file list + set(LANGUAGES_QRC ${CMAKE_CURRENT_BINARY_DIR}/languages.qrc) + file(WRITE ${LANGUAGES_QRC} "<RCC><qresource prefix=\"languages\">\n") + foreach (QM ${LANGUAGES_QM}) + get_filename_component(QM_FILE ${QM} NAME) + file(APPEND ${LANGUAGES_QRC} "<file>${QM_FILE}</file>\n") + endforeach (QM) + file(APPEND ${LANGUAGES_QRC} "</qresource></RCC>") + + # Add the QRC file to package in all QM files + qt5_add_resources(LANGUAGES ${LANGUAGES_QRC}) +else() + set(LANGUAGES) +endif() target_sources(yuzu PRIVATE ${COMPAT_LIST} ${ICONS} + ${LANGUAGES} ${THEMES} ) diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 9e9b38214..59a193edd 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -611,6 +611,7 @@ void Config::ReadPathValues() { } } UISettings::values.recent_files = ReadSetting(QStringLiteral("recentFiles")).toStringList(); + UISettings::values.language = ReadSetting(QStringLiteral("language"), QString{}).toString(); qt_config->endGroup(); } @@ -661,6 +662,8 @@ void Config::ReadRendererValues() { ReadSettingGlobal(Settings::values.use_vsync, QStringLiteral("use_vsync"), true); ReadSettingGlobal(Settings::values.use_assembly_shaders, QStringLiteral("use_assembly_shaders"), false); + ReadSettingGlobal(Settings::values.use_asynchronous_shaders, + QStringLiteral("use_asynchronous_shaders"), false); ReadSettingGlobal(Settings::values.use_fast_gpu_time, QStringLiteral("use_fast_gpu_time"), true); ReadSettingGlobal(Settings::values.force_30fps_mode, QStringLiteral("force_30fps_mode"), false); @@ -1093,6 +1096,7 @@ void Config::SavePathValues() { } qt_config->endArray(); WriteSetting(QStringLiteral("recentFiles"), UISettings::values.recent_files); + WriteSetting(QStringLiteral("language"), UISettings::values.language, QString{}); qt_config->endGroup(); } @@ -1145,6 +1149,8 @@ void Config::SaveRendererValues() { WriteSettingGlobal(QStringLiteral("use_vsync"), Settings::values.use_vsync, true); WriteSettingGlobal(QStringLiteral("use_assembly_shaders"), Settings::values.use_assembly_shaders, false); + WriteSettingGlobal(QStringLiteral("use_asynchronous_shaders"), + Settings::values.use_asynchronous_shaders, false); WriteSettingGlobal(QStringLiteral("use_fast_gpu_time"), Settings::values.use_fast_gpu_time, true); WriteSettingGlobal(QStringLiteral("force_30fps_mode"), Settings::values.force_30fps_mode, @@ -1368,11 +1374,13 @@ void Config::WriteSettingGlobal(const QString& name, const QVariant& value, bool void Config::Reload() { ReadValues(); + Settings::Sanitize(); // To apply default value changes SaveValues(); Settings::Apply(); } void Config::Save() { + Settings::Sanitize(); SaveValues(); } diff --git a/src/yuzu/configuration/configuration_shared.cpp b/src/yuzu/configuration/configuration_shared.cpp index bb47c3933..f9becab6e 100644 --- a/src/yuzu/configuration/configuration_shared.cpp +++ b/src/yuzu/configuration/configuration_shared.cpp @@ -4,17 +4,20 @@ #include <QCheckBox> #include <QComboBox> +#include <QObject> +#include <QString> #include "core/settings.h" #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_per_game.h" void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<bool>* setting, - const QCheckBox* checkbox) { - if (checkbox->checkState() == Qt::PartiallyChecked) { + const QCheckBox* checkbox, + const CheckState& tracker) { + if (tracker == CheckState::Global) { setting->SetGlobal(true); } else { setting->SetGlobal(false); - setting->SetValue(checkbox->checkState() == Qt::Checked); + setting->SetValue(checkbox->checkState()); } } @@ -69,8 +72,69 @@ void ConfigurationShared::SetPerGameSetting( ConfigurationShared::USE_GLOBAL_OFFSET); } -void ConfigurationShared::InsertGlobalItem(QComboBox* combobox) { - const QString use_global_text = ConfigurePerGame::tr("Use global configuration"); +void ConfigurationShared::SetHighlight(QWidget* widget, const std::string& name, bool highlighted) { + if (highlighted) { + widget->setStyleSheet(QStringLiteral("QWidget#%1 { background-color:rgba(0,203,255,0.5) }") + .arg(QString::fromStdString(name))); + } else { + widget->setStyleSheet(QStringLiteral("QWidget#%1 { background-color:rgba(0,0,0,0) }") + .arg(QString::fromStdString(name))); + } + widget->show(); +} + +void ConfigurationShared::SetColoredTristate(QCheckBox* checkbox, const std::string& name, + const Settings::Setting<bool>& setting, + CheckState& tracker) { + if (setting.UsingGlobal()) { + tracker = CheckState::Global; + } else { + tracker = (setting.GetValue() == setting.GetValue(true)) ? CheckState::On : CheckState::Off; + } + SetHighlight(checkbox, name, tracker != CheckState::Global); + QObject::connect(checkbox, &QCheckBox::clicked, checkbox, + [checkbox, name, setting, &tracker]() { + tracker = static_cast<CheckState>((static_cast<int>(tracker) + 1) % + static_cast<int>(CheckState::Count)); + if (tracker == CheckState::Global) { + checkbox->setChecked(setting.GetValue(true)); + } + SetHighlight(checkbox, name, tracker != CheckState::Global); + }); +} + +void ConfigurationShared::SetColoredTristate(QCheckBox* checkbox, const std::string& name, + bool global, bool state, bool global_state, + CheckState& tracker) { + if (global) { + tracker = CheckState::Global; + } else { + tracker = (state == global_state) ? CheckState::On : CheckState::Off; + } + SetHighlight(checkbox, name, tracker != CheckState::Global); + QObject::connect(checkbox, &QCheckBox::clicked, checkbox, + [checkbox, name, global_state, &tracker]() { + tracker = static_cast<CheckState>((static_cast<int>(tracker) + 1) % + static_cast<int>(CheckState::Count)); + if (tracker == CheckState::Global) { + checkbox->setChecked(global_state); + } + SetHighlight(checkbox, name, tracker != CheckState::Global); + }); +} + +void ConfigurationShared::SetColoredComboBox(QComboBox* combobox, QWidget* target, + const std::string& target_name, int global) { + InsertGlobalItem(combobox, global); + QObject::connect(combobox, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), target, + [target, target_name](int index) { + ConfigurationShared::SetHighlight(target, target_name, index != 0); + }); +} + +void ConfigurationShared::InsertGlobalItem(QComboBox* combobox, int global_index) { + const QString use_global_text = + ConfigurePerGame::tr("Use global configuration (%1)").arg(combobox->itemText(global_index)); combobox->insertItem(ConfigurationShared::USE_GLOBAL_INDEX, use_global_text); combobox->insertSeparator(ConfigurationShared::USE_GLOBAL_SEPARATOR_INDEX); } diff --git a/src/yuzu/configuration/configuration_shared.h b/src/yuzu/configuration/configuration_shared.h index b11b1b950..003148c68 100644 --- a/src/yuzu/configuration/configuration_shared.h +++ b/src/yuzu/configuration/configuration_shared.h @@ -15,9 +15,17 @@ constexpr int USE_GLOBAL_INDEX = 0; constexpr int USE_GLOBAL_SEPARATOR_INDEX = 1; constexpr int USE_GLOBAL_OFFSET = 2; +enum class CheckState { + Off, + On, + Global, + Count, +}; + // Global-aware apply and set functions -void ApplyPerGameSetting(Settings::Setting<bool>* setting, const QCheckBox* checkbox); +void ApplyPerGameSetting(Settings::Setting<bool>* setting, const QCheckBox* checkbox, + const CheckState& tracker); void ApplyPerGameSetting(Settings::Setting<int>* setting, const QComboBox* combobox); void ApplyPerGameSetting(Settings::Setting<Settings::RendererBackend>* setting, const QComboBox* combobox); @@ -31,6 +39,14 @@ void SetPerGameSetting(QComboBox* combobox, void SetPerGameSetting(QComboBox* combobox, const Settings::Setting<Settings::GPUAccuracy>* setting); -void InsertGlobalItem(QComboBox* combobox); +void SetHighlight(QWidget* widget, const std::string& name, bool highlighted); +void SetColoredTristate(QCheckBox* checkbox, const std::string& name, + const Settings::Setting<bool>& setting, CheckState& tracker); +void SetColoredTristate(QCheckBox* checkbox, const std::string& name, bool global, bool state, + bool global_state, CheckState& tracker); +void SetColoredComboBox(QComboBox* combobox, QWidget* target, const std::string& target_name, + int global); + +void InsertGlobalItem(QComboBox* combobox, int global_index); } // namespace ConfigurationShared diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp index cc021beec..fea632531 100644 --- a/src/yuzu/configuration/configure_audio.cpp +++ b/src/yuzu/configuration/configure_audio.cpp @@ -49,12 +49,9 @@ void ConfigureAudio::SetConfiguration() { ui->volume_slider->setValue(Settings::values.volume.GetValue() * ui->volume_slider->maximum()); - if (Settings::configuring_global) { - ui->toggle_audio_stretching->setChecked( - Settings::values.enable_audio_stretching.GetValue()); - } else { - ConfigurationShared::SetPerGameSetting(ui->toggle_audio_stretching, - &Settings::values.enable_audio_stretching); + ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching.GetValue()); + + if (!Settings::configuring_global) { if (Settings::values.volume.UsingGlobal()) { ui->volume_combo_box->setCurrentIndex(0); ui->volume_slider->setEnabled(false); @@ -62,6 +59,8 @@ void ConfigureAudio::SetConfiguration() { ui->volume_combo_box->setCurrentIndex(1); ui->volume_slider->setEnabled(true); } + ConfigurationShared::SetHighlight(ui->volume_layout, "volume_layout", + !Settings::values.volume.UsingGlobal()); } SetVolumeIndicatorText(ui->volume_slider->sliderPosition()); } @@ -120,7 +119,8 @@ void ConfigureAudio::ApplyConfiguration() { } } else { ConfigurationShared::ApplyPerGameSetting(&Settings::values.enable_audio_stretching, - ui->toggle_audio_stretching); + ui->toggle_audio_stretching, + enable_audio_stretching); if (ui->volume_combo_box->currentIndex() == 0) { Settings::values.volume.SetGlobal(true); } else { @@ -173,9 +173,14 @@ void ConfigureAudio::SetupPerGameUI() { return; } - ui->toggle_audio_stretching->setTristate(true); + ConfigurationShared::SetColoredTristate(ui->toggle_audio_stretching, "toggle_audio_stretching", + Settings::values.enable_audio_stretching, + enable_audio_stretching); connect(ui->volume_combo_box, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), - this, [this](int index) { ui->volume_slider->setEnabled(index == 1); }); + this, [this](int index) { + ui->volume_slider->setEnabled(index == 1); + ConfigurationShared::SetHighlight(ui->volume_layout, "volume_layout", index == 1); + }); ui->output_sink_combo_box->setVisible(false); ui->output_sink_label->setVisible(false); diff --git a/src/yuzu/configuration/configure_audio.h b/src/yuzu/configuration/configure_audio.h index d84f4a682..9dbd3d93e 100644 --- a/src/yuzu/configuration/configure_audio.h +++ b/src/yuzu/configuration/configure_audio.h @@ -7,6 +7,10 @@ #include <memory> #include <QWidget> +namespace ConfigurationShared { +enum class CheckState; +} + namespace Ui { class ConfigureAudio; } @@ -37,4 +41,6 @@ private: void SetupPerGameUI(); std::unique_ptr<Ui::ConfigureAudio> ui; + + ConfigurationShared::CheckState enable_audio_stretching; }; diff --git a/src/yuzu/configuration/configure_audio.ui b/src/yuzu/configuration/configure_audio.ui index 862ccb988..9bd0cca96 100644 --- a/src/yuzu/configuration/configure_audio.ui +++ b/src/yuzu/configuration/configure_audio.ui @@ -56,80 +56,91 @@ </layout> </item> <item> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <property name="topMargin"> - <number>0</number> - </property> - <item> - <widget class="QComboBox" name="volume_combo_box"> - <item> + <widget class="QWidget" name="volume_layout" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QComboBox" name="volume_combo_box"> + <item> + <property name="text"> + <string>Use global volume</string> + </property> + </item> + <item> + <property name="text"> + <string>Set volume:</string> + </property> + </item> + </widget> + </item> + <item> + <widget class="QLabel" name="volume_label"> <property name="text"> - <string>Use global volume</string> + <string>Volume:</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>30</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QSlider" name="volume_slider"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximum"> + <number>100</number> + </property> + <property name="pageStep"> + <number>10</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="volume_indicator"> + <property name="minimumSize"> + <size> + <width>32</width> + <height>0</height> + </size> </property> - </item> - <item> <property name="text"> - <string>Set volume:</string> + <string>0 %</string> </property> - </item> - </widget> - </item> - <item> - <widget class="QLabel" name="volume_label"> - <property name="text"> - <string>Volume:</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>30</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QSlider" name="volume_slider"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="maximum"> - <number>100</number> - </property> - <property name="pageStep"> - <number>10</number> - </property> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="volume_indicator"> - <property name="minimumSize"> - <size> - <width>32</width> - <height>0</height> - </size> - </property> - <property name="text"> - <string>0 %</string> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - </widget> - </item> - </layout> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + </layout> + </widget> </item> </layout> </widget> diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index a5afb354f..4e30dc51e 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -23,6 +23,7 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry) SetConfiguration(); PopulateSelectionList(); + connect(ui->uiTab, &ConfigureUi::LanguageChanged, this, &ConfigureDialog::OnLanguageChanged); connect(ui->selectorList, &QListWidget::itemSelectionChanged, this, &ConfigureDialog::UpdateVisibleTabs); @@ -98,6 +99,14 @@ void ConfigureDialog::PopulateSelectionList() { } } +void ConfigureDialog::OnLanguageChanged(const QString& locale) { + emit LanguageChanged(locale); + // first apply the configuration, and then restore the display + ApplyConfiguration(); + RetranslateUI(); + SetConfiguration(); +} + void ConfigureDialog::UpdateVisibleTabs() { const auto items = ui->selectorList->selectedItems(); if (items.isEmpty()) { diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h index 2d3bfc2da..4289bc225 100644 --- a/src/yuzu/configuration/configure_dialog.h +++ b/src/yuzu/configuration/configure_dialog.h @@ -22,6 +22,12 @@ public: void ApplyConfiguration(); +private slots: + void OnLanguageChanged(const QString& locale); + +signals: + void LanguageChanged(const QString& locale); + private: void changeEvent(QEvent* event) override; diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 20316c9cc..c0dbd9855 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -19,9 +19,10 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent) SetConfiguration(); - connect(ui->toggle_frame_limit, &QCheckBox::stateChanged, ui->frame_limit, [this]() { - ui->frame_limit->setEnabled(ui->toggle_frame_limit->checkState() == Qt::Checked); - }); + if (Settings::configuring_global) { + connect(ui->toggle_frame_limit, &QCheckBox::clicked, ui->frame_limit, + [this]() { ui->frame_limit->setEnabled(ui->toggle_frame_limit->isChecked()); }); + } } ConfigureGeneral::~ConfigureGeneral() = default; @@ -40,17 +41,12 @@ void ConfigureGeneral::SetConfiguration() { ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit.GetValue()); ui->frame_limit->setValue(Settings::values.frame_limit.GetValue()); - if (!Settings::configuring_global) { - if (Settings::values.use_multi_core.UsingGlobal()) { - ui->use_multi_core->setCheckState(Qt::PartiallyChecked); - } - if (Settings::values.use_frame_limit.UsingGlobal()) { - ui->toggle_frame_limit->setCheckState(Qt::PartiallyChecked); - } + if (Settings::configuring_global) { + ui->frame_limit->setEnabled(Settings::values.use_frame_limit.GetValue()); + } else { + ui->frame_limit->setEnabled(Settings::values.use_frame_limit.GetValue() && + use_frame_limit != ConfigurationShared::CheckState::Global); } - - ui->frame_limit->setEnabled(ui->toggle_frame_limit->checkState() == Qt::Checked && - ui->toggle_frame_limit->isEnabled()); } void ConfigureGeneral::ApplyConfiguration() { @@ -71,9 +67,9 @@ void ConfigureGeneral::ApplyConfiguration() { } } else { ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core, - ui->use_multi_core); + ui->use_multi_core, use_multi_core); - bool global_frame_limit = ui->toggle_frame_limit->checkState() == Qt::PartiallyChecked; + bool global_frame_limit = use_frame_limit == ConfigurationShared::CheckState::Global; Settings::values.use_frame_limit.SetGlobal(global_frame_limit); Settings::values.frame_limit.SetGlobal(global_frame_limit); if (!global_frame_limit) { @@ -109,6 +105,13 @@ void ConfigureGeneral::SetupPerGameUI() { ui->toggle_background_pause->setVisible(false); ui->toggle_hide_mouse->setVisible(false); - ui->toggle_frame_limit->setTristate(true); - ui->use_multi_core->setTristate(true); + ConfigurationShared::SetColoredTristate(ui->toggle_frame_limit, "toggle_frame_limit", + Settings::values.use_frame_limit, use_frame_limit); + ConfigurationShared::SetColoredTristate(ui->use_multi_core, "use_multi_core", + Settings::values.use_multi_core, use_multi_core); + + connect(ui->toggle_frame_limit, &QCheckBox::clicked, ui->frame_limit, [this]() { + ui->frame_limit->setEnabled(ui->toggle_frame_limit->isChecked() && + (use_frame_limit != ConfigurationShared::CheckState::Global)); + }); } diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h index 9c785c22e..323ffbd8f 100644 --- a/src/yuzu/configuration/configure_general.h +++ b/src/yuzu/configuration/configure_general.h @@ -7,6 +7,10 @@ #include <memory> #include <QWidget> +namespace ConfigurationShared { +enum class CheckState; +} + class HotkeyRegistry; namespace Ui { @@ -31,4 +35,7 @@ private: void SetupPerGameUI(); std::unique_ptr<Ui::ConfigureGeneral> ui; + + ConfigurationShared::CheckState use_frame_limit; + ConfigurationShared::CheckState use_multi_core; }; diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index cb4706bd6..3e42531c3 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -31,8 +31,14 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent) SetConfiguration(); - connect(ui->api, qOverload<int>(&QComboBox::currentIndexChanged), this, - [this] { UpdateDeviceComboBox(); }); + connect(ui->api, qOverload<int>(&QComboBox::currentIndexChanged), this, [this] { + UpdateDeviceComboBox(); + if (!Settings::configuring_global) { + ConfigurationShared::SetHighlight(ui->api_layout, "api_layout", + ui->api->currentIndex() != + ConfigurationShared::USE_GLOBAL_INDEX); + } + }); connect(ui->device, qOverload<int>(&QComboBox::activated), this, [this](int device) { UpdateDeviceSelection(device); }); @@ -65,25 +71,26 @@ void ConfigureGraphics::SetConfiguration() { ui->api->setEnabled(runtime_lock); ui->use_asynchronous_gpu_emulation->setEnabled(runtime_lock); ui->use_disk_shader_cache->setEnabled(runtime_lock); + ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue()); + ui->use_asynchronous_gpu_emulation->setChecked( + Settings::values.use_asynchronous_gpu_emulation.GetValue()); if (Settings::configuring_global) { ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue())); ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue()); - ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue()); - ui->use_asynchronous_gpu_emulation->setChecked( - Settings::values.use_asynchronous_gpu_emulation.GetValue()); } else { - ConfigurationShared::SetPerGameSetting(ui->use_disk_shader_cache, - &Settings::values.use_disk_shader_cache); - ConfigurationShared::SetPerGameSetting(ui->use_asynchronous_gpu_emulation, - &Settings::values.use_asynchronous_gpu_emulation); - ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend); + ConfigurationShared::SetHighlight(ui->api_layout, "api_layout", + !Settings::values.renderer_backend.UsingGlobal()); ConfigurationShared::SetPerGameSetting(ui->aspect_ratio_combobox, &Settings::values.aspect_ratio); ui->bg_combobox->setCurrentIndex(Settings::values.bg_red.UsingGlobal() ? 0 : 1); ui->bg_button->setEnabled(!Settings::values.bg_red.UsingGlobal()); + ConfigurationShared::SetHighlight(ui->ar_label, "ar_label", + !Settings::values.aspect_ratio.UsingGlobal()); + ConfigurationShared::SetHighlight(ui->bg_layout, "bg_layout", + !Settings::values.bg_red.UsingGlobal()); } UpdateBackgroundColorButton(QColor::fromRgbF(Settings::values.bg_red.GetValue(), @@ -135,9 +142,10 @@ void ConfigureGraphics::ApplyConfiguration() { ui->aspect_ratio_combobox); ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_disk_shader_cache, - ui->use_disk_shader_cache); + ui->use_disk_shader_cache, use_disk_shader_cache); ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_gpu_emulation, - ui->use_asynchronous_gpu_emulation); + ui->use_asynchronous_gpu_emulation, + use_asynchronous_gpu_emulation); if (ui->bg_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { Settings::values.bg_red.SetGlobal(true); @@ -241,10 +249,20 @@ void ConfigureGraphics::SetupPerGameUI() { } connect(ui->bg_combobox, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, - [this](int index) { ui->bg_button->setEnabled(index == 1); }); - - ui->use_disk_shader_cache->setTristate(true); - ui->use_asynchronous_gpu_emulation->setTristate(true); - ConfigurationShared::InsertGlobalItem(ui->aspect_ratio_combobox); - ConfigurationShared::InsertGlobalItem(ui->api); + [this](int index) { + ui->bg_button->setEnabled(index == 1); + ConfigurationShared::SetHighlight(ui->bg_layout, "bg_layout", index == 1); + }); + + ConfigurationShared::SetColoredTristate(ui->use_disk_shader_cache, "use_disk_shader_cache", + Settings::values.use_disk_shader_cache, + use_disk_shader_cache); + ConfigurationShared::SetColoredTristate( + ui->use_asynchronous_gpu_emulation, "use_asynchronous_gpu_emulation", + Settings::values.use_asynchronous_gpu_emulation, use_asynchronous_gpu_emulation); + + ConfigurationShared::SetColoredComboBox(ui->aspect_ratio_combobox, ui->ar_label, "ar_label", + Settings::values.aspect_ratio.GetValue(true)); + ConfigurationShared::InsertGlobalItem( + ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true))); } diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h index 24f01c739..b4961f719 100644 --- a/src/yuzu/configuration/configure_graphics.h +++ b/src/yuzu/configuration/configure_graphics.h @@ -10,6 +10,10 @@ #include <QWidget> #include "core/settings.h" +namespace ConfigurationShared { +enum class CheckState; +} + namespace Ui { class ConfigureGraphics; } @@ -42,6 +46,9 @@ private: std::unique_ptr<Ui::ConfigureGraphics> ui; QColor bg_color; + ConfigurationShared::CheckState use_disk_shader_cache; + ConfigurationShared::CheckState use_asynchronous_gpu_emulation; + std::vector<QString> vulkan_devices; u32 vulkan_device{}; }; diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index 62418fc14..62aa337e7 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui @@ -6,7 +6,7 @@ <rect> <x>0</x> <y>0</y> - <width>400</width> + <width>437</width> <height>321</height> </rect> </property> @@ -23,43 +23,56 @@ </property> <layout class="QVBoxLayout" name="verticalLayout_3"> <item> - <layout class="QHBoxLayout" name="horizontalLayout_4"> - <item> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>API:</string> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="api"> - <item> + <widget class="QWidget" name="api_layout" native="true"> + <layout class="QGridLayout" name="gridLayout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="horizontalSpacing"> + <number>6</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="api_label"> <property name="text"> - <string notr="true">OpenGL</string> + <string>API:</string> </property> - </item> - <item> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="api"> + <item> + <property name="text"> + <string notr="true">OpenGL</string> + </property> + </item> + <item> + <property name="text"> + <string notr="true">Vulkan</string> + </property> + </item> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="device_label"> <property name="text"> - <string notr="true">Vulkan</string> + <string>Device:</string> </property> - </item> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_5"> - <item> - <widget class="QLabel" name="label_3"> - <property name="text"> - <string>Device:</string> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="device"/> - </item> - </layout> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="device"/> + </item> + </layout> + </widget> </item> </layout> </widget> @@ -85,96 +98,133 @@ </widget> </item> <item> - <layout class="QHBoxLayout" name="horizontalLayout_6"> - <item> - <widget class="QLabel" name="ar_label"> - <property name="text"> - <string>Aspect Ratio:</string> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="aspect_ratio_combobox"> - <item> - <property name="text"> - <string>Default (16:9)</string> - </property> - </item> - <item> - <property name="text"> - <string>Force 4:3</string> - </property> - </item> - <item> - <property name="text"> - <string>Force 21:9</string> - </property> - </item> - <item> + <widget class="QWidget" name="aspect_ratio_layout" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_6"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="ar_label"> <property name="text"> - <string>Stretch to Window</string> + <string>Aspect Ratio:</string> </property> - </item> - </widget> - </item> - </layout> + </widget> + </item> + <item> + <widget class="QComboBox" name="aspect_ratio_combobox"> + <item> + <property name="text"> + <string>Default (16:9)</string> + </property> + </item> + <item> + <property name="text"> + <string>Force 4:3</string> + </property> + </item> + <item> + <property name="text"> + <string>Force 21:9</string> + </property> + </item> + <item> + <property name="text"> + <string>Stretch to Window</string> + </property> + </item> + </widget> + </item> + </layout> + </widget> </item> <item> - <layout class="QHBoxLayout" name="horizontalLayout_3"> - <item> - <widget class="QComboBox" name="bg_combobox"> - <property name="currentText"> - <string>Use global background color</string> - </property> - <property name="currentIndex"> - <number>0</number> - </property> - <property name="maxVisibleItems"> - <number>10</number> - </property> - <item> - <property name="text"> + <widget class="QWidget" name="bg_layout" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <property name="spacing"> + <number>6</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QComboBox" name="bg_combobox"> + <property name="currentText"> <string>Use global background color</string> </property> - </item> - <item> + <property name="currentIndex"> + <number>0</number> + </property> + <property name="maxVisibleItems"> + <number>10</number> + </property> + <item> + <property name="text"> + <string>Use global background color</string> + </property> + </item> + <item> + <property name="text"> + <string>Set background color:</string> + </property> + </item> + </widget> + </item> + <item> + <widget class="QLabel" name="bg_label"> <property name="text"> - <string>Set background color:</string> + <string>Background Color:</string> </property> - </item> - </widget> - </item> - <item> - <widget class="QLabel" name="bg_label"> - <property name="text"> - <string>Background Color:</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="bg_button"> - <property name="maximumSize"> - <size> - <width>40</width> - <height>16777215</height> - </size> - </property> - </widget> - </item> - </layout> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="bg_button"> + <property name="maximumSize"> + <size> + <width>40</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + </layout> + </widget> </item> </layout> </widget> diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 7c0fa7ec5..8b9180811 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -24,29 +24,29 @@ void ConfigureGraphicsAdvanced::SetConfiguration() { const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); ui->use_vsync->setEnabled(runtime_lock); ui->use_assembly_shaders->setEnabled(runtime_lock); + ui->use_asynchronous_shaders->setEnabled(runtime_lock); ui->force_30fps_mode->setEnabled(runtime_lock); ui->anisotropic_filtering_combobox->setEnabled(runtime_lock); + ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue()); + ui->use_assembly_shaders->setChecked(Settings::values.use_assembly_shaders.GetValue()); + ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue()); + ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue()); + ui->force_30fps_mode->setChecked(Settings::values.force_30fps_mode.GetValue()); + if (Settings::configuring_global) { ui->gpu_accuracy->setCurrentIndex( static_cast<int>(Settings::values.gpu_accuracy.GetValue())); - ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue()); - ui->use_assembly_shaders->setChecked(Settings::values.use_assembly_shaders.GetValue()); - ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue()); - ui->force_30fps_mode->setChecked(Settings::values.force_30fps_mode.GetValue()); ui->anisotropic_filtering_combobox->setCurrentIndex( Settings::values.max_anisotropy.GetValue()); } else { ConfigurationShared::SetPerGameSetting(ui->gpu_accuracy, &Settings::values.gpu_accuracy); - ConfigurationShared::SetPerGameSetting(ui->use_vsync, &Settings::values.use_vsync); - ConfigurationShared::SetPerGameSetting(ui->use_assembly_shaders, - &Settings::values.use_assembly_shaders); - ConfigurationShared::SetPerGameSetting(ui->use_fast_gpu_time, - &Settings::values.use_fast_gpu_time); - ConfigurationShared::SetPerGameSetting(ui->force_30fps_mode, - &Settings::values.force_30fps_mode); ConfigurationShared::SetPerGameSetting(ui->anisotropic_filtering_combobox, &Settings::values.max_anisotropy); + ConfigurationShared::SetHighlight(ui->label_gpu_accuracy, "label_gpu_accuracy", + !Settings::values.gpu_accuracy.UsingGlobal()); + ConfigurationShared::SetHighlight(ui->af_label, "af_label", + !Settings::values.max_anisotropy.UsingGlobal()); } } @@ -67,6 +67,14 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() { if (Settings::values.use_assembly_shaders.UsingGlobal()) { Settings::values.use_assembly_shaders.SetValue(ui->use_assembly_shaders->isChecked()); } + if (Settings::values.use_asynchronous_shaders.UsingGlobal()) { + Settings::values.use_asynchronous_shaders.SetValue( + ui->use_asynchronous_shaders->isChecked()); + } + if (Settings::values.use_asynchronous_shaders.UsingGlobal()) { + Settings::values.use_asynchronous_shaders.SetValue( + ui->use_asynchronous_shaders->isChecked()); + } if (Settings::values.use_fast_gpu_time.UsingGlobal()) { Settings::values.use_fast_gpu_time.SetValue(ui->use_fast_gpu_time->isChecked()); } @@ -80,13 +88,17 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() { } else { ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy, ui->anisotropic_filtering_combobox); - ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync); + ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync, + use_vsync); ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_assembly_shaders, - ui->use_assembly_shaders); + ui->use_assembly_shaders, use_assembly_shaders); + ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders, + ui->use_asynchronous_shaders, + use_asynchronous_shaders); ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time, - ui->use_fast_gpu_time); + ui->use_fast_gpu_time, use_fast_gpu_time); ConfigurationShared::ApplyPerGameSetting(&Settings::values.force_30fps_mode, - ui->force_30fps_mode); + ui->force_30fps_mode, force_30fps_mode); ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy, ui->anisotropic_filtering_combobox); @@ -117,6 +129,8 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() { ui->gpu_accuracy->setEnabled(Settings::values.gpu_accuracy.UsingGlobal()); ui->use_vsync->setEnabled(Settings::values.use_vsync.UsingGlobal()); ui->use_assembly_shaders->setEnabled(Settings::values.use_assembly_shaders.UsingGlobal()); + ui->use_asynchronous_shaders->setEnabled( + Settings::values.use_asynchronous_shaders.UsingGlobal()); ui->use_fast_gpu_time->setEnabled(Settings::values.use_fast_gpu_time.UsingGlobal()); ui->force_30fps_mode->setEnabled(Settings::values.force_30fps_mode.UsingGlobal()); ui->anisotropic_filtering_combobox->setEnabled( @@ -125,10 +139,22 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() { return; } - ConfigurationShared::InsertGlobalItem(ui->gpu_accuracy); - ui->use_vsync->setTristate(true); - ui->use_assembly_shaders->setTristate(true); - ui->use_fast_gpu_time->setTristate(true); - ui->force_30fps_mode->setTristate(true); - ConfigurationShared::InsertGlobalItem(ui->anisotropic_filtering_combobox); + ConfigurationShared::SetColoredTristate(ui->use_vsync, "use_vsync", Settings::values.use_vsync, + use_vsync); + ConfigurationShared::SetColoredTristate(ui->use_assembly_shaders, "use_assembly_shaders", + Settings::values.use_assembly_shaders, + use_assembly_shaders); + ConfigurationShared::SetColoredTristate( + ui->use_asynchronous_shaders, "use_asynchronous_shaders", + Settings::values.use_asynchronous_shaders, use_asynchronous_shaders); + ConfigurationShared::SetColoredTristate(ui->use_fast_gpu_time, "use_fast_gpu_time", + Settings::values.use_fast_gpu_time, use_fast_gpu_time); + ConfigurationShared::SetColoredTristate(ui->force_30fps_mode, "force_30fps_mode", + Settings::values.force_30fps_mode, force_30fps_mode); + ConfigurationShared::SetColoredComboBox( + ui->gpu_accuracy, ui->label_gpu_accuracy, "label_gpu_accuracy", + static_cast<int>(Settings::values.gpu_accuracy.GetValue(true))); + ConfigurationShared::SetColoredComboBox( + ui->anisotropic_filtering_combobox, ui->af_label, "af_label", + static_cast<int>(Settings::values.max_anisotropy.GetValue(true))); } diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h index c043588ff..3c4f6f7bb 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.h +++ b/src/yuzu/configuration/configure_graphics_advanced.h @@ -7,6 +7,10 @@ #include <memory> #include <QWidget> +namespace ConfigurationShared { +enum class CheckState; +} + namespace Ui { class ConfigureGraphicsAdvanced; } @@ -29,4 +33,10 @@ private: void SetupPerGameUI(); std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui; + + ConfigurationShared::CheckState use_vsync; + ConfigurationShared::CheckState use_assembly_shaders; + ConfigurationShared::CheckState use_asynchronous_shaders; + ConfigurationShared::CheckState use_fast_gpu_time; + ConfigurationShared::CheckState force_30fps_mode; }; diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui index 0021607ac..6a0d29c27 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.ui +++ b/src/yuzu/configuration/configure_graphics_advanced.ui @@ -6,7 +6,7 @@ <rect> <x>0</x> <y>0</y> - <width>400</width> + <width>404</width> <height>321</height> </rect> </property> @@ -23,34 +23,48 @@ </property> <layout class="QVBoxLayout" name="verticalLayout_3"> <item> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <item> - <widget class="QLabel" name="label_gpu_accuracy"> - <property name="text"> - <string>Accuracy Level:</string> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="gpu_accuracy"> - <item> + <widget class="QWidget" name="gpu_accuracy_layout" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="label_gpu_accuracy"> <property name="text"> - <string notr="true">Normal</string> + <string>Accuracy Level:</string> </property> - </item> - <item> - <property name="text"> - <string notr="true">High</string> - </property> - </item> - <item> - <property name="text"> - <string notr="true">Extreme(very slow)</string> - </property> - </item> - </widget> - </item> - </layout> + </widget> + </item> + <item> + <widget class="QComboBox" name="gpu_accuracy"> + <item> + <property name="text"> + <string notr="true">Normal</string> + </property> + </item> + <item> + <property name="text"> + <string notr="true">High</string> + </property> + </item> + <item> + <property name="text"> + <string notr="true">Extreme(very slow)</string> + </property> + </item> + </widget> + </item> + </layout> + </widget> </item> <item> <widget class="QCheckBox" name="use_vsync"> @@ -73,6 +87,16 @@ </widget> </item> <item> + <widget class="QCheckBox" name="use_asynchronous_shaders"> + <property name="toolTip"> + <string>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</string> + </property> + <property name="text"> + <string>Use asynchronous shader building (experimental, OpenGL or Assembly shaders only)</string> + </property> + </widget> + </item> + <item> <widget class="QCheckBox" name="force_30fps_mode"> <property name="text"> <string>Force 30 FPS mode</string> @@ -87,44 +111,58 @@ </widget> </item> <item> - <layout class="QHBoxLayout" name="horizontalLayout_1"> - <item> - <widget class="QLabel" name="af_label"> - <property name="text"> - <string>Anisotropic Filtering:</string> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="anisotropic_filtering_combobox"> - <item> - <property name="text"> - <string>Default</string> - </property> - </item> - <item> - <property name="text"> - <string>2x</string> - </property> - </item> - <item> + <widget class="QWidget" name="af_layout" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_1"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="af_label"> <property name="text"> - <string>4x</string> + <string>Anisotropic Filtering:</string> </property> - </item> - <item> - <property name="text"> - <string>8x</string> - </property> - </item> - <item> - <property name="text"> - <string>16x</string> - </property> - </item> - </widget> - </item> - </layout> + </widget> + </item> + <item> + <widget class="QComboBox" name="anisotropic_filtering_combobox"> + <item> + <property name="text"> + <string>Default</string> + </property> + </item> + <item> + <property name="text"> + <string>2x</string> + </property> + </item> + <item> + <property name="text"> + <string>4x</string> + </property> + </item> + <item> + <property name="text"> + <string>8x</string> + </property> + </item> + <item> + <property name="text"> + <string>16x</string> + </property> + </item> + </widget> + </item> + </layout> + </widget> </item> </layout> </widget> diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index 68e02738b..0c4daf147 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp @@ -67,21 +67,21 @@ void ConfigureSystem::SetConfiguration() { const auto rtc_time = Settings::values.custom_rtc.GetValue().value_or( std::chrono::seconds(QDateTime::currentSecsSinceEpoch())); + ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.GetValue().has_value()); + ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.GetValue().has_value() && + Settings::values.rng_seed.UsingGlobal()); + ui->rng_seed_edit->setText(rng_seed); + + ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.GetValue().has_value()); + ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.GetValue().has_value() && + Settings::values.rng_seed.UsingGlobal()); + ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count())); + if (Settings::configuring_global) { ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue()); ui->combo_region->setCurrentIndex(Settings::values.region_index.GetValue()); ui->combo_time_zone->setCurrentIndex(Settings::values.time_zone_index.GetValue()); ui->combo_sound->setCurrentIndex(Settings::values.sound_index.GetValue()); - - ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.GetValue().has_value()); - ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.GetValue().has_value() && - Settings::values.rng_seed.UsingGlobal()); - ui->rng_seed_edit->setText(rng_seed); - - ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.GetValue().has_value()); - ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.GetValue().has_value() && - Settings::values.rng_seed.UsingGlobal()); - ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count())); } else { ConfigurationShared::SetPerGameSetting(ui->combo_language, &Settings::values.language_index); @@ -90,27 +90,14 @@ void ConfigureSystem::SetConfiguration() { &Settings::values.time_zone_index); ConfigurationShared::SetPerGameSetting(ui->combo_sound, &Settings::values.sound_index); - if (Settings::values.rng_seed.UsingGlobal()) { - ui->rng_seed_checkbox->setCheckState(Qt::PartiallyChecked); - } else { - ui->rng_seed_checkbox->setCheckState( - Settings::values.rng_seed.GetValue().has_value() ? Qt::Checked : Qt::Unchecked); - ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.GetValue().has_value()); - if (Settings::values.rng_seed.GetValue().has_value()) { - ui->rng_seed_edit->setText(rng_seed); - } - } - - if (Settings::values.custom_rtc.UsingGlobal()) { - ui->custom_rtc_checkbox->setCheckState(Qt::PartiallyChecked); - } else { - ui->custom_rtc_checkbox->setCheckState( - Settings::values.custom_rtc.GetValue().has_value() ? Qt::Checked : Qt::Unchecked); - ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.GetValue().has_value()); - if (Settings::values.custom_rtc.GetValue().has_value()) { - ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count())); - } - } + ConfigurationShared::SetHighlight(ui->label_language, "label_language", + !Settings::values.language_index.UsingGlobal()); + ConfigurationShared::SetHighlight(ui->label_region, "label_region", + !Settings::values.region_index.UsingGlobal()); + ConfigurationShared::SetHighlight(ui->label_timezone, "label_timezone", + !Settings::values.time_zone_index.UsingGlobal()); + ConfigurationShared::SetHighlight(ui->label_sound, "label_sound", + !Settings::values.sound_index.UsingGlobal()); } } @@ -161,37 +148,44 @@ void ConfigureSystem::ApplyConfiguration() { ui->combo_time_zone); ConfigurationShared::ApplyPerGameSetting(&Settings::values.sound_index, ui->combo_sound); - switch (ui->rng_seed_checkbox->checkState()) { - case Qt::Checked: - Settings::values.rng_seed.SetGlobal(false); - Settings::values.rng_seed.SetValue(ui->rng_seed_edit->text().toULongLong(nullptr, 16)); - break; - case Qt::Unchecked: + switch (use_rng_seed) { + case ConfigurationShared::CheckState::On: + case ConfigurationShared::CheckState::Off: Settings::values.rng_seed.SetGlobal(false); - Settings::values.rng_seed.SetValue(std::nullopt); + if (ui->rng_seed_checkbox->isChecked()) { + Settings::values.rng_seed.SetValue( + ui->rng_seed_edit->text().toULongLong(nullptr, 16)); + } else { + Settings::values.rng_seed.SetValue(std::nullopt); + } break; - case Qt::PartiallyChecked: + case ConfigurationShared::CheckState::Global: Settings::values.rng_seed.SetGlobal(false); Settings::values.rng_seed.SetValue(std::nullopt); Settings::values.rng_seed.SetGlobal(true); break; + case ConfigurationShared::CheckState::Count: + break; } - switch (ui->custom_rtc_checkbox->checkState()) { - case Qt::Checked: - Settings::values.custom_rtc.SetGlobal(false); - Settings::values.custom_rtc.SetValue( - std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch())); - break; - case Qt::Unchecked: + switch (use_custom_rtc) { + case ConfigurationShared::CheckState::On: + case ConfigurationShared::CheckState::Off: Settings::values.custom_rtc.SetGlobal(false); - Settings::values.custom_rtc.SetValue(std::nullopt); + if (ui->custom_rtc_checkbox->isChecked()) { + Settings::values.custom_rtc.SetValue( + std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch())); + } else { + Settings::values.custom_rtc.SetValue(std::nullopt); + } break; - case Qt::PartiallyChecked: + case ConfigurationShared::CheckState::Global: Settings::values.custom_rtc.SetGlobal(false); Settings::values.custom_rtc.SetValue(std::nullopt); Settings::values.custom_rtc.SetGlobal(true); break; + case ConfigurationShared::CheckState::Count: + break; } } @@ -229,10 +223,23 @@ void ConfigureSystem::SetupPerGameUI() { return; } - ConfigurationShared::InsertGlobalItem(ui->combo_language); - ConfigurationShared::InsertGlobalItem(ui->combo_region); - ConfigurationShared::InsertGlobalItem(ui->combo_time_zone); - ConfigurationShared::InsertGlobalItem(ui->combo_sound); - ui->rng_seed_checkbox->setTristate(true); - ui->custom_rtc_checkbox->setTristate(true); + ConfigurationShared::SetColoredComboBox(ui->combo_language, ui->label_language, + "label_language", + Settings::values.language_index.GetValue(true)); + ConfigurationShared::SetColoredComboBox(ui->combo_region, ui->label_region, "label_region", + Settings::values.region_index.GetValue(true)); + ConfigurationShared::SetColoredComboBox(ui->combo_time_zone, ui->label_timezone, + "label_timezone", + Settings::values.time_zone_index.GetValue(true)); + ConfigurationShared::SetColoredComboBox(ui->combo_sound, ui->label_sound, "label_sound", + Settings::values.sound_index.GetValue(true)); + + ConfigurationShared::SetColoredTristate( + ui->rng_seed_checkbox, "rng_seed_checkbox", Settings::values.rng_seed.UsingGlobal(), + Settings::values.rng_seed.GetValue().has_value(), + Settings::values.rng_seed.GetValue(true).has_value(), use_rng_seed); + ConfigurationShared::SetColoredTristate( + ui->custom_rtc_checkbox, "custom_rtc_checkbox", Settings::values.custom_rtc.UsingGlobal(), + Settings::values.custom_rtc.GetValue().has_value(), + Settings::values.custom_rtc.GetValue(true).has_value(), use_custom_rtc); } diff --git a/src/yuzu/configuration/configure_system.h b/src/yuzu/configuration/configure_system.h index f317ef8b5..fc5cd2945 100644 --- a/src/yuzu/configuration/configure_system.h +++ b/src/yuzu/configuration/configure_system.h @@ -9,6 +9,10 @@ #include <QList> #include <QWidget> +namespace ConfigurationShared { +enum class CheckState; +} + namespace Ui { class ConfigureSystem; } @@ -41,4 +45,7 @@ private: int region_index = 0; int time_zone_index = 0; int sound_index = 0; + + ConfigurationShared::CheckState use_rng_seed; + ConfigurationShared::CheckState use_custom_rtc; }; diff --git a/src/yuzu/configuration/configure_system.ui b/src/yuzu/configuration/configure_system.ui index 9c8cca6dc..53b95658b 100644 --- a/src/yuzu/configuration/configure_system.ui +++ b/src/yuzu/configuration/configure_system.ui @@ -21,490 +21,494 @@ <property name="title"> <string>System Settings</string> </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="3" column="0"> - <widget class="QLabel" name="label_sound"> - <property name="text"> - <string>Sound output mode</string> - </property> - </widget> - </item> - <item row="4" column="0"> - <widget class="QLabel" name="label_console_id"> - <property name="text"> - <string>Console ID:</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QComboBox" name="combo_language"> - <property name="toolTip"> - <string>Note: this can be overridden when region setting is auto-select</string> - </property> - <item> - <property name="text"> - <string>Japanese (日本語)</string> - </property> - </item> - <item> - <property name="text"> - <string>English</string> - </property> - </item> - <item> - <property name="text"> - <string>French (français)</string> - </property> - </item> - <item> - <property name="text"> - <string>German (Deutsch)</string> - </property> - </item> - <item> - <property name="text"> - <string>Italian (italiano)</string> - </property> - </item> - <item> - <property name="text"> - <string>Spanish (español)</string> - </property> - </item> - <item> - <property name="text"> - <string>Chinese</string> - </property> - </item> - <item> - <property name="text"> - <string>Korean (한국어)</string> - </property> - </item> - <item> - <property name="text"> - <string>Dutch (Nederlands)</string> - </property> - </item> - <item> - <property name="text"> - <string>Portuguese (português)</string> - </property> - </item> - <item> - <property name="text"> - <string>Russian (Русский)</string> - </property> - </item> - <item> - <property name="text"> - <string>Taiwanese</string> - </property> - </item> - <item> - <property name="text"> - <string>British English</string> - </property> - </item> - <item> - <property name="text"> - <string>Canadian French</string> - </property> - </item> - <item> - <property name="text"> - <string>Latin American Spanish</string> - </property> - </item> - <item> - <property name="text"> - <string>Simplified Chinese</string> - </property> - </item> - <item> - <property name="text"> - <string>Traditional Chinese (正體中文)</string> - </property> - </item> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_region"> - <property name="text"> - <string>Region:</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QComboBox" name="combo_region"> - <item> - <property name="text"> - <string>Japan</string> - </property> - </item> - <item> - <property name="text"> - <string>USA</string> - </property> - </item> - <item> - <property name="text"> - <string>Europe</string> - </property> - </item> - <item> - <property name="text"> - <string>Australia</string> - </property> - </item> - <item> - <property name="text"> - <string>China</string> - </property> - </item> - <item> - <property name="text"> - <string>Korea</string> - </property> - </item> - <item> - <property name="text"> - <string>Taiwan</string> - </property> - </item> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_timezone"> - <property name="text"> - <string>Time Zone:</string> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QComboBox" name="combo_time_zone"> - <item> - <property name="text"> - <string>Auto</string> - </property> - </item> - <item> - <property name="text"> - <string>Default</string> - </property> - </item> - <item> - <property name="text"> - <string>CET</string> - </property> - </item> - <item> - <property name="text"> - <string>CST6CDT</string> - </property> - </item> - <item> - <property name="text"> - <string>Cuba</string> - </property> - </item> - <item> - <property name="text"> - <string>EET</string> - </property> - </item> - <item> - <property name="text"> - <string>Egypt</string> - </property> - </item> - <item> - <property name="text"> - <string>Eire</string> - </property> - </item> - <item> - <property name="text"> - <string>EST</string> - </property> - </item> - <item> - <property name="text"> - <string>EST5EDT</string> - </property> - </item> - <item> - <property name="text"> - <string>GB</string> - </property> - </item> - <item> - <property name="text"> - <string>GB-Eire</string> - </property> - </item> - <item> - <property name="text"> - <string>GMT</string> - </property> - </item> - <item> - <property name="text"> - <string>GMT+0</string> - </property> - </item> - <item> - <property name="text"> - <string>GMT-0</string> - </property> - </item> - <item> - <property name="text"> - <string>GMT0</string> - </property> - </item> - <item> - <property name="text"> - <string>Greenwich</string> - </property> - </item> - <item> - <property name="text"> - <string>Hongkong</string> - </property> - </item> - <item> - <property name="text"> - <string>HST</string> - </property> - </item> - <item> - <property name="text"> - <string>Iceland</string> - </property> - </item> - <item> - <property name="text"> - <string>Iran</string> - </property> - </item> - <item> - <property name="text"> - <string>Israel</string> - </property> - </item> - <item> - <property name="text"> - <string>Jamaica</string> - </property> - </item> - <item> - <property name="text"> - <string>Japan</string> - </property> - </item> - <item> - <property name="text"> - <string>Kwajalein</string> - </property> - </item> - <item> - <property name="text"> - <string>Libya</string> - </property> - </item> - <item> - <property name="text"> - <string>MET</string> - </property> - </item> - <item> - <property name="text"> - <string>MST</string> - </property> - </item> - <item> - <property name="text"> - <string>MST7MDT</string> - </property> - </item> - <item> - <property name="text"> - <string>Navajo</string> - </property> - </item> - <item> - <property name="text"> - <string>NZ</string> - </property> - </item> - <item> - <property name="text"> - <string>NZ-CHAT</string> - </property> - </item> - <item> - <property name="text"> - <string>Poland</string> - </property> - </item> - <item> - <property name="text"> - <string>Portugal</string> - </property> - </item> - <item> - <property name="text"> - <string>PRC</string> - </property> - </item> - <item> - <property name="text"> - <string>PST8PDT</string> - </property> - </item> - <item> - <property name="text"> - <string>ROC</string> - </property> - </item> - <item> - <property name="text"> - <string>ROK</string> - </property> - </item> - <item> - <property name="text"> - <string>Singapore</string> - </property> - </item> - <item> - <property name="text"> - <string>Turkey</string> - </property> - </item> - <item> - <property name="text"> - <string>UCT</string> - </property> - </item> - <item> - <property name="text"> - <string>Universal</string> - </property> - </item> - <item> - <property name="text"> - <string>UTC</string> - </property> - </item> - <item> - <property name="text"> - <string>W-SU</string> - </property> - </item> - <item> - <property name="text"> - <string>WET</string> - </property> - </item> - <item> - <property name="text"> - <string>Zulu</string> - </property> - </item> - </widget> - </item> - <item row="6" column="0"> - <widget class="QCheckBox" name="rng_seed_checkbox"> - <property name="text"> - <string>RNG Seed</string> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="QComboBox" name="combo_sound"> - <item> - <property name="text"> - <string>Mono</string> - </property> - </item> - <item> - <property name="text"> - <string>Stereo</string> - </property> - </item> - <item> - <property name="text"> - <string>Surround</string> - </property> - </item> - </widget> - </item> - <item row="0" column="0"> - <widget class="QLabel" name="label_language"> - <property name="text"> - <string>Language</string> - </property> - </widget> - </item> - <item row="4" column="1"> - <widget class="QPushButton" name="button_regenerate_console_id"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="layoutDirection"> - <enum>Qt::RightToLeft</enum> - </property> - <property name="text"> - <string>Regenerate</string> - </property> - </widget> - </item> - <item row="5" column="0"> - <widget class="QCheckBox" name="custom_rtc_checkbox"> - <property name="text"> - <string>Custom RTC</string> - </property> - </widget> - </item> - <item row="5" column="1"> - <widget class="QDateTimeEdit" name="custom_rtc_edit"> - <property name="minimumDate"> - <date> - <year>1970</year> - <month>1</month> - <day>1</day> - </date> - </property> - <property name="displayFormat"> - <string>d MMM yyyy h:mm:ss AP</string> - </property> - </widget> - </item> - <item row="6" column="1"> - <widget class="QLineEdit" name="rng_seed_edit"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="font"> - <font> - <family>Lucida Console</family> - </font> - </property> - <property name="inputMask"> - <string notr="true">HHHHHHHH</string> - </property> - <property name="maxLength"> - <number>8</number> - </property> - </widget> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="1" column="0"> + <widget class="QLabel" name="label_region"> + <property name="text"> + <string>Region:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QComboBox" name="combo_time_zone"> + <item> + <property name="text"> + <string>Auto</string> + </property> + </item> + <item> + <property name="text"> + <string>Default</string> + </property> + </item> + <item> + <property name="text"> + <string>CET</string> + </property> + </item> + <item> + <property name="text"> + <string>CST6CDT</string> + </property> + </item> + <item> + <property name="text"> + <string>Cuba</string> + </property> + </item> + <item> + <property name="text"> + <string>EET</string> + </property> + </item> + <item> + <property name="text"> + <string>Egypt</string> + </property> + </item> + <item> + <property name="text"> + <string>Eire</string> + </property> + </item> + <item> + <property name="text"> + <string>EST</string> + </property> + </item> + <item> + <property name="text"> + <string>EST5EDT</string> + </property> + </item> + <item> + <property name="text"> + <string>GB</string> + </property> + </item> + <item> + <property name="text"> + <string>GB-Eire</string> + </property> + </item> + <item> + <property name="text"> + <string>GMT</string> + </property> + </item> + <item> + <property name="text"> + <string>GMT+0</string> + </property> + </item> + <item> + <property name="text"> + <string>GMT-0</string> + </property> + </item> + <item> + <property name="text"> + <string>GMT0</string> + </property> + </item> + <item> + <property name="text"> + <string>Greenwich</string> + </property> + </item> + <item> + <property name="text"> + <string>Hongkong</string> + </property> + </item> + <item> + <property name="text"> + <string>HST</string> + </property> + </item> + <item> + <property name="text"> + <string>Iceland</string> + </property> + </item> + <item> + <property name="text"> + <string>Iran</string> + </property> + </item> + <item> + <property name="text"> + <string>Israel</string> + </property> + </item> + <item> + <property name="text"> + <string>Jamaica</string> + </property> + </item> + <item> + <property name="text"> + <string>Japan</string> + </property> + </item> + <item> + <property name="text"> + <string>Kwajalein</string> + </property> + </item> + <item> + <property name="text"> + <string>Libya</string> + </property> + </item> + <item> + <property name="text"> + <string>MET</string> + </property> + </item> + <item> + <property name="text"> + <string>MST</string> + </property> + </item> + <item> + <property name="text"> + <string>MST7MDT</string> + </property> + </item> + <item> + <property name="text"> + <string>Navajo</string> + </property> + </item> + <item> + <property name="text"> + <string>NZ</string> + </property> + </item> + <item> + <property name="text"> + <string>NZ-CHAT</string> + </property> + </item> + <item> + <property name="text"> + <string>Poland</string> + </property> + </item> + <item> + <property name="text"> + <string>Portugal</string> + </property> + </item> + <item> + <property name="text"> + <string>PRC</string> + </property> + </item> + <item> + <property name="text"> + <string>PST8PDT</string> + </property> + </item> + <item> + <property name="text"> + <string>ROC</string> + </property> + </item> + <item> + <property name="text"> + <string>ROK</string> + </property> + </item> + <item> + <property name="text"> + <string>Singapore</string> + </property> + </item> + <item> + <property name="text"> + <string>Turkey</string> + </property> + </item> + <item> + <property name="text"> + <string>UCT</string> + </property> + </item> + <item> + <property name="text"> + <string>Universal</string> + </property> + </item> + <item> + <property name="text"> + <string>UTC</string> + </property> + </item> + <item> + <property name="text"> + <string>W-SU</string> + </property> + </item> + <item> + <property name="text"> + <string>WET</string> + </property> + </item> + <item> + <property name="text"> + <string>Zulu</string> + </property> + </item> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="combo_region"> + <item> + <property name="text"> + <string>Japan</string> + </property> + </item> + <item> + <property name="text"> + <string>USA</string> + </property> + </item> + <item> + <property name="text"> + <string>Europe</string> + </property> + </item> + <item> + <property name="text"> + <string>Australia</string> + </property> + </item> + <item> + <property name="text"> + <string>China</string> + </property> + </item> + <item> + <property name="text"> + <string>Korea</string> + </property> + </item> + <item> + <property name="text"> + <string>Taiwan</string> + </property> + </item> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_timezone"> + <property name="text"> + <string>Time Zone:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="combo_language"> + <property name="toolTip"> + <string>Note: this can be overridden when region setting is auto-select</string> + </property> + <item> + <property name="text"> + <string>Japanese (日本語)</string> + </property> + </item> + <item> + <property name="text"> + <string>English</string> + </property> + </item> + <item> + <property name="text"> + <string>French (français)</string> + </property> + </item> + <item> + <property name="text"> + <string>German (Deutsch)</string> + </property> + </item> + <item> + <property name="text"> + <string>Italian (italiano)</string> + </property> + </item> + <item> + <property name="text"> + <string>Spanish (español)</string> + </property> + </item> + <item> + <property name="text"> + <string>Chinese</string> + </property> + </item> + <item> + <property name="text"> + <string>Korean (한국어)</string> + </property> + </item> + <item> + <property name="text"> + <string>Dutch (Nederlands)</string> + </property> + </item> + <item> + <property name="text"> + <string>Portuguese (português)</string> + </property> + </item> + <item> + <property name="text"> + <string>Russian (Русский)</string> + </property> + </item> + <item> + <property name="text"> + <string>Taiwanese</string> + </property> + </item> + <item> + <property name="text"> + <string>British English</string> + </property> + </item> + <item> + <property name="text"> + <string>Canadian French</string> + </property> + </item> + <item> + <property name="text"> + <string>Latin American Spanish</string> + </property> + </item> + <item> + <property name="text"> + <string>Simplified Chinese</string> + </property> + </item> + <item> + <property name="text"> + <string>Traditional Chinese (正體中文)</string> + </property> + </item> + </widget> + </item> + <item row="5" column="0"> + <widget class="QCheckBox" name="custom_rtc_checkbox"> + <property name="text"> + <string>Custom RTC</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label_language"> + <property name="text"> + <string>Language</string> + </property> + </widget> + </item> + <item row="6" column="0"> + <widget class="QCheckBox" name="rng_seed_checkbox"> + <property name="text"> + <string>RNG Seed</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QComboBox" name="combo_sound"> + <item> + <property name="text"> + <string>Mono</string> + </property> + </item> + <item> + <property name="text"> + <string>Stereo</string> + </property> + </item> + <item> + <property name="text"> + <string>Surround</string> + </property> + </item> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="label_console_id"> + <property name="text"> + <string>Console ID:</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_sound"> + <property name="text"> + <string>Sound output mode</string> + </property> + </widget> + </item> + <item row="5" column="1"> + <widget class="QDateTimeEdit" name="custom_rtc_edit"> + <property name="minimumDate"> + <date> + <year>1970</year> + <month>1</month> + <day>1</day> + </date> + </property> + <property name="displayFormat"> + <string>d MMM yyyy h:mm:ss AP</string> + </property> + </widget> + </item> + <item row="6" column="1"> + <widget class="QLineEdit" name="rng_seed_edit"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="font"> + <font> + <family>Lucida Console</family> + </font> + </property> + <property name="inputMask"> + <string notr="true">HHHHHHHH</string> + </property> + <property name="maxLength"> + <number>8</number> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QPushButton" name="button_regenerate_console_id"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="layoutDirection"> + <enum>Qt::RightToLeft</enum> + </property> + <property name="text"> + <string>Regenerate</string> + </property> + </widget> + </item> + </layout> </item> </layout> </widget> diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp index 94424ee44..24b6c5b72 100644 --- a/src/yuzu/configuration/configure_ui.cpp +++ b/src/yuzu/configuration/configure_ui.cpp @@ -5,6 +5,7 @@ #include <array> #include <utility> +#include <QDirIterator> #include "common/common_types.h" #include "core/settings.h" #include "ui_configure_ui.h" @@ -29,6 +30,8 @@ constexpr std::array row_text_names{ ConfigureUi::ConfigureUi(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureUi) { ui->setupUi(this); + InitializeLanguageComboBox(); + for (const auto& theme : UISettings::themes) { ui->theme_combobox->addItem(QString::fromUtf8(theme.first), QString::fromUtf8(theme.second)); @@ -72,6 +75,8 @@ void ConfigureUi::RequestGameListUpdate() { void ConfigureUi::SetConfiguration() { ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme)); + ui->language_combobox->setCurrentIndex( + ui->language_combobox->findData(UISettings::values.language)); ui->show_add_ons->setChecked(UISettings::values.show_add_ons); ui->icon_size_combobox->setCurrentIndex( ui->icon_size_combobox->findData(UISettings::values.icon_size)); @@ -100,6 +105,25 @@ void ConfigureUi::RetranslateUI() { } } +void ConfigureUi::InitializeLanguageComboBox() { + ui->language_combobox->addItem(tr("<System>"), QString{}); + ui->language_combobox->addItem(tr("English"), QStringLiteral("en")); + QDirIterator it(QStringLiteral(":/languages"), QDirIterator::NoIteratorFlags); + while (it.hasNext()) { + QString locale = it.next(); + locale.truncate(locale.lastIndexOf(QLatin1Char{'.'})); + locale.remove(0, locale.lastIndexOf(QLatin1Char{'/'}) + 1); + const QString lang = QLocale::languageToString(QLocale(locale).language()); + ui->language_combobox->addItem(lang, locale); + } + + // Unlike other configuration changes, interface language changes need to be reflected on the + // interface immediately. This is done by passing a signal to the main window, and then + // retranslating when passing back. + connect(ui->language_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, + &ConfigureUi::OnLanguageChanged); +} + void ConfigureUi::InitializeIconSizeComboBox() { for (const auto& size : default_icon_sizes) { ui->icon_size_combobox->addItem(QString::fromUtf8(size.second), size.first); @@ -147,3 +171,10 @@ void ConfigureUi::UpdateSecondRowComboBox(bool init) { ui->row_2_text_combobox->removeItem( ui->row_2_text_combobox->findData(ui->row_1_text_combobox->currentData())); } + +void ConfigureUi::OnLanguageChanged(int index) { + if (index == -1) + return; + + emit LanguageChanged(ui->language_combobox->itemData(index).toString()); +} diff --git a/src/yuzu/configuration/configure_ui.h b/src/yuzu/configuration/configure_ui.h index d471afe99..c30bcf6ff 100644 --- a/src/yuzu/configuration/configure_ui.h +++ b/src/yuzu/configuration/configure_ui.h @@ -20,6 +20,12 @@ public: void ApplyConfiguration(); +private slots: + void OnLanguageChanged(int index); + +signals: + void LanguageChanged(const QString& locale); + private: void RequestGameListUpdate(); @@ -28,6 +34,7 @@ private: void changeEvent(QEvent*) override; void RetranslateUI(); + void InitializeLanguageComboBox(); void InitializeIconSizeComboBox(); void InitializeRowComboBoxes(); diff --git a/src/yuzu/configuration/configure_ui.ui b/src/yuzu/configuration/configure_ui.ui index bd5c5d3c2..0b81747d7 100644 --- a/src/yuzu/configuration/configure_ui.ui +++ b/src/yuzu/configuration/configure_ui.ui @@ -13,112 +13,132 @@ <property name="windowTitle"> <string>Form</string> </property> - <layout class="QHBoxLayout" name="HorizontalLayout"> + <layout class="QVBoxLayout" name="verticalLayout"> <item> - <layout class="QVBoxLayout" name="VerticalLayout"> - <item> - <widget class="QGroupBox" name="GeneralGroupBox"> - <property name="title"> - <string>General</string> - </property> - <layout class="QHBoxLayout" name="horizontalLayout"> + <widget class="QGroupBox" name="general_groupBox"> + <property name="title"> + <string>General</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <layout class="QVBoxLayout" name="verticalLayout_2"> <item> - <layout class="QVBoxLayout" name="verticalLayout"> + <widget class="QLabel" name="label_change_language_info"> + <property name="text"> + <string>Note: Changing language will apply your configuration.</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLabel" name="language_label"> + <property name="text"> + <string>Interface language:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="language_combobox"/> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QLabel" name="theme_label"> + <property name="text"> + <string>Theme:</string> + </property> + </widget> + </item> <item> - <layout class="QHBoxLayout" name="horizontalLayout_3"> - <item> - <widget class="QLabel" name="theme_label"> - <property name="text"> - <string>Theme:</string> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="theme_combobox"/> - </item> - </layout> + <widget class="QComboBox" name="theme_combobox"/> </item> </layout> </item> </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="GameListGroupBox"> - <property name="title"> - <string>Game List</string> - </property> - <layout class="QHBoxLayout" name="GameListHorizontalLayout"> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="GameListGroupBox"> + <property name="title"> + <string>Game List</string> + </property> + <layout class="QHBoxLayout" name="GameListHorizontalLayout"> + <item> + <layout class="QVBoxLayout" name="GeneralVerticalLayout"> <item> - <layout class="QVBoxLayout" name="GeneralVerticalLayout"> + <widget class="QCheckBox" name="show_add_ons"> + <property name="text"> + <string>Show Add-Ons Column</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="icon_size_qhbox_layout_2"> <item> - <widget class="QCheckBox" name="show_add_ons"> + <widget class="QLabel" name="icon_size_label"> <property name="text"> - <string>Show Add-Ons Column</string> + <string>Icon Size:</string> </property> </widget> </item> <item> - <layout class="QHBoxLayout" name="icon_size_qhbox_layout_2"> - <item> - <widget class="QLabel" name="icon_size_label"> - <property name="text"> - <string>Icon Size:</string> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="icon_size_combobox"/> - </item> - </layout> + <widget class="QComboBox" name="icon_size_combobox"/> </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="row_1_qhbox_layout"> <item> - <layout class="QHBoxLayout" name="row_1_qhbox_layout"> - <item> - <widget class="QLabel" name="row_1_label"> - <property name="text"> - <string>Row 1 Text:</string> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="row_1_text_combobox"/> - </item> - </layout> + <widget class="QLabel" name="row_1_label"> + <property name="text"> + <string>Row 1 Text:</string> + </property> + </widget> </item> <item> - <layout class="QHBoxLayout" name="row_2_qhbox_layout"> - <item> - <widget class="QLabel" name="row_2_label"> - <property name="text"> - <string>Row 2 Text:</string> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="row_2_text_combobox"/> - </item> - </layout> + <widget class="QComboBox" name="row_1_text_combobox"/> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="row_2_qhbox_layout"> + <item> + <widget class="QLabel" name="row_2_label"> + <property name="text"> + <string>Row 2 Text:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="row_2_text_combobox"/> </item> </layout> </item> </layout> - </widget> - </item> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> </item> </layout> </widget> diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 9bb0a0109..3439cb333 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -2,9 +2,11 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <array> #include <fmt/format.h> #include "yuzu/debugger/wait_tree.h" +#include "yuzu/uisettings.h" #include "yuzu/util/util.h" #include "common/assert.h" @@ -19,11 +21,40 @@ #include "core/hle/kernel/thread.h" #include "core/memory.h" +namespace { + +constexpr std::array<std::array<Qt::GlobalColor, 2>, 10> WaitTreeColors{{ + {Qt::GlobalColor::darkGreen, Qt::GlobalColor::green}, + {Qt::GlobalColor::darkGreen, Qt::GlobalColor::green}, + {Qt::GlobalColor::darkBlue, Qt::GlobalColor::cyan}, + {Qt::GlobalColor::lightGray, Qt::GlobalColor::lightGray}, + {Qt::GlobalColor::lightGray, Qt::GlobalColor::lightGray}, + {Qt::GlobalColor::darkRed, Qt::GlobalColor::red}, + {Qt::GlobalColor::darkYellow, Qt::GlobalColor::yellow}, + {Qt::GlobalColor::red, Qt::GlobalColor::red}, + {Qt::GlobalColor::darkCyan, Qt::GlobalColor::cyan}, + {Qt::GlobalColor::gray, Qt::GlobalColor::gray}, +}}; + +bool IsDarkTheme() { + const auto& theme = UISettings::values.theme; + return theme == QStringLiteral("qdarkstyle") || + theme == QStringLiteral("qdarkstyle_midnight_blue") || + theme == QStringLiteral("colorful_dark") || + theme == QStringLiteral("colorful_midnight_blue"); +} + +} // namespace + WaitTreeItem::WaitTreeItem() = default; WaitTreeItem::~WaitTreeItem() = default; QColor WaitTreeItem::GetColor() const { - return QColor(Qt::GlobalColor::black); + if (IsDarkTheme()) { + return QColor(Qt::GlobalColor::white); + } else { + return QColor(Qt::GlobalColor::black); + } } std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeItem::GetChildren() const { @@ -263,36 +294,38 @@ QString WaitTreeThread::GetText() const { } QColor WaitTreeThread::GetColor() const { + const std::size_t color_index = IsDarkTheme() ? 1 : 0; + const auto& thread = static_cast<const Kernel::Thread&>(object); switch (thread.GetStatus()) { case Kernel::ThreadStatus::Running: - return QColor(Qt::GlobalColor::darkGreen); + return QColor(WaitTreeColors[0][color_index]); case Kernel::ThreadStatus::Ready: if (!thread.IsPaused()) { if (thread.WasRunning()) { - return QColor(Qt::GlobalColor::darkGreen); + return QColor(WaitTreeColors[1][color_index]); } else { - return QColor(Qt::GlobalColor::darkBlue); + return QColor(WaitTreeColors[2][color_index]); } } else { - return QColor(Qt::GlobalColor::lightGray); + return QColor(WaitTreeColors[3][color_index]); } case Kernel::ThreadStatus::Paused: - return QColor(Qt::GlobalColor::lightGray); + return QColor(WaitTreeColors[4][color_index]); case Kernel::ThreadStatus::WaitHLEEvent: case Kernel::ThreadStatus::WaitIPC: - return QColor(Qt::GlobalColor::darkRed); + return QColor(WaitTreeColors[5][color_index]); case Kernel::ThreadStatus::WaitSleep: - return QColor(Qt::GlobalColor::darkYellow); + return QColor(WaitTreeColors[6][color_index]); case Kernel::ThreadStatus::WaitSynch: case Kernel::ThreadStatus::WaitMutex: case Kernel::ThreadStatus::WaitCondVar: case Kernel::ThreadStatus::WaitArb: - return QColor(Qt::GlobalColor::red); + return QColor(WaitTreeColors[7][color_index]); case Kernel::ThreadStatus::Dormant: - return QColor(Qt::GlobalColor::darkCyan); + return QColor(WaitTreeColors[8][color_index]); case Kernel::ThreadStatus::Dead: - return QColor(Qt::GlobalColor::gray); + return QColor(WaitTreeColors[9][color_index]); default: return WaitTreeItem::GetColor(); } diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index d51cb2bcb..31a635176 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -94,6 +94,8 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "core/perf_stats.h" #include "core/settings.h" #include "core/telemetry_session.h" +#include "video_core/gpu.h" +#include "video_core/shader_notify.h" #include "yuzu/about_dialog.h" #include "yuzu/bootmanager.h" #include "yuzu/compatdb.h" @@ -189,6 +191,8 @@ GMainWindow::GMainWindow() provider(std::make_unique<FileSys::ManualContentProvider>()) { InitializeLogging(); + LoadTranslation(); + setAcceptDrops(true); ui.setupUi(this); statusBar()->hide(); @@ -279,17 +283,21 @@ GMainWindow::~GMainWindow() { } void GMainWindow::ProfileSelectorSelectProfile() { - QtProfileSelectionDialog dialog(this); - dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | - Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); - dialog.setWindowModality(Qt::WindowModal); - if (dialog.exec() == QDialog::Rejected) { - emit ProfileSelectorFinishedSelection(std::nullopt); - return; + const Service::Account::ProfileManager manager; + int index = 0; + if (manager.GetUserCount() != 1) { + QtProfileSelectionDialog dialog(this); + dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | + Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); + dialog.setWindowModality(Qt::WindowModal); + if (dialog.exec() == QDialog::Rejected) { + emit ProfileSelectorFinishedSelection(std::nullopt); + return; + } + index = dialog.GetIndex(); } - Service::Account::ProfileManager manager; - const auto uuid = manager.GetUser(static_cast<std::size_t>(dialog.GetIndex())); + const auto uuid = manager.GetUser(static_cast<std::size_t>(index)); if (!uuid.has_value()) { emit ProfileSelectorFinishedSelection(std::nullopt); return; @@ -494,6 +502,8 @@ void GMainWindow::InitializeWidgets() { message_label->setAlignment(Qt::AlignLeft); statusBar()->addPermanentWidget(message_label, 1); + shader_building_label = new QLabel(); + shader_building_label->setToolTip(tr("The amount of shaders currently being built")); emu_speed_label = new QLabel(); emu_speed_label->setToolTip( tr("Current emulation speed. Values higher or lower than 100% " @@ -506,7 +516,8 @@ void GMainWindow::InitializeWidgets() { tr("Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For " "full-speed emulation this should be at most 16.67 ms.")); - for (auto& label : {emu_speed_label, game_fps_label, emu_frametime_label}) { + for (auto& label : + {shader_building_label, emu_speed_label, game_fps_label, emu_frametime_label}) { label->setVisible(false); label->setFrameStyle(QFrame::NoFrame); label->setContentsMargins(4, 0, 4, 0); @@ -1172,6 +1183,7 @@ void GMainWindow::ShutdownGame() { // Disable status bar updates status_bar_update_timer.stop(); + shader_building_label->setVisible(false); emu_speed_label->setVisible(false); game_fps_label->setVisible(false); emu_frametime_label->setVisible(false); @@ -2038,6 +2050,9 @@ void GMainWindow::OnConfigure() { const bool old_discord_presence = UISettings::values.enable_discord_presence; ConfigureDialog configure_dialog(this, hotkey_registry); + connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this, + &GMainWindow::OnLanguageChanged); + const auto result = configure_dialog.exec(); if (result != QDialog::Accepted) { return; @@ -2182,6 +2197,17 @@ void GMainWindow::UpdateStatusBar() { } auto results = Core::System::GetInstance().GetAndResetPerfStats(); + auto& shader_notify = Core::System::GetInstance().GPU().ShaderNotify(); + const auto shaders_building = shader_notify.GetShadersBuilding(); + + if (shaders_building != 0) { + shader_building_label->setText( + tr("Building: %1 shader").arg(shaders_building) + + (shaders_building != 1 ? QString::fromStdString("s") : QString::fromStdString(""))); + shader_building_label->setVisible(true); + } else { + shader_building_label->setVisible(false); + } if (Settings::values.use_frame_limit.GetValue()) { emu_speed_label->setText(tr("Speed: %1% / %2%") @@ -2311,9 +2337,12 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { if (behavior == ReinitializeKeyBehavior::Warning) { const auto res = QMessageBox::information( this, tr("Confirm Key Rederivation"), - tr("You are about to force rederive all of your keys. \nIf you do not know what this " - "means or what you are doing, \nthis is a potentially destructive action. \nPlease " - "make sure this is what you want \nand optionally make backups.\n\nThis will delete " + tr("You are about to force rederive all of your keys. \nIf you do not know what " + "this " + "means or what you are doing, \nthis is a potentially destructive action. " + "\nPlease " + "make sure this is what you want \nand optionally make backups.\n\nThis will " + "delete " "your autogenerated key files and re-run the key derivation module."), QMessageBox::StandardButtons{QMessageBox::Ok, QMessageBox::Cancel}); @@ -2596,6 +2625,43 @@ void GMainWindow::UpdateUITheme() { QIcon::setThemeSearchPaths(theme_paths); } +void GMainWindow::LoadTranslation() { + // If the selected language is English, no need to install any translation + if (UISettings::values.language == QStringLiteral("en")) { + return; + } + + bool loaded; + + if (UISettings::values.language.isEmpty()) { + // If the selected language is empty, use system locale + loaded = translator.load(QLocale(), {}, {}, QStringLiteral(":/languages/")); + } else { + // Otherwise load from the specified file + loaded = translator.load(UISettings::values.language, QStringLiteral(":/languages/")); + } + + if (loaded) { + qApp->installTranslator(&translator); + } else { + UISettings::values.language = QStringLiteral("en"); + } +} + +void GMainWindow::OnLanguageChanged(const QString& locale) { + if (UISettings::values.language != QStringLiteral("en")) { + qApp->removeTranslator(&translator); + } + + UISettings::values.language = locale; + LoadTranslation(); + ui.retranslateUi(this); + UpdateWindowTitle(); + + if (emulation_running) + ui.action_Start->setText(tr("Continue")); +} + void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) { #ifdef USE_DISCORD_PRESENCE if (state) { @@ -2624,8 +2690,8 @@ int main(int argc, char* argv[]) { #ifdef __APPLE__ // If you start a bundle (binary) on OSX without the Terminal, the working directory is "/". - // But since we require the working directory to be the executable path for the location of the - // user folder in the Qt Frontend, we need to cd into that working directory + // But since we require the working directory to be the executable path for the location of + // the user folder in the Qt Frontend, we need to cd into that working directory const std::string bin_path = FileUtil::GetBundleDirectory() + DIR_SEP + ".."; chdir(bin_path.c_str()); #endif diff --git a/src/yuzu/main.h b/src/yuzu/main.h index adff65fb5..db573d606 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -10,6 +10,7 @@ #include <QMainWindow> #include <QTimer> +#include <QTranslator> #include "common/common_types.h" #include "core/core.h" @@ -225,6 +226,7 @@ private slots: void OnCaptureScreenshot(); void OnCoreError(Core::System::ResultStatus, std::string); void OnReinitializeKeys(ReinitializeKeyBehavior behavior); + void OnLanguageChanged(const QString& locale); private: std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id); @@ -237,6 +239,7 @@ private: void HideMouseCursor(); void ShowMouseCursor(); void OpenURL(const QUrl& url); + void LoadTranslation(); Ui::MainWindow ui; @@ -248,6 +251,7 @@ private: // Status bar elements QLabel* message_label = nullptr; + QLabel* shader_building_label = nullptr; QLabel* emu_speed_label = nullptr; QLabel* game_fps_label = nullptr; QLabel* emu_frametime_label = nullptr; @@ -284,6 +288,8 @@ private: HotkeyRegistry hotkey_registry; + QTranslator translator; + // Install progress dialog QProgressDialog* install_progress; diff --git a/src/yuzu/uisettings.cpp b/src/yuzu/uisettings.cpp index 738c4b2fc..a51175f36 100644 --- a/src/yuzu/uisettings.cpp +++ b/src/yuzu/uisettings.cpp @@ -11,6 +11,8 @@ const Themes themes{{ {"Light Colorful", "colorful"}, {"Dark", "qdarkstyle"}, {"Dark Colorful", "colorful_dark"}, + {"Midnight Blue", "qdarkstyle_midnight_blue"}, + {"Midnight Blue Colorful", "colorful_midnight_blue"}, }}; Values values = {}; diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index 830932d45..ac7b9aef6 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h @@ -24,7 +24,7 @@ struct Shortcut { ContextualShortcut shortcut; }; -using Themes = std::array<std::pair<const char*, const char*>, 4>; +using Themes = std::array<std::pair<const char*, const char*>, 6>; extern const Themes themes; struct GameDir { @@ -75,6 +75,7 @@ struct Values { bool game_dir_deprecated_deepscan; QVector<UISettings::GameDir> game_dirs; QStringList recent_files; + QString language; QString theme; diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index 7773228c8..c2a2982fb 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp @@ -394,6 +394,10 @@ void Config::ReadValues() { static_cast<u16>(sdl2_config->GetInteger("Renderer", "use_vsync", 1))); Settings::values.use_assembly_shaders.SetValue( sdl2_config->GetBoolean("Renderer", "use_assembly_shaders", false)); + Settings::values.use_asynchronous_shaders.SetValue( + sdl2_config->GetBoolean("Renderer", "use_asynchronous_shaders", false)); + Settings::values.use_asynchronous_shaders.SetValue( + sdl2_config->GetBoolean("Renderer", "use_asynchronous_shaders", false)); Settings::values.use_fast_gpu_time.SetValue( sdl2_config->GetBoolean("Renderer", "use_fast_gpu_time", true)); diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index 5bed47fd7..aa9e40380 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h @@ -166,6 +166,10 @@ use_vsync = # 0 (default): Off, 1: On use_assembly_shaders = +# Whether to allow asynchronous shader building. +# 0 (default): Off, 1: On +use_asynchronous_shaders = + # Turns on the frame limiter, which will limit frames output to the target game speed # 0: Off, 1: On (default) use_frame_limit = |