UI: Massive revamp, new features and improvements

This commit is contained in:
Connor McLaughlin 2022-07-11 23:03:29 +10:00
parent 3fb61865e5
commit b42b5501f6
425 changed files with 39701 additions and 29487 deletions

View file

@ -89,12 +89,12 @@ if(WIN32 AND USE_SDL2)
set(SDL2_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/sdl2/lib64/SDL2.lib") set(SDL2_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/sdl2/lib64/SDL2.lib")
set(SDL2MAIN_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/sdl2/lib64/SDL2main.lib") set(SDL2MAIN_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/sdl2/lib64/SDL2main.lib")
set(SDL2_DLL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/sdl2/bin64/SDL2.dll") set(SDL2_DLL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/sdl2/bin64/SDL2.dll")
set(Qt5_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/qt/5.15.0/msvc2017_64/lib/cmake/Qt5") set(Qt6_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/qt/6.1.0/msvc2019_64/lib/cmake/Qt6")
else() else()
set(SDL2_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/sdl2/lib32/SDL2.lib") set(SDL2_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/sdl2/lib32/SDL2.lib")
set(SDL2MAIN_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/sdl2/lib32/SDL2main.lib") set(SDL2MAIN_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/sdl2/lib32/SDL2main.lib")
set(SDL2_DLL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/sdl2/bin32/SDL2.dll") set(SDL2_DLL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/sdl2/bin32/SDL2.dll")
set(Qt5_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/qt/5.15.0/msvc2017_32/lib/cmake/Qt5") set(Qt6_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/qt/6.1.0/msvc2019_32/lib/cmake/Qt6")
endif() endif()
endif() endif()
@ -105,7 +105,7 @@ if(NOT ANDROID)
find_package(SDL2 REQUIRED) find_package(SDL2 REQUIRED)
endif() endif()
if(BUILD_QT_FRONTEND) if(BUILD_QT_FRONTEND)
find_package(Qt5 COMPONENTS Core Gui Widgets Network LinguistTools REQUIRED) find_package(Qt6 COMPONENTS Core Gui Widgets Network LinguistTools REQUIRED)
endif() endif()
endif() endif()

View file

@ -36683,7 +36683,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -94490,7 +94490,7 @@
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"PlayStationMouse", "PlayStationMouse",
"NamcoGuncon", "GunCon",
"KonamiJustifier" "KonamiJustifier"
], ],
"track_data": [ "track_data": [
@ -94528,7 +94528,7 @@
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"PlayStationMouse", "PlayStationMouse",
"NamcoGuncon", "GunCon",
"KonamiJustifier" "KonamiJustifier"
], ],
"track_data": [ "track_data": [
@ -94566,7 +94566,7 @@
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"PlayStationMouse", "PlayStationMouse",
"NamcoGuncon", "GunCon",
"KonamiJustifier" "KonamiJustifier"
], ],
"track_data": [ "track_data": [
@ -94604,7 +94604,7 @@
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"PlayStationMouse", "PlayStationMouse",
"NamcoGuncon", "GunCon",
"KonamiJustifier" "KonamiJustifier"
], ],
"track_data": [ "track_data": [
@ -94642,7 +94642,7 @@
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"PlayStationMouse", "PlayStationMouse",
"NamcoGuncon", "GunCon",
"KonamiJustifier" "KonamiJustifier"
], ],
"track_data": [ "track_data": [
@ -118156,7 +118156,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon", "GunCon",
"KonamiJustifier", "KonamiJustifier",
"PlayStationMouse" "PlayStationMouse"
], ],
@ -131024,7 +131024,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -159741,7 +159741,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon", "GunCon",
"KonamiJustifier", "KonamiJustifier",
"PlayStationMouse" "PlayStationMouse"
], ],
@ -161094,7 +161094,7 @@
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"PlayStationMouse", "PlayStationMouse",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -168086,7 +168086,7 @@
"linkCable": false, "linkCable": false,
"controllers": [ "controllers": [
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -168130,7 +168130,7 @@
"linkCable": false, "linkCable": false,
"controllers": [ "controllers": [
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -168166,7 +168166,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -168202,7 +168202,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -168264,7 +168264,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -168300,7 +168300,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
] ]
}, },
{ {
@ -169280,7 +169280,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -169316,7 +169316,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -169792,7 +169792,7 @@
"linkCable": false, "linkCable": false,
"controllers": [ "controllers": [
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -200165,7 +200165,7 @@
"linkCable": false, "linkCable": false,
"controllers": [ "controllers": [
"DigitalController", "DigitalController",
"NamcoGuncon", "GunCon",
"KonamiJustifier" "KonamiJustifier"
], ],
"track_data": [ "track_data": [
@ -200201,7 +200201,7 @@
"linkCable": false, "linkCable": false,
"controllers": [ "controllers": [
"DigitalController", "DigitalController",
"NamcoGuncon", "GunCon",
"KonamiJustifier" "KonamiJustifier"
], ],
"track_data": [ "track_data": [
@ -201057,7 +201057,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -243440,7 +243440,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon", "GunCon",
"KonamiJustifier" "KonamiJustifier"
], ],
"track_data": [ "track_data": [
@ -243477,7 +243477,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon", "GunCon",
"KonamiJustifier" "KonamiJustifier"
], ],
"track_data": [ "track_data": [
@ -250279,7 +250279,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon", "GunCon",
"KonamiJustifier" "KonamiJustifier"
], ],
"track_data": [ "track_data": [
@ -250316,7 +250316,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon", "GunCon",
"KonamiJustifier" "KonamiJustifier"
], ],
"track_data": [ "track_data": [
@ -257141,7 +257141,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -257262,7 +257262,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -290498,7 +290498,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
] ]
}, },
{ {
@ -313576,7 +313576,7 @@
"linkCable": false, "linkCable": false,
"controllers": [ "controllers": [
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -313620,7 +313620,7 @@
"linkCable": false, "linkCable": false,
"controllers": [ "controllers": [
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -313660,7 +313660,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -313696,7 +313696,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -313736,7 +313736,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -313772,7 +313772,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -313808,7 +313808,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
] ]
}, },
{ {
@ -323119,7 +323119,7 @@
"linkCable": false, "linkCable": false,
"controllers": [ "controllers": [
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -336352,7 +336352,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon", "GunCon",
"PlayStationMouse" "PlayStationMouse"
], ],
"track_data": [ "track_data": [
@ -336389,7 +336389,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon", "GunCon",
"PlayStationMouse" "PlayStationMouse"
] ]
}, },
@ -336437,7 +336437,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon", "GunCon",
"PlayStationMouse" "PlayStationMouse"
], ],
"track_data": [ "track_data": [
@ -336837,7 +336837,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -336874,7 +336874,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -336910,7 +336910,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -338230,7 +338230,7 @@
"linkCable": false, "linkCable": false,
"controllers": [ "controllers": [
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -338333,7 +338333,7 @@
"linkCable": false, "linkCable": false,
"controllers": [ "controllers": [
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -338436,7 +338436,7 @@
"linkCable": false, "linkCable": false,
"controllers": [ "controllers": [
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -338539,7 +338539,7 @@
"linkCable": false, "linkCable": false,
"controllers": [ "controllers": [
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -370386,7 +370386,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -372433,7 +372433,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -430122,7 +430122,7 @@
"linkCable": false, "linkCable": false,
"controllers": [ "controllers": [
"DigitalController", "DigitalController",
"NamcoGuncon", "GunCon",
"PlayStationMouse" "PlayStationMouse"
], ],
"track_data": [ "track_data": [
@ -430287,7 +430287,7 @@
"linkCable": false, "linkCable": false,
"controllers": [ "controllers": [
"DigitalController", "DigitalController",
"NamcoGuncon", "GunCon",
"PlayStationMouse" "PlayStationMouse"
], ],
"track_data": [ "track_data": [
@ -430451,7 +430451,7 @@
"linkCable": false, "linkCable": false,
"controllers": [ "controllers": [
"DigitalController", "DigitalController",
"NamcoGuncon", "GunCon",
"PlayStationMouse" "PlayStationMouse"
], ],
"track_data": [ "track_data": [
@ -430615,7 +430615,7 @@
"linkCable": false, "linkCable": false,
"controllers": [ "controllers": [
"DigitalController", "DigitalController",
"NamcoGuncon", "GunCon",
"PlayStationMouse" "PlayStationMouse"
], ],
"track_data": [ "track_data": [
@ -430780,7 +430780,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
] ]
}, },
{ {
@ -430810,7 +430810,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -431114,7 +431114,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -431234,7 +431234,7 @@
"controllers": [ "controllers": [
"AnalogController", "AnalogController",
"DigitalController", "DigitalController",
"NamcoGuncon" "GunCon"
], ],
"track_data": [ "track_data": [
{ {
@ -431353,7 +431353,7 @@
"linkCable": false, "linkCable": false,
"controllers": [ "controllers": [
"DigitalController", "DigitalController",
"NamcoGuncon", "GunCon",
"PlayStationMouse" "PlayStationMouse"
] ]
}, },

View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Binary file not shown.

View file

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View file

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View file

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 120 KiB

View file

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 117 KiB

View file

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View file

Before

Width:  |  Height:  |  Size: 202 KiB

After

Width:  |  Height:  |  Size: 202 KiB

View file

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View file

Before

Width:  |  Height:  |  Size: 6 KiB

After

Width:  |  Height:  |  Size: 6 KiB

View file

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

View file

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

View file

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

View file

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

@ -1 +1 @@
Subproject commit fb9018121818293b72e9f5064b2cb202e713c501 Subproject commit f44f99baad9c52e6e98831f95dde283b3c3d7993

View file

@ -2,36 +2,38 @@
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="UserMacros"> <PropertyGroup Label="UserMacros">
<BinaryOutputDir>$(SolutionDir)bin\$(Platform)\</BinaryOutputDir> <BinaryOutputDir>$(SolutionDir)bin\$(Platform)\</BinaryOutputDir>
<QTDIRDefault Condition="'$(Platform)'=='x64'">$(SolutionDir)dep\msvc\qt\6.1.0\msvc2019_64\</QTDIRDefault> <DSQTDIRDefault Condition="'$(Platform)'=='x64'">$(SolutionDir)dep\msvc\qt\6.1.0\msvc2019_64\</DSQTDIRDefault>
<QTDIRDefault Condition="'$(Platform)'=='ARM64'">$(SolutionDir)dep\msvc\qt\6.1.0\msvc2019_arm64\</QTDIRDefault> <DSQTDIRDefault Condition="'$(Platform)'=='ARM64'">$(SolutionDir)dep\msvc\qt\6.3.1\msvc2022_arm64\</DSQTDIRDefault>
<QTDIR Condition="Exists('$(QTDIRDefault)') And ('$(QTDIR)'=='' Or !Exists('$(QTDIR)'))">$(QTDIRDefault)</QTDIR> <DSQTDIR Condition="Exists('$(DSQTDIRDefault)') And ('$(DSQTDIR)'=='' Or !Exists('$(DSQTDIR)'))">$(DSQTDIRDefault)</DSQTDIR>
<QTDIR Condition="Exists('$(QTDIR)') And !HasTrailingSlash('$(QTDIR)')">$(QTDIR)\</QTDIR> <DSQTDIR Condition="Exists('$(DSQTDIR)') And !HasTrailingSlash('$(DSQTDIR)')">$(DSQTDIR)\</DSQTDIR>
<QTDIRHost>$(SolutionDir)dep\msvc\qt\6.1.0\msvc2019_64\</QTDIRHost> <DSQTDIRHost Condition="'$(Platform)'!='ARM64'">$(SolutionDir)dep\msvc\qt\6.1.0\msvc2019_64\</DSQTDIRHost>
<QtDirValid>false</QtDirValid> <DSQTDIRHost Condition="'$(Platform)'=='ARM64'">$(SolutionDir)dep\msvc\qt\6.3.1\msvc2022_64\</DSQTDIRHost>
<QtDirValid Condition="Exists('$(QTDIR)')">true</QtDirValid> <DSQTDIRValid>false</DSQTDIRValid>
<QtIncludeDir>$(QTDIR)include\</QtIncludeDir> <DSQTDIRValid Condition="Exists('$(DSQTDIR)')">true</DSQTDIRValid>
<QtLibDir>$(QTDIR)lib\</QtLibDir> <QtIncludeDir>$(DSQTDIR)include\</QtIncludeDir>
<QtBinDir>$(QTDIR)bin\</QtBinDir> <QtLibDir>$(DSQTDIR)lib\</QtLibDir>
<QtHostBinDir>$(QTDIRHost)bin\</QtHostBinDir> <QtBinDir>$(DSQTDIR)bin\</QtBinDir>
<QtPluginsDir>$(QTDIR)plugins\</QtPluginsDir> <QtHostBinDir>$(DSQTDIRHost)bin\</QtHostBinDir>
<QtTranslationsDir>$(QTDIR)translations\</QtTranslationsDir> <QtPluginsDir>$(DSQTDIR)plugins\</QtPluginsDir>
<QtToolOutDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</QtToolOutDir> <QtTranslationsDir>$(DSQTDIR)translations\</QtTranslationsDir>
<QtToolOutDir>$(IntDir)</QtToolOutDir>
<QtMocOutPrefix>$(QtToolOutDir)moc_</QtMocOutPrefix> <QtMocOutPrefix>$(QtToolOutDir)moc_</QtMocOutPrefix>
<QtTsOutDir>$(BinaryOutputDir)translations\</QtTsOutDir> <QtTsOutDir>$(BinaryOutputDir)translations\</QtTsOutDir>
<QtDebugSuffix>d</QtDebugSuffix> <QtDebugSuffix>d</QtDebugSuffix>
<QtLibSuffix Condition="'$(Configuration)'=='Debug' Or '$(Configuration)'=='DebugFast'">$(QtDebugSuffix)</QtLibSuffix> <QtLibSuffix Condition="$(Configuration.Contains(Debug))">$(QtDebugSuffix)</QtLibSuffix>
<QtPluginFolder>QtPlugins</QtPluginFolder> <QtPluginFolder>QtPlugins</QtPluginFolder>
<QtEntryPointLib>$(QtLibDir)Qt6EntryPoint$(QtLibSuffix).lib</QtEntryPointLib>
</PropertyGroup> </PropertyGroup>
<ItemDefinitionGroup> <ItemDefinitionGroup>
<ClCompile> <ClCompile>
<PreprocessorDefinitions Condition="'$(Configuration)'=='Release' Or '$(Configuration)'=='ReleaseLTCG'">QT_NO_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="!$(Configuration.Contains(Debug))">QT_NO_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(QtToolOutDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(QtToolOutDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(QtIncludeDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(QtIncludeDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalLibraryDirectories>$(QtLibDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(QtLibDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>Qt6Core$(QtLibSuffix).lib;Qt6Gui$(QtLibSuffix).lib;Qt6Widgets$(QtLibSuffix).lib;Qt6Network$(QtLibSuffix).lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>Qt6Core$(QtLibSuffix).lib;Qt6Gui$(QtLibSuffix).lib;Qt6Widgets$(QtLibSuffix).lib;Qt6Network$(QtLibSuffix).lib;Qt6Concurrent$(QtLibSuffix).lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
@ -45,7 +47,7 @@
Condition="'@(QtResource)'!=''" Condition="'@(QtResource)'!=''"
Outputs="@(ResFiles->'$(QtToolOutDir)qrc_%(Filename).cpp')"> Outputs="@(ResFiles->'$(QtToolOutDir)qrc_%(Filename).cpp')">
<Message Text="rcc %(ResFiles.Filename)" Importance="High" /> <Message Text="rcc %(ResFiles.Filename)" Importance="High" />
<Error Condition="!$(QtDirValid)" Text="QTDIR not set or non-existent (pull the submodule?)" /> <Error Condition="!$(DSQTDIRValid)" Text="Qt directory non-existent (pull the submodule?)" />
<MakeDir Directories="$(QtToolOutDir)" /> <MakeDir Directories="$(QtToolOutDir)" />
<Exec Command="&quot;$(QtHostBinDir)rcc.exe&quot; &quot;%(ResFiles.FullPath)&quot; -o &quot;$(QtToolOutDir)qrc_%(ResFiles.Filename).cpp&quot;" /> <Exec Command="&quot;$(QtHostBinDir)rcc.exe&quot; &quot;%(ResFiles.FullPath)&quot; -o &quot;$(QtToolOutDir)qrc_%(ResFiles.Filename).cpp&quot;" />
</Target> </Target>
@ -64,7 +66,7 @@
Condition="'@(QtUi)'!=''" Condition="'@(QtUi)'!=''"
Outputs="@(UiFiles->'$(QtToolOutDir)ui_%(Filename).h')"> Outputs="@(UiFiles->'$(QtToolOutDir)ui_%(Filename).h')">
<Message Text="uic %(UiFiles.Filename)" Importance="High" /> <Message Text="uic %(UiFiles.Filename)" Importance="High" />
<Error Condition="!$(QtDirValid)" Text="QTDIR not set or non-existent (pull the submodule?)" /> <Error Condition="!$(DSQTDIRValid)" Text="Qt directory non-existent (pull the submodule?)" />
<MakeDir Directories="$(QtToolOutDir)" /> <MakeDir Directories="$(QtToolOutDir)" />
<Exec Command="&quot;$(QtHostBinDir)uic.exe&quot; &quot;%(UiFiles.FullPath)&quot; -o &quot;$(QtToolOutDir)ui_%(UiFiles.Filename).h&quot;" /> <Exec Command="&quot;$(QtHostBinDir)uic.exe&quot; &quot;%(UiFiles.FullPath)&quot; -o &quot;$(QtToolOutDir)ui_%(UiFiles.Filename).h&quot;" />
</Target> </Target>
@ -77,26 +79,18 @@
<!--TODO find a way to autocreate from ClCompile settings--> <!--TODO find a way to autocreate from ClCompile settings-->
<PropertyGroup> <PropertyGroup>
<MocDefines></MocDefines> <MocDefines></MocDefines>
<MocDefines Condition="'$(Configuration)'=='Release' Or '$(Configuration)'=='ReleaseLTCG'">-DQT_NO_DEBUG -DNDEBUG $(MocDefines)</MocDefines> <MocDefines Condition="!$(Configuration.Contains(Debug))">-DQT_NO_DEBUG -DNDEBUG $(MocDefines)</MocDefines>
<!-- !!!HOLY UGLY BATMAN!!! <MocIncludes>-I"$(QtIncludeDir)." -I"$(SolutionDir)pcsx2" "-I$(SolutionDir)." -I.</MocIncludes>
Be very careful here when adding include directories. Each path must have the whole arg surrounded by doublequotes - HOWEVER,
the ending doublequote cannot be directly preceeded by a directory seperator. In other words, you must use:
"-I$(SomeDir) "
instead of
"-I$(SomeDir)"
in order to prevent the trailing slash from escaping the doublequote after value replacement.
-->
<MocIncludes>"-I$(QtIncludeDir)" "-I$(SolutionDir)src" -I.</MocIncludes>
</PropertyGroup> </PropertyGroup>
<Target Name="QtMoc" <Target Name="QtMoc"
BeforeTargets="ClCompile" BeforeTargets="ClCompile"
Condition="'@(QtMoc)'!=''" Condition="'@(QtMoc)'!=''"
Inputs="%(QtMoc.Identity);%(QtMoc.AdditionalDependencies);$(MSBuildProjectFile)" Inputs="%(QtMoc.Identity);%(QtMoc.AdditionalDependencies);$(MSBuildProjectFile)"
Outputs="$(QtToolOutDir)moc_%(QtMoc.Filename).cpp"> Outputs="$(QtToolOutDir)%(QtMoc.RelativeDir)moc_%(QtMoc.Filename).cpp">
<Message Text="moc %(QtMoc.Filename) $(QtToolOutDir)moc_%(QtMoc.Filename).cpp" Importance="High" /> <Message Text="moc %(QtMoc.Filename) $(QtToolOutDir)%(QtMoc.RelativeDir)moc_%(QtMoc.Filename).cpp" Importance="High" />
<Error Condition="!$(QtDirValid)" Text="QTDIR not set or non-existent (pull the submodule?)" /> <Error Condition="!$(DSQTDIRValid)" Text="Qt directory non-existent (pull the submodule?)" />
<MakeDir Directories="$(QtToolOutDir)" /> <MakeDir Directories="$(QtToolOutDir)" />
<Exec Command="&quot;$(QtHostBinDir)moc.exe&quot; &quot;%(QtMoc.FullPath)&quot; -o &quot;$(QtToolOutDir)moc_%(QtMoc.Filename).cpp&quot; -f%(QtMoc.Filename)%(QtMoc.Extension) $(MocDefines) $(MocIncludes)" /> <Exec Command="&quot;$(QtHostBinDir)moc.exe&quot; &quot;%(QtMoc.FullPath)&quot; -o &quot;$(QtToolOutDir)%(QtMoc.RelativeDir)moc_%(QtMoc.Filename).cpp&quot; -f%(QtMoc.Filename)%(QtMoc.Extension) $(MocDefines) $(MocIncludes)" />
</Target> </Target>
<ItemGroup> <ItemGroup>
@ -125,21 +119,24 @@
<!--Copy the needed dlls--> <!--Copy the needed dlls-->
<ItemGroup> <ItemGroup>
<QtLibNames Include="Qt6Core$(QtLibSuffix);Qt6Gui$(QtLibSuffix);Qt6Widgets$(QtLibSuffix);Qt6Network$(QtLibSuffix);Qt6Svg$(QtLibSuffix)" /> <QtLibNames Include="Qt6Core$(QtLibSuffix);Qt6Gui$(QtLibSuffix);Qt6Widgets$(QtLibSuffix);Qt6Network$(QtLibSuffix);Qt6Svg$(QtLibSuffix);Qt6Concurrent$(QtLibSuffix)" />
<QtDlls Include="@(QtLibNames -> '$(QtBinDir)%(Identity).dll')" /> <QtDlls Include="@(QtLibNames -> '$(QtBinDir)%(Identity).dll')" />
<!--Filter plugins to copy based on the observation that all debug versions end in "d"--> <!--Filter plugins to copy based on the observation that all debug versions end in "d"-->
<QtAllPlugins Include="$(QtPluginsDir)**\*$(QtLibSuffix).dll" /> <QtAllPlugins Include="$(QtPluginsDir)**\*$(QtLibSuffix).dll" />
<QtPlugins Condition="'$(Configuration)'=='Debug' Or '$(Configuration)'=='DebugFast'" Include="@(QtAllPlugins)" /> <QtPlugins Condition="$(Configuration.Contains(Debug))" Include="@(QtAllPlugins)" />
<QtPlugins Condition="'$(Configuration)'=='Release' Or '$(Configuration)'=='ReleaseLTCG'" Exclude="$(QtPluginsDir)**\*$(QtDebugSuffix).dll" Include="@(QtAllPlugins)" /> <QtPlugins Condition="!$(Configuration.Contains(Debug))" Exclude="$(QtPluginsDir)**\*$(QtDebugSuffix).dll" Include="@(QtAllPlugins)" />
<QtPluginsDest Include="@(QtPlugins -> '$(BinaryOutputDir)$(QtPluginFolder)\%(RecursiveDir)%(Filename)%(Extension)')" /> <QtPluginsDest Include="@(QtPlugins -> '$(BinaryOutputDir)$(QtPluginFolder)\%(RecursiveDir)%(Filename)%(Extension)')" />
<!--Our normal *d filter fails for the TLS DLLs, because backend ends in d. -->
<!--<QtTLSDlls Include="$(QtPluginsDir)tls\qcertonlybackend$(QtLibSuffix).dll;$(QtPluginsDir)tls\qschannelbackend$(QtLibSuffix).dll" />-->
<QtTLSDllsDest Include="@(QtTLSDlls -> '$(BinaryOutputDir)$(QtPluginFolder)\tls\%(Filename)%(Extension)')" />
</ItemGroup> </ItemGroup>
<PropertyGroup> <PropertyGroup>
<QtConfFile>$(BinaryOutputDir)qt.conf</QtConfFile> <QtConfFile>$(BinaryOutputDir)qt.conf</QtConfFile>
</PropertyGroup> </PropertyGroup>
<Target Name="QtCopyBinaries" <Target Name="QtCopyBinaries"
AfterTargets="Build" AfterTargets="Build"
Inputs="@(QtDlls);@(QtPlugins)" Inputs="@(QtDlls);@(QtPlugins);@(QtTLSDlls)"
Outputs="@(QtDlls -> '$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(Extension)');@(QtPlugins -> '$(BinaryOutputDir)$(QtPluginFolder)\%(RecursiveDir)%(Filename)%(Extension)')"> Outputs="@(QtDlls -> '$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(Extension)');@(QtPluginsDest);@(QtTLSDllsDest)">
<Message Text="Copying Qt .dlls" Importance="High" /> <Message Text="Copying Qt .dlls" Importance="High" />
<Copy <Copy
SourceFiles="@(QtDlls)" SourceFiles="@(QtDlls)"
@ -151,6 +148,11 @@
DestinationFiles="@(QtPluginsDest)" DestinationFiles="@(QtPluginsDest)"
SkipUnchangedFiles="true" SkipUnchangedFiles="true"
/> />
<Copy
SourceFiles="@(QtTLSDlls)"
DestinationFiles="@(QtTLSDllsDest)"
SkipUnchangedFiles="true"
/>
</Target> </Target>
<Target Name="QtCreateConf" <Target Name="QtCreateConf"
BeforeTargets="QtCopyBinaries" BeforeTargets="QtCopyBinaries"
@ -192,7 +194,7 @@
Condition="'@(QtTs)'!=''" Condition="'@(QtTs)'!=''"
Outputs="@(TsFiles->'$(QtTsOutDir)%(Filename).qm')"> Outputs="@(TsFiles->'$(QtTsOutDir)%(Filename).qm')">
<Message Text="lrelease %(TsFiles.Filename)" Importance="High" /> <Message Text="lrelease %(TsFiles.Filename)" Importance="High" />
<Error Condition="!$(QtDirValid)" Text="QTDIR not set or non-existent (pull the submodule?)" /> <Error Condition="!$(DSQTDIRValid)" Text="Qt directory non-existent (pull the submodule?)" />
<MakeDir Directories="$(QtTsOutDir)" /> <MakeDir Directories="$(QtTsOutDir)" />
<Exec Command="&quot;$(QtHostBinDir)lrelease.exe&quot; &quot;%(TsFiles.FullPath)&quot; -qm &quot;$(QtTsOutDir)%(TsFiles.Filename).qm&quot;" /> <Exec Command="&quot;$(QtHostBinDir)lrelease.exe&quot; &quot;%(TsFiles.FullPath)&quot; -qm &quot;$(QtTsOutDir)%(TsFiles.Filename).qm&quot;" />
</Target> </Target>

View file

@ -16,6 +16,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "src\common\common
{ED601289-AC1A-46B8-A8ED-17DB9EB73423} = {ED601289-AC1A-46B8-A8ED-17DB9EB73423} {ED601289-AC1A-46B8-A8ED-17DB9EB73423} = {ED601289-AC1A-46B8-A8ED-17DB9EB73423}
{8BDA439C-6358-45FB-9994-2FF083BABE06} = {8BDA439C-6358-45FB-9994-2FF083BABE06} {8BDA439C-6358-45FB-9994-2FF083BABE06} = {8BDA439C-6358-45FB-9994-2FF083BABE06}
{7FF9FDB9-D504-47DB-A16A-B08071999620} = {7FF9FDB9-D504-47DB-A16A-B08071999620} {7FF9FDB9-D504-47DB-A16A-B08071999620} = {7FF9FDB9-D504-47DB-A16A-B08071999620}
{8BE398E6-B882-4248-9065-FECC8728E038} = {8BE398E6-B882-4248-9065-FECC8728E038}
EndProjectSection EndProjectSection
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core", "src\core\core.vcxproj", "{868B98C8-65A1-494B-8346-250A73A48C0A}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core", "src\core\core.vcxproj", "{868B98C8-65A1-494B-8346-250A73A48C0A}"
@ -811,30 +812,22 @@ Global
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64 {39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32 {39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|ARM64.ActiveCfg = Debug|ARM64 {0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|ARM64.ActiveCfg = Debug|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|ARM64.Build.0 = Debug|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|x64.ActiveCfg = Debug|x64 {0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|x64.ActiveCfg = Debug|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|x64.Build.0 = Debug|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|x86.ActiveCfg = Debug|Win32 {0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|x86.ActiveCfg = Debug|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|x86.Build.0 = Debug|Win32 {0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|x86.Build.0 = Debug|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|ARM64.ActiveCfg = DebugFast|ARM64 {0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|ARM64.ActiveCfg = DebugFast|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|ARM64.Build.0 = DebugFast|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|x64.ActiveCfg = DebugFast|x64 {0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|x64.ActiveCfg = DebugFast|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|x64.Build.0 = DebugFast|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|x86.ActiveCfg = DebugFast|Win32 {0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|x86.ActiveCfg = DebugFast|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|x86.Build.0 = DebugFast|Win32 {0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|x86.Build.0 = DebugFast|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64 {0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugUWP|x64.ActiveCfg = DebugUWP|x64 {0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32 {0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|ARM64.ActiveCfg = Release|ARM64 {0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|ARM64.ActiveCfg = Release|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|ARM64.Build.0 = Release|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|x64.ActiveCfg = Release|x64 {0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|x64.ActiveCfg = Release|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|x64.Build.0 = Release|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|x86.ActiveCfg = Release|Win32 {0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|x86.ActiveCfg = Release|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|x86.Build.0 = Release|Win32 {0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|x86.Build.0 = Release|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|ARM64.ActiveCfg = ReleaseLTCG|ARM64 {0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|ARM64.ActiveCfg = ReleaseLTCG|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|ARM64.Build.0 = ReleaseLTCG|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|x64.ActiveCfg = ReleaseLTCG|x64 {0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|x64.ActiveCfg = ReleaseLTCG|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|x64.Build.0 = ReleaseLTCG|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|x86.ActiveCfg = ReleaseLTCG|Win32 {0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|x86.ActiveCfg = ReleaseLTCG|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|x86.Build.0 = ReleaseLTCG|Win32 {0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|x86.Build.0 = ReleaseLTCG|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64 {0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64

View file

@ -896,6 +896,105 @@ void GrowableMemoryByteStream::Grow(u32 MinimumGrowth)
ResizeMemory(NewSize); ResizeMemory(NewSize);
} }
bool ByteStream::ReadU8(u8* dest)
{
return Read2(dest, sizeof(u8));
}
bool ByteStream::ReadU16(u16* dest)
{
return Read2(dest, sizeof(u16));
}
bool ByteStream::ReadU32(u32* dest)
{
return Read2(dest, sizeof(u32));
}
bool ByteStream::ReadU64(u64* dest)
{
return Read2(dest, sizeof(u64));
}
bool ByteStream::ReadS8(s8* dest)
{
return Read2(dest, sizeof(s8));
}
bool ByteStream::ReadS16(s16* dest)
{
return Read2(dest, sizeof(s16));
}
bool ByteStream::ReadS32(s32* dest)
{
return Read2(dest, sizeof(s32));
}
bool ByteStream::ReadS64(s64* dest)
{
return Read2(dest, sizeof(s64));
}
bool ByteStream::ReadSizePrefixedString(std::string* dest)
{
u32 size;
if (!Read2(&size, sizeof(size)))
return false;
dest->resize(size);
if (!Read2(dest->data(), size))
return false;
return true;
}
bool ByteStream::WriteU8(u8 dest)
{
return Write2(&dest, sizeof(u8));
}
bool ByteStream::WriteU16(u16 dest)
{
return Write2(&dest, sizeof(u16));
}
bool ByteStream::WriteU32(u32 dest)
{
return Write2(&dest, sizeof(u32));
}
bool ByteStream::WriteU64(u64 dest)
{
return Write2(&dest, sizeof(u64));
}
bool ByteStream::WriteS8(s8 dest)
{
return Write2(&dest, sizeof(s8));
}
bool ByteStream::WriteS16(s16 dest)
{
return Write2(&dest, sizeof(s16));
}
bool ByteStream::WriteS32(s32 dest)
{
return Write2(&dest, sizeof(s32));
}
bool ByteStream::WriteS64(s64 dest)
{
return Write2(&dest, sizeof(s64));
}
bool ByteStream::WriteSizePrefixedString(const std::string_view& str)
{
const u32 size = static_cast<u32>(str.size());
return (Write2(&size, sizeof(size)) && (size == 0 || Write2(str.data(), size)));
}
std::unique_ptr<ByteStream> ByteStream::OpenFile(const char* fileName, u32 openMode) std::unique_ptr<ByteStream> ByteStream::OpenFile(const char* fileName, u32 openMode)
{ {
if ((openMode & (BYTESTREAM_OPEN_CREATE | BYTESTREAM_OPEN_WRITE)) == BYTESTREAM_OPEN_WRITE) if ((openMode & (BYTESTREAM_OPEN_CREATE | BYTESTREAM_OPEN_WRITE)) == BYTESTREAM_OPEN_WRITE)

View file

@ -2,6 +2,7 @@
#include "types.h" #include "types.h"
#include <memory> #include <memory>
#include <string> #include <string>
#include <string_view>
#include <vector> #include <vector>
// base byte stream creation functions // base byte stream creation functions
@ -76,6 +77,26 @@ public:
inline void SetErrorState() { m_errorState = true; } inline void SetErrorState() { m_errorState = true; }
inline void ClearErrorState() { m_errorState = false; } inline void ClearErrorState() { m_errorState = false; }
bool ReadU8(u8* dest);
bool ReadU16(u16* dest);
bool ReadU32(u32* dest);
bool ReadU64(u64* dest);
bool ReadS8(s8* dest);
bool ReadS16(s16* dest);
bool ReadS32(s32* dest);
bool ReadS64(s64* dest);
bool ReadSizePrefixedString(std::string* dest);
bool WriteU8(u8 dest);
bool WriteU16(u16 dest);
bool WriteU32(u32 dest);
bool WriteU64(u64 dest);
bool WriteS8(s8 dest);
bool WriteS16(s16 dest);
bool WriteS32(s32 dest);
bool WriteS64(s64 dest);
bool WriteSizePrefixedString(const std::string_view& str);
// base byte stream creation functions // base byte stream creation functions
// opens a local file-based stream. fills in error if passed, and returns false if the file cannot be opened. // opens a local file-based stream. fills in error if passed, and returns false if the file cannot be opened.
static std::unique_ptr<ByteStream> OpenFile(const char* FileName, u32 OpenMode); static std::unique_ptr<ByteStream> OpenFile(const char* FileName, u32 OpenMode);

View file

@ -167,7 +167,7 @@ std::string ShaderCache::GetCacheBaseFileName(const std::string_view& base_path,
bool debug) bool debug)
{ {
std::string base_filename(base_path); std::string base_filename(base_path);
base_filename += "d3d_shaders_"; base_filename += FS_OSPATH_SEPARATOR_STR "d3d_shaders_";
switch (feature_level) switch (feature_level)
{ {

View file

@ -226,7 +226,7 @@ std::string ShaderCache::GetCacheBaseFileName(const std::string_view& base_path,
D3D_FEATURE_LEVEL feature_level, bool debug) D3D_FEATURE_LEVEL feature_level, bool debug)
{ {
std::string base_filename(base_path); std::string base_filename(base_path);
base_filename += "d3d12_"; base_filename += FS_OSPATH_SEPARATOR_STR "d3d12_";
base_filename += type; base_filename += type;
base_filename += "_"; base_filename += "_";

View file

@ -2,6 +2,7 @@
#include "../file_system.h" #include "../file_system.h"
#include "../log.h" #include "../log.h"
#include "../md5_digest.h" #include "../md5_digest.h"
#include "../path.h"
#include "../string_util.h" #include "../string_util.h"
Log_SetChannel(GL::ShaderCache); Log_SetChannel(GL::ShaderCache);
@ -251,12 +252,12 @@ ShaderCache::CacheIndexKey ShaderCache::GetCacheKey(const std::string_view& vert
std::string ShaderCache::GetIndexFileName() const std::string ShaderCache::GetIndexFileName() const
{ {
return StringUtil::StdStringFromFormat("%sgl_programs.idx", m_base_path.c_str()); return Path::Combine(m_base_path, "gl_programs.idx");
} }
std::string ShaderCache::GetBlobFileName() const std::string ShaderCache::GetBlobFileName() const
{ {
return StringUtil::StdStringFromFormat("%sgl_programs.bin", m_base_path.c_str()); return Path::Combine(m_base_path, "gl_programs.bin");
} }
std::optional<Program> ShaderCache::GetProgram(const std::string_view vertex_shader, std::optional<Program> ShaderCache::GetProgram(const std::string_view vertex_shader,

View file

@ -7,7 +7,7 @@ Log_SetChannel(HTTPDownloader);
static constexpr float DEFAULT_TIMEOUT_IN_SECONDS = 30; static constexpr float DEFAULT_TIMEOUT_IN_SECONDS = 30;
static constexpr u32 DEFAULT_MAX_ACTIVE_REQUESTS = 4; static constexpr u32 DEFAULT_MAX_ACTIVE_REQUESTS = 4;
namespace FrontendCommon { namespace Common {
const char HTTPDownloader::DEFAULT_USER_AGENT[] = const char HTTPDownloader::DEFAULT_USER_AGENT[] =
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0"; "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0";

View file

@ -7,7 +7,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
namespace FrontendCommon { namespace Common {
class HTTPDownloader class HTTPDownloader
{ {

View file

@ -9,7 +9,7 @@
#include <signal.h> #include <signal.h>
Log_SetChannel(HTTPDownloaderCurl); Log_SetChannel(HTTPDownloaderCurl);
namespace FrontendCommon { namespace Common {
HTTPDownloaderCurl::HTTPDownloaderCurl() : HTTPDownloader() {} HTTPDownloaderCurl::HTTPDownloaderCurl() : HTTPDownloader() {}

View file

@ -6,7 +6,7 @@
#include <mutex> #include <mutex>
#include <curl/curl.h> #include <curl/curl.h>
namespace FrontendCommon { namespace Common {
class HTTPDownloaderCurl final : public HTTPDownloader class HTTPDownloaderCurl final : public HTTPDownloader
{ {

View file

@ -13,7 +13,7 @@ Log_SetChannel(HTTPDownloaderWinHttp);
using namespace winrt::Windows::Foundation; using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Web::Http; using namespace winrt::Windows::Web::Http;
namespace FrontendCommon { namespace Common {
HTTPDownloaderUWP::HTTPDownloaderUWP(std::string user_agent) : HTTPDownloader(), m_user_agent(std::move(user_agent)) {} HTTPDownloaderUWP::HTTPDownloaderUWP(std::string user_agent) : HTTPDownloader(), m_user_agent(std::move(user_agent)) {}

View file

@ -6,7 +6,7 @@
#include <winrt/windows.Web.Http.h> #include <winrt/windows.Web.Http.h>
namespace FrontendCommon { namespace Common {
class HTTPDownloaderUWP final : public HTTPDownloader class HTTPDownloaderUWP final : public HTTPDownloader
{ {

View file

@ -9,7 +9,7 @@ Log_SetChannel(HTTPDownloaderWinHttp);
#pragma comment(lib, "winhttp.lib") #pragma comment(lib, "winhttp.lib")
namespace FrontendCommon { namespace Common {
HTTPDownloaderWinHttp::HTTPDownloaderWinHttp() : HTTPDownloader() {} HTTPDownloaderWinHttp::HTTPDownloaderWinHttp() : HTTPDownloader() {}

View file

@ -5,7 +5,7 @@
#include <winhttp.h> #include <winhttp.h>
namespace FrontendCommon { namespace Common {
class HTTPDownloaderWinHttp final : public HTTPDownloader class HTTPDownloaderWinHttp final : public HTTPDownloader
{ {

View file

@ -1,4 +1,5 @@
#pragma once #pragma once
#include "heterogeneous_containers.h"
#include <cstdint> #include <cstdint>
#include <map> #include <map>
@ -13,7 +14,7 @@ class LRUCache
CounterType last_access; CounterType last_access;
}; };
using MapType = std::map<K, Item>; using MapType = std::conditional_t<std::is_same_v<K, std::string>, StringMap<Item>, std::map<K, Item>>;
public: public:
LRUCache(std::size_t max_capacity = 16, bool manual_evict = false) LRUCache(std::size_t max_capacity = 16, bool manual_evict = false)

View file

@ -24,15 +24,18 @@
#include <sys/syscall.h> #include <sys/syscall.h>
#define gettid() syscall(SYS_gettid) #define gettid() syscall(SYS_gettid)
#endif #endif
#else #elif defined(__APPLE__)
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <mach/mach_time.h>
#include <mach/semaphore.h>
#include <mach/task.h>
#include <pthread_np.h> #include <pthread_np.h>
#endif #endif
#endif #endif
#ifdef _WIN32 #ifdef _WIN32
// This hacky union would probably fail on some cpu platforms if the contents of FILETIME aren't union FileTimeU64Union
// packed (but for any x86 CPU and microsoft compiler, they will be).
union FileTimeSucks
{ {
FILETIME filetime; FILETIME filetime;
u64 u64time; u64 u64time;
@ -208,18 +211,16 @@ Threading::ThreadHandle& Threading::ThreadHandle::operator=(const ThreadHandle&
u64 Threading::ThreadHandle::GetCPUTime() const u64 Threading::ThreadHandle::GetCPUTime() const
{ {
#if defined(_WIN32) #if defined(_WIN32) && !defined(_UWP) && !defined(_M_ARM64)
#if 0
u64 ret = 0; u64 ret = 0;
if (m_native_handle) if (m_native_handle)
QueryThreadCycleTime((HANDLE)m_native_handle, &ret); QueryThreadCycleTime((HANDLE)m_native_handle, &ret);
return ret; return ret;
#else #elif defined(_WIN32)
FileTimeSucks user = {}, kernel = {}; FileTimeU64Union user = {}, kernel = {};
FILETIME dummy; FILETIME dummy;
GetThreadTimes((HANDLE)m_native_handle, &dummy, &dummy, &kernel.filetime, &user.filetime); GetThreadTimes((HANDLE)m_native_handle, &dummy, &dummy, &kernel.filetime, &user.filetime);
return user.u64time + kernel.u64time; return user.u64time + kernel.u64time;
#endif
#elif defined(__APPLE__) #elif defined(__APPLE__)
return getthreadtime(pthread_mach_thread_np((pthread_t)m_native_handle)); return getthreadtime(pthread_mach_thread_np((pthread_t)m_native_handle));
#elif defined(__linux__) #elif defined(__linux__)
@ -457,17 +458,15 @@ Threading::ThreadHandle& Threading::Thread::operator=(Thread&& thread)
u64 Threading::GetThreadCpuTime() u64 Threading::GetThreadCpuTime()
{ {
#if defined(_WIN32) #if defined(_WIN32) && !defined(_UWP) && !defined(_M_ARM64)
#if 0
u64 ret = 0; u64 ret = 0;
QueryThreadCycleTime(GetCurrentThread(), &ret); QueryThreadCycleTime(GetCurrentThread(), &ret);
return ret; return ret;
#else #elif defined(_WIN32)
FileTimeSucks user = {}, kernel = {}; FileTimeU64Union user = {}, kernel = {};
FILETIME dummy; FILETIME dummy;
GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &kernel.filetime, &user.filetime); GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &kernel.filetime, &user.filetime);
return user.u64time + kernel.u64time; return user.u64time + kernel.u64time;
#endif
#elif defined(__APPLE__) #elif defined(__APPLE__)
return getthreadtime(pthread_mach_thread_np(pthread_self())); return getthreadtime(pthread_mach_thread_np(pthread_self()));
#else #else
@ -477,17 +476,33 @@ u64 Threading::GetThreadCpuTime()
u64 Threading::GetThreadTicksPerSecond() u64 Threading::GetThreadTicksPerSecond()
{ {
#if defined(_WIN32) #if defined(_WIN32) && !defined(_UWP) && !defined(_M_ARM64)
#if 0
// On x86, despite what the MS documentation says, this basically appears to be rdtsc. // On x86, despite what the MS documentation says, this basically appears to be rdtsc.
// So, the frequency is our base clock speed (and stable regardless of power management). // So, the frequency is our base clock speed (and stable regardless of power management).
static u64 frequency = 0; static u64 frequency = 0;
if (unlikely(frequency == 0)) if (UNLIKELY(frequency == 0))
frequency = x86caps.CachedMHz() * u64(1000000); {
frequency = 1000000;
HKEY hKey;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &hKey) ==
ERROR_SUCCESS)
{
DWORD value;
DWORD value_size = sizeof(value);
if (RegQueryValueExW(hKey, L"~MHz", 0, nullptr, reinterpret_cast<LPBYTE>(&value), &value_size) == ERROR_SUCCESS)
{
// value is in mhz, convert to hz
frequency *= value;
}
RegCloseKey(hKey);
}
}
return frequency; return frequency;
#else #elif defined(_WIN32)
return 10000000; return 10000000;
#endif
#elif defined(__APPLE__) #elif defined(__APPLE__)
return 1000000; return 1000000;
@ -539,3 +554,60 @@ void Threading::SetNameOfCurrentThread(const char* name)
pthread_set_name_np(pthread_self(), name); pthread_set_name_np(pthread_self(), name);
#endif #endif
} }
Threading::KernelSemaphore::KernelSemaphore()
{
#ifdef _WIN32
m_sema = CreateSemaphore(nullptr, 0, LONG_MAX, nullptr);
#elif defined(__APPLE__)
semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, 0);
#else
sem_init(&m_sema, false, 0);
#endif
}
Threading::KernelSemaphore::~KernelSemaphore()
{
#ifdef _WIN32
CloseHandle(m_sema);
#elif defined(__APPLE__)
semaphore_destroy(mach_task_self(), m_sema);
#else
sem_destroy(&m_sema);
#endif
}
void Threading::KernelSemaphore::Post()
{
#ifdef _WIN32
ReleaseSemaphore(m_sema, 1, nullptr);
#elif defined(__APPLE__)
semaphore_signal(m_sema);
#else
sem_post(&m_sema);
#endif
}
void Threading::KernelSemaphore::Wait()
{
#ifdef _WIN32
WaitForSingleObject(m_sema, INFINITE);
#elif defined(__APPLE__)
semaphore_wait(m_sema);
#else
sem_wait(&m_sema);
#endif
}
bool Threading::KernelSemaphore::TryWait()
{
#ifdef _WIN32
return WaitForSingleObject(m_sema, 0) == WAIT_OBJECT_0;
#elif defined(__APPLE__)
mach_timespec_t time = {};
kern_return_t res = semaphore_timedwait(m_sema, time);
return (res != KERN_OPERATION_TIMED_OUT);
#else
return sem_trywait(&m_sema) == 0;
#endif
}

View file

@ -55,6 +55,16 @@ char (&__countof_ArraySizeHelper(T (&array)[N]))[N];
#define printflike(n,m) #define printflike(n,m)
#endif #endif
#ifdef _MSC_VER
// TODO: Use C++20 [[likely]] when available.
#define LIKELY(x) (!!(x))
#define UNLIKELY(x) (!!(x))
#else
#define LIKELY(x) __builtin_expect(!!(x), 1)
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
#endif
// disable warnings that show up at warning level 4 // disable warnings that show up at warning level 4
// TODO: Move to build system instead // TODO: Move to build system instead
#ifdef _MSC_VER #ifdef _MSC_VER

View file

@ -386,7 +386,7 @@ void ShaderCache::ClosePipelineCache()
std::string ShaderCache::GetShaderCacheBaseFileName(const std::string_view& base_path, bool debug) std::string ShaderCache::GetShaderCacheBaseFileName(const std::string_view& base_path, bool debug)
{ {
std::string base_filename(base_path); std::string base_filename(base_path);
base_filename += "vulkan_shaders"; base_filename += FS_OSPATH_SEPARATOR_STR "vulkan_shaders";
if (debug) if (debug)
base_filename += "_debug"; base_filename += "_debug";
@ -397,7 +397,7 @@ std::string ShaderCache::GetShaderCacheBaseFileName(const std::string_view& base
std::string ShaderCache::GetPipelineCacheBaseFileName(const std::string_view& base_path, bool debug) std::string ShaderCache::GetPipelineCacheBaseFileName(const std::string_view& base_path, bool debug)
{ {
std::string base_filename(base_path); std::string base_filename(base_path);
base_filename += "vulkan_pipelines"; base_filename += FS_OSPATH_SEPARATOR_STR "vulkan_pipelines";
if (debug) if (debug)
base_filename += "_debug"; base_filename += "_debug";

View file

@ -1,4 +1,5 @@
add_library(core add_library(core
achievements.h
analog_controller.cpp analog_controller.cpp
analog_controller.h analog_controller.h
analog_joystick.cpp analog_joystick.cpp
@ -28,6 +29,8 @@ add_library(core
digital_controller.h digital_controller.h
dma.cpp dma.cpp
dma.h dma.h
game_database.cpp
game_database.h
gdb_protocol.cpp gdb_protocol.cpp
gdb_protocol.h gdb_protocol.h
gpu.cpp gpu.cpp
@ -48,21 +51,18 @@ add_library(core
gpu_sw_backend.cpp gpu_sw_backend.cpp
gpu_sw_backend.h gpu_sw_backend.h
gpu_types.h gpu_types.h
guncon.cpp
guncon.h
gte.cpp gte.cpp
gte.h gte.h
gte_types.h gte_types.h
host.cpp
host.h host.h
host_display.cpp host_display.cpp
host_display.h host_display.h
host_interface.cpp
host_interface.h
host_interface_progress_callback.cpp host_interface_progress_callback.cpp
host_interface_progress_callback.h host_interface_progress_callback.h
host_settings.h host_settings.h
imgui_styles.cpp
imgui_styles.h
imgui_fullscreen.cpp
imgui_fullscreen.h
interrupt_controller.cpp interrupt_controller.cpp
interrupt_controller.h interrupt_controller.h
libcrypt_game_codes.cpp libcrypt_game_codes.cpp
@ -75,8 +75,6 @@ add_library(core
memory_card_image.h memory_card_image.h
multitap.cpp multitap.cpp
multitap.h multitap.h
namco_guncon.cpp
namco_guncon.h
negcon.cpp negcon.cpp
negcon.h negcon.h
pad.cpp pad.cpp
@ -123,7 +121,7 @@ set(RECOMPILER_SRCS
target_include_directories(core PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/..") target_include_directories(core PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/..")
target_include_directories(core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..") target_include_directories(core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..")
target_link_libraries(core PUBLIC Threads::Threads common util zlib) target_link_libraries(core PUBLIC Threads::Threads common util zlib)
target_link_libraries(core PRIVATE glad stb xxhash imgui) target_link_libraries(core PRIVATE glad stb xxhash imgui rapidjson tinyxml2)
if(WIN32) if(WIN32)
target_sources(core PRIVATE target_sources(core PRIVATE
@ -161,10 +159,5 @@ else()
endif() endif()
if(ENABLE_CHEEVOS) if(ENABLE_CHEEVOS)
target_sources(core PRIVATE target_compile_definitions(core PRIVATE -DWITH_CHEEVOS=1)
cheevos.cpp
cheevos.h
)
target_compile_definitions(core PUBLIC -DWITH_CHEEVOS=1)
target_link_libraries(core PRIVATE rcheevos rapidjson)
endif() endif()

55
src/core/achievements.h Normal file
View file

@ -0,0 +1,55 @@
#pragma once
#include "common/types.h"
class StateWrapper;
class CDImage;
namespace Achievements {
#ifdef WITH_CHEEVOS
// Implemented in Host.
extern bool Reset();
extern bool DoState(StateWrapper& sw);
extern void GameChanged(const std::string& path, CDImage* image);
/// Re-enables hardcode mode if it is enabled in the settings.
extern void ResetChallengeMode();
/// Forces hardcore mode off until next reset.
extern void DisableChallengeMode();
/// Prompts the user to disable hardcore mode, if they agree, returns true.
extern bool ConfirmChallengeModeDisable(const char* trigger);
/// Returns true if features such as save states should be disabled.
extern bool ChallengeModeActive();
#else
// Make noops when compiling without cheevos.
static inline bool Reset()
{
return true;
}
static inline bool DoState(StateWrapper& sw)
{
return true;
}
static constexpr inline bool ChallengeModeActive()
{
return false;
}
static inline void ResetChallengeMode() {}
static inline void DisableChallengeMode() {}
static inline bool ConfirmChallengeModeDisable(const char* trigger)
{
return true;
}
#endif
} // namespace Achievements

View file

@ -1,14 +1,14 @@
#include "analog_controller.h" #include "analog_controller.h"
#include "common/log.h" #include "common/log.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "host_interface.h" #include "host.h"
#include "settings.h" #include "settings.h"
#include "system.h" #include "system.h"
#include "util/state_wrapper.h" #include "util/state_wrapper.h"
#include <cmath> #include <cmath>
Log_SetChannel(AnalogController); Log_SetChannel(AnalogController);
AnalogController::AnalogController(u32 index) : m_index(index) AnalogController::AnalogController(u32 index) : Controller(index)
{ {
m_axis_state.fill(0x80); m_axis_state.fill(0x80);
Reset(); Reset();
@ -29,7 +29,12 @@ void AnalogController::Reset()
m_tx_buffer.fill(0x00); m_tx_buffer.fill(0x00);
m_analog_mode = false; m_analog_mode = false;
m_configuration_mode = false; m_configuration_mode = false;
m_motor_state.fill(0);
for (u32 i = 0; i < NUM_MOTORS; i++)
{
if (m_motor_state[i] != 0)
SetMotorState(i, 0);
}
m_dualshock_enabled = false; m_dualshock_enabled = false;
ResetRumbleConfig(); ResetRumbleConfig();
@ -40,8 +45,8 @@ void AnalogController::Reset()
{ {
if (g_settings.controller_disable_analog_mode_forcing) if (g_settings.controller_disable_analog_mode_forcing)
{ {
g_host_interface->AddOSDMessage( Host::AddOSDMessage(
g_host_interface->TranslateStdString( Host::TranslateStdString(
"OSDMessage", "Analog mode forcing is disabled by game settings. Controller will start in digital mode."), "OSDMessage", "Analog mode forcing is disabled by game settings. Controller will start in digital mode."),
10.0f); 10.0f);
} }
@ -88,72 +93,42 @@ bool AnalogController::DoState(StateWrapper& sw, bool apply_input_state)
if (old_analog_mode != m_analog_mode) if (old_analog_mode != m_analog_mode)
{ {
g_host_interface->AddFormattedOSDMessage( Host::AddFormattedOSDMessage(
5.0f, 5.0f,
m_analog_mode ? m_analog_mode ? Host::TranslateString("AnalogController", "Controller %u switched to analog mode.") :
g_host_interface->TranslateString("AnalogController", "Controller %u switched to analog mode.") : Host::TranslateString("AnalogController", "Controller %u switched to digital mode."),
g_host_interface->TranslateString("AnalogController", "Controller %u switched to digital mode."),
m_index + 1u); m_index + 1u);
} }
} }
return true; return true;
} }
std::optional<s32> AnalogController::GetAxisCodeByName(std::string_view axis_name) const float AnalogController::GetBindState(u32 index) const
{ {
return StaticGetAxisCodeByName(axis_name); if (index >= static_cast<u32>(Button::Count))
}
std::optional<s32> AnalogController::GetButtonCodeByName(std::string_view button_name) const
{ {
return StaticGetButtonCodeByName(button_name); const u32 sub_index = index - static_cast<u32>(Button::Count);
} if (sub_index >= static_cast<u32>(m_half_axis_state.size()))
float AnalogController::GetAxisState(s32 axis_code) const
{
if (axis_code < 0 || axis_code >= static_cast<s32>(Axis::Count))
return 0.0f; return 0.0f;
// 0..255 -> -1..1 return static_cast<float>(m_half_axis_state[sub_index]) * (1.0f / 255.0f);
const float value = (((static_cast<float>(m_axis_state[static_cast<s32>(axis_code)]) / 255.0f) * 2.0f) - 1.0f); }
return std::clamp(value / m_axis_scale, -1.0f, 1.0f); else if (index < static_cast<u32>(Button::Analog))
{
return static_cast<float>(((m_button_state >> index) & 1u) ^ 1u);
}
else
{
return 0.0f;
}
} }
void AnalogController::SetAxisState(s32 axis_code, float value) void AnalogController::SetBindState(u32 index, float value)
{ {
if (axis_code < 0 || axis_code >= static_cast<s32>(Axis::Count)) if (index == static_cast<s32>(Button::Analog))
return;
// -1..1 -> 0..255
const float scaled_value = std::clamp(value * m_axis_scale, -1.0f, 1.0f);
const u8 u8_value = static_cast<u8>(std::clamp(std::round(((scaled_value + 1.0f) / 2.0f) * 255.0f), 0.0f, 255.0f));
SetAxisState(static_cast<Axis>(axis_code), u8_value);
}
void AnalogController::SetAxisState(Axis axis, u8 value)
{
if (value != m_axis_state[static_cast<u8>(axis)])
System::SetRunaheadReplayFlag();
m_axis_state[static_cast<u8>(axis)] = value;
}
bool AnalogController::GetButtonState(s32 button_code) const
{
if (button_code < 0 || button_code >= static_cast<s32>(Button::Analog))
return false;
const u16 bit = u16(1) << static_cast<u8>(button_code);
return ((m_button_state & bit) == 0);
}
void AnalogController::SetButtonState(Button button, bool pressed)
{
if (button == Button::Analog)
{ {
// analog toggle // analog toggle
if (pressed) if (value >= 0.5f)
{ {
if (m_command == Command::Idle) if (m_command == Command::Idle)
ProcessAnalogModeToggle(); ProcessAnalogModeToggle();
@ -163,10 +138,58 @@ void AnalogController::SetButtonState(Button button, bool pressed)
return; return;
} }
else if (index >= static_cast<u32>(Button::Count))
{
const u32 sub_index = index - static_cast<u32>(Button::Count);
if (sub_index >= static_cast<u32>(m_half_axis_state.size()))
return;
const u16 bit = u16(1) << static_cast<u8>(button); value = ApplyAnalogDeadzoneSensitivity(m_analog_deadzone, m_analog_sensitivity, value);
const u8 u8_value = static_cast<u8>(std::clamp(value * 255.0f, 0.0f, 255.0f));
if (u8_value == m_half_axis_state[sub_index])
return;
if (pressed) m_half_axis_state[sub_index] = u8_value;
System::SetRunaheadReplayFlag();
#define MERGE(pos, neg) \
((m_half_axis_state[static_cast<u32>(pos)] != 0) ? (127u + ((m_half_axis_state[static_cast<u32>(pos)] + 1u) / 2u)) : \
(127u - (m_half_axis_state[static_cast<u32>(neg)] / 2u)))
switch (static_cast<HalfAxis>(sub_index))
{
case HalfAxis::LLeft:
case HalfAxis::LRight:
m_axis_state[static_cast<u8>(Axis::LeftX)] = MERGE(HalfAxis::LRight, HalfAxis::LLeft);
break;
case HalfAxis::LDown:
case HalfAxis::LUp:
m_axis_state[static_cast<u8>(Axis::LeftY)] = MERGE(HalfAxis::LDown, HalfAxis::LUp);
break;
case HalfAxis::RLeft:
case HalfAxis::RRight:
m_axis_state[static_cast<u8>(Axis::RightX)] = MERGE(HalfAxis::RRight, HalfAxis::RLeft);
break;
case HalfAxis::RDown:
case HalfAxis::RUp:
m_axis_state[static_cast<u8>(Axis::RightY)] = MERGE(HalfAxis::RDown, HalfAxis::RUp);
break;
default:
break;
}
#undef MERGE
return;
}
const u16 bit = u16(1) << static_cast<u8>(index);
if (value >= 0.5f)
{ {
if (m_button_state & bit) if (m_button_state & bit)
System::SetRunaheadReplayFlag(); System::SetRunaheadReplayFlag();
@ -182,14 +205,6 @@ void AnalogController::SetButtonState(Button button, bool pressed)
} }
} }
void AnalogController::SetButtonState(s32 button_code, bool pressed)
{
if (button_code < 0 || button_code >= static_cast<s32>(Button::Count))
return;
SetButtonState(static_cast<Button>(button_code), pressed);
}
u32 AnalogController::GetButtonStateBits() const u32 AnalogController::GetButtonStateBits() const
{ {
// flip bits, native data is active low // flip bits, native data is active low
@ -202,26 +217,6 @@ std::optional<u32> AnalogController::GetAnalogInputBytes() const
m_axis_state[static_cast<size_t>(Axis::RightY)] << 8 | m_axis_state[static_cast<size_t>(Axis::RightX)]; m_axis_state[static_cast<size_t>(Axis::RightY)] << 8 | m_axis_state[static_cast<size_t>(Axis::RightX)];
} }
u32 AnalogController::GetVibrationMotorCount() const
{
return NUM_MOTORS;
}
float AnalogController::GetVibrationMotorStrength(u32 motor)
{
DebugAssert(motor < NUM_MOTORS);
if (m_motor_state[motor] == 0)
return 0.0f;
// Curve from https://github.com/KrossX/Pokopom/blob/master/Pokopom/Input_XInput.cpp#L210
const double x =
static_cast<double>(std::min<u32>(static_cast<u32>(m_motor_state[motor]) + static_cast<u32>(m_rumble_bias), 255));
const double strength = 0.006474549734772402 * std::pow(x, 3.0) - 1.258165252213538 * std::pow(x, 2.0) +
156.82454281087692 * x + 3.637978807091713e-11;
return static_cast<float>(strength / 65535.0);
}
void AnalogController::ResetTransferState() void AnalogController::ResetTransferState()
{ {
if (m_analog_toggle_queued) if (m_analog_toggle_queued)
@ -240,10 +235,10 @@ void AnalogController::SetAnalogMode(bool enabled)
return; return;
Log_InfoPrintf("Controller %u switched to %s mode.", m_index + 1u, enabled ? "analog" : "digital"); Log_InfoPrintf("Controller %u switched to %s mode.", m_index + 1u, enabled ? "analog" : "digital");
g_host_interface->AddFormattedOSDMessage( Host::AddFormattedOSDMessage(5.0f,
5.0f, enabled ?
enabled ? g_host_interface->TranslateString("AnalogController", "Controller %u switched to analog mode.") : Host::TranslateString("AnalogController", "Controller %u switched to analog mode.") :
g_host_interface->TranslateString("AnalogController", "Controller %u switched to digital mode."), Host::TranslateString("AnalogController", "Controller %u switched to digital mode."),
m_index + 1u); m_index + 1u);
m_analog_mode = enabled; m_analog_mode = enabled;
} }
@ -252,11 +247,10 @@ void AnalogController::ProcessAnalogModeToggle()
{ {
if (m_analog_locked) if (m_analog_locked)
{ {
g_host_interface->AddFormattedOSDMessage( Host::AddFormattedOSDMessage(
5.0f, 5.0f,
m_analog_mode ? m_analog_mode ? Host::TranslateString("AnalogController", "Controller %u is locked to analog mode by the game.") :
g_host_interface->TranslateString("AnalogController", "Controller %u is locked to analog mode by the game.") : Host::TranslateString("AnalogController", "Controller %u is locked to digital mode by the game."),
g_host_interface->TranslateString("AnalogController", "Controller %u is locked to digital mode by the game."),
m_index + 1u); m_index + 1u);
} }
else else
@ -269,10 +263,32 @@ void AnalogController::ProcessAnalogModeToggle()
} }
} }
void AnalogController::SetMotorState(u8 motor, u8 value) void AnalogController::SetMotorState(u32 motor, u8 value)
{ {
DebugAssert(motor < NUM_MOTORS); DebugAssert(motor < NUM_MOTORS);
if (m_motor_state[motor] != value)
{
m_motor_state[motor] = value; m_motor_state[motor] = value;
UpdateHostVibration();
}
}
void AnalogController::UpdateHostVibration()
{
std::array<float, NUM_MOTORS> hvalues;
for (u32 motor = 0; motor < NUM_MOTORS; motor++)
{
// Curve from https://github.com/KrossX/Pokopom/blob/master/Pokopom/Input_XInput.cpp#L210
const u8 state = m_motor_state[motor];
const double x =
static_cast<double>(std::min<u32>(state + static_cast<u32>(m_rumble_bias), 255));
const double strength = 0.006474549734772402 * std::pow(x, 3.0) - 1.258165252213538 * std::pow(x, 2.0) +
156.82454281087692 * x + 3.637978807091713e-11;
hvalues[motor] = (state != 0) ? static_cast<float>(strength / 65535.0) : 0.0f;
}
Host::SetPadVibrationIntensity(m_index, hvalues[0], hvalues[1]);
} }
u8 AnalogController::GetExtraButtonMaskLSB() const u8 AnalogController::GetExtraButtonMaskLSB() const
@ -350,7 +366,7 @@ bool AnalogController::Transfer(const u8 data_in, u8* data_out)
if (data_in == 0x01) if (data_in == 0x01)
{ {
Log_DevPrintf("ACK controller access"); Log_DebugPrintf("ACK controller access");
m_command = Command::Ready; m_command = Command::Ready;
return true; return true;
} }
@ -689,9 +705,9 @@ bool AnalogController::Transfer(const u8 data_in, u8* data_out)
{ {
m_command = Command::Idle; m_command = Command::Idle;
Log_DevPrintf("Rx: %02x %02x %02x %02x %02x %02x %02x %02x", m_rx_buffer[0], m_rx_buffer[1], m_rx_buffer[2], Log_DebugPrintf("Rx: %02x %02x %02x %02x %02x %02x %02x %02x", m_rx_buffer[0], m_rx_buffer[1], m_rx_buffer[2],
m_rx_buffer[3], m_rx_buffer[4], m_rx_buffer[5], m_rx_buffer[6], m_rx_buffer[7]); m_rx_buffer[3], m_rx_buffer[4], m_rx_buffer[5], m_rx_buffer[6], m_rx_buffer[7]);
Log_DevPrintf("Tx: %02x %02x %02x %02x %02x %02x %02x %02x", m_tx_buffer[0], m_tx_buffer[1], m_tx_buffer[2], Log_DebugPrintf("Tx: %02x %02x %02x %02x %02x %02x %02x %02x", m_tx_buffer[0], m_tx_buffer[1], m_tx_buffer[2],
m_tx_buffer[3], m_tx_buffer[4], m_tx_buffer[5], m_tx_buffer[6], m_tx_buffer[7]); m_tx_buffer[3], m_tx_buffer[4], m_tx_buffer[5], m_tx_buffer[6], m_tx_buffer[7]);
m_rx_buffer.fill(0x00); m_rx_buffer.fill(0x00);
@ -706,122 +722,89 @@ std::unique_ptr<AnalogController> AnalogController::Create(u32 index)
return std::make_unique<AnalogController>(index); return std::make_unique<AnalogController>(index);
} }
std::optional<s32> AnalogController::StaticGetAxisCodeByName(std::string_view axis_name) static const Controller::ControllerBindingInfo s_binding_info[] = {
{ #define BUTTON(name, display_name, button, genb) \
#define AXIS(name) \
if (axis_name == #name) \
{ \ { \
return static_cast<s32>(ZeroExtend32(static_cast<u8>(Axis::name))); \ name, display_name, static_cast<u32>(button), Controller::ControllerBindingType::Button, genb \
}
#define AXIS(name, display_name, halfaxis, genb) \
{ \
name, display_name, static_cast<u32>(AnalogController::Button::Count) + static_cast<u32>(halfaxis), \
Controller::ControllerBindingType::HalfAxis, genb \
} }
AXIS(LeftX); BUTTON("Up", "D-Pad Up", AnalogController::Button::Up, GenericInputBinding::DPadUp),
AXIS(LeftY); BUTTON("Right", "D-Pad Right", AnalogController::Button::Right, GenericInputBinding::DPadRight),
AXIS(RightX); BUTTON("Down", "D-Pad Down", AnalogController::Button::Down, GenericInputBinding::DPadDown),
AXIS(RightY); BUTTON("Left", "D-Pad Left", AnalogController::Button::Left, GenericInputBinding::DPadLeft),
BUTTON("Triangle", "Triangle", AnalogController::Button::Triangle, GenericInputBinding::Triangle),
BUTTON("Circle", "Circle", AnalogController::Button::Circle, GenericInputBinding::Circle),
BUTTON("Cross", "Cross", AnalogController::Button::Cross, GenericInputBinding::Cross),
BUTTON("Square", "Square", AnalogController::Button::Square, GenericInputBinding::Square),
BUTTON("Select", "Select", AnalogController::Button::Select, GenericInputBinding::Select),
BUTTON("Start", "Start", AnalogController::Button::Start, GenericInputBinding::Start),
BUTTON("Analog", "Analog Toggle", AnalogController::Button::Analog, GenericInputBinding::System),
BUTTON("L1", "L1", AnalogController::Button::L1, GenericInputBinding::L1),
BUTTON("R1", "R1", AnalogController::Button::R1, GenericInputBinding::R1),
BUTTON("L2", "L2", AnalogController::Button::L2, GenericInputBinding::L2),
BUTTON("R2", "R2", AnalogController::Button::R2, GenericInputBinding::R2),
BUTTON("L3", "L3", AnalogController::Button::L3, GenericInputBinding::L3),
BUTTON("R3", "R3", AnalogController::Button::R3, GenericInputBinding::R3),
return std::nullopt; AXIS("LLeft", "Left Stick Left", AnalogController::HalfAxis::LLeft, GenericInputBinding::LeftStickLeft),
AXIS("LRight", "Left Stick Right", AnalogController::HalfAxis::LRight, GenericInputBinding::LeftStickRight),
AXIS("LDown", "Left Stick Down", AnalogController::HalfAxis::LDown, GenericInputBinding::LeftStickDown),
AXIS("LUp", "Left Stick Up", AnalogController::HalfAxis::LUp, GenericInputBinding::LeftStickUp),
AXIS("RLeft", "Right Stick Left", AnalogController::HalfAxis::RLeft, GenericInputBinding::RightStickLeft),
AXIS("RRight", "Right Stick Right", AnalogController::HalfAxis::RRight, GenericInputBinding::RightStickRight),
AXIS("RDown", "Right Stick Down", AnalogController::HalfAxis::RDown, GenericInputBinding::RightStickDown),
AXIS("RUp", "Right Stick Up", AnalogController::HalfAxis::RUp, GenericInputBinding::RightStickUp),
#undef AXIS #undef AXIS
}
std::optional<s32> AnalogController::StaticGetButtonCodeByName(std::string_view button_name)
{
#define BUTTON(name) \
if (button_name == #name) \
{ \
return static_cast<s32>(ZeroExtend32(static_cast<u8>(Button::name))); \
}
BUTTON(Select);
BUTTON(L3);
BUTTON(R3);
BUTTON(Start);
BUTTON(Up);
BUTTON(Right);
BUTTON(Down);
BUTTON(Left);
BUTTON(L2);
BUTTON(R2);
BUTTON(L1);
BUTTON(R1);
BUTTON(Triangle);
BUTTON(Circle);
BUTTON(Cross);
BUTTON(Square);
BUTTON(Analog);
return std::nullopt;
#undef BUTTON #undef BUTTON
} };
Controller::AxisList AnalogController::StaticGetAxisNames() static const SettingInfo s_settings[] = {
{ {SettingInfo::Type::Boolean, "ForceAnalogOnReset", TRANSLATABLE("AnalogController", "Force Analog Mode on Reset"),
return {{TRANSLATABLE("AnalogController", "LeftX"), static_cast<s32>(Axis::LeftX), AxisType::Full},
{TRANSLATABLE("AnalogController", "LeftY"), static_cast<s32>(Axis::LeftY), AxisType::Full},
{TRANSLATABLE("AnalogController", "RightX"), static_cast<s32>(Axis::RightX), AxisType::Full},
{TRANSLATABLE("AnalogController", "RightY"), static_cast<s32>(Axis::RightY), AxisType::Full}};
}
Controller::ButtonList AnalogController::StaticGetButtonNames()
{
return {{TRANSLATABLE("AnalogController", "Up"), static_cast<s32>(Button::Up)},
{TRANSLATABLE("AnalogController", "Down"), static_cast<s32>(Button::Down)},
{TRANSLATABLE("AnalogController", "Left"), static_cast<s32>(Button::Left)},
{TRANSLATABLE("AnalogController", "Right"), static_cast<s32>(Button::Right)},
{TRANSLATABLE("AnalogController", "Select"), static_cast<s32>(Button::Select)},
{TRANSLATABLE("AnalogController", "Start"), static_cast<s32>(Button::Start)},
{TRANSLATABLE("AnalogController", "Triangle"), static_cast<s32>(Button::Triangle)},
{TRANSLATABLE("AnalogController", "Cross"), static_cast<s32>(Button::Cross)},
{TRANSLATABLE("AnalogController", "Circle"), static_cast<s32>(Button::Circle)},
{TRANSLATABLE("AnalogController", "Square"), static_cast<s32>(Button::Square)},
{TRANSLATABLE("AnalogController", "L1"), static_cast<s32>(Button::L1)},
{TRANSLATABLE("AnalogController", "L2"), static_cast<s32>(Button::L2)},
{TRANSLATABLE("AnalogController", "R1"), static_cast<s32>(Button::R1)},
{TRANSLATABLE("AnalogController", "R2"), static_cast<s32>(Button::R2)},
{TRANSLATABLE("AnalogController", "L3"), static_cast<s32>(Button::L3)},
{TRANSLATABLE("AnalogController", "R3"), static_cast<s32>(Button::R3)},
{TRANSLATABLE("AnalogController", "Analog"), static_cast<s32>(Button::Analog)}};
}
u32 AnalogController::StaticGetVibrationMotorCount()
{
return NUM_MOTORS;
}
Controller::SettingList AnalogController::StaticGetSettings()
{
static constexpr std::array<SettingInfo, 4> settings = {
{{SettingInfo::Type::Boolean, "ForceAnalogOnReset", TRANSLATABLE("AnalogController", "Force Analog Mode on Reset"),
TRANSLATABLE("AnalogController", "Forces the controller to analog mode when the console is reset/powered on. May " TRANSLATABLE("AnalogController", "Forces the controller to analog mode when the console is reset/powered on. May "
"cause issues with games, so it is recommended to leave this option off."), "cause issues with games, so it is recommended to leave this option off."),
"false"}, "true"},
{SettingInfo::Type::Boolean, "AnalogDPadInDigitalMode", {SettingInfo::Type::Boolean, "AnalogDPadInDigitalMode",
TRANSLATABLE("AnalogController", "Use Analog Sticks for D-Pad in Digital Mode"), TRANSLATABLE("AnalogController", "Use Analog Sticks for D-Pad in Digital Mode"),
TRANSLATABLE("AnalogController", TRANSLATABLE("AnalogController",
"Allows you to use the analog sticks to control the d-pad in digital mode, as well as the buttons."), "Allows you to use the analog sticks to control the d-pad in digital mode, as well as the buttons."),
"false"}, "true"},
{SettingInfo::Type::Float, "AxisScale", TRANSLATABLE("AnalogController", "Analog Axis Scale"), {SettingInfo::Type::Float, "AnalogDeadzone", TRANSLATABLE("AnalogController", "Analog Deadzone"),
TRANSLATABLE("AnalogController",
"Sets the analog stick deadzone, i.e. the fraction of the stick movement which will be ignored."),
"0.00f", "0.00f", "1.00f", "0.01f"},
{SettingInfo::Type::Float, "AnalogSensitivity", TRANSLATABLE("AnalogController", "Analog Sensitivity"),
TRANSLATABLE( TRANSLATABLE(
"AnalogController", "AnalogController",
"Sets the analog stick axis scaling factor. A value between 1.30 and 1.40 is recommended when using recent " "Sets the analog stick axis scaling factor. A value between 1.30 and 1.40 is recommended when using recent "
"controllers, e.g. DualShock 4, Xbox One Controller."), "controllers, e.g. DualShock 4, Xbox One Controller."),
"1.00f", "0.01f", "1.50f", "0.01f"}, "1.33f", "0.01f", "2.00f", "0.01f"},
{SettingInfo::Type::Integer, "VibrationBias", TRANSLATABLE("AnalogController", "Vibration Bias"), {SettingInfo::Type::Integer, "VibrationBias", TRANSLATABLE("AnalogController", "Vibration Bias"),
TRANSLATABLE("AnalogController", "Sets the rumble bias value. If rumble in some games is too weak or not " TRANSLATABLE("AnalogController", "Sets the rumble bias value. If rumble in some games is too weak or not "
"functioning, try increasing this value."), "functioning, try increasing this value."),
"8", "0", "255", "1"}}}; "8", "0", "255", "1"}};
return SettingList(settings.begin(), settings.end()); const Controller::ControllerInfo AnalogController::INFO = {ControllerType::AnalogController,
} "AnalogController",
TRANSLATABLE("ControllerType", "Analog Controller"),
s_binding_info,
countof(s_binding_info),
s_settings,
countof(s_settings),
Controller::VibrationCapabilities::LargeSmallMotors};
void AnalogController::LoadSettings(const char* section) void AnalogController::LoadSettings(SettingsInterface& si, const char* section)
{ {
Controller::LoadSettings(section); Controller::LoadSettings(si, section);
m_force_analog_on_reset = g_host_interface->GetBoolSettingValue(section, "ForceAnalogOnReset", false); m_force_analog_on_reset = si.GetBoolValue(section, "ForceAnalogOnReset", true);
m_analog_dpad_in_digital_mode = g_host_interface->GetBoolSettingValue(section, "AnalogDPadInDigitalMode", false); m_analog_dpad_in_digital_mode = si.GetBoolValue(section, "AnalogDPadInDigitalMode", true);
m_axis_scale = m_analog_deadzone = std::clamp(si.GetFloatValue(section, "AnalogDeadzone", DEFAULT_STICK_DEADZONE), 0.0f, 1.0f);
std::clamp(std::abs(g_host_interface->GetFloatSettingValue(section, "AxisScale", 1.00f)), 0.01f, 1.50f); m_analog_sensitivity =
m_rumble_bias = std::clamp(si.GetFloatValue(section, "AnalogSensitivity", DEFAULT_STICK_SENSITIVITY), 0.01f, 3.0f);
static_cast<u8>(std::min<u32>(g_host_interface->GetIntSettingValue(section, "VibrationBias", 8), 255)); m_rumble_bias = static_cast<u8>(std::min<u32>(si.GetIntValue(section, "VibrationBias", 8), 255));
} }

View file

@ -39,43 +39,42 @@ public:
Count Count
}; };
enum class HalfAxis : u8
{
LLeft,
LRight,
LDown,
LUp,
RLeft,
RRight,
RDown,
RUp,
Count
};
static constexpr u8 NUM_MOTORS = 2; static constexpr u8 NUM_MOTORS = 2;
static const Controller::ControllerInfo INFO;
AnalogController(u32 index); AnalogController(u32 index);
~AnalogController() override; ~AnalogController() override;
static std::unique_ptr<AnalogController> Create(u32 index); static std::unique_ptr<AnalogController> Create(u32 index);
static std::optional<s32> StaticGetAxisCodeByName(std::string_view axis_name);
static std::optional<s32> StaticGetButtonCodeByName(std::string_view button_name);
static AxisList StaticGetAxisNames();
static ButtonList StaticGetButtonNames();
static u32 StaticGetVibrationMotorCount();
static SettingList StaticGetSettings();
ControllerType GetType() const override; ControllerType GetType() const override;
std::optional<s32> GetAxisCodeByName(std::string_view axis_name) const override;
std::optional<s32> GetButtonCodeByName(std::string_view button_name) const override;
void Reset() override; void Reset() override;
bool DoState(StateWrapper& sw, bool ignore_input_state) override; bool DoState(StateWrapper& sw, bool ignore_input_state) override;
float GetAxisState(s32 axis_code) const override; float GetBindState(u32 index) const override;
void SetAxisState(s32 axis_code, float value) override; void SetBindState(u32 index, float value) override;
bool GetButtonState(s32 button_code) const override;
void SetButtonState(s32 button_code, bool pressed) override;
u32 GetButtonStateBits() const override; u32 GetButtonStateBits() const override;
std::optional<u32> GetAnalogInputBytes() const override; std::optional<u32> GetAnalogInputBytes() const override;
void ResetTransferState() override; void ResetTransferState() override;
bool Transfer(const u8 data_in, u8* data_out) override; bool Transfer(const u8 data_in, u8* data_out) override;
void SetAxisState(Axis axis, u8 value); void LoadSettings(SettingsInterface& si, const char* section) override;
void SetButtonState(Button button, bool pressed);
u32 GetVibrationMotorCount() const override;
float GetVibrationMotorStrength(u32 motor) override;
void LoadSettings(const char* section) override;
private: private:
using MotorState = std::array<u8, NUM_MOTORS>; using MotorState = std::array<u8, NUM_MOTORS>;
@ -111,16 +110,16 @@ private:
void SetAnalogMode(bool enabled); void SetAnalogMode(bool enabled);
void ProcessAnalogModeToggle(); void ProcessAnalogModeToggle();
void SetMotorState(u8 motor, u8 value); void SetMotorState(u32 motor, u8 value);
void UpdateHostVibration();
u8 GetExtraButtonMaskLSB() const; u8 GetExtraButtonMaskLSB() const;
void ResetRumbleConfig(); void ResetRumbleConfig();
void SetMotorStateForConfigIndex(int index, u8 value); void SetMotorStateForConfigIndex(int index, u8 value);
u32 m_index;
bool m_force_analog_on_reset = false; bool m_force_analog_on_reset = false;
bool m_analog_dpad_in_digital_mode = false; bool m_analog_dpad_in_digital_mode = false;
float m_axis_scale = 1.00f; float m_analog_deadzone = 0.0f;
float m_analog_sensitivity = 1.33f;
u8 m_rumble_bias = 8; u8 m_rumble_bias = 8;
bool m_analog_mode = false; bool m_analog_mode = false;
@ -151,6 +150,9 @@ private:
MotorState m_motor_state{}; MotorState m_motor_state{};
// both directions of axis state, merged to m_axis_state
std::array<u8, static_cast<u32>(HalfAxis::Count)> m_half_axis_state{};
// Member variables that are no longer used, but kept and serialized for compatibility with older save states // Member variables that are no longer used, but kept and serialized for compatibility with older save states
u8 m_command_param = 0; u8 m_command_param = 0;
bool m_legacy_rumble_unlocked = false; bool m_legacy_rumble_unlocked = false;

View file

@ -1,15 +1,14 @@
#include "analog_joystick.h" #include "analog_joystick.h"
#include "common/log.h" #include "common/log.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "host_interface.h" #include "host.h"
#include "system.h" #include "system.h"
#include "util/state_wrapper.h" #include "util/state_wrapper.h"
#include <cmath> #include <cmath>
Log_SetChannel(AnalogJoystick); Log_SetChannel(AnalogJoystick);
AnalogJoystick::AnalogJoystick(u32 index) AnalogJoystick::AnalogJoystick(u32 index) : Controller(index)
{ {
m_index = index;
m_axis_state.fill(0x80); m_axis_state.fill(0x80);
Reset(); Reset();
} }
@ -50,82 +49,101 @@ bool AnalogJoystick::DoState(StateWrapper& sw, bool apply_input_state)
if (sw.IsReading() && (old_analog_mode != m_analog_mode)) if (sw.IsReading() && (old_analog_mode != m_analog_mode))
{ {
g_host_interface->AddFormattedOSDMessage( Host::AddFormattedOSDMessage(5.0f,
5.0f, m_analog_mode ?
m_analog_mode ? g_host_interface->TranslateString("AnalogJoystick", "Controller %u switched to analog mode.") : Host::TranslateString("AnalogJoystick", "Controller %u switched to analog mode.") :
g_host_interface->TranslateString("AnalogJoystick", "Controller %u switched to digital mode."), Host::TranslateString("AnalogJoystick", "Controller %u switched to digital mode."),
m_index + 1u); m_index + 1u);
} }
return true; return true;
} }
std::optional<s32> AnalogJoystick::GetAxisCodeByName(std::string_view axis_name) const float AnalogJoystick::GetBindState(u32 index) const
{ {
return StaticGetAxisCodeByName(axis_name); if (index >= static_cast<u32>(Button::Count))
}
std::optional<s32> AnalogJoystick::GetButtonCodeByName(std::string_view button_name) const
{ {
return StaticGetButtonCodeByName(button_name); const u32 sub_index = index - static_cast<u32>(Button::Count);
} if (sub_index >= static_cast<u32>(m_half_axis_state.size()))
float AnalogJoystick::GetAxisState(s32 axis_code) const
{
if (axis_code < 0 || axis_code >= static_cast<s32>(Axis::Count))
return 0.0f; return 0.0f;
// 0..255 -> -1..1 return static_cast<float>(m_half_axis_state[sub_index]) * (1.0f / 255.0f);
const float value = (((static_cast<float>(m_axis_state[static_cast<s32>(axis_code)]) / 255.0f) * 2.0f) - 1.0f); }
return std::clamp(value / m_axis_scale, -1.0f, 1.0f); else if (index < static_cast<u32>(Button::Mode))
{
return static_cast<float>(((m_button_state >> index) & 1u) ^ 1u);
}
else
{
return 0.0f;
}
} }
void AnalogJoystick::SetAxisState(s32 axis_code, float value) void AnalogJoystick::SetBindState(u32 index, float value)
{ {
if (axis_code < 0 || axis_code >= static_cast<s32>(Axis::Count)) if (index == static_cast<s32>(Button::Mode))
return;
// -1..1 -> 0..255
const float scaled_value = std::clamp(value * m_axis_scale, -1.0f, 1.0f);
const u8 u8_value = static_cast<u8>(std::clamp(std::round(((scaled_value + 1.0f) / 2.0f) * 255.0f), 0.0f, 255.0f));
SetAxisState(static_cast<Axis>(axis_code), u8_value);
}
void AnalogJoystick::SetAxisState(Axis axis, u8 value)
{ {
if (m_axis_state[static_cast<u8>(axis)] != value) // analog toggle
System::SetRunaheadReplayFlag(); if (value >= 0.5f)
m_axis_state[static_cast<u8>(axis)] = value;
}
bool AnalogJoystick::GetButtonState(s32 button_code) const
{
if (button_code < 0 || button_code >= static_cast<s32>(Button::Count))
return false;
const u16 bit = u16(1) << static_cast<u8>(button_code);
return ((m_button_state & bit) == 0);
}
void AnalogJoystick::SetButtonState(Button button, bool pressed)
{
if (button == Button::Mode)
{
if (pressed)
ToggleAnalogMode(); ToggleAnalogMode();
return; return;
} }
else if (index >= static_cast<u32>(Button::Count))
{
const u32 sub_index = index - static_cast<u32>(Button::Count);
if (sub_index >= static_cast<u32>(m_half_axis_state.size()))
return;
const u16 bit = u16(1) << static_cast<u8>(button); value = ApplyAnalogDeadzoneSensitivity(m_analog_deadzone, m_analog_sensitivity, value);
const u8 u8_value = static_cast<u8>(std::clamp(value * 255.0f, 0.0f, 255.0f));
if (u8_value != m_half_axis_state[sub_index])
System::SetRunaheadReplayFlag();
if (pressed) m_half_axis_state[sub_index] = u8_value;
#define MERGE(pos, neg) \
((m_half_axis_state[static_cast<u32>(pos)] != 0) ? (127u + ((m_half_axis_state[static_cast<u32>(pos)] + 1u) / 2u)) : \
(127u - (m_half_axis_state[static_cast<u32>(neg)] / 2u)))
switch (static_cast<HalfAxis>(sub_index))
{
case HalfAxis::LLeft:
case HalfAxis::LRight:
m_axis_state[static_cast<u8>(Axis::LeftX)] = MERGE(HalfAxis::LRight, HalfAxis::LLeft);
break;
case HalfAxis::LDown:
case HalfAxis::LUp:
m_axis_state[static_cast<u8>(Axis::LeftY)] = MERGE(HalfAxis::LDown, HalfAxis::LUp);
break;
case HalfAxis::RLeft:
case HalfAxis::RRight:
m_axis_state[static_cast<u8>(Axis::RightX)] = MERGE(HalfAxis::RRight, HalfAxis::RLeft);
break;
case HalfAxis::RDown:
case HalfAxis::RUp:
m_axis_state[static_cast<u8>(Axis::RightY)] = MERGE(HalfAxis::RDown, HalfAxis::RUp);
break;
default:
break;
}
#undef MERGE
return;
}
const u16 bit = u16(1) << static_cast<u8>(index);
if (value >= 0.5f)
{ {
if (m_button_state & bit) if (m_button_state & bit)
System::SetRunaheadReplayFlag(); System::SetRunaheadReplayFlag();
m_button_state &= ~bit; m_button_state &= ~(bit);
} }
else else
{ {
@ -136,14 +154,6 @@ void AnalogJoystick::SetButtonState(Button button, bool pressed)
} }
} }
void AnalogJoystick::SetButtonState(s32 button_code, bool pressed)
{
if (button_code < 0 || button_code >= static_cast<s32>(Button::Count))
return;
SetButtonState(static_cast<Button>(button_code), pressed);
}
u32 AnalogJoystick::GetButtonStateBits() const u32 AnalogJoystick::GetButtonStateBits() const
{ {
return m_button_state ^ 0xFFFF; return m_button_state ^ 0xFFFF;
@ -173,10 +183,10 @@ void AnalogJoystick::ToggleAnalogMode()
m_analog_mode = !m_analog_mode; m_analog_mode = !m_analog_mode;
Log_InfoPrintf("Joystick %u switched to %s mode.", m_index + 1u, m_analog_mode ? "analog" : "digital"); Log_InfoPrintf("Joystick %u switched to %s mode.", m_index + 1u, m_analog_mode ? "analog" : "digital");
g_host_interface->AddFormattedOSDMessage( Host::AddFormattedOSDMessage(5.0f,
5.0f, m_analog_mode ?
m_analog_mode ? g_host_interface->TranslateString("AnalogJoystick", "Controller %u switched to analog mode.") : Host::TranslateString("AnalogJoystick", "Controller %u switched to analog mode.") :
g_host_interface->TranslateString("AnalogJoystick", "Controller %u switched to digital mode."), Host::TranslateString("AnalogJoystick", "Controller %u switched to digital mode."),
m_index + 1u); m_index + 1u);
} }
@ -272,104 +282,73 @@ std::unique_ptr<AnalogJoystick> AnalogJoystick::Create(u32 index)
return std::make_unique<AnalogJoystick>(index); return std::make_unique<AnalogJoystick>(index);
} }
std::optional<s32> AnalogJoystick::StaticGetAxisCodeByName(std::string_view axis_name) static const Controller::ControllerBindingInfo s_binding_info[] = {
{ #define BUTTON(name, display_name, button, genb) \
#define AXIS(name) \
if (axis_name == #name) \
{ \ { \
return static_cast<s32>(ZeroExtend32(static_cast<u8>(Axis::name))); \ name, display_name, static_cast<u32>(button), Controller::ControllerBindingType::Button, genb \
}
#define AXIS(name, display_name, halfaxis, genb) \
{ \
name, display_name, static_cast<u32>(AnalogJoystick::Button::Count) + static_cast<u32>(halfaxis), \
Controller::ControllerBindingType::HalfAxis, genb \
} }
AXIS(LeftX); BUTTON("Up", "D-Pad Up", AnalogJoystick::Button::Up, GenericInputBinding::DPadUp),
AXIS(LeftY); BUTTON("Right", "D-Pad Right", AnalogJoystick::Button::Right, GenericInputBinding::DPadRight),
AXIS(RightX); BUTTON("Down", "D-Pad Down", AnalogJoystick::Button::Down, GenericInputBinding::DPadDown),
AXIS(RightY); BUTTON("Left", "D-Pad Left", AnalogJoystick::Button::Left, GenericInputBinding::DPadLeft),
BUTTON("Triangle", "Triangle", AnalogJoystick::Button::Triangle, GenericInputBinding::Triangle),
BUTTON("Circle", "Circle", AnalogJoystick::Button::Circle, GenericInputBinding::Circle),
BUTTON("Cross", "Cross", AnalogJoystick::Button::Cross, GenericInputBinding::Cross),
BUTTON("Square", "Square", AnalogJoystick::Button::Square, GenericInputBinding::Square),
BUTTON("Select", "Select", AnalogJoystick::Button::Select, GenericInputBinding::Select),
BUTTON("Start", "Start", AnalogJoystick::Button::Start, GenericInputBinding::Start),
BUTTON("Mode", "Mode Toggle", AnalogJoystick::Button::Mode, GenericInputBinding::System),
BUTTON("L1", "L1", AnalogJoystick::Button::L1, GenericInputBinding::L1),
BUTTON("R1", "R1", AnalogJoystick::Button::R1, GenericInputBinding::R1),
BUTTON("L2", "L2", AnalogJoystick::Button::L2, GenericInputBinding::L2),
BUTTON("R2", "R2", AnalogJoystick::Button::R2, GenericInputBinding::R2),
BUTTON("L3", "L3", AnalogJoystick::Button::L3, GenericInputBinding::L3),
BUTTON("R3", "R3", AnalogJoystick::Button::R3, GenericInputBinding::R3),
return std::nullopt; AXIS("LLeft", "Left Stick Left", AnalogJoystick::HalfAxis::LLeft, GenericInputBinding::LeftStickLeft),
AXIS("LRight", "Left Stick Right", AnalogJoystick::HalfAxis::LRight, GenericInputBinding::LeftStickRight),
AXIS("LDown", "Left Stick Down", AnalogJoystick::HalfAxis::LDown, GenericInputBinding::LeftStickDown),
AXIS("LUp", "Left Stick Up", AnalogJoystick::HalfAxis::LUp, GenericInputBinding::LeftStickUp),
AXIS("RLeft", "Right Stick Left", AnalogJoystick::HalfAxis::RLeft, GenericInputBinding::RightStickLeft),
AXIS("RRight", "Right Stick Right", AnalogJoystick::HalfAxis::RRight, GenericInputBinding::RightStickRight),
AXIS("RDown", "Right Stick Down", AnalogJoystick::HalfAxis::RDown, GenericInputBinding::RightStickDown),
AXIS("RUp", "Right Stick Up", AnalogJoystick::HalfAxis::RUp, GenericInputBinding::RightStickUp),
#undef AXIS #undef AXIS
}
std::optional<s32> AnalogJoystick::StaticGetButtonCodeByName(std::string_view button_name)
{
#define BUTTON(name) \
if (button_name == #name) \
{ \
return static_cast<s32>(ZeroExtend32(static_cast<u8>(Button::name))); \
}
BUTTON(Select);
BUTTON(L3);
BUTTON(R3);
BUTTON(Start);
BUTTON(Up);
BUTTON(Right);
BUTTON(Down);
BUTTON(Left);
BUTTON(L2);
BUTTON(R2);
BUTTON(L1);
BUTTON(R1);
BUTTON(Triangle);
BUTTON(Circle);
BUTTON(Cross);
BUTTON(Square);
BUTTON(Mode);
return std::nullopt;
#undef BUTTON #undef BUTTON
} };
Controller::AxisList AnalogJoystick::StaticGetAxisNames() static const SettingInfo s_settings[] = {
{ {SettingInfo::Type::Float, "AnalogDeadzone", TRANSLATABLE("AnalogController", "Analog Deadzone"),
return {{TRANSLATABLE("AnalogJoystick", "LeftX"), static_cast<s32>(Axis::LeftX), AxisType::Full}, TRANSLATABLE("AnalogController",
{TRANSLATABLE("AnalogJoystick", "LeftY"), static_cast<s32>(Axis::LeftY), AxisType::Full}, "Sets the analog stick deadzone, i.e. the fraction of the stick movement which will be ignored.s"),
{TRANSLATABLE("AnalogJoystick", "RightX"), static_cast<s32>(Axis::RightX), AxisType::Full}, "1.00f", "0.00f", "1.00f", "0.01f"},
{TRANSLATABLE("AnalogJoystick", "RightY"), static_cast<s32>(Axis::RightY), AxisType::Full}}; {SettingInfo::Type::Float, "AnalogSensitivity", TRANSLATABLE("AnalogController", "Analog Sensitivity"),
}
Controller::ButtonList AnalogJoystick::StaticGetButtonNames()
{
return {{TRANSLATABLE("AnalogJoystick", "Up"), static_cast<s32>(Button::Up)},
{TRANSLATABLE("AnalogJoystick", "Down"), static_cast<s32>(Button::Down)},
{TRANSLATABLE("AnalogJoystick", "Left"), static_cast<s32>(Button::Left)},
{TRANSLATABLE("AnalogJoystick", "Right"), static_cast<s32>(Button::Right)},
{TRANSLATABLE("AnalogJoystick", "Select"), static_cast<s32>(Button::Select)},
{TRANSLATABLE("AnalogJoystick", "Start"), static_cast<s32>(Button::Start)},
{TRANSLATABLE("AnalogJoystick", "Triangle"), static_cast<s32>(Button::Triangle)},
{TRANSLATABLE("AnalogJoystick", "Cross"), static_cast<s32>(Button::Cross)},
{TRANSLATABLE("AnalogJoystick", "Circle"), static_cast<s32>(Button::Circle)},
{TRANSLATABLE("AnalogJoystick", "Square"), static_cast<s32>(Button::Square)},
{TRANSLATABLE("AnalogJoystick", "L1"), static_cast<s32>(Button::L1)},
{TRANSLATABLE("AnalogJoystick", "L2"), static_cast<s32>(Button::L2)},
{TRANSLATABLE("AnalogJoystick", "R1"), static_cast<s32>(Button::R1)},
{TRANSLATABLE("AnalogJoystick", "R2"), static_cast<s32>(Button::R2)},
{TRANSLATABLE("AnalogJoystick", "L3"), static_cast<s32>(Button::L3)},
{TRANSLATABLE("AnalogJoystick", "R3"), static_cast<s32>(Button::R3)},
{TRANSLATABLE("AnalogJoystick", "Analog"), static_cast<s32>(Button::Mode)}};
}
u32 AnalogJoystick::StaticGetVibrationMotorCount()
{
return 0;
}
Controller::SettingList AnalogJoystick::StaticGetSettings()
{
static constexpr std::array<SettingInfo, 1> settings = {
{{SettingInfo::Type::Float, "AxisScale", TRANSLATABLE("AnalogJoystick", "Analog Axis Scale"),
TRANSLATABLE( TRANSLATABLE(
"AnalogJoystick", "AnalogController",
"Sets the analog stick axis scaling factor. A value between 1.30 and 1.40 is recommended when using recent " "Sets the analog stick axis scaling factor. A value between 1.30 and 1.40 is recommended when using recent "
"controllers, e.g. DualShock 4, Xbox One Controller."), "controllers, e.g. DualShock 4, Xbox One Controller."),
"1.00f", "0.01f", "1.50f", "0.01f"}}}; "1.33f", "0.01f", "2.00f", "0.01f"}};
return SettingList(settings.begin(), settings.end()); const Controller::ControllerInfo AnalogJoystick::INFO = {ControllerType::AnalogJoystick,
} "AnalogJoystick",
TRANSLATABLE("ControllerType", "Analog Joystick"),
s_binding_info,
countof(s_binding_info),
s_settings,
countof(s_settings),
Controller::VibrationCapabilities::NoVibration};
void AnalogJoystick::LoadSettings(const char* section) void AnalogJoystick::LoadSettings(SettingsInterface& si, const char* section)
{ {
Controller::LoadSettings(section); Controller::LoadSettings(si, section);
m_axis_scale = std::clamp(g_host_interface->GetFloatSettingValue(section, "AxisScale", 1.00f), 0.01f, 1.50f); m_analog_deadzone = std::clamp(si.GetFloatValue(section, "AnalogDeadzone", DEFAULT_STICK_DEADZONE), 0.0f, 1.0f);
m_analog_sensitivity =
std::clamp(si.GetFloatValue(section, "AnalogSensitivity", DEFAULT_STICK_SENSITIVITY), 0.01f, 3.0f);
} }

View file

@ -39,38 +39,40 @@ public:
Count Count
}; };
enum class HalfAxis : u8
{
LLeft,
LRight,
LDown,
LUp,
RLeft,
RRight,
RDown,
RUp,
Count
};
static const Controller::ControllerInfo INFO;
AnalogJoystick(u32 index); AnalogJoystick(u32 index);
~AnalogJoystick() override; ~AnalogJoystick() override;
static std::unique_ptr<AnalogJoystick> Create(u32 index); static std::unique_ptr<AnalogJoystick> Create(u32 index);
static std::optional<s32> StaticGetAxisCodeByName(std::string_view axis_name);
static std::optional<s32> StaticGetButtonCodeByName(std::string_view button_name);
static AxisList StaticGetAxisNames();
static ButtonList StaticGetButtonNames();
static u32 StaticGetVibrationMotorCount();
static SettingList StaticGetSettings();
ControllerType GetType() const override; ControllerType GetType() const override;
std::optional<s32> GetAxisCodeByName(std::string_view axis_name) const override;
std::optional<s32> GetButtonCodeByName(std::string_view button_name) const override;
void Reset() override; void Reset() override;
bool DoState(StateWrapper& sw, bool apply_input_state) override; bool DoState(StateWrapper& sw, bool apply_input_state) override;
float GetAxisState(s32 axis_code) const override; float GetBindState(u32 index) const override;
void SetAxisState(s32 axis_code, float value) override; void SetBindState(u32 index, float value) override;
bool GetButtonState(s32 button_code) const override;
void SetButtonState(s32 button_code, bool pressed) override;
u32 GetButtonStateBits() const override; u32 GetButtonStateBits() const override;
std::optional<u32> GetAnalogInputBytes() const override; std::optional<u32> GetAnalogInputBytes() const override;
void ResetTransferState() override; void ResetTransferState() override;
bool Transfer(const u8 data_in, u8* data_out) override; bool Transfer(const u8 data_in, u8* data_out) override;
void LoadSettings(const char* section) override; void LoadSettings(SettingsInterface& si, const char* section) override;
void SetAxisState(Axis axis, u8 value);
void SetButtonState(Button button, bool pressed);
private: private:
enum class TransferState : u8 enum class TransferState : u8
@ -89,9 +91,8 @@ private:
u16 GetID() const; u16 GetID() const;
void ToggleAnalogMode(); void ToggleAnalogMode();
u32 m_index; float m_analog_deadzone = 0.0f;
float m_analog_sensitivity = 1.33f;
float m_axis_scale = 1.00f;
// On original hardware, the mode toggle is a switch rather than a button, so we'll enable Analog Mode by default // On original hardware, the mode toggle is a switch rather than a button, so we'll enable Analog Mode by default
bool m_analog_mode = true; bool m_analog_mode = true;
@ -101,5 +102,8 @@ private:
std::array<u8, static_cast<u8>(Axis::Count)> m_axis_state{}; std::array<u8, static_cast<u8>(Axis::Count)> m_axis_state{};
// both directions of axis state, merged to m_axis_state
std::array<u8, static_cast<u32>(HalfAxis::Count)> m_half_axis_state{};
TransferState m_transfer_state = TransferState::Idle; TransferState m_transfer_state = TransferState::Idle;
}; };

View file

@ -3,7 +3,11 @@
#include "common/file_system.h" #include "common/file_system.h"
#include "common/log.h" #include "common/log.h"
#include "common/md5_digest.h" #include "common/md5_digest.h"
#include "common/path.h"
#include "cpu_disasm.h" #include "cpu_disasm.h"
#include "host.h"
#include "host_settings.h"
#include "settings.h"
#include <array> #include <array>
#include <cerrno> #include <cerrno>
Log_SetChannel(BIOS); Log_SetChannel(BIOS);
@ -272,3 +276,143 @@ DiscRegion GetPSExeDiscRegion(const PSEXEHeader& header)
} }
} // namespace BIOS } // namespace BIOS
std::optional<std::vector<u8>> BIOS::GetBIOSImage(ConsoleRegion region)
{
std::string bios_name;
switch (region)
{
case ConsoleRegion::NTSC_J:
bios_name = Host::GetStringSettingValue("BIOS", "PathNTSCJ", "");
break;
case ConsoleRegion::PAL:
bios_name = Host::GetStringSettingValue("BIOS", "PathPAL", "");
break;
case ConsoleRegion::NTSC_U:
default:
bios_name = Host::GetStringSettingValue("BIOS", "PathNTSCU", "");
break;
}
if (bios_name.empty())
{
// auto-detect
return FindBIOSImageInDirectory(region, EmuFolders::Bios.c_str());
}
// try the configured path
std::optional<Image> image = LoadImageFromFile(Path::Combine(EmuFolders::Bios, bios_name).c_str());
if (!image.has_value())
{
Host::ReportFormattedErrorAsync(
"Error", Host::TranslateString("HostInterface", "Failed to load configured BIOS file '%s'"), bios_name.c_str());
return std::nullopt;
}
Hash found_hash = GetHash(*image);
Log_DevPrintf("Hash for BIOS '%s': %s", bios_name.c_str(), found_hash.ToString().c_str());
if (!IsValidHashForRegion(region, found_hash))
Log_WarningPrintf("Hash for BIOS '%s' does not match region. This may cause issues.", bios_name.c_str());
return image;
}
std::optional<std::vector<u8>> BIOS::FindBIOSImageInDirectory(ConsoleRegion region, const char* directory)
{
Log_InfoPrintf("Searching for a %s BIOS in '%s'...", Settings::GetConsoleRegionDisplayName(region), directory);
FileSystem::FindResultsArray results;
FileSystem::FindFiles(
directory, "*", FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_HIDDEN_FILES | FILESYSTEM_FIND_RELATIVE_PATHS, &results);
std::string fallback_path;
std::optional<Image> fallback_image;
const ImageInfo* fallback_info = nullptr;
for (const FILESYSTEM_FIND_DATA& fd : results)
{
if (fd.Size != BIOS_SIZE && fd.Size != BIOS_SIZE_PS2 && fd.Size != BIOS_SIZE_PS3)
{
Log_WarningPrintf("Skipping '%s': incorrect size", fd.FileName.c_str());
continue;
}
std::string full_path(Path::Combine(directory, fd.FileName));
std::optional<Image> found_image = LoadImageFromFile(full_path.c_str());
if (!found_image)
continue;
Hash found_hash = GetHash(*found_image);
Log_DevPrintf("Hash for BIOS '%s': %s", fd.FileName.c_str(), found_hash.ToString().c_str());
const ImageInfo* ii = GetImageInfoForHash(found_hash);
if (IsValidHashForRegion(region, found_hash))
{
Log_InfoPrintf("Using BIOS '%s': %s", fd.FileName.c_str(), ii ? ii->description : "");
return found_image;
}
// don't let an unknown bios take precedence over a known one
if (!fallback_path.empty() && (fallback_info || !ii))
continue;
fallback_path = std::move(full_path);
fallback_image = std::move(found_image);
fallback_info = ii;
}
if (!fallback_image.has_value())
{
Host::ReportFormattedErrorAsync("Error",
Host::TranslateString("HostInterface", "No BIOS image found for %s region"),
Settings::GetConsoleRegionDisplayName(region));
return std::nullopt;
}
if (!fallback_info)
{
Log_WarningPrintf("Using unknown BIOS '%s'. This may crash.", fallback_path.c_str());
}
else
{
Log_WarningPrintf("Falling back to possibly-incompatible image '%s': %s", fallback_path.c_str(),
fallback_info->description);
}
return fallback_image;
}
std::vector<std::pair<std::string, const BIOS::ImageInfo*>> BIOS::FindBIOSImagesInDirectory(const char* directory)
{
std::vector<std::pair<std::string, const ImageInfo*>> results;
FileSystem::FindResultsArray files;
FileSystem::FindFiles(directory, "*",
FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_HIDDEN_FILES | FILESYSTEM_FIND_RELATIVE_PATHS, &files);
for (FILESYSTEM_FIND_DATA& fd : files)
{
if (fd.Size != BIOS_SIZE && fd.Size != BIOS_SIZE_PS2 && fd.Size != BIOS_SIZE_PS3)
continue;
std::string full_path(Path::Combine(directory, fd.FileName));
std::optional<Image> found_image = LoadImageFromFile(full_path.c_str());
if (!found_image)
continue;
Hash found_hash = GetHash(*found_image);
const ImageInfo* ii = GetImageInfoForHash(found_hash);
results.emplace_back(std::move(fd.FileName), ii);
}
return results;
}
bool BIOS::HasAnyBIOSImages()
{
return FindBIOSImageInDirectory(ConsoleRegion::Auto, EmuFolders::Bios.c_str()).has_value();
}

View file

@ -70,4 +70,17 @@ bool PatchBIOSForEXE(u8* image, u32 image_size, u32 r_pc, u32 r_gp, u32 r_sp, u3
bool IsValidPSExeHeader(const PSEXEHeader& header, u32 file_size); bool IsValidPSExeHeader(const PSEXEHeader& header, u32 file_size);
DiscRegion GetPSExeDiscRegion(const PSEXEHeader& header); DiscRegion GetPSExeDiscRegion(const PSEXEHeader& header);
/// Loads the BIOS image for the specified region.
std::optional<std::vector<u8>> GetBIOSImage(ConsoleRegion region);
/// Searches for a BIOS image for the specified region in the specified directory. If no match is found, the first
/// BIOS image within 512KB and 4MB will be used.
std::optional<std::vector<u8>> FindBIOSImageInDirectory(ConsoleRegion region, const char* directory);
/// Returns a list of filenames and descriptions for BIOS images in a directory.
std::vector<std::pair<std::string, const BIOS::ImageInfo*>> FindBIOSImagesInDirectory(const char* directory);
/// Returns true if any BIOS images are found in the configured BIOS directory.
bool HasAnyBIOSImages();
} // namespace BIOS } // namespace BIOS

View file

@ -10,7 +10,7 @@
#include "cpu_disasm.h" #include "cpu_disasm.h"
#include "dma.h" #include "dma.h"
#include "gpu.h" #include "gpu.h"
#include "host_interface.h" #include "host.h"
#include "interrupt_controller.h" #include "interrupt_controller.h"
#include "mdec.h" #include "mdec.h"
#include "pad.h" #include "pad.h"
@ -130,7 +130,7 @@ bool Initialize()
{ {
if (!AllocateMemory(g_settings.enable_8mb_ram)) if (!AllocateMemory(g_settings.enable_8mb_ram))
{ {
g_host_interface->ReportError("Failed to allocate memory"); Host::ReportErrorAsync("Error", "Failed to allocate memory");
return false; return false;
} }

View file

@ -3,6 +3,7 @@
#include "common/log.h" #include "common/log.h"
#include "common/platform.h" #include "common/platform.h"
#include "dma.h" #include "dma.h"
#include "host.h"
#include "imgui.h" #include "imgui.h"
#include "interrupt_controller.h" #include "interrupt_controller.h"
#include "settings.h" #include "settings.h"
@ -2722,7 +2723,7 @@ void CDROM::DrawDebugWindow()
{ {
static const ImVec4 active_color{1.0f, 1.0f, 1.0f, 1.0f}; static const ImVec4 active_color{1.0f, 1.0f, 1.0f, 1.0f};
static const ImVec4 inactive_color{0.4f, 0.4f, 0.4f, 1.0f}; static const ImVec4 inactive_color{0.4f, 0.4f, 0.4f, 1.0f};
const float framebuffer_scale = ImGui::GetIO().DisplayFramebufferScale.x; const float framebuffer_scale = Host::GetOSDScale();
ImGui::SetNextWindowSize(ImVec2(800.0f * framebuffer_scale, 550.0f * framebuffer_scale), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(800.0f * framebuffer_scale, 550.0f * framebuffer_scale), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("CDROM State", nullptr)) if (!ImGui::Begin("CDROM State", nullptr))

View file

@ -29,6 +29,7 @@ public:
bool HasMedia() const { return m_reader.HasMedia(); } bool HasMedia() const { return m_reader.HasMedia(); }
const std::string& GetMediaFileName() const { return m_reader.GetMediaFileName(); } const std::string& GetMediaFileName() const { return m_reader.GetMediaFileName(); }
const CDImage* GetMedia() const { return m_reader.GetMedia(); } const CDImage* GetMedia() const { return m_reader.GetMedia(); }
DiscRegion GetDiscRegion() const { return m_disc_region; }
bool IsMediaPS1Disc() const; bool IsMediaPS1Disc() const;
bool DoesMediaRegionMatchConsole() const; bool DoesMediaRegionMatchConsole() const;

View file

@ -9,7 +9,7 @@
#include "controller.h" #include "controller.h"
#include "cpu_code_cache.h" #include "cpu_code_cache.h"
#include "cpu_core.h" #include "cpu_core.h"
#include "host_interface.h" #include "host.h"
#include "system.h" #include "system.h"
#include <cctype> #include <cctype>
#include <iomanip> #include <iomanip>
@ -686,17 +686,11 @@ bool CheatList::SaveToPCSXRFile(const char* filename)
bool CheatList::LoadFromPackage(const std::string& game_code) bool CheatList::LoadFromPackage(const std::string& game_code)
{ {
std::unique_ptr<ByteStream> stream = const std::optional<std::string> db_string(Host::ReadResourceFileToString("chtdb.txt"));
g_host_interface->OpenPackageFile("database/chtdb.txt", BYTESTREAM_OPEN_READ | BYTESTREAM_OPEN_STREAMED); if (!db_string.has_value())
if (!stream)
return false; return false;
std::string db_string = ByteStream::ReadStreamToString(stream.get()); std::istringstream iss(db_string.value());
stream.reset();
if (db_string.empty())
return false;
std::istringstream iss(db_string);
std::string line; std::string line;
while (std::getline(iss, line)) while (std::getline(iss, line))
{ {

File diff suppressed because it is too large Load diff

View file

@ -2,12 +2,27 @@
#include "analog_controller.h" #include "analog_controller.h"
#include "analog_joystick.h" #include "analog_joystick.h"
#include "digital_controller.h" #include "digital_controller.h"
#include "namco_guncon.h" #include "fmt/format.h"
#include "guncon.h"
#include "negcon.h" #include "negcon.h"
#include "playstation_mouse.h" #include "playstation_mouse.h"
#include "util/state_wrapper.h" #include "util/state_wrapper.h"
Controller::Controller() = default; static const Controller::ControllerInfo s_none_info = {ControllerType::None,
"None",
"Not Connected",
nullptr,
0,
nullptr,
0,
Controller::VibrationCapabilities::NoVibration};
static const Controller::ControllerInfo* s_controller_info[] = {
&s_none_info, &DigitalController::INFO, &AnalogController::INFO, &AnalogJoystick::INFO, &NeGcon::INFO,
&GunCon::INFO, &PlayStationMouse::INFO,
};
Controller::Controller(u32 index) : m_index(index) {}
Controller::~Controller() = default; Controller::~Controller() = default;
@ -26,19 +41,12 @@ bool Controller::Transfer(const u8 data_in, u8* data_out)
return false; return false;
} }
float Controller::GetAxisState(s32 axis_code) const float Controller::GetBindState(u32 index) const
{ {
return 0.0f; return 0.0f;
} }
void Controller::SetAxisState(s32 axis_code, float value) {} void Controller::SetBindState(u32 index, float value) {}
bool Controller::GetButtonState(s32 button_code) const
{
return false;
}
void Controller::SetButtonState(s32 button_code, bool pressed) {}
u32 Controller::GetButtonStateBits() const u32 Controller::GetButtonStateBits() const
{ {
@ -50,17 +58,7 @@ std::optional<u32> Controller::GetAnalogInputBytes() const
return std::nullopt; return std::nullopt;
} }
u32 Controller::GetVibrationMotorCount() const void Controller::LoadSettings(SettingsInterface& si, const char* section) {}
{
return 0;
}
float Controller::GetVibrationMotorStrength(u32 motor)
{
return 0.0f;
}
void Controller::LoadSettings(const char* section) {}
bool Controller::GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale, bool* relative_mode) bool Controller::GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale, bool* relative_mode)
{ {
@ -72,7 +70,7 @@ std::unique_ptr<Controller> Controller::Create(ControllerType type, u32 index)
switch (type) switch (type)
{ {
case ControllerType::DigitalController: case ControllerType::DigitalController:
return DigitalController::Create(); return DigitalController::Create(index);
case ControllerType::AnalogController: case ControllerType::AnalogController:
return AnalogController::Create(index); return AnalogController::Create(index);
@ -80,14 +78,14 @@ std::unique_ptr<Controller> Controller::Create(ControllerType type, u32 index)
case ControllerType::AnalogJoystick: case ControllerType::AnalogJoystick:
return AnalogJoystick::Create(index); return AnalogJoystick::Create(index);
case ControllerType::NamcoGunCon: case ControllerType::GunCon:
return NamcoGunCon::Create(); return GunCon::Create(index);
case ControllerType::PlayStationMouse: case ControllerType::PlayStationMouse:
return PlayStationMouse::Create(); return PlayStationMouse::Create(index);
case ControllerType::NeGcon: case ControllerType::NeGcon:
return NeGcon::Create(); return NeGcon::Create(index);
case ControllerType::None: case ControllerType::None:
default: default:
@ -95,179 +93,134 @@ std::unique_ptr<Controller> Controller::Create(ControllerType type, u32 index)
} }
} }
std::optional<s32> Controller::GetAxisCodeByName(std::string_view button_name) const const char* Controller::GetDefaultPadType(u32 pad)
{ {
return (pad == 0) ? "DigitalController" : "None";
}
const Controller::ControllerInfo* Controller::GetControllerInfo(ControllerType type)
{
for (const ControllerInfo* info : s_controller_info)
{
if (type == info->type)
return info;
}
return nullptr;
}
const Controller::ControllerInfo* Controller::GetControllerInfo(const std::string_view& name)
{
for (const ControllerInfo* info : s_controller_info)
{
if (name == info->name)
return info;
}
return nullptr;
}
std::vector<std::pair<std::string, std::string>> Controller::GetControllerTypeNames()
{
std::vector<std::pair<std::string, std::string>> ret;
for (const ControllerInfo* info : s_controller_info)
ret.emplace_back(info->name, info->display_name);
return ret;
}
std::vector<std::string> Controller::GetControllerBinds(const std::string_view& type)
{
std::vector<std::string> ret;
const ControllerInfo* info = GetControllerInfo(type);
if (info)
{
for (u32 i = 0; i < info->num_bindings; i++)
{
const ControllerBindingInfo& bi = info->bindings[i];
if (bi.type == ControllerBindingType::Unknown || bi.type == ControllerBindingType::Motor)
continue;
ret.emplace_back(info->bindings[i].name);
}
}
return ret;
}
std::vector<std::string> Controller::GetControllerBinds(ControllerType type)
{
std::vector<std::string> ret;
const ControllerInfo* info = GetControllerInfo(type);
if (info)
{
for (u32 i = 0; i < info->num_bindings; i++)
{
const ControllerBindingInfo& bi = info->bindings[i];
if (bi.type == ControllerBindingType::Unknown || bi.type == ControllerBindingType::Motor)
continue;
ret.emplace_back(info->bindings[i].name);
}
}
return ret;
}
std::optional<u32> Controller::GetBindIndex(ControllerType type, const std::string_view& bind_name)
{
const ControllerInfo* info = GetControllerInfo(type);
if (!info)
return std::nullopt;
for (u32 i = 0; i < info->num_bindings; i++)
{
if (bind_name == info->bindings[i].name)
return i;
}
return std::nullopt; return std::nullopt;
} }
std::optional<s32> Controller::GetButtonCodeByName(std::string_view button_name) const Controller::VibrationCapabilities Controller::GetControllerVibrationCapabilities(const std::string_view& type)
{ {
return std::nullopt; const ControllerInfo* info = GetControllerInfo(type);
return info ? info->vibration_caps : VibrationCapabilities::NoVibration;
} }
Controller::AxisList Controller::GetAxisNames(ControllerType type) std::tuple<u32, u32> Controller::ConvertPadToPortAndSlot(u32 index)
{ {
switch (type) if (index > 4) // [5,6,7]
{ return std::make_tuple(1, index - 4); // 2B,2C,2D
case ControllerType::DigitalController: else if (index > 1) // [2,3,4]
return DigitalController::StaticGetAxisNames(); return std::make_tuple(0, index - 1); // 1B,1C,1D
else // [0,1]
case ControllerType::AnalogController: return std::make_tuple(index, 0); // 1A,2A
return AnalogController::StaticGetAxisNames();
case ControllerType::AnalogJoystick:
return AnalogJoystick::StaticGetAxisNames();
case ControllerType::NamcoGunCon:
return NamcoGunCon::StaticGetAxisNames();
case ControllerType::PlayStationMouse:
return PlayStationMouse::StaticGetAxisNames();
case ControllerType::NeGcon:
return NeGcon::StaticGetAxisNames();
case ControllerType::None:
default:
return {};
}
} }
Controller::ButtonList Controller::GetButtonNames(ControllerType type) u32 Controller::ConvertPortAndSlotToPad(u32 port, u32 slot)
{ {
switch (type) if (slot == 0)
{ return port;
case ControllerType::DigitalController: else if (port == 0) // slot=[0,1]
return DigitalController::StaticGetButtonNames(); return slot + 1; // 2,3,4
else
case ControllerType::AnalogController: return slot + 4; // 5,6,7
return AnalogController::StaticGetButtonNames();
case ControllerType::AnalogJoystick:
return AnalogJoystick::StaticGetButtonNames();
case ControllerType::NamcoGunCon:
return NamcoGunCon::StaticGetButtonNames();
case ControllerType::PlayStationMouse:
return PlayStationMouse::StaticGetButtonNames();
case ControllerType::NeGcon:
return NeGcon::StaticGetButtonNames();
case ControllerType::None:
default:
return {};
}
} }
u32 Controller::GetVibrationMotorCount(ControllerType type) bool Controller::PadIsMultitapSlot(u32 index)
{ {
switch (type) return (index >= 2);
{
case ControllerType::DigitalController:
return DigitalController::StaticGetVibrationMotorCount();
case ControllerType::AnalogController:
return AnalogController::StaticGetVibrationMotorCount();
case ControllerType::AnalogJoystick:
return AnalogJoystick::StaticGetVibrationMotorCount();
case ControllerType::NamcoGunCon:
return NamcoGunCon::StaticGetVibrationMotorCount();
case ControllerType::PlayStationMouse:
return PlayStationMouse::StaticGetVibrationMotorCount();
case ControllerType::NeGcon:
return NeGcon::StaticGetVibrationMotorCount();
case ControllerType::None:
default:
return 0;
}
} }
std::optional<s32> Controller::GetAxisCodeByName(ControllerType type, std::string_view axis_name) bool Controller::PortAndSlotIsMultitap(u32 port, u32 slot)
{ {
switch (type) return (slot != 0);
{
case ControllerType::DigitalController:
return DigitalController::StaticGetAxisCodeByName(axis_name);
case ControllerType::AnalogController:
return AnalogController::StaticGetAxisCodeByName(axis_name);
case ControllerType::AnalogJoystick:
return AnalogJoystick::StaticGetAxisCodeByName(axis_name);
case ControllerType::NamcoGunCon:
return NamcoGunCon::StaticGetAxisCodeByName(axis_name);
case ControllerType::PlayStationMouse:
return PlayStationMouse::StaticGetAxisCodeByName(axis_name);
case ControllerType::NeGcon:
return NeGcon::StaticGetAxisCodeByName(axis_name);
case ControllerType::None:
default:
return std::nullopt;
}
} }
std::optional<s32> Controller::GetButtonCodeByName(ControllerType type, std::string_view button_name) std::string Controller::GetSettingsSection(u32 pad)
{ {
switch (type) return fmt::format("Pad{}", pad + 1u);
{
case ControllerType::DigitalController:
return DigitalController::StaticGetButtonCodeByName(button_name);
case ControllerType::AnalogController:
return AnalogController::StaticGetButtonCodeByName(button_name);
case ControllerType::AnalogJoystick:
return AnalogJoystick::StaticGetButtonCodeByName(button_name);
case ControllerType::NamcoGunCon:
return NamcoGunCon::StaticGetButtonCodeByName(button_name);
case ControllerType::PlayStationMouse:
return PlayStationMouse::StaticGetButtonCodeByName(button_name);
case ControllerType::NeGcon:
return NeGcon::StaticGetButtonCodeByName(button_name);
case ControllerType::None:
default:
return std::nullopt;
}
}
Controller::SettingList Controller::GetSettings(ControllerType type)
{
switch (type)
{
case ControllerType::DigitalController:
return DigitalController::StaticGetSettings();
case ControllerType::AnalogController:
return AnalogController::StaticGetSettings();
case ControllerType::AnalogJoystick:
return AnalogJoystick::StaticGetSettings();
case ControllerType::NamcoGunCon:
return NamcoGunCon::StaticGetSettings();
case ControllerType::NeGcon:
return NeGcon::StaticGetSettings();
case ControllerType::PlayStationMouse:
return PlayStationMouse::StaticGetSettings();
default:
return {};
}
} }

View file

@ -6,36 +6,67 @@
#include <optional> #include <optional>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <tuple>
#include <vector> #include <vector>
class SettingsInterface;
class StateWrapper; class StateWrapper;
class HostInterface; class HostInterface;
enum class GenericInputBinding : u8;
class Controller class Controller
{ {
public: public:
enum class AxisType : u8 enum class ControllerBindingType : u8
{ {
Full, Unknown,
Half Button,
Axis,
HalfAxis,
Motor,
Macro
}; };
using ButtonList = std::vector<std::pair<std::string, s32>>; enum class VibrationCapabilities : u8
using AxisList = std::vector<std::tuple<std::string, s32, AxisType>>; {
using SettingList = std::vector<SettingInfo>; NoVibration,
LargeSmallMotors,
SingleMotor,
Count
};
Controller(); struct ControllerBindingInfo
{
const char* name;
const char* display_name;
u32 bind_index;
ControllerBindingType type;
GenericInputBinding generic_mapping;
};
struct ControllerInfo
{
ControllerType type;
const char* name;
const char* display_name;
const ControllerBindingInfo* bindings;
u32 num_bindings;
const SettingInfo* settings;
u32 num_settings;
VibrationCapabilities vibration_caps;
};
/// Default stick deadzone/sensitivity.
static constexpr float DEFAULT_STICK_DEADZONE = 0.0f;
static constexpr float DEFAULT_STICK_SENSITIVITY = 1.33f;
Controller(u32 index);
virtual ~Controller(); virtual ~Controller();
/// Returns the type of controller. /// Returns the type of controller.
virtual ControllerType GetType() const = 0; virtual ControllerType GetType() const = 0;
/// Gets the integer code for an axis in the specified controller type.
virtual std::optional<s32> GetAxisCodeByName(std::string_view axis_name) const;
/// Gets the integer code for a button in the specified controller type.
virtual std::optional<s32> GetButtonCodeByName(std::string_view button_name) const;
virtual void Reset(); virtual void Reset();
virtual bool DoState(StateWrapper& sw, bool apply_input_state); virtual bool DoState(StateWrapper& sw, bool apply_input_state);
@ -46,16 +77,10 @@ public:
virtual bool Transfer(const u8 data_in, u8* data_out); virtual bool Transfer(const u8 data_in, u8* data_out);
/// Changes the specified axis state. Values are normalized from -1..1. /// Changes the specified axis state. Values are normalized from -1..1.
virtual float GetAxisState(s32 axis_code) const; virtual float GetBindState(u32 index) const;
/// Changes the specified axis state. Values are normalized from -1..1. /// Changes the specified bind state. Values are normalized from -1..1.
virtual void SetAxisState(s32 axis_code, float value); virtual void SetBindState(u32 index, float value);
/// Returns the specified button state.
virtual bool GetButtonState(s32 button_code) const;
/// Changes the specified button state.
virtual void SetButtonState(s32 button_code, bool pressed);
/// Returns a bitmask of the current button states, 1 = on. /// Returns a bitmask of the current button states, 1 = on.
virtual u32 GetButtonStateBits() const; virtual u32 GetButtonStateBits() const;
@ -63,14 +88,8 @@ public:
/// Returns analog input bytes packed as a u32. Values are specific to controller type. /// Returns analog input bytes packed as a u32. Values are specific to controller type.
virtual std::optional<u32> GetAnalogInputBytes() const; virtual std::optional<u32> GetAnalogInputBytes() const;
/// Returns the number of vibration motors.
virtual u32 GetVibrationMotorCount() const;
/// Queries the state of the specified vibration motor. Values are normalized from 0..1.
virtual float GetVibrationMotorStrength(u32 motor);
/// Loads/refreshes any per-controller settings. /// Loads/refreshes any per-controller settings.
virtual void LoadSettings(const char* section); virtual void LoadSettings(SettingsInterface& si, const char* section);
/// Returns the software cursor to use for this controller, if any. /// Returns the software cursor to use for this controller, if any.
virtual bool GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale, bool* relative_mode); virtual bool GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale, bool* relative_mode);
@ -78,21 +97,45 @@ public:
/// Creates a new controller of the specified type. /// Creates a new controller of the specified type.
static std::unique_ptr<Controller> Create(ControllerType type, u32 index); static std::unique_ptr<Controller> Create(ControllerType type, u32 index);
/// Returns the default type for the specified port.
static const char* GetDefaultPadType(u32 pad);
/// Returns a list of controller type names. Pair of [name, display name].
static std::vector<std::pair<std::string, std::string>> GetControllerTypeNames();
/// Returns the list of binds for the specified controller type.
static std::vector<std::string> GetControllerBinds(const std::string_view& type);
static std::vector<std::string> GetControllerBinds(ControllerType type);
/// Gets the integer code for an axis in the specified controller type. /// Gets the integer code for an axis in the specified controller type.
static std::optional<s32> GetAxisCodeByName(ControllerType type, std::string_view axis_name); static std::optional<u32> GetBindIndex(ControllerType type, const std::string_view& bind_name);
/// Gets the integer code for a button in the specified controller type. /// Returns the vibration configuration for the specified controller type.
static std::optional<s32> GetButtonCodeByName(ControllerType type, std::string_view button_name); static VibrationCapabilities GetControllerVibrationCapabilities(const std::string_view& type);
/// Returns a list of axises for the specified controller type. /// Returns general information for the specified controller type.
static AxisList GetAxisNames(ControllerType type); static const ControllerInfo* GetControllerInfo(ControllerType type);
static const ControllerInfo* GetControllerInfo(const std::string_view& name);
/// Returns a list of buttons for the specified controller type. /// Converts a global pad index to a multitap port and slot.
static ButtonList GetButtonNames(ControllerType type); static std::tuple<u32, u32> ConvertPadToPortAndSlot(u32 index);
/// Returns the number of vibration motors. /// Converts a multitap port and slot to a global pad index.
static u32 GetVibrationMotorCount(ControllerType type); static u32 ConvertPortAndSlotToPad(u32 port, u32 slot);
/// Returns settings for the controller. /// Returns true if the given pad index is a multitap slot.
static SettingList GetSettings(ControllerType type); static bool PadIsMultitapSlot(u32 index);
static bool PortAndSlotIsMultitap(u32 port, u32 slot);
/// Returns the configuration section for the specified gamepad.
static std::string GetSettingsSection(u32 pad);
/// Applies an analog deadzone/sensitivity.
static float ApplyAnalogDeadzoneSensitivity(float deadzone, float sensitivity, float value)
{
return (value < deadzone) ? 0.0f : ((value - deadzone) / (1.0f - deadzone) * sensitivity);
}
protected:
u32 m_index;
}; };

View file

@ -9,7 +9,7 @@
<PreprocessorDefinitions Condition="('$(Platform)'=='x64' Or '$(Platform)'=='ARM' Or '$(Platform)'=='ARM64')">WITH_RECOMPILER=1;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="('$(Platform)'=='x64' Or '$(Platform)'=='ARM' Or '$(Platform)'=='ARM64')">WITH_RECOMPILER=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="('$(Platform)'=='x64' Or '$(Platform)'=='ARM64') And ('$(BuildingForUWP)'!='true')">WITH_MMAP_FASTMEM=1;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="('$(Platform)'=='x64' Or '$(Platform)'=='ARM64') And ('$(BuildingForUWP)'!='true')">WITH_MMAP_FASTMEM=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xxhash\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\rcheevos\include;$(SolutionDir)dep\rapidjson\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(SolutionDir)dep\tinyxml2\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xxhash\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\rcheevos\include;$(SolutionDir)dep\rapidjson\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="('$(BuildingForUWP)'!='true' And '$(Platform)'!='ARM64')">$(SolutionDir)dep\rainterface;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories Condition="('$(BuildingForUWP)'!='true' And '$(Platform)'!='ARM64')">$(SolutionDir)dep\rainterface;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="'$(Platform)'=='x64'">$(SolutionDir)dep\xbyak\xbyak;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories Condition="'$(Platform)'=='x64'">$(SolutionDir)dep\xbyak\xbyak;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@ -19,7 +19,7 @@
<ItemDefinitionGroup> <ItemDefinitionGroup>
<Lib> <Lib>
<AdditionalDependencies>$(RootBuildDir)rcheevos\rcheevos.lib;$(RootBuildDir)imgui\imgui.lib;$(RootBuildDir)stb\stb.lib;$(RootBuildDir)xxhash\xxhash.lib;$(RootBuildDir)zlib\zlib.lib;$(RootBuildDir)util\util.lib;$(RootBuildDir)common\common.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>$(RootBuildDir)tinyxml2\tinyxml2.lib;$(RootBuildDir)rcheevos\rcheevos.lib;$(RootBuildDir)imgui\imgui.lib;$(RootBuildDir)stb\stb.lib;$(RootBuildDir)xxhash\xxhash.lib;$(RootBuildDir)zlib\zlib.lib;$(RootBuildDir)util\util.lib;$(RootBuildDir)common\common.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies Condition="('$(BuildingForUWP)'!='true' And '$(Platform)'!='ARM64')">$(RootBuildDir)rainterface\rainterface.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies Condition="('$(BuildingForUWP)'!='true' And '$(Platform)'!='ARM64')">$(RootBuildDir)rainterface\rainterface.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies Condition="'$(Platform)'=='ARM64'">$(RootBuildDir)vixl\vixl.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies Condition="'$(Platform)'=='ARM64'">$(RootBuildDir)vixl\vixl.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Lib> </Lib>

View file

@ -9,7 +9,6 @@
<ClCompile Include="cdrom.cpp" /> <ClCompile Include="cdrom.cpp" />
<ClCompile Include="cdrom_async_reader.cpp" /> <ClCompile Include="cdrom_async_reader.cpp" />
<ClCompile Include="cheats.cpp" /> <ClCompile Include="cheats.cpp" />
<ClCompile Include="cheevos.cpp" />
<ClCompile Include="cpu_core.cpp" /> <ClCompile Include="cpu_core.cpp" />
<ClCompile Include="cpu_disasm.cpp" /> <ClCompile Include="cpu_disasm.cpp" />
<ClCompile Include="cpu_code_cache.cpp" /> <ClCompile Include="cpu_code_cache.cpp" />
@ -33,6 +32,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="cpu_types.cpp" /> <ClCompile Include="cpu_types.cpp" />
<ClCompile Include="digital_controller.cpp" /> <ClCompile Include="digital_controller.cpp" />
<ClCompile Include="game_database.cpp" />
<ClCompile Include="gpu_backend.cpp" /> <ClCompile Include="gpu_backend.cpp" />
<ClCompile Include="gpu_commands.cpp" /> <ClCompile Include="gpu_commands.cpp" />
<ClCompile Include="gpu_hw_d3d11.cpp" /> <ClCompile Include="gpu_hw_d3d11.cpp" />
@ -47,18 +47,16 @@
<ClCompile Include="gpu.cpp" /> <ClCompile Include="gpu.cpp" />
<ClCompile Include="gpu_hw.cpp" /> <ClCompile Include="gpu_hw.cpp" />
<ClCompile Include="gpu_hw_opengl.cpp" /> <ClCompile Include="gpu_hw_opengl.cpp" />
<ClCompile Include="host.cpp" />
<ClCompile Include="host_display.cpp" /> <ClCompile Include="host_display.cpp" />
<ClCompile Include="host_interface.cpp" />
<ClCompile Include="host_interface_progress_callback.cpp" /> <ClCompile Include="host_interface_progress_callback.cpp" />
<ClCompile Include="imgui_fullscreen.cpp" />
<ClCompile Include="imgui_styles.cpp" />
<ClCompile Include="interrupt_controller.cpp" /> <ClCompile Include="interrupt_controller.cpp" />
<ClCompile Include="libcrypt_game_codes.cpp" /> <ClCompile Include="libcrypt_game_codes.cpp" />
<ClCompile Include="mdec.cpp" /> <ClCompile Include="mdec.cpp" />
<ClCompile Include="memory_card.cpp" /> <ClCompile Include="memory_card.cpp" />
<ClCompile Include="memory_card_image.cpp" /> <ClCompile Include="memory_card_image.cpp" />
<ClCompile Include="multitap.cpp" /> <ClCompile Include="multitap.cpp" />
<ClCompile Include="namco_guncon.cpp" /> <ClCompile Include="guncon.cpp" />
<ClCompile Include="negcon.cpp" /> <ClCompile Include="negcon.cpp" />
<ClCompile Include="pad.cpp" /> <ClCompile Include="pad.cpp" />
<ClCompile Include="controller.cpp" /> <ClCompile Include="controller.cpp" />
@ -83,7 +81,7 @@
<ClInclude Include="cdrom.h" /> <ClInclude Include="cdrom.h" />
<ClInclude Include="cdrom_async_reader.h" /> <ClInclude Include="cdrom_async_reader.h" />
<ClInclude Include="cheats.h" /> <ClInclude Include="cheats.h" />
<ClInclude Include="cheevos.h" /> <ClInclude Include="achievements.h" />
<ClInclude Include="cpu_core.h" /> <ClInclude Include="cpu_core.h" />
<ClInclude Include="cpu_core_private.h" /> <ClInclude Include="cpu_core_private.h" />
<ClInclude Include="cpu_disasm.h" /> <ClInclude Include="cpu_disasm.h" />
@ -101,6 +99,7 @@
<ExcludedFromBuild Condition="'$(Platform)'=='Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Platform)'=='Win32'">true</ExcludedFromBuild>
</ClInclude> </ClInclude>
<ClInclude Include="digital_controller.h" /> <ClInclude Include="digital_controller.h" />
<ClInclude Include="game_database.h" />
<ClInclude Include="gpu_backend.h" /> <ClInclude Include="gpu_backend.h" />
<ClInclude Include="gpu_hw_d3d11.h" /> <ClInclude Include="gpu_hw_d3d11.h" />
<ClInclude Include="gpu_hw_d3d12.h" /> <ClInclude Include="gpu_hw_d3d12.h" />
@ -119,18 +118,15 @@
<ClInclude Include="gte_types.h" /> <ClInclude Include="gte_types.h" />
<ClInclude Include="host.h" /> <ClInclude Include="host.h" />
<ClInclude Include="host_display.h" /> <ClInclude Include="host_display.h" />
<ClInclude Include="host_interface.h" />
<ClInclude Include="host_interface_progress_callback.h" /> <ClInclude Include="host_interface_progress_callback.h" />
<ClInclude Include="host_settings.h" /> <ClInclude Include="host_settings.h" />
<ClInclude Include="imgui_fullscreen.h" />
<ClInclude Include="imgui_styles.h" />
<ClInclude Include="interrupt_controller.h" /> <ClInclude Include="interrupt_controller.h" />
<ClInclude Include="libcrypt_game_codes.h" /> <ClInclude Include="libcrypt_game_codes.h" />
<ClInclude Include="mdec.h" /> <ClInclude Include="mdec.h" />
<ClInclude Include="memory_card.h" /> <ClInclude Include="memory_card.h" />
<ClInclude Include="memory_card_image.h" /> <ClInclude Include="memory_card_image.h" />
<ClInclude Include="multitap.h" /> <ClInclude Include="multitap.h" />
<ClInclude Include="namco_guncon.h" /> <ClInclude Include="guncon.h" />
<ClInclude Include="negcon.h" /> <ClInclude Include="negcon.h" />
<ClInclude Include="pad.h" /> <ClInclude Include="pad.h" />
<ClInclude Include="controller.h" /> <ClInclude Include="controller.h" />

View file

@ -10,7 +10,6 @@
<ClCompile Include="gpu.cpp" /> <ClCompile Include="gpu.cpp" />
<ClCompile Include="gpu_hw_opengl.cpp" /> <ClCompile Include="gpu_hw_opengl.cpp" />
<ClCompile Include="gpu_hw.cpp" /> <ClCompile Include="gpu_hw.cpp" />
<ClCompile Include="host_interface.cpp" />
<ClCompile Include="interrupt_controller.cpp" /> <ClCompile Include="interrupt_controller.cpp" />
<ClCompile Include="cdrom.cpp" /> <ClCompile Include="cdrom.cpp" />
<ClCompile Include="gte.cpp" /> <ClCompile Include="gte.cpp" />
@ -40,7 +39,7 @@
<ClCompile Include="timing_event.cpp" /> <ClCompile Include="timing_event.cpp" />
<ClCompile Include="cdrom_async_reader.cpp" /> <ClCompile Include="cdrom_async_reader.cpp" />
<ClCompile Include="psf_loader.cpp" /> <ClCompile Include="psf_loader.cpp" />
<ClCompile Include="namco_guncon.cpp" /> <ClCompile Include="guncon.cpp" />
<ClCompile Include="playstation_mouse.cpp" /> <ClCompile Include="playstation_mouse.cpp" />
<ClCompile Include="negcon.cpp" /> <ClCompile Include="negcon.cpp" />
<ClCompile Include="gpu_hw_vulkan.cpp" /> <ClCompile Include="gpu_hw_vulkan.cpp" />
@ -58,9 +57,8 @@
<ClCompile Include="texture_replacements.cpp" /> <ClCompile Include="texture_replacements.cpp" />
<ClCompile Include="multitap.cpp" /> <ClCompile Include="multitap.cpp" />
<ClCompile Include="gpu_hw_d3d12.cpp" /> <ClCompile Include="gpu_hw_d3d12.cpp" />
<ClCompile Include="imgui_fullscreen.cpp" /> <ClCompile Include="host.cpp" />
<ClCompile Include="imgui_styles.cpp" /> <ClCompile Include="game_database.cpp" />
<ClCompile Include="cheevos.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="types.h" /> <ClInclude Include="types.h" />
@ -74,7 +72,6 @@
<ClInclude Include="gpu.h" /> <ClInclude Include="gpu.h" />
<ClInclude Include="gpu_hw_opengl.h" /> <ClInclude Include="gpu_hw_opengl.h" />
<ClInclude Include="gpu_hw.h" /> <ClInclude Include="gpu_hw.h" />
<ClInclude Include="host_interface.h" />
<ClInclude Include="interrupt_controller.h" /> <ClInclude Include="interrupt_controller.h" />
<ClInclude Include="cdrom.h" /> <ClInclude Include="cdrom.h" />
<ClInclude Include="gte.h" /> <ClInclude Include="gte.h" />
@ -101,7 +98,7 @@
<ClInclude Include="timing_event.h" /> <ClInclude Include="timing_event.h" />
<ClInclude Include="cdrom_async_reader.h" /> <ClInclude Include="cdrom_async_reader.h" />
<ClInclude Include="psf_loader.h" /> <ClInclude Include="psf_loader.h" />
<ClInclude Include="namco_guncon.h" /> <ClInclude Include="guncon.h" />
<ClInclude Include="playstation_mouse.h" /> <ClInclude Include="playstation_mouse.h" />
<ClInclude Include="negcon.h" /> <ClInclude Include="negcon.h" />
<ClInclude Include="gpu_hw_vulkan.h" /> <ClInclude Include="gpu_hw_vulkan.h" />
@ -123,10 +120,9 @@
<ClInclude Include="multitap.h" /> <ClInclude Include="multitap.h" />
<ClInclude Include="gpu_hw_d3d12.h" /> <ClInclude Include="gpu_hw_d3d12.h" />
<ClInclude Include="gdb_protocol.h" /> <ClInclude Include="gdb_protocol.h" />
<ClInclude Include="imgui_fullscreen.h" />
<ClInclude Include="imgui_styles.h" />
<ClInclude Include="cheevos.h" />
<ClInclude Include="host.h" /> <ClInclude Include="host.h" />
<ClInclude Include="host_settings.h" /> <ClInclude Include="host_settings.h" />
<ClInclude Include="achievements.h" />
<ClInclude Include="game_database.h" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -7,7 +7,7 @@
#include "cpu_disasm.h" #include "cpu_disasm.h"
#include "cpu_recompiler_thunks.h" #include "cpu_recompiler_thunks.h"
#include "gte.h" #include "gte.h"
#include "host_interface.h" #include "host.h"
#include "pgxp.h" #include "pgxp.h"
#include "settings.h" #include "settings.h"
#include "system.h" #include "system.h"
@ -1691,8 +1691,8 @@ bool AddBreakpoint(VirtualMemoryAddress address, bool auto_clear, bool enabled)
if (!auto_clear) if (!auto_clear)
{ {
g_host_interface->ReportFormattedDebuggerMessage( Host::ReportFormattedDebuggerMessage(Host::TranslateString("DebuggerMessage", "Added breakpoint at 0x%08X."),
g_host_interface->TranslateString("DebuggerMessage", "Added breakpoint at 0x%08X."), address); address);
} }
return true; return true;
@ -1718,8 +1718,8 @@ bool RemoveBreakpoint(VirtualMemoryAddress address)
if (it == s_breakpoints.end()) if (it == s_breakpoints.end())
return false; return false;
g_host_interface->ReportFormattedDebuggerMessage( Host::ReportFormattedDebuggerMessage(Host::TranslateString("DebuggerMessage", "Removed breakpoint at 0x%08X."),
g_host_interface->TranslateString("DebuggerMessage", "Removed breakpoint at 0x%08X."), address); address);
s_breakpoints.erase(it); s_breakpoints.erase(it);
UpdateDebugDispatcherFlag(); UpdateDebugDispatcherFlag();
@ -1750,8 +1750,8 @@ bool AddStepOverBreakpoint()
if (!IsCallInstruction(inst)) if (!IsCallInstruction(inst))
{ {
g_host_interface->ReportFormattedDebuggerMessage( Host::ReportFormattedDebuggerMessage(Host::TranslateString("DebuggerMessage", "0x%08X is not a call instruction."),
g_host_interface->TranslateString("DebuggerMessage", "0x%08X is not a call instruction."), g_state.regs.pc); g_state.regs.pc);
return false; return false;
} }
@ -1760,16 +1760,15 @@ bool AddStepOverBreakpoint()
if (IsBranchInstruction(inst)) if (IsBranchInstruction(inst))
{ {
g_host_interface->ReportFormattedDebuggerMessage( Host::ReportFormattedDebuggerMessage(
g_host_interface->TranslateString("DebuggerMessage", "Can't step over double branch at 0x%08X"), g_state.regs.pc); Host::TranslateString("DebuggerMessage", "Can't step over double branch at 0x%08X"), g_state.regs.pc);
return false; return false;
} }
// skip the delay slot // skip the delay slot
bp_pc += sizeof(Instruction); bp_pc += sizeof(Instruction);
g_host_interface->ReportFormattedDebuggerMessage( Host::ReportFormattedDebuggerMessage(Host::TranslateString("DebuggerMessage", "Stepping over to 0x%08X."), bp_pc);
g_host_interface->TranslateString("DebuggerMessage", "Stepping over to 0x%08X."), bp_pc);
return AddBreakpoint(bp_pc, true); return AddBreakpoint(bp_pc, true);
} }
@ -1785,25 +1784,22 @@ bool AddStepOutBreakpoint(u32 max_instructions_to_search)
Instruction inst; Instruction inst;
if (!SafeReadInstruction(ret_pc, &inst.bits)) if (!SafeReadInstruction(ret_pc, &inst.bits))
{ {
g_host_interface->ReportFormattedDebuggerMessage( Host::ReportFormattedDebuggerMessage(
g_host_interface->TranslateString("DebuggerMessage", Host::TranslateString("DebuggerMessage", "Instruction read failed at %08X while searching for function end."),
"Instruction read failed at %08X while searching for function end."),
ret_pc); ret_pc);
return false; return false;
} }
if (IsReturnInstruction(inst)) if (IsReturnInstruction(inst))
{ {
g_host_interface->ReportFormattedDebuggerMessage( Host::ReportFormattedDebuggerMessage(Host::TranslateString("DebuggerMessage", "Stepping out to 0x%08X."), ret_pc);
g_host_interface->TranslateString("DebuggerMessage", "Stepping out to 0x%08X."), ret_pc);
return AddBreakpoint(ret_pc, true); return AddBreakpoint(ret_pc, true);
} }
} }
g_host_interface->ReportFormattedDebuggerMessage( Host::ReportFormattedDebuggerMessage(
g_host_interface->TranslateString("DebuggerMessage", Host::TranslateString("DebuggerMessage", "No return instruction found after %u instructions for step-out at %08X."),
"No return instruction found after %u instructions for step-out at %08X."),
max_instructions_to_search, g_state.regs.pc); max_instructions_to_search, g_state.regs.pc);
return false; return false;
@ -1857,18 +1853,18 @@ ALWAYS_INLINE_RELEASE static bool BreakpointCheck()
} }
else else
{ {
g_host_interface->PauseSystem(true); System::PauseSystem(true);
if (bp.auto_clear) if (bp.auto_clear)
{ {
g_host_interface->ReportFormattedDebuggerMessage("Stopped execution at 0x%08X.", pc); Host::ReportFormattedDebuggerMessage("Stopped execution at 0x%08X.", pc);
s_breakpoints.erase(s_breakpoints.begin() + i); s_breakpoints.erase(s_breakpoints.begin() + i);
count--; count--;
UpdateDebugDispatcherFlag(); UpdateDebugDispatcherFlag();
} }
else else
{ {
g_host_interface->ReportFormattedDebuggerMessage("Hit breakpoint %u at 0x%08X.", bp.number, pc); Host::ReportFormattedDebuggerMessage("Hit breakpoint %u at 0x%08X.", bp.number, pc);
i++; i++;
} }
} }
@ -1979,7 +1975,7 @@ void SingleStep()
{ {
s_single_step = true; s_single_step = true;
ExecuteDebug(); ExecuteDebug();
g_host_interface->ReportFormattedDebuggerMessage("Stepped to 0x%08X.", g_state.regs.pc); Host::ReportFormattedDebuggerMessage("Stepped to 0x%08X.", g_state.regs.pc);
} }
namespace CodeCache { namespace CodeCache {

View file

@ -1,10 +1,10 @@
#include "digital_controller.h" #include "digital_controller.h"
#include "common/assert.h" #include "common/assert.h"
#include "host_interface.h" #include "host.h"
#include "system.h" #include "system.h"
#include "util/state_wrapper.h" #include "util/state_wrapper.h"
DigitalController::DigitalController() = default; DigitalController::DigitalController(u32 index) : Controller(index) {}
DigitalController::~DigitalController() = default; DigitalController::~DigitalController() = default;
@ -13,16 +13,6 @@ ControllerType DigitalController::GetType() const
return ControllerType::DigitalController; return ControllerType::DigitalController;
} }
std::optional<s32> DigitalController::GetAxisCodeByName(std::string_view axis_name) const
{
return StaticGetAxisCodeByName(axis_name);
}
std::optional<s32> DigitalController::GetButtonCodeByName(std::string_view button_name) const
{
return StaticGetButtonCodeByName(button_name);
}
void DigitalController::Reset() void DigitalController::Reset()
{ {
m_transfer_state = TransferState::Idle; m_transfer_state = TransferState::Idle;
@ -42,18 +32,25 @@ bool DigitalController::DoState(StateWrapper& sw, bool apply_input_state)
return true; return true;
} }
bool DigitalController::GetButtonState(s32 button_code) const float DigitalController::GetBindState(u32 index) const
{ {
if (button_code < 0 || button_code >= static_cast<s32>(Button::Count)) if (index < static_cast<u32>(Button::Count))
return false; {
return static_cast<float>(((m_button_state >> index) & 1u) ^ 1u);
const u16 bit = u16(1) << static_cast<u8>(button_code); }
return ((m_button_state & bit) == 0); else
{
return 0.0f;
}
} }
void DigitalController::SetButtonState(Button button, bool pressed) void DigitalController::SetBindState(u32 index, float value)
{ {
const u16 bit = u16(1) << static_cast<u8>(button); if (index >= static_cast<u32>(Button::Count))
return;
const bool pressed = (value >= 0.5f);
const u16 bit = u16(1) << static_cast<u8>(index);
if (pressed) if (pressed)
{ {
if (m_button_state & bit) if (m_button_state & bit)
@ -70,14 +67,6 @@ void DigitalController::SetButtonState(Button button, bool pressed)
} }
} }
void DigitalController::SetButtonState(s32 button_code, bool pressed)
{
if (button_code < 0 || button_code >= static_cast<s32>(Button::Count))
return;
SetButtonState(static_cast<Button>(button_code), pressed);
}
u32 DigitalController::GetButtonStateBits() const u32 DigitalController::GetButtonStateBits() const
{ {
return m_button_state ^ 0xFFFF; return m_button_state ^ 0xFFFF;
@ -146,87 +135,53 @@ bool DigitalController::Transfer(const u8 data_in, u8* data_out)
} }
} }
std::unique_ptr<DigitalController> DigitalController::Create() std::unique_ptr<DigitalController> DigitalController::Create(u32 index)
{ {
return std::make_unique<DigitalController>(); return std::make_unique<DigitalController>(index);
} }
std::optional<s32> DigitalController::StaticGetAxisCodeByName(std::string_view button_name) static const Controller::ControllerBindingInfo s_binding_info[] = {
{ #define BUTTON(name, display_name, button, genb) \
return std::nullopt;
}
std::optional<s32> DigitalController::StaticGetButtonCodeByName(std::string_view button_name)
{
#define BUTTON(name) \
if (button_name == #name) \
{ \ { \
return static_cast<s32>(ZeroExtend32(static_cast<u8>(Button::name))); \ name, display_name, static_cast<u32>(button), Controller::ControllerBindingType::Button, genb \
} }
BUTTON(Select); BUTTON("Up", "D-Pad Up", DigitalController::Button::Up, GenericInputBinding::DPadUp),
BUTTON(L3); BUTTON("Right", "D-Pad Right", DigitalController::Button::Right, GenericInputBinding::DPadRight),
BUTTON(R3); BUTTON("Down", "D-Pad Down", DigitalController::Button::Down, GenericInputBinding::DPadDown),
BUTTON(Start); BUTTON("Left", "D-Pad Left", DigitalController::Button::Left, GenericInputBinding::DPadLeft),
BUTTON(Up); BUTTON("Triangle", "Triangle", DigitalController::Button::Triangle, GenericInputBinding::Triangle),
BUTTON(Right); BUTTON("Circle", "Circle", DigitalController::Button::Circle, GenericInputBinding::Circle),
BUTTON(Down); BUTTON("Cross", "Cross", DigitalController::Button::Cross, GenericInputBinding::Cross),
BUTTON(Left); BUTTON("Square", "Square", DigitalController::Button::Square, GenericInputBinding::Square),
BUTTON(L2); BUTTON("Select", "Select", DigitalController::Button::Select, GenericInputBinding::Select),
BUTTON(R2); BUTTON("Start", "Start", DigitalController::Button::Start, GenericInputBinding::Start),
BUTTON(L1); BUTTON("L1", "L1", DigitalController::Button::L1, GenericInputBinding::L1),
BUTTON(R1); BUTTON("R1", "R1", DigitalController::Button::R1, GenericInputBinding::R1),
BUTTON(Triangle); BUTTON("L2", "L2", DigitalController::Button::L2, GenericInputBinding::L2),
BUTTON(Circle); BUTTON("R2", "R2", DigitalController::Button::R2, GenericInputBinding::R2),
BUTTON(Cross);
BUTTON(Square);
return std::nullopt;
#undef BUTTON #undef BUTTON
} };
Controller::AxisList DigitalController::StaticGetAxisNames() static const SettingInfo s_settings[] = {
{ {SettingInfo::Type::Boolean, "ForcePopnControllerMode",
return {};
}
Controller::ButtonList DigitalController::StaticGetButtonNames()
{
return {{TRANSLATABLE("DigitalController", "Up"), static_cast<s32>(Button::Up)},
{TRANSLATABLE("DigitalController", "Down"), static_cast<s32>(Button::Down)},
{TRANSLATABLE("DigitalController", "Left"), static_cast<s32>(Button::Left)},
{TRANSLATABLE("DigitalController", "Right"), static_cast<s32>(Button::Right)},
{TRANSLATABLE("DigitalController", "Select"), static_cast<s32>(Button::Select)},
{TRANSLATABLE("DigitalController", "Start"), static_cast<s32>(Button::Start)},
{TRANSLATABLE("DigitalController", "Triangle"), static_cast<s32>(Button::Triangle)},
{TRANSLATABLE("DigitalController", "Cross"), static_cast<s32>(Button::Cross)},
{TRANSLATABLE("DigitalController", "Circle"), static_cast<s32>(Button::Circle)},
{TRANSLATABLE("DigitalController", "Square"), static_cast<s32>(Button::Square)},
{TRANSLATABLE("DigitalController", "L1"), static_cast<s32>(Button::L1)},
{TRANSLATABLE("DigitalController", "L2"), static_cast<s32>(Button::L2)},
{TRANSLATABLE("DigitalController", "R1"), static_cast<s32>(Button::R1)},
{TRANSLATABLE("DigitalController", "R2"), static_cast<s32>(Button::R2)}};
}
u32 DigitalController::StaticGetVibrationMotorCount()
{
return 0;
}
Controller::SettingList DigitalController::StaticGetSettings()
{
static constexpr std::array<SettingInfo, 1> settings = {
{{SettingInfo::Type::Boolean, "ForcePopnControllerMode",
TRANSLATABLE("DigitalController", "Force Pop'n Controller Mode"), TRANSLATABLE("DigitalController", "Force Pop'n Controller Mode"),
TRANSLATABLE("DigitalController", "Forces the Digital Controller to act as a Pop'n Controller."), "false"}}}; TRANSLATABLE("DigitalController", "Forces the Digital Controller to act as a Pop'n Controller."), "false"}};
return SettingList(settings.begin(), settings.end());
}
void DigitalController::LoadSettings(const char* section) const Controller::ControllerInfo DigitalController::INFO = {ControllerType::DigitalController,
"DigitalController",
TRANSLATABLE("ControllerType", "Digital Controller"),
s_binding_info,
countof(s_binding_info),
s_settings,
countof(s_settings),
Controller::VibrationCapabilities::NoVibration};
void DigitalController::LoadSettings(SettingsInterface& si, const char* section)
{ {
Controller::LoadSettings(section); Controller::LoadSettings(si, section);
m_popn_controller_mode = g_host_interface->GetBoolSettingValue(section, "ForcePopnControllerMode", false); m_popn_controller_mode = si.GetBoolValue(section, "ForcePopnControllerMode", false);
} }
u8 DigitalController::GetButtonsLSBMask() const u8 DigitalController::GetButtonsLSBMask() const

View file

@ -28,34 +28,26 @@ public:
Count Count
}; };
DigitalController(); static const Controller::ControllerInfo INFO;
DigitalController(u32 index);
~DigitalController() override; ~DigitalController() override;
static std::unique_ptr<DigitalController> Create(); static std::unique_ptr<DigitalController> Create(u32 index);
static std::optional<s32> StaticGetAxisCodeByName(std::string_view button_name);
static std::optional<s32> StaticGetButtonCodeByName(std::string_view button_name);
static AxisList StaticGetAxisNames();
static ButtonList StaticGetButtonNames();
static u32 StaticGetVibrationMotorCount();
static SettingList StaticGetSettings();
ControllerType GetType() const override; ControllerType GetType() const override;
std::optional<s32> GetAxisCodeByName(std::string_view axis_name) const override;
std::optional<s32> GetButtonCodeByName(std::string_view button_name) const override;
void Reset() override; void Reset() override;
bool DoState(StateWrapper& sw, bool apply_input_state) override; bool DoState(StateWrapper& sw, bool apply_input_state) override;
bool GetButtonState(s32 button_code) const override; float GetBindState(u32 index) const override;
void SetButtonState(s32 button_code, bool pressed) override; void SetBindState(u32 index, float value) override;
u32 GetButtonStateBits() const override; u32 GetButtonStateBits() const override;
void ResetTransferState() override; void ResetTransferState() override;
bool Transfer(const u8 data_in, u8* data_out) override; bool Transfer(const u8 data_in, u8* data_out) override;
void SetButtonState(Button button, bool pressed); void LoadSettings(SettingsInterface& si, const char* section) override;
void LoadSettings(const char* section) override;
private: private:
enum class TransferState : u8 enum class TransferState : u8

View file

@ -6,6 +6,7 @@
#include "cpu_code_cache.h" #include "cpu_code_cache.h"
#include "cpu_core.h" #include "cpu_core.h"
#include "gpu.h" #include "gpu.h"
#include "host.h"
#include "imgui.h" #include "imgui.h"
#include "interrupt_controller.h" #include "interrupt_controller.h"
#include "mdec.h" #include "mdec.h"
@ -626,7 +627,7 @@ void DMA::DrawDebugStateWindow()
{"MDECin", "MDECout", "GPU", "CDROM", "SPU", "PIO", "OTC"}}; {"MDECin", "MDECout", "GPU", "CDROM", "SPU", "PIO", "OTC"}};
static constexpr std::array<const char*, 4> sync_mode_names = {{"Manual", "Request", "LinkedList", "Reserved"}}; static constexpr std::array<const char*, 4> sync_mode_names = {{"Manual", "Request", "LinkedList", "Reserved"}};
const float framebuffer_scale = ImGui::GetIO().DisplayFramebufferScale.x; const float framebuffer_scale = Host::GetOSDScale();
ImGui::SetNextWindowSize(ImVec2(850.0f * framebuffer_scale, 250.0f * framebuffer_scale), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(850.0f * framebuffer_scale, 250.0f * framebuffer_scale), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("DMA State", nullptr)) if (!ImGui::Begin("DMA State", nullptr))

1137
src/core/game_database.cpp Normal file

File diff suppressed because it is too large Load diff

122
src/core/game_database.h Normal file
View file

@ -0,0 +1,122 @@
#pragma once
#include "core/types.h"
#include "util/cd_image_hasher.h"
#include <bitset>
#include <map>
#include <string>
#include <string_view>
#include <vector>
class CDImage;
struct Settings;
namespace GameDatabase {
enum class CompatibilityRating : u32
{
Unknown = 0,
DoesntBoot = 1,
CrashesInIntro = 2,
CrashesInGame = 3,
GraphicalAudioIssues = 4,
NoIssues = 5,
Count,
};
enum class Trait : u32
{
ForceInterpreter,
ForceSoftwareRenderer,
ForceSoftwareRendererForReadbacks,
ForceInterlacing,
DisableTrueColor,
DisableUpscaling,
DisableScaledDithering,
DisableForceNTSCTimings,
DisableWidescreen,
DisablePGXP,
DisablePGXPCulling,
DisablePGXPTextureCorrection,
DisablePGXPDepthBuffer,
ForcePGXPVertexCache,
ForcePGXPCPUMode,
ForceRecompilerMemoryExceptions,
ForceRecompilerICache,
ForceRecompilerLUTFastmem,
Count
};
struct Entry
{
// TODO: Make string_view.
std::string serial;
std::string title;
std::string genre;
std::string developer;
std::string publisher;
u64 release_date;
u8 min_players;
u8 max_players;
u8 min_blocks;
u8 max_blocks;
u32 supported_controllers;
CompatibilityRating compatibility;
std::bitset<static_cast<int>(Trait::Count)> traits{};
std::optional<s16> display_active_start_offset;
std::optional<s16> display_active_end_offset;
std::optional<s8> display_line_start_offset;
std::optional<s8> display_line_end_offset;
std::optional<u32> dma_max_slice_ticks;
std::optional<u32> dma_halt_ticks;
std::optional<u32> gpu_fifo_size;
std::optional<u32> gpu_max_run_ahead;
std::optional<float> gpu_pgxp_tolerance;
std::optional<float> gpu_pgxp_depth_threshold;
ALWAYS_INLINE bool HasTrait(Trait trait) const { return traits[static_cast<int>(trait)]; }
void ApplySettings(Settings& settings, bool display_osd_messages) const;
};
void EnsureLoaded();
void Unload();
const Entry* GetEntryForDisc(CDImage* image);
const Entry* GetEntryForSerial(const std::string_view& serial);
const Entry* GetEntryForCode(const std::string_view& code);
std::string GetSerialForDisc(CDImage* image);
std::string GetSerialForPath(const char* path);
const char* GetTraitName(Trait trait);
const char* GetTraitDisplayName(Trait trait);
const char* GetCompatibilityRatingName(CompatibilityRating rating);
const char* GetCompatibilityRatingDisplayName(CompatibilityRating rating);
/// Map of track hashes for image verification
struct TrackData
{
TrackData(std::vector<std::string> codes, std::string revisionString, uint32_t revision)
: codes(std::move(codes)), revisionString(revisionString), revision(revision)
{
}
friend bool operator==(const TrackData& left, const TrackData& right)
{
// 'revisionString' is deliberately ignored in comparisons as it's redundant with comparing 'revision'! Do not
// change!
return left.codes == right.codes && left.revision == right.revision;
}
std::vector<std::string> codes;
std::string revisionString;
uint32_t revision;
};
using TrackHashesMap = std::multimap<CDImageHasher::Hash, TrackData>;
const TrackHashesMap& GetTrackHashesMap();
void EnsureTrackHashesMapLoaded();
} // namespace GameDatabase

View file

@ -4,7 +4,7 @@
#include "common/log.h" #include "common/log.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "cpu_core.h" #include "cpu_core.h"
#include "frontend-common/common_host_interface.h" #include "frontend-common/common_host.h"
#include "system.h" #include "system.h"
#include <functional> #include <functional>
#include <iomanip> #include <iomanip>

View file

@ -4,8 +4,8 @@
#include "common/log.h" #include "common/log.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "dma.h" #include "dma.h"
#include "host.h"
#include "host_display.h" #include "host_display.h"
#include "host_interface.h"
#include "imgui.h" #include "imgui.h"
#include "interrupt_controller.h" #include "interrupt_controller.h"
#include "settings.h" #include "settings.h"
@ -24,9 +24,8 @@ GPU::GPU() = default;
GPU::~GPU() = default; GPU::~GPU() = default;
bool GPU::Initialize(HostDisplay* host_display) bool GPU::Initialize()
{ {
m_host_display = host_display;
m_force_progressive_scan = g_settings.gpu_disable_interlacing; m_force_progressive_scan = g_settings.gpu_disable_interlacing;
m_force_ntsc_timings = g_settings.gpu_force_ntsc_timings; m_force_ntsc_timings = g_settings.gpu_force_ntsc_timings;
m_crtc_tick_event = TimingEvents::CreateTimingEvent( m_crtc_tick_event = TimingEvents::CreateTimingEvent(
@ -41,6 +40,16 @@ bool GPU::Initialize(HostDisplay* host_display)
m_max_run_ahead = g_settings.gpu_max_run_ahead; m_max_run_ahead = g_settings.gpu_max_run_ahead;
m_console_is_pal = System::IsPALRegion(); m_console_is_pal = System::IsPALRegion();
UpdateCRTCConfig(); UpdateCRTCConfig();
g_host_display->SetDisplayLinearFiltering(g_settings.display_linear_filtering);
g_host_display->SetDisplayIntegerScaling(g_settings.display_integer_scaling);
g_host_display->SetDisplayStretch(g_settings.display_stretch);
if (g_settings.display_post_processing &&
!g_host_display->SetPostProcessingChain(g_settings.display_post_process_chain))
{
Host::AddOSDMessage(Host::TranslateStdString("OSDMessage", "Failed to load post processing shader chain."), 20.0f);
}
return true; return true;
} }
@ -59,6 +68,10 @@ void GPU::UpdateSettings()
// Crop mode calls this, so recalculate the display area // Crop mode calls this, so recalculate the display area
UpdateCRTCDisplayParameters(); UpdateCRTCDisplayParameters();
g_host_display->SetDisplayLinearFiltering(g_settings.display_linear_filtering);
g_host_display->SetDisplayIntegerScaling(g_settings.display_integer_scaling);
g_host_display->SetDisplayStretch(g_settings.display_stretch);
} }
bool GPU::IsHardwareRenderer() bool GPU::IsHardwareRenderer()
@ -962,9 +975,9 @@ void GPU::UpdateCommandTickEvent()
bool GPU::ConvertScreenCoordinatesToBeamTicksAndLines(s32 window_x, s32 window_y, float x_scale, u32* out_tick, bool GPU::ConvertScreenCoordinatesToBeamTicksAndLines(s32 window_x, s32 window_y, float x_scale, u32* out_tick,
u32* out_line) const u32* out_line) const
{ {
auto [display_x, display_y] = m_host_display->ConvertWindowCoordinatesToDisplayCoordinates( auto [display_x, display_y] = g_host_display->ConvertWindowCoordinatesToDisplayCoordinates(
window_x, window_y, m_host_display->GetWindowWidth(), m_host_display->GetWindowHeight(), window_x, window_y, g_host_display->GetWindowWidth(), g_host_display->GetWindowHeight(),
m_host_display->GetDisplayTopMargin()); g_host_display->GetDisplayTopMargin());
if (x_scale != 1.0f) if (x_scale != 1.0f)
{ {
@ -1551,7 +1564,7 @@ bool GPU::DumpVRAMToFile(const char* filename, u32 width, u32 height, u32 stride
void GPU::DrawDebugStateWindow() void GPU::DrawDebugStateWindow()
{ {
const float framebuffer_scale = ImGui::GetIO().DisplayFramebufferScale.x; const float framebuffer_scale = Host::GetOSDScale();
ImGui::SetNextWindowSize(ImVec2(450.0f * framebuffer_scale, 550.0f * framebuffer_scale), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(450.0f * framebuffer_scale, 550.0f * framebuffer_scale), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("GPU", nullptr)) if (!ImGui::Begin("GPU", nullptr))

View file

@ -75,7 +75,7 @@ public:
virtual GPURenderer GetRendererType() const = 0; virtual GPURenderer GetRendererType() const = 0;
virtual bool Initialize(HostDisplay* host_display); virtual bool Initialize();
virtual void Reset(bool clear_vram); virtual void Reset(bool clear_vram);
virtual bool DoState(StateWrapper& sw, HostDisplayTexture** save_to_texture, bool update_display); virtual bool DoState(StateWrapper& sw, HostDisplayTexture** save_to_texture, bool update_display);
@ -319,8 +319,6 @@ protected:
AddCommandTicks(std::max(width, height)); AddCommandTicks(std::max(width, height));
} }
HostDisplay* m_host_display = nullptr;
std::unique_ptr<TimingEvent> m_crtc_tick_event; std::unique_ptr<TimingEvent> m_crtc_tick_event;
std::unique_ptr<TimingEvent> m_command_tick_event; std::unique_ptr<TimingEvent> m_command_tick_event;

View file

@ -173,7 +173,7 @@ void GPUBackend::StartGPUThread()
{ {
m_gpu_loop_done.store(false); m_gpu_loop_done.store(false);
m_use_gpu_thread = true; m_use_gpu_thread = true;
m_gpu_thread = std::thread(&GPUBackend::RunGPULoop, this); m_gpu_thread.Start([this]() { RunGPULoop(); });
Log_InfoPrint("GPU thread started."); Log_InfoPrint("GPU thread started.");
} }
@ -184,7 +184,7 @@ void GPUBackend::StopGPUThread()
m_gpu_loop_done.store(true); m_gpu_loop_done.store(true);
WakeGPUThread(); WakeGPUThread();
m_gpu_thread.join(); m_gpu_thread.Join();
m_use_gpu_thread = false; m_use_gpu_thread = false;
Log_InfoPrint("GPU thread stopped."); Log_InfoPrint("GPU thread stopped.");
} }

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "common/event.h" #include "common/event.h"
#include "common/heap_array.h" #include "common/heap_array.h"
#include "common/threading.h"
#include "gpu_types.h" #include "gpu_types.h"
#include <atomic> #include <atomic>
#include <condition_variable> #include <condition_variable>
@ -20,6 +21,7 @@ public:
virtual ~GPUBackend(); virtual ~GPUBackend();
ALWAYS_INLINE u16* GetVRAM() const { return m_vram_ptr; } ALWAYS_INLINE u16* GetVRAM() const { return m_vram_ptr; }
ALWAYS_INLINE const Threading::Thread* GetThread() const { return m_use_gpu_thread ? &m_gpu_thread : nullptr; }
virtual bool Initialize(bool force_thread); virtual bool Initialize(bool force_thread);
virtual void UpdateSettings(); virtual void UpdateSettings();
@ -67,7 +69,7 @@ protected:
Common::Event m_sync_event; Common::Event m_sync_event;
std::atomic_bool m_gpu_thread_sleeping{false}; std::atomic_bool m_gpu_thread_sleeping{false};
std::atomic_bool m_gpu_loop_done{false}; std::atomic_bool m_gpu_loop_done{false};
std::thread m_gpu_thread; Threading::Thread m_gpu_thread;
bool m_use_gpu_thread = false; bool m_use_gpu_thread = false;
std::mutex m_sync_mutex; std::mutex m_sync_mutex;

View file

@ -4,6 +4,7 @@
#include "common/log.h" #include "common/log.h"
#include "cpu_core.h" #include "cpu_core.h"
#include "gpu_sw_backend.h" #include "gpu_sw_backend.h"
#include "host.h"
#include "imgui.h" #include "imgui.h"
#include "pgxp.h" #include "pgxp.h"
#include "settings.h" #include "settings.h"
@ -43,14 +44,14 @@ GPU_HW::~GPU_HW()
} }
} }
bool GPU_HW::Initialize(HostDisplay* host_display) bool GPU_HW::Initialize()
{ {
if (!GPU::Initialize(host_display)) if (!GPU::Initialize())
return false; return false;
m_resolution_scale = CalculateResolutionScale(); m_resolution_scale = CalculateResolutionScale();
m_multisamples = std::min(g_settings.gpu_multisamples, m_max_multisamples); m_multisamples = std::min(g_settings.gpu_multisamples, m_max_multisamples);
m_render_api = host_display->GetRenderAPI(); m_render_api = g_host_display->GetRenderAPI();
m_per_sample_shading = g_settings.gpu_per_sample_shading && m_supports_per_sample_shading; m_per_sample_shading = g_settings.gpu_per_sample_shading && m_supports_per_sample_shading;
m_true_color = g_settings.gpu_true_color; m_true_color = g_settings.gpu_true_color;
m_scaled_dithering = g_settings.gpu_scaled_dithering; m_scaled_dithering = g_settings.gpu_scaled_dithering;
@ -61,29 +62,26 @@ bool GPU_HW::Initialize(HostDisplay* host_display)
if (m_multisamples != g_settings.gpu_multisamples) if (m_multisamples != g_settings.gpu_multisamples)
{ {
g_host_interface->AddFormattedOSDMessage( Host::AddFormattedOSDMessage(20.0f,
20.0f, g_host_interface->TranslateString("OSDMessage", "%ux MSAA is not supported, using %ux instead."), Host::TranslateString("OSDMessage", "%ux MSAA is not supported, using %ux instead."),
g_settings.gpu_multisamples, m_multisamples); g_settings.gpu_multisamples, m_multisamples);
} }
if (!m_per_sample_shading && g_settings.gpu_per_sample_shading) if (!m_per_sample_shading && g_settings.gpu_per_sample_shading)
{ {
g_host_interface->AddOSDMessage( Host::AddOSDMessage(Host::TranslateStdString("OSDMessage", "SSAA is not supported, using MSAA instead."), 20.0f);
g_host_interface->TranslateStdString("OSDMessage", "SSAA is not supported, using MSAA instead."), 20.0f);
} }
if (!m_supports_dual_source_blend && TextureFilterRequiresDualSourceBlend(m_texture_filtering)) if (!m_supports_dual_source_blend && TextureFilterRequiresDualSourceBlend(m_texture_filtering))
{ {
g_host_interface->AddFormattedOSDMessage( Host::AddFormattedOSDMessage(
20.0f, 20.0f, Host::TranslateString("OSDMessage", "Texture filter '%s' is not supported with the current renderer."),
g_host_interface->TranslateString("OSDMessage",
"Texture filter '%s' is not supported with the current renderer."),
Settings::GetTextureFilterDisplayName(m_texture_filtering)); Settings::GetTextureFilterDisplayName(m_texture_filtering));
m_texture_filtering = GPUTextureFilter::Nearest; m_texture_filtering = GPUTextureFilter::Nearest;
} }
if (!m_supports_adaptive_downsampling && g_settings.gpu_resolution_scale > 1 && if (!m_supports_adaptive_downsampling && g_settings.gpu_resolution_scale > 1 &&
g_settings.gpu_downsample_mode == GPUDownsampleMode::Adaptive) g_settings.gpu_downsample_mode == GPUDownsampleMode::Adaptive)
{ {
g_host_interface->AddOSDMessage( Host::AddOSDMessage(
g_host_interface->TranslateStdString( Host::TranslateStdString(
"OSDMessage", "Adaptive downsampling is not supported with the current renderer, using box filter instead."), "OSDMessage", "Adaptive downsampling is not supported with the current renderer, using box filter instead."),
20.0f); 20.0f);
} }
@ -149,27 +147,26 @@ void GPU_HW::UpdateHWSettings(bool* framebuffer_changed, bool* shaders_changed)
if (m_resolution_scale != resolution_scale) if (m_resolution_scale != resolution_scale)
{ {
g_host_interface->AddKeyedFormattedOSDMessage( Host::AddKeyedFormattedOSDMessage(
"ResolutionScale", 10.0f, "ResolutionScale", 10.0f,
g_host_interface->TranslateString("OSDMessage", "Resolution scale set to %ux (display %ux%u, VRAM %ux%u)"), Host::TranslateString("OSDMessage", "Resolution scale set to %ux (display %ux%u, VRAM %ux%u)"), resolution_scale,
resolution_scale, m_crtc_state.display_vram_width * resolution_scale, m_crtc_state.display_vram_width * resolution_scale, resolution_scale * m_crtc_state.display_vram_height,
resolution_scale * m_crtc_state.display_vram_height, VRAM_WIDTH * resolution_scale, VRAM_WIDTH * resolution_scale, VRAM_HEIGHT * resolution_scale);
VRAM_HEIGHT * resolution_scale);
} }
if (m_multisamples != multisamples || m_per_sample_shading != per_sample_shading) if (m_multisamples != multisamples || m_per_sample_shading != per_sample_shading)
{ {
if (per_sample_shading) if (per_sample_shading)
{ {
g_host_interface->AddKeyedFormattedOSDMessage( Host::AddKeyedFormattedOSDMessage(
"Multisampling", 10.0f, "Multisampling", 10.0f, Host::TranslateString("OSDMessage", "Multisample anti-aliasing set to %ux (SSAA)."),
g_host_interface->TranslateString("OSDMessage", "Multisample anti-aliasing set to %ux (SSAA)."), multisamples); multisamples);
} }
else else
{ {
g_host_interface->AddKeyedFormattedOSDMessage( Host::AddKeyedFormattedOSDMessage("Multisampling", 10.0f,
"Multisampling", 10.0f, Host::TranslateString("OSDMessage", "Multisample anti-aliasing set to %ux."),
g_host_interface->TranslateString("OSDMessage", "Multisample anti-aliasing set to %ux."), multisamples); multisamples);
} }
} }
@ -215,7 +212,7 @@ u32 GPU_HW::CalculateResolutionScale() const
(m_console_is_pal ? (PAL_VERTICAL_ACTIVE_END - PAL_VERTICAL_ACTIVE_START) : (m_console_is_pal ? (PAL_VERTICAL_ACTIVE_END - PAL_VERTICAL_ACTIVE_START) :
(NTSC_VERTICAL_ACTIVE_END - NTSC_VERTICAL_ACTIVE_START)); (NTSC_VERTICAL_ACTIVE_END - NTSC_VERTICAL_ACTIVE_START));
const s32 preferred_scale = const s32 preferred_scale =
static_cast<s32>(std::ceil(static_cast<float>(m_host_display->GetWindowHeight()) / height)); static_cast<s32>(std::ceil(static_cast<float>(g_host_display->GetWindowHeight()) / height));
Log_InfoPrintf("Height = %d, preferred scale = %d", height, preferred_scale); Log_InfoPrintf("Height = %d, preferred scale = %d", height, preferred_scale);
scale = static_cast<u32>(std::clamp<s32>(preferred_scale, 1, m_max_resolution_scale)); scale = static_cast<u32>(std::clamp<s32>(preferred_scale, 1, m_max_resolution_scale));
@ -229,10 +226,9 @@ u32 GPU_HW::CalculateResolutionScale() const
if (g_settings.gpu_resolution_scale != 0) if (g_settings.gpu_resolution_scale != 0)
{ {
g_host_interface->AddFormattedOSDMessage( Host::AddFormattedOSDMessage(
10.0f, 10.0f,
g_host_interface->TranslateString("OSDMessage", Host::TranslateString("OSDMessage", "Resolution scale %ux not supported for adaptive smoothing, using %ux."),
"Resolution scale %ux not supported for adaptive smoothing, using %ux."),
scale, new_scale); scale, new_scale);
} }
@ -1410,7 +1406,7 @@ void GPU_HW::DrawRendererStats(bool is_idle_frame)
const auto& stats = m_last_renderer_stats; const auto& stats = m_last_renderer_stats;
ImGui::Columns(2); ImGui::Columns(2);
ImGui::SetColumnWidth(0, 200.0f * ImGui::GetIO().DisplayFramebufferScale.x); ImGui::SetColumnWidth(0, 200.0f * Host::GetOSDScale());
ImGui::TextUnformatted("Resolution Scale:"); ImGui::TextUnformatted("Resolution Scale:");
ImGui::NextColumn(); ImGui::NextColumn();
@ -1487,7 +1483,7 @@ void GPU_HW::ShaderCompileProgressTracker::Increment()
const u64 tv = Common::Timer::GetCurrentValue(); const u64 tv = Common::Timer::GetCurrentValue();
if ((tv - m_start_time) >= m_min_time && (tv - m_last_update_time) >= m_update_interval) if ((tv - m_start_time) >= m_min_time && (tv - m_last_update_time) >= m_update_interval)
{ {
g_host_interface->DisplayLoadingScreen(m_title.c_str(), 0, static_cast<int>(m_total), static_cast<int>(m_progress)); Host::DisplayLoadingScreen(m_title.c_str(), 0, static_cast<int>(m_total), static_cast<int>(m_progress));
m_last_update_time = tv; m_last_update_time = tv;
} }
} }

View file

@ -33,7 +33,7 @@ public:
GPU_HW(); GPU_HW();
virtual ~GPU_HW(); virtual ~GPU_HW();
virtual bool Initialize(HostDisplay* host_display) override; virtual bool Initialize() override;
virtual void Reset(bool clear_vram) override; virtual void Reset(bool clear_vram) override;
virtual bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override; virtual bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override;

View file

@ -6,7 +6,6 @@
#include "gpu_hw_shadergen.h" #include "gpu_hw_shadergen.h"
#include "gpu_sw_backend.h" #include "gpu_sw_backend.h"
#include "host_display.h" #include "host_display.h"
#include "host_interface.h"
#include "shader_cache_version.h" #include "shader_cache_version.h"
#include "system.h" #include "system.h"
#include "util/state_wrapper.h" #include "util/state_wrapper.h"
@ -16,8 +15,11 @@ GPU_HW_D3D11::GPU_HW_D3D11() = default;
GPU_HW_D3D11::~GPU_HW_D3D11() GPU_HW_D3D11::~GPU_HW_D3D11()
{ {
if (m_host_display) if (g_host_display)
m_host_display->ClearDisplayTexture(); {
g_host_display->ClearDisplayTexture();
ResetGraphicsAPIState();
}
if (m_context) if (m_context)
m_context->ClearState(); m_context->ClearState();
@ -31,22 +33,22 @@ GPURenderer GPU_HW_D3D11::GetRendererType() const
return GPURenderer::HardwareD3D11; return GPURenderer::HardwareD3D11;
} }
bool GPU_HW_D3D11::Initialize(HostDisplay* host_display) bool GPU_HW_D3D11::Initialize()
{ {
if (host_display->GetRenderAPI() != HostDisplay::RenderAPI::D3D11) if (!Host::AcquireHostDisplay(HostDisplay::RenderAPI::D3D11))
{ {
Log_ErrorPrintf("Host render API is incompatible"); Log_ErrorPrintf("Host render API is incompatible");
return false; return false;
} }
m_device = static_cast<ID3D11Device*>(host_display->GetRenderDevice()); m_device = static_cast<ID3D11Device*>(g_host_display->GetRenderDevice());
m_context = static_cast<ID3D11DeviceContext*>(host_display->GetRenderContext()); m_context = static_cast<ID3D11DeviceContext*>(g_host_display->GetRenderContext());
if (!m_device || !m_context) if (!m_device || !m_context)
return false; return false;
SetCapabilities(); SetCapabilities();
if (!GPU_HW::Initialize(host_display)) if (!GPU_HW::Initialize())
return false; return false;
if (!CreateFramebuffer()) if (!CreateFramebuffer())
@ -122,7 +124,7 @@ bool GPU_HW_D3D11::DoState(StateWrapper& sw, HostDisplayTexture** host_texture,
{ {
delete tex; delete tex;
tex = m_host_display tex = g_host_display
->CreateTexture(m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 1, 1, ->CreateTexture(m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 1, 1,
m_vram_texture.GetSamples(), HostDisplayPixelFormat::RGBA8, nullptr, 0, false) m_vram_texture.GetSamples(), HostDisplayPixelFormat::RGBA8, nullptr, 0, false)
.release(); .release();
@ -178,7 +180,7 @@ void GPU_HW_D3D11::UpdateSettings()
RestoreGraphicsAPIState(); RestoreGraphicsAPIState();
ReadVRAM(0, 0, VRAM_WIDTH, VRAM_HEIGHT); ReadVRAM(0, 0, VRAM_WIDTH, VRAM_HEIGHT);
ResetGraphicsAPIState(); ResetGraphicsAPIState();
m_host_display->ClearDisplayTexture(); g_host_display->ClearDisplayTexture();
CreateFramebuffer(); CreateFramebuffer();
} }
@ -501,10 +503,10 @@ void GPU_HW_D3D11::DestroyStateObjects()
bool GPU_HW_D3D11::CompileShaders() bool GPU_HW_D3D11::CompileShaders()
{ {
D3D11::ShaderCache shader_cache; D3D11::ShaderCache shader_cache;
shader_cache.Open(g_host_interface->GetShaderCacheBasePath(), m_device->GetFeatureLevel(), SHADER_CACHE_VERSION, shader_cache.Open(EmuFolders::Cache, m_device->GetFeatureLevel(), SHADER_CACHE_VERSION,
g_settings.gpu_use_debug_device); g_settings.gpu_use_debug_device);
GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_multisamples, m_per_sample_shading, GPU_HW_ShaderGen shadergen(g_host_display->GetRenderAPI(), m_resolution_scale, m_multisamples, m_per_sample_shading,
m_true_color, m_scaled_dithering, m_texture_filtering, m_using_uv_limits, m_true_color, m_scaled_dithering, m_texture_filtering, m_using_uv_limits,
m_pgxp_depth_buffer, m_supports_dual_source_blend); m_pgxp_depth_buffer, m_supports_dual_source_blend);
@ -826,7 +828,7 @@ void GPU_HW_D3D11::ClearDisplay()
{ {
GPU_HW::ClearDisplay(); GPU_HW::ClearDisplay();
m_host_display->ClearDisplayTexture(); g_host_display->ClearDisplayTexture();
static constexpr std::array<float, 4> clear_color = {0.0f, 0.0f, 0.0f, 1.0f}; static constexpr std::array<float, 4> clear_color = {0.0f, 0.0f, 0.0f, 1.0f};
m_context->ClearRenderTargetView(m_display_texture.GetD3DRTV(), clear_color.data()); m_context->ClearRenderTargetView(m_display_texture.GetD3DRTV(), clear_color.data());
@ -841,23 +843,23 @@ void GPU_HW_D3D11::UpdateDisplay()
if (IsUsingMultisampling()) if (IsUsingMultisampling())
{ {
UpdateVRAMReadTexture(); UpdateVRAMReadTexture();
m_host_display->SetDisplayTexture(m_vram_read_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8, g_host_display->SetDisplayTexture(m_vram_read_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8,
m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight(), 0, 0, m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight(), 0, 0,
m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight()); m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight());
} }
else else
{ {
m_host_display->SetDisplayTexture(m_vram_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8, g_host_display->SetDisplayTexture(m_vram_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8,
m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 0, 0, m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 0, 0,
m_vram_texture.GetWidth(), m_vram_texture.GetHeight()); m_vram_texture.GetWidth(), m_vram_texture.GetHeight());
} }
m_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT, g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT,
static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT)); static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT));
} }
else else
{ {
m_host_display->SetDisplayParameters(m_crtc_state.display_width, m_crtc_state.display_height, g_host_display->SetDisplayParameters(m_crtc_state.display_width, m_crtc_state.display_height,
m_crtc_state.display_origin_left, m_crtc_state.display_origin_top, m_crtc_state.display_origin_left, m_crtc_state.display_origin_top,
m_crtc_state.display_vram_width, m_crtc_state.display_vram_height, m_crtc_state.display_vram_width, m_crtc_state.display_vram_height,
GetDisplayAspectRatio()); GetDisplayAspectRatio());
@ -875,7 +877,7 @@ void GPU_HW_D3D11::UpdateDisplay()
if (IsDisplayDisabled()) if (IsDisplayDisabled())
{ {
m_host_display->ClearDisplayTexture(); g_host_display->ClearDisplayTexture();
} }
else if (!m_GPUSTAT.display_area_color_depth_24 && interlaced == InterlacedRenderMode::None && else if (!m_GPUSTAT.display_area_color_depth_24 && interlaced == InterlacedRenderMode::None &&
!IsUsingMultisampling() && (scaled_vram_offset_x + scaled_display_width) <= m_vram_texture.GetWidth() && !IsUsingMultisampling() && (scaled_vram_offset_x + scaled_display_width) <= m_vram_texture.GetWidth() &&
@ -889,7 +891,7 @@ void GPU_HW_D3D11::UpdateDisplay()
} }
else else
{ {
m_host_display->SetDisplayTexture(m_vram_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8, g_host_display->SetDisplayTexture(m_vram_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8,
m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), scaled_vram_offset_x, m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), scaled_vram_offset_x,
scaled_vram_offset_y, scaled_display_width, scaled_display_height); scaled_vram_offset_y, scaled_display_width, scaled_display_height);
} }
@ -921,7 +923,7 @@ void GPU_HW_D3D11::UpdateDisplay()
} }
else else
{ {
m_host_display->SetDisplayTexture(m_display_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8, g_host_display->SetDisplayTexture(m_display_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8,
m_display_texture.GetWidth(), m_display_texture.GetHeight(), 0, 0, m_display_texture.GetWidth(), m_display_texture.GetHeight(), 0, 0,
scaled_display_width, scaled_display_height); scaled_display_width, scaled_display_height);
} }
@ -1202,7 +1204,7 @@ void GPU_HW_D3D11::DownsampleFramebufferAdaptive(D3D11::Texture& source, u32 lef
RestoreGraphicsAPIState(); RestoreGraphicsAPIState();
m_host_display->SetDisplayTexture(m_display_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8, g_host_display->SetDisplayTexture(m_display_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8,
m_display_texture.GetWidth(), m_display_texture.GetHeight(), left, top, width, m_display_texture.GetWidth(), m_display_texture.GetHeight(), left, top, width,
height); height);
} }
@ -1227,7 +1229,7 @@ void GPU_HW_D3D11::DownsampleFramebufferBoxFilter(D3D11::Texture& source, u32 le
RestoreGraphicsAPIState(); RestoreGraphicsAPIState();
m_host_display->SetDisplayTexture(m_downsample_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8, g_host_display->SetDisplayTexture(m_downsample_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8,
m_downsample_texture.GetWidth(), m_downsample_texture.GetHeight(), ds_left, ds_top, m_downsample_texture.GetWidth(), m_downsample_texture.GetHeight(), ds_left, ds_top,
ds_width, ds_height); ds_width, ds_height);
} }

View file

@ -22,7 +22,7 @@ public:
GPURenderer GetRendererType() const override; GPURenderer GetRendererType() const override;
bool Initialize(HostDisplay* host_display) override; bool Initialize() override;
void Reset(bool clear_vram) override; void Reset(bool clear_vram) override;
bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override; bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override;

View file

@ -11,7 +11,6 @@
#include "common/timer.h" #include "common/timer.h"
#include "gpu_hw_shadergen.h" #include "gpu_hw_shadergen.h"
#include "host_display.h" #include "host_display.h"
#include "host_interface.h"
#include "system.h" #include "system.h"
Log_SetChannel(GPU_HW_D3D12); Log_SetChannel(GPU_HW_D3D12);
@ -19,9 +18,9 @@ GPU_HW_D3D12::GPU_HW_D3D12() = default;
GPU_HW_D3D12::~GPU_HW_D3D12() GPU_HW_D3D12::~GPU_HW_D3D12()
{ {
if (m_host_display) if (g_host_display)
{ {
m_host_display->ClearDisplayTexture(); g_host_display->ClearDisplayTexture();
ResetGraphicsAPIState(); ResetGraphicsAPIState();
} }
@ -33,9 +32,9 @@ GPURenderer GPU_HW_D3D12::GetRendererType() const
return GPURenderer::HardwareD3D12; return GPURenderer::HardwareD3D12;
} }
bool GPU_HW_D3D12::Initialize(HostDisplay* host_display) bool GPU_HW_D3D12::Initialize()
{ {
if (host_display->GetRenderAPI() != HostDisplay::RenderAPI::D3D12) if (!Host::AcquireHostDisplay(HostDisplay::RenderAPI::D3D12))
{ {
Log_ErrorPrintf("Host render API is incompatible"); Log_ErrorPrintf("Host render API is incompatible");
return false; return false;
@ -43,7 +42,7 @@ bool GPU_HW_D3D12::Initialize(HostDisplay* host_display)
SetCapabilities(); SetCapabilities();
if (!GPU_HW::Initialize(host_display)) if (!GPU_HW::Initialize())
return false; return false;
if (!CreateRootSignatures()) if (!CreateRootSignatures())
@ -144,7 +143,7 @@ void GPU_HW_D3D12::UpdateSettings()
} }
// Everything should be finished executing before recreating resources. // Everything should be finished executing before recreating resources.
m_host_display->ClearDisplayTexture(); g_host_display->ClearDisplayTexture();
g_d3d12_context->ExecuteCommandList(true); g_d3d12_context->ExecuteCommandList(true);
if (framebuffer_changed) if (framebuffer_changed)
@ -413,10 +412,9 @@ bool GPU_HW_D3D12::CreateTextureBuffer()
bool GPU_HW_D3D12::CompilePipelines() bool GPU_HW_D3D12::CompilePipelines()
{ {
D3D12::ShaderCache shader_cache; D3D12::ShaderCache shader_cache;
shader_cache.Open(g_host_interface->GetShaderCacheBasePath(), g_d3d12_context->GetFeatureLevel(), shader_cache.Open(EmuFolders::Cache, g_d3d12_context->GetFeatureLevel(), g_settings.gpu_use_debug_device);
g_settings.gpu_use_debug_device);
GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_multisamples, m_per_sample_shading, GPU_HW_ShaderGen shadergen(g_host_display->GetRenderAPI(), m_resolution_scale, m_multisamples, m_per_sample_shading,
m_true_color, m_scaled_dithering, m_texture_filtering, m_using_uv_limits, m_true_color, m_scaled_dithering, m_texture_filtering, m_using_uv_limits,
m_pgxp_depth_buffer, m_supports_dual_source_blend); m_pgxp_depth_buffer, m_supports_dual_source_blend);
@ -852,7 +850,7 @@ void GPU_HW_D3D12::ClearDisplay()
{ {
GPU_HW::ClearDisplay(); GPU_HW::ClearDisplay();
m_host_display->ClearDisplayTexture(); g_host_display->ClearDisplayTexture();
static constexpr float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; static constexpr float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
m_display_texture.TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET); m_display_texture.TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
@ -869,23 +867,23 @@ void GPU_HW_D3D12::UpdateDisplay()
if (IsUsingMultisampling()) if (IsUsingMultisampling())
{ {
UpdateVRAMReadTexture(); UpdateVRAMReadTexture();
m_host_display->SetDisplayTexture(&m_vram_read_texture, HostDisplayPixelFormat::RGBA8, g_host_display->SetDisplayTexture(&m_vram_read_texture, HostDisplayPixelFormat::RGBA8,
m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight(), 0, 0, m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight(), 0, 0,
m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight()); m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight());
} }
else else
{ {
m_vram_texture.TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); m_vram_texture.TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
m_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(),
m_vram_texture.GetHeight(), 0, 0, m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 0, 0, m_vram_texture.GetWidth(),
m_vram_texture.GetHeight()); m_vram_texture.GetHeight());
} }
m_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT, g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT,
static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT)); static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT));
} }
else else
{ {
m_host_display->SetDisplayParameters(m_crtc_state.display_width, m_crtc_state.display_height, g_host_display->SetDisplayParameters(m_crtc_state.display_width, m_crtc_state.display_height,
m_crtc_state.display_origin_left, m_crtc_state.display_origin_top, m_crtc_state.display_origin_left, m_crtc_state.display_origin_top,
m_crtc_state.display_vram_width, m_crtc_state.display_vram_height, m_crtc_state.display_vram_width, m_crtc_state.display_vram_height,
GetDisplayAspectRatio()); GetDisplayAspectRatio());
@ -903,14 +901,14 @@ void GPU_HW_D3D12::UpdateDisplay()
if (IsDisplayDisabled()) if (IsDisplayDisabled())
{ {
m_host_display->ClearDisplayTexture(); g_host_display->ClearDisplayTexture();
} }
else if (!m_GPUSTAT.display_area_color_depth_24 && interlaced == InterlacedRenderMode::None && else if (!m_GPUSTAT.display_area_color_depth_24 && interlaced == InterlacedRenderMode::None &&
!IsUsingMultisampling() && (scaled_vram_offset_x + scaled_display_width) <= m_vram_texture.GetWidth() && !IsUsingMultisampling() && (scaled_vram_offset_x + scaled_display_width) <= m_vram_texture.GetWidth() &&
(scaled_vram_offset_y + scaled_display_height) <= m_vram_texture.GetHeight()) (scaled_vram_offset_y + scaled_display_height) <= m_vram_texture.GetHeight())
{ {
m_vram_texture.TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); m_vram_texture.TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
m_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(),
m_vram_texture.GetHeight(), scaled_vram_offset_x, scaled_vram_offset_y, m_vram_texture.GetHeight(), scaled_vram_offset_x, scaled_vram_offset_y,
scaled_display_width, scaled_display_height); scaled_display_width, scaled_display_height);
} }
@ -938,7 +936,7 @@ void GPU_HW_D3D12::UpdateDisplay()
m_display_texture.TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); m_display_texture.TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
m_vram_texture.TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET); m_vram_texture.TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
m_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8, m_display_texture.GetWidth(), g_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8, m_display_texture.GetWidth(),
m_display_texture.GetHeight(), 0, 0, scaled_display_width, m_display_texture.GetHeight(), 0, 0, scaled_display_width,
scaled_display_height); scaled_display_height);

View file

@ -20,7 +20,7 @@ public:
GPURenderer GetRendererType() const override; GPURenderer GetRendererType() const override;
bool Initialize(HostDisplay* host_display) override; bool Initialize() override;
void Reset(bool clear_vram) override; void Reset(bool clear_vram) override;
void ResetGraphicsAPIState() override; void ResetGraphicsAPIState() override;

View file

@ -3,6 +3,7 @@
#include "common/log.h" #include "common/log.h"
#include "common/timer.h" #include "common/timer.h"
#include "gpu_hw_shadergen.h" #include "gpu_hw_shadergen.h"
#include "host.h"
#include "host_display.h" #include "host_display.h"
#include "shader_cache_version.h" #include "shader_cache_version.h"
#include "system.h" #include "system.h"
@ -24,9 +25,9 @@ GPU_HW_OpenGL::~GPU_HW_OpenGL()
if (m_texture_buffer_r16ui_texture != 0) if (m_texture_buffer_r16ui_texture != 0)
glDeleteTextures(1, &m_texture_buffer_r16ui_texture); glDeleteTextures(1, &m_texture_buffer_r16ui_texture);
if (m_host_display) if (g_host_display)
{ {
m_host_display->ClearDisplayTexture(); g_host_display->ClearDisplayTexture();
ResetGraphicsAPIState(); ResetGraphicsAPIState();
} }
@ -40,31 +41,30 @@ GPURenderer GPU_HW_OpenGL::GetRendererType() const
return GPURenderer::HardwareOpenGL; return GPURenderer::HardwareOpenGL;
} }
bool GPU_HW_OpenGL::Initialize(HostDisplay* host_display) bool GPU_HW_OpenGL::Initialize()
{ {
if (host_display->GetRenderAPI() != HostDisplay::RenderAPI::OpenGL && if (!Host::AcquireHostDisplay(HostDisplay::RenderAPI::OpenGL))
host_display->GetRenderAPI() != HostDisplay::RenderAPI::OpenGLES)
{ {
Log_ErrorPrintf("Host render API type is incompatible"); Log_ErrorPrintf("Host render API type is incompatible");
return false; return false;
} }
const bool opengl_is_available = const bool opengl_is_available =
((host_display->GetRenderAPI() == HostDisplay::RenderAPI::OpenGL && ((g_host_display->GetRenderAPI() == HostDisplay::RenderAPI::OpenGL &&
(GLAD_GL_VERSION_3_0 || GLAD_GL_ARB_uniform_buffer_object)) || (GLAD_GL_VERSION_3_0 || GLAD_GL_ARB_uniform_buffer_object)) ||
(host_display->GetRenderAPI() == HostDisplay::RenderAPI::OpenGLES && GLAD_GL_ES_VERSION_3_0)); (g_host_display->GetRenderAPI() == HostDisplay::RenderAPI::OpenGLES && GLAD_GL_ES_VERSION_3_0));
if (!opengl_is_available) if (!opengl_is_available)
{ {
g_host_interface->AddOSDMessage( Host::AddOSDMessage(Host::TranslateStdString("OSDMessage",
g_host_interface->TranslateStdString("OSDMessage", "OpenGL renderer unavailable, your driver or hardware is not " "OpenGL renderer unavailable, your driver or hardware is not "
"recent enough. OpenGL 3.1 or OpenGL ES 3.0 is required."), "recent enough. OpenGL 3.1 or OpenGL ES 3.0 is required."),
20.0f); 20.0f);
return false; return false;
} }
SetCapabilities(host_display); SetCapabilities();
if (!GPU_HW::Initialize(host_display)) if (!GPU_HW::Initialize())
return false; return false;
if (!CreateFramebuffer()) if (!CreateFramebuffer())
@ -133,7 +133,7 @@ bool GPU_HW_OpenGL::DoState(StateWrapper& sw, HostDisplayTexture** host_texture,
{ {
delete tex; delete tex;
tex = m_host_display tex = g_host_display
->CreateTexture(m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 1, 1, ->CreateTexture(m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 1, 1,
m_vram_texture.GetSamples(), HostDisplayPixelFormat::RGBA8, nullptr, 0, false) m_vram_texture.GetSamples(), HostDisplayPixelFormat::RGBA8, nullptr, 0, false)
.release(); .release();
@ -252,7 +252,7 @@ void GPU_HW_OpenGL::UpdateSettings()
RestoreGraphicsAPIState(); RestoreGraphicsAPIState();
ReadVRAM(0, 0, VRAM_WIDTH, VRAM_HEIGHT); ReadVRAM(0, 0, VRAM_WIDTH, VRAM_HEIGHT);
ResetGraphicsAPIState(); ResetGraphicsAPIState();
m_host_display->ClearDisplayTexture(); g_host_display->ClearDisplayTexture();
CreateFramebuffer(); CreateFramebuffer();
} }
if (shaders_changed) if (shaders_changed)
@ -297,7 +297,7 @@ std::tuple<s32, s32> GPU_HW_OpenGL::ConvertToFramebufferCoordinates(s32 x, s32 y
return std::make_tuple(x, static_cast<s32>(static_cast<s32>(VRAM_HEIGHT) - y)); return std::make_tuple(x, static_cast<s32>(static_cast<s32>(VRAM_HEIGHT) - y));
} }
void GPU_HW_OpenGL::SetCapabilities(HostDisplay* host_display) void GPU_HW_OpenGL::SetCapabilities()
{ {
GLint max_texture_size = VRAM_WIDTH; GLint max_texture_size = VRAM_WIDTH;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
@ -510,10 +510,10 @@ bool GPU_HW_OpenGL::CreateTextureBuffer()
bool GPU_HW_OpenGL::CompilePrograms() bool GPU_HW_OpenGL::CompilePrograms()
{ {
GL::ShaderCache shader_cache; GL::ShaderCache shader_cache;
shader_cache.Open(IsGLES(), g_host_interface->GetShaderCacheBasePath(), SHADER_CACHE_VERSION); shader_cache.Open(IsGLES(), EmuFolders::Cache, SHADER_CACHE_VERSION);
const bool use_binding_layout = GPU_HW_ShaderGen::UseGLSLBindingLayout(); const bool use_binding_layout = GPU_HW_ShaderGen::UseGLSLBindingLayout();
GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_multisamples, m_per_sample_shading, GPU_HW_ShaderGen shadergen(g_host_display->GetRenderAPI(), m_resolution_scale, m_multisamples, m_per_sample_shading,
m_true_color, m_scaled_dithering, m_texture_filtering, m_using_uv_limits, m_true_color, m_scaled_dithering, m_texture_filtering, m_using_uv_limits,
m_pgxp_depth_buffer, m_supports_dual_source_blend); m_pgxp_depth_buffer, m_supports_dual_source_blend);
@ -844,7 +844,7 @@ void GPU_HW_OpenGL::ClearDisplay()
{ {
GPU_HW::ClearDisplay(); GPU_HW::ClearDisplay();
m_host_display->ClearDisplayTexture(); g_host_display->ClearDisplayTexture();
m_display_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER); m_display_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
@ -864,7 +864,7 @@ void GPU_HW_OpenGL::UpdateDisplay()
{ {
UpdateVRAMReadTexture(); UpdateVRAMReadTexture();
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_read_texture.GetGLId())), g_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_read_texture.GetGLId())),
HostDisplayPixelFormat::RGBA8, m_vram_read_texture.GetWidth(), HostDisplayPixelFormat::RGBA8, m_vram_read_texture.GetWidth(),
static_cast<s32>(m_vram_read_texture.GetHeight()), 0, static_cast<s32>(m_vram_read_texture.GetHeight()), 0,
m_vram_read_texture.GetHeight(), m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight(), m_vram_read_texture.GetWidth(),
@ -872,17 +872,17 @@ void GPU_HW_OpenGL::UpdateDisplay()
} }
else else
{ {
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_texture.GetGLId())), g_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_texture.GetGLId())),
HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(),
static_cast<s32>(m_vram_texture.GetHeight()), 0, m_vram_texture.GetHeight(), static_cast<s32>(m_vram_texture.GetHeight()), 0, m_vram_texture.GetHeight(),
m_vram_texture.GetWidth(), -static_cast<s32>(m_vram_texture.GetHeight())); m_vram_texture.GetWidth(), -static_cast<s32>(m_vram_texture.GetHeight()));
} }
m_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT, g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT,
static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT)); static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT));
} }
else else
{ {
m_host_display->SetDisplayParameters(m_crtc_state.display_width, m_crtc_state.display_height, g_host_display->SetDisplayParameters(m_crtc_state.display_width, m_crtc_state.display_height,
m_crtc_state.display_origin_left, m_crtc_state.display_origin_top, m_crtc_state.display_origin_left, m_crtc_state.display_origin_top,
m_crtc_state.display_vram_width, m_crtc_state.display_vram_height, m_crtc_state.display_vram_width, m_crtc_state.display_vram_height,
GetDisplayAspectRatio()); GetDisplayAspectRatio());
@ -900,7 +900,7 @@ void GPU_HW_OpenGL::UpdateDisplay()
if (IsDisplayDisabled()) if (IsDisplayDisabled())
{ {
m_host_display->ClearDisplayTexture(); g_host_display->ClearDisplayTexture();
} }
else if (!m_GPUSTAT.display_area_color_depth_24 && interlaced == GPU_HW::InterlacedRenderMode::None && else if (!m_GPUSTAT.display_area_color_depth_24 && interlaced == GPU_HW::InterlacedRenderMode::None &&
!IsUsingMultisampling() && (scaled_vram_offset_x + scaled_display_width) <= m_vram_texture.GetWidth() && !IsUsingMultisampling() && (scaled_vram_offset_x + scaled_display_width) <= m_vram_texture.GetWidth() &&
@ -913,7 +913,7 @@ void GPU_HW_OpenGL::UpdateDisplay()
} }
else else
{ {
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_texture.GetGLId())), g_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_texture.GetGLId())),
HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(),
m_vram_texture.GetHeight(), scaled_vram_offset_x, m_vram_texture.GetHeight(), scaled_vram_offset_x,
m_vram_texture.GetHeight() - scaled_vram_offset_y, scaled_display_width, m_vram_texture.GetHeight() - scaled_vram_offset_y, scaled_display_width,
@ -960,7 +960,7 @@ void GPU_HW_OpenGL::UpdateDisplay()
} }
else else
{ {
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_display_texture.GetGLId())), g_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_display_texture.GetGLId())),
HostDisplayPixelFormat::RGBA8, m_display_texture.GetWidth(), HostDisplayPixelFormat::RGBA8, m_display_texture.GetWidth(),
m_display_texture.GetHeight(), 0, scaled_display_height, scaled_display_width, m_display_texture.GetHeight(), 0, scaled_display_height, scaled_display_width,
-static_cast<s32>(scaled_display_height)); -static_cast<s32>(scaled_display_height));
@ -1353,7 +1353,7 @@ void GPU_HW_OpenGL::DownsampleFramebufferBoxFilter(GL::Texture& source, u32 left
RestoreGraphicsAPIState(); RestoreGraphicsAPIState();
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_downsample_texture.GetGLId())), g_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_downsample_texture.GetGLId())),
HostDisplayPixelFormat::RGBA8, m_downsample_texture.GetWidth(), HostDisplayPixelFormat::RGBA8, m_downsample_texture.GetWidth(),
m_downsample_texture.GetHeight(), ds_left, m_downsample_texture.GetHeight(), ds_left,
m_downsample_texture.GetHeight() - ds_top, ds_width, -static_cast<s32>(ds_height)); m_downsample_texture.GetHeight() - ds_top, ds_width, -static_cast<s32>(ds_height));

View file

@ -18,7 +18,7 @@ public:
GPURenderer GetRendererType() const override; GPURenderer GetRendererType() const override;
bool Initialize(HostDisplay* host_display) override; bool Initialize() override;
void Reset(bool clear_vram) override; void Reset(bool clear_vram) override;
bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override; bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override;
@ -57,7 +57,7 @@ private:
std::tuple<s32, s32> ConvertToFramebufferCoordinates(s32 x, s32 y); std::tuple<s32, s32> ConvertToFramebufferCoordinates(s32 x, s32 y);
void SetCapabilities(HostDisplay* host_display); void SetCapabilities();
bool CreateFramebuffer(); bool CreateFramebuffer();
void ClearFramebuffer(); void ClearFramebuffer();
void CopyFramebufferForState(GLenum target, GLuint src_texture, u32 src_fbo, u32 src_x, u32 src_y, GLuint dst_texture, void CopyFramebufferForState(GLenum target, GLuint src_texture, u32 src_fbo, u32 src_x, u32 src_y, GLuint dst_texture,

View file

@ -9,7 +9,6 @@
#include "common/vulkan/util.h" #include "common/vulkan/util.h"
#include "gpu_hw_shadergen.h" #include "gpu_hw_shadergen.h"
#include "host_display.h" #include "host_display.h"
#include "host_interface.h"
#include "system.h" #include "system.h"
#include "util/state_wrapper.h" #include "util/state_wrapper.h"
Log_SetChannel(GPU_HW_Vulkan); Log_SetChannel(GPU_HW_Vulkan);
@ -18,9 +17,9 @@ GPU_HW_Vulkan::GPU_HW_Vulkan() = default;
GPU_HW_Vulkan::~GPU_HW_Vulkan() GPU_HW_Vulkan::~GPU_HW_Vulkan()
{ {
if (m_host_display) if (g_host_display)
{ {
m_host_display->ClearDisplayTexture(); g_host_display->ClearDisplayTexture();
ResetGraphicsAPIState(); ResetGraphicsAPIState();
} }
@ -32,9 +31,9 @@ GPURenderer GPU_HW_Vulkan::GetRendererType() const
return GPURenderer::HardwareVulkan; return GPURenderer::HardwareVulkan;
} }
bool GPU_HW_Vulkan::Initialize(HostDisplay* host_display) bool GPU_HW_Vulkan::Initialize()
{ {
if (host_display->GetRenderAPI() != HostDisplay::RenderAPI::Vulkan) if (!Host::AcquireHostDisplay(HostDisplay::RenderAPI::Vulkan))
{ {
Log_ErrorPrintf("Host render API is incompatible"); Log_ErrorPrintf("Host render API is incompatible");
return false; return false;
@ -43,7 +42,7 @@ bool GPU_HW_Vulkan::Initialize(HostDisplay* host_display)
Assert(g_vulkan_shader_cache); Assert(g_vulkan_shader_cache);
SetCapabilities(); SetCapabilities();
if (!GPU_HW::Initialize(host_display)) if (!GPU_HW::Initialize())
return false; return false;
if (!CreatePipelineLayouts()) if (!CreatePipelineLayouts())
@ -144,7 +143,7 @@ bool GPU_HW_Vulkan::DoState(StateWrapper& sw, HostDisplayTexture** host_texture,
{ {
delete htex; delete htex;
htex = m_host_display htex = g_host_display
->CreateTexture(m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 1, 1, ->CreateTexture(m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 1, 1,
m_vram_texture.GetSamples(), HostDisplayPixelFormat::RGBA8, nullptr, 0, false) m_vram_texture.GetSamples(), HostDisplayPixelFormat::RGBA8, nullptr, 0, false)
.release(); .release();
@ -179,7 +178,7 @@ void GPU_HW_Vulkan::ResetGraphicsAPIState()
EndRenderPass(); EndRenderPass();
if (m_host_display->GetDisplayTextureHandle() == &m_vram_texture) if (g_host_display->GetDisplayTextureHandle() == &m_vram_texture)
{ {
m_vram_texture.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), m_vram_texture.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(),
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
@ -218,7 +217,7 @@ void GPU_HW_Vulkan::UpdateSettings()
} }
// Everything should be finished executing before recreating resources. // Everything should be finished executing before recreating resources.
m_host_display->ClearDisplayTexture(); g_host_display->ClearDisplayTexture();
g_vulkan_context->ExecuteCommandBuffer(true); g_vulkan_context->ExecuteCommandBuffer(true);
if (framebuffer_changed) if (framebuffer_changed)
@ -923,7 +922,7 @@ bool GPU_HW_Vulkan::CompilePipelines()
VkDevice device = g_vulkan_context->GetDevice(); VkDevice device = g_vulkan_context->GetDevice();
VkPipelineCache pipeline_cache = g_vulkan_shader_cache->GetPipelineCache(); VkPipelineCache pipeline_cache = g_vulkan_shader_cache->GetPipelineCache();
GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_multisamples, m_per_sample_shading, GPU_HW_ShaderGen shadergen(g_host_display->GetRenderAPI(), m_resolution_scale, m_multisamples, m_per_sample_shading,
m_true_color, m_scaled_dithering, m_texture_filtering, m_using_uv_limits, m_true_color, m_scaled_dithering, m_texture_filtering, m_using_uv_limits,
m_pgxp_depth_buffer, m_supports_dual_source_blend); m_pgxp_depth_buffer, m_supports_dual_source_blend);
@ -1405,7 +1404,7 @@ void GPU_HW_Vulkan::ClearDisplay()
GPU_HW::ClearDisplay(); GPU_HW::ClearDisplay();
EndRenderPass(); EndRenderPass();
m_host_display->ClearDisplayTexture(); g_host_display->ClearDisplayTexture();
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer(); VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
const Vulkan::Util::DebugScope debugScope(cmdbuf, "GPU_HW_Vulkan::ClearDisplay"); const Vulkan::Util::DebugScope debugScope(cmdbuf, "GPU_HW_Vulkan::ClearDisplay");
@ -1435,22 +1434,22 @@ void GPU_HW_Vulkan::UpdateDisplay()
UpdateVRAMReadTexture(); UpdateVRAMReadTexture();
} }
m_host_display->SetDisplayTexture(&m_vram_read_texture, HostDisplayPixelFormat::RGBA8, g_host_display->SetDisplayTexture(&m_vram_read_texture, HostDisplayPixelFormat::RGBA8,
m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight(), 0, 0, m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight(), 0, 0,
m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight()); m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight());
} }
else else
{ {
m_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(),
m_vram_texture.GetHeight(), 0, 0, m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 0, 0, m_vram_texture.GetWidth(),
m_vram_texture.GetHeight()); m_vram_texture.GetHeight());
} }
m_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT, g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT,
static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT)); static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT));
} }
else else
{ {
m_host_display->SetDisplayParameters(m_crtc_state.display_width, m_crtc_state.display_height, g_host_display->SetDisplayParameters(m_crtc_state.display_width, m_crtc_state.display_height,
m_crtc_state.display_origin_left, m_crtc_state.display_origin_top, m_crtc_state.display_origin_left, m_crtc_state.display_origin_top,
m_crtc_state.display_vram_width, m_crtc_state.display_vram_height, m_crtc_state.display_vram_width, m_crtc_state.display_vram_height,
GetDisplayAspectRatio()); GetDisplayAspectRatio());
@ -1468,7 +1467,7 @@ void GPU_HW_Vulkan::UpdateDisplay()
if (IsDisplayDisabled()) if (IsDisplayDisabled())
{ {
m_host_display->ClearDisplayTexture(); g_host_display->ClearDisplayTexture();
} }
else if (!m_GPUSTAT.display_area_color_depth_24 && interlaced == InterlacedRenderMode::None && else if (!m_GPUSTAT.display_area_color_depth_24 && interlaced == InterlacedRenderMode::None &&
!IsUsingMultisampling() && (scaled_vram_offset_x + scaled_display_width) <= m_vram_texture.GetWidth() && !IsUsingMultisampling() && (scaled_vram_offset_x + scaled_display_width) <= m_vram_texture.GetWidth() &&
@ -1481,7 +1480,7 @@ void GPU_HW_Vulkan::UpdateDisplay()
} }
else else
{ {
m_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(), g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(),
m_vram_texture.GetHeight(), scaled_vram_offset_x, scaled_vram_offset_y, m_vram_texture.GetHeight(), scaled_vram_offset_x, scaled_vram_offset_y,
scaled_display_width, scaled_display_height); scaled_display_width, scaled_display_height);
} }
@ -1528,7 +1527,7 @@ void GPU_HW_Vulkan::UpdateDisplay()
} }
else else
{ {
m_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8, g_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8,
m_display_texture.GetWidth(), m_display_texture.GetHeight(), 0, 0, m_display_texture.GetWidth(), m_display_texture.GetHeight(), 0, 0,
scaled_display_width, scaled_display_height); scaled_display_width, scaled_display_height);
RestoreGraphicsAPIState(); RestoreGraphicsAPIState();
@ -1938,7 +1937,7 @@ void GPU_HW_Vulkan::DownsampleFramebufferBoxFilter(Vulkan::Texture& source, u32
RestoreGraphicsAPIState(); RestoreGraphicsAPIState();
m_host_display->SetDisplayTexture(&m_downsample_texture, HostDisplayPixelFormat::RGBA8, g_host_display->SetDisplayTexture(&m_downsample_texture, HostDisplayPixelFormat::RGBA8,
m_downsample_texture.GetWidth(), m_downsample_texture.GetHeight(), ds_left, ds_top, m_downsample_texture.GetWidth(), m_downsample_texture.GetHeight(), ds_left, ds_top,
ds_width, ds_height); ds_width, ds_height);
} }
@ -2037,7 +2036,7 @@ void GPU_HW_Vulkan::DownsampleFramebufferAdaptive(Vulkan::Texture& source, u32 l
} }
RestoreGraphicsAPIState(); RestoreGraphicsAPIState();
m_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8, m_display_texture.GetWidth(), g_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8, m_display_texture.GetWidth(),
m_display_texture.GetHeight(), left, top, width, height); m_display_texture.GetHeight(), left, top, width, height);
} }

View file

@ -17,7 +17,7 @@ public:
GPURenderer GetRendererType() const override; GPURenderer GetRendererType() const override;
bool Initialize(HostDisplay* host_display) override; bool Initialize() override;
void Reset(bool clear_vram) override; void Reset(bool clear_vram) override;
bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override; bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override;

View file

@ -36,8 +36,8 @@ GPU_SW::GPU_SW()
GPU_SW::~GPU_SW() GPU_SW::~GPU_SW()
{ {
m_backend.Shutdown(); m_backend.Shutdown();
if (m_host_display) if (g_host_display)
m_host_display->ClearDisplayTexture(); g_host_display->ClearDisplayTexture();
} }
GPURenderer GPU_SW::GetRendererType() const GPURenderer GPU_SW::GetRendererType() const
@ -45,9 +45,13 @@ GPURenderer GPU_SW::GetRendererType() const
return GPURenderer::Software; return GPURenderer::Software;
} }
bool GPU_SW::Initialize(HostDisplay* host_display) bool GPU_SW::Initialize()
{ {
if (!GPU::Initialize(host_display) || !m_backend.Initialize(false)) // we need something to draw in.. but keep the current api if we have one
if (!g_host_display && !Host::AcquireHostDisplay(HostDisplay::GetPreferredAPI()))
return false;
if (!GPU::Initialize() || !m_backend.Initialize(false))
return false; return false;
static constexpr auto formats_for_16bit = make_array(HostDisplayPixelFormat::RGB565, HostDisplayPixelFormat::RGBA5551, static constexpr auto formats_for_16bit = make_array(HostDisplayPixelFormat::RGB565, HostDisplayPixelFormat::RGBA5551,
@ -57,7 +61,7 @@ bool GPU_SW::Initialize(HostDisplay* host_display)
HostDisplayPixelFormat::RGBA5551); HostDisplayPixelFormat::RGBA5551);
for (const HostDisplayPixelFormat format : formats_for_16bit) for (const HostDisplayPixelFormat format : formats_for_16bit)
{ {
if (m_host_display->SupportsDisplayPixelFormat(format)) if (g_host_display->SupportsDisplayPixelFormat(format))
{ {
m_16bit_display_format = format; m_16bit_display_format = format;
break; break;
@ -65,7 +69,7 @@ bool GPU_SW::Initialize(HostDisplay* host_display)
} }
for (const HostDisplayPixelFormat format : formats_for_24bit) for (const HostDisplayPixelFormat format : formats_for_24bit)
{ {
if (m_host_display->SupportsDisplayPixelFormat(format)) if (g_host_display->SupportsDisplayPixelFormat(format))
{ {
m_24bit_display_format = format; m_24bit_display_format = format;
break; break;
@ -233,7 +237,7 @@ void GPU_SW::CopyOut15Bit(u32 src_x, u32 src_y, u32 width, u32 height, u32 field
if (!interlaced) if (!interlaced)
{ {
if (!m_host_display->BeginSetDisplayPixels(display_format, width, height, reinterpret_cast<void**>(&dst_ptr), if (!g_host_display->BeginSetDisplayPixels(display_format, width, height, reinterpret_cast<void**>(&dst_ptr),
&dst_stride)) &dst_stride))
{ {
return; return;
@ -285,11 +289,11 @@ void GPU_SW::CopyOut15Bit(u32 src_x, u32 src_y, u32 width, u32 height, u32 field
if (!interlaced) if (!interlaced)
{ {
m_host_display->EndSetDisplayPixels(); g_host_display->EndSetDisplayPixels();
} }
else else
{ {
m_host_display->SetDisplayPixels(display_format, width, height, m_display_texture_buffer.data(), output_stride); g_host_display->SetDisplayPixels(display_format, width, height, m_display_texture_buffer.data(), output_stride);
} }
} }
@ -327,7 +331,7 @@ void GPU_SW::CopyOut24Bit(u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 heigh
if (!interlaced) if (!interlaced)
{ {
if (!m_host_display->BeginSetDisplayPixels(display_format, width, height, reinterpret_cast<void**>(&dst_ptr), if (!g_host_display->BeginSetDisplayPixels(display_format, width, height, reinterpret_cast<void**>(&dst_ptr),
&dst_stride)) &dst_stride))
{ {
return; return;
@ -443,11 +447,11 @@ void GPU_SW::CopyOut24Bit(u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 heigh
if (!interlaced) if (!interlaced)
{ {
m_host_display->EndSetDisplayPixels(); g_host_display->EndSetDisplayPixels();
} }
else else
{ {
m_host_display->SetDisplayPixels(display_format, width, height, m_display_texture_buffer.data(), output_stride); g_host_display->SetDisplayPixels(display_format, width, height, m_display_texture_buffer.data(), output_stride);
} }
} }
@ -486,14 +490,14 @@ void GPU_SW::UpdateDisplay()
if (!g_settings.debugging.show_vram) if (!g_settings.debugging.show_vram)
{ {
m_host_display->SetDisplayParameters(m_crtc_state.display_width, m_crtc_state.display_height, g_host_display->SetDisplayParameters(m_crtc_state.display_width, m_crtc_state.display_height,
m_crtc_state.display_origin_left, m_crtc_state.display_origin_top, m_crtc_state.display_origin_left, m_crtc_state.display_origin_top,
m_crtc_state.display_vram_width, m_crtc_state.display_vram_height, m_crtc_state.display_vram_width, m_crtc_state.display_vram_height,
GetDisplayAspectRatio()); GetDisplayAspectRatio());
if (IsDisplayDisabled()) if (IsDisplayDisabled())
{ {
m_host_display->ClearDisplayTexture(); g_host_display->ClearDisplayTexture();
return; return;
} }
@ -534,7 +538,7 @@ void GPU_SW::UpdateDisplay()
else else
{ {
CopyOut15Bit(m_16bit_display_format, 0, 0, VRAM_WIDTH, VRAM_HEIGHT, 0, false, false); CopyOut15Bit(m_16bit_display_format, 0, 0, VRAM_WIDTH, VRAM_HEIGHT, 0, false, false);
m_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT, g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT,
static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT)); static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT));
} }
} }

View file

@ -7,6 +7,11 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
namespace Threading
{
class Thread;
}
class HostDisplayTexture; class HostDisplayTexture;
class GPU_SW final : public GPU class GPU_SW final : public GPU
@ -15,9 +20,11 @@ public:
GPU_SW(); GPU_SW();
~GPU_SW() override; ~GPU_SW() override;
ALWAYS_INLINE const GPU_SW_Backend& GetBackend() const { return m_backend; }
GPURenderer GetRendererType() const override; GPURenderer GetRendererType() const override;
bool Initialize(HostDisplay* host_display) override; bool Initialize() override;
bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override; bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override;
void Reset(bool clear_vram) override; void Reset(bool clear_vram) override;
void UpdateSettings() override; void UpdateSettings() override;

View file

@ -5,7 +5,6 @@
#include "cpu_core.h" #include "cpu_core.h"
#include "cpu_core_private.h" #include "cpu_core_private.h"
#include "host_display.h" #include "host_display.h"
#include "host_interface.h"
#include "pgxp.h" #include "pgxp.h"
#include "settings.h" #include "settings.h"
#include "timing_event.h" #include "timing_event.h"
@ -188,15 +187,14 @@ void UpdateAspectRatio()
{ {
case DisplayAspectRatio::MatchWindow: case DisplayAspectRatio::MatchWindow:
{ {
const HostDisplay* display = g_host_interface->GetDisplay(); if (!g_host_display)
if (!display)
{ {
s_aspect_ratio = DisplayAspectRatio::R4_3; s_aspect_ratio = DisplayAspectRatio::R4_3;
return; return;
} }
num = display->GetWindowWidth(); num = g_host_display->GetWindowWidth();
denom = display->GetWindowHeight(); denom = g_host_display->GetWindowHeight();
} }
break; break;

273
src/core/guncon.cpp Normal file
View file

@ -0,0 +1,273 @@
#include "guncon.h"
#include "common/assert.h"
#include "common/log.h"
#include "gpu.h"
#include "host.h"
#include "host_display.h"
#include "resources.h"
#include "system.h"
#include "util/state_wrapper.h"
#include <array>
Log_SetChannel(GunCon);
static constexpr std::array<u8, static_cast<size_t>(GunCon::Button::Count)> s_button_indices = {{13, 3, 14}};
GunCon::GunCon(u32 index) : Controller(index) {}
GunCon::~GunCon() = default;
ControllerType GunCon::GetType() const
{
return ControllerType::GunCon;
}
void GunCon::Reset()
{
m_transfer_state = TransferState::Idle;
}
bool GunCon::DoState(StateWrapper& sw, bool apply_input_state)
{
if (!Controller::DoState(sw, apply_input_state))
return false;
u16 button_state = m_button_state;
u16 position_x = m_position_x;
u16 position_y = m_position_y;
sw.Do(&button_state);
sw.Do(&position_x);
sw.Do(&position_y);
if (apply_input_state)
{
m_button_state = button_state;
m_position_x = position_x;
m_position_y = position_y;
}
sw.Do(&m_transfer_state);
return true;
}
float GunCon::GetBindState(u32 index) const
{
if (index >= s_button_indices.size())
return 0.0f;
const u32 bit = s_button_indices[index];
return static_cast<float>(((m_button_state >> bit) & 1u) ^ 1u);
}
void GunCon::SetBindState(u32 index, float value)
{
const bool pressed = (value >= 0.5f);
if (index == static_cast<u32>(Button::ShootOffscreen))
{
if (m_shoot_offscreen != pressed)
{
m_shoot_offscreen = pressed;
SetBindState(static_cast<u32>(Button::Trigger), pressed);
}
return;
}
if (pressed)
m_button_state &= ~(u16(1) << s_button_indices[static_cast<u8>(index)]);
else
m_button_state |= u16(1) << s_button_indices[static_cast<u8>(index)];
}
void GunCon::ResetTransferState()
{
m_transfer_state = TransferState::Idle;
}
bool GunCon::Transfer(const u8 data_in, u8* data_out)
{
static constexpr u16 ID = 0x5A63;
switch (m_transfer_state)
{
case TransferState::Idle:
{
*data_out = 0xFF;
if (data_in == 0x01)
{
m_transfer_state = TransferState::Ready;
return true;
}
return false;
}
case TransferState::Ready:
{
if (data_in == 0x42)
{
*data_out = Truncate8(ID);
m_transfer_state = TransferState::IDMSB;
return true;
}
*data_out = 0xFF;
return false;
}
case TransferState::IDMSB:
{
*data_out = Truncate8(ID >> 8);
m_transfer_state = TransferState::ButtonsLSB;
return true;
}
case TransferState::ButtonsLSB:
{
*data_out = Truncate8(m_button_state);
m_transfer_state = TransferState::ButtonsMSB;
return true;
}
case TransferState::ButtonsMSB:
{
*data_out = Truncate8(m_button_state >> 8);
m_transfer_state = TransferState::XLSB;
return true;
}
case TransferState::XLSB:
{
UpdatePosition();
*data_out = Truncate8(m_position_x);
m_transfer_state = TransferState::XMSB;
return true;
}
case TransferState::XMSB:
{
*data_out = Truncate8(m_position_x >> 8);
m_transfer_state = TransferState::YLSB;
return true;
}
case TransferState::YLSB:
{
*data_out = Truncate8(m_position_y);
m_transfer_state = TransferState::YMSB;
return true;
}
case TransferState::YMSB:
{
*data_out = Truncate8(m_position_y >> 8);
m_transfer_state = TransferState::Idle;
return false;
}
default:
{
UnreachableCode();
return false;
}
}
}
void GunCon::UpdatePosition()
{
// get screen coordinates
const s32 mouse_x = g_host_display->GetMousePositionX();
const s32 mouse_y = g_host_display->GetMousePositionY();
// are we within the active display area?
u32 tick, line;
if (mouse_x < 0 || mouse_y < 0 ||
!g_gpu->ConvertScreenCoordinatesToBeamTicksAndLines(mouse_x, mouse_y, m_x_scale, &tick, &line) ||
m_shoot_offscreen)
{
Log_DebugPrintf("Lightgun out of range for window coordinates %d,%d", mouse_x, mouse_y);
m_position_x = 0x01;
m_position_y = 0x0A;
return;
}
// 8MHz units for X = 44100*768*11/7 = 53222400 / 8000000 = 6.6528
const double divider = static_cast<double>(g_gpu->GetCRTCFrequency()) / 8000000.0;
m_position_x = static_cast<u16>(static_cast<float>(tick) / static_cast<float>(divider));
m_position_y = static_cast<u16>(line);
Log_DebugPrintf("Lightgun window coordinates %d,%d -> tick %u line %u 8mhz ticks %u", mouse_x, mouse_y, tick, line,
m_position_x);
}
std::unique_ptr<GunCon> GunCon::Create(u32 index)
{
return std::make_unique<GunCon>(index);
}
static const Controller::ControllerBindingInfo s_binding_info[] = {
#define BUTTON(name, display_name, button, genb) \
{ \
name, display_name, static_cast<u32>(button), Controller::ControllerBindingType::Button, genb \
}
BUTTON("Trigger", "Trigger", GunCon::Button::Trigger, GenericInputBinding::R2),
BUTTON("ShootOffscreen", "ShootOffscreen", GunCon::Button::ShootOffscreen, GenericInputBinding::L2),
BUTTON("A", "A", GunCon::Button::A, GenericInputBinding::Cross),
BUTTON("B", "B", GunCon::Button::B, GenericInputBinding::Circle),
#undef BUTTON
};
static const SettingInfo s_settings[] = {
{SettingInfo::Type::Path, "CrosshairImagePath", TRANSLATABLE("NamcoGunCon", "Crosshair Image Path"),
TRANSLATABLE("NamcoGunCon", "Path to an image to use as a crosshair/cursor.")},
{SettingInfo::Type::Float, "CrosshairScale", TRANSLATABLE("NamcoGunCon", "Crosshair Image Scale"),
TRANSLATABLE("NamcoGunCon", "Scale of crosshair image on screen."), "1.0", "0.0001", "100.0", "0.10"},
{SettingInfo::Type::Float, "XScale", TRANSLATABLE("NamcoGunCon", "X Scale"),
TRANSLATABLE("NamcoGunCon", "Scales X coordinates relative to the center of the screen."), "1.0", "0.01", "2.0",
"0.01"}};
const Controller::ControllerInfo GunCon::INFO = {ControllerType::GunCon,
"GunCon",
TRANSLATABLE("ControllerType", "GunCon"),
s_binding_info,
countof(s_binding_info),
s_settings,
countof(s_settings),
Controller::VibrationCapabilities::NoVibration};
void GunCon::LoadSettings(SettingsInterface& si, const char* section)
{
Controller::LoadSettings(si, section);
std::string path = si.GetStringValue(section, "CrosshairImagePath");
if (path != m_crosshair_image_path)
{
m_crosshair_image_path = std::move(path);
if (m_crosshair_image_path.empty() || !m_crosshair_image.LoadFromFile(m_crosshair_image_path.c_str()))
{
m_crosshair_image.Invalidate();
}
}
#ifndef __ANDROID__
if (!m_crosshair_image.IsValid())
{
m_crosshair_image.SetPixels(Resources::CROSSHAIR_IMAGE_WIDTH, Resources::CROSSHAIR_IMAGE_HEIGHT,
Resources::CROSSHAIR_IMAGE_DATA.data());
}
#endif
m_crosshair_image_scale = si.GetFloatValue(section, "CrosshairScale", 1.0f);
m_x_scale = si.GetFloatValue(section, "XScale", 1.0f);
}
bool GunCon::GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale, bool* relative_mode)
{
if (!m_crosshair_image.IsValid())
return false;
*image = &m_crosshair_image;
*image_scale = m_crosshair_image_scale;
*relative_mode = false;
return true;
}

View file

@ -4,7 +4,7 @@
#include <optional> #include <optional>
#include <string_view> #include <string_view>
class NamcoGunCon final : public Controller class GunCon final : public Controller
{ {
public: public:
enum class Button : u8 enum class Button : u8
@ -16,34 +16,27 @@ public:
Count Count
}; };
NamcoGunCon(); static const Controller::ControllerInfo INFO;
~NamcoGunCon() override;
static std::unique_ptr<NamcoGunCon> Create(); GunCon(u32 index);
static std::optional<s32> StaticGetAxisCodeByName(std::string_view button_name); ~GunCon() override;
static std::optional<s32> StaticGetButtonCodeByName(std::string_view button_name);
static AxisList StaticGetAxisNames(); static std::unique_ptr<GunCon> Create(u32 index);
static ButtonList StaticGetButtonNames();
static u32 StaticGetVibrationMotorCount();
static SettingList StaticGetSettings();
ControllerType GetType() const override; ControllerType GetType() const override;
std::optional<s32> GetAxisCodeByName(std::string_view axis_name) const override;
std::optional<s32> GetButtonCodeByName(std::string_view button_name) const override;
void Reset() override; void Reset() override;
bool DoState(StateWrapper& sw, bool apply_input_state) override; bool DoState(StateWrapper& sw, bool apply_input_state) override;
void LoadSettings(const char* section) override;
void LoadSettings(SettingsInterface& si, const char* section) override;
bool GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale, bool* relative_mode) override; bool GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale, bool* relative_mode) override;
bool GetButtonState(s32 button_code) const override; float GetBindState(u32 index) const override;
void SetButtonState(s32 button_code, bool pressed) override; void SetBindState(u32 index, float value) override;
void ResetTransferState() override; void ResetTransferState() override;
bool Transfer(const u8 data_in, u8* data_out) override; bool Transfer(const u8 data_in, u8* data_out) override;
void SetButtonState(Button button, bool pressed);
private: private:
void UpdatePosition(); void UpdatePosition();

32
src/core/host.cpp Normal file
View file

@ -0,0 +1,32 @@
#include "host.h"
#include "common/string_util.h"
#include <cstdarg>
void Host::ReportFormattedErrorAsync(const std::string_view& title, const char* format, ...)
{
std::va_list ap;
va_start(ap, format);
std::string message(StringUtil::StdStringFromFormatV(format, ap));
va_end(ap);
ReportErrorAsync(title, message);
}
bool Host::ConfirmFormattedMessage(const std::string_view& title, const char* format, ...)
{
std::va_list ap;
va_start(ap, format);
std::string message = StringUtil::StdStringFromFormatV(format, ap);
va_end(ap);
return ConfirmMessage(title, message);
}
void Host::ReportFormattedDebuggerMessage(const char* format, ...)
{
std::va_list ap;
va_start(ap, format);
std::string message = StringUtil::StdStringFromFormatV(format, ap);
va_end(ap);
ReportDebuggerMessage(message);
}

View file

@ -1,12 +1,67 @@
#pragma once #pragma once
#include "common/string.h"
#include "common/types.h" #include "common/types.h"
#include <ctime>
#include <functional>
#include <memory>
#include <optional> #include <optional>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <vector> #include <vector>
struct WindowInfo;
enum class AudioBackend : u8;
class AudioStream;
class CDImage;
/// Marks a core string as being translatable.
#define TRANSLATABLE(context, str) str
/// Generic input bindings. These roughly match a DualShock 4 or XBox One controller.
/// They are used for automatic binding to PS2 controller types, and for big picture mode navigation.
enum class GenericInputBinding : u8
{
Unknown,
DPadUp,
DPadRight,
DPadLeft,
DPadDown,
LeftStickUp,
LeftStickRight,
LeftStickDown,
LeftStickLeft,
L3,
RightStickUp,
RightStickRight,
RightStickDown,
RightStickLeft,
R3,
Triangle, // Y on XBox pads.
Circle, // B on XBox pads.
Cross, // A on XBox pads.
Square, // X on XBox pads.
Select, // Share on DS4, View on XBox pads.
Start, // Options on DS4, Menu on XBox pads.
System, // PS button on DS4, Guide button on XBox pads.
L1, // LB on Xbox pads.
L2, // Left trigger on XBox pads.
R1, // RB on XBox pads.
R2, // Right trigger on Xbox pads.
SmallMotor, // High frequency vibration.
LargeMotor, // Low frequency vibration.
Count,
};
namespace Host { namespace Host {
/// Reads a file from the resources directory of the application. /// Reads a file from the resources directory of the application.
/// This may be outside of the "normal" filesystem on platforms such as Mac. /// This may be outside of the "normal" filesystem on platforms such as Mac.
@ -15,6 +70,18 @@ std::optional<std::vector<u8>> ReadResourceFile(const char* filename);
/// Reads a resource file file from the resources directory as a string. /// Reads a resource file file from the resources directory as a string.
std::optional<std::string> ReadResourceFileToString(const char* filename); std::optional<std::string> ReadResourceFileToString(const char* filename);
/// Returns the modified time of a resource.
std::optional<std::time_t> GetResourceFileTimestamp(const char* filename);
/// Translates a string to the current language.
TinyString TranslateString(const char* context, const char* str, const char* disambiguation = nullptr, int n = -1);
std::string TranslateStdString(const char* context, const char* str, const char* disambiguation = nullptr, int n = -1);
std::unique_ptr<AudioStream> CreateAudioStream(AudioBackend backend);
/// Returns the scale of OSD elements.
float GetOSDScale();
/// Adds OSD messages, duration is in seconds. /// Adds OSD messages, duration is in seconds.
void AddOSDMessage(std::string message, float duration = 2.0f); void AddOSDMessage(std::string message, float duration = 2.0f);
void AddKeyedOSDMessage(std::string key, std::string message, float duration = 2.0f); void AddKeyedOSDMessage(std::string key, std::string message, float duration = 2.0f);
@ -26,4 +93,26 @@ void ClearOSDMessages();
/// Displays an asynchronous error on the UI thread, i.e. doesn't block the caller. /// Displays an asynchronous error on the UI thread, i.e. doesn't block the caller.
void ReportErrorAsync(const std::string_view& title, const std::string_view& message); void ReportErrorAsync(const std::string_view& title, const std::string_view& message);
void ReportFormattedErrorAsync(const std::string_view& title, const char* format, ...); void ReportFormattedErrorAsync(const std::string_view& title, const char* format, ...);
/// Displays a synchronous confirmation on the UI thread, i.e. blocks the caller.
bool ConfirmMessage(const std::string_view& title, const std::string_view& message);
bool ConfirmFormattedMessage(const std::string_view& title, const char* format, ...);
/// Debugger feedback.
void ReportDebuggerMessage(const std::string_view& message);
void ReportFormattedDebuggerMessage(const char* format, ...);
/// Displays a loading screen with the logo, rendered with ImGui. Use when executing possibly-time-consuming tasks
/// such as compiling shaders when starting up.
void DisplayLoadingScreen(const char* message, int progress_min = -1, int progress_max = -1, int progress_value = -1);
/// Internal method used by pads to dispatch vibration updates to input sources.
/// Intensity is normalized from 0 to 1.
void SetPadVibrationIntensity(u32 pad_index, float large_or_single_motor_intensity, float small_motor_intensity);
/// Enables "relative" mouse mode, locking the cursor position and returning relative coordinates.
void SetMouseMode(bool relative, bool hide_cursor);
/// Safely executes a function on the VM thread.
void RunOnCPUThread(std::function<void()> function, bool block = false);
} // namespace Host } // namespace Host

View file

@ -5,7 +5,6 @@
#include "common/log.h" #include "common/log.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "common/timer.h" #include "common/timer.h"
#include "host_interface.h"
#include "stb_image.h" #include "stb_image.h"
#include "stb_image_resize.h" #include "stb_image_resize.h"
#include "stb_image_write.h" #include "stb_image_write.h"
@ -16,10 +15,72 @@
#include <vector> #include <vector>
Log_SetChannel(HostDisplay); Log_SetChannel(HostDisplay);
std::unique_ptr<HostDisplay> g_host_display;
HostDisplayTexture::~HostDisplayTexture() = default; HostDisplayTexture::~HostDisplayTexture() = default;
HostDisplay::~HostDisplay() = default; HostDisplay::~HostDisplay() = default;
HostDisplay::RenderAPI HostDisplay::GetPreferredAPI()
{
#ifdef _WIN32
return RenderAPI::D3D11;
#else
return RenderAPI::OpenGL;
#endif
}
bool HostDisplay::ParseFullscreenMode(const std::string_view& mode, u32* width, u32* height, float* refresh_rate)
{
if (!mode.empty())
{
std::string_view::size_type sep1 = mode.find('x');
if (sep1 != std::string_view::npos)
{
std::optional<u32> owidth = StringUtil::FromChars<u32>(mode.substr(0, sep1));
sep1++;
while (sep1 < mode.length() && std::isspace(mode[sep1]))
sep1++;
if (owidth.has_value() && sep1 < mode.length())
{
std::string_view::size_type sep2 = mode.find('@', sep1);
if (sep2 != std::string_view::npos)
{
std::optional<u32> oheight = StringUtil::FromChars<u32>(mode.substr(sep1, sep2 - sep1));
sep2++;
while (sep2 < mode.length() && std::isspace(mode[sep2]))
sep2++;
if (oheight.has_value() && sep2 < mode.length())
{
std::optional<float> orefresh_rate = StringUtil::FromChars<float>(mode.substr(sep2));
if (orefresh_rate.has_value())
{
*width = owidth.value();
*height = oheight.value();
*refresh_rate = orefresh_rate.value();
return true;
}
}
}
}
}
}
*width = 0;
*height = 0;
*refresh_rate = 0;
return false;
}
std::string HostDisplay::GetFullscreenModeString(u32 width, u32 height, float refresh_rate)
{
return StringUtil::StdStringFromFormat("%u x %u @ %f hz", width, height, refresh_rate);
}
bool HostDisplay::UsesLowerLeftOrigin() const bool HostDisplay::UsesLowerLeftOrigin() const
{ {
const RenderAPI api = GetRenderAPI(); const RenderAPI api = GetRenderAPI();

View file

@ -62,6 +62,15 @@ public:
virtual ~HostDisplay(); virtual ~HostDisplay();
/// Returns the default/preferred API for the system.
static RenderAPI GetPreferredAPI();
/// Parses a fullscreen mode into its components (width * height @ refresh hz)
static bool ParseFullscreenMode(const std::string_view& mode, u32* width, u32* height, float* refresh_rate);
/// Converts a fullscreen mode to a string.
static std::string GetFullscreenModeString(u32 width, u32 height, float refresh_rate);
ALWAYS_INLINE const WindowInfo& GetWindowInfo() const { return m_window_info; } ALWAYS_INLINE const WindowInfo& GetWindowInfo() const { return m_window_info; }
ALWAYS_INLINE s32 GetWindowWidth() const { return static_cast<s32>(m_window_info.surface_width); } ALWAYS_INLINE s32 GetWindowWidth() const { return static_cast<s32>(m_window_info.surface_width); }
ALWAYS_INLINE s32 GetWindowHeight() const { return static_cast<s32>(m_window_info.surface_height); } ALWAYS_INLINE s32 GetWindowHeight() const { return static_cast<s32>(m_window_info.surface_height); }
@ -290,3 +299,25 @@ protected:
bool m_display_integer_scaling = false; bool m_display_integer_scaling = false;
bool m_display_stretch = false; bool m_display_stretch = false;
}; };
/// Returns a pointer to the current host display abstraction. Assumes AcquireHostDisplay() has been caled.
extern std::unique_ptr<HostDisplay> g_host_display;
namespace Host {
/// Creates the host display. This may create a new window. The API used depends on the current configuration.
bool AcquireHostDisplay(HostDisplay::RenderAPI api);
/// Destroys the host display. This may close the display window.
void ReleaseHostDisplay();
/// Returns false if the window was completely occluded. If frame_skip is set, the frame won't be
/// displayed, but the GPU command queue will still be flushed.
//bool BeginPresentFrame(bool frame_skip);
/// Presents the frame to the display, and renders OSD elements.
//void EndPresentFrame();
/// Provided by the host; renders the display.
void RenderDisplay();
void InvalidateDisplay();
} // namespace Host

File diff suppressed because it is too large Load diff

View file

@ -1,225 +0,0 @@
#pragma once
#include "common/string.h"
#include "common/timer.h"
#include "settings.h"
#include "types.h"
#include <chrono>
#include <deque>
#include <functional>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <vector>
enum LOGLEVEL;
class AudioStream;
class ByteStream;
class CDImage;
class HostDisplay;
class GameList;
struct SystemBootParameters;
namespace BIOS {
struct ImageInfo;
}
class HostInterface
{
public:
enum : u32
{
AUDIO_SAMPLE_RATE = 44100,
AUDIO_CHANNELS = 2,
DEFAULT_AUDIO_BUFFER_SIZE = 2048
};
HostInterface();
virtual ~HostInterface();
/// Access to host display.
ALWAYS_INLINE HostDisplay* GetDisplay() const { return m_display.get(); }
ALWAYS_INLINE bool HasDisplay() const { return static_cast<bool>(m_display.get()); }
/// Access to host audio stream.
ALWAYS_INLINE AudioStream* GetAudioStream() const { return m_audio_stream.get(); }
/// Initializes the emulator frontend.
virtual bool Initialize();
/// Shuts down the emulator frontend.
virtual void Shutdown();
virtual bool BootSystem(std::shared_ptr<SystemBootParameters> parameters);
virtual void PauseSystem(bool paused);
virtual void ResetSystem();
virtual void DestroySystem();
/// Loads state from the specified filename.
bool LoadState(const char* filename);
virtual void ReportError(const char* message);
virtual void ReportMessage(const char* message);
virtual void ReportDebuggerMessage(const char* message);
virtual bool ConfirmMessage(const char* message);
void ReportFormattedError(const char* format, ...) printflike(2, 3);
void ReportFormattedMessage(const char* format, ...) printflike(2, 3);
void ReportFormattedDebuggerMessage(const char* format, ...) printflike(2, 3);
bool ConfirmFormattedMessage(const char* format, ...) printflike(2, 3);
/// Adds OSD messages, duration is in seconds.
virtual void AddOSDMessage(std::string message, float duration = 2.0f) = 0;
virtual void AddKeyedOSDMessage(std::string key, std::string message, float duration = 2.0f) = 0;
virtual void RemoveKeyedOSDMessage(std::string key) = 0;
void AddFormattedOSDMessage(float duration, const char* format, ...) printflike(3, 4);
void AddKeyedFormattedOSDMessage(std::string key, float duration, const char* format, ...) printflike(4, 5);
/// Returns the base user directory path.
ALWAYS_INLINE const std::string& GetUserDirectory() const { return m_user_directory; }
/// Returns a path relative to the user directory.
std::string GetUserDirectoryRelativePath(const char* format, ...) const printflike(2, 3);
/// Returns a path relative to the application directory (for system files).
std::string GetProgramDirectoryRelativePath(const char* format, ...) const printflike(2, 3);
/// Returns a string which can be used as part of a filename, based on the current date/time.
static TinyString GetTimestampStringForFileName();
/// Displays a loading screen with the logo, rendered with ImGui. Use when executing possibly-time-consuming tasks
/// such as compiling shaders when starting up.
virtual void DisplayLoadingScreen(const char* message, int progress_min = -1, int progress_max = -1,
int progress_value = -1) = 0;
/// Retrieves information about specified game from game list.
virtual void GetGameInfo(const char* path, CDImage* image, std::string* code, std::string* title) = 0;
/// Returns the directory where per-game memory cards will be saved.
virtual std::string GetMemoryCardDirectory() const;
/// Returns the default path to a memory card.
virtual std::string GetSharedMemoryCardPath(u32 slot) const;
/// Returns the default path to a memory card for a specific game.
virtual std::string GetGameMemoryCardPath(const char* game_code, u32 slot) const;
/// Returns the path to the shader cache directory.
virtual std::string GetShaderCacheBasePath() const;
/// Returns a setting value from the configuration.
virtual std::string GetStringSettingValue(const char* section, const char* key, const char* default_value = "") = 0;
/// Returns a boolean setting from the configuration.
virtual bool GetBoolSettingValue(const char* section, const char* key, bool default_value = false);
/// Returns an integer setting from the configuration.
virtual int GetIntSettingValue(const char* section, const char* key, int default_value = 0);
/// Returns a float setting from the configuration.
virtual float GetFloatSettingValue(const char* section, const char* key, float default_value = 0.0f);
/// Returns a string list from the configuration.
virtual std::vector<std::string> GetSettingStringList(const char* section, const char* key) = 0;
/// Returns the settings interface.
virtual SettingsInterface* GetSettingsInterface() = 0;
virtual std::lock_guard<std::recursive_mutex> GetSettingsLock() = 0;
/// Translates a string to the current language.
virtual TinyString TranslateString(const char* context, const char* str, const char* disambiguation = nullptr,
int n = -1) const;
virtual std::string TranslateStdString(const char* context, const char* str, const char* disambiguation = nullptr,
int n = -1) const;
/// Returns the path to the directory to search for BIOS images.
virtual std::string GetBIOSDirectory();
/// Loads the BIOS image for the specified region.
std::optional<std::vector<u8>> GetBIOSImage(ConsoleRegion region);
/// Searches for a BIOS image for the specified region in the specified directory. If no match is found, the first
/// BIOS image within 512KB and 4MB will be used.
std::optional<std::vector<u8>> FindBIOSImageInDirectory(ConsoleRegion region, const char* directory);
/// Returns a list of filenames and descriptions for BIOS images in a directory.
std::vector<std::pair<std::string, const BIOS::ImageInfo*>> FindBIOSImagesInDirectory(const char* directory);
/// Returns true if any BIOS images are found in the configured BIOS directory.
bool HasAnyBIOSImages();
/// Opens a file in the DuckStation "package".
/// This is the APK for Android builds, or the program directory for standalone builds.
virtual std::unique_ptr<ByteStream> OpenPackageFile(const char* path, u32 flags) = 0;
virtual void OnRunningGameChanged(const std::string& path, CDImage* image, const std::string& game_code,
const std::string& game_title) = 0;
virtual void OnSystemPerformanceCountersUpdated() = 0;
/// Called when the display is invalidated (e.g. a state is loaded).
virtual void OnDisplayInvalidated() = 0;
/// Called when achievements data is loaded.
virtual void OnAchievementsRefreshed() = 0;
protected:
virtual bool AcquireHostDisplay() = 0;
virtual void ReleaseHostDisplay() = 0;
virtual std::unique_ptr<AudioStream> CreateAudioStream(AudioBackend backend) = 0;
virtual s32 GetAudioOutputVolume() const;
virtual void OnSystemCreated() = 0;
virtual void OnSystemPaused(bool paused) = 0;
virtual void OnSystemDestroyed() = 0;
virtual void OnControllerTypeChanged(u32 slot) = 0;
/// Restores all settings to defaults.
virtual void SetDefaultSettings(SettingsInterface& si);
/// Loads settings to m_settings and any frontend-specific parameters.
virtual void LoadSettings(SettingsInterface& si);
/// Saves current settings variables to ini.
virtual void SaveSettings(SettingsInterface& si);
/// Checks and fixes up any incompatible settings.
virtual void FixIncompatibleSettings(bool display_osd_messages);
/// Checks for settings changes, std::move() the old settings away for comparing beforehand.
virtual void CheckForSettingsChanges(const Settings& old_settings);
/// Switches the GPU renderer by saving state, recreating the display window, and restoring state (if needed).
virtual void RecreateSystem();
/// Enables "relative" mouse mode, locking the cursor position and returning relative coordinates.
virtual void SetMouseMode(bool relative, bool hide_cursor) = 0;
/// Call when host display size changes, use with "match display" aspect ratio setting.
virtual void OnHostDisplayResized();
/// Sets the user directory to the program directory, i.e. "portable mode".
void SetUserDirectoryToProgramDirectory();
/// Quick switch between software and hardware rendering.
void ToggleSoftwareRendering();
/// Adjusts the internal (render) resolution of the hardware backends.
void ModifyResolutionScale(s32 increment);
/// Updates software cursor state, based on controllers.
void UpdateSoftwareCursor();
bool SaveState(const char* filename);
void CreateAudioStream();
std::unique_ptr<HostDisplay> m_display;
std::unique_ptr<AudioStream> m_audio_stream;
std::string m_program_directory;
std::string m_user_directory;
};
#define TRANSLATABLE(context, str) str
extern HostInterface* g_host_interface;

View file

@ -1,10 +1,14 @@
#include "host_interface_progress_callback.h" #include "host_interface_progress_callback.h"
#include "common/log.h" #include "common/log.h"
#include "host.h"
Log_SetChannel(HostInterfaceProgressCallback); Log_SetChannel(HostInterfaceProgressCallback);
HostInterfaceProgressCallback::HostInterfaceProgressCallback() : BaseProgressCallback() {} HostInterfaceProgressCallback::HostInterfaceProgressCallback() : BaseProgressCallback() {}
void HostInterfaceProgressCallback::PushState() { BaseProgressCallback::PushState(); } void HostInterfaceProgressCallback::PushState()
{
BaseProgressCallback::PushState();
}
void HostInterfaceProgressCallback::PopState() void HostInterfaceProgressCallback::PopState()
{ {
@ -57,32 +61,42 @@ void HostInterfaceProgressCallback::Redraw(bool force)
return; return;
m_last_progress_percent = percent; m_last_progress_percent = percent;
g_host_interface->DisplayLoadingScreen(m_status_text, 0, static_cast<int>(m_progress_range), Host::DisplayLoadingScreen(m_status_text, 0, static_cast<int>(m_progress_range), static_cast<int>(m_progress_value));
static_cast<int>(m_progress_value));
} }
void HostInterfaceProgressCallback::DisplayError(const char* message) { Log_ErrorPrint(message); } void HostInterfaceProgressCallback::DisplayError(const char* message)
{
Log_ErrorPrint(message);
}
void HostInterfaceProgressCallback::DisplayWarning(const char* message) { Log_WarningPrint(message); } void HostInterfaceProgressCallback::DisplayWarning(const char* message)
{
Log_WarningPrint(message);
}
void HostInterfaceProgressCallback::DisplayInformation(const char* message) { Log_InfoPrint(message); } void HostInterfaceProgressCallback::DisplayInformation(const char* message)
{
Log_InfoPrint(message);
}
void HostInterfaceProgressCallback::DisplayDebugMessage(const char* message) { Log_DevPrint(message); } void HostInterfaceProgressCallback::DisplayDebugMessage(const char* message)
{
Log_DevPrint(message);
}
void HostInterfaceProgressCallback::ModalError(const char* message) void HostInterfaceProgressCallback::ModalError(const char* message)
{ {
Log_ErrorPrint(message); Log_ErrorPrint(message);
g_host_interface->ReportError(message); Host::ReportErrorAsync("Error", message);
} }
bool HostInterfaceProgressCallback::ModalConfirmation(const char* message) bool HostInterfaceProgressCallback::ModalConfirmation(const char* message)
{ {
Log_InfoPrint(message); Log_InfoPrint(message);
return g_host_interface->ConfirmMessage(message); return Host::ConfirmMessage("Confirm", message);
} }
void HostInterfaceProgressCallback::ModalInformation(const char* message) void HostInterfaceProgressCallback::ModalInformation(const char* message)
{ {
Log_InfoPrint(message); Log_InfoPrint(message);
g_host_interface->ReportMessage(message);
} }

View file

@ -1,6 +1,5 @@
#pragma once #pragma once
#include "common/progress_callback.h" #include "common/progress_callback.h"
#include "host_interface.h"
class HostInterfaceProgressCallback final : public BaseProgressCallback class HostInterfaceProgressCallback final : public BaseProgressCallback
{ {

View file

@ -18,13 +18,16 @@ double GetBaseDoubleSettingValue(const char* section, const char* key, double de
std::vector<std::string> GetBaseStringListSetting(const char* section, const char* key); std::vector<std::string> GetBaseStringListSetting(const char* section, const char* key);
// Allows the emucore to write settings back to the frontend. Use with care. // Allows the emucore to write settings back to the frontend. Use with care.
// You should call CommitBaseSettingChanges() after finishing writing, or it may not be written to disk. // You should call CommitBaseSettingChanges() if you directly write to the layer (i.e. not these functions), or it may
// not be written to disk.
void SetBaseBoolSettingValue(const char* section, const char* key, bool value); void SetBaseBoolSettingValue(const char* section, const char* key, bool value);
void SetBaseIntSettingValue(const char* section, const char* key, s32 value); void SetBaseIntSettingValue(const char* section, const char* key, s32 value);
void SetBaseUIntSettingValue(const char* section, const char* key, u32 value); void SetBaseUIntSettingValue(const char* section, const char* key, u32 value);
void SetBaseFloatSettingValue(const char* section, const char* key, float value); void SetBaseFloatSettingValue(const char* section, const char* key, float value);
void SetBaseStringSettingValue(const char* section, const char* key, const char* value); void SetBaseStringSettingValue(const char* section, const char* key, const char* value);
void SetBaseStringListSettingValue(const char* section, const char* key, const std::vector<std::string>& values); void SetBaseStringListSettingValue(const char* section, const char* key, const std::vector<std::string>& values);
bool AddValueToBaseStringListSetting(const char* section, const char* key, const char* value);
bool RemoveValueFromBaseStringListSetting(const char* section, const char* key, const char* value);
void DeleteBaseSettingValue(const char* section, const char* key); void DeleteBaseSettingValue(const char* section, const char* key);
void CommitBaseSettingChanges(); void CommitBaseSettingChanges();

View file

@ -1,56 +0,0 @@
#include "imgui_styles.h"
void ImGui::StyleColorsDarker(ImGuiStyle* dst)
{
ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
ImVec4* colors = style->Colors;
colors[ImGuiCol_Text] = ImVec4(0.95f, 0.96f, 0.98f, 1.00f);
colors[ImGuiCol_TextDisabled] = ImVec4(0.36f, 0.42f, 0.47f, 1.00f);
colors[ImGuiCol_WindowBg] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
colors[ImGuiCol_ChildBg] = ImVec4(0.15f, 0.18f, 0.22f, 1.00f);
colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
colors[ImGuiCol_Border] = ImVec4(0.08f, 0.10f, 0.12f, 1.00f);
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImGuiCol_FrameBg] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.12f, 0.20f, 0.28f, 1.00f);
colors[ImGuiCol_FrameBgActive] = ImVec4(0.09f, 0.12f, 0.14f, 1.00f);
colors[ImGuiCol_TitleBg] = ImVec4(0.09f, 0.12f, 0.14f, 0.65f);
colors[ImGuiCol_TitleBgActive] = ImVec4(0.08f, 0.10f, 0.12f, 1.00f);
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f);
colors[ImGuiCol_MenuBarBg] = ImVec4(0.15f, 0.18f, 0.22f, 1.00f);
colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.39f);
colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.18f, 0.22f, 0.25f, 1.00f);
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.09f, 0.21f, 0.31f, 1.00f);
colors[ImGuiCol_CheckMark] = ImVec4(0.28f, 0.56f, 1.00f, 1.00f);
colors[ImGuiCol_SliderGrab] = ImVec4(0.28f, 0.56f, 1.00f, 1.00f);
colors[ImGuiCol_SliderGrabActive] = ImVec4(0.37f, 0.61f, 1.00f, 1.00f);
colors[ImGuiCol_Button] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);
colors[ImGuiCol_ButtonHovered] = ImVec4(0.33f, 0.38f, 0.46f, 1.00f);
colors[ImGuiCol_ButtonActive] = ImVec4(0.27f, 0.32f, 0.38f, 1.00f);
colors[ImGuiCol_Header] = ImVec4(0.20f, 0.25f, 0.29f, 0.55f);
colors[ImGuiCol_HeaderHovered] = ImVec4(0.33f, 0.38f, 0.46f, 1.00f);
colors[ImGuiCol_HeaderActive] = ImVec4(0.27f, 0.32f, 0.38f, 1.00f);
colors[ImGuiCol_Separator] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.33f, 0.38f, 0.46f, 1.00f);
colors[ImGuiCol_SeparatorActive] = ImVec4(0.27f, 0.32f, 0.38f, 1.00f);
colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.25f);
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.33f, 0.38f, 0.46f, 1.00f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.27f, 0.32f, 0.38f, 1.00f);
colors[ImGuiCol_Tab] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
colors[ImGuiCol_TabHovered] = ImVec4(0.33f, 0.38f, 0.46f, 1.00f);
colors[ImGuiCol_TabActive] = ImVec4(0.27f, 0.32f, 0.38f, 1.00f);
colors[ImGuiCol_TabUnfocused] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
}

Some files were not shown because too many files have changed in this diff Show more