Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 71cf0e0daa | |||
| 59444d5c48 | |||
| 3aa4fb867c | |||
| ab1ad1dc4a | |||
| 0dc64e2a48 | |||
| 420b002448 | |||
| 413cebca20 | |||
| a2d830e51b | |||
| 47d6360038 | |||
| e0daa0d83d | |||
| c487a5cbc4 | |||
| 6b7e54e115 | |||
| 8bbbd28f48 | |||
| ca7c1c7230 | |||
| db10193a16 | |||
| 8c045a47d2 | |||
| 616e0a93c7 | |||
| 78e7037ccc | |||
| 635335fc85 | |||
| e35efd3db1 | |||
| 901f556af5 | |||
| ef730ed490 | |||
| c188b6a819 | |||
| 476f035672 | |||
| b4a1207dab | |||
| 59c41f0746 | |||
| c2f0a1c786 | |||
| a711a4e6ab | |||
| 5aa9ed4dc0 | |||
| 1b8f4c2062 | |||
| 1eaf8bb28f | |||
| 28bf78db3a |
@@ -641,7 +641,7 @@ if (ENABLE_QT)
|
||||
list(APPEND CMAKE_PREFIX_PATH "${Qt6_DIR}")
|
||||
endif()
|
||||
|
||||
find_package(Qt6 CONFIG REQUIRED COMPONENTS Widgets Charts Concurrent)
|
||||
find_package(Qt6 CONFIG REQUIRED COMPONENTS Widgets Concurrent)
|
||||
|
||||
if (YUZU_USE_QT_MULTIMEDIA)
|
||||
find_package(Qt6 REQUIRED COMPONENTS Multimedia)
|
||||
@@ -680,7 +680,7 @@ if (ENABLE_QT)
|
||||
## Components ##
|
||||
|
||||
# Best practice is to ask for all components at once, so they are from the same version
|
||||
set(YUZU_QT_COMPONENTS Core Widgets Charts Concurrent)
|
||||
set(YUZU_QT_COMPONENTS Core Widgets Concurrent)
|
||||
if (PLATFORM_LINUX)
|
||||
list(APPEND YUZU_QT_COMPONENTS DBus)
|
||||
endif()
|
||||
|
||||
@@ -36,17 +36,14 @@ set(GIT_DESC ${BUILD_VERSION})
|
||||
# Also if this is a CI build, add the build name (ie: Nightly, Canary) to the scm_rev file as well
|
||||
|
||||
# Auto-updater metadata! Must somewhat mirror GitHub API endpoint
|
||||
set(BUILD_AUTO_UPDATE_WEBSITE "https://github.com")
|
||||
set(BUILD_AUTO_UPDATE_API "http://api.github.com")
|
||||
|
||||
if (NIGHTLY_BUILD)
|
||||
set(BUILD_AUTO_UPDATE_WEBSITE "https://github.com")
|
||||
set(BUILD_AUTO_UPDATE_API "api.github.com")
|
||||
set(BUILD_AUTO_UPDATE_API_PATH "/repos/")
|
||||
set(BUILD_AUTO_UPDATE_REPO "Eden-CI/Nightly")
|
||||
set(REPO_NAME "Eden Nightly")
|
||||
else()
|
||||
set(BUILD_AUTO_UPDATE_WEBSITE "https://git.eden-emu.dev")
|
||||
set(BUILD_AUTO_UPDATE_API "git.eden-emu.dev")
|
||||
set(BUILD_AUTO_UPDATE_API_PATH "/api/v1/repos/")
|
||||
set(BUILD_AUTO_UPDATE_REPO "eden-emu/eden")
|
||||
set(BUILD_AUTO_UPDATE_REPO "eden-emulator/Releases")
|
||||
set(REPO_NAME "Eden")
|
||||
endif()
|
||||
|
||||
|
||||
@@ -6,225 +6,206 @@
|
||||
viewBox="0 0 512 512"
|
||||
version="1.1"
|
||||
id="svg7"
|
||||
sodipodi:docname="base.svg.2026_01_12_14_43_47.0.svg"
|
||||
inkscape:version="1.4.2 (ebf0e94, 2025-05-08)"
|
||||
inkscape:export-filename="base.svg.2026_01_12_14_43_47.0.svg"
|
||||
sodipodi:docname="EdenLogoLoveWhiteV3.svg"
|
||||
inkscape:version="1.4.3 (0d15f75, 2025-12-25)"
|
||||
xml:space="preserve"
|
||||
inkscape:export-filename="dev.eden_emu.eden.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<metadata
|
||||
id="metadata1">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Madeline_Dev</dc:title>
|
||||
<dc:identifier>mailto:madelvidel@gmail.com</dc:identifier>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:date>2025</dc:date>
|
||||
<dc:license
|
||||
rdf:resource="https://www.gnu.org/licenses/gpl-3.0.html" />
|
||||
<dc:rights>2025 Eden Emulator Project</dc:rights>
|
||||
<dc:source>https://git.eden-emu.dev</dc:source>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs7">
|
||||
<linearGradient
|
||||
id="linearGradient1"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
style="stop-color:#ff2e88;stop-opacity:0.5;"
|
||||
offset="0"
|
||||
id="stop3" />
|
||||
<stop
|
||||
style="stop-color:#bf42f6;stop-opacity:0.5;"
|
||||
offset="0.44631511"
|
||||
id="stop4" />
|
||||
<stop
|
||||
style="stop-color:#5da5ed;stop-opacity:0.5;"
|
||||
offset="0.90088946"
|
||||
id="stop2" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient138"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
style="stop-color:#ff2e88;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop152" />
|
||||
<stop
|
||||
style="stop-color:#bf42f6;stop-opacity:1;"
|
||||
offset="0.44971901"
|
||||
id="stop137" />
|
||||
<stop
|
||||
style="stop-color:#5da5ed;stop-opacity:1;"
|
||||
offset="0.89793283"
|
||||
id="stop138" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="swatch37"
|
||||
inkscape:swatch="solid">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop37" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="swatch28"
|
||||
inkscape:swatch="solid">
|
||||
<stop
|
||||
style="stop-color:#252525;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop28" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="swatch27"
|
||||
inkscape:swatch="solid">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop27" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="swatch15"
|
||||
inkscape:swatch="solid">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop16" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient14"
|
||||
inkscape:swatch="gradient">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop14" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop15" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="swatch9"
|
||||
inkscape:swatch="solid">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop10" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="swatch8"
|
||||
inkscape:swatch="solid">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop9" />
|
||||
</linearGradient>
|
||||
<rect
|
||||
x="22.627417"
|
||||
y="402.76802"
|
||||
width="521.34025"
|
||||
height="248.94868"
|
||||
id="rect24" />
|
||||
<linearGradient
|
||||
id="linearGradient11"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
style="stop-color:#ff2e88;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop11" />
|
||||
<stop
|
||||
style="stop-color:#bf42f6;stop-opacity:1;"
|
||||
offset="0.44971901"
|
||||
id="stop154" />
|
||||
<stop
|
||||
style="stop-color:#5da5ed;stop-opacity:1;"
|
||||
offset="0.89793283"
|
||||
id="stop12" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient138"
|
||||
id="linearGradient6"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.118028,0,0,1.116699,-46.314723,-42.388667)"
|
||||
x1="270.39996"
|
||||
y1="40.000019"
|
||||
x2="270.39996"
|
||||
y2="494.39996"
|
||||
spreadMethod="pad" />
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath18">
|
||||
<circle
|
||||
style="opacity:1;mix-blend-mode:normal;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10.8382;stroke-opacity:0.566238;paint-order:stroke fill markers"
|
||||
id="circle18"
|
||||
cx="-246.8315"
|
||||
cy="246.8338"
|
||||
inkscape:label="Circle"
|
||||
r="191.89999" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath22">
|
||||
<circle
|
||||
style="opacity:1;mix-blend-mode:normal;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10.8382;stroke-opacity:0.566238;paint-order:stroke fill markers"
|
||||
id="circle22"
|
||||
cx="256"
|
||||
cy="256"
|
||||
inkscape:label="Circle"
|
||||
r="191.89999" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient11"
|
||||
id="linearGradient27"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-6.9401139e-5,-2.8678628)"
|
||||
x1="256.00012"
|
||||
y1="102.94693"
|
||||
x2="256.00012"
|
||||
y2="409.05307" />
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath128">
|
||||
<circle
|
||||
style="fill:none;fill-opacity:1;stroke:#03ffff;stroke-width:0;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="circle128"
|
||||
cx="256"
|
||||
cy="256"
|
||||
r="192" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient1"
|
||||
id="linearGradient2"
|
||||
x1="256"
|
||||
y1="64"
|
||||
x2="256"
|
||||
y2="448"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.3229974,0,0,1.3214002,-82.687336,-82.290326)" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="1.4142136"
|
||||
inkscape:cx="261.62951"
|
||||
inkscape:cy="230.87036"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1008"
|
||||
inkscape:window-x="1080"
|
||||
inkscape:window-y="351"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg7" />
|
||||
<path
|
||||
id="path8-7"
|
||||
style="display:inline;mix-blend-mode:multiply;fill:url(#linearGradient6);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2);stroke-width:3.9666;stroke-dasharray:none;stroke-opacity:0.566238;paint-order:stroke fill markers"
|
||||
inkscape:label="Circle"
|
||||
d="M 256,2.2792898 A 254.0155,253.71401 0 0 0 150.68475,25.115202 c 19.54414,1.070775 38.74692,5.250294 51.56848,11.647658 14.14361,7.056691 28.63804,19.185961 39.4212,29.347551 h 40.60981 c 1.03847,-0.68139 2.10297,-1.36938 3.1938,-2.05957 5.45602,-15.78533 14.79164,-43.183497 19.49612,-57.0097682 A 254.0155,253.71401 0 0 0 256,2.2792898 Z m 61.57106,7.567234 -18.26098,46.1544672 c 7.79702,-4.13918 16.35655,-7.87447 25.20671,-10.87081 23.1229,-7.828433 43.96931,-10.170904 54.94058,-10.868226 A 254.0155,253.71401 0 0 0 317.57106,9.8465238 Z m 65.39277,26.4001532 c -9.68256,4.806644 -33.05532,16.642034 -55.68217,29.863734 H 424.4677 A 254.0155,253.71401 0 0 0 382.96383,36.246677 Z M 113.90698,45.690231 A 254.0155,253.71401 0 0 0 87.532302,66.110411 H 194.2739 c -1.47402,-0.80231 -2.35141,-1.25949 -2.35141,-1.25949 l 10.4496,-11.83348 -38.40568,7.01234 c 0,1e-5 -12.21537,-4.60266 -40.17313,-12.27223 -3.45336,-0.94731 -6.75329,-1.61824 -9.8863,-2.06732 z m -36.803618,30.18635 a 254.0155,253.71401 0 0 0 -34.88372,43.090929 h 59.976738 c 18.11461,-12.04145 40.14252,-22.882149 62.31266,-24.534159 52.93006,-3.9444 70.16538,1.86342 70.16538,1.86342 0,0 -4.612,-4.8206 -14.51938,-13.36656 -2.72366,-2.34942 -6.0844,-4.77373 -9.52455,-7.05363 z m 174.472868,0 c 4.57322,4.7186 7.29716,7.83565 7.29716,7.83565 0,0 3.53501,-3.18484 9.62532,-7.83565 z m 60.27649,0 c -21.56573,15.45339 -25.4703,27.979669 -25.4703,27.979669 0,0 54.83326,-19.215729 100.70543,-0.31228 11.63986,4.79661 21.58481,10.13159 29.94832,15.42354 h 52.74419 A 254.0155,253.71401 0 0 0 434.89664,75.876581 Z M 36.250648,128.73367 A 254.0155,253.71401 0 0 0 16.372095,171.82459 H 147.45478 c 1.45695,-2.5815 3.06539,-5.08648 4.83979,-7.48982 14.23694,-19.28301 27.92088,-30.0088 36.86047,-35.6011 h -30.25323 c -5.87346,0.93472 -12.04945,1.99094 -18.28166,3.16937 -30.12936,5.69727 -81.157618,22.78945 -81.157618,22.78945 0,0 11.47125,-12.39249 29.11369,-25.95882 z m 265.630492,0 c 33.48676,11.2434 52.42799,26.78443 62.7752,43.09092 h 130.97157 a 254.0155,253.71401 0 0 0 -19.87856,-43.09092 h -44.81136 c 14.85233,11.5863 21.59948,20.9854 21.59948,20.9854 0,0 -33.5226,-12.37087 -66.0646,-20.9854 z m -45.96641,16.27007 c -1.00419,0.0106 -10.12705,0.72026 -44.98966,20.64729 -3.12132,1.78406 -6.25434,3.86182 -9.37468,6.17356 h 41.81911 c 7.17181,-17.34774 12.64083,-26.82085 12.64083,-26.82085 0,0 -0.0287,-7.1e-4 -0.0957,0 z m 14.18088,0.0465 c 0,0 -3.31228,9.32762 -7.30492,26.77438 h 51.78554 C 287.6577,146.14158 270.09561,145.0502 270.09561,145.0502 Z M 13.152456,181.59075 A 254.0155,253.71401 0 0 0 3.927651,224.68167 H 134.1447 c 0.56161,-12.72411 2.67825,-28.50188 8.61499,-43.09092 z m 176.661504,0 c -14.27121,13.10564 -27.60733,29.58761 -37.56073,43.09092 h 73.3721 c 4.47018,-16.79061 9.35068,-31.26371 13.86562,-43.09092 z m 70.85787,0 c -2.41384,11.76417 -4.9032,26.20707 -6.94831,43.09092 H 360.4832 c -8.32133,-10.88917 -20.66988,-26.17008 -36.35141,-43.09092 z m 109.17313,0 c 6.63611,15.24089 6.92441,30.5373 5.57882,43.09092 h 132.64857 a 254.0155,253.71401 0 0 0 -9.22481,-43.09092 z M 2.90181,234.44783 A 254.0155,253.71401 0 0 0 1.984498,255.9933 254.0155,253.71401 0 0 0 2.90181,277.53876 h 211.89923 c 2.25762,-15.52555 5.14325,-29.93448 8.3385,-43.09093 h -77.8863 c -6.46396,9.27617 -10.33076,15.56549 -10.33076,15.56549 0,0 -0.82623,-6.14945 -0.9354,-15.56549 z m 249.72093,0 c -1.3692,13.09684 -2.4456,27.49209 -3.02068,43.09093 h 259.49613 a 254.0155,253.71401 0 0 0 0.91731,-21.54546 254.0155,253.71401 0 0 0 -0.91731,-21.54547 H 374.02584 c -0.445,2.5469 -0.90878,4.89768 -1.32817,7.01751 0,0 -1.69726,-2.53821 -4.94056,-7.01751 z M 3.927651,287.30493 a 254.0155,253.71401 0 0 0 9.224805,43.09091 H 214.04393 c -1.29238,-15.40742 -1.57503,-30.04388 -0.41861,-43.09091 z m 245.385009,0 c -0.30355,13.54349 -0.22032,27.92598 0.36951,43.09091 h 249.16537 a 254.0155,253.71401 0 0 0 9.22481,-43.09091 z M 16.369511,340.16201 a 254.0155,253.71401 0 0 0 19.878554,43.09091 H 221.4677 c -2.69781,-14.4523 -4.96108,-29.01285 -6.4832,-43.09091 z m 233.842379,0 c 1.15864,15.47765 3.81286,29.83979 7.51679,43.09091 h 218.02325 a 254.0155,253.71401 0 0 0 19.87856,-43.09091 z M 42.217052,393.01909 a 254.0155,253.71401 0 0 0 34.88372,43.09093 H 233.09561 c -3.40902,-13.67281 -6.76794,-28.2531 -9.73902,-43.09093 z m 218.490958,0 c 5.34985,16.15926 12.22007,30.51982 19.68733,43.09093 h 154.50389 a 254.0155,253.71401 0 0 0 34.88371,-43.09093 z M 87.529722,445.87618 a 254.0155,253.71401 0 0 0 166.229968,63.8208 c -3.67805,-12.0825 -10.85464,-35.49828 -18.18088,-63.8208 z m 199.010328,0 c 17.5887,26.43772 36.99259,43.60598 47.33592,51.61309 a 254.0155,253.71401 0 0 0 90.59431,-51.61309 z" />
|
||||
<path
|
||||
id="path27"
|
||||
style="display:inline;mix-blend-mode:multiply;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient27);stroke-width:3;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
d="m 318.98012,441.7375 c -9.87518,-6.73978 -64.39137,-49.0272 -67.68975,-127.81978 -3.69298,-88.21893 15.36468,-141.91029 15.36468,-141.91029 0,0 16.00378,0.99513 39.80316,26.53195 23.79939,25.53753 37.74965,46.43102 37.74965,46.43102 3.91262,-19.79992 12.84563,-66.32402 -60.72865,-87.55523 0,0 12.82326,-5.38883 39.3925,-3.81382 26.56907,1.57572 81.6822,21.93799 81.6822,21.93799 0,0 -14.79766,-20.63773 -49.47063,-34.94295 -34.67291,-14.30533 -76.1182,0.23644 -76.1182,0.23644 0,0 3.86959,-12.43127 27.22669,-26.38478 23.35718,-13.9537 49.27409,-26.501533 49.27409,-26.501533 0,0 -21.97854,-0.26548 -47.67725,8.44535 -6.68948,2.267506 -13.15863,5.094213 -19.05208,8.226563 l 16.05803,-40.634103 -4.4617,-1.89059 -5.1305,-0.95965 c 0,0 -11.24072,33.12428 -16.92051,49.576513 -12.13137,7.68489 -20.11005,14.87735 -20.11005,14.87735 0,0 -21.90573,-25.09227 -42.79668,-35.527803 -26.03412,-13.00525 -86.88249,-13.90359 -94.0044,10.401173 0,0 13.56804,-7.884703 34.70032,-2.080917 21.13214,5.803997 30.3644,9.287307 30.3644,9.287307 l 29.02989,-5.30681 -7.89811,8.95527 c 0,0 13.8496,7.21324 21.33822,13.68063 7.48859,6.46722 10.9757,10.11472 10.9757,10.11472 0,0 -13.02739,-4.39388 -53.03507,-1.40893 -40.00771,2.98473 -79.40016,45.60209 -79.40016,45.60209 0,0 38.57037,-12.93531 61.34393,-17.24677 22.77354,-4.31126 44.52166,-6.46757 44.52166,-6.46757 0,0 -17.23298,5.97003 -35.69792,31.00932 -18.46522,25.03987 -13.13146,64.83866 -13.13146,64.83866 0,0 29.33874,-47.7577 57.44675,-63.84249 28.10798,-16.08527 34.0799,-15.6238 34.0799,-15.6238 0,0 -22.56785,39.13486 -31.39017,101.98268 -8.03005,57.2039 26.77689,163.75449 31.1572,178.89699"
|
||||
sodipodi:nodetypes="cscsccscscscsccccccscscccscscscscscsc"
|
||||
inkscape:label="MainOutline"
|
||||
clip-path="url(#clipPath128)"
|
||||
transform="matrix(1.3229974,0,0,1.3214002,-82.687282,-82.278451)" />
|
||||
</svg>
|
||||
id="defs7"><linearGradient
|
||||
id="swatch14"
|
||||
inkscape:swatch="solid"><stop
|
||||
style="stop-color:#66003b;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop14" /></linearGradient><linearGradient
|
||||
id="linearGradient1"
|
||||
inkscape:collect="always"><stop
|
||||
style="stop-color:#ffffff;stop-opacity:0.50980395;"
|
||||
offset="0"
|
||||
id="stop1" /><stop
|
||||
style="stop-color:#000000;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop2" /></linearGradient><linearGradient
|
||||
id="linearGradient11"
|
||||
inkscape:collect="always"><stop
|
||||
style="stop-color:#9523a7;stop-opacity:0.50980395;"
|
||||
offset="0"
|
||||
id="stop11" /><stop
|
||||
style="stop-color:#ffabad;stop-opacity:1;"
|
||||
offset="0.99898213"
|
||||
id="stop20" /><stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
offset="0.99898213"
|
||||
id="stop12" /></linearGradient><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient11"
|
||||
id="linearGradient12"
|
||||
x1="109.74531"
|
||||
y1="106.54533"
|
||||
x2="431.05463"
|
||||
y2="427.85461"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
spreadMethod="reflect"
|
||||
gradientTransform="matrix(1.0945321,0,0,1.0945321,-39.661525,-35.159057)" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient1"
|
||||
id="linearGradient2"
|
||||
x1="125.40197"
|
||||
y1="271.834"
|
||||
x2="431.02424"
|
||||
y2="271.834"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.0964243,0,0,1.0253208,-40.187969,-20.060025)" /><filter
|
||||
inkscape:label="Light Contour"
|
||||
inkscape:menu="Image Paint and Draw"
|
||||
inkscape:menu-tooltip="Uses vertical specular light to draw lines"
|
||||
style="color-interpolation-filters:sRGB"
|
||||
id="filter11"
|
||||
x="-0.01907517"
|
||||
y="-0.054959154"
|
||||
width="1.0379885"
|
||||
height="1.1092314"><feGaussianBlur
|
||||
in="SourceGraphic"
|
||||
stdDeviation="0.38250006"
|
||||
result="result3"
|
||||
id="feGaussianBlur9" /><feComponentTransfer
|
||||
result="result1"
|
||||
in="result3"
|
||||
id="feComponentTransfer9"><feFuncR
|
||||
type="discrete"
|
||||
tableValues="0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1"
|
||||
id="feFuncR9" /><feFuncG
|
||||
type="discrete"
|
||||
tableValues="0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1"
|
||||
id="feFuncG9" /><feFuncB
|
||||
type="discrete"
|
||||
tableValues="0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1"
|
||||
id="feFuncB9" /></feComponentTransfer><feGaussianBlur
|
||||
result="result5"
|
||||
stdDeviation="0.01"
|
||||
id="feGaussianBlur10" /><feBlend
|
||||
in2="result5"
|
||||
result="result6"
|
||||
mode="lighten"
|
||||
in="result5"
|
||||
id="feBlend10" /><feColorMatrix
|
||||
in="result6"
|
||||
type="luminanceToAlpha"
|
||||
result="result2"
|
||||
id="feColorMatrix10" /><feSpecularLighting
|
||||
surfaceScale="5"
|
||||
result="result9"
|
||||
specularExponent="20"
|
||||
in="result2"
|
||||
specularConstant="1"
|
||||
id="feSpecularLighting10"><feDistantLight
|
||||
azimuth="180"
|
||||
elevation="90"
|
||||
id="feDistantLight10" /></feSpecularLighting><feComposite
|
||||
in2="result6"
|
||||
operator="arithmetic"
|
||||
in="result9"
|
||||
k1="0.4"
|
||||
k3="0.7"
|
||||
result="result3"
|
||||
id="feComposite10"
|
||||
k2="0"
|
||||
k4="0" /><feBlend
|
||||
in2="result1"
|
||||
in="result3"
|
||||
mode="normal"
|
||||
result="result8"
|
||||
id="feBlend11" /><feComposite
|
||||
in2="SourceGraphic"
|
||||
in="result8"
|
||||
operator="in"
|
||||
result="result7"
|
||||
id="feComposite11" /></filter></defs><sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="1.35"
|
||||
inkscape:cx="254.81481"
|
||||
inkscape:cy="260.37037"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1001"
|
||||
inkscape:window-x="-9"
|
||||
inkscape:window-y="-9"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg7"
|
||||
showguides="false" /><circle
|
||||
style="fill:url(#linearGradient12);fill-opacity:1;stroke:#e4e4e4;stroke-width:14.0448;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
id="path8"
|
||||
cx="256.2999"
|
||||
cy="257.2999"
|
||||
r="248.67769" /><path
|
||||
id="path15"
|
||||
style="fill:url(#linearGradient2);fill-opacity:1;stroke:#ffffff;stroke-width:16.9642;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.52156866;paint-order:stroke fill markers"
|
||||
d="m 306.72111,24.233031 c 0,0 -11.98397,40.08696 -18.0546,60.431848 -12.96613,9.503601 -21.49377,18.397701 -21.49377,18.397701 0,0 -23.41313,-31.029398 -45.74145,-43.934598 -22.32833,-12.905201 -52.42065,-11.242483 -52.42065,-11.242483 0,0 -12.50052,4e-4 -27.63117,5.537132 -15.13066,5.536732 -21.27107,9.227888 -21.27107,9.227888 0,0 15.35165,-0.410529 37.93799,6.766716 22.58635,7.177243 32.45374,11.484796 32.45374,11.484796 l 31.02752,-6.562453 -8.44161,11.074275 c 0,0 14.80259,8.920284 22.80648,16.917787 8.0039,7.9975 11.73088,12.50812 11.73088,12.50812 0,0 -13.92373,-5.43341 -56.68427,-1.74226 -42.76055,3.69116 -84.86368,56.39265 -84.86368,56.39265 0,0 41.22428,-15.9958 65.5649,-21.32747 24.34062,-5.33166 47.58524,-7.9983 47.58524,-7.9983 0,0 -18.41865,7.3827 -38.15428,38.3474 -19.73564,30.96468 -14.0351,80.18128 -14.0351,80.18128 0,0 31.35774,-59.05848 61.39977,-78.94969 30.04203,-19.89124 36.182,-20.50642 36.182,-20.50642 0,0 -24.1209,48.39514 -33.55015,126.11445 -9.42924,77.71931 30.26089,207.72959 30.26089,207.72959 l 47.80367,-6.97298 c 0,0 -45.61041,-42.24281 -49.55753,-151.33695 -3.94713,-109.09413 16.66479,-174.30453 16.66479,-174.30453 0,0 17.10508,1.23039 42.54213,32.81027 25.43704,31.57987 40.34713,57.41795 40.34713,57.41795 0,0 9.65024,-51.26683 -11.4011,-74.64415 -21.05135,-23.3773 -53.50637,-33.62931 -53.50637,-33.62931 0,0 13.70573,-6.66419 42.10313,-4.71609 28.39738,1.94813 87.30278,27.12897 87.30278,27.12896 0,0 -15.8158,-25.5214 -52.87463,-43.21167 -37.05881,-17.69028 -81.35597,0.29238 -81.35597,0.29238 0,0 4.13589,-15.37277 29.10021,-32.628037 24.96432,-17.25527 56.907,-34.36427 56.907,-34.36427 0,0 -26.3595,1.160335 -55.20025,12.035504 -7.176,2.7059 -14.064,6.299542 -20.36309,10.173104 l 17.40574,-51.051762 z" /><path
|
||||
id="path4-2-6"
|
||||
style="fill:#ffffff;fill-opacity:0.509804;stroke:#ffffff;stroke-width:8.49614;stroke-dasharray:none;stroke-opacity:0.521569"
|
||||
d="m 105.64857,363.95957 a 27.851731,25.309928 0 0 0 -7.115581,35.20471 27.851731,25.309928 0 0 0 5.656921,5.48617 c 7.16052,5.83605 21.58543,14.65841 45.88391,17.847 37.57172,4.93039 41.7105,10.38005 41.71122,10.381 -4.5e-4,-6e-4 -4.13529,-5.45309 4.14459,-39.11953 5.35491,-21.77281 1.40624,-37.16078 -2.05217,-45.31698 a 27.851731,25.309928 0 0 0 -3.63281,-6.75471 27.851731,25.309928 0 0 0 -38.74027,-6.4662 27.851731,25.309928 0 0 0 -7.11556,35.20472 27.851731,25.309928 0 0 0 -38.74025,-6.46618 z" /><path
|
||||
id="path4-2-6-1"
|
||||
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:6.89965;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||
d="m 351.29524,378.32915 a 20.862787,22.283365 87.929759 0 0 -28.94663,11.7882 20.862787,22.283365 87.929759 0 0 -1.50914,6.04125 c -1.09835,7.13663 -1.16134,20.16231 7.28339,36.72931 13.0577,25.61689 10.90177,30.69793 10.90138,30.69882 2.4e-4,-5.6e-4 2.16,-5.08045 30.49632,-15.43688 18.32576,-6.69765 27.84648,-16.23659 32.287,-22.14109 a 20.862787,22.283365 87.929759 0 0 3.33646,-5.36755 20.862787,22.283365 87.929759 0 0 -12.45108,-27.05014 20.862787,22.283365 87.929759 0 0 -28.94664,11.78822 20.862787,22.283365 87.929759 0 0 -12.45106,-27.05014 z" /><path
|
||||
id="path4-2-6-1-5"
|
||||
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:6.89965;stroke-dasharray:none;stroke-opacity:0.52156866"
|
||||
d="m 83.024352,249.4105 a 22.283365,20.862787 0 0 0 -29.353581,10.73482 22.283365,20.862787 0 0 0 -1.72639,5.98278 c -1.35544,7.0923 -1.88894,20.10721 5.951801,36.96846 12.12378,26.07187 9.7857,31.07171 9.78528,31.07259 2.6e-4,-5.5e-4 2.34212,-4.99911 31.03406,-14.32513 18.555748,-6.03127 28.414858,-15.22005 33.065768,-20.96029 a 22.283365,20.862787 0 0 0 3.52818,-5.24352 22.283365,20.862787 0 0 0 -11.46577,-27.48227 22.283365,20.862787 0 0 0 -29.353588,10.73483 22.283365,20.862787 0 0 0 -11.46576,-27.48227 z" /><path
|
||||
id="path4-2-6-1-9"
|
||||
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:5.01078;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||
d="m 320.97602,291.36362 a 16.625347,14.748181 0 0 0 -21.90036,7.58859 16.625347,14.748181 0 0 0 -1.28804,4.2293 c -1.01128,5.01364 -1.40932,14.21406 4.44057,26.1335 9.0454,18.43055 7.30098,21.965 7.30067,21.96562 2e-4,-3.9e-4 1.74743,-3.53394 23.15415,-10.12663 13.84423,-4.26358 21.19999,-10.75925 24.66998,-14.8171 a 16.625347,14.748181 0 0 0 2.63233,-3.70671 16.625347,14.748181 0 0 0 -8.55447,-19.42758 16.625347,14.748181 0 0 0 -21.90037,7.58859 16.625347,14.748181 0 0 0 -8.55446,-19.42758 z" /><path
|
||||
id="path4-2-6-1-9-8"
|
||||
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:4.22313;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||
d="m 416.90426,193.13811 a 12.322476,14.134158 82.30909 0 0 -17.56469,8.83612 12.322476,14.134158 82.30909 0 0 -0.59553,3.65007 c -0.27175,4.26676 0.45709,11.92642 6.76182,21.10665 9.74867,14.19503 8.68847,17.32338 8.68827,17.3239 1.2e-4,-3.3e-4 1.06282,-3.12827 18.32699,-11.08266 11.16516,-5.14424 16.60821,-11.37802 19.06101,-15.14093 a 12.322476,14.134158 82.30909 0 0 1.788,-3.37453 12.322476,14.134158 82.30909 0 0 -9.45059,-15.07737 12.322476,14.134158 82.30909 0 0 -17.5647,8.83612 12.322476,14.134158 82.30909 0 0 -9.45058,-15.07737 z" /><path
|
||||
id="path4-2-6-1-9-8-4"
|
||||
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:3.48342;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||
d="m 96.169666,99.754795 a 10.296362,11.508677 62.365085 0 0 -7.330189,13.841365 10.296362,11.508677 62.365085 0 0 1.473186,2.6805 c 2.008889,2.93989 6.437543,7.66269 15.415927,10.84633 13.88288,4.92276 14.77391,7.47086 14.77407,7.4713 -1e-4,-2.8e-4 -0.88925,-2.54921 6.69094,-15.67164 4.90232,-8.48655 5.37758,-15.08279 5.10162,-18.6847 a 10.296362,11.508677 62.365085 0 0 -0.5257,-3.042454 10.296362,11.508677 62.365085 0 0 -14.1348,-5.641051 10.296362,11.508677 62.365085 0 0 -7.33021,13.841385 10.296362,11.508677 62.365085 0 0 -14.134844,-5.641035 z" /><path
|
||||
id="path4-2-6-1-9-8-4-9-2"
|
||||
style="fill:#ffffff;fill-opacity:0.5117;stroke:#ffffff;stroke-width:3.05139;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||
d="m 296.64657,233.26347 a 8.8114666,10.319195 80.445391 0 0 -11.58972,8.06989 8.8114666,10.319195 80.445391 0 0 0.0366,2.62543 c 0.35019,3.02392 1.86017,8.32306 7.60386,14.09672 8.8812,8.92759 8.51432,11.23624 8.51426,11.23663 5e-5,-2.5e-4 0.36876,-2.30885 11.85385,-9.72788 7.4277,-4.79799 10.57103,-9.75243 11.86523,-12.65455 a 8.8114666,10.319195 80.445391 0 0 0.86244,-2.55882 8.8114666,10.319195 80.445391 0 0 -8.77837,-9.57865 8.8114666,10.319195 80.445391 0 0 -11.58975,8.06989 8.8114666,10.319195 80.445391 0 0 -8.77842,-9.57866 z" /><path
|
||||
id="path4-2-6-1-9-8-4-9-2-6"
|
||||
style="fill:#ffffff;fill-opacity:0.5117;stroke:#ffffff;stroke-width:2.49738;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||
d="m 403.95446,91.44744 a 7.0950375,8.5844443 82.142743 0 0 -9.64888,6.492875 7.0950375,8.5844443 82.142743 0 0 0.0305,2.112375 c 0.29155,2.43298 1.54866,6.69657 6.33049,11.34195 7.39392,7.18298 7.08848,9.04046 7.08843,9.04078 4e-5,-2.1e-4 0.307,-1.85765 9.86876,-7.82686 6.18383,-3.86038 8.80077,-7.84663 9.87824,-10.18161 a 7.0950375,8.5844443 82.142743 0 0 0.718,-2.05879 7.0950375,8.5844443 82.142743 0 0 -7.30831,-7.706798 7.0950375,8.5844443 82.142743 0 0 -9.64889,6.492875 7.0950375,8.5844443 82.142743 0 0 -7.30834,-7.706797 z" /><path
|
||||
id="path4-2-6-1-9-8-4-9-5"
|
||||
style="fill:#ffffff;fill-opacity:0.5117;stroke:#ffffff;stroke-width:7.54176;stroke-dasharray:none;stroke-opacity:0.521569"
|
||||
d="m 410.46352,265.86621 a 24.802737,22.39469 2.0523303 0 0 -30.17074,15.95063 24.802737,22.39469 2.0523303 0 0 -0.74427,6.61415 c -0.12337,7.7333 1.79614,21.62064 13.65297,38.28529 18.33368,25.76802 16.72835,31.4347 16.72811,31.43572 1.4e-4,-6.3e-4 1.60998,-5.66652 31.32518,-20.02007 19.21759,-9.28266 28.27643,-20.56192 32.27921,-27.37361 a 24.802737,22.39469 2.0523303 0 0 2.8654,-6.11021 24.802737,22.39469 2.0523303 0 0 -17.88248,-27.36631 24.802737,22.39469 2.0523303 0 0 -30.17081,15.95066 24.802737,22.39469 2.0523303 0 0 -17.88257,-27.36625 z" /><path
|
||||
id="path4-2-6-1-9-8-5"
|
||||
style="fill:#ffffff;fill-opacity:0.50980395;stroke:#ffffff;stroke-width:3.6405;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||
d="m 114.43099,189.33754 a 10.333135,12.525309 79.004057 0 0 -14.00848,9.75499 10.333135,12.525309 79.004057 0 0 0.0547,3.08382 c 0.43602,3.54457 2.28588,9.73496 9.26636,16.38295 10.79359,10.27954 10.35819,13.00063 10.3581,13.00111 6e-5,-3e-4 0.4377,-2.72141 14.32197,-11.70923 8.9793,-5.8126 12.76786,-11.70785 14.32433,-15.14812 a 10.333135,12.525309 79.004057 0 0 1.03481,-3.02677 10.333135,12.525309 79.004057 0 0 -10.67161,-11.04688 10.333135,12.525309 79.004057 0 0 -14.00848,9.75501 10.333135,12.525309 79.004057 0 0 -10.6716,-11.04688 z" /><path
|
||||
id="path4-2-6-1-9-8-4-9-2-2"
|
||||
style="fill:#ffffff;fill-opacity:0.5117;stroke:#ffffff;stroke-width:3.62674;stroke-dasharray:none;stroke-opacity:0.519962"
|
||||
d="m 178.56055,273.32338 a 10.656883,12.053184 66.089768 0 0 -7.97821,14.16205 10.656883,12.053184 66.089768 0 0 1.49012,2.79504 c 2.04675,3.07265 6.5954,8.03049 15.94965,11.48124 14.46412,5.33577 15.34612,7.98353 15.34628,7.98398 -8e-5,-2.8e-4 -0.88012,-2.64887 7.3455,-16.0639 5.31973,-8.67576 5.95524,-15.47956 5.74045,-19.20452 a 10.656883,12.053184 66.089768 0 0 -0.48843,-3.15169 10.656883,12.053184 66.089768 0 0 -14.7135,-6.08217 10.656883,12.053184 66.089768 0 0 -7.97826,14.1621 10.656883,12.053184 66.089768 0 0 -14.71355,-6.08215 z" /></svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 256 KiB After Width: | Height: | Size: 256 KiB |
|
Before Width: | Height: | Size: 332 KiB After Width: | Height: | Size: 379 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 79 KiB |
@@ -6,4 +6,7 @@ Debugging on physical hardware can get tedious and time consuming. Users are emp
|
||||
|
||||
**Standard key prefix**: Allows to redirect the key manager to a file other than `prod.keys` (for example `other` would redirect to `other.keys`). This is useful for testing multiple keysets. Default is `prod`.
|
||||
|
||||
**Changing serial**: Very basic way to set debug values for the serial (and battery number). Developers do not need to write the full serial as only the first digits (excluding the last) will be accoutned for. Region settings will affect the generated serial. The serial corresponds to a non-OLED/Lite console.
|
||||
**Changing serial**: Very basic way to set debug values for the serial (and battery number). Developers do not need to write the full serial as it will be writen in-place (that is, it will be filled with the default serial and then overwrite the serial from the beginning).
|
||||
- Battery serial: `YUZU0EMULATOR14022024`
|
||||
- Board serial: `YUZ10000000001`
|
||||
If the user were to set their board serial as `ABC`, then it will be written in-place and the resulting serial would be `ABC10000000001`. There are no underlying checks to ensure correctness of serials other than a hard limit of 16-characters for both.
|
||||
|
||||
@@ -407,10 +407,12 @@ if (APPLE)
|
||||
# moltenvk
|
||||
if (NOT YUZU_USE_BUNDLED_MOLTENVK)
|
||||
find_library(MOLTENVK_LIBRARY MoltenVK)
|
||||
else()
|
||||
unset(MOLTENVK_LIBRARY)
|
||||
endif()
|
||||
|
||||
# TODO: kosmickrisp?
|
||||
if (NOT MOLTENVK_LIBRARY OR YUZU_USE_BUNDLED_MOLTENVK)
|
||||
if (NOT MOLTENVK_LIBRARY)
|
||||
AddJsonPackage(moltenvk)
|
||||
|
||||
set(MOLTENVK_LIBRARY "${moltenvk_SOURCE_DIR}/MoltenVK/dylib/macOS/libMoltenVK.dylib" CACHE STRING "" FORCE)
|
||||
|
||||
|
Before Width: | Height: | Size: 267 KiB After Width: | Height: | Size: 288 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 168 KiB |
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 203 KiB |
@@ -534,8 +534,8 @@
|
||||
<item>@string/frame_pacing_mode_target_Auto</item>
|
||||
<item>@string/frame_pacing_mode_target_30</item>
|
||||
<item>@string/frame_pacing_mode_target_60</item>
|
||||
<item>@string/frame_pacing_mode_target_90</item>
|
||||
<item>@string/frame_pacing_mode_target_120</item>
|
||||
<item>@string/frame_pacing_mode_target_240</item>
|
||||
</string-array>
|
||||
<integer-array name="framePacingModeValues">
|
||||
<item>0</item>
|
||||
|
||||
@@ -1 +1 @@
|
||||
<?xml version='1.0' encoding='utf-8'?><resources><color name='ic_launcher_background'>#1F143C</color></resources>
|
||||
<?xml version='1.0' encoding='utf-8'?><resources><color name='ic_launcher_background'>#e48cc9ff</color></resources>
|
||||
|
||||
@@ -1038,8 +1038,8 @@
|
||||
<string name="frame_pacing_mode_target_Auto">Auto</string>
|
||||
<string name="frame_pacing_mode_target_30">30 FPS</string>
|
||||
<string name="frame_pacing_mode_target_60">60 FPS</string>
|
||||
<string name="frame_pacing_mode_target_90">90 FPS</string>
|
||||
<string name="frame_pacing_mode_target_120">120 FPS</string>
|
||||
<string name="frame_pacing_mode_target_240">240 FPS</string>
|
||||
|
||||
<!-- ASTC Decoding Method Choices -->
|
||||
<string name="accelerate_astc_cpu" translatable="false">CPU</string>
|
||||
|
||||
@@ -186,8 +186,6 @@ if(ARCHITECTURE_x86_64)
|
||||
common
|
||||
PRIVATE x64/cpu_detect.cpp
|
||||
x64/cpu_detect.h
|
||||
x64/cpu_wait.cpp
|
||||
x64/cpu_wait.h
|
||||
x64/native_clock.cpp
|
||||
x64/native_clock.h
|
||||
x64/rdtsc.cpp
|
||||
|
||||
@@ -219,6 +219,11 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
bool ClearBackingRegion(size_t physical_offset, size_t length) {
|
||||
// TODO: This does not seem to be possible on Windows.
|
||||
return false;
|
||||
}
|
||||
|
||||
void EnableDirectMappedAddress() {
|
||||
// TODO
|
||||
UNREACHABLE();
|
||||
@@ -612,6 +617,24 @@ public:
|
||||
ASSERT_MSG(ret == 0, "mprotect failed: {}", strerror(errno));
|
||||
}
|
||||
|
||||
bool ClearBackingRegion(size_t physical_offset, size_t length) {
|
||||
#ifdef __linux__
|
||||
// Only incur syscall cost IF memset would be slower (theshold = 16MiB)
|
||||
// TODO(lizzie): Smarter way to dynamically get this threshold (broadwell != raptor lake) for example
|
||||
if (length >= 2097152UL * 8) {
|
||||
// Set MADV_REMOVE on backing map to destroy it instantly.
|
||||
// This also deletes the area from the backing file.
|
||||
int ret = madvise(backing_base + physical_offset, length, MADV_REMOVE);
|
||||
ASSERT_MSG(ret == 0, "madvise failed: {}", strerror(errno));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void EnableDirectMappedAddress() {
|
||||
virtual_base = nullptr;
|
||||
}
|
||||
@@ -725,7 +748,9 @@ void HostMemory::Protect(size_t virtual_offset, size_t length, MemoryPermission
|
||||
}
|
||||
|
||||
void HostMemory::ClearBackingRegion(size_t physical_offset, size_t length, u32 fill_value) {
|
||||
std::memset(backing_base + physical_offset, fill_value, length);
|
||||
if (!impl || fill_value != 0 || !impl->ClearBackingRegion(physical_offset, length)) {
|
||||
std::memset(backing_base + physical_offset, fill_value, length);
|
||||
}
|
||||
}
|
||||
|
||||
void HostMemory::EnableDirectMappedAddress() {
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/div_ceil.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
template <typename AddressType, u32 PageBits, u64 MaxAddress>
|
||||
class PageBitsetRangeSet {
|
||||
public:
|
||||
PageBitsetRangeSet() : m_words(kWordCount) {
|
||||
static_assert((MaxAddress % kPageSize) == 0, "MaxAddress must be page-aligned.");
|
||||
}
|
||||
|
||||
void Add(AddressType base_address, size_t size) {
|
||||
Modify(base_address, size, true);
|
||||
}
|
||||
|
||||
void Subtract(AddressType base_address, size_t size) {
|
||||
Modify(base_address, size, false);
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
std::fill(m_words.begin(), m_words.end(), 0);
|
||||
}
|
||||
|
||||
bool Empty() const {
|
||||
return std::none_of(m_words.begin(), m_words.end(), [](u64 word) { return word != 0; });
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
void ForEachInRange(AddressType base_address, size_t size, Func&& func) const {
|
||||
if (size == 0 || m_words.empty()) {
|
||||
return;
|
||||
}
|
||||
const AddressType end_address = base_address + static_cast<AddressType>(size);
|
||||
const u64 start_page = static_cast<u64>(base_address) >> PageBits;
|
||||
const u64 end_page = Common::DivCeil(static_cast<u64>(end_address), kPageSize);
|
||||
const u64 clamped_start = (std::min)(start_page, kPageCount);
|
||||
const u64 clamped_end = (std::min)(end_page, kPageCount);
|
||||
if (clamped_start >= clamped_end) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool in_run = false;
|
||||
u64 run_start_page = 0;
|
||||
for (u64 page = clamped_start; page < clamped_end; ++page) {
|
||||
if (Test(page)) {
|
||||
if (!in_run) {
|
||||
in_run = true;
|
||||
run_start_page = page;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (in_run) {
|
||||
EmitRun(run_start_page, page, base_address, end_address, func);
|
||||
in_run = false;
|
||||
}
|
||||
}
|
||||
if (in_run) {
|
||||
EmitRun(run_start_page, clamped_end, base_address, end_address, func);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr u64 kPageSize = u64{1} << PageBits;
|
||||
static constexpr u64 kPageCount = MaxAddress / kPageSize;
|
||||
static constexpr u64 kWordCount = (kPageCount + 63) / 64;
|
||||
|
||||
void Modify(AddressType base_address, size_t size, bool set_bits) {
|
||||
if (size == 0 || m_words.empty()) {
|
||||
return;
|
||||
}
|
||||
const AddressType end_address = base_address + static_cast<AddressType>(size);
|
||||
const u64 start_page = static_cast<u64>(base_address) >> PageBits;
|
||||
const u64 end_page = Common::DivCeil(static_cast<u64>(end_address), kPageSize);
|
||||
const u64 clamped_start = (std::min)(start_page, kPageCount);
|
||||
const u64 clamped_end = (std::min)(end_page, kPageCount);
|
||||
if (clamped_start >= clamped_end) {
|
||||
return;
|
||||
}
|
||||
const u64 start_word = clamped_start / 64;
|
||||
const u64 end_word = (clamped_end - 1) / 64;
|
||||
const u64 start_mask = ~0ULL << (clamped_start % 64);
|
||||
const u64 end_mask = (clamped_end % 64) == 0 ? ~0ULL : ((1ULL << (clamped_end % 64)) - 1);
|
||||
|
||||
if (start_word == end_word) {
|
||||
const u64 mask = start_mask & end_mask;
|
||||
if (set_bits) {
|
||||
m_words[start_word] |= mask;
|
||||
} else {
|
||||
m_words[start_word] &= ~mask;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (set_bits) {
|
||||
m_words[start_word] |= start_mask;
|
||||
m_words[end_word] |= end_mask;
|
||||
std::fill(m_words.begin() + static_cast<std::ptrdiff_t>(start_word + 1),
|
||||
m_words.begin() + static_cast<std::ptrdiff_t>(end_word), ~0ULL);
|
||||
} else {
|
||||
m_words[start_word] &= ~start_mask;
|
||||
m_words[end_word] &= ~end_mask;
|
||||
std::fill(m_words.begin() + static_cast<std::ptrdiff_t>(start_word + 1),
|
||||
m_words.begin() + static_cast<std::ptrdiff_t>(end_word), 0ULL);
|
||||
}
|
||||
}
|
||||
|
||||
bool Test(u64 page) const {
|
||||
const u64 word = page / 64;
|
||||
const u64 bit = page % 64;
|
||||
return (m_words[word] & (1ULL << bit)) != 0;
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
static void EmitRun(u64 run_start_page, u64 run_end_page, AddressType base_address,
|
||||
AddressType end_address, Func&& func) {
|
||||
AddressType run_start = static_cast<AddressType>(run_start_page * kPageSize);
|
||||
AddressType run_end = static_cast<AddressType>(run_end_page * kPageSize);
|
||||
if (run_start < base_address) {
|
||||
run_start = base_address;
|
||||
}
|
||||
if (run_end > end_address) {
|
||||
run_end = end_address;
|
||||
}
|
||||
if (run_start < run_end) {
|
||||
func(run_start, run_end);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<u64> m_words;
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -116,28 +119,25 @@ struct OverlapRangeSet<AddressType>::OverlapRangeSetImpl {
|
||||
}
|
||||
AddressType end_address = base_address + static_cast<AddressType>(size);
|
||||
IntervalType interval{base_address, end_address};
|
||||
bool any_removals = false;
|
||||
m_split_ranges_set += std::make_pair(interval, -amount);
|
||||
do {
|
||||
any_removals = false;
|
||||
auto it = m_split_ranges_set.lower_bound(interval);
|
||||
if (it == m_split_ranges_set.end()) {
|
||||
return;
|
||||
}
|
||||
auto end_it = m_split_ranges_set.upper_bound(interval);
|
||||
for (; it != end_it; it++) {
|
||||
if (it->second <= 0) {
|
||||
if constexpr (has_on_delete) {
|
||||
if (it->second == 0) {
|
||||
on_delete(it->first.lower(), it->first.upper());
|
||||
}
|
||||
auto it = m_split_ranges_set.lower_bound(interval);
|
||||
if (it == m_split_ranges_set.end()) {
|
||||
return;
|
||||
}
|
||||
auto end_it = m_split_ranges_set.upper_bound(interval);
|
||||
while (it != end_it) {
|
||||
if (it->second <= 0) {
|
||||
if constexpr (has_on_delete) {
|
||||
if (it->second == 0) {
|
||||
on_delete(it->first.lower(), it->first.upper());
|
||||
}
|
||||
any_removals = true;
|
||||
m_split_ranges_set.erase(it);
|
||||
break;
|
||||
}
|
||||
auto to_erase = it++;
|
||||
m_split_ranges_set.erase(to_erase);
|
||||
continue;
|
||||
}
|
||||
} while (any_removals);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#define COMPILER_ID "@CXX_COMPILER@"
|
||||
#define BUILD_AUTO_UPDATE_WEBSITE "@BUILD_AUTO_UPDATE_WEBSITE@"
|
||||
#define BUILD_AUTO_UPDATE_API "@BUILD_AUTO_UPDATE_API@"
|
||||
#define BUILD_AUTO_UPDATE_API_PATH "@BUILD_AUTO_UPDATE_API_PATH@"
|
||||
#define BUILD_AUTO_UPDATE_REPO "@BUILD_AUTO_UPDATE_REPO@"
|
||||
#define IS_NIGHTLY_BUILD @IS_NIGHTLY_BUILD@
|
||||
|
||||
@@ -43,7 +42,6 @@ constexpr const bool g_is_nightly_build = IS_NIGHTLY_BUILD;
|
||||
|
||||
constexpr const char g_build_auto_update_website[] = BUILD_AUTO_UPDATE_WEBSITE;
|
||||
constexpr const char g_build_auto_update_api[] = BUILD_AUTO_UPDATE_API;
|
||||
constexpr const char g_build_auto_update_api_path[] = BUILD_AUTO_UPDATE_API_PATH;
|
||||
constexpr const char g_build_auto_update_repo[] = BUILD_AUTO_UPDATE_REPO;
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -26,7 +26,6 @@ extern const bool g_is_nightly_build;
|
||||
|
||||
extern const char g_build_auto_update_website[];
|
||||
extern const char g_build_auto_update_api[];
|
||||
extern const char g_build_auto_update_api_path[];
|
||||
extern const char g_build_auto_update_repo[];
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -462,12 +462,9 @@ struct Values {
|
||||
SwitchableSetting<FramePacingMode, true> frame_pacing_mode{linkage,
|
||||
FramePacingMode::Target_Auto,
|
||||
FramePacingMode::Target_Auto,
|
||||
FramePacingMode::Target_120,
|
||||
FramePacingMode::Target_240,
|
||||
"frame_pacing_mode",
|
||||
Category::RendererAdvanced,
|
||||
Specialization::Default,
|
||||
true,
|
||||
true};
|
||||
Category::RendererAdvanced};
|
||||
|
||||
SwitchableSetting<AstcRecompression, true> astc_recompression{linkage,
|
||||
AstcRecompression::Uncompressed,
|
||||
@@ -623,11 +620,11 @@ struct Values {
|
||||
"language_index",
|
||||
Category::System};
|
||||
SwitchableSetting<Region, true> region_index{linkage, Region::Usa, "region_index", Category::System};
|
||||
SwitchableSetting<TimeZone, true> time_zone_index{linkage, TimeZone::Auto, "time_zone_index", Category::System};
|
||||
Setting<u32> serial_battery{linkage, 0, "serial_battery", Category::System};
|
||||
Setting<u32> serial_unit{linkage, 0, "serial_unit", Category::System};
|
||||
SwitchableSetting<TimeZone, true> time_zone_index{linkage, TimeZone::Auto,
|
||||
"time_zone_index", Category::System};
|
||||
// Measured in seconds since epoch
|
||||
SwitchableSetting<bool> custom_rtc_enabled{linkage, false, "custom_rtc_enabled", Category::System, Specialization::Paired, true, true};
|
||||
SwitchableSetting<bool> custom_rtc_enabled{
|
||||
linkage, false, "custom_rtc_enabled", Category::System, Specialization::Paired, true, true};
|
||||
SwitchableSetting<s64> custom_rtc{
|
||||
linkage, 0, "custom_rtc", Category::System, Specialization::Time,
|
||||
false, true, &custom_rtc_enabled};
|
||||
@@ -797,6 +794,8 @@ struct Values {
|
||||
true};
|
||||
|
||||
// Miscellaneous
|
||||
Setting<std::string> serial_battery{linkage, std::string(), "serial_battery", Category::Miscellaneous};
|
||||
Setting<std::string> serial_unit{linkage, std::string(), "serial_unit", Category::Miscellaneous};
|
||||
Setting<std::string> log_filter{linkage, "*:Info", "log_filter", Category::Miscellaneous};
|
||||
Setting<bool> log_flush_line{linkage, false, "flush_line", Category::Miscellaneous, Specialization::Default, true, true};
|
||||
Setting<bool> censor_username{linkage, true, "censor_username", Category::Miscellaneous};
|
||||
|
||||
@@ -129,7 +129,7 @@ ENUM(TimeZone, Auto, Default, Cet, Cst6Cdt, Cuba, Eet, Egypt, Eire, Est, Est5Edt
|
||||
ENUM(AnisotropyMode, Automatic, Default, X2, X4, X8, X16, X32, X64, None);
|
||||
ENUM(AstcDecodeMode, Cpu, Gpu, CpuAsynchronous);
|
||||
ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
|
||||
ENUM(FramePacingMode, Target_Auto, Target_30, Target_60, Target_90, Target_120);
|
||||
ENUM(FramePacingMode, Target_Auto, Target_30, Target_60, Target_120, Target_240);
|
||||
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
|
||||
ENUM(VramUsageMode, Conservative, Aggressive);
|
||||
ENUM(RendererBackend, OpenGL_GLSL, Vulkan, Null, OpenGL_GLASM, OpenGL_SPIRV);
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <thread>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#include "common/x64/cpu_detect.h"
|
||||
#include "common/x64/cpu_wait.h"
|
||||
#include "common/x64/rdtsc.h"
|
||||
|
||||
namespace Common::X64 {
|
||||
|
||||
namespace {
|
||||
|
||||
// 100,000 cycles is a reasonable amount of time to wait to save on CPU resources.
|
||||
// For reference:
|
||||
// At 1 GHz, 100K cycles is 100us
|
||||
// At 2 GHz, 100K cycles is 50us
|
||||
// At 4 GHz, 100K cycles is 25us
|
||||
constexpr auto PauseCycles = 100'000U;
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
__forceinline static void TPAUSE() {
|
||||
static constexpr auto RequestC02State = 0U;
|
||||
_tpause(RequestC02State, FencedRDTSC() + PauseCycles);
|
||||
}
|
||||
|
||||
__forceinline static void MWAITX() {
|
||||
static constexpr auto EnableWaitTimeFlag = 1U << 1;
|
||||
static constexpr auto RequestC1State = 0U;
|
||||
|
||||
// monitor_var should be aligned to a cache line.
|
||||
alignas(64) u64 monitor_var{};
|
||||
_mm_monitorx(&monitor_var, 0, 0);
|
||||
_mm_mwaitx(EnableWaitTimeFlag, RequestC1State, PauseCycles);
|
||||
}
|
||||
#else
|
||||
static void TPAUSE() {
|
||||
static constexpr auto RequestC02State = 0U;
|
||||
const auto tsc = FencedRDTSC() + PauseCycles;
|
||||
const auto eax = static_cast<u32>(tsc & 0xFFFFFFFF);
|
||||
const auto edx = static_cast<u32>(tsc >> 32);
|
||||
asm volatile("tpause %0" : : "r"(RequestC02State), "d"(edx), "a"(eax));
|
||||
}
|
||||
|
||||
static void MWAITX() {
|
||||
static constexpr auto EnableWaitTimeFlag = 1U << 1;
|
||||
static constexpr auto RequestC1State = 0U;
|
||||
|
||||
// monitor_var should be aligned to a cache line.
|
||||
alignas(64) u64 monitor_var{};
|
||||
asm volatile("monitorx" : : "a"(&monitor_var), "c"(0), "d"(0));
|
||||
asm volatile("mwaitx" : : "a"(RequestC1State), "b"(PauseCycles), "c"(EnableWaitTimeFlag));
|
||||
}
|
||||
#endif
|
||||
|
||||
void MicroSleep() {
|
||||
static const bool has_waitpkg = GetCPUCaps().waitpkg;
|
||||
static const bool has_monitorx = GetCPUCaps().monitorx;
|
||||
|
||||
if (has_waitpkg) {
|
||||
TPAUSE();
|
||||
} else if (has_monitorx) {
|
||||
MWAITX();
|
||||
} else {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Common::X64
|
||||
@@ -1,10 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Common::X64 {
|
||||
|
||||
void MicroSleep();
|
||||
|
||||
} // namespace Common::X64
|
||||
@@ -1219,7 +1219,6 @@ target_link_libraries(core PRIVATE
|
||||
fmt::fmt
|
||||
nlohmann_json::nlohmann_json
|
||||
RenderDoc::API
|
||||
ZLIB::ZLIB
|
||||
MbedTLS::mbedcrypto${MBEDTLS_LIB_SUFFIX}
|
||||
MbedTLS::mbedtls${MBEDTLS_LIB_SUFFIX})
|
||||
|
||||
|
||||
@@ -13,10 +13,6 @@
|
||||
#include "common/windows/timer_resolution.h"
|
||||
#endif
|
||||
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
#include "common/x64/cpu_wait.h"
|
||||
#endif
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hardware_properties.h"
|
||||
@@ -287,28 +283,7 @@ void CoreTiming::ThreadLoop() {
|
||||
if (next_time) {
|
||||
// There are more events left in the queue, wait until the next event.
|
||||
auto wait_time = *next_time - GetGlobalTimeNs().count();
|
||||
if (wait_time > 0) {
|
||||
#ifdef _WIN32
|
||||
while (!paused && !event.IsSet() && wait_time > 0) {
|
||||
wait_time = *next_time - GetGlobalTimeNs().count();
|
||||
if (wait_time >= timer_resolution_ns) {
|
||||
Common::Windows::SleepForOneTick();
|
||||
} else {
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
Common::X64::MicroSleep();
|
||||
#else
|
||||
std::this_thread::yield();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (event.IsSet()) {
|
||||
event.Reset();
|
||||
}
|
||||
#else
|
||||
event.WaitFor(std::chrono::nanoseconds(wait_time));
|
||||
#endif
|
||||
}
|
||||
event.WaitFor(std::chrono::nanoseconds(wait_time));
|
||||
} else {
|
||||
// Queue is empty, wait until another event is scheduled and signals us to
|
||||
// continue.
|
||||
|
||||
@@ -4,13 +4,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <span>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "common/string_util.h"
|
||||
#include "common/swap.h"
|
||||
@@ -38,73 +31,6 @@ const std::array<const char*, 16> LANGUAGE_NAMES{{
|
||||
"BrazilianPortuguese",
|
||||
}};
|
||||
|
||||
namespace {
|
||||
constexpr std::size_t LEGACY_LANGUAGE_REGION_SIZE = sizeof(std::array<LanguageEntry, 16>);
|
||||
constexpr std::size_t PACKED_LANGUAGE_REGION_MAX_SIZE = sizeof(LanguageEntry) * 32;
|
||||
|
||||
bool InflateRawDeflate(std::span<const u8> compressed, std::vector<u8>& out) {
|
||||
if (compressed.empty() || compressed.size() > std::numeric_limits<uInt>::max()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
z_stream stream{};
|
||||
stream.next_in = const_cast<Bytef*>(reinterpret_cast<const Bytef*>(compressed.data()));
|
||||
stream.avail_in = static_cast<uInt>(compressed.size());
|
||||
if (inflateInit2(&stream, -MAX_WBITS) != Z_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::array<u8, 0x1000> chunk{};
|
||||
int ret = Z_OK;
|
||||
while (ret == Z_OK) {
|
||||
stream.next_out = reinterpret_cast<Bytef*>(chunk.data());
|
||||
stream.avail_out = static_cast<uInt>(chunk.size());
|
||||
ret = inflate(&stream, Z_NO_FLUSH);
|
||||
if (ret != Z_OK && ret != Z_STREAM_END) {
|
||||
inflateEnd(&stream);
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto produced = chunk.size() - static_cast<std::size_t>(stream.avail_out);
|
||||
if (produced != 0) {
|
||||
if (out.size() + produced > PACKED_LANGUAGE_REGION_MAX_SIZE) {
|
||||
inflateEnd(&stream);
|
||||
return false;
|
||||
}
|
||||
out.insert(out.end(), chunk.begin(),
|
||||
chunk.begin() + static_cast<std::ptrdiff_t>(produced));
|
||||
}
|
||||
}
|
||||
|
||||
inflateEnd(&stream);
|
||||
return ret == Z_STREAM_END;
|
||||
}
|
||||
|
||||
void DecodePackedLanguageEntries(RawNACP& raw) {
|
||||
auto* packed_region = reinterpret_cast<u8*>(raw.language_entries.data());
|
||||
u16_le compressed_size_le{};
|
||||
std::memcpy(&compressed_size_le, packed_region, sizeof(compressed_size_le));
|
||||
const auto compressed_size = static_cast<std::size_t>(compressed_size_le);
|
||||
|
||||
if (compressed_size == 0 || compressed_size > LEGACY_LANGUAGE_REGION_SIZE - sizeof(u16_le)) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<u8> decompressed;
|
||||
if (!InflateRawDeflate(
|
||||
std::span<const u8>(packed_region + sizeof(u16_le), compressed_size), decompressed)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (decompressed.size() < LEGACY_LANGUAGE_REGION_SIZE ||
|
||||
decompressed.size() % sizeof(LanguageEntry) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::memcpy(raw.language_entries.data(), decompressed.data(), LEGACY_LANGUAGE_REGION_SIZE);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::string LanguageEntry::GetApplicationName() const {
|
||||
return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(),
|
||||
application_name.size());
|
||||
@@ -140,7 +66,6 @@ NACP::NACP() = default;
|
||||
|
||||
NACP::NACP(VirtualFile file) {
|
||||
file->ReadObject(&raw);
|
||||
DecodePackedLanguageEntries(raw);
|
||||
}
|
||||
|
||||
NACP::~NACP() = default;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
@@ -980,82 +980,25 @@ Result ISystemSettingsServer::SetPrimaryAlbumStorage(PrimaryAlbumStorage primary
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
static void Fill3DS_CRC(u32 d, char* data) {
|
||||
std::array<u8, 10> digits = {
|
||||
u8((d / 1000000000) % 100),
|
||||
u8((d / 100000000) % 10),
|
||||
u8((d / 10000000) % 10),
|
||||
u8((d / 1000000) % 10),
|
||||
u8((d / 100000) % 10),
|
||||
u8((d / 10000) % 10),
|
||||
u8((d / 1000) % 10),
|
||||
u8((d / 100) % 10),
|
||||
u8((d / 10) % 10),
|
||||
u8(d % 10),
|
||||
};
|
||||
// Normalize to retail values
|
||||
std::array<u8, 4> retail_digits = { 1, 4, 5, 7 };
|
||||
digits[0] = retail_digits[(d % 10) % 4];
|
||||
digits[1] = 0;
|
||||
//
|
||||
for (size_t i = 0; i < sizeof(digits); ++i)
|
||||
data[i] = char(digits[i] + '0');
|
||||
u8 sum_odd = 0, sum_even = 0;
|
||||
for (size_t i = 0; i < sizeof(digits); i += 2) {
|
||||
sum_odd += digits[i + 0];
|
||||
sum_even += digits[i + 1];
|
||||
}
|
||||
u8 sum_digit = u8(((sum_even * 3) + sum_odd) % 10);
|
||||
if (sum_digit != 0)
|
||||
sum_digit = 10 - sum_digit;
|
||||
data[sizeof(digits)] = char(sum_digit + '0');
|
||||
}
|
||||
|
||||
Result ISystemSettingsServer::GetBatteryLot(Out<BatteryLot> out_battery_lot) {
|
||||
LOG_INFO(Service_SET, "called");
|
||||
*out_battery_lot = []{
|
||||
u32 d = ::Settings::values.serial_battery.GetValue();
|
||||
BatteryLot c{};
|
||||
c.lot_number[0] = 'B';
|
||||
c.lot_number[1] = 'H';
|
||||
c.lot_number[2] = 'A';
|
||||
c.lot_number[3] = 'C';
|
||||
// TODO: I have no fucking idea what the letters mean
|
||||
c.lot_number[4] = 'H';
|
||||
c.lot_number[5] = 'Z';
|
||||
c.lot_number[6] = 'Z';
|
||||
c.lot_number[7] = 'A';
|
||||
c.lot_number[8] = 'D';
|
||||
c.lot_number[9] = char(((d / 100000) % 26) + 'A');
|
||||
Fill3DS_CRC(d, c.lot_number.data() + 10);
|
||||
return c;
|
||||
}();
|
||||
*out_battery_lot = {"YUZU0EMULATOR14022024"};
|
||||
if (auto const s = ::Settings::values.serial_battery.GetValue(); !s.empty()) {
|
||||
auto const max_size = out_battery_lot->lot_number.size();
|
||||
auto const end = s.size() > max_size ? s.begin() + max_size : s.end();
|
||||
std::copy(s.begin(), end, out_battery_lot->lot_number.begin());
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ISystemSettingsServer::GetSerialNumber(Out<SerialNumber> out_console_serial) {
|
||||
LOG_INFO(Service_SET, "called");
|
||||
*out_console_serial = []{
|
||||
u32 d = ::Settings::values.serial_unit.GetValue();
|
||||
SerialNumber c{};
|
||||
c.serial_number[0] = 'X';
|
||||
c.serial_number[1] = 'A';
|
||||
c.serial_number[2] = [] {
|
||||
// Adding another setting would be tedious so... let's just reuse region_index :)
|
||||
switch (::Settings::values.region_index.GetValue()) {
|
||||
case ::Settings::Region::Japan: return 'J';
|
||||
case ::Settings::Region::Usa: return 'W';
|
||||
case ::Settings::Region::Europe: return 'E';
|
||||
case ::Settings::Region::Australia: return 'M'; //pretend its Malaysia
|
||||
case ::Settings::Region::China:
|
||||
case ::Settings::Region::Taiwan: return 'C';
|
||||
case ::Settings::Region::Korea: return 'K';
|
||||
default: return 'W';
|
||||
}
|
||||
}();
|
||||
Fill3DS_CRC(d, c.serial_number.data() + 3);
|
||||
return c;
|
||||
}();
|
||||
*out_console_serial = {"YUZ10000000001"};
|
||||
if (auto const s = ::Settings::values.serial_unit.GetValue(); !s.empty()) {
|
||||
auto const max_size = out_console_serial->serial_number.size();
|
||||
auto const end = s.size() > max_size ? s.begin() + max_size : s.end();
|
||||
std::copy(s.begin(), end, out_console_serial->serial_number.begin());
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
@@ -178,7 +178,7 @@ void LoopProcess(Core::System& system) {
|
||||
auto module = std::make_shared<Module>();
|
||||
|
||||
server_manager->RegisterNamedService("csrng", std::make_shared<CSRNG>(system, module));
|
||||
server_manager->RegisterNamedService("spl:", std::make_shared<SPL>(system, module));
|
||||
server_manager->RegisterNamedService("spl", std::make_shared<SPL>(system, module));
|
||||
server_manager->RegisterNamedService("spl:mig", std::make_shared<SPL_MIG>(system, module));
|
||||
server_manager->RegisterNamedService("spl:fs", std::make_shared<SPL_FS>(system, module));
|
||||
server_manager->RegisterNamedService("spl:ssl", std::make_shared<SPL_SSL>(system, module));
|
||||
|
||||
@@ -105,6 +105,9 @@ add_library(dynarmic STATIC
|
||||
frontend/A32/decoder/thumb32.inc
|
||||
frontend/A32/decoder/vfp.h
|
||||
frontend/A32/decoder/vfp.inc
|
||||
frontend/A32/disassembler/disassembler.h
|
||||
frontend/A32/disassembler/disassembler_arm.cpp
|
||||
frontend/A32/disassembler/disassembler_thumb.cpp
|
||||
frontend/A32/FPSCR.h
|
||||
frontend/A32/ITState.h
|
||||
frontend/A32/PSR.h
|
||||
@@ -119,6 +122,7 @@ add_library(dynarmic STATIC
|
||||
interface/A32/config.h
|
||||
interface/A32/coprocessor.h
|
||||
interface/A32/coprocessor_util.h
|
||||
interface/A32/disassembler.h
|
||||
# A64
|
||||
frontend/A64/a64_ir_emitter.cpp
|
||||
frontend/A64/a64_ir_emitter.h
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <fmt/format.h>
|
||||
#include <fmt/ostream.h>
|
||||
#include <mcl/type_traits/integer_of_size.hpp>
|
||||
#include "dynarmic/backend/x64/xbyak.h"
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
#include "dynarmic/backend/x64/a32_emit_x64.h"
|
||||
#include "dynarmic/backend/x64/abi.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <fmt/format.h>
|
||||
#include <fmt/ostream.h>
|
||||
#include <mcl/type_traits/integer_of_size.hpp>
|
||||
#include "dynarmic/backend/x64/xbyak.h"
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
#include "dynarmic/backend/x64/a64_emit_x64.h"
|
||||
#include "dynarmic/backend/x64/abi.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "dynarmic/common/common_types.h"
|
||||
#include "dynarmic/backend/x64/xbyak.h"
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
#include "dynarmic/backend/x64/block_of_code.h"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#include "dynarmic/common/assert.h"
|
||||
#include <mcl/bit/bit_field.hpp>
|
||||
#include "dynarmic/backend/x64/xbyak.h"
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
#include "dynarmic/backend/x64/a32_jitstate.h"
|
||||
#include "dynarmic/backend/x64/abi.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
@@ -15,7 +15,9 @@
|
||||
|
||||
#include <mcl/bit/bit_field.hpp>
|
||||
#include "dynarmic/common/common_types.h"
|
||||
#include "dynarmic/backend/x64/xbyak.h"
|
||||
#include <xbyak/xbyak.h>
|
||||
#include <xbyak/xbyak_util.h>
|
||||
|
||||
#include "dynarmic/backend/x64/abi.h"
|
||||
#include "dynarmic/backend/x64/callback.h"
|
||||
#include "dynarmic/backend/x64/constant_pool.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "dynarmic/common/common_types.h"
|
||||
#include "dynarmic/backend/x64/xbyak.h"
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
namespace Dynarmic::Backend::X64 {
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#include "dynarmic/common/common_types.h"
|
||||
#include <ankerl/unordered_dense.h>
|
||||
#include "dynarmic/backend/x64/xbyak.h"
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
namespace Dynarmic::Backend::X64 {
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
|
||||
#include <mcl/bitsizeof.hpp>
|
||||
#include <ankerl/unordered_dense.h>
|
||||
#include "dynarmic/backend/x64/xbyak.h"
|
||||
#include <xbyak/xbyak.h>
|
||||
#include <xbyak/xbyak_util.h>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
#include "dynarmic/backend/exception_handler.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
@@ -19,7 +19,7 @@
|
||||
#include <mcl/mp/typelist/lower_to_tuple.hpp>
|
||||
#include "dynarmic/common/common_types.h"
|
||||
#include <mcl/type_traits/integer_of_size.hpp>
|
||||
#include "dynarmic/backend/x64/xbyak.h"
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
#include "dynarmic/backend/x64/abi.h"
|
||||
#include "dynarmic/backend/x64/block_of_code.h"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <bit>
|
||||
#include "dynarmic/backend/x64/xbyak.h"
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
#include "dynarmic/backend/x64/a32_emit_x64.h"
|
||||
#include "dynarmic/backend/x64/a64_emit_x64.h"
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <mcl/bitsizeof.hpp>
|
||||
#include "dynarmic/common/common_types.h"
|
||||
#include <mcl/type_traits/function_info.hpp>
|
||||
#include "dynarmic/backend/x64/xbyak.h"
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
#include "dynarmic/backend/x64/abi.h"
|
||||
#include "dynarmic/backend/x64/block_of_code.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <mcl/mp/typelist/lower_to_tuple.hpp>
|
||||
#include <mcl/type_traits/function_info.hpp>
|
||||
#include <mcl/type_traits/integer_of_size.hpp>
|
||||
#include "dynarmic/backend/x64/xbyak.h"
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
#include "dynarmic/backend/x64/abi.h"
|
||||
#include "dynarmic/backend/x64/block_of_code.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include "dynarmic/common/assert.h"
|
||||
#include "dynarmic/common/common_types.h"
|
||||
#include "dynarmic/backend/x64/xbyak.h"
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
namespace Dynarmic::Backend::X64 {
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
@@ -9,7 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "dynarmic/common/assert.h"
|
||||
#include "dynarmic/backend/x64/xbyak.h"
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
namespace Dynarmic::Backend::X64 {
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
@@ -16,7 +16,7 @@
|
||||
#include <fmt/ostream.h>
|
||||
#include "dynarmic/common/assert.h"
|
||||
#include <bit>
|
||||
#include "dynarmic/backend/x64/xbyak.h"
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
#include "dynarmic/backend/x64/abi.h"
|
||||
#include "dynarmic/backend/x64/stack_layout.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#include "boost/container/small_vector.hpp"
|
||||
#include "dynarmic/common/common_types.h"
|
||||
#include "dynarmic/backend/x64/xbyak.h"
|
||||
#include <xbyak/xbyak.h>
|
||||
#include <boost/container/static_vector.hpp>
|
||||
#include <boost/container/flat_set.hpp>
|
||||
#include <boost/pool/pool_alloc.hpp>
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
// TODO: Defining this crashes e v e r y t h i n g
|
||||
// #define XBYAK_STD_UNORDERED_SET ankerl::unordered_dense::set
|
||||
// #define XBYAK_STD_UNORDERED_MAP ankerl::unordered_dense::map
|
||||
// #define XBYAK_STD_UNORDERED_MULTIMAP boost::unordered_multimap
|
||||
|
||||
#include <xbyak/xbyak.h>
|
||||
#include <xbyak/xbyak_util.h>
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include "dynarmic/backend/x64/xbyak.h"
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
#include "dynarmic/backend/x64/abi.h"
|
||||
#include "dynarmic/backend/x64/hostloc.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "dynarmic/backend/x64/xbyak.h"
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
namespace Dynarmic {
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2016 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "dynarmic/common/common_types.h"
|
||||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
std::string DisassembleArm(u32 instruction);
|
||||
std::string DisassembleThumb16(u16 instruction);
|
||||
|
||||
} // namespace Dynarmic::A32
|
||||
@@ -0,0 +1,397 @@
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2016 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <fmt/ostream.h>
|
||||
#include <mcl/bit/bit_field.hpp>
|
||||
|
||||
#include "dynarmic/common/string_util.h"
|
||||
#include "dynarmic/frontend/A32/a32_types.h"
|
||||
#include "dynarmic/frontend/A32/decoder/thumb16.h"
|
||||
#include "dynarmic/frontend/A32/disassembler/disassembler.h"
|
||||
#include "dynarmic/frontend/imm.h"
|
||||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
class DisassemblerVisitor {
|
||||
public:
|
||||
using instruction_return_type = std::string;
|
||||
|
||||
std::string thumb16_LSL_imm(Imm<5> imm5, Reg m, Reg d) {
|
||||
return fmt::format("lsls {}, {}, #{}", d, m, imm5.ZeroExtend());
|
||||
}
|
||||
|
||||
std::string thumb16_LSR_imm(Imm<5> imm5, Reg m, Reg d) {
|
||||
const u32 shift = imm5 != 0 ? imm5.ZeroExtend() : 32U;
|
||||
return fmt::format("lsrs {}, {}, #{}", d, m, shift);
|
||||
}
|
||||
|
||||
std::string thumb16_ASR_imm(Imm<5> imm5, Reg m, Reg d) {
|
||||
const u32 shift = imm5 != 0 ? imm5.ZeroExtend() : 32U;
|
||||
return fmt::format("asrs {}, {}, #{}", d, m, shift);
|
||||
}
|
||||
|
||||
std::string thumb16_ADD_reg_t1(Reg m, Reg n, Reg d) {
|
||||
return fmt::format("adds {}, {}, {}", d, n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_SUB_reg(Reg m, Reg n, Reg d) {
|
||||
return fmt::format("subs {}, {}, {}", d, n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_ADD_imm_t1(Imm<3> imm3, Reg n, Reg d) {
|
||||
return fmt::format("adds {}, {}, #{}", d, n, imm3.ZeroExtend());
|
||||
}
|
||||
|
||||
std::string thumb16_SUB_imm_t1(Imm<3> imm3, Reg n, Reg d) {
|
||||
return fmt::format("subs {}, {}, #{}", d, n, imm3.ZeroExtend());
|
||||
}
|
||||
|
||||
std::string thumb16_MOV_imm(Reg d, Imm<8> imm8) {
|
||||
return fmt::format("movs {}, #{}", d, imm8.ZeroExtend());
|
||||
}
|
||||
|
||||
std::string thumb16_CMP_imm(Reg n, Imm<8> imm8) {
|
||||
return fmt::format("cmp {}, #{}", n, imm8.ZeroExtend());
|
||||
}
|
||||
|
||||
std::string thumb16_ADD_imm_t2(Reg d_n, Imm<8> imm8) {
|
||||
return fmt::format("adds {}, #{}", d_n, imm8.ZeroExtend());
|
||||
}
|
||||
|
||||
std::string thumb16_SUB_imm_t2(Reg d_n, Imm<8> imm8) {
|
||||
return fmt::format("subs {}, #{}", d_n, imm8.ZeroExtend());
|
||||
}
|
||||
|
||||
std::string thumb16_AND_reg(Reg m, Reg d_n) {
|
||||
return fmt::format("ands {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_EOR_reg(Reg m, Reg d_n) {
|
||||
return fmt::format("eors {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_LSL_reg(Reg m, Reg d_n) {
|
||||
return fmt::format("lsls {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_LSR_reg(Reg m, Reg d_n) {
|
||||
return fmt::format("lsrs {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_ASR_reg(Reg m, Reg d_n) {
|
||||
return fmt::format("asrs {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_ADC_reg(Reg m, Reg d_n) {
|
||||
return fmt::format("adcs {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_SBC_reg(Reg m, Reg d_n) {
|
||||
return fmt::format("sbcs {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_ROR_reg(Reg m, Reg d_n) {
|
||||
return fmt::format("rors {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_TST_reg(Reg m, Reg n) {
|
||||
return fmt::format("tst {}, {}", n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_RSB_imm(Reg n, Reg d) {
|
||||
// Pre-UAL syntax: NEGS <Rd>, <Rn>
|
||||
return fmt::format("rsbs {}, {}, #0", d, n);
|
||||
}
|
||||
|
||||
std::string thumb16_CMP_reg_t1(Reg m, Reg n) {
|
||||
return fmt::format("cmp {}, {}", n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_CMN_reg(Reg m, Reg n) {
|
||||
return fmt::format("cmn {}, {}", n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_ORR_reg(Reg m, Reg d_n) {
|
||||
return fmt::format("orrs {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_MUL_reg(Reg n, Reg d_m) {
|
||||
return fmt::format("muls {}, {}, {}", d_m, n, d_m);
|
||||
}
|
||||
|
||||
std::string thumb16_BIC_reg(Reg m, Reg d_n) {
|
||||
return fmt::format("bics {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_MVN_reg(Reg m, Reg d) {
|
||||
return fmt::format("mvns {}, {}", d, m);
|
||||
}
|
||||
|
||||
std::string thumb16_ADD_reg_t2(bool d_n_hi, Reg m, Reg d_n_lo) {
|
||||
const Reg d_n = d_n_hi ? (d_n_lo + 8) : d_n_lo;
|
||||
return fmt::format("add {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_CMP_reg_t2(bool n_hi, Reg m, Reg n_lo) {
|
||||
const Reg n = n_hi ? (n_lo + 8) : n_lo;
|
||||
return fmt::format("cmp {}, {}", n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_MOV_reg(bool d_hi, Reg m, Reg d_lo) {
|
||||
const Reg d = d_hi ? (d_lo + 8) : d_lo;
|
||||
return fmt::format("mov {}, {}", d, m);
|
||||
}
|
||||
|
||||
std::string thumb16_LDR_literal(Reg t, Imm<8> imm8) {
|
||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
||||
return fmt::format("ldr {}, [pc, #{}]", t, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_STR_reg(Reg m, Reg n, Reg t) {
|
||||
return fmt::format("str {}, [{}, {}]", t, n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_STRH_reg(Reg m, Reg n, Reg t) {
|
||||
return fmt::format("strh {}, [{}, {}]", t, n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_STRB_reg(Reg m, Reg n, Reg t) {
|
||||
return fmt::format("strb {}, [{}, {}]", t, n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_LDRSB_reg(Reg m, Reg n, Reg t) {
|
||||
return fmt::format("ldrsb {}, [{}, {}]", t, n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_LDR_reg(Reg m, Reg n, Reg t) {
|
||||
return fmt::format("ldr {}, [{}, {}]", t, n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_LDRH_reg(Reg m, Reg n, Reg t) {
|
||||
return fmt::format("ldrh {}, [%s, %s]", t, n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_LDRB_reg(Reg m, Reg n, Reg t) {
|
||||
return fmt::format("ldrb {}, [{}, {}]", t, n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_LDRSH_reg(Reg m, Reg n, Reg t) {
|
||||
return fmt::format("ldrsh {}, [{}, {}]", t, n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_STR_imm_t1(Imm<5> imm5, Reg n, Reg t) {
|
||||
const u32 imm32 = imm5.ZeroExtend() << 2;
|
||||
return fmt::format("str {}, [{}, #{}]", t, n, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_LDR_imm_t1(Imm<5> imm5, Reg n, Reg t) {
|
||||
const u32 imm32 = imm5.ZeroExtend() << 2;
|
||||
return fmt::format("ldr {}, [{}, #{}]", t, n, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_STRB_imm(Imm<5> imm5, Reg n, Reg t) {
|
||||
const u32 imm32 = imm5.ZeroExtend();
|
||||
return fmt::format("strb {}, [{}, #{}]", t, n, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_LDRB_imm(Imm<5> imm5, Reg n, Reg t) {
|
||||
const u32 imm32 = imm5.ZeroExtend();
|
||||
return fmt::format("ldrb {}, [{}, #{}]", t, n, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_STRH_imm(Imm<5> imm5, Reg n, Reg t) {
|
||||
const u32 imm32 = imm5.ZeroExtend() << 1;
|
||||
return fmt::format("strh {}, [{}, #{}]", t, n, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_LDRH_imm(Imm<5> imm5, Reg n, Reg t) {
|
||||
const u32 imm32 = imm5.ZeroExtend() << 1;
|
||||
return fmt::format("ldrh {}, [{}, #{}]", t, n, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_STR_imm_t2(Reg t, Imm<8> imm8) {
|
||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
||||
return fmt::format("str {}, [sp, #{}]", t, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_LDR_imm_t2(Reg t, Imm<8> imm8) {
|
||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
||||
return fmt::format("ldr {}, [sp, #{}]", t, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_ADR(Reg d, Imm<8> imm8) {
|
||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
||||
return fmt::format("adr {}, +#{}", d, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_ADD_sp_t1(Reg d, Imm<8> imm8) {
|
||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
||||
return fmt::format("add {}, sp, #{}", d, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_ADD_sp_t2(Imm<7> imm7) {
|
||||
const u32 imm32 = imm7.ZeroExtend() << 2;
|
||||
return fmt::format("add sp, sp, #{}", imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_SUB_sp(Imm<7> imm7) {
|
||||
const u32 imm32 = imm7.ZeroExtend() << 2;
|
||||
return fmt::format("sub sp, sp, #{}", imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_NOP() {
|
||||
return "nop";
|
||||
}
|
||||
|
||||
std::string thumb16_SEV() {
|
||||
return "sev";
|
||||
}
|
||||
|
||||
std::string thumb16_SEVL() {
|
||||
return "sevl";
|
||||
}
|
||||
|
||||
std::string thumb16_WFE() {
|
||||
return "wfe";
|
||||
}
|
||||
|
||||
std::string thumb16_WFI() {
|
||||
return "wfi";
|
||||
}
|
||||
|
||||
std::string thumb16_YIELD() {
|
||||
return "yield";
|
||||
}
|
||||
|
||||
std::string thumb16_IT(Imm<8> imm8) {
|
||||
const Cond firstcond = imm8.Bits<4, 7, Cond>();
|
||||
const bool firstcond0 = imm8.Bit<4>();
|
||||
const auto [x, y, z] = [&] {
|
||||
if (imm8.Bits<0, 3>() == 0b1000) {
|
||||
return std::make_tuple("", "", "");
|
||||
}
|
||||
if (imm8.Bits<0, 2>() == 0b100) {
|
||||
return std::make_tuple(imm8.Bit<3>() == firstcond0 ? "t" : "e", "", "");
|
||||
}
|
||||
if (imm8.Bits<0, 1>() == 0b10) {
|
||||
return std::make_tuple(imm8.Bit<3>() == firstcond0 ? "t" : "e", imm8.Bit<2>() == firstcond0 ? "t" : "e", "");
|
||||
}
|
||||
// Sanity note: Here imm8.Bit<0>() is guaranteed to be == 1. (imm8 can never be 0bxxxx0000)
|
||||
return std::make_tuple(imm8.Bit<3>() == firstcond0 ? "t" : "e", imm8.Bit<2>() == firstcond0 ? "t" : "e", imm8.Bit<1>() == firstcond0 ? "t" : "e");
|
||||
}();
|
||||
return fmt::format("it{}{}{} {}", x, y, z, CondToString(firstcond));
|
||||
}
|
||||
|
||||
std::string thumb16_SXTH(Reg m, Reg d) {
|
||||
return fmt::format("sxth {}, {}", d, m);
|
||||
}
|
||||
|
||||
std::string thumb16_SXTB(Reg m, Reg d) {
|
||||
return fmt::format("sxtb {}, {}", d, m);
|
||||
}
|
||||
|
||||
std::string thumb16_UXTH(Reg m, Reg d) {
|
||||
return fmt::format("uxth {}, {}", d, m);
|
||||
}
|
||||
|
||||
std::string thumb16_UXTB(Reg m, Reg d) {
|
||||
return fmt::format("uxtb {}, {}", d, m);
|
||||
}
|
||||
|
||||
std::string thumb16_PUSH(bool M, RegList reg_list) {
|
||||
if (M)
|
||||
reg_list |= 1 << 14;
|
||||
return fmt::format("push {{{}}}", RegListToString(reg_list));
|
||||
}
|
||||
|
||||
std::string thumb16_POP(bool P, RegList reg_list) {
|
||||
if (P)
|
||||
reg_list |= 1 << 15;
|
||||
return fmt::format("pop {{{}}}", RegListToString(reg_list));
|
||||
}
|
||||
|
||||
std::string thumb16_SETEND(bool E) {
|
||||
return fmt::format("setend {}", E ? "BE" : "LE");
|
||||
}
|
||||
|
||||
std::string thumb16_CPS(bool im, bool a, bool i, bool f) {
|
||||
return fmt::format("cps{} {}{}{}", im ? "id" : "ie", a ? "a" : "", i ? "i" : "", f ? "f" : "");
|
||||
}
|
||||
|
||||
std::string thumb16_REV(Reg m, Reg d) {
|
||||
return fmt::format("rev {}, {}", d, m);
|
||||
}
|
||||
|
||||
std::string thumb16_REV16(Reg m, Reg d) {
|
||||
return fmt::format("rev16 {}, {}", d, m);
|
||||
}
|
||||
|
||||
std::string thumb16_REVSH(Reg m, Reg d) {
|
||||
return fmt::format("revsh {}, {}", d, m);
|
||||
}
|
||||
|
||||
std::string thumb16_BKPT(Imm<8> imm8) {
|
||||
return fmt::format("bkpt #{}", imm8.ZeroExtend());
|
||||
}
|
||||
|
||||
std::string thumb16_STMIA(Reg n, RegList reg_list) {
|
||||
return fmt::format("stm {}!, {{{}}}", n, RegListToString(reg_list));
|
||||
}
|
||||
|
||||
std::string thumb16_LDMIA(Reg n, RegList reg_list) {
|
||||
const bool write_back = !mcl::bit::get_bit(static_cast<size_t>(n), reg_list);
|
||||
return fmt::format("ldm {}{}, {{{}}}", n, write_back ? "!" : "", RegListToString(reg_list));
|
||||
}
|
||||
|
||||
std::string thumb16_BX(Reg m) {
|
||||
return fmt::format("bx {}", m);
|
||||
}
|
||||
|
||||
std::string thumb16_BLX_reg(Reg m) {
|
||||
return fmt::format("blx {}", m);
|
||||
}
|
||||
|
||||
std::string thumb16_CBZ_CBNZ(bool nonzero, Imm<1> i, Imm<5> imm5, Reg n) {
|
||||
const char* const name = nonzero ? "cbnz" : "cbz";
|
||||
const u32 imm = concatenate(i, imm5, Imm<1>{0}).ZeroExtend();
|
||||
|
||||
return fmt::format("{} {}, #{}", name, n, imm);
|
||||
}
|
||||
|
||||
std::string thumb16_UDF() {
|
||||
return fmt::format("udf");
|
||||
}
|
||||
|
||||
std::string thumb16_SVC(Imm<8> imm8) {
|
||||
return fmt::format("svc #{}", imm8.ZeroExtend());
|
||||
}
|
||||
|
||||
std::string thumb16_B_t1(Cond cond, Imm<8> imm8) {
|
||||
const s32 imm32 = static_cast<s32>((imm8.SignExtend<u32>() << 1) + 4);
|
||||
return fmt::format("b{} {}#{}",
|
||||
CondToString(cond),
|
||||
Common::SignToChar(imm32),
|
||||
abs(imm32));
|
||||
}
|
||||
|
||||
std::string thumb16_B_t2(Imm<11> imm11) {
|
||||
const s32 imm32 = static_cast<s32>((imm11.SignExtend<u32>() << 1) + 4);
|
||||
return fmt::format("b {}#{}",
|
||||
Common::SignToChar(imm32),
|
||||
abs(imm32));
|
||||
}
|
||||
};
|
||||
|
||||
std::string DisassembleThumb16(u16 instruction) {
|
||||
DisassemblerVisitor visitor;
|
||||
auto decoder = DecodeThumb16<DisassemblerVisitor>(instruction);
|
||||
return !decoder ? fmt::format("UNKNOWN: {:x}", instruction) : decoder->get().call(visitor, instruction);
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::A32
|
||||
@@ -0,0 +1,18 @@
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2016 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace A32 {
|
||||
|
||||
std::string DisassembleArm(std::uint32_t instruction);
|
||||
std::string DisassembleThumb16(std::uint16_t instruction);
|
||||
|
||||
} // namespace A32
|
||||
} // namespace Dynarmic
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "dynarmic/frontend/A32/FPSCR.h"
|
||||
#include "dynarmic/frontend/A32/PSR.h"
|
||||
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
|
||||
#include "dynarmic/frontend/A32/disassembler/disassembler.h"
|
||||
#include "dynarmic/frontend/A32/translate/a32_translate.h"
|
||||
#include "dynarmic/interface/A32/a32.h"
|
||||
#include "dynarmic/ir/basic_block.h"
|
||||
|
||||
@@ -0,0 +1,381 @@
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2016 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "dynarmic/frontend/A32/disassembler/disassembler.h"
|
||||
|
||||
using Dynarmic::A32::DisassembleArm;
|
||||
|
||||
TEST_CASE("Disassemble branch instructions", "[arm][disassembler]") {
|
||||
REQUIRE(DisassembleArm(0xEAFFFFFE) == "b +#0");
|
||||
REQUIRE(DisassembleArm(0xEB000008) == "bl +#40");
|
||||
REQUIRE(DisassembleArm(0xFBFFFFFE) == "blx +#2");
|
||||
REQUIRE(DisassembleArm(0xFAFFFFFF) == "blx +#4");
|
||||
REQUIRE(DisassembleArm(0xFBE1E7FE) == "blx -#7888894");
|
||||
REQUIRE(DisassembleArm(0xE12FFF3D) == "blx sp");
|
||||
REQUIRE(DisassembleArm(0x312FFF13) == "bxcc r3");
|
||||
REQUIRE(DisassembleArm(0x012FFF29) == "bxjeq r9");
|
||||
}
|
||||
|
||||
TEST_CASE("Disassemble data processing instructions", "[arm][disassembler]") {
|
||||
REQUIRE(DisassembleArm(0xE2A21004) == "adc r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0A21143) == "adc r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0A21103) == "adc r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0A21123) == "adc r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0A21163) == "adc r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0A21003) == "adc r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0A21063) == "adc r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE0A21453) == "adc r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0A21413) == "adc r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0A21433) == "adc r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0A21473) == "adc r1, r2, r3, ror r4");
|
||||
REQUIRE(DisassembleArm(0xE2B21004) == "adcs r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0B21143) == "adcs r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0B21103) == "adcs r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0B21123) == "adcs r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0B21163) == "adcs r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0B21003) == "adcs r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0B21063) == "adcs r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE0B21453) == "adcs r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0B21413) == "adcs r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0B21433) == "adcs r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0B21473) == "adcs r1, r2, r3, ror r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE2853004) == "add r3, r5, #4");
|
||||
REQUIRE(DisassembleArm(0xE0821143) == "add r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0821103) == "add r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0821123) == "add r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0821163) == "add r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0821003) == "add r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0821453) == "add r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0821413) == "add r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0821433) == "add r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0821473) == "add r1, r2, r3, ror r4");
|
||||
REQUIRE(DisassembleArm(0xE0821063) == "add r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE2953004) == "adds r3, r5, #4");
|
||||
REQUIRE(DisassembleArm(0xE0921143) == "adds r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0921103) == "adds r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0921123) == "adds r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0921163) == "adds r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0921003) == "adds r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0921063) == "adds r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE0921453) == "adds r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0921413) == "adds r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0921433) == "adds r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0921473) == "adds r1, r2, r3, ror r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE2021004) == "and r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0021143) == "and r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0021103) == "and r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0021123) == "and r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0021163) == "and r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0021003) == "and r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0021453) == "and r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0021413) == "and r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0021433) == "and r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0021473) == "and r1, r2, r3, ror r4");
|
||||
REQUIRE(DisassembleArm(0xE0021063) == "and r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE2121004) == "ands r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0121143) == "ands r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0121103) == "ands r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0121123) == "ands r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0121163) == "ands r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0121003) == "ands r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0121063) == "ands r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE0121453) == "ands r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0121413) == "ands r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0121433) == "ands r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0121473) == "ands r1, r2, r3, ror r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE3C21004) == "bic r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE1C21143) == "bic r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1C21103) == "bic r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1C21123) == "bic r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1C21163) == "bic r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1C21003) == "bic r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE1C21453) == "bic r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE1C21413) == "bic r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE1C21433) == "bic r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE1C21473) == "bic r1, r2, r3, ror r4");
|
||||
REQUIRE(DisassembleArm(0xE1C21063) == "bic r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE3D21004) == "bics r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE1D21143) == "bics r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1D21103) == "bics r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1D21123) == "bics r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1D21163) == "bics r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1D21003) == "bics r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE1D21063) == "bics r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE1D21453) == "bics r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE1D21413) == "bics r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE1D21433) == "bics r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE1D21473) == "bics r1, r2, r3, ror r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE3710004) == "cmn r1, #4");
|
||||
REQUIRE(DisassembleArm(0xE1710142) == "cmn r1, r2, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1710102) == "cmn r1, r2, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1710122) == "cmn r1, r2, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1710162) == "cmn r1, r2, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1710002) == "cmn r1, r2");
|
||||
REQUIRE(DisassembleArm(0xE1710062) == "cmn r1, r2, rrx");
|
||||
REQUIRE(DisassembleArm(0xE1710352) == "cmn r1, r2, asr r3");
|
||||
REQUIRE(DisassembleArm(0xE1710312) == "cmn r1, r2, lsl r3");
|
||||
REQUIRE(DisassembleArm(0xE1710332) == "cmn r1, r2, lsr r3");
|
||||
REQUIRE(DisassembleArm(0xE1710372) == "cmn r1, r2, ror r3");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE3510004) == "cmp r1, #4");
|
||||
REQUIRE(DisassembleArm(0xE1510142) == "cmp r1, r2, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1510102) == "cmp r1, r2, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1510122) == "cmp r1, r2, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1510162) == "cmp r1, r2, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1510002) == "cmp r1, r2");
|
||||
REQUIRE(DisassembleArm(0xE1510062) == "cmp r1, r2, rrx");
|
||||
REQUIRE(DisassembleArm(0xE1510352) == "cmp r1, r2, asr r3");
|
||||
REQUIRE(DisassembleArm(0xE1510312) == "cmp r1, r2, lsl r3");
|
||||
REQUIRE(DisassembleArm(0xE1510332) == "cmp r1, r2, lsr r3");
|
||||
REQUIRE(DisassembleArm(0xE1510372) == "cmp r1, r2, ror r3");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE2221004) == "eor r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0221243) == "eor r1, r2, r3, asr #4");
|
||||
REQUIRE(DisassembleArm(0xE0221203) == "eor r1, r2, r3, lsl #4");
|
||||
REQUIRE(DisassembleArm(0xE0221223) == "eor r1, r2, r3, lsr #4");
|
||||
REQUIRE(DisassembleArm(0xE0221263) == "eor r1, r2, r3, ror #4");
|
||||
REQUIRE(DisassembleArm(0xE0221003) == "eor r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0221453) == "eor r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0221413) == "eor r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0221433) == "eor r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0221473) == "eor r1, r2, r3, ror r4");
|
||||
REQUIRE(DisassembleArm(0xE0221063) == "eor r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE2321004) == "eors r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0321243) == "eors r1, r2, r3, asr #4");
|
||||
REQUIRE(DisassembleArm(0xE0321203) == "eors r1, r2, r3, lsl #4");
|
||||
REQUIRE(DisassembleArm(0xE0321223) == "eors r1, r2, r3, lsr #4");
|
||||
REQUIRE(DisassembleArm(0xE0321263) == "eors r1, r2, r3, ror #4");
|
||||
REQUIRE(DisassembleArm(0xE0321003) == "eors r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0321453) == "eors r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0321413) == "eors r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0321433) == "eors r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0321473) == "eors r1, r2, r3, ror r4");
|
||||
REQUIRE(DisassembleArm(0xE0321063) == "eors r1, r2, r3, rrx");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE3A010FF) == "mov r1, #255");
|
||||
REQUIRE(DisassembleArm(0xE1A01142) == "mov r1, r2, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1A01102) == "mov r1, r2, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1A01122) == "mov r1, r2, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1A01162) == "mov r1, r2, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1A01062) == "mov r1, r2, rrx");
|
||||
REQUIRE(DisassembleArm(0xE1A0E00F) == "mov lr, pc");
|
||||
REQUIRE(DisassembleArm(0xE3B010FF) == "movs r1, #255");
|
||||
REQUIRE(DisassembleArm(0xE1B0E00F) == "movs lr, pc");
|
||||
REQUIRE(DisassembleArm(0xE1B01142) == "movs r1, r2, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1B01102) == "movs r1, r2, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1B01122) == "movs r1, r2, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1B01162) == "movs r1, r2, ror #2");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE3E01004) == "mvn r1, #4");
|
||||
REQUIRE(DisassembleArm(0xE1E01142) == "mvn r1, r2, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1E01102) == "mvn r1, r2, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1E01122) == "mvn r1, r2, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1E01162) == "mvn r1, r2, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1E01062) == "mvn r1, r2, rrx");
|
||||
REQUIRE(DisassembleArm(0xE1E01002) == "mvn r1, r2");
|
||||
REQUIRE(DisassembleArm(0xE1E01352) == "mvn r1, r2, asr r3");
|
||||
REQUIRE(DisassembleArm(0xE1E01312) == "mvn r1, r2, lsl r3");
|
||||
REQUIRE(DisassembleArm(0xE1E01332) == "mvn r1, r2, lsr r3");
|
||||
REQUIRE(DisassembleArm(0xE1E01372) == "mvn r1, r2, ror r3");
|
||||
REQUIRE(DisassembleArm(0xE3F01004) == "mvns r1, #4");
|
||||
REQUIRE(DisassembleArm(0xE1F01142) == "mvns r1, r2, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1F01102) == "mvns r1, r2, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1F01122) == "mvns r1, r2, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1F01162) == "mvns r1, r2, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1F01062) == "mvns r1, r2, rrx");
|
||||
REQUIRE(DisassembleArm(0xE1F01002) == "mvns r1, r2");
|
||||
REQUIRE(DisassembleArm(0xE1F01352) == "mvns r1, r2, asr r3");
|
||||
REQUIRE(DisassembleArm(0xE1F01312) == "mvns r1, r2, lsl r3");
|
||||
REQUIRE(DisassembleArm(0xE1F01332) == "mvns r1, r2, lsr r3");
|
||||
REQUIRE(DisassembleArm(0xE1F01372) == "mvns r1, r2, ror r3");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE3821004) == "orr r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE1821143) == "orr r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1821103) == "orr r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1821123) == "orr r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1821163) == "orr r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1821063) == "orr r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE1821003) == "orr r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE1821453) == "orr r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE1821413) == "orr r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE1821433) == "orr r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE1821473) == "orr r1, r2, r3, ror r4");
|
||||
REQUIRE(DisassembleArm(0xE3921004) == "orrs r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE1921143) == "orrs r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1921103) == "orrs r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1921123) == "orrs r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1921163) == "orrs r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1921063) == "orrs r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE1921003) == "orrs r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE1921453) == "orrs r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE1921413) == "orrs r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE1921433) == "orrs r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE1921473) == "orrs r1, r2, r3, ror r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE2621004) == "rsb r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0621143) == "rsb r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0621103) == "rsb r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0621123) == "rsb r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0621163) == "rsb r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0621063) == "rsb r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE0621003) == "rsb r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0621453) == "rsb r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0621413) == "rsb r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0621433) == "rsb r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0621473) == "rsb r1, r2, r3, ror r4");
|
||||
REQUIRE(DisassembleArm(0xE2721004) == "rsbs r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0721143) == "rsbs r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0721103) == "rsbs r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0721123) == "rsbs r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0721163) == "rsbs r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0721063) == "rsbs r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE0721003) == "rsbs r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0721453) == "rsbs r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0721413) == "rsbs r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0721433) == "rsbs r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0721473) == "rsbs r1, r2, r3, ror r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE2E21004) == "rsc r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0E21143) == "rsc r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0E21103) == "rsc r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0E21123) == "rsc r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0E21163) == "rsc r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0E21063) == "rsc r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE0E21003) == "rsc r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0E21453) == "rsc r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0E21413) == "rsc r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0E21433) == "rsc r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0E21473) == "rsc r1, r2, r3, ror r4");
|
||||
REQUIRE(DisassembleArm(0xE2F21004) == "rscs r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0F21143) == "rscs r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0F21103) == "rscs r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0F21123) == "rscs r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0F21163) == "rscs r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0F21063) == "rscs r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE0F21003) == "rscs r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0F21453) == "rscs r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0F21413) == "rscs r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0F21433) == "rscs r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0F21473) == "rscs r1, r2, r3, ror r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE2C21004) == "sbc r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0C21143) == "sbc r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0C21103) == "sbc r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0C21123) == "sbc r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0C21163) == "sbc r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0C21063) == "sbc r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE0C21003) == "sbc r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0C21453) == "sbc r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0C21413) == "sbc r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0C21433) == "sbc r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0C21473) == "sbc r1, r2, r3, ror r4");
|
||||
REQUIRE(DisassembleArm(0xE2D21004) == "sbcs r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0D21143) == "sbcs r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0D21103) == "sbcs r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0D21123) == "sbcs r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0D21163) == "sbcs r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0D21063) == "sbcs r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE0D21003) == "sbcs r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0D21453) == "sbcs r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0D21413) == "sbcs r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0D21433) == "sbcs r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0D21473) == "sbcs r1, r2, r3, ror r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE3310004) == "teq r1, #4");
|
||||
REQUIRE(DisassembleArm(0xE1310142) == "teq r1, r2, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1310102) == "teq r1, r2, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1310122) == "teq r1, r2, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1310162) == "teq r1, r2, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1310002) == "teq r1, r2");
|
||||
REQUIRE(DisassembleArm(0xE1310062) == "teq r1, r2, rrx");
|
||||
REQUIRE(DisassembleArm(0xE1310352) == "teq r1, r2, asr r3");
|
||||
REQUIRE(DisassembleArm(0xE1310312) == "teq r1, r2, lsl r3");
|
||||
REQUIRE(DisassembleArm(0xE1310332) == "teq r1, r2, lsr r3");
|
||||
REQUIRE(DisassembleArm(0xE1310372) == "teq r1, r2, ror r3");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE3110004) == "tst r1, #4");
|
||||
REQUIRE(DisassembleArm(0xE1110142) == "tst r1, r2, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1110102) == "tst r1, r2, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1110122) == "tst r1, r2, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1110162) == "tst r1, r2, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1110002) == "tst r1, r2");
|
||||
REQUIRE(DisassembleArm(0xE1110062) == "tst r1, r2, rrx");
|
||||
REQUIRE(DisassembleArm(0xE1110352) == "tst r1, r2, asr r3");
|
||||
REQUIRE(DisassembleArm(0xE1110312) == "tst r1, r2, lsl r3");
|
||||
REQUIRE(DisassembleArm(0xE1110332) == "tst r1, r2, lsr r3");
|
||||
REQUIRE(DisassembleArm(0xE1110372) == "tst r1, r2, ror r3");
|
||||
}
|
||||
|
||||
TEST_CASE("Disassemble half-word multiply and multiply accumulate instructions", "[arm][disassembler]") {
|
||||
REQUIRE(DisassembleArm(0xE1003281) == "smlabb r0, r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE10032C1) == "smlabt r0, r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE10032A1) == "smlatb r0, r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE10032E1) == "smlatt r0, r1, r2, r3");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE1203281) == "smlawb r0, r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE12032C1) == "smlawt r0, r1, r2, r3");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE12002A1) == "smulwb r0, r1, r2");
|
||||
REQUIRE(DisassembleArm(0xE12002E1) == "smulwt r0, r1, r2");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE1410382) == "smlalbb r0, r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE14103C2) == "smlalbt r0, r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE14103A2) == "smlaltb r0, r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE14103E2) == "smlaltt r0, r1, r2, r3");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE1600281) == "smulbb r0, r1, r2");
|
||||
REQUIRE(DisassembleArm(0xE16002C1) == "smulbt r0, r1, r2");
|
||||
REQUIRE(DisassembleArm(0xE16002A1) == "smultb r0, r1, r2");
|
||||
REQUIRE(DisassembleArm(0xE16002E1) == "smultt r0, r1, r2");
|
||||
}
|
||||
|
||||
TEST_CASE("Disassemble multiply and multiply accumulate instructions", "[arm][disassembler]") {
|
||||
REQUIRE(DisassembleArm(0xE0214392) == "mla r1, r2, r3, r4");
|
||||
REQUIRE(DisassembleArm(0xE0314392) == "mlas r1, r2, r3, r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE0010392) == "mul r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0110392) == "muls r1, r2, r3");
|
||||
|
||||
// TODO: MLS should be here whenever it's supported.
|
||||
|
||||
REQUIRE(DisassembleArm(0xE0E21493) == "smlal r1, r2, r3, r4");
|
||||
REQUIRE(DisassembleArm(0xE0F21493) == "smlals r1, r2, r3, r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE0C21493) == "smull r1, r2, r3, r4");
|
||||
REQUIRE(DisassembleArm(0xE0D21493) == "smulls r1, r2, r3, r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE0421493) == "umaal r1, r2, r3, r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE0A21493) == "umlal r1, r2, r3, r4");
|
||||
REQUIRE(DisassembleArm(0xE0B21493) == "umlals r1, r2, r3, r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE0821493) == "umull r1, r2, r3, r4");
|
||||
REQUIRE(DisassembleArm(0xE0921493) == "umulls r1, r2, r3, r4");
|
||||
}
|
||||
|
||||
TEST_CASE("Disassemble synchronization primitive instructions", "[arm][disassembler]") {
|
||||
REQUIRE(DisassembleArm(0xE1921F9F) == "ldrex r1, [r2]");
|
||||
REQUIRE(DisassembleArm(0xE1D21F9F) == "ldrexb r1, [r2]");
|
||||
REQUIRE(DisassembleArm(0xE1B31F9F) == "ldrexd r1, r2, [r3]");
|
||||
REQUIRE(DisassembleArm(0xE1F21F9F) == "ldrexh r1, [r2]");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE1831F92) == "strex r1, r2, [r3]");
|
||||
REQUIRE(DisassembleArm(0xE1C31F92) == "strexb r1, r2, [r3]");
|
||||
REQUIRE(DisassembleArm(0xE1A41F92) == "strexd r1, r2, r3, [r4]");
|
||||
REQUIRE(DisassembleArm(0xE1E31F92) == "strexh r1, r2, [r3]");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE1031092) == "swp r1, r2, [r3]");
|
||||
REQUIRE(DisassembleArm(0xE1431092) == "swpb r1, r2, [r3]");
|
||||
}
|
||||
|
||||
TEST_CASE("Disassemble load / store multiple instructions", "[arm][disassembler]") {
|
||||
REQUIRE(DisassembleArm(0xE92D500F) == "stmdb sp!, {r0, r1, r2, r3, r12, lr}");
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
include(TargetArchitectureSpecificSources)
|
||||
|
||||
@@ -9,6 +9,7 @@ add_executable(dynarmic_tests
|
||||
fp/unpacked_tests.cpp
|
||||
rand_int.h
|
||||
# A32
|
||||
A32/test_arm_disassembler.cpp
|
||||
A32/test_arm_instructions.cpp
|
||||
A32/test_coprocessor.cpp
|
||||
A32/test_svc.cpp
|
||||
@@ -24,7 +25,7 @@ add_executable(dynarmic_tests
|
||||
A64/real_world.cpp
|
||||
A64/testenv.h
|
||||
)
|
||||
target_link_libraries(dynarmic_tests PRIVATE merry::oaknut unordered_dense::unordered_dense)
|
||||
target_link_libraries(dynarmic_tests PRIVATE merry::oaknut)
|
||||
|
||||
if (DYNARMIC_TESTS_USE_UNICORN)
|
||||
target_link_libraries(dynarmic_tests PRIVATE Unicorn::Unicorn)
|
||||
@@ -72,7 +73,7 @@ add_executable(dynarmic_print_info
|
||||
print_info.cpp
|
||||
)
|
||||
create_target_directory_groups(dynarmic_print_info)
|
||||
target_link_libraries(dynarmic_print_info PRIVATE dynarmic fmt::fmt merry::mcl unordered_dense::unordered_dense)
|
||||
target_link_libraries(dynarmic_print_info PRIVATE dynarmic fmt::fmt merry::mcl)
|
||||
if (BOOST_NO_HEADERS)
|
||||
target_link_libraries(dynarmic_print_info PRIVATE Boost::variant Boost::icl Boost::pool)
|
||||
else()
|
||||
@@ -93,7 +94,7 @@ add_executable(dynarmic_test_generator
|
||||
|
||||
create_target_directory_groups(dynarmic_test_generator)
|
||||
|
||||
target_link_libraries(dynarmic_test_generator PRIVATE dynarmic fmt::fmt merry::mcl unordered_dense::unordered_dense)
|
||||
target_link_libraries(dynarmic_test_generator PRIVATE dynarmic fmt::fmt merry::mcl)
|
||||
if (BOOST_NO_HEADERS)
|
||||
target_link_libraries(dynarmic_test_generator PRIVATE Boost::variant Boost::icl Boost::pool)
|
||||
else()
|
||||
@@ -110,7 +111,7 @@ add_executable(dynarmic_test_reader
|
||||
test_reader.cpp
|
||||
)
|
||||
create_target_directory_groups(dynarmic_test_reader)
|
||||
target_link_libraries(dynarmic_test_reader PRIVATE dynarmic fmt::fmt merry::mcl unordered_dense::unordered_dense)
|
||||
target_link_libraries(dynarmic_test_reader PRIVATE dynarmic fmt::fmt merry::mcl)
|
||||
if (BOOST_NO_HEADERS)
|
||||
target_link_libraries(dynarmic_test_reader PRIVATE Boost::variant Boost::icl Boost::pool)
|
||||
else()
|
||||
@@ -123,7 +124,7 @@ target_compile_definitions(dynarmic_test_reader PRIVATE FMT_USE_USER_DEFINED_LIT
|
||||
#
|
||||
create_target_directory_groups(dynarmic_tests)
|
||||
|
||||
target_link_libraries(dynarmic_tests PRIVATE dynarmic Catch2::Catch2WithMain fmt::fmt merry::mcl unordered_dense::unordered_dense)
|
||||
target_link_libraries(dynarmic_tests PRIVATE dynarmic Catch2::Catch2WithMain fmt::fmt merry::mcl)
|
||||
if (BOOST_NO_HEADERS)
|
||||
target_link_libraries(dynarmic_tests PRIVATE Boost::variant Boost::icl Boost::pool)
|
||||
else()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "dynarmic/frontend/A64/translate/impl/impl.h"
|
||||
#include "dynarmic/interface/A32/a32.h"
|
||||
#include "dynarmic/interface/A32/config.h"
|
||||
#include "dynarmic/interface/A32/disassembler.h"
|
||||
#include "dynarmic/ir/basic_block.h"
|
||||
#include "dynarmic/ir/opt_passes.h"
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ if (ENABLE_UPDATE_CHECKER)
|
||||
update_checker.h)
|
||||
|
||||
if (ENABLE_OPENSSL)
|
||||
target_compile_definitions(frontend_common PUBLIC CPPHTTPLIB_OPENSSL_SUPPORT)
|
||||
target_compile_definitions(frontend_common PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT)
|
||||
target_link_libraries(frontend_common PRIVATE OpenSSL::SSL OpenSSL::Crypto)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -11,8 +11,9 @@ namespace FrontendCommon {
|
||||
void GenerateSettings() {
|
||||
static std::random_device rd;
|
||||
|
||||
// Web Token
|
||||
if (Settings::values.eden_token.GetValue().empty()) {
|
||||
// Web Token //
|
||||
auto &token_setting = Settings::values.eden_token;
|
||||
if (token_setting.GetValue().empty()) {
|
||||
static constexpr const size_t token_length = 48;
|
||||
static constexpr const frozen::string token_set = "abcdefghijklmnopqrstuvwxyz";
|
||||
static std::uniform_int_distribution<int> token_dist(0, token_set.size() - 1);
|
||||
@@ -22,18 +23,9 @@ void GenerateSettings() {
|
||||
size_t idx = token_dist(rd);
|
||||
result += token_set[idx];
|
||||
}
|
||||
Settings::values.eden_token.SetValue(result);
|
||||
|
||||
token_setting.SetValue(result);
|
||||
}
|
||||
|
||||
// Randomly generated number because, well, we fill the rest automagically ;)
|
||||
// Other serial parts are filled by Region_Index
|
||||
std::random_device device;
|
||||
std::mt19937 gen(device());
|
||||
std::uniform_int_distribution<u32> distribution(1, (std::numeric_limits<u32>::max)());
|
||||
if (Settings::values.serial_unit.GetValue() == 0)
|
||||
Settings::values.serial_unit.SetValue(distribution(gen));
|
||||
if (Settings::values.serial_battery.GetValue() == 0)
|
||||
Settings::values.serial_battery.SetValue(distribution(gen));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -82,8 +82,8 @@ std::optional<std::string> UpdateChecker::GetResponse(std::string url, std::stri
|
||||
|
||||
std::optional<UpdateChecker::Update> UpdateChecker::GetLatestRelease(bool include_prereleases) {
|
||||
const auto update_check_url = std::string{Common::g_build_auto_update_api};
|
||||
auto update_check_path = fmt::format("{}{}", std::string{Common::g_build_auto_update_api_path},
|
||||
std::string{Common::g_build_auto_update_repo});
|
||||
std::string update_check_path = fmt::format("/repos/{}",
|
||||
std::string{Common::g_build_auto_update_repo});
|
||||
try {
|
||||
if (include_prereleases) { // This can return either a prerelease or a stable release,
|
||||
// whichever is more recent.
|
||||
@@ -124,14 +124,14 @@ std::optional<UpdateChecker::Update> UpdateChecker::GetLatestRelease(bool includ
|
||||
return Update{latest_tag, latest_name};
|
||||
}
|
||||
|
||||
} catch (nlohmann::detail::out_of_range&) {
|
||||
} catch (nlohmann::detail::out_of_range &) {
|
||||
LOG_ERROR(Frontend,
|
||||
"Parsing JSON response from {}{} failed during update check: "
|
||||
"nlohmann::detail::out_of_range",
|
||||
update_check_url,
|
||||
update_check_path);
|
||||
return {};
|
||||
} catch (nlohmann::detail::type_error&) {
|
||||
} catch (nlohmann::detail::type_error &) {
|
||||
LOG_ERROR(Frontend,
|
||||
"Parsing JSON response from {}{} failed during update check: "
|
||||
"nlohmann::detail::type_error",
|
||||
|
||||
@@ -517,8 +517,8 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent)
|
||||
PAIR(FramePacingMode, Target_Auto, tr("Auto")),
|
||||
PAIR(FramePacingMode, Target_30, tr("30 FPS")),
|
||||
PAIR(FramePacingMode, Target_60, tr("60 FPS")),
|
||||
PAIR(FramePacingMode, Target_90, tr("90 FPS")),
|
||||
PAIR(FramePacingMode, Target_120, tr("120 FPS")),
|
||||
PAIR(FramePacingMode, Target_240, tr("240 FPS")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::VramUsageMode>::Index(),
|
||||
{
|
||||
|
||||
@@ -219,9 +219,6 @@ struct Values {
|
||||
QVector<u64> favorited_ids;
|
||||
QMap<u64, QDir> ryujinx_link_paths;
|
||||
|
||||
// perf overlay
|
||||
Setting<bool> show_perf_overlay{linkage, false, "show_perf_overlay", Category::UiGameList};
|
||||
|
||||
// Compatibility List
|
||||
Setting<bool> show_compat{linkage, true, "show_compat", Category::UiGameList};
|
||||
|
||||
@@ -252,40 +249,39 @@ void RestoreWindowState(std::unique_ptr<QtConfig>& qtConfig);
|
||||
// This must be in alphabetical order according to action name as it must have the same order as
|
||||
// UISetting::values.shortcuts, which is alphabetically ordered.
|
||||
// clang-format off
|
||||
const std::array<Shortcut, 33> default_hotkeys{{
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+M"), std::string("Home+Dpad_Right"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("-"), std::string("Home+Dpad_Down"), Qt::ApplicationShortcut, true}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("="), std::string("Home+Dpad_Up"), Qt::ApplicationShortcut, true}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+P"), std::string("Screenshot"), Qt::WidgetWithChildrenShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F8"), std::string("Home+L"), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F10"), std::string("Home+X"), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change GPU Mode")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F9"), std::string("Home+R"), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Configure")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+,"), std::string(""), Qt::WidgetWithChildrenShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Configure Current Game")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+."), std::string(""), Qt::WidgetWithChildrenShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Continue/Pause Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F4"), std::string("Home+Plus"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Esc"), std::string(""), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Eden")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+Q"), std::string("Home+Minus"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F11"), std::string("Home+B"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+O"), std::string(""), Qt::WidgetWithChildrenShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F2"), std::string("Home+A"), Qt::WidgetWithChildrenShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Browse Public Game Lobby")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+B"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Create Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+N"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Direct Connect to Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+C"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Leave Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+L"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Show Current Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+R"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F6"), std::string("R+Plus+Minus"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F5"), std::string("L+Plus+Minus"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F7"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Reset")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F6"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F5"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F"), std::string(""), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+U"), std::string("Home+Y"), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Turbo Speed")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+Z"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Slow Speed")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+X"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F9"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string(""), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+S"), std::string(""), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Performance Overlay")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+V"), std::string(""), Qt::WindowShortcut, false}},
|
||||
const std::array<Shortcut, 32> default_hotkeys{{
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+M"), std::string("Home+Dpad_Right"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("-"), std::string("Home+Dpad_Down"), Qt::ApplicationShortcut, true}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("="), std::string("Home+Dpad_Up"), Qt::ApplicationShortcut, true}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+P"), std::string("Screenshot"), Qt::WidgetWithChildrenShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F8"), std::string("Home+L"), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F10"), std::string("Home+X"), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change GPU Mode")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F9"), std::string("Home+R"), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Configure")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+,"), std::string(""), Qt::WidgetWithChildrenShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Configure Current Game")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+."), std::string(""), Qt::WidgetWithChildrenShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Continue/Pause Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F4"), std::string("Home+Plus"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Esc"), std::string(""), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Eden")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+Q"), std::string("Home+Minus"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F11"), std::string("Home+B"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+O"), std::string(""), Qt::WidgetWithChildrenShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F2"), std::string("Home+A"), Qt::WidgetWithChildrenShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Browse Public Game Lobby")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+B"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Create Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+N"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Direct Connect to Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+C"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Leave Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+L"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Show Current Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+R"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F6"), std::string("R+Plus+Minus"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F5"), std::string("L+Plus+Minus"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F7"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Reset")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F6"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F5"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F"), std::string(""), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+U"), std::string("Home+Y"), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Turbo Speed")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+Z"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Slow Speed")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+X"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F9"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string(""), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+S"), std::string(""), Qt::WindowShortcut, false}},
|
||||
}};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -684,6 +684,7 @@ void BufferCache<P>::PopAsyncBuffers() {
|
||||
auto& async_buffer = async_buffers.front();
|
||||
u8* base = async_buffer->mapped_span.data();
|
||||
const size_t base_offset = async_buffer->offset;
|
||||
Common::RangeSet<DAddr> ranges_to_remove;
|
||||
for (const auto& copy : downloads) {
|
||||
const DAddr device_addr = static_cast<DAddr>(copy.src_offset);
|
||||
const u64 dst_offset = copy.dst_offset - base_offset;
|
||||
@@ -693,9 +694,11 @@ void BufferCache<P>::PopAsyncBuffers() {
|
||||
end - start);
|
||||
});
|
||||
async_downloads.Subtract(device_addr, copy.size, [&](DAddr start, DAddr end) {
|
||||
gpu_modified_ranges.Subtract(start, end - start);
|
||||
ranges_to_remove.Add(start, end - start);
|
||||
});
|
||||
}
|
||||
ranges_to_remove.ForEach(
|
||||
[&](DAddr start, DAddr end) { gpu_modified_ranges.Subtract(start, end - start); });
|
||||
async_buffers_death_ring.emplace_back(*async_buffer);
|
||||
async_buffers.pop_front();
|
||||
pending_downloads.pop_front();
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "common/div_ceil.h"
|
||||
#include "common/literals.h"
|
||||
#include "common/lru_cache.h"
|
||||
#include "common/page_bitset_range_set.h"
|
||||
#include "common/range_sets.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/settings.h"
|
||||
@@ -489,7 +490,7 @@ private:
|
||||
|
||||
MemoryTracker memory_tracker;
|
||||
Common::RangeSet<DAddr> uncommitted_gpu_modified_ranges;
|
||||
Common::RangeSet<DAddr> gpu_modified_ranges;
|
||||
Common::PageBitsetRangeSet<DAddr, CACHING_PAGEBITS, (1ULL << 34)> gpu_modified_ranges;
|
||||
std::deque<Common::RangeSet<DAddr>> committed_gpu_modified_ranges;
|
||||
|
||||
// Async Buffers
|
||||
|
||||
@@ -89,7 +89,7 @@ public:
|
||||
: HLEMacroImpl(maxwell3d_)
|
||||
{}
|
||||
|
||||
void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
|
||||
void Execute(std::span<const u32> parameters, [[maybe_unused]] u32 method) override {
|
||||
auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[0]);
|
||||
if (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology)) {
|
||||
Fallback(parameters);
|
||||
@@ -120,7 +120,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void Fallback(const std::vector<u32>& parameters) {
|
||||
void Fallback(std::span<const u32> parameters) {
|
||||
SCOPE_EXIT {
|
||||
if (extended) {
|
||||
maxwell3d.engine_state = Maxwell3D::EngineHint::None;
|
||||
@@ -167,7 +167,7 @@ class HLE_DrawIndexedIndirect final : public HLEMacroImpl {
|
||||
public:
|
||||
explicit HLE_DrawIndexedIndirect(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
|
||||
|
||||
void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
|
||||
void Execute(std::span<const u32> parameters, [[maybe_unused]] u32 method) override {
|
||||
auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[0]);
|
||||
if (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology)) {
|
||||
Fallback(parameters);
|
||||
@@ -207,7 +207,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void Fallback(const std::vector<u32>& parameters) {
|
||||
void Fallback(std::span<const u32> parameters) {
|
||||
maxwell3d.RefreshParameters();
|
||||
const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]);
|
||||
const u32 element_base = parameters[4];
|
||||
@@ -238,7 +238,7 @@ class HLE_MultiLayerClear final : public HLEMacroImpl {
|
||||
public:
|
||||
explicit HLE_MultiLayerClear(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
|
||||
|
||||
void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
|
||||
void Execute(std::span<const u32> parameters, [[maybe_unused]] u32 method) override {
|
||||
maxwell3d.RefreshParameters();
|
||||
ASSERT(parameters.size() == 1);
|
||||
|
||||
@@ -256,7 +256,7 @@ class HLE_MultiDrawIndexedIndirectCount final : public HLEMacroImpl {
|
||||
public:
|
||||
explicit HLE_MultiDrawIndexedIndirectCount(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
|
||||
|
||||
void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
|
||||
void Execute(std::span<const u32> parameters, [[maybe_unused]] u32 method) override {
|
||||
const auto topology = Maxwell3D::Regs::PrimitiveTopology(parameters[2]);
|
||||
if (!IsTopologySafe(topology)) {
|
||||
Fallback(parameters);
|
||||
@@ -301,7 +301,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void Fallback(const std::vector<u32>& parameters) {
|
||||
void Fallback(std::span<const u32> parameters) {
|
||||
SCOPE_EXIT {
|
||||
// Clean everything.
|
||||
maxwell3d.regs.vertex_id_base = 0x0;
|
||||
@@ -347,7 +347,7 @@ class HLE_DrawIndirectByteCount final : public HLEMacroImpl {
|
||||
public:
|
||||
explicit HLE_DrawIndirectByteCount(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
|
||||
|
||||
void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
|
||||
void Execute(std::span<const u32> parameters, [[maybe_unused]] u32 method) override {
|
||||
const bool force = maxwell3d.Rasterizer().HasDrawTransformFeedback();
|
||||
|
||||
auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0xFFFFU);
|
||||
@@ -372,7 +372,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void Fallback(const std::vector<u32>& parameters) {
|
||||
void Fallback(std::span<const u32> parameters) {
|
||||
maxwell3d.RefreshParameters();
|
||||
|
||||
maxwell3d.regs.draw.begin = parameters[0];
|
||||
@@ -381,7 +381,8 @@ private:
|
||||
|
||||
maxwell3d.draw_manager->DrawArray(
|
||||
maxwell3d.regs.draw.topology, 0,
|
||||
maxwell3d.regs.draw_auto_byte_count / maxwell3d.regs.draw_auto_stride, 0, 1);
|
||||
maxwell3d.regs.draw_auto_stride > 0 ? maxwell3d.regs.draw_auto_byte_count / maxwell3d.regs.draw_auto_stride : 0,
|
||||
0, 1);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -389,7 +390,7 @@ class HLE_C713C83D8F63CCF3 final : public HLEMacroImpl {
|
||||
public:
|
||||
explicit HLE_C713C83D8F63CCF3(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
|
||||
|
||||
void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
|
||||
void Execute(std::span<const u32> parameters, [[maybe_unused]] u32 method) override {
|
||||
maxwell3d.RefreshParameters();
|
||||
const u32 offset = (parameters[0] & 0x3FFFFFFF) << 2;
|
||||
const u32 address = maxwell3d.regs.shadow_scratch[24];
|
||||
@@ -405,7 +406,7 @@ class HLE_D7333D26E0A93EDE final : public HLEMacroImpl {
|
||||
public:
|
||||
explicit HLE_D7333D26E0A93EDE(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
|
||||
|
||||
void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
|
||||
void Execute(std::span<const u32> parameters, [[maybe_unused]] u32 method) override {
|
||||
maxwell3d.RefreshParameters();
|
||||
const size_t index = parameters[0];
|
||||
const u32 address = maxwell3d.regs.shadow_scratch[42 + index];
|
||||
@@ -421,7 +422,7 @@ class HLE_BindShader final : public HLEMacroImpl {
|
||||
public:
|
||||
explicit HLE_BindShader(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
|
||||
|
||||
void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
|
||||
void Execute(std::span<const u32> parameters, [[maybe_unused]] u32 method) override {
|
||||
maxwell3d.RefreshParameters();
|
||||
auto& regs = maxwell3d.regs;
|
||||
const u32 index = parameters[0];
|
||||
@@ -451,7 +452,7 @@ class HLE_SetRasterBoundingBox final : public HLEMacroImpl {
|
||||
public:
|
||||
explicit HLE_SetRasterBoundingBox(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
|
||||
|
||||
void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
|
||||
void Execute(std::span<const u32> parameters, [[maybe_unused]] u32 method) override {
|
||||
maxwell3d.RefreshParameters();
|
||||
const u32 raster_mode = parameters[0];
|
||||
auto& regs = maxwell3d.regs;
|
||||
@@ -467,7 +468,7 @@ class HLE_ClearConstBuffer final : public HLEMacroImpl {
|
||||
public:
|
||||
explicit HLE_ClearConstBuffer(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
|
||||
|
||||
void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
|
||||
void Execute(std::span<const u32> parameters, [[maybe_unused]] u32 method) override {
|
||||
maxwell3d.RefreshParameters();
|
||||
static constexpr std::array<u32, base_size> zeroes{};
|
||||
auto& regs = maxwell3d.regs;
|
||||
@@ -483,7 +484,7 @@ class HLE_ClearMemory final : public HLEMacroImpl {
|
||||
public:
|
||||
explicit HLE_ClearMemory(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
|
||||
|
||||
void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
|
||||
void Execute(std::span<const u32> parameters, [[maybe_unused]] u32 method) override {
|
||||
maxwell3d.RefreshParameters();
|
||||
|
||||
const u32 needed_memory = parameters[2] / sizeof(u32);
|
||||
@@ -507,7 +508,7 @@ class HLE_TransformFeedbackSetup final : public HLEMacroImpl {
|
||||
public:
|
||||
explicit HLE_TransformFeedbackSetup(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
|
||||
|
||||
void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
|
||||
void Execute(std::span<const u32> parameters, [[maybe_unused]] u32 method) override {
|
||||
maxwell3d.RefreshParameters();
|
||||
|
||||
auto& regs = maxwell3d.regs;
|
||||
@@ -560,12 +561,12 @@ std::unique_ptr<CachedMacro> HLEMacro::GetHLEProgram(u64 hash) const {
|
||||
namespace {
|
||||
class MacroInterpreterImpl final : public CachedMacro {
|
||||
public:
|
||||
explicit MacroInterpreterImpl(Engines::Maxwell3D& maxwell3d_, const std::vector<u32>& code_)
|
||||
explicit MacroInterpreterImpl(Engines::Maxwell3D& maxwell3d_, std::span<const u32> code_)
|
||||
: CachedMacro(maxwell3d_)
|
||||
, code{code_}
|
||||
{}
|
||||
|
||||
void Execute(const std::vector<u32>& params, u32 method) override;
|
||||
void Execute(std::span<const u32> params, u32 method) override;
|
||||
|
||||
private:
|
||||
/// Resets the execution engine state, zeroing registers, etc.
|
||||
@@ -630,10 +631,10 @@ private:
|
||||
u32 next_parameter_index = 0;
|
||||
|
||||
bool carry_flag = false;
|
||||
const std::vector<u32>& code;
|
||||
std::span<const u32> code;
|
||||
};
|
||||
|
||||
void MacroInterpreterImpl::Execute(const std::vector<u32>& params, u32 method) {
|
||||
void MacroInterpreterImpl::Execute(std::span<const u32> params, u32 method) {
|
||||
Reset();
|
||||
|
||||
registers[1] = params[0];
|
||||
@@ -932,7 +933,7 @@ static const auto default_cg_mode = nullptr; //Allow RWE
|
||||
|
||||
class MacroJITx64Impl final : public Xbyak::CodeGenerator, public CachedMacro {
|
||||
public:
|
||||
explicit MacroJITx64Impl(Engines::Maxwell3D& maxwell3d_, const std::vector<u32>& code_)
|
||||
explicit MacroJITx64Impl(Engines::Maxwell3D& maxwell3d_, std::span<const u32> code_)
|
||||
: Xbyak::CodeGenerator(MAX_CODE_SIZE, default_cg_mode)
|
||||
, CachedMacro(maxwell3d_)
|
||||
, code{code_}
|
||||
@@ -940,7 +941,7 @@ public:
|
||||
Compile();
|
||||
}
|
||||
|
||||
void Execute(const std::vector<u32>& parameters, u32 method) override;
|
||||
void Execute(std::span<const u32> parameters, u32 method) override;
|
||||
|
||||
void Compile_ALU(Macro::Opcode opcode);
|
||||
void Compile_AddImmediate(Macro::Opcode opcode);
|
||||
@@ -992,10 +993,10 @@ private:
|
||||
bool is_delay_slot{};
|
||||
u32 pc{};
|
||||
|
||||
const std::vector<u32>& code;
|
||||
std::span<const u32> code;
|
||||
};
|
||||
|
||||
void MacroJITx64Impl::Execute(const std::vector<u32>& parameters, u32 method) {
|
||||
void MacroJITx64Impl::Execute(std::span<const u32> parameters, u32 method) {
|
||||
ASSERT_OR_EXECUTE(program != nullptr, { return; });
|
||||
JITState state{};
|
||||
state.maxwell3d = &maxwell3d;
|
||||
@@ -1591,7 +1592,7 @@ void MacroEngine::ClearCode(u32 method) {
|
||||
uploaded_macro_code.erase(method);
|
||||
}
|
||||
|
||||
void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) {
|
||||
void MacroEngine::Execute(u32 method, std::span<const u32> parameters) {
|
||||
auto compiled_macro = macro_cache.find(method);
|
||||
if (compiled_macro != macro_cache.end()) {
|
||||
const auto& cache_info = compiled_macro->second;
|
||||
@@ -1648,7 +1649,7 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) {
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<CachedMacro> MacroEngine::Compile(const std::vector<u32>& code) {
|
||||
std::unique_ptr<CachedMacro> MacroEngine::Compile(std::span<const u32> code) {
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
if (!is_interpreted)
|
||||
return std::make_unique<MacroJITx64Impl>(maxwell3d, code);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <ankerl/unordered_dense.h>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
@@ -107,7 +108,7 @@ public:
|
||||
/// Executes the macro code with the specified input parameters.
|
||||
/// @param parameters The parameters of the macro
|
||||
/// @param method The method to execute
|
||||
virtual void Execute(const std::vector<u32>& parameters, u32 method) = 0;
|
||||
virtual void Execute(std::span<const u32> parameters, u32 method) = 0;
|
||||
Engines::Maxwell3D& maxwell3d;
|
||||
};
|
||||
|
||||
@@ -134,10 +135,10 @@ public:
|
||||
void ClearCode(u32 method);
|
||||
|
||||
// Compiles the macro if its not in the cache, and executes the compiled macro
|
||||
void Execute(u32 method, const std::vector<u32>& parameters);
|
||||
void Execute(u32 method, std::span<const u32> parameters);
|
||||
|
||||
protected:
|
||||
std::unique_ptr<CachedMacro> Compile(const std::vector<u32>& code);
|
||||
std::unique_ptr<CachedMacro> Compile(std::span<const u32> code);
|
||||
|
||||
private:
|
||||
struct CacheInfo {
|
||||
|
||||
@@ -436,7 +436,23 @@ void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayo
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
// Blit image barrier - transition can happen at any stage
|
||||
// Using specific stages for better parallelism, but keeping broad since this is a general utility
|
||||
const VkPipelineStageFlags src_stages_blit =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
const VkPipelineStageFlags dst_stages_blit =
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_blit, dst_stages_blit,
|
||||
0, barrier);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,14 +12,12 @@
|
||||
#include "shader_recompiler/shader_info.h"
|
||||
#include "video_core/renderer_vulkan/vk_texture_cache.h"
|
||||
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
|
||||
#include "video_core/surface.h"
|
||||
#include "video_core/texture_cache/types.h"
|
||||
#include "video_core/vulkan_common/vulkan_device.h"
|
||||
|
||||
namespace Vulkan {
|
||||
|
||||
using Shader::Backend::SPIRV::NUM_TEXTURE_AND_IMAGE_SCALING_WORDS;
|
||||
using VideoCore::Surface::IsPixelFormatInteger;
|
||||
|
||||
class DescriptorLayoutBuilder {
|
||||
public:
|
||||
@@ -193,14 +191,10 @@ inline void PushImageDescriptors(TextureCache& texture_cache,
|
||||
ImageView& image_view{texture_cache.GetImageView(image_view_id)};
|
||||
const VkImageView vk_image_view{image_view.Handle(desc.type)};
|
||||
const Sampler& sampler{texture_cache.GetSampler(sampler_id)};
|
||||
// Integer formats don't support VK_FILTER_LINEAR in Vulkan.
|
||||
const bool needs_nearest{sampler.HasLinearFilter() &&
|
||||
IsPixelFormatInteger(image_view.format)};
|
||||
const bool use_fallback_sampler{sampler.HasAddedAnisotropy() &&
|
||||
!image_view.SupportsAnisotropy()};
|
||||
const VkSampler vk_sampler{needs_nearest ? sampler.HandleWithNearestFilter()
|
||||
: use_fallback_sampler ? sampler.HandleWithDefaultAnisotropy()
|
||||
: sampler.Handle()};
|
||||
const VkSampler vk_sampler{use_fallback_sampler ? sampler.HandleWithDefaultAnisotropy()
|
||||
: sampler.Handle()};
|
||||
guest_descriptor_queue.AddSampledImage(vk_image_view, vk_sampler);
|
||||
rescaling.PushTexture(texture_cache.IsRescaling(image_view));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
@@ -68,7 +68,16 @@ void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayo
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
// Present path - use specific stages for better parallelism on tile-based GPUs
|
||||
const VkPipelineStageFlags src_stages =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
const VkPipelineStageFlags dst_stages =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages, dst_stages,
|
||||
0, barrier);
|
||||
}
|
||||
|
||||
@@ -103,12 +112,15 @@ void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& sc
|
||||
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([&](vk::CommandBuffer cmdbuf) {
|
||||
TransitionImageLayout(cmdbuf, *image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
const VkImageLayout transfer_dst_layout = device.IsKhrUnifiedImageLayoutsSupported()
|
||||
? VK_IMAGE_LAYOUT_GENERAL
|
||||
: VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
TransitionImageLayout(cmdbuf, *image, transfer_dst_layout,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
cmdbuf.CopyBufferToImage(*upload_buffer, *image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
cmdbuf.CopyBufferToImage(*upload_buffer, *image, transfer_dst_layout,
|
||||
regions);
|
||||
TransitionImageLayout(cmdbuf, *image, VK_IMAGE_LAYOUT_GENERAL,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
transfer_dst_layout);
|
||||
});
|
||||
scheduler.Finish();
|
||||
}
|
||||
@@ -151,11 +163,12 @@ void DownloadColorImage(vk::CommandBuffer& cmdbuf, VkImage image, VkBuffer buffe
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
// Host will read the downloaded data
|
||||
static constexpr VkMemoryBarrier memory_write_barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_HOST_READ_BIT,
|
||||
};
|
||||
const VkBufferImageCopy copy{
|
||||
.bufferOffset = 0,
|
||||
@@ -170,10 +183,20 @@ void DownloadColorImage(vk::CommandBuffer& cmdbuf, VkImage image, VkBuffer buffe
|
||||
.imageOffset{.x = 0, .y = 0, .z = 0},
|
||||
.imageExtent{extent},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||
const VkPipelineStageFlags src_stages_copy =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_copy, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||
read_barrier);
|
||||
cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, copy);
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0,
|
||||
const VkPipelineStageFlags dst_stages_copy =
|
||||
VK_PIPELINE_STAGE_HOST_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages_copy, 0,
|
||||
memory_write_barrier, nullptr, image_write_barrier);
|
||||
}
|
||||
|
||||
|
||||
@@ -436,13 +436,27 @@ void BufferCacheRuntime::CopyBuffer(VkBuffer dst_buffer, VkBuffer src_buffer,
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([src_buffer, dst_buffer, vk_copies, barrier](vk::CommandBuffer cmdbuf) {
|
||||
if (barrier) {
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
// Buffer writes can come from vertex input, shaders, or compute
|
||||
const VkPipelineStageFlags src_stages =
|
||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, READ_BARRIER);
|
||||
}
|
||||
cmdbuf.CopyBuffer(src_buffer, dst_buffer, VideoCommon::FixSmallVectorADL(vk_copies));
|
||||
if (barrier) {
|
||||
// Buffer reads can go to vertex input, shaders, or compute
|
||||
const VkPipelineStageFlags dst_stages =
|
||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, WRITE_BARRIER);
|
||||
dst_stages, 0, WRITE_BARRIER);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -456,21 +470,36 @@ void BufferCacheRuntime::PreCopyBarrier() {
|
||||
};
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
const VkPipelineStageFlags src_stages =
|
||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, READ_BARRIER);
|
||||
});
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::PostCopyBarrier() {
|
||||
// Specific access flags for buffer destinations: vertex input, uniforms, storage, index
|
||||
static constexpr VkMemoryBarrier WRITE_BARRIER{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDEX_READ_BIT |
|
||||
VK_ACCESS_UNIFORM_READ_BIT | VK_ACCESS_SHADER_READ_BIT |
|
||||
VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
|
||||
};
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
const VkPipelineStageFlags dst_stages =
|
||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages,
|
||||
0, WRITE_BARRIER);
|
||||
});
|
||||
}
|
||||
@@ -494,10 +523,24 @@ void BufferCacheRuntime::ClearBuffer(VkBuffer dest_buffer, u32 offset, size_t si
|
||||
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([dest_buffer, offset, size, value](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
// Buffer writes can come from vertex input, shaders, or compute
|
||||
const VkPipelineStageFlags src_stages_clear =
|
||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_clear, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, READ_BARRIER);
|
||||
cmdbuf.FillBuffer(dest_buffer, offset, size, value);
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
// Buffer reads can go to vertex input, shaders, or compute
|
||||
const VkPipelineStageFlags dst_stages_clear =
|
||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages_clear,
|
||||
0, WRITE_BARRIER);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -446,13 +446,26 @@ void ConditionalRenderingResolvePass::Resolve(VkBuffer dst_buffer, VkBuffer src_
|
||||
const VkDescriptorSet set = descriptor_allocator.Commit();
|
||||
device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
|
||||
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
// Memory writes can come from graphics or compute stages
|
||||
const VkPipelineStageFlags src_stages_compute =
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_compute,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, read_barrier);
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
|
||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
|
||||
cmdbuf.Dispatch(1, 1, 1);
|
||||
// Conditional rendering result used by draw indirect or conditional rendering
|
||||
const VkPipelineStageFlags dst_stages_cond =
|
||||
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT |
|
||||
VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT |
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, write_barrier);
|
||||
dst_stages_cond, 0, write_barrier);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -520,14 +533,29 @@ void QueriesPrefixScanPass::Run(VkBuffer accumulation_buffer, VkBuffer dst_buffe
|
||||
const VkDescriptorSet set = descriptor_allocator.Commit();
|
||||
device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
|
||||
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
// Memory writes can come from graphics or compute stages
|
||||
const VkPipelineStageFlags src_stages_scan =
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_scan,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, read_barrier);
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
|
||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
|
||||
cmdbuf.PushConstants(*layout, VK_SHADER_STAGE_COMPUTE_BIT, uniforms);
|
||||
cmdbuf.Dispatch(1, 1, 1);
|
||||
// Query prefix scan results used by draw indirect, conditional rendering, or shaders
|
||||
const VkPipelineStageFlags dst_stages_scan =
|
||||
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT |
|
||||
VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT |
|
||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, write_barrier);
|
||||
dst_stages_scan, 0, write_barrier);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -579,8 +607,15 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(is_initialized ? VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
|
||||
: VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
// If initialized, memory writes can come from graphics or compute stages
|
||||
const VkPipelineStageFlags src_stages_astc = is_initialized ?
|
||||
(VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT) :
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_astc,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, image_barrier);
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, vk_pipeline);
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
@@ -441,7 +441,13 @@ void PresentManager::CopyToSwapchainImpl(Frame* frame) {
|
||||
},
|
||||
};
|
||||
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, {},
|
||||
// Previous operations that might have written to the frame image
|
||||
const VkPipelineStageFlags src_stages_present =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_present, VK_PIPELINE_STAGE_TRANSFER_BIT, {},
|
||||
{}, {}, pre_barriers);
|
||||
|
||||
if (blit_supported) {
|
||||
|
||||
@@ -809,12 +809,19 @@ public:
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_SHADER_READ_BIT,
|
||||
};
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([](vk::CommandBuffer cmdbuf) {
|
||||
// After transfer, results may be read by host or used in subsequent operations
|
||||
const VkPipelineStageFlags dst_stages_query =
|
||||
VK_PIPELINE_STAGE_HOST_BIT |
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, WRITE_BARRIER);
|
||||
dst_stages_query, 0, WRITE_BARRIER);
|
||||
});
|
||||
|
||||
std::scoped_lock lk(flush_guard);
|
||||
@@ -942,7 +949,7 @@ private:
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
|
||||
};
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([dst_buffer = current_bank->GetBuffer(),
|
||||
@@ -1475,22 +1482,40 @@ void QueryCacheRuntime::Barriers(bool is_prebarrier) {
|
||||
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
};
|
||||
// Query results may be read by host or used in shaders/indirect commands
|
||||
static constexpr VkMemoryBarrier WRITE_BARRIER{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_SHADER_READ_BIT |
|
||||
VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
|
||||
};
|
||||
impl->scheduler.RequestOutsideRenderPassOperationContext();
|
||||
if (is_prebarrier) {
|
||||
impl->scheduler.Record([](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
// Query data can be written by graphics or compute stages
|
||||
const VkPipelineStageFlags src_stages_query =
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_query,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, READ_BARRIER);
|
||||
});
|
||||
} else {
|
||||
impl->scheduler.Record([](vk::CommandBuffer cmdbuf) {
|
||||
// Query results may be read by host or used in shaders/indirect commands
|
||||
const VkPipelineStageFlags dst_stages_query =
|
||||
VK_PIPELINE_STAGE_HOST_BIT |
|
||||
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT |
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, WRITE_BARRIER);
|
||||
dst_stages_query, 0, WRITE_BARRIER);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,14 +586,23 @@ void RasterizerVulkan::DispatchCompute() {
|
||||
}
|
||||
const std::array<u32, 3> dim{qmd.grid_dim_x, qmd.grid_dim_y, qmd.grid_dim_z};
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
// Compute shader reads from storage buffers, uniforms, and images
|
||||
static constexpr VkMemoryBarrier READ_BARRIER{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
|
||||
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_UNIFORM_READ_BIT,
|
||||
};
|
||||
scheduler.Record([](vk::CommandBuffer cmdbuf) { cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
0, READ_BARRIER); });
|
||||
scheduler.Record([](vk::CommandBuffer cmdbuf) {
|
||||
// Memory writes can come from graphics or compute stages
|
||||
const VkPipelineStageFlags src_stages =
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
0, READ_BARRIER);
|
||||
});
|
||||
scheduler.Record([dim](vk::CommandBuffer cmdbuf) { cmdbuf.Dispatch(dim[0], dim[1], dim[2]); });
|
||||
|
||||
// Log compute dispatch
|
||||
|
||||
@@ -44,13 +44,19 @@ using VideoCore::Surface::SurfaceType;
|
||||
}
|
||||
|
||||
VkAttachmentDescription AttachmentDescription(const Device& device, PixelFormat format,
|
||||
VkSampleCountFlagBits samples) {
|
||||
VkSampleCountFlagBits samples,
|
||||
bool is_depth_stencil) {
|
||||
using MaxwellToVK::SurfaceFormat;
|
||||
|
||||
const SurfaceType surface_type = GetSurfaceType(format);
|
||||
const bool has_stencil = surface_type == SurfaceType::DepthStencil ||
|
||||
surface_type == SurfaceType::Stencil;
|
||||
|
||||
// Use optimal layouts for attachments - this allows drivers to optimize tiling and access patterns
|
||||
const VkImageLayout attachment_layout = is_depth_stencil
|
||||
? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
|
||||
: VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
return {
|
||||
.flags = {},
|
||||
.format = SurfaceFormat(device, FormatType::Optimal, true, format).format,
|
||||
@@ -61,8 +67,8 @@ using VideoCore::Surface::SurfaceType;
|
||||
: VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||
.stencilStoreOp = has_stencil ? VK_ATTACHMENT_STORE_OP_STORE
|
||||
: VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.finalLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.initialLayout = attachment_layout,
|
||||
.finalLayout = attachment_layout,
|
||||
};
|
||||
}
|
||||
} // Anonymous namespace
|
||||
@@ -84,10 +90,10 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
|
||||
const bool is_valid{format != PixelFormat::Invalid};
|
||||
references[index] = VkAttachmentReference{
|
||||
.attachment = is_valid ? num_colors : VK_ATTACHMENT_UNUSED,
|
||||
.layout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
};
|
||||
if (is_valid) {
|
||||
descriptions.push_back(AttachmentDescription(*device, format, key.samples));
|
||||
descriptions.push_back(AttachmentDescription(*device, format, key.samples, false));
|
||||
num_attachments = static_cast<u32>(index + 1);
|
||||
++num_colors;
|
||||
}
|
||||
@@ -97,9 +103,9 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
|
||||
if (key.depth_format != PixelFormat::Invalid) {
|
||||
depth_reference = VkAttachmentReference{
|
||||
.attachment = num_colors,
|
||||
.layout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
};
|
||||
descriptions.push_back(AttachmentDescription(*device, key.depth_format, key.samples));
|
||||
descriptions.push_back(AttachmentDescription(*device, key.depth_format, key.samples, true));
|
||||
}
|
||||
const VkSubpassDescription subpass{
|
||||
.flags = 0,
|
||||
|
||||
@@ -168,6 +168,10 @@ bool Scheduler::UpdateGraphicsPipeline(GraphicsPipeline* pipeline) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pipeline->UsesExtendedDynamicState() && !pipeline->HasDynamicVertexInput()) {
|
||||
state_tracker.InvalidateVertexBufferState();
|
||||
}
|
||||
|
||||
if (!pipeline->UsesExtendedDynamicState()) {
|
||||
state.needs_state_enable_refresh = true;
|
||||
} else if (state.needs_state_enable_refresh) {
|
||||
@@ -264,14 +268,26 @@ u64 Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_se
|
||||
const u64 signal_value = master_semaphore->NextTick();
|
||||
RecordWithUploadBuffer([signal_semaphore, wait_semaphore, signal_value,
|
||||
this](vk::CommandBuffer cmdbuf, vk::CommandBuffer upload_cmdbuf) {
|
||||
// Specific access flags for upload destinations: vertex input, uniforms, storage, index, textures
|
||||
static constexpr VkMemoryBarrier WRITE_BARRIER{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDEX_READ_BIT |
|
||||
VK_ACCESS_UNIFORM_READ_BIT | VK_ACCESS_SHADER_READ_BIT |
|
||||
VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
|
||||
};
|
||||
// Specify exact stages that need the transfer results instead of ALL_COMMANDS_BIT
|
||||
upload_cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, WRITE_BARRIER);
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
0, WRITE_BARRIER);
|
||||
upload_cmdbuf.End();
|
||||
cmdbuf.End();
|
||||
|
||||
@@ -332,11 +348,11 @@ void Scheduler::EndRenderPass()
|
||||
|
||||
query_cache->CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, false);
|
||||
query_cache->NotifySegment(false);
|
||||
|
||||
Record([num_images = num_renderpass_images,
|
||||
images = renderpass_images,
|
||||
ranges = renderpass_image_ranges](vk::CommandBuffer cmdbuf) {
|
||||
std::array<VkImageMemoryBarrier, 9> barriers;
|
||||
std::vector<VkImageMemoryBarrier> barriers(num_images);
|
||||
VkPipelineStageFlags src_stages = 0;
|
||||
for (size_t i = 0; i < num_images; ++i) {
|
||||
const VkImageSubresourceRange& range = ranges[i];
|
||||
const bool is_color = (range.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0;
|
||||
@@ -344,38 +360,76 @@ void Scheduler::EndRenderPass()
|
||||
& (VK_IMAGE_ASPECT_DEPTH_BIT
|
||||
| VK_IMAGE_ASPECT_STENCIL_BIT)) !=0;
|
||||
|
||||
// Determine optimal destination layout based on image usage
|
||||
// After render pass, images may be used as shader resources or as attachments again
|
||||
// Use optimal layouts to allow driver optimizations
|
||||
VkAccessFlags src_access = 0;
|
||||
VkAccessFlags dst_access = 0;
|
||||
VkPipelineStageFlags this_stage = 0;
|
||||
VkImageLayout new_layout;
|
||||
|
||||
if (is_color)
|
||||
src_access |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
else if (is_depth_stencil)
|
||||
src_access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
else
|
||||
src_access |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
|
||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
|
||||
if (is_color) {
|
||||
// Color attachments can be read as textures or used as attachments again
|
||||
src_access = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
this_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
new_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
dst_access = VK_ACCESS_SHADER_READ_BIT
|
||||
| VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
|
||||
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
} else if (is_depth_stencil) {
|
||||
// Depth attachments can be read as textures or used as attachments again
|
||||
src_access = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
this_stage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
|
||||
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
new_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
dst_access = VK_ACCESS_SHADER_READ_BIT
|
||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
|
||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
} else {
|
||||
// Fallback to GENERAL for unknown usage
|
||||
src_access = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
|
||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
this_stage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
|
||||
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
|
||||
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
new_layout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
dst_access = VK_ACCESS_SHADER_READ_BIT
|
||||
| VK_ACCESS_SHADER_WRITE_BIT
|
||||
| VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
|
||||
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
|
||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
|
||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
}
|
||||
src_stages |= this_stage;
|
||||
barriers[i] = VkImageMemoryBarrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = src_access,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT
|
||||
| VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
|
||||
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
|
||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
|
||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.dstAccessMask = dst_access,
|
||||
.oldLayout = is_color ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
||||
: (is_depth_stencil ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
|
||||
: VK_IMAGE_LAYOUT_GENERAL),
|
||||
.newLayout = new_layout,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = images[i],
|
||||
.subresourceRange = range,
|
||||
};
|
||||
}
|
||||
|
||||
cmdbuf.EndRenderPass();
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
|
||||
// Use specific pipeline stages instead of ALL_COMMANDS_BIT for better parallelism
|
||||
// The destination stages depend on how the images will be used next
|
||||
const VkPipelineStageFlags dst_stages =
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
|
||||
cmdbuf.PipelineBarrier(src_stages,
|
||||
dst_stages,
|
||||
0,
|
||||
nullptr,
|
||||
nullptr,
|
||||
|
||||
@@ -115,27 +115,28 @@ public:
|
||||
/// Waits for the given GPU tick, optionally pacing frames.
|
||||
void Wait(u64 tick, double target_fps = 0.0) {
|
||||
if (Settings::values.use_speed_limit.GetValue() && target_fps > 0.0) {
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
if (start_time == std::chrono::steady_clock::time_point{} || current_target_fps != target_fps) {
|
||||
start_time = now;
|
||||
frame_counter = 0;
|
||||
current_target_fps = target_fps;
|
||||
}
|
||||
frame_counter++;
|
||||
std::chrono::duration<double> frame_interval(1.0 / current_target_fps);
|
||||
auto target_time = start_time + frame_interval * frame_counter;
|
||||
if (target_time > now) {
|
||||
std::this_thread::sleep_until(target_time);
|
||||
auto frame_duration = std::chrono::duration_cast<std::chrono::steady_clock::duration>(std::chrono::duration<double>(1.0 / target_fps));
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
if (now < next_frame_time) {
|
||||
std::this_thread::sleep_until(next_frame_time);
|
||||
next_frame_time += frame_duration;
|
||||
} else {
|
||||
start_time = now;
|
||||
frame_counter = 0;
|
||||
next_frame_time = now + frame_duration;
|
||||
}
|
||||
}
|
||||
if (tick > 0) {
|
||||
if (tick >= master_semaphore->CurrentTick()) {
|
||||
Flush();
|
||||
}
|
||||
master_semaphore->Wait(tick);
|
||||
if (tick > master_semaphore->CurrentTick() && !chunk->Empty()) {
|
||||
Flush();
|
||||
}
|
||||
master_semaphore->Wait(tick);
|
||||
}
|
||||
|
||||
/// Resets the frame pacing state by setting the next frame time.
|
||||
void ResetFramePacing(double target_fps = 0.0) {
|
||||
if (target_fps > 0.0) {
|
||||
auto frame_duration = std::chrono::duration_cast<std::chrono::steady_clock::duration>(std::chrono::duration<double>(1.0 / target_fps));
|
||||
next_frame_time = std::chrono::steady_clock::now() + frame_duration;
|
||||
} else {
|
||||
next_frame_time = std::chrono::steady_clock::time_point{};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,9 +282,7 @@ private:
|
||||
std::condition_variable_any event_cv;
|
||||
std::jthread worker_thread;
|
||||
|
||||
std::chrono::steady_clock::time_point start_time{};
|
||||
u64 frame_counter{};
|
||||
double current_target_fps{};
|
||||
std::chrono::steady_clock::time_point next_frame_time{};
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
@@ -101,6 +101,14 @@ public:
|
||||
(*flags)[Dirty::StateEnable] = true;
|
||||
}
|
||||
|
||||
void InvalidateVertexBufferState() {
|
||||
(*flags)[VideoCommon::Dirty::VertexBuffers] = true;
|
||||
for (int index = VideoCommon::Dirty::VertexBuffer0;
|
||||
index <= VideoCommon::Dirty::VertexBuffer31; ++index) {
|
||||
(*flags)[index] = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool TouchViewports() {
|
||||
const bool dirty_viewports = Exchange(Dirty::Viewports, false);
|
||||
const bool rescale_viewports = Exchange(VideoCommon::Dirty::RescaleViewports, false);
|
||||
|
||||
@@ -146,6 +146,25 @@ void Swapchain::Create(
|
||||
{
|
||||
is_outdated = false;
|
||||
is_suboptimal = false;
|
||||
|
||||
switch (Settings::values.frame_pacing_mode.GetValue()) {
|
||||
case Settings::FramePacingMode::Target_Auto:
|
||||
scheduler.ResetFramePacing();
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_30:
|
||||
scheduler.ResetFramePacing(30.0);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_60:
|
||||
scheduler.ResetFramePacing(60.0);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_120:
|
||||
scheduler.ResetFramePacing(120.0);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_240:
|
||||
scheduler.ResetFramePacing(240.0);
|
||||
break;
|
||||
}
|
||||
|
||||
width = width_;
|
||||
height = height_;
|
||||
#ifdef ANDROID
|
||||
@@ -194,22 +213,24 @@ bool Swapchain::AcquireNextImage() {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (Settings::values.frame_pacing_mode.GetValue()) {
|
||||
case Settings::FramePacingMode::Target_Auto:
|
||||
scheduler.Wait(resource_ticks[image_index]);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_30:
|
||||
scheduler.Wait(resource_ticks[image_index], 30.0);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_60:
|
||||
scheduler.Wait(resource_ticks[image_index], 60.0);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_90:
|
||||
scheduler.Wait(resource_ticks[image_index], 90.0);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_120:
|
||||
scheduler.Wait(resource_ticks[image_index], 120.0);
|
||||
break;
|
||||
if (resource_ticks[image_index] != 0 && !scheduler.IsFree(resource_ticks[image_index])) {
|
||||
switch (Settings::values.frame_pacing_mode.GetValue()) {
|
||||
case Settings::FramePacingMode::Target_Auto:
|
||||
scheduler.Wait(resource_ticks[image_index]);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_30:
|
||||
scheduler.Wait(resource_ticks[image_index], 30.0);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_60:
|
||||
scheduler.Wait(resource_ticks[image_index], 60.0);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_120:
|
||||
scheduler.Wait(resource_ticks[image_index], 120.0);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_240:
|
||||
scheduler.Wait(resource_ticks[image_index], 240.0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
resource_ticks[image_index] = scheduler.CurrentTick();
|
||||
|
||||
@@ -38,7 +38,6 @@ namespace Vulkan {
|
||||
|
||||
using Tegra::Engines::Fermi2D;
|
||||
using Tegra::Texture::SwizzleSource;
|
||||
using Tegra::Texture::TextureFilter;
|
||||
using Tegra::Texture::TextureMipmapFilter;
|
||||
using VideoCommon::BufferImageCopy;
|
||||
using VideoCommon::ImageFlagBits;
|
||||
@@ -537,6 +536,7 @@ struct RangedBarrierRange {
|
||||
};
|
||||
void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage image,
|
||||
VkImageAspectFlags aspect_mask, bool is_initialized,
|
||||
bool use_unified_layouts,
|
||||
std::span<const VkBufferImageCopy> copies) {
|
||||
static constexpr VkAccessFlags WRITE_ACCESS_FLAGS =
|
||||
VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
||||
@@ -551,6 +551,8 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im
|
||||
range.AddLayers(region.imageSubresource);
|
||||
}
|
||||
const VkImageSubresourceRange subresource_range = range.SubresourceRange(aspect_mask);
|
||||
const VkImageLayout transfer_dst_layout =
|
||||
use_unified_layouts ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
|
||||
const VkImageMemoryBarrier read_barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
@@ -558,7 +560,7 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im
|
||||
.srcAccessMask = WRITE_ACCESS_FLAGS,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.newLayout = transfer_dst_layout,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = image,
|
||||
@@ -570,7 +572,7 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = WRITE_ACCESS_FLAGS | READ_ACCESS_FLAGS,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.oldLayout = transfer_dst_layout,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
@@ -582,7 +584,7 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||
read_barrier);
|
||||
cmdbuf.CopyBufferToImage(src_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copies);
|
||||
cmdbuf.CopyBufferToImage(src_buffer, image, transfer_dst_layout, copies);
|
||||
// TODO: Move this to another API
|
||||
cmdbuf.PipelineBarrier(
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
@@ -704,7 +706,7 @@ void TryTransformSwizzleIfNeeded(PixelFormat format, std::array<SwizzleSource, 4
|
||||
|
||||
void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const ImageInfo& info,
|
||||
VkImageAspectFlags aspect_mask, const Settings::ResolutionScalingInfo& resolution,
|
||||
bool up_scaling = true) {
|
||||
bool use_unified_layouts, bool up_scaling = true) {
|
||||
const bool is_2d = info.type == ImageType::e2D;
|
||||
const auto resources = info.resources;
|
||||
const VkExtent2D extent{
|
||||
@@ -718,7 +720,7 @@ void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const
|
||||
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([dst_image, src_image, extent, resources, aspect_mask, resolution, is_2d,
|
||||
vk_filter, up_scaling](vk::CommandBuffer cmdbuf) {
|
||||
vk_filter, up_scaling, use_unified_layouts](vk::CommandBuffer cmdbuf) {
|
||||
const VkOffset2D src_size{
|
||||
.x = static_cast<s32>(up_scaling ? extent.width : resolution.ScaleUp(extent.width)),
|
||||
.y = static_cast<s32>(is_2d && up_scaling ? extent.height
|
||||
@@ -778,6 +780,10 @@ void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
};
|
||||
const VkImageLayout transfer_src_layout =
|
||||
use_unified_layouts ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
const VkImageLayout transfer_dst_layout =
|
||||
use_unified_layouts ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
const std::array read_barriers{
|
||||
VkImageMemoryBarrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
@@ -785,7 +791,7 @@ void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const
|
||||
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
.newLayout = transfer_src_layout,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = src_image,
|
||||
@@ -799,7 +805,7 @@ void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, // Discard contents
|
||||
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.newLayout = transfer_dst_layout,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = dst_image,
|
||||
@@ -811,8 +817,9 @@ void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = 0,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT | VK_ACCESS_MEMORY_READ_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
.oldLayout = transfer_src_layout,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
@@ -823,8 +830,9 @@ void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT | VK_ACCESS_MEMORY_READ_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
.oldLayout = transfer_dst_layout,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
@@ -832,11 +840,26 @@ void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const
|
||||
.subresourceRange = subresource_range,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
// Use specific pipeline stages for better parallelism
|
||||
const VkPipelineStageFlags src_stages =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, nullptr, nullptr, read_barriers);
|
||||
cmdbuf.BlitImage(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, regions, vk_filter);
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
cmdbuf.BlitImage(src_image, transfer_src_layout, dst_image,
|
||||
transfer_dst_layout, regions, vk_filter);
|
||||
// After transfer, images may be used in graphics, compute, or as attachments
|
||||
const VkPipelineStageFlags dst_stages =
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages,
|
||||
0, nullptr, nullptr, write_barriers);
|
||||
});
|
||||
}
|
||||
@@ -1024,11 +1047,12 @@ void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src,
|
||||
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
};
|
||||
// After reinterpret, buffers used as transfer source, uniforms, or storage
|
||||
static constexpr VkMemoryBarrier WRITE_BARRIER{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT,
|
||||
};
|
||||
const std::array pre_barriers{
|
||||
VkImageMemoryBarrier{
|
||||
@@ -1095,18 +1119,39 @@ void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src,
|
||||
.subresourceRange = dst_range.SubresourceRange(dst_aspect_mask),
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
const VkPipelineStageFlags src_stages_transfer =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_transfer, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, {}, {}, pre_barriers);
|
||||
|
||||
cmdbuf.CopyImageToBuffer(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, copy_buffer,
|
||||
vk_in_copies);
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
const VkPipelineStageFlags dst_stages_transfer =
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages_transfer,
|
||||
0, WRITE_BARRIER, nullptr, middle_in_barrier);
|
||||
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
cmdbuf.PipelineBarrier(src_stages_transfer, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, READ_BARRIER, {}, middle_out_barrier);
|
||||
cmdbuf.CopyBufferToImage(copy_buffer, dst_image, VK_IMAGE_LAYOUT_GENERAL, vk_out_copies);
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
// After reinterpret copy, image may be used in shaders or as attachment
|
||||
const VkPipelineStageFlags dst_stages_post =
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages_post,
|
||||
0, {}, {}, post_barriers);
|
||||
});
|
||||
}
|
||||
@@ -1233,7 +1278,12 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
const VkPipelineStageFlags src_stages_resolve =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_resolve, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, nullptr, nullptr, read_barriers);
|
||||
if (is_resolve) {
|
||||
cmdbuf.ResolveImage(src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image,
|
||||
@@ -1246,7 +1296,14 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst
|
||||
src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
MakeImageBlit(dst_region, src_region, dst_layers, src_layers), vk_filter);
|
||||
}
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
// After blit/resolve, image may be used in shaders or as attachment
|
||||
const VkPipelineStageFlags dst_stages_blit =
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages_blit,
|
||||
0, write_barrier);
|
||||
});
|
||||
}
|
||||
@@ -1693,9 +1750,11 @@ void Image::UploadMemory(VkBuffer buffer, VkDeviceSize offset,
|
||||
const VkImage temp_vk_image = *temp_wrapper->original_image;
|
||||
const VkImageAspectFlags vk_aspect_mask = temp_wrapper->aspect_mask;
|
||||
|
||||
scheduler->Record([src_buffer, temp_vk_image, vk_aspect_mask, vk_copies,
|
||||
const bool use_unified_layouts = runtime->device.IsKhrUnifiedImageLayoutsSupported();
|
||||
scheduler->Record([src_buffer, temp_vk_image, vk_aspect_mask, vk_copies, use_unified_layouts,
|
||||
keep = temp_wrapper](vk::CommandBuffer cmdbuf) {
|
||||
CopyBufferToImage(cmdbuf, src_buffer, temp_vk_image, vk_aspect_mask, false, VideoCommon::FixSmallVectorADL(vk_copies));
|
||||
CopyBufferToImage(cmdbuf, src_buffer, temp_vk_image, vk_aspect_mask, false,
|
||||
use_unified_layouts, VideoCommon::FixSmallVectorADL(vk_copies));
|
||||
});
|
||||
|
||||
// Use MSAACopyPass to convert from non-MSAA to MSAA
|
||||
@@ -1732,9 +1791,11 @@ void Image::UploadMemory(VkBuffer buffer, VkDeviceSize offset,
|
||||
const VkImageAspectFlags vk_aspect_mask = aspect_mask;
|
||||
const bool was_initialized = std::exchange(initialized, true);
|
||||
|
||||
const bool use_unified_layouts = runtime->device.IsKhrUnifiedImageLayoutsSupported();
|
||||
scheduler->Record([src_buffer, vk_image, vk_aspect_mask, was_initialized,
|
||||
vk_copies](vk::CommandBuffer cmdbuf) {
|
||||
CopyBufferToImage(cmdbuf, src_buffer, vk_image, vk_aspect_mask, was_initialized, VideoCommon::FixSmallVectorADL(vk_copies));
|
||||
vk_copies, use_unified_layouts](vk::CommandBuffer cmdbuf) {
|
||||
CopyBufferToImage(cmdbuf, src_buffer, vk_image, vk_aspect_mask, was_initialized,
|
||||
use_unified_layouts, VideoCommon::FixSmallVectorADL(vk_copies));
|
||||
});
|
||||
|
||||
if (is_rescaled) {
|
||||
@@ -1824,7 +1885,14 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
const VkPipelineStageFlags src_stages_download =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_download, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, read_barrier);
|
||||
|
||||
for (size_t index = 0; index < buffers.size(); index++) {
|
||||
@@ -1832,17 +1900,20 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
|
||||
vk_copies[index]);
|
||||
}
|
||||
|
||||
// Host will read the downloaded data
|
||||
const VkMemoryBarrier memory_write_barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_HOST_READ_BIT,
|
||||
};
|
||||
// Image will be used for shaders or as attachment
|
||||
const VkImageMemoryBarrier image_write_barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = 0,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
@@ -1856,7 +1927,13 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
const VkPipelineStageFlags dst_stages_download =
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages_download,
|
||||
0, memory_write_barrier, nullptr, image_write_barrier);
|
||||
});
|
||||
return;
|
||||
@@ -1891,7 +1968,15 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
// Image writes can come from graphics or compute stages
|
||||
const VkPipelineStageFlags src_stages_img =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_img, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, read_barrier);
|
||||
|
||||
for (size_t index = 0; index < buffers.size(); index++) {
|
||||
@@ -1923,7 +2008,14 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
// After download, image may be used in shaders or as attachment
|
||||
const VkPipelineStageFlags dst_stages_img =
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages_img,
|
||||
0, memory_write_barrier, nullptr, image_write_barrier);
|
||||
});
|
||||
}
|
||||
@@ -1990,7 +2082,8 @@ bool Image::ScaleUp(bool ignore) {
|
||||
if (NeedsScaleHelper()) {
|
||||
return BlitScaleHelper(true);
|
||||
} else {
|
||||
BlitScale(*scheduler, *original_image, *scaled_image, info, aspect_mask, resolution);
|
||||
BlitScale(*scheduler, *original_image, *scaled_image, info, aspect_mask, resolution,
|
||||
runtime->device.IsKhrUnifiedImageLayoutsSupported());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -2015,7 +2108,8 @@ bool Image::ScaleDown(bool ignore) {
|
||||
if (NeedsScaleHelper()) {
|
||||
return BlitScaleHelper(false);
|
||||
} else {
|
||||
BlitScale(*scheduler, *scaled_image, *original_image, info, aspect_mask, resolution, false);
|
||||
BlitScale(*scheduler, *scaled_image, *original_image, info, aspect_mask, resolution,
|
||||
runtime->device.IsKhrUnifiedImageLayoutsSupported(), false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -2357,35 +2451,6 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t
|
||||
if (max_anisotropy > max_anisotropy_default) {
|
||||
sampler_default_anisotropy = create_sampler(max_anisotropy_default);
|
||||
}
|
||||
|
||||
// Create a nearest-filter fallback for integer format image views.
|
||||
// but Vulkan requires the format to support linear filtering.
|
||||
const bool is_mag_linear = tsc.mag_filter == TextureFilter::Linear;
|
||||
const bool is_min_linear = tsc.min_filter == TextureFilter::Linear;
|
||||
has_linear_filter = is_mag_linear || is_min_linear;
|
||||
if (has_linear_filter) {
|
||||
sampler_nearest = device.GetLogical().CreateSampler(VkSamplerCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
||||
.pNext = pnext,
|
||||
.flags = 0,
|
||||
.magFilter = VK_FILTER_NEAREST,
|
||||
.minFilter = VK_FILTER_NEAREST,
|
||||
.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
|
||||
.addressModeU = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_u, tsc.mag_filter),
|
||||
.addressModeV = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_v, tsc.mag_filter),
|
||||
.addressModeW = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_p, tsc.mag_filter),
|
||||
.mipLodBias = tsc.LodBias(),
|
||||
.anisotropyEnable = VK_FALSE,
|
||||
.maxAnisotropy = 1.0f,
|
||||
.compareEnable = tsc.depth_compare_enabled,
|
||||
.compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func),
|
||||
.minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(),
|
||||
.maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.MaxLod(),
|
||||
.borderColor = has_custom_border_colors ? VK_BORDER_COLOR_FLOAT_CUSTOM_EXT
|
||||
: ConvertBorderColor(color),
|
||||
.unnormalizedCoordinates = VK_FALSE,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM_RT> color_buffers,
|
||||
@@ -2514,7 +2579,9 @@ void TextureCacheRuntime::TransitionImageLayout(Image& image) {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_NONE,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
@@ -2530,8 +2597,16 @@ void TextureCacheRuntime::TransitionImageLayout(Image& image) {
|
||||
};
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([barrier](vk::CommandBuffer cmdbuf) {
|
||||
// After layout transition, image may be used in shaders or as attachment
|
||||
const VkPipelineStageFlags dst_stages_layout =
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, barrier);
|
||||
dst_stages_layout, 0, barrier);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,19 +408,9 @@ public:
|
||||
return static_cast<bool>(sampler_default_anisotropy);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool HasLinearFilter() const noexcept {
|
||||
return has_linear_filter;
|
||||
}
|
||||
|
||||
[[nodiscard]] VkSampler HandleWithNearestFilter() const noexcept {
|
||||
return sampler_nearest ? *sampler_nearest : *sampler;
|
||||
}
|
||||
|
||||
private:
|
||||
vk::Sampler sampler;
|
||||
vk::Sampler sampler_default_anisotropy;
|
||||
vk::Sampler sampler_nearest;
|
||||
bool has_linear_filter = false;
|
||||
};
|
||||
|
||||
struct TextureCacheParams {
|
||||
|
||||
@@ -45,8 +45,8 @@ TextureCache<P>::TextureCache(Runtime& runtime_, Tegra::MaxwellDeviceMemoryManag
|
||||
sampler_descriptor.cubemap_anisotropy.Assign(1);
|
||||
|
||||
// These values were chosen based on typical peak swizzle data sizes seen in some titles
|
||||
constexpr size_t SWIZZLE_DATA_BUFFER_INITIAL_CAPACITY = 8_MiB;
|
||||
constexpr size_t UNSWIZZLE_DATA_BUFFER_INITIAL_CAPACITY = 1_MiB;
|
||||
static constexpr size_t SWIZZLE_DATA_BUFFER_INITIAL_CAPACITY = 8_MiB;
|
||||
static constexpr size_t UNSWIZZLE_DATA_BUFFER_INITIAL_CAPACITY = 1_MiB;
|
||||
swizzle_data_buffer.resize_destructive(SWIZZLE_DATA_BUFFER_INITIAL_CAPACITY);
|
||||
unswizzle_data_buffer.resize_destructive(UNSWIZZLE_DATA_BUFFER_INITIAL_CAPACITY);
|
||||
|
||||
@@ -1445,9 +1445,13 @@ void TextureCache<P>::QueueAsyncDecode(Image& image, ImageId image_id) {
|
||||
decode->image_id = image_id;
|
||||
async_decodes.push_back(std::move(decode));
|
||||
|
||||
std::vector<u8> local_unswizzle_data_buffer(image.unswizzled_size_bytes, 0);
|
||||
Tegra::Memory::GpuGuestMemory<u8, Tegra::Memory::GuestMemoryFlags::UnsafeRead> swizzle_data(*gpu_memory, image.gpu_addr, image.guest_size_bytes, &swizzle_data_buffer);
|
||||
auto copies = UnswizzleImage(*gpu_memory, image.gpu_addr, image.info, swizzle_data, local_unswizzle_data_buffer);
|
||||
static Common::ScratchBuffer<u8> local_unswizzle_data_buffer;
|
||||
local_unswizzle_data_buffer.resize_destructive(image.unswizzled_size_bytes);
|
||||
Tegra::Memory::GpuGuestMemory<u8, Tegra::Memory::GuestMemoryFlags::UnsafeRead> swizzle_data(
|
||||
*gpu_memory, image.gpu_addr, image.guest_size_bytes, &swizzle_data_buffer);
|
||||
|
||||
auto copies = UnswizzleImage(*gpu_memory, image.gpu_addr, image.info, swizzle_data,
|
||||
local_unswizzle_data_buffer);
|
||||
const size_t out_size = MapSizeBytes(image);
|
||||
|
||||
auto func = [out_size, copies, info = image.info,
|
||||
@@ -1716,7 +1720,7 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DA
|
||||
return;
|
||||
}
|
||||
join_overlaps_found.insert(overlap_id);
|
||||
constexpr bool strict_size = true;
|
||||
static constexpr bool strict_size = true;
|
||||
const std::optional<OverlapResult> solution = ResolveOverlap(
|
||||
new_info, gpu_addr, cpu_addr, overlap, strict_size, broken_views, native_bgr);
|
||||
if (solution) {
|
||||
@@ -1727,7 +1731,7 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DA
|
||||
join_copies_to_do.emplace_back(JoinCopy{false, overlap_id});
|
||||
return;
|
||||
}
|
||||
constexpr auto options = RelaxedOptions::Size | RelaxedOptions::Format;
|
||||
static constexpr auto options = RelaxedOptions::Size | RelaxedOptions::Format;
|
||||
const ImageBase new_image_base(new_info, gpu_addr, cpu_addr);
|
||||
if (IsSubresource(new_info, overlap, gpu_addr, options, broken_views, native_bgr)) {
|
||||
join_left_aliased_ids.push_back(overlap_id);
|
||||
@@ -1896,7 +1900,7 @@ std::optional<typename TextureCache<P>::BlitImages> TextureCache<P>::GetBlitImag
|
||||
const Tegra::Engines::Fermi2D::Surface& dst, const Tegra::Engines::Fermi2D::Surface& src,
|
||||
const Tegra::Engines::Fermi2D::Config& copy) {
|
||||
|
||||
constexpr auto FIND_OPTIONS = RelaxedOptions::Samples;
|
||||
static constexpr auto FIND_OPTIONS = RelaxedOptions::Samples;
|
||||
const GPUVAddr dst_addr = dst.Address();
|
||||
const GPUVAddr src_addr = src.Address();
|
||||
ImageInfo dst_info(dst);
|
||||
@@ -2078,7 +2082,7 @@ void TextureCache<P>::TrimInactiveSamplers(size_t budget) {
|
||||
if (channel_state->samplers.empty()) {
|
||||
return;
|
||||
}
|
||||
constexpr size_t SAMPLER_GC_SLACK = 1024;
|
||||
static constexpr size_t SAMPLER_GC_SLACK = 1024;
|
||||
auto mark_active = [](auto& set, SamplerId id) {
|
||||
if (!id || id == CORRUPT_ID || id == NULL_SAMPLER_ID) {
|
||||
return;
|
||||
@@ -2187,7 +2191,7 @@ template <class P>
|
||||
template <typename Func>
|
||||
void TextureCache<P>::ForEachImageInRegion(DAddr cpu_addr, size_t size, Func&& func) {
|
||||
using FuncReturn = typename std::invoke_result<Func, ImageId, Image&>::type;
|
||||
constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>;
|
||||
static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>;
|
||||
boost::container::small_vector<ImageId, 32> images;
|
||||
boost::container::small_vector<ImageMapId, 32> maps;
|
||||
ForEachCPUPage(cpu_addr, size, [this, &images, &maps, cpu_addr, size, func](u64 page) {
|
||||
@@ -2240,7 +2244,7 @@ template <typename Func>
|
||||
void TextureCache<P>::ForEachImageInRegionGPU(size_t as_id, GPUVAddr gpu_addr, size_t size,
|
||||
Func&& func) {
|
||||
using FuncReturn = typename std::invoke_result<Func, ImageId, Image&>::type;
|
||||
constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>;
|
||||
static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>;
|
||||
boost::container::small_vector<ImageId, 8> images;
|
||||
auto storage_id = getStorageID(as_id);
|
||||
if (!storage_id) {
|
||||
@@ -2289,7 +2293,7 @@ template <typename Func>
|
||||
void TextureCache<P>::ForEachSparseImageInRegion(size_t as_id, GPUVAddr gpu_addr, size_t size,
|
||||
Func&& func) {
|
||||
using FuncReturn = typename std::invoke_result<Func, ImageId, Image&>::type;
|
||||
constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>;
|
||||
static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>;
|
||||
boost::container::small_vector<ImageId, 8> images;
|
||||
auto storage_id = getStorageID(as_id);
|
||||
if (!storage_id) {
|
||||
@@ -2337,7 +2341,7 @@ template <class P>
|
||||
template <typename Func>
|
||||
void TextureCache<P>::ForEachSparseSegment(ImageBase& image, Func&& func) {
|
||||
using FuncReturn = typename std::invoke_result<Func, GPUVAddr, DAddr, size_t>::type;
|
||||
constexpr bool RETURNS_BOOL = std::is_same_v<FuncReturn, bool>;
|
||||
static constexpr bool RETURNS_BOOL = std::is_same_v<FuncReturn, bool>;
|
||||
const auto segments = gpu_memory->GetSubmappedRange(image.gpu_addr, image.guest_size_bytes);
|
||||
for (const auto& [gpu_addr, size] : segments) {
|
||||
std::optional<DAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
|
||||
|
||||
@@ -924,9 +924,6 @@ bool Device::ShouldBoostClocks() const {
|
||||
}
|
||||
|
||||
bool Device::HasTimelineSemaphore() const {
|
||||
if (GetDriverID() == VK_DRIVER_ID_MESA_TURNIP) {
|
||||
return false;
|
||||
}
|
||||
return features.timeline_semaphore.timelineSemaphore;
|
||||
}
|
||||
|
||||
@@ -935,8 +932,18 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
||||
bool suitable = true;
|
||||
|
||||
// Configure properties.
|
||||
if (!Settings::values.renderer_debug) {
|
||||
features.features.robustBufferAccess = VK_FALSE;
|
||||
if (extensions.robustness_2) {
|
||||
features.robustness2.robustBufferAccess2 = VK_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
VkPhysicalDeviceVulkan12Features features_1_2{};
|
||||
VkPhysicalDeviceVulkan13Features features_1_3{};
|
||||
#ifdef VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES
|
||||
VkPhysicalDeviceVulkan14Features features_1_4{};
|
||||
#endif
|
||||
|
||||
// Configure properties.
|
||||
properties.properties = physical.GetProperties();
|
||||
@@ -976,6 +983,11 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
||||
if (instance_version < VK_API_VERSION_1_3) {
|
||||
FOR_EACH_VK_FEATURE_1_3(FEATURE_EXTENSION);
|
||||
}
|
||||
#ifdef VK_API_VERSION_1_4
|
||||
if (instance_version < VK_API_VERSION_1_4) {
|
||||
FOR_EACH_VK_FEATURE_1_4(FEATURE_EXTENSION);
|
||||
}
|
||||
#endif
|
||||
|
||||
FOR_EACH_VK_FEATURE_EXT(FEATURE_EXTENSION);
|
||||
FOR_EACH_VK_EXTENSION(EXTENSION);
|
||||
@@ -1011,11 +1023,16 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
||||
// Set next pointer.
|
||||
void** next = &features2.pNext;
|
||||
|
||||
// Vulkan 1.2 and 1.3 features
|
||||
// Vulkan 1.2, 1.3 and 1.4 features
|
||||
if (instance_version >= VK_API_VERSION_1_2) {
|
||||
features_1_2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
|
||||
features_1_3.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
|
||||
|
||||
#ifdef VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES
|
||||
features_1_4.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES;
|
||||
features_1_3.pNext = &features_1_4;
|
||||
#endif
|
||||
|
||||
features_1_2.pNext = &features_1_3;
|
||||
|
||||
*next = &features_1_2;
|
||||
@@ -1047,6 +1064,13 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
||||
} else {
|
||||
FOR_EACH_VK_FEATURE_1_3(EXT_FEATURE);
|
||||
}
|
||||
#ifdef VK_API_VERSION_1_4
|
||||
if (instance_version >= VK_API_VERSION_1_4) {
|
||||
FOR_EACH_VK_FEATURE_1_4(FEATURE);
|
||||
} else {
|
||||
FOR_EACH_VK_FEATURE_1_4(EXT_FEATURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef EXT_FEATURE
|
||||
#undef FEATURE
|
||||
@@ -1484,16 +1508,31 @@ void Device::RemoveUnsuitableExtensions() {
|
||||
RemoveExtensionFeatureIfUnsuitable(extensions.maintenance6, features.maintenance6,
|
||||
VK_KHR_MAINTENANCE_6_EXTENSION_NAME);
|
||||
|
||||
// VK_KHR_maintenance7 (proposed for Vulkan 1.4, no features)
|
||||
// VK_KHR_maintenance7
|
||||
#ifdef VK_API_VERSION_1_4
|
||||
extensions.maintenance7 = instance_version >= VK_API_VERSION_1_4 ||
|
||||
loaded_extensions.contains(VK_KHR_MAINTENANCE_7_EXTENSION_NAME);
|
||||
#else
|
||||
extensions.maintenance7 = loaded_extensions.contains(VK_KHR_MAINTENANCE_7_EXTENSION_NAME);
|
||||
#endif
|
||||
RemoveExtensionIfUnsuitable(extensions.maintenance7, VK_KHR_MAINTENANCE_7_EXTENSION_NAME);
|
||||
|
||||
// VK_KHR_maintenance8 (proposed for Vulkan 1.4, no features)
|
||||
// VK_KHR_maintenance8
|
||||
#ifdef VK_API_VERSION_1_4
|
||||
extensions.maintenance8 = instance_version >= VK_API_VERSION_1_4 ||
|
||||
loaded_extensions.contains(VK_KHR_MAINTENANCE_8_EXTENSION_NAME);
|
||||
#else
|
||||
extensions.maintenance8 = loaded_extensions.contains(VK_KHR_MAINTENANCE_8_EXTENSION_NAME);
|
||||
#endif
|
||||
RemoveExtensionIfUnsuitable(extensions.maintenance8, VK_KHR_MAINTENANCE_8_EXTENSION_NAME);
|
||||
|
||||
// VK_KHR_maintenance9 (proposed for Vulkan 1.4, no features)
|
||||
// VK_KHR_maintenance9
|
||||
#ifdef VK_API_VERSION_1_4
|
||||
extensions.maintenance9 = instance_version >= VK_API_VERSION_1_4 ||
|
||||
loaded_extensions.contains(VK_KHR_MAINTENANCE_9_EXTENSION_NAME);
|
||||
#else
|
||||
extensions.maintenance9 = loaded_extensions.contains(VK_KHR_MAINTENANCE_9_EXTENSION_NAME);
|
||||
#endif
|
||||
RemoveExtensionIfUnsuitable(extensions.maintenance9, VK_KHR_MAINTENANCE_9_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
|
||||
@@ -487,6 +487,11 @@ public:
|
||||
return extensions.workgroup_memory_explicit_layout;
|
||||
}
|
||||
|
||||
/// Returns true if the device supports VK_KHR_unified_image_layouts.
|
||||
bool IsKhrUnifiedImageLayoutsSupported() const {
|
||||
return extensions.unified_image_layouts;
|
||||
}
|
||||
|
||||
/// Returns true if the device supports VK_KHR_image_format_list.
|
||||
bool IsKhrImageFormatListSupported() const {
|
||||
return extensions.image_format_list || instance_version >= VK_API_VERSION_1_2;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
@@ -47,6 +47,14 @@ bool IsMicrosoftDozen(const char* device_name) {
|
||||
return std::strstr(device_name, "Microsoft") != nullptr;
|
||||
}
|
||||
|
||||
constexpr u32 MaxInstanceApiVersion() {
|
||||
#ifdef VK_API_VERSION_1_4
|
||||
return VK_API_VERSION_1_4;
|
||||
#else
|
||||
return VK_API_VERSION_1_3;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SortPhysicalDevices(std::vector<VkPhysicalDevice>& devices, const InstanceDispatch& dld) {
|
||||
// Sort by name, this will set a base and make GPUs with higher numbers appear first
|
||||
// (e.g. GTX 1650 will intentionally be listed before a GTX 1080).
|
||||
@@ -437,8 +445,8 @@ Instance Instance::Create(u32 version, Span<const char*> layers, Span<const char
|
||||
#else
|
||||
constexpr VkFlags ci_flags{};
|
||||
#endif
|
||||
// DO NOT TOUCH, breaks RNDA3!!
|
||||
// Don't know why, but gloom + yellow line glitch appears
|
||||
// Keep application and engine tags stable for driver behavior compatibility.
|
||||
const u32 api_version = std::min(version, MaxInstanceApiVersion());
|
||||
const VkApplicationInfo application_info{
|
||||
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||
.pNext = nullptr,
|
||||
@@ -446,7 +454,7 @@ Instance Instance::Create(u32 version, Span<const char*> layers, Span<const char
|
||||
.applicationVersion = VK_MAKE_VERSION(1, 3, 0),
|
||||
.pEngineName = "yuzu Emulator",
|
||||
.engineVersion = VK_MAKE_VERSION(1, 3, 0),
|
||||
.apiVersion = VK_API_VERSION_1_3,
|
||||
.apiVersion = api_version,
|
||||
};
|
||||
const VkInstanceCreateInfo ci{
|
||||
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||
|
||||
@@ -242,8 +242,6 @@ add_executable(yuzu
|
||||
configuration/system/new_user_dialog.h configuration/system/new_user_dialog.cpp configuration/system/new_user_dialog.ui
|
||||
configuration/system/profile_avatar_dialog.h configuration/system/profile_avatar_dialog.cpp
|
||||
configuration/addon/mod_select_dialog.h configuration/addon/mod_select_dialog.cpp configuration/addon/mod_select_dialog.ui
|
||||
|
||||
render/performance_overlay.h render/performance_overlay.cpp render/performance_overlay.ui
|
||||
)
|
||||
|
||||
set_target_properties(yuzu PROPERTIES OUTPUT_NAME "eden")
|
||||
@@ -401,7 +399,7 @@ endif()
|
||||
|
||||
target_link_libraries(yuzu PRIVATE nlohmann_json::nlohmann_json)
|
||||
target_link_libraries(yuzu PRIVATE common core input_common frontend_common network video_core qt_common)
|
||||
target_link_libraries(yuzu PRIVATE Boost::headers glad Qt6::Widgets Qt6::Charts Qt6::Concurrent)
|
||||
target_link_libraries(yuzu PRIVATE Boost::headers glad Qt6::Widgets Qt6::Concurrent)
|
||||
target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
||||
@@ -57,6 +57,10 @@ void ConfigureDebug::SetConfiguration() {
|
||||
#endif
|
||||
|
||||
// Immutable after starting
|
||||
ui->serial_battery_edit->setEnabled(runtime_lock);
|
||||
ui->serial_battery_edit->setText(QString::fromStdString(Settings::values.serial_battery.GetValue()));
|
||||
ui->serial_board_edit->setEnabled(runtime_lock);
|
||||
ui->serial_board_edit->setText(QString::fromStdString(Settings::values.serial_unit.GetValue()));
|
||||
ui->homebrew_args_edit->setEnabled(runtime_lock);
|
||||
ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args.GetValue()));
|
||||
ui->toggle_console->setEnabled(runtime_lock);
|
||||
|
||||
@@ -38,9 +38,9 @@ ConfigureFilesystem::ConfigureFilesystem(QWidget* parent)
|
||||
connect(ui->reset_game_list_cache, &QPushButton::pressed, this,
|
||||
&ConfigureFilesystem::ResetMetadata);
|
||||
|
||||
connect(ui->gamecard_inserted, &QCheckBox::STATE_CHANGED, this,
|
||||
connect(ui->gamecard_inserted, &QCheckBox::stateChanged, this,
|
||||
&ConfigureFilesystem::UpdateEnabledControls);
|
||||
connect(ui->gamecard_current_game, &QCheckBox::STATE_CHANGED, this,
|
||||
connect(ui->gamecard_current_game, &QCheckBox::stateChanged, this,
|
||||
&ConfigureFilesystem::UpdateEnabledControls);
|
||||
}
|
||||
|
||||
|
||||
@@ -146,7 +146,6 @@
|
||||
<addaction name="action_Enable_Overlay_Applet"/>
|
||||
<addaction name="action_Show_Filter_Bar"/>
|
||||
<addaction name="action_Show_Status_Bar"/>
|
||||
<addaction name="action_Show_Performance_Overlay"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="menu_Reset_Window_Size"/>
|
||||
<addaction name="menu_View_Debugging"/>
|
||||
@@ -612,14 +611,6 @@
|
||||
<string>Show Game &Name</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Show_Performance_Overlay">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show &Performance Overlay</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="yuzu.qrc"/>
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "common/settings_enums.h"
|
||||
#include "frontend_common/settings_generator.h"
|
||||
#include "qt_common/qt_string_lookup.h"
|
||||
#include "render/performance_overlay.h"
|
||||
#if defined(QT_STATICPLUGIN) && !defined(__APPLE__)
|
||||
#undef VMA_IMPLEMENTATION
|
||||
#endif
|
||||
@@ -1402,7 +1401,6 @@ void MainWindow::InitializeHotkeys() {
|
||||
LinkActionShortcut(ui->action_Stop, QStringLiteral("Stop Emulation"));
|
||||
LinkActionShortcut(ui->action_Show_Filter_Bar, QStringLiteral("Toggle Filter Bar"));
|
||||
LinkActionShortcut(ui->action_Show_Status_Bar, QStringLiteral("Toggle Status Bar"));
|
||||
LinkActionShortcut(ui->action_Show_Performance_Overlay, QStringLiteral("Toggle Performance Overlay"));
|
||||
LinkActionShortcut(ui->action_Fullscreen, QStringLiteral("Fullscreen"));
|
||||
LinkActionShortcut(ui->action_Capture_Screenshot, QStringLiteral("Capture Screenshot"));
|
||||
LinkActionShortcut(ui->action_TAS_Start, QStringLiteral("TAS Start/Stop"), true);
|
||||
@@ -1513,9 +1511,6 @@ void MainWindow::RestoreUIState() {
|
||||
|
||||
ui->action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar.GetValue());
|
||||
statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked());
|
||||
|
||||
ui->action_Show_Performance_Overlay->setChecked(UISettings::values.show_perf_overlay.GetValue());
|
||||
if (perf_overlay) perf_overlay->setVisible(ui->action_Show_Performance_Overlay->isChecked());
|
||||
Debugger::ToggleConsole();
|
||||
}
|
||||
|
||||
@@ -1635,7 +1630,6 @@ void MainWindow::ConnectMenuEvents() {
|
||||
connect_menu(ui->action_Single_Window_Mode, &MainWindow::ToggleWindowMode);
|
||||
connect_menu(ui->action_Show_Filter_Bar, &MainWindow::OnToggleFilterBar);
|
||||
connect_menu(ui->action_Show_Status_Bar, &MainWindow::OnToggleStatusBar);
|
||||
connect_menu(ui->action_Show_Performance_Overlay, &MainWindow::OnTogglePerfOverlay);
|
||||
|
||||
connect_menu(ui->action_Reset_Window_Size_720, &MainWindow::ResetWindowSize720);
|
||||
connect_menu(ui->action_Reset_Window_Size_900, &MainWindow::ResetWindowSize900);
|
||||
@@ -2216,10 +2210,6 @@ bool MainWindow::OnShutdownBegin() {
|
||||
return false;
|
||||
}
|
||||
|
||||
perf_overlay->hide();
|
||||
perf_overlay->deleteLater();
|
||||
perf_overlay = nullptr;
|
||||
|
||||
QtCommon::system->SetShuttingDown(true);
|
||||
discord_rpc->Pause();
|
||||
|
||||
@@ -3221,13 +3211,6 @@ bool MainWindow::ConfirmShutdownGame() {
|
||||
|
||||
void MainWindow::OnLoadComplete() {
|
||||
loading_screen->OnLoadComplete();
|
||||
|
||||
perf_overlay = new PerformanceOverlay(this);
|
||||
perf_overlay->setVisible(ui->action_Show_Performance_Overlay->isChecked());
|
||||
|
||||
connect(perf_overlay, &PerformanceOverlay::closed, perf_overlay, [this]() {
|
||||
ui->action_Show_Performance_Overlay->setChecked(false);
|
||||
});
|
||||
}
|
||||
|
||||
void MainWindow::OnExecuteProgram(std::size_t program_index) {
|
||||
@@ -4049,12 +4032,6 @@ void MainWindow::OnToggleStatusBar() {
|
||||
statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked());
|
||||
}
|
||||
|
||||
void MainWindow::OnTogglePerfOverlay() {
|
||||
if (perf_overlay) {
|
||||
perf_overlay->setVisible(ui->action_Show_Performance_Overlay->isChecked());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::OnGameListRefresh() {
|
||||
// Resets metadata cache and reloads
|
||||
QtCommon::Game::ResetMetadata(false);
|
||||
@@ -4279,8 +4256,6 @@ void MainWindow::UpdateStatusBar() {
|
||||
auto& shader_notify = QtCommon::system->GPU().ShaderNotify();
|
||||
const int shaders_building = shader_notify.ShadersBuilding();
|
||||
|
||||
emit statsUpdated(results, shader_notify);
|
||||
|
||||
if (shaders_building > 0) {
|
||||
shader_building_label->setText(tr("Building: %n shader(s)", "", shaders_building));
|
||||
shader_building_label->setVisible(true);
|
||||
@@ -4375,7 +4350,6 @@ void MainWindow::UpdateStatusButtons() {
|
||||
UpdateVolumeUI();
|
||||
}
|
||||
|
||||
// TODO(crueter): Use this for game list stuff
|
||||
void MainWindow::UpdateUISettings() {
|
||||
if (!ui->action_Fullscreen->isChecked()) {
|
||||
UISettings::values.geometry = saveGeometry();
|
||||
@@ -4386,8 +4360,6 @@ void MainWindow::UpdateUISettings() {
|
||||
UISettings::values.fullscreen = ui->action_Fullscreen->isChecked();
|
||||
UISettings::values.show_filter_bar = ui->action_Show_Filter_Bar->isChecked();
|
||||
UISettings::values.show_status_bar = ui->action_Show_Status_Bar->isChecked();
|
||||
UISettings::values.show_perf_overlay = ui->action_Show_Performance_Overlay->isChecked();
|
||||
|
||||
UISettings::values.first_start = false;
|
||||
|
||||
Settings::values.enable_overlay = ui->action_Enable_Overlay_Applet->isChecked();
|
||||
@@ -4616,15 +4588,6 @@ void MainWindow::closeEvent(QCloseEvent* event) {
|
||||
QWidget::closeEvent(event);
|
||||
}
|
||||
|
||||
void MainWindow::resizeEvent(QResizeEvent* event) {
|
||||
emit sizeChanged(event->size());
|
||||
}
|
||||
|
||||
void MainWindow::moveEvent(QMoveEvent* event) {
|
||||
auto window_frame_height = frameGeometry().height() - geometry().height();
|
||||
emit positionChanged(event->pos() - QPoint{0, window_frame_height});
|
||||
}
|
||||
|
||||
static bool IsSingleFileDropEvent(const QMimeData* mime) {
|
||||
return mime->hasUrls() && mime->urls().length() == 1;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,6 @@ class QProgressDialog;
|
||||
class QSlider;
|
||||
class QHBoxLayout;
|
||||
class WaitTreeWidget;
|
||||
class PerformanceOverlay;
|
||||
enum class GameListOpenTarget;
|
||||
enum class DumpRomFSTarget;
|
||||
class GameListPlaceholder;
|
||||
@@ -71,9 +70,6 @@ enum class StartGameType {
|
||||
Global, // Only uses global configuration
|
||||
};
|
||||
|
||||
namespace VideoCore {
|
||||
class ShaderNotify;
|
||||
}
|
||||
namespace Core {
|
||||
enum class SystemResultStatus : u32;
|
||||
} // namespace Core
|
||||
@@ -218,9 +214,6 @@ signals:
|
||||
void WebBrowserClosed(Service::AM::Frontend::WebExitReason exit_reason, std::string last_url);
|
||||
|
||||
void SigInterrupt();
|
||||
void sizeChanged(const QSize &size);
|
||||
void positionChanged(const QPoint &pos);
|
||||
void statsUpdated(const Core::PerfStatsResults &results, const VideoCore::ShaderNotify &shaders);
|
||||
|
||||
public slots:
|
||||
void OnLoadComplete();
|
||||
@@ -317,8 +310,6 @@ private:
|
||||
void RequestGameExit();
|
||||
void changeEvent(QEvent* event) override;
|
||||
void closeEvent(QCloseEvent* event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void moveEvent(QMoveEvent *event) override;
|
||||
|
||||
std::string CreateTASFramesString(
|
||||
std::array<size_t, InputCommon::TasInput::PLAYER_NUMBER> frames) const;
|
||||
@@ -401,7 +392,6 @@ private slots:
|
||||
void OnDataDialog();
|
||||
void OnToggleFilterBar();
|
||||
void OnToggleStatusBar();
|
||||
void OnTogglePerfOverlay();
|
||||
void OnGameListRefresh();
|
||||
void InitializeHotkeys();
|
||||
void ToggleFullscreen();
|
||||
@@ -503,7 +493,6 @@ private:
|
||||
LoadingScreen* loading_screen = nullptr;
|
||||
QTimer shutdown_timer;
|
||||
OverlayDialog* shutdown_dialog{};
|
||||
PerformanceOverlay *perf_overlay = nullptr;
|
||||
|
||||
GameListPlaceholder* game_list_placeholder = nullptr;
|
||||
|
||||
|
||||
@@ -1,207 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/perf_stats.h"
|
||||
#include "performance_overlay.h"
|
||||
#include "ui_performance_overlay.h"
|
||||
|
||||
#include "main_window.h"
|
||||
|
||||
#include <QChart>
|
||||
#include <QChartView>
|
||||
#include <QGraphicsLayout>
|
||||
#include <QLineSeries>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QValueAxis>
|
||||
|
||||
// TODO(crueter): Reset samples when user changes turbo, slow, etc.
|
||||
PerformanceOverlay::PerformanceOverlay(MainWindow* parent)
|
||||
: QWidget(parent), m_mainWindow{parent}, ui(new Ui::PerformanceOverlay) {
|
||||
ui->setupUi(this);
|
||||
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
setWindowFlags(Qt::FramelessWindowHint | Qt::Tool);
|
||||
raise();
|
||||
|
||||
// chart setup
|
||||
m_fpsSeries = new QLineSeries(this);
|
||||
|
||||
QPen pen(Qt::red);
|
||||
pen.setWidth(2);
|
||||
m_fpsSeries->setPen(pen);
|
||||
|
||||
m_fpsChart = new QChart;
|
||||
m_fpsChart->addSeries(m_fpsSeries);
|
||||
m_fpsChart->legend()->hide();
|
||||
m_fpsChart->setBackgroundBrush(Qt::black);
|
||||
m_fpsChart->setBackgroundVisible(true);
|
||||
m_fpsChart->layout()->setContentsMargins(2, 2, 2, 2);
|
||||
m_fpsChart->setMargins(QMargins{4, 4, 4, 4});
|
||||
|
||||
// axes
|
||||
m_fpsX = new QValueAxis(this);
|
||||
m_fpsX->setRange(0, NUM_FPS_SAMPLES);
|
||||
m_fpsX->setVisible(false);
|
||||
|
||||
m_fpsY = new QValueAxis(this);
|
||||
m_fpsY->setRange(0, 60);
|
||||
m_fpsY->setLabelFormat(QStringLiteral("%d"));
|
||||
m_fpsY->setLabelsColor(Qt::white);
|
||||
|
||||
QFont axisFont = m_fpsY->labelsFont();
|
||||
axisFont.setPixelSize(10);
|
||||
m_fpsY->setLabelsFont(axisFont);
|
||||
m_fpsY->setTickCount(3);
|
||||
|
||||
// gray-ish label w/ white lines
|
||||
m_fpsY->setLabelsVisible(true);
|
||||
m_fpsY->setGridLineColor(QColor(50, 50, 50));
|
||||
m_fpsY->setLinePenColor(Qt::white);
|
||||
|
||||
m_fpsChart->addAxis(m_fpsX, Qt::AlignBottom);
|
||||
m_fpsChart->addAxis(m_fpsY, Qt::AlignLeft);
|
||||
m_fpsSeries->attachAxis(m_fpsX);
|
||||
m_fpsSeries->attachAxis(m_fpsY);
|
||||
|
||||
// chart view
|
||||
m_fpsChartView = new QChartView(m_fpsChart, this);
|
||||
m_fpsChartView->setRenderHint(QPainter::Antialiasing);
|
||||
m_fpsChartView->setMinimumHeight(100);
|
||||
|
||||
ui->verticalLayout->addWidget(m_fpsChartView, 1);
|
||||
|
||||
// thanks Debian.
|
||||
QFont font = ui->fps->font();
|
||||
font.setWeight(QFont::DemiBold);
|
||||
|
||||
ui->fps->setFont(font);
|
||||
ui->frametime->setFont(font);
|
||||
|
||||
// pos/stats
|
||||
resetPosition(m_mainWindow->pos());
|
||||
connect(parent, &MainWindow::positionChanged, this, &PerformanceOverlay::resetPosition);
|
||||
connect(m_mainWindow, &MainWindow::statsUpdated, this, &PerformanceOverlay::updateStats);
|
||||
}
|
||||
|
||||
PerformanceOverlay::~PerformanceOverlay() {
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void PerformanceOverlay::resetPosition(const QPoint& _) {
|
||||
auto pos = m_mainWindow->pos();
|
||||
move(pos.x() + m_offset.x(), pos.y() + m_offset.y());
|
||||
}
|
||||
|
||||
void PerformanceOverlay::updateStats(const Core::PerfStatsResults& results,
|
||||
const VideoCore::ShaderNotify& shaders) {
|
||||
auto fps = results.average_game_fps;
|
||||
if (!std::isnan(fps)) {
|
||||
// don't sample measurements < 3 fps because they are probably outliers or freezes
|
||||
static constexpr double FPS_SAMPLE_THRESHOLD = 3.0;
|
||||
|
||||
QString fpsText = tr("%1 fps").arg(std::round(fps), 0, 'f', 0);
|
||||
// if (!m_fpsSuffix.isEmpty()) fpsText = fpsText % QStringLiteral(" (%1)").arg(m_fpsSuffix);
|
||||
ui->fps->setText(fpsText);
|
||||
|
||||
// sampling
|
||||
if (fps > FPS_SAMPLE_THRESHOLD) {
|
||||
m_fpsSamples.push_back(fps);
|
||||
m_fpsPoints.push_back(QPointF{m_xPos++, fps});
|
||||
}
|
||||
|
||||
if (m_fpsSamples.size() > NUM_FPS_SAMPLES) {
|
||||
m_fpsSamples.pop_front();
|
||||
m_fpsPoints.pop_front();
|
||||
}
|
||||
|
||||
// For the average only go back 10 samples max
|
||||
if (m_fpsSamples.size() >= 2) {
|
||||
const int back_search = std::min(size_t(10), m_fpsSamples.size() - 1);
|
||||
double sum = std::accumulate(m_fpsSamples.end() - back_search, m_fpsSamples.end(), 0.0);
|
||||
double avg = sum / back_search;
|
||||
|
||||
ui->fps_avg->setText(tr("Avg: %1").arg(avg, 0, 'f', 0));
|
||||
}
|
||||
|
||||
// chart it :)
|
||||
if (!m_fpsPoints.empty()) {
|
||||
auto [min_it, max_it] = std::minmax_element(m_fpsSamples.begin(), m_fpsSamples.end());
|
||||
double min_fps = *min_it;
|
||||
double max_fps = *max_it;
|
||||
|
||||
ui->fps_min->setText(tr("Min: %1").arg(min_fps, 0, 'f', 0));
|
||||
ui->fps_max->setText(tr("Max: %1").arg(max_fps, 0, 'f', 0));
|
||||
|
||||
m_fpsSeries->replace(QList<QPointF>(m_fpsPoints.begin(), m_fpsPoints.end()));
|
||||
|
||||
qreal x_min = std::max(0.0, m_xPos - NUM_FPS_SAMPLES);
|
||||
qreal x_max = std::max(qreal(10), m_xPos);
|
||||
m_fpsX->setRange(x_min, x_max);
|
||||
m_fpsY->setRange(0.0, max_fps);
|
||||
}
|
||||
}
|
||||
|
||||
auto ft = results.frametime;
|
||||
if (!std::isnan(ft)) {
|
||||
// don't sample measurements > 500 ms because they are probably outliers
|
||||
static constexpr double FT_SAMPLE_THRESHOLD = 500.0;
|
||||
|
||||
double ft_ms = results.frametime * 1000.0;
|
||||
ui->frametime->setText(tr("%1 ms").arg(ft_ms, 0, 'f', 2));
|
||||
|
||||
// sampling
|
||||
if (ft_ms <= FT_SAMPLE_THRESHOLD)
|
||||
m_frametimeSamples.push_back(ft_ms);
|
||||
|
||||
if (m_frametimeSamples.size() > NUM_FRAMETIME_SAMPLES)
|
||||
m_frametimeSamples.pop_front();
|
||||
|
||||
if (!m_frametimeSamples.empty()) {
|
||||
auto [min_it, max_it] =
|
||||
std::minmax_element(m_frametimeSamples.begin(), m_frametimeSamples.end());
|
||||
ui->ft_min->setText(tr("Min: %1").arg(*min_it, 0, 'f', 1));
|
||||
ui->ft_max->setText(tr("Max: %1").arg(*max_it, 0, 'f', 1));
|
||||
}
|
||||
|
||||
// For the average only go back 10 samples max
|
||||
if (m_frametimeSamples.size() >= 2) {
|
||||
const int back_search = std::min(size_t(10), m_frametimeSamples.size() - 1);
|
||||
double sum = std::accumulate(m_frametimeSamples.end() - back_search,
|
||||
m_frametimeSamples.end(), 0.0);
|
||||
double avg = sum / back_search;
|
||||
|
||||
ui->ft_avg->setText(tr("Avg: %1").arg(avg, 0, 'f', 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PerformanceOverlay::paintEvent(QPaintEvent* event) {
|
||||
QPainter painter(this);
|
||||
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
painter.setBrush(m_background);
|
||||
painter.setPen(Qt::NoPen);
|
||||
|
||||
painter.drawRoundedRect(rect(), 10.0, 10.0);
|
||||
}
|
||||
|
||||
void PerformanceOverlay::mousePressEvent(QMouseEvent* event) {
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
m_drag_start_pos = event->pos();
|
||||
}
|
||||
}
|
||||
|
||||
void PerformanceOverlay::mouseMoveEvent(QMouseEvent* event) {
|
||||
// drag
|
||||
if (event->buttons() & Qt::LeftButton) {
|
||||
QPoint new_global_pos = event->globalPosition().toPoint() - m_drag_start_pos;
|
||||
m_offset = new_global_pos - m_mainWindow->pos();
|
||||
move(new_global_pos);
|
||||
}
|
||||
}
|
||||
|
||||
void PerformanceOverlay::closeEvent(QCloseEvent* event) {
|
||||
emit closed();
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
#include <QWidget>
|
||||
|
||||
namespace VideoCore {
|
||||
class ShaderNotify;
|
||||
}
|
||||
namespace Core {
|
||||
struct PerfStatsResults;
|
||||
}
|
||||
namespace Ui {
|
||||
class PerformanceOverlay;
|
||||
}
|
||||
|
||||
class QLineSeries;
|
||||
class QChart;
|
||||
class QChartView;
|
||||
class QValueAxis;
|
||||
class MainWindow;
|
||||
|
||||
class PerformanceOverlay : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PerformanceOverlay(MainWindow* parent = nullptr);
|
||||
~PerformanceOverlay();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
void mouseMoveEvent(QMouseEvent* event) override;
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
|
||||
private:
|
||||
void resetPosition(const QPoint& pos);
|
||||
void updateStats(const Core::PerfStatsResults &results, const VideoCore::ShaderNotify &shaders);
|
||||
|
||||
MainWindow *m_mainWindow = nullptr;
|
||||
Ui::PerformanceOverlay* ui;
|
||||
|
||||
// colors
|
||||
QColor m_background{127, 127, 127, 190};
|
||||
|
||||
QPoint m_offset{25, 75};
|
||||
|
||||
// frametime
|
||||
const size_t NUM_FRAMETIME_SAMPLES = 300;
|
||||
std::deque<double> m_frametimeSamples;
|
||||
|
||||
// fps
|
||||
const size_t NUM_FPS_SAMPLES = 120;
|
||||
qreal m_xPos = 0;
|
||||
std::deque<double> m_fpsSamples;
|
||||
std::deque<QPointF> m_fpsPoints;
|
||||
|
||||
// drag
|
||||
QPoint m_drag_start_pos;
|
||||
|
||||
// fps chart
|
||||
QLineSeries *m_fpsSeries = nullptr;
|
||||
QChart *m_fpsChart = nullptr;
|
||||
QChartView *m_fpsChartView = nullptr;
|
||||
QValueAxis *m_fpsX = nullptr;
|
||||
QValueAxis *m_fpsY = nullptr;
|
||||
|
||||
signals:
|
||||
void closed();
|
||||
};
|
||||