mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-09-11 23:32:56 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37a8be7b42 | ||
|
|
4cdda8d99b | ||
|
|
a5fc5aefc9 | ||
|
|
e6a88bccff | ||
|
|
0caaa2cb49 | ||
|
|
4a4cbb875e | ||
|
|
6a0d3011ab | ||
|
|
d3cc62f37e | ||
|
|
32c19d94fa | ||
|
|
1810140d1d | ||
|
|
7676b1f73e | ||
|
|
bbc57ec622 | ||
|
|
98697735f1 | ||
|
|
4102a0bd2c | ||
|
|
cb3c60557e | ||
|
|
c62d29e6a1 | ||
|
|
ac24959c4a | ||
|
|
236f67a82f | ||
|
|
4e9c5dcc88 | ||
|
|
450a39a37c | ||
|
|
ca0145e6aa | ||
|
|
20c51dd80e | ||
|
|
aaf03c18b6 | ||
|
|
77bec5e0f5 | ||
|
|
f0cd834ed2 | ||
|
|
77cfac7dbe | ||
|
|
ca5942151a | ||
|
|
0be8947a33 | ||
|
|
33127ad0df | ||
|
|
c475c752bf | ||
|
|
bd9b6daaad | ||
|
|
9120e6fb6a | ||
|
|
65dc286e9b | ||
|
|
4545e24f7d | ||
|
|
deb6edc076 |
+1
-1
@@ -2,7 +2,7 @@
|
||||
* text=auto
|
||||
|
||||
# Declare files that will always have CRLF line endings on checkout.
|
||||
*.sln text eol=crlf
|
||||
*.slnx text eol=crlf
|
||||
*.props text eol=crlf
|
||||
*.vcxproj text eol=crlf
|
||||
*.vcxproj.filters text eol=crlf
|
||||
|
||||
@@ -3,6 +3,7 @@ name: Application Bug Report
|
||||
description: Found a problem with the application itself (ie. bad file path handling, UX issue)? Help us improve it.
|
||||
title: "[BUG]: "
|
||||
labels: [Bug]
|
||||
type: Bug
|
||||
# assignees:
|
||||
# - octocat
|
||||
body:
|
||||
|
||||
@@ -3,6 +3,7 @@ name: Emulation Bug Report
|
||||
description: Problem in a game (ie. graphical artifacts, crashes)? Help us improve it.
|
||||
title: "[BUG]: "
|
||||
labels: [Bug]
|
||||
type: Bug
|
||||
# assignees:
|
||||
# - octocat
|
||||
body:
|
||||
|
||||
@@ -3,6 +3,7 @@ name: Feature request
|
||||
description: Suggest a new feature or improve an existing one
|
||||
title: "[Feature Request]: "
|
||||
labels: ["Enhancement / Feature Request", "FR: Awaiting Consideration"]
|
||||
type: Feature Request
|
||||
# assignees:
|
||||
# - octocat
|
||||
body:
|
||||
|
||||
+2
-2
@@ -6,8 +6,8 @@
|
||||
- any-glob-to-any-file:
|
||||
- '.github/*'
|
||||
- '.github/**/*'
|
||||
- '*.sln'
|
||||
- '**/*.sln'
|
||||
- '*.slnx'
|
||||
- '**/*.slnx'
|
||||
- '*.vcxproj*'
|
||||
- '**/*.vcxproj*'
|
||||
- 'cmake/*'
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
uses: gsactions/commit-message-checker@16fa2d5de096ae0d35626443bcd24f1e756cafee
|
||||
with:
|
||||
accessToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
pattern: '^[A-Z0-9][A-Za-z0-9 \["\/\\]+:.+'
|
||||
pattern: '^[A-Z0-9][A-Za-z0-9 \["\/\\-]+:.+'
|
||||
excludeTitle: true
|
||||
excludeDescription: true
|
||||
checkAllCommitMessages: true
|
||||
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
name: ${{ inputs.jobName }}
|
||||
runs-on: ${{ inputs.os }}
|
||||
container:
|
||||
image: ghcr.io/flathub-infra/flatpak-github-actions:kde-6.9
|
||||
image: ghcr.io/flathub-infra/flatpak-github-actions:kde-6.10
|
||||
options: --privileged
|
||||
timeout-minutes: 60
|
||||
|
||||
@@ -93,7 +93,7 @@ jobs:
|
||||
|
||||
- name: Build Flatpak (beta)
|
||||
if: ${{ inputs.stableBuild == false || inputs.stableBuild == 'false' }}
|
||||
uses: flatpak/flatpak-github-actions/flatpak-builder@401fe28a8384095fc1531b9d320b292f0ee45adb
|
||||
uses: flatpak/flatpak-github-actions/flatpak-builder@79327416609af08178ad73b352877e51450790b3
|
||||
with:
|
||||
bundle: ${{ steps.artifact-metadata.outputs.artifact-name }}.flatpak
|
||||
upload-artifact: false
|
||||
@@ -109,7 +109,7 @@ jobs:
|
||||
|
||||
- name: Build Flatpak (stable)
|
||||
if: ${{ inputs.stableBuild == true || inputs.stableBuild == 'true' }}
|
||||
uses: flatpak/flatpak-github-actions/flatpak-builder@401fe28a8384095fc1531b9d320b292f0ee45adb
|
||||
uses: flatpak/flatpak-github-actions/flatpak-builder@79327416609af08178ad73b352877e51450790b3
|
||||
with:
|
||||
bundle: ${{ steps.artifact-metadata.outputs.artifact-name }}.flatpak
|
||||
upload-artifact: false
|
||||
@@ -129,7 +129,7 @@ jobs:
|
||||
|
||||
- name: Push to Flathub (beta)
|
||||
if: ${{ inputs.publish == true && (inputs.stableBuild == false || inputs.stableBuild == 'false') }}
|
||||
uses: flatpak/flatpak-github-actions/flat-manager@401fe28a8384095fc1531b9d320b292f0ee45adb
|
||||
uses: flatpak/flatpak-github-actions/flat-manager@79327416609af08178ad73b352877e51450790b3
|
||||
with:
|
||||
flat-manager-url: https://hub.flathub.org/
|
||||
repository: beta
|
||||
@@ -138,7 +138,7 @@ jobs:
|
||||
|
||||
- name: Push to Flathub (stable)
|
||||
if: ${{ inputs.publish == true && (inputs.stableBuild == true || inputs.stableBuild == 'true') }}
|
||||
uses: flatpak/flatpak-github-actions/flat-manager@401fe28a8384095fc1531b9d320b292f0ee45adb
|
||||
uses: flatpak/flatpak-github-actions/flat-manager@79327416609af08178ad73b352877e51450790b3
|
||||
with:
|
||||
flat-manager-url: https://hub.flathub.org/
|
||||
repository: stable
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"app-id": "net.pcsx2.PCSX2",
|
||||
"runtime": "org.kde.Platform",
|
||||
"runtime-version": "6.10",
|
||||
"runtime-version": "6.11",
|
||||
"sdk": "org.kde.Sdk",
|
||||
"sdk-extensions": [
|
||||
"org.freedesktop.Sdk.Extension.llvm20"
|
||||
"org.freedesktop.Sdk.Extension.llvm22"
|
||||
],
|
||||
"add-extensions": {
|
||||
"org.freedesktop.Platform.ffmpeg-full": {
|
||||
"directory": "lib/ffmpeg",
|
||||
"version": "25.08",
|
||||
"version": "26.08",
|
||||
"add-ld-path": ".",
|
||||
"autodownload": true
|
||||
}
|
||||
@@ -52,8 +52,8 @@
|
||||
"-DCMAKE_PREFIX_PATH=\"${FLATPAK_DEST}\"",
|
||||
"-DCMAKE_BUILD_TYPE=Release",
|
||||
"-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON",
|
||||
"-DCMAKE_C_COMPILER=/usr/lib/sdk/llvm20/bin/clang",
|
||||
"-DCMAKE_CXX_COMPILER=/usr/lib/sdk/llvm20/bin/clang++",
|
||||
"-DCMAKE_C_COMPILER=/usr/lib/sdk/llvm22/bin/clang",
|
||||
"-DCMAKE_CXX_COMPILER=/usr/lib/sdk/llvm22/bin/clang++",
|
||||
"-DCMAKE_EXE_LINKER_FLAGS_INIT=-fuse-ld=lld",
|
||||
"-DCMAKE_MODULE_LINKER_FLAGS_INIT=-fuse-ld=lld",
|
||||
"-DCMAKE_SHARED_LINKER_FLAGS_INIT=-fuse-ld=lld",
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
From 4cf93f0f16b1503580cdb7ffdedb056321446677 Mon Sep 17 00:00:00 2001
|
||||
From: squidbus <175574877+squidbus@users.noreply.github.com>
|
||||
Date: Sat, 9 May 2026 16:53:22 -0700
|
||||
Subject: [PATCH] Restore some checks for Mac1 GPUs.
|
||||
|
||||
---
|
||||
MoltenVK/MoltenVK/GPUObjects/MVKDevice.h | 1 +
|
||||
MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 34 +++++++++++--------
|
||||
MoltenVK/MoltenVK/GPUObjects/MVKImage.mm | 2 +-
|
||||
.../MoltenVK/GPUObjects/MVKPixelFormats.mm | 2 +-
|
||||
4 files changed, 23 insertions(+), 16 deletions(-)
|
||||
|
||||
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
|
||||
index ba3914de5..8923d23f0 100644
|
||||
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
|
||||
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
|
||||
@@ -112,6 +112,7 @@ typedef struct MVKMTLDeviceCapabilities {
|
||||
bool supportsApple8;
|
||||
bool supportsApple9;
|
||||
bool supportsApple10;
|
||||
+ bool supportsMac1;
|
||||
bool supportsMac2;
|
||||
bool supportsMetal3;
|
||||
bool supportsMetal4;
|
||||
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
|
||||
index 2c930b004..2e212645a 100644
|
||||
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
|
||||
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
|
||||
@@ -110,7 +110,8 @@
|
||||
#if MVK_XCODE_26
|
||||
supportsApple10 = supportsGPUFam(Apple10, mtlDev);
|
||||
#endif
|
||||
- supportsMac2 = MVK_MACOS; // Incl Mac2 & MacCatalyst2
|
||||
+ supportsMac1 = MVK_MACOS;
|
||||
+ supportsMac2 = supportsGPUFam(Mac2, mtlDev) || supportsGPUFam(MacCatalyst2, mtlDev);
|
||||
|
||||
isAppleGPU = supportsApple1;
|
||||
|
||||
@@ -1547,7 +1548,7 @@
|
||||
const auto placementHeapFlags = VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT |
|
||||
VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT |
|
||||
VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT;
|
||||
- if (!getMVKConfig().useMTLHeap && mvkIsAnyFlagEnabled(flags, placementHeapFlags)) {
|
||||
+ if (!_metalFeatures.placementHeaps && mvkIsAnyFlagEnabled(flags, placementHeapFlags)) {
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
@@ -2456,9 +2457,10 @@
|
||||
|
||||
// AMD support for MTLHeap is buggy.
|
||||
auto cfgUseMTLHeap = getMVKConfig().useMTLHeap;
|
||||
- _metalFeatures.placementHeaps = (_properties.vendorID == kAMDVendorId
|
||||
- ? cfgUseMTLHeap == MVK_CONFIG_USE_MTLHEAP_ALWAYS
|
||||
- : cfgUseMTLHeap != MVK_CONFIG_USE_MTLHEAP_NEVER);
|
||||
+ auto allowMTLHeap = (_properties.vendorID == kAMDVendorId
|
||||
+ ? cfgUseMTLHeap == MVK_CONFIG_USE_MTLHEAP_ALWAYS
|
||||
+ : cfgUseMTLHeap != MVK_CONFIG_USE_MTLHEAP_NEVER);
|
||||
+ _metalFeatures.placementHeaps = allowMTLHeap && (supportsMTLGPUFamily(Apple2) || supportsMTLGPUFamily(Mac2));
|
||||
_metalFeatures.multisampleArrayTextures = !MVK_TVOS || mvkOSVersionIsAtLeast(16.0);
|
||||
|
||||
// Dynamic vertex stride needs to have everything aligned - compiled with support for vertex stride calls, and supported by both runtime OS and GPU.
|
||||
@@ -2467,7 +2469,7 @@
|
||||
|
||||
_metalFeatures.renderLinearTextures = _gpuCapabilities.supportsRenderLinearTextures;
|
||||
|
||||
- if (supportsMTLGPUFamily(Mac2)) {
|
||||
+ if (supportsMTLGPUFamily(Mac1)) {
|
||||
_metalFeatures.mtlBufferAlignment = 256;
|
||||
_metalFeatures.mtlConstantBufferAlignment = 32;
|
||||
_metalFeatures.mtlCopyBufferAlignment = 4;
|
||||
@@ -2489,15 +2491,18 @@
|
||||
_metalFeatures.presentModeImmediate = true;
|
||||
_metalFeatures.nonUniformThreadgroups = true;
|
||||
_metalFeatures.native3DCompressedTextures = true;
|
||||
- _metalFeatures.multisampleLayeredRendering = _metalFeatures.layeredRendering;
|
||||
+ _metalFeatures.simdPermute = true;
|
||||
+ _metalFeatures.memoryBarriers = true;
|
||||
+ }
|
||||
+
|
||||
+ if (supportsMTLGPUFamily(Mac2)) {
|
||||
+ _metalFeatures.multisampleLayeredRendering = true;
|
||||
_metalFeatures.stencilFeedback = true;
|
||||
_metalFeatures.depthResolve = true;
|
||||
_metalFeatures.stencilResolve = true;
|
||||
- _metalFeatures.simdPermute = true;
|
||||
_metalFeatures.quadPermute = true;
|
||||
_metalFeatures.simdReduction = true;
|
||||
- _metalFeatures.memoryBarriers = true;
|
||||
- }
|
||||
+ }
|
||||
|
||||
if (supportsMTLGPUFamily(Apple1)) {
|
||||
_metalFeatures.mtlBufferAlignment = 64;
|
||||
@@ -2798,7 +2803,7 @@
|
||||
_features.shaderResourceMinLod = true;
|
||||
}
|
||||
|
||||
- if (supportsMTLGPUFamily(Mac2)) {
|
||||
+ if (supportsMTLGPUFamily(Mac1)) {
|
||||
_features.occlusionQueryPrecise = true;
|
||||
_features.imageCubeArray = true;
|
||||
_features.tessellationShader = true;
|
||||
@@ -2970,19 +2975,19 @@
|
||||
|
||||
if (supportsMTLGPUFamily(Apple3)) {
|
||||
_properties.limits.optimalBufferCopyOffsetAlignment = 16;
|
||||
- } else if (supportsMTLGPUFamily(Mac2)) {
|
||||
+ } else if (supportsMTLGPUFamily(Mac1)) {
|
||||
_properties.limits.optimalBufferCopyOffsetAlignment = 256;
|
||||
} else {
|
||||
_properties.limits.optimalBufferCopyOffsetAlignment = 64;
|
||||
}
|
||||
|
||||
- if (supportsMTLGPUFamily(Apple4) || supportsMTLGPUFamily(Mac2)) {
|
||||
+ if (supportsMTLGPUFamily(Apple4) || supportsMTLGPUFamily(Mac1)) {
|
||||
_properties.limits.maxFragmentInputComponents = 124;
|
||||
} else {
|
||||
_properties.limits.maxFragmentInputComponents = 60;
|
||||
}
|
||||
|
||||
- if (supportsMTLGPUFamily(Apple5) || supportsMTLGPUFamily(Mac2)) {
|
||||
+ if (supportsMTLGPUFamily(Apple5) || supportsMTLGPUFamily(Mac1)) {
|
||||
_properties.limits.maxTessellationGenerationLevel = 64;
|
||||
_properties.limits.maxTessellationPatchSize = 32;
|
||||
} else if (supportsMTLGPUFamily(Apple3)) {
|
||||
@@ -3653,6 +3658,7 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope
|
||||
if (supportsMTLGPUFamily(Apple2)) { logMsg += "\n\t\tGPU Family Apple 2"; } else
|
||||
if (supportsMTLGPUFamily(Apple1)) { logMsg += "\n\t\tGPU Family Apple 1"; }
|
||||
|
||||
+ if (supportsMTLGPUFamily(Mac1)) { logMsg += "\n\t\tGPU Family Mac 1"; }
|
||||
if (supportsMTLGPUFamily(Mac2)) { logMsg += "\n\t\tGPU Family Mac 2"; }
|
||||
|
||||
logMsg += "\n\t\tRead-Write Texture Tier ";
|
||||
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
|
||||
index d2fdd4020..696ec4467 100644
|
||||
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
|
||||
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
|
||||
@@ -1382,7 +1382,7 @@ static MTLRegion getMTLRegion(const ImgRgn& imgRgn) {
|
||||
const auto placementHeapFlags = VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT |
|
||||
VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT |
|
||||
VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT;
|
||||
- if (!getMVKConfig().useMTLHeap && mvkIsAnyFlagEnabled(pCreateInfo->flags, placementHeapFlags)) {
|
||||
+ if (!getMetalFeatures().placementHeaps && mvkIsAnyFlagEnabled(pCreateInfo->flags, placementHeapFlags)) {
|
||||
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : MTLHeap must be enabled to create 2D-on-3D or block texel view compatible images."));
|
||||
}
|
||||
|
||||
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
|
||||
index d16d6c8f6..11ca10a03 100644
|
||||
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
|
||||
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
|
||||
@@ -1343,7 +1343,7 @@
|
||||
|
||||
addMTLVertexFormatDesc( UChar4Normalized_BGRA );
|
||||
|
||||
- if (gpuCaps.supportsApple5 || gpuCaps.supportsMac2) {
|
||||
+ if (gpuCaps.supportsApple5 || gpuCaps.supportsMac1) {
|
||||
addMTLVertexFormatDesc( FloatRG11B10 );
|
||||
addMTLVertexFormatDesc( FloatRGB9E5 );
|
||||
}
|
||||
@@ -289,6 +289,8 @@ echo "Installing MoltenVK..."
|
||||
rm -fr "MoltenVK-${MOLTENVK}"
|
||||
tar xf "MoltenVK-$MOLTENVK.tar.gz"
|
||||
cd "MoltenVK-${MOLTENVK}"
|
||||
patch -p1 < "$SCRIPTDIR/4cf93f0f16b1503580cdb7ffdedb056321446677.patch"
|
||||
patch -p1 < "$SCRIPTDIR/mvk-texture-swizzle.patch"
|
||||
./fetchDependencies --macos
|
||||
make macos MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=0 MVK_CONFIG_USE_METAL_PRIVATE_API=1
|
||||
cp Package/Latest/MoltenVK/dynamic/dylib/macOS/libMoltenVK.dylib "$INSTALLDIR/lib/"
|
||||
|
||||
@@ -78,7 +78,7 @@ e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWE
|
||||
eee7dea22ed502868017971c86c63c4ed1e6085de0baebfdcc3d3322f00f3eb0 libpng-$LIBPNG-apng.patch.gz
|
||||
6f30092cef9fb839779646608f4ee14ae3cbac989c47fa05e841b0841f09878e libjpeg-turbo-$LIBJPEGTURBO.tar.gz
|
||||
cf38e0e28c7e5605942c4a77755349b0145804a397af37eb1fb4c77cb237f635 ffmpeg-$FFMPEG.tar.xz
|
||||
9985f141902a17de818e264d17c1ce334b748e499ee02fcb4703e4dc0038f89c v$MOLTENVK.tar.gz
|
||||
9985f141902a17de818e264d17c1ce334b748e499ee02fcb4703e4dc0038f89c MoltenVK-$MOLTENVK.tar.gz
|
||||
5cd9495d9316cf6cc937bb328a7fd491c3248ef2469cfa42511f1039f6148aca KDDockWidgets-$KDDOCKWIDGETS.tar.gz
|
||||
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
|
||||
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
|
||||
@@ -102,7 +102,7 @@ if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
|
||||
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
|
||||
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
|
||||
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
|
||||
-O "https://github.com/KhronosGroup/MoltenVK/archive/refs/tags/v$MOLTENVK.tar.gz" \
|
||||
-O "https://github.com/KhronosGroup/MoltenVK/archive/v$MOLTENVK/MoltenVK-$MOLTENVK.tar.gz" \
|
||||
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
|
||||
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
|
||||
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
|
||||
@@ -228,8 +228,10 @@ cd ..
|
||||
# MoltenVK already builds universal binaries, nothing special to do here.
|
||||
echo "Installing MoltenVK..."
|
||||
rm -fr "MoltenVK-${MOLTENVK}"
|
||||
tar xf "v$MOLTENVK.tar.gz"
|
||||
tar xf "MoltenVK-$MOLTENVK.tar.gz"
|
||||
cd "MoltenVK-${MOLTENVK}"
|
||||
patch -p1 < "$SCRIPTDIR/4cf93f0f16b1503580cdb7ffdedb056321446677.patch"
|
||||
patch -p1 < "$SCRIPTDIR/mvk-texture-swizzle.patch"
|
||||
sed -i '' 's/xcodebuild "$@"/xcodebuild $XCODEBUILD_EXTRA_ARGS "$@"/g' fetchDependencies
|
||||
sed -i '' 's/XCODEBUILD :=/XCODEBUILD ?=/g' Makefile
|
||||
XCODEBUILD_EXTRA_ARGS="VALID_ARCHS=x86_64" ./fetchDependencies --macos
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
From f6be31a110761ea494a938d62473abc085ea447b Mon Sep 17 00:00:00 2001
|
||||
From: TellowKrinkle <tellowkrinkle@gmail.com>
|
||||
Date: Mon, 31 Aug 2026 02:52:38 -0500
|
||||
Subject: [PATCH] Re-add native texture swizzle checks
|
||||
|
||||
---
|
||||
MoltenVK/MoltenVK/API/mvk_deprecated_api.h | 2 +-
|
||||
MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 3 +-
|
||||
MoltenVK/MoltenVK/GPUObjects/MVKImage.mm | 51 ++++++++++++++++++-
|
||||
.../MoltenVK/GPUObjects/MVKPixelFormats.mm | 3 ++
|
||||
4 files changed, 56 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/MoltenVK/MoltenVK/API/mvk_deprecated_api.h b/MoltenVK/MoltenVK/API/mvk_deprecated_api.h
|
||||
index 74fef844..8d16f86c 100644
|
||||
--- a/MoltenVK/MoltenVK/API/mvk_deprecated_api.h
|
||||
+++ b/MoltenVK/MoltenVK/API/mvk_deprecated_api.h
|
||||
@@ -118,7 +118,7 @@ typedef struct {
|
||||
VkBool32 fences; /**< If true, Metal synchronization fences (MTLFence) are supported. Deprecated. Will always be true on all platforms. */
|
||||
VkBool32 rasterOrderGroups; /**< If true, Raster order groups in fragment shaders are supported. */
|
||||
VkBool32 native3DCompressedTextures; /**< If true, 3D compressed images are supported natively, without manual decompression. */
|
||||
- VkBool32 nativeTextureSwizzle; /**< If true, component swizzle is supported natively, without manual swizzling in shaders. Deprecated. Will always be true on all platforms. */
|
||||
+ VkBool32 nativeTextureSwizzle; /**< If true, component swizzle is supported natively, without manual swizzling in shaders. */
|
||||
VkBool32 placementHeaps; /**< If true, MTLHeap objects support placement of resources. */
|
||||
VkDeviceSize pushConstantSizeAlignment; /**< The alignment used internally when allocating memory for push constants. Must be PoT. */
|
||||
uint32_t maxTextureLayers; /**< The maximum number of layers in an array texture. */
|
||||
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
|
||||
index aaf5945b..c7da8256 100644
|
||||
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
|
||||
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
|
||||
@@ -2496,6 +2496,7 @@
|
||||
_metalFeatures.stencilResolve = true;
|
||||
_metalFeatures.quadPermute = true;
|
||||
_metalFeatures.simdReduction = true;
|
||||
+ _metalFeatures.nativeTextureSwizzle = true;
|
||||
}
|
||||
|
||||
if (supportsMTLGPUFamily(Apple1)) {
|
||||
@@ -2504,6 +2505,7 @@
|
||||
_metalFeatures.maxPerStageTextureCount = 31;
|
||||
_metalFeatures.maxTextureDimension = (8 * KIBI);
|
||||
_metalFeatures.maxQueryBufferSize = (64 * KIBI);
|
||||
+ _metalFeatures.nativeTextureSwizzle = true;
|
||||
|
||||
_metalFeatures.maxPerStageDynamicMTLBufferCount = _metalFeatures.maxPerStageBufferCount;
|
||||
_metalFeatures.renderLinearTextures = true;
|
||||
@@ -2727,7 +2729,6 @@
|
||||
_metalFeatures.events = true;
|
||||
_metalFeatures.ioSurfaces = true;
|
||||
_metalFeatures.renderWithoutAttachments = true;
|
||||
- _metalFeatures.nativeTextureSwizzle = true;
|
||||
}
|
||||
|
||||
bool MVKPhysicalDevice::isTier2MetalArgumentBuffers() {
|
||||
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
|
||||
index 8eda5515..392a4f98 100644
|
||||
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
|
||||
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
|
||||
@@ -1925,7 +1925,7 @@ static void signalAndUntrack(const MVKSwapchainSignaler& signaler) {
|
||||
}
|
||||
|
||||
id<MTLTexture> texView = nil;
|
||||
- if (_useSwizzle) {
|
||||
+ if (_useSwizzle && getMetalFeatures().nativeTextureSwizzle) {
|
||||
texView = [mtlTex newTextureViewWithPixelFormat: _mtlPixFmt
|
||||
textureType: _imageView->_mtlTextureType
|
||||
levels: levelRange
|
||||
@@ -2103,6 +2103,55 @@ static void signalAndUntrack(const MVKSwapchainSignaler& signaler) {
|
||||
}
|
||||
}
|
||||
|
||||
+#define SWIZZLE_MATCHES(R, G, B, A) mvkVkComponentMappingsMatch(_componentSwizzle, {VK_COMPONENT_SWIZZLE_ ##R, VK_COMPONENT_SWIZZLE_ ##G, VK_COMPONENT_SWIZZLE_ ##B, VK_COMPONENT_SWIZZLE_ ##A} )
|
||||
+#define VK_COMPONENT_SWIZZLE_ANY VK_COMPONENT_SWIZZLE_MAX_ENUM
|
||||
+
|
||||
+ if (_imageView->_image->hasPixelFormatView(_planeIndex)) {
|
||||
+ switch (_mtlPixFmt) {
|
||||
+ case MTLPixelFormatR8Unorm:
|
||||
+ if (SWIZZLE_MATCHES(ZERO, ANY, ANY, R)) {
|
||||
+ _mtlPixFmt = MTLPixelFormatA8Unorm;
|
||||
+ return VK_SUCCESS;
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case MTLPixelFormatA8Unorm:
|
||||
+ if (SWIZZLE_MATCHES(A, ANY, ANY, ZERO)) {
|
||||
+ _mtlPixFmt = MTLPixelFormatR8Unorm;
|
||||
+ return VK_SUCCESS;
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case MTLPixelFormatRGBA8Unorm:
|
||||
+ if (SWIZZLE_MATCHES(B, G, R, A)) {
|
||||
+ _mtlPixFmt = MTLPixelFormatBGRA8Unorm;
|
||||
+ return VK_SUCCESS;
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case MTLPixelFormatRGBA8Unorm_sRGB:
|
||||
+ if (SWIZZLE_MATCHES(B, G, R, A)) {
|
||||
+ _mtlPixFmt = MTLPixelFormatBGRA8Unorm_sRGB;
|
||||
+ return VK_SUCCESS;
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case MTLPixelFormatBGRA8Unorm:
|
||||
+ if (SWIZZLE_MATCHES(B, G, R, A)) {
|
||||
+ _mtlPixFmt = MTLPixelFormatRGBA8Unorm;
|
||||
+ return VK_SUCCESS;
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case MTLPixelFormatBGRA8Unorm_sRGB:
|
||||
+ if (SWIZZLE_MATCHES(B, G, R, A)) {
|
||||
+ _mtlPixFmt = MTLPixelFormatRGBA8Unorm_sRGB;
|
||||
+ return VK_SUCCESS;
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
_useSwizzle = !mvkVkComponentMappingsMatch(_componentSwizzle, {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A});
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
|
||||
index 316d7c6f..31a2c6a1 100644
|
||||
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
|
||||
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
|
||||
@@ -654,6 +654,9 @@
|
||||
|
||||
bool pfv = false;
|
||||
|
||||
+ // Swizzle emulation may need to reinterpret
|
||||
+ needsReinterpretation |= !_physicalDevice->getMetalFeatures()->nativeTextureSwizzle;
|
||||
+
|
||||
pfv |= isColorFormat && needsReinterpretation &&
|
||||
mvkIsAnyFlagEnabled(vkImageUsageFlags, (VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
VK_IMAGE_USAGE_STORAGE_BIT |
|
||||
--
|
||||
2.39.5 (Apple Git-154)
|
||||
|
||||
@@ -145,7 +145,7 @@ jobs:
|
||||
cmake --build build --config Release || exit /b
|
||||
cmake --install build --config Release || exit /b
|
||||
) else (
|
||||
msbuild "PCSX2_qt.sln" /m /v:m /p:Configuration="${{ inputs.configuration }}" /p:Platform="${{ inputs.platform }}" || exit /b
|
||||
msbuild "PCSX2_qt.slnx" /m /v:m /p:Configuration="${{ inputs.configuration }}" /p:Platform="${{ inputs.platform }}" || exit /b
|
||||
)
|
||||
REM We can use Segoe UI Emoji so we don't need to bundle this
|
||||
del bin\resources\fonts\Twemoji*
|
||||
|
||||
-1018
File diff suppressed because it is too large
Load Diff
+485
@@ -0,0 +1,485 @@
|
||||
<Solution>
|
||||
<Configurations>
|
||||
<BuildType Name="Debug" />
|
||||
<BuildType Name="Debug AVX2" />
|
||||
<BuildType Name="Debug Clang" />
|
||||
<BuildType Name="Debug Clang AVX2" />
|
||||
<BuildType Name="Devel" />
|
||||
<BuildType Name="Devel AVX2" />
|
||||
<BuildType Name="Devel Clang" />
|
||||
<BuildType Name="Devel Clang AVX2" />
|
||||
<BuildType Name="Release" />
|
||||
<BuildType Name="Release AVX2" />
|
||||
<BuildType Name="Release Clang" />
|
||||
<BuildType Name="Release Clang AVX2" />
|
||||
<Platform Name="ARM64" />
|
||||
<Platform Name="x64" />
|
||||
</Configurations>
|
||||
<Folder Name="/3rdparty/">
|
||||
<Project Path="3rdparty/ccc/ccc.vcxproj" Id="2589f8ce-ea77-4b73-911e-64074569795b">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
<Project Path="3rdparty/cpuinfo/cpuinfo.vcxproj" Id="7e183337-a7e9-460c-9d3d-568bc9f9bcc1">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
<Project Path="3rdparty/cubeb/cubeb.vcxproj" Id="bf74c473-dc04-44b3-92e8-4145f4e77342">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
<Project Path="3rdparty/d3d12memalloc/d3d12memalloc.vcxproj" Id="d45cec7a-3171-40dd-975d-e1544cf16139">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
<Project Path="3rdparty/demangler/demangler.vcxproj" Id="d31a6dd1-99ca-41d8-a230-1fae913c8989">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
<Project Path="3rdparty/discord-rpc/discord-rpc.vcxproj" Id="e960dfdf-1bd3-4c29-b251-d1a0919c9b09">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
<Project Path="3rdparty/fmt/fmt.vcxproj" Id="449ad25e-424a-4714-babc-68706cdcc33b">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
<Project Path="3rdparty/freesurround/freesurround.vcxproj" Id="1dd0b31f-37f0-4a36-a521-74133aca4737">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
<Project Path="3rdparty/glad/glad.vcxproj" Id="c0293b32-5acf-40f0-aa6c-e6da6f3bf33a">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
<Project Path="3rdparty/imgui/imgui.vcxproj" Id="88fb34ec-845e-4f21-a552-f1573b9ed167">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
<Project Path="3rdparty/libchdr/libchdr.vcxproj" Id="a0d2b3ad-1f72-4ee3-8b5c-f2c358da35f0">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
<Project Path="3rdparty/libzip/libzip.vcxproj" Id="20b2e9fe-f020-42a0-b324-956f5b06ea68">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
<Project Path="3rdparty/lzma/lzma.vcxproj" Id="a4323327-3f2b-4271-83d9-7f9a3c66b6b2">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
<Project Path="3rdparty/rainterface/rainterface.vcxproj" Id="95dd0a0c-d14d-4cff-a593-820ef26efcc8">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
<Project Path="3rdparty/rcheevos/rcheevos.vcxproj" Id="6d5b5ad9-1525-459b-939f-a5e1082af6b3">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
<Project Path="3rdparty/simpleini/simpleini.vcxproj" Id="1ec8b3c0-8fb3-46de-a2e0-a9121203f266">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
<Project Path="3rdparty/soundtouch/SoundTouch.vcxproj" Id="e9b51944-7e6d-4bcd-83f2-7bbd5a46182d">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
<Project Path="3rdparty/vixl/vixl.vcxproj" Id="8906836e-f06e-46e8-b11a-74e5e8c7b8fb">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="*|x64" Project="false" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
<Project Path="3rdparty/zydis/zydis.vcxproj" Id="67d0160c-0fe4-44b9-ac2e-82bbcf4104df">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="*|ARM64" Project="false" />
|
||||
</Project>
|
||||
</Folder>
|
||||
<Project Path="common/common.vcxproj" Id="4639972e-424e-4e13-8b07-ca403c481346">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
<Project Path="pcsx2-gsrunner/pcsx2-gsrunner.vcxproj" Id="bb98bf81-a132-444a-bb81-96d510f433a8">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Project="false" />
|
||||
</Project>
|
||||
<Project Path="pcsx2-qt/pcsx2-qt.vcxproj" Id="2a016f21-87ae-4154-8271-1f57e91408e9">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
<Project Path="pcsx2/pcsx2.vcxproj" Id="6c7986c4-3e4d-4dcc-b3c6-6bb12b238995">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
<Project Path="updater/updater.vcxproj" Id="90bbdc04-cc44-4006-b893-06a4fea8ed47">
|
||||
<BuildType Solution="Debug AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug Clang AVX2|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Debug|ARM64" Project="Debug Clang" />
|
||||
<BuildType Solution="Devel AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel Clang AVX2|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Devel|ARM64" Project="Devel Clang" />
|
||||
<BuildType Solution="Release AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release Clang AVX2|ARM64" Project="Release Clang" />
|
||||
<BuildType Solution="Release|ARM64" Project="Release Clang" />
|
||||
<Build Solution="Debug AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Debug|ARM64" Project="false" />
|
||||
<Build Solution="Devel AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Devel|ARM64" Project="false" />
|
||||
<Build Solution="Release AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release Clang AVX2|ARM64" Project="false" />
|
||||
<Build Solution="Release|ARM64" Project="false" />
|
||||
</Project>
|
||||
</Solution>
|
||||
@@ -4706,6 +4706,7 @@ SCES-50000:
|
||||
gpuPaletteConversion: 2 # Lots of CLUTs in large textures.
|
||||
cpuSpriteRenderBW: 1 # Fixes car textures.
|
||||
cpuSpriteRenderLevel: 1 # Needed for above.
|
||||
rewriteLargeSTCoords: 1 # Fix reflections on cars.
|
||||
SCES-50001:
|
||||
name: "Tekken Tag Tournament"
|
||||
region: "PAL-M5"
|
||||
@@ -35387,6 +35388,7 @@ SLPM-60109:
|
||||
gpuPaletteConversion: 2 # Lots of CLUTs in large textures.
|
||||
cpuSpriteRenderBW: 1 # Fixes car textures.
|
||||
cpuSpriteRenderLevel: 1 # Needed for above.
|
||||
rewriteLargeSTCoords: 1 # Fix reflections on cars.
|
||||
SLPM-60112:
|
||||
name: "フレースヴェルグ [体験版]"
|
||||
name-sort: "ふれーすヴぇるぐ [たいけんばん]"
|
||||
@@ -54809,6 +54811,7 @@ SLPS-20001:
|
||||
gpuPaletteConversion: 2 # Lots of CLUTs in large textures.
|
||||
cpuSpriteRenderBW: 1 # Fixes car textures.
|
||||
cpuSpriteRenderLevel: 1 # Needed for above.
|
||||
rewriteLargeSTCoords: 1 # Fix reflections on cars.
|
||||
SLPS-20002:
|
||||
name: "撞球 ビリヤードマスター2"
|
||||
name-sort: "どうきゅう びりやーどますたー2"
|
||||
@@ -60602,7 +60605,6 @@ SLPS-25529:
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 4 # Aligns DoF effects.
|
||||
nativeScaling: 2 # Fixes post effects.
|
||||
getSkipCount: "GSC_UltramanFightingEvolution"
|
||||
SLPS-25530:
|
||||
name: "餓狼伝 Breakblow"
|
||||
name-sort: "がろうでん Breakblow"
|
||||
@@ -62340,7 +62342,6 @@ SLPS-25800:
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 4 # Aligns DoF effects.
|
||||
nativeScaling: 2 # Fixes post effects.
|
||||
getSkipCount: "GSC_UltramanFightingEvolution"
|
||||
SLPS-25801:
|
||||
name: "今日からマ王! 眞マ国の休日"
|
||||
name-sort: "きょうからまおう しんまこくのきゅうじつ"
|
||||
@@ -63501,6 +63502,7 @@ SLPS-71502:
|
||||
gpuPaletteConversion: 2 # Lots of CLUTs in large textures.
|
||||
cpuSpriteRenderBW: 1 # Fixes car textures.
|
||||
cpuSpriteRenderLevel: 1 # Needed for above.
|
||||
rewriteLargeSTCoords: 1 # Fix reflections on cars.
|
||||
SLPS-72501:
|
||||
name: "ファイナルファンタジーⅩ [MEGA HITS!]"
|
||||
name-sort: "ふぁいなるふぁんたじー10 [MEGA HITS!]"
|
||||
@@ -64503,6 +64505,7 @@ SLUS-20002:
|
||||
gpuPaletteConversion: 2 # Lots of CLUTs in large textures.
|
||||
cpuSpriteRenderBW: 1 # Fixes car textures.
|
||||
cpuSpriteRenderLevel: 1 # Needed for above.
|
||||
rewriteLargeSTCoords: 1 # Fix reflections on cars.
|
||||
SLUS-20003:
|
||||
name: "Portal Runner"
|
||||
region: "NTSC-U"
|
||||
|
||||
@@ -403,6 +403,7 @@
|
||||
030000006d04000011c2000000000000,Logitech WingMan Cordless,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows,
|
||||
030000006d0400000ac2000000000000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows,
|
||||
03000000380700005645000000000000,Lynx,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
030000004e3700001101000000000000,M64 Pro Controller,a:b0,x:b1,start:b9,leftshoulder:b3,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,-rightx:b7,+rightx:b8,-righty:b5,+righty:b6,lefttrigger:b2,platform:Windows,
|
||||
03000000222200006000000000000000,Macally,a:b1,b:b2,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b33,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000380700003888000000000000,Mad Catz Arcade Fightstick TE S Plus PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000380700008532000000000000,Mad Catz Arcade Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
@@ -550,7 +551,7 @@
|
||||
03000000250900000500000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows,
|
||||
030000004c0500006802000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b10,lefttrigger:a3~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:a4~,rightx:a2,righty:a5,start:b8,x:b3,y:b0,platform:Windows,
|
||||
030000004f1f00000800000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000632500007505000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000632500007505000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Windows,
|
||||
03000000888800000804000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,
|
||||
030000008f0e00000300000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,
|
||||
@@ -1023,6 +1024,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000006d0400001fc2000000000000,Logitech F710,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
|
||||
030000006d0400001ac2000004000000,Logitech Precision,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000006d04000018c2000000010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3~,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000004e3700001101000000020000,M64 Pro Controller,a:b0,x:b1,start:b9,leftshoulder:b3,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,-rightx:b7,+rightx:b8,-righty:b5,+righty:b6,lefttrigger:b2,platform:Mac OS X,
|
||||
03000000380700005032000000010000,Mad Catz PS3 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
03000000380700008433000000010000,Mad Catz PS3 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
03000000380700005082000000010000,Mad Catz PS4 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
|
||||
@@ -1357,6 +1359,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000006f0e00008001000011010000,Faceoff Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000852100000201000010010000,FF GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
05000000b40400001224000001010000,Flydigi APEX 4,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b20,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
03000000d73700001424000004010000,Flydigi Direwolf 4,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,paddle1:b12,paddle2:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
|
||||
03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000b40400001224000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
@@ -1437,6 +1440,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000341a000005f7000010010000,HuiJia GameCube Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
|
||||
05000000242e00000b20000001000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Linux,
|
||||
03000000242e0000ff0b000011010000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Linux,
|
||||
03000000790000004e95000010010000,Hyperkin N64 Adapter,a:b1,b:b2,start:b9,leftshoulder:b7,rightshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightx:a5,righty:a2,dpup:b12,dpdown:b14,dpleft:b15,dpright:b13,platform:Linux,
|
||||
03000000242e00006a38000010010000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b3,start:b5,platform:Linux,
|
||||
03000000242e00008816000001010000,Hyperkin X91,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000f00300008d03000011010000,HyperX Clutch,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
@@ -1483,6 +1487,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000006d04000019c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000006d0400000ac2000010010000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Linux,
|
||||
030000006d04000011c2000010010000,Logitech WingMan RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux,
|
||||
050000004e3700001101000000020000,M64 Pro Controller,a:b0,x:b1,start:b9,leftshoulder:b3,rightshoulder:b4,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,-rightx:b7,+rightx:b8,-righty:b5,+righty:b6,lefttrigger:b2,platform:Linux,
|
||||
05000000380700006652000025010000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000380700008532000010010000,Mad Catz Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000380700005032000011010000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
|
||||
@@ -169,6 +169,11 @@ float depth32_to_depth24(float d)
|
||||
return uint_to_depth24(depth_to_uint(d));
|
||||
}
|
||||
|
||||
float4 primid_to_rgba8(float p)
|
||||
{
|
||||
return uint_to_rgba8(asuint(p));
|
||||
}
|
||||
|
||||
#if defined(__ps_copy__)
|
||||
OUTPUT_TYPE ps_copy(PS_INPUT input) : OUTPUT_SV
|
||||
{
|
||||
@@ -323,6 +328,13 @@ OUTPUT_TYPE ps_convert_depth32_depth24(PS_INPUT input) : OUTPUT_SV
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__ps_convert_primid_rgba8__)
|
||||
OUTPUT_TYPE ps_convert_primid_rgba8(PS_INPUT input) : OUTPUT_SV
|
||||
{
|
||||
return primid_to_rgba8(sample_c(input.t));
|
||||
}
|
||||
#endif
|
||||
|
||||
#define SAMPLE_RGBA_DEPTH_BILN(CONVERT_FN) \
|
||||
uint width, height; \
|
||||
Texture.GetDimensions(width, height); \
|
||||
@@ -650,9 +662,9 @@ float ps_primid_image_init_0(PS_INPUT input) : SV_Target
|
||||
{
|
||||
float c;
|
||||
if ((127.5f / 255.0f) < sample_c(input.t).a) // < 0x80 pass (== 0x80 should not pass)
|
||||
c = float(-1);
|
||||
c = float(PRIMID_MIN);
|
||||
else
|
||||
c = float(0x7FFFFFFF);
|
||||
c = float(PRIMID_MAX);
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
@@ -662,9 +674,9 @@ float ps_primid_image_init_1(PS_INPUT input) : SV_Target
|
||||
{
|
||||
float c;
|
||||
if (sample_c(input.t).a < (127.5f / 255.0f)) // >= 0x80 pass
|
||||
c = float(-1);
|
||||
c = float(PRIMID_MIN);
|
||||
else
|
||||
c = float(0x7FFFFFFF);
|
||||
c = float(PRIMID_MAX);
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
@@ -674,9 +686,9 @@ float ps_primid_image_init_2(PS_INPUT input) : SV_Target
|
||||
{
|
||||
float c;
|
||||
if ((254.5f / 255.0f) < sample_c(input.t).a) // < 0x80 pass (== 0x80 should not pass)
|
||||
c = float(-1);
|
||||
c = float(PRIMID_MIN);
|
||||
else
|
||||
c = float(0x7FFFFFFF);
|
||||
c = float(PRIMID_MAX);
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
@@ -686,9 +698,9 @@ float ps_primid_image_init_3(PS_INPUT input) : SV_Target
|
||||
{
|
||||
float c;
|
||||
if (sample_c(input.t).a < (254.5f / 255.0f)) // >= 0x80 pass
|
||||
c = float(-1);
|
||||
c = float(PRIMID_MIN);
|
||||
else
|
||||
c = float(0x7FFFFFFF);
|
||||
c = float(PRIMID_MAX);
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1097,8 +1097,11 @@ void ps_fbmask(inout float4 C, float2 pos_xy)
|
||||
{
|
||||
if (PS_FBMASK)
|
||||
{
|
||||
float multi = PS_COLCLIP_HW ? 65535.0f : 255.0f;
|
||||
float4 RT = trunc(RtLoad(int2(pos_xy)) * multi + 0.1f);
|
||||
float multi_rgb = PS_COLCLIP_HW ? 65535.0f : 255.0f;
|
||||
float multi_a = PS_RTA_CORRECTION ? 128.0f : 255.0f;
|
||||
float4 RT = RtLoad(int2(pos_xy));
|
||||
RT.rgb = trunc(RT.rgb * multi_rgb + 0.1f);
|
||||
RT.a = round(RT.a * multi_a);
|
||||
C = (float4)(((uint4)C & ~FbMask) | ((uint4)RT & FbMask));
|
||||
}
|
||||
}
|
||||
@@ -1594,7 +1597,6 @@ if (bad)
|
||||
output.c1 = o_col1;
|
||||
#endif
|
||||
#elif PS_RETURN_COLOR_ROV
|
||||
o_col0 = (FbMask == 0xFFu) ? RtLoad(input.p.xy) : o_col0; // channel masking
|
||||
if (!rov_discard_color)
|
||||
RtWrite(input.p.xy, o_col0);
|
||||
#endif
|
||||
|
||||
@@ -139,6 +139,11 @@ float depth32_to_depth24(float d)
|
||||
return uint_to_depth24(depth_to_uint(d));
|
||||
}
|
||||
|
||||
vec4 primid_to_rgba8(float p)
|
||||
{
|
||||
return uint_to_rgba8(floatBitsToUint(p));
|
||||
}
|
||||
|
||||
#ifdef ps_copy
|
||||
void ps_copy()
|
||||
{
|
||||
@@ -212,6 +217,13 @@ void ps_convert_depth32_depth24()
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_primid_rgba8
|
||||
void ps_convert_primid_rgba8()
|
||||
{
|
||||
OUTPUT = primid_to_rgba8(sample_c());
|
||||
}
|
||||
#endif
|
||||
|
||||
#define SAMPLE_RGBA_DEPTH_BILN(CONVERT_FN) \
|
||||
ivec2 dims = textureSize(TextureSampler, 0); \
|
||||
vec2 top_left_f = PSin_t * vec2(dims) - 0.5f; \
|
||||
@@ -615,23 +627,23 @@ void ps_yuv()
|
||||
|
||||
void main()
|
||||
{
|
||||
o_col0 = vec4(0x7FFFFFFF);
|
||||
o_col0 = vec4(PRIMID_MAX);
|
||||
|
||||
#ifdef ps_primid_image_init_0
|
||||
if((127.5f / 255.0f) < sample_c().a) // < 0x80 pass (== 0x80 should not pass)
|
||||
o_col0 = vec4(-1);
|
||||
o_col0 = vec4(PRIMID_MIN);
|
||||
#endif
|
||||
#ifdef ps_primid_image_init_1
|
||||
if(sample_c().a < (127.5f / 255.0f)) // >= 0x80 pass
|
||||
o_col0 = vec4(-1);
|
||||
o_col0 = vec4(PRIMID_MIN);
|
||||
#endif
|
||||
#ifdef ps_primid_image_init_2
|
||||
if((254.5f / 255.0f) < sample_c().a) // < 0x80 pass (== 0x80 should not pass)
|
||||
o_col0 = vec4(-1);
|
||||
o_col0 = vec4(PRIMID_MIN);
|
||||
#endif
|
||||
#ifdef ps_primid_image_init_3
|
||||
if(sample_c().a < (254.5f / 255.0f)) // >= 0x80 pass
|
||||
o_col0 = vec4(-1);
|
||||
o_col0 = vec4(PRIMID_MIN);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -932,11 +932,11 @@ void ps_fbmask(inout vec4 C)
|
||||
{
|
||||
// FIXME do I need special case for 16 bits
|
||||
#if PS_FBMASK
|
||||
#if PS_COLCLIP_HW == 1
|
||||
vec4 RT = trunc(sample_from_rt() * 65535.0f);
|
||||
#else
|
||||
vec4 RT = trunc(sample_from_rt() * 255.0f + 0.1f);
|
||||
#endif
|
||||
float multi_rgb = PS_COLCLIP_HW != 0 ? 65535.0f : 255.0f;
|
||||
float multi_a = PS_RTA_CORRECTION != 0 ? 128.0f : 255.0f;
|
||||
vec4 RT = sample_from_rt();
|
||||
RT.rgb = trunc(RT.rgb * multi_rgb + 0.1f);
|
||||
RT.a = round(RT.a * multi_a);
|
||||
C = vec4((uvec4(C) & ~FbMask) | (uvec4(RT) & FbMask));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -130,6 +130,11 @@ float depth32_to_depth24(float d)
|
||||
return uint_to_depth24(depth_to_uint(d));
|
||||
}
|
||||
|
||||
vec4 primid_to_rgba8(float p)
|
||||
{
|
||||
return uint_to_rgba8(floatBitsToUint(p));
|
||||
}
|
||||
|
||||
#ifdef ps_copy
|
||||
void ps_copy()
|
||||
{
|
||||
@@ -281,6 +286,13 @@ void ps_convert_depth32_depth24()
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_primid_rgba8
|
||||
void ps_convert_primid_rgba8()
|
||||
{
|
||||
OUTPUT = primid_to_rgba8(sample_c(v_tex));
|
||||
}
|
||||
#endif
|
||||
|
||||
#define SAMPLE_RGBA_DEPTH_BILN(CONVERT_FN) \
|
||||
ivec2 dims = textureSize(samp0, 0); \
|
||||
vec2 top_left_f = v_tex * vec2(dims) - 0.5f; \
|
||||
@@ -628,23 +640,23 @@ void ps_yuv()
|
||||
|
||||
void main()
|
||||
{
|
||||
o_col0 = vec4(0x7FFFFFFF);
|
||||
o_col0 = vec4(PRIMID_MAX);
|
||||
|
||||
#ifdef ps_primid_image_init_0
|
||||
if((127.5f / 255.0f) < sample_c(v_tex).a) // < 0x80 pass (== 0x80 should not pass)
|
||||
o_col0 = vec4(-1);
|
||||
o_col0 = vec4(PRIMID_MIN);
|
||||
#endif
|
||||
#ifdef ps_primid_image_init_1
|
||||
if(sample_c(v_tex).a < (127.5f / 255.0f)) // >= 0x80 pass
|
||||
o_col0 = vec4(-1);
|
||||
o_col0 = vec4(PRIMID_MIN);
|
||||
#endif
|
||||
#ifdef ps_primid_image_init_2
|
||||
if((254.5f / 255.0f) < sample_c(v_tex).a) // < 0x80 pass (== 0x80 should not pass)
|
||||
o_col0 = vec4(-1);
|
||||
o_col0 = vec4(PRIMID_MIN);
|
||||
#endif
|
||||
#ifdef ps_primid_image_init_3
|
||||
if(sample_c(v_tex).a < (254.5f / 255.0f)) // >= 0x80 pass
|
||||
o_col0 = vec4(-1);
|
||||
o_col0 = vec4(PRIMID_MIN);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1448,11 +1448,11 @@ vec4 ps_color()
|
||||
void ps_fbmask(inout vec4 C)
|
||||
{
|
||||
#if PS_FBMASK
|
||||
#if PS_COLCLIP_HW == 1
|
||||
vec4 RT = trunc(sample_from_rt() * 65535.0f);
|
||||
#else
|
||||
vec4 RT = trunc(sample_from_rt() * 255.0f + 0.1f);
|
||||
#endif
|
||||
float multi_rgb = PS_COLCLIP_HW != 0 ? 65535.0f : 255.0f;
|
||||
float multi_a = PS_RTA_CORRECTION != 0 ? 128.0f : 255.0f;
|
||||
vec4 RT = sample_from_rt();
|
||||
RT.rgb = trunc(RT.rgb * multi_rgb + 0.1f);
|
||||
RT.a = round(RT.a * multi_a);
|
||||
C = vec4((uvec4(C) & ~FbMask) | (uvec4(RT) & FbMask));
|
||||
#endif
|
||||
}
|
||||
@@ -1966,8 +1966,6 @@ void main()
|
||||
|
||||
// Writing back color (result already written to o_col0 for non-ROV)
|
||||
#if PS_RETURN_COLOR_ROV
|
||||
o_col0 = mix(o_col0, sample_from_rt(), equal(FbMask, uvec4(0xFFu))); // channel masking
|
||||
|
||||
if (!rov_discard_color)
|
||||
imageStore(RtImageRov, ivec2(gl_FragCoord.xy), o_col0);
|
||||
#endif
|
||||
|
||||
@@ -104,7 +104,7 @@ disable_compiler_warnings_for_target(speex)
|
||||
|
||||
# Find the Qt components that we need.
|
||||
if(ENABLE_QT_UI)
|
||||
find_package(Qt6 6.10.1 COMPONENTS CoreTools Core GuiTools Gui WidgetsTools Widgets LinguistTools REQUIRED)
|
||||
find_package(Qt6 6.10 COMPONENTS CoreTools Core GuiTools Gui WidgetsTools Widgets LinguistTools REQUIRED)
|
||||
|
||||
if(NOT WIN32 AND NOT APPLE)
|
||||
if (Qt6_VERSION VERSION_GREATER_EQUAL 6.10.0)
|
||||
|
||||
+3
-110
@@ -62,7 +62,6 @@ namespace GSRunner
|
||||
static bool InitializeConfig();
|
||||
static void SettingsOverride();
|
||||
static bool ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& params);
|
||||
static void DumpStats();
|
||||
|
||||
static bool CreatePlatformWindow();
|
||||
static void DestroyPlatformWindow();
|
||||
@@ -80,43 +79,11 @@ static std::string s_output_prefix;
|
||||
static s32 s_loop_count = 1;
|
||||
static std::optional<bool> s_use_window;
|
||||
static bool s_no_console = false;
|
||||
static bool s_perf_enable = false;
|
||||
|
||||
// Owned by the GS thread.
|
||||
static u32 s_dump_frame_number = 0;
|
||||
static u32 s_loop_number = s_loop_count;
|
||||
static double s_last_internal_draws = 0;
|
||||
static double s_last_draws = 0;
|
||||
static double s_last_render_passes = 0;
|
||||
static double s_last_barriers = 0;
|
||||
static double s_last_copies = 0;
|
||||
static double s_last_uploads = 0;
|
||||
static double s_last_readbacks = 0;
|
||||
static double s_last_depth_copies_rov = 0;
|
||||
static double s_last_draws_rov = 0;
|
||||
static double s_last_barriers_rov = 0;
|
||||
static u64 s_total_internal_draws = 0;
|
||||
static u64 s_total_draws = 0;
|
||||
static u64 s_total_render_passes = 0;
|
||||
static u64 s_total_barriers = 0;
|
||||
static u64 s_total_copies = 0;
|
||||
static u64 s_total_uploads = 0;
|
||||
static u64 s_total_readbacks = 0;
|
||||
static u64 s_total_copies_rov = 0;
|
||||
static u64 s_total_draws_rov = 0;
|
||||
static u64 s_total_barriers_rov = 0;
|
||||
static u32 s_total_frames = 0;
|
||||
static u32 s_total_drawn_frames = 0;
|
||||
|
||||
static bool s_perf_enable = false;
|
||||
static float s_perf_updates = 0.0f;
|
||||
static float s_perf_sum_fps = 0.0f;
|
||||
static float s_perf_sum_internal_fps = 0.0f;
|
||||
static float s_perf_sum_cpu_thread_usage = 0.0f;
|
||||
static float s_perf_sum_cpu_thread_time = 0.0f;
|
||||
static float s_perf_sum_gs_thread_usage = 0.0f;
|
||||
static float s_perf_sum_gs_thread_time = 0.0f;
|
||||
static float s_perf_sum_gpu_time = 0.0f;
|
||||
static float s_perf_sum_gpu_usage = 0.0f;
|
||||
|
||||
bool GSRunner::InitializeConfig()
|
||||
{
|
||||
@@ -278,39 +245,6 @@ void Host::BeginPresentFrame()
|
||||
std::string dump_path(fmt::format("{}_frame{:05}.png", s_output_prefix, s_dump_frame_number));
|
||||
GSQueueSnapshot(dump_path);
|
||||
}
|
||||
|
||||
if (GSIsHardwareRenderer())
|
||||
{
|
||||
const u32 last_draws = s_total_internal_draws;
|
||||
const u32 last_uploads = s_total_uploads;
|
||||
|
||||
static constexpr auto update_stat = [](GSPerfMon::counter_t counter, u64& dst, double& last) {
|
||||
// perfmon resets every 30 frames to zero
|
||||
const double val = g_perfmon.GetCounter(counter);
|
||||
dst += static_cast<u64>((val < last) ? val : (val - last));
|
||||
last = val;
|
||||
};
|
||||
|
||||
update_stat(GSPerfMon::Draw, s_total_internal_draws, s_last_internal_draws);
|
||||
update_stat(GSPerfMon::DrawCalls, s_total_draws, s_last_draws);
|
||||
update_stat(GSPerfMon::RenderPasses, s_total_render_passes, s_last_render_passes);
|
||||
update_stat(GSPerfMon::Barriers, s_total_barriers, s_last_barriers);
|
||||
update_stat(GSPerfMon::TextureCopies, s_total_copies, s_last_copies);
|
||||
update_stat(GSPerfMon::TextureUploads, s_total_uploads, s_last_uploads);
|
||||
update_stat(GSPerfMon::Readbacks, s_total_readbacks, s_last_readbacks);
|
||||
update_stat(GSPerfMon::TextureCopiesROV, s_total_copies_rov, s_last_depth_copies_rov);
|
||||
update_stat(GSPerfMon::DrawCallsROV, s_total_draws_rov, s_last_draws_rov);
|
||||
update_stat(GSPerfMon::BarriersROV, s_total_barriers_rov, s_last_barriers_rov);
|
||||
|
||||
const bool idle_frame = s_total_frames && (last_draws == s_total_internal_draws && last_uploads == s_total_uploads);
|
||||
|
||||
if (!idle_frame)
|
||||
s_total_drawn_frames++;
|
||||
|
||||
s_total_frames++;
|
||||
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
}
|
||||
}
|
||||
|
||||
void Host::RequestResizeHostDisplay(s32 width, s32 height)
|
||||
@@ -344,18 +278,6 @@ void Host::OnGameChanged(const std::string& title, const std::string& elf_overri
|
||||
|
||||
void Host::OnPerformanceMetricsUpdated()
|
||||
{
|
||||
if (s_perf_enable)
|
||||
{
|
||||
s_perf_updates += 1.0f;
|
||||
s_perf_sum_fps += PerformanceMetrics::GetFPS();
|
||||
s_perf_sum_internal_fps += PerformanceMetrics::GetInternalFPS();
|
||||
s_perf_sum_cpu_thread_usage += PerformanceMetrics::GetCPUThreadUsage();
|
||||
s_perf_sum_cpu_thread_time += PerformanceMetrics::GetCPUThreadAverageTime();
|
||||
s_perf_sum_gs_thread_usage += PerformanceMetrics::GetGSThreadUsage();
|
||||
s_perf_sum_gs_thread_time += PerformanceMetrics::GetGSThreadAverageTime();
|
||||
s_perf_sum_gpu_time += PerformanceMetrics::GetGPUAverageTime();
|
||||
s_perf_sum_gpu_usage += PerformanceMetrics::GetGPUUsage();
|
||||
}
|
||||
}
|
||||
|
||||
void Host::OnSaveStateLoading(const std::string_view filename)
|
||||
@@ -655,6 +577,7 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
|
||||
{
|
||||
s_loop_count = StringUtil::FromChars<s32>(argv[++i]).value_or(0);
|
||||
Console.WriteLn("Looping dump playback %d times.", s_loop_count);
|
||||
s_settings_interface.SetIntValue("EmuCore/GS", "DumpReplayLoopCount", s_loop_count);
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG_PARAM("-renderer"))
|
||||
@@ -907,34 +830,6 @@ void GSRunner::SettingsOverride()
|
||||
}
|
||||
}
|
||||
|
||||
void GSRunner::DumpStats()
|
||||
{
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
Console.WriteLn(fmt::format("======= HW STATISTICS FOR {} ({}) FRAMES ========", s_total_frames, s_total_drawn_frames));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Draw Calls: {} (avg {})", s_total_draws, static_cast<u64>(std::ceil(s_total_draws / static_cast<double>(s_total_drawn_frames)))));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Render Passes: {} (avg {})", s_total_render_passes, static_cast<u64>(std::ceil(s_total_render_passes / static_cast<double>(s_total_drawn_frames)))));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Barriers: {} (avg {})", s_total_barriers, static_cast<u64>(std::ceil(s_total_barriers / static_cast<double>(s_total_drawn_frames)))));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Copies: {} (avg {})", s_total_copies, static_cast<u64>(std::ceil(s_total_copies / static_cast<double>(s_total_drawn_frames)))));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Uploads: {} (avg {})", s_total_uploads, static_cast<u64>(std::ceil(s_total_uploads / static_cast<double>(s_total_drawn_frames)))));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Readbacks: {} (avg {})", s_total_readbacks, static_cast<u64>(std::ceil(s_total_readbacks / static_cast<double>(s_total_drawn_frames)))));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Copies (ROV): {} (avg {})", s_total_copies_rov, static_cast<u64>(std::ceil(s_total_copies_rov / static_cast<double>(s_total_drawn_frames)))));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Draws Calls (ROV): {} (avg {})", s_total_draws_rov, static_cast<u64>(std::ceil(s_total_draws_rov / static_cast<double>(s_total_drawn_frames)))));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Barriers (ROV): {} (avg {})", s_total_barriers_rov, static_cast<u64>(std::ceil(s_total_barriers_rov / static_cast<double>(s_total_drawn_frames)))));
|
||||
if (s_perf_enable)
|
||||
{
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Minimum Frame Time: {:.3f} ms ({:.3f} FPS)", PerformanceMetrics::GetMinimumFrameTime(), 1000.0f / PerformanceMetrics::GetMinimumFrameTime()));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Average Frame Time: {:.3f} ms ({:.3f} FPS)", PerformanceMetrics::GetAverageFrameTime(), 1000.0f / PerformanceMetrics::GetAverageFrameTime()));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Maximum Frame Time: {:.3f} ms ({:.3f} FPS)", PerformanceMetrics::GetMaximumFrameTime(), 1000.0f / PerformanceMetrics::GetMaximumFrameTime()));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ CPU Thread Usage: {:.3f} %", s_perf_sum_cpu_thread_usage / s_perf_updates));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ GS Thread Usage: {:.3f} %", s_perf_sum_gs_thread_usage / s_perf_updates));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ GPU Usage: {:.3f} %", s_perf_sum_gpu_usage / s_perf_updates));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Average CPU Thread Time: {:.3f} ms", s_perf_sum_cpu_thread_time / s_perf_updates));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Average GS Thread Time: {:.3f} ms", s_perf_sum_gs_thread_time / s_perf_updates));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Average GPU Time: {:.3f} ms", s_perf_sum_gpu_time / s_perf_updates));
|
||||
}
|
||||
Console.WriteLn("============================================");
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// We can't handle unicode in filenames if we don't use wmain on Win32.
|
||||
#define main real_main
|
||||
@@ -948,12 +843,11 @@ static void CPUThreadMain(VMBootParameters* params, std::atomic<int>* ret)
|
||||
{
|
||||
// apply new settings (e.g. pick up renderer change)
|
||||
VMManager::ApplySettings();
|
||||
GSDumpReplayer::SetIsDumpRunner(true);
|
||||
GSDumpReplayer::SetIsDumpRunner(true, s_perf_enable);
|
||||
|
||||
if (VMManager::Initialize(*params) == VMBootResult::StartupSuccess)
|
||||
{
|
||||
// run until end
|
||||
GSDumpReplayer::SetLoopCount(s_loop_count);
|
||||
VMManager::SetState(VMState::Running);
|
||||
if (s_perf_enable)
|
||||
{
|
||||
@@ -963,7 +857,6 @@ static void CPUThreadMain(VMBootParameters* params, std::atomic<int>* ret)
|
||||
while (VMManager::GetState() == VMState::Running)
|
||||
VMManager::Execute();
|
||||
VMManager::Shutdown(false);
|
||||
GSRunner::DumpStats();
|
||||
ret->store(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<widget class="QGroupBox" name="groupBoxDrawDumping">
|
||||
<property name="title">
|
||||
<string>Draw Dumping</string>
|
||||
</property>
|
||||
@@ -240,6 +240,118 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBoxDumpReplay">
|
||||
<property name="title">
|
||||
<string>Dump Replay Options</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayoutDumpReplay">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="gridLayoutDumpReplay">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="replayUseFrameRange">
|
||||
<property name="text">
|
||||
<string>Use Frame Range</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelDumpReplay1">
|
||||
<property name="text">
|
||||
<string>Replay Frame Start:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>replayFrameStart</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="replayFrameStart">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>99999999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelDumpReplay2">
|
||||
<property name="text">
|
||||
<string>Replay Frame End:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>replayFrameEnd</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="replayFrameEnd">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>99999999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="labelDumpReplay3">
|
||||
<property name="text">
|
||||
<string>Replay Loop Count:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>replayLoopCount</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="replayLoopCount">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>99999999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBoxPerfMetrics">
|
||||
<property name="title">
|
||||
<string>Performance Metrics Options</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayoutPerfMetrics">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelPerfMetrics1">
|
||||
<property name="text">
|
||||
<string>Saved Metrics Capture Time:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>savedMetricsCaptureSeconds</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="savedMetricsCaptureSeconds">
|
||||
<property name="suffix">
|
||||
<string> seconds</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>99999999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
|
||||
@@ -159,6 +159,16 @@ DebugSettingsWidget::DebugSettingsWidget(SettingsWindow* settings_dialog, QWidge
|
||||
tr("Destination directory for dumps generated by the hardware renderer."));
|
||||
dialog()->registerWidgetHelp(m_gs.swDumpDirectory, tr("Software Dump Directory"), tr("Default"),
|
||||
tr("Destination directory for dumps generated by the software renderer."));
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_gs.replayUseFrameRange, "EmuCore/GS", "DumpReplayUseFrameRange", false);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_gs.replayFrameStart, "EmuCore/GS", "DumpReplayFrameStart", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_gs.replayFrameEnd, "EmuCore/GS", "DumpReplayFrameEnd", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_gs.replayLoopCount, "EmuCore/GS", "DumpReplayLoopCount", 0);
|
||||
|
||||
connect(m_gs.replayUseFrameRange, &QCheckBox::checkStateChanged, this, &DebugSettingsWidget::onDumpReplayUseFrameRangeChanged);
|
||||
onDumpReplayUseFrameRangeChanged();
|
||||
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_gs.savedMetricsCaptureSeconds, "EmuCore/GS", "SavedMetricsCaptureSeconds", 10);
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -268,6 +278,13 @@ void DebugSettingsWidget::onDrawDumpingChanged()
|
||||
m_gs.swDumpOpen->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void DebugSettingsWidget::onDumpReplayUseFrameRangeChanged()
|
||||
{
|
||||
const bool enabled = dialog()->getEffectiveBoolValue("EmuCore/GS", "DumpReplayUseFrameRange", false);
|
||||
m_gs.replayFrameStart->setEnabled(enabled);
|
||||
m_gs.replayFrameEnd->setEnabled(enabled);
|
||||
}
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
void DebugSettingsWidget::onLoggingEnableChanged()
|
||||
{
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
|
||||
private Q_SLOTS:
|
||||
void onDrawDumpingChanged();
|
||||
void onDumpReplayUseFrameRangeChanged();
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
void onLoggingEnableChanged();
|
||||
#endif
|
||||
|
||||
@@ -33,6 +33,7 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsWindow* settings_dialog
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.syncToHostRefreshRate, "EmuCore/GS", "SyncToHostRefreshRate", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.useVSyncForTiming, "EmuCore/GS", "UseVSyncForTiming", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.skipPresentingDuplicateFrames, "EmuCore/GS", "SkipDuplicateFrames", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.advancedFrameDisplay, "EmuCore/GS", "AdvancedFrameDisplay", false);
|
||||
connect(m_ui.optimalFramePacing, &QCheckBox::checkStateChanged, this, &EmulationSettingsWidget::onOptimalFramePacingChanged);
|
||||
connect(m_ui.vsync, &QCheckBox::checkStateChanged, this, &EmulationSettingsWidget::updateUseVSyncForTimingEnabled);
|
||||
connect(m_ui.syncToHostRefreshRate, &QCheckBox::checkStateChanged, this, &EmulationSettingsWidget::updateUseVSyncForTimingEnabled);
|
||||
@@ -155,6 +156,11 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsWindow* settings_dialog
|
||||
"rendered, it just means the GPU has more time to complete it (this is NOT frame skipping). Can smooth out frame time "
|
||||
"fluctuations when the CPU/GPU are near maximum utilization, but makes frame pacing more inconsistent and can increase "
|
||||
"input lag. Helps when using frame generation on 25/30fps games."));
|
||||
dialog()->registerWidgetHelp(m_ui.advancedFrameDisplay, tr("Advanced Frame Display"), tr("Unchecked"),
|
||||
tr("Displays the newest frame immediately at the beginning of the "
|
||||
"frame raster time, instead of at the end. Can reduce perceived "
|
||||
"input lag, but may cause problems with some games, such as "
|
||||
"Soulcalibur II and Baldur's Gate Dark Alliance II."));
|
||||
dialog()->registerWidgetHelp(m_ui.manuallySetRealTimeClock, tr("Manually Set Real-Time Clock"), tr("Unchecked"),
|
||||
tr("Manually set a real-time clock to use for the virtual PlayStation 2 instead of using your OS' system clock."));
|
||||
dialog()->registerWidgetHelp(m_ui.rtcDateTime, tr("Real-Time Clock"), tr("Current date and time"),
|
||||
|
||||
@@ -263,6 +263,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="advancedFrameDisplay">
|
||||
<property name="text">
|
||||
<string>Advanced Frame Display</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
@@ -271,6 +271,13 @@
|
||||
</item>
|
||||
<item row="7" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="hwFixesLayout">
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="rewriteLargeSTCoords">
|
||||
<property name="text">
|
||||
<string>Rewrite Large ST</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="drawBuffering">
|
||||
<property name="text">
|
||||
@@ -389,6 +396,7 @@
|
||||
<tabstop>disableRenderFixes</tabstop>
|
||||
<tabstop>readTCOnClose</tabstop>
|
||||
<tabstop>estimateTextureRegion</tabstop>
|
||||
<tabstop>rewriteLargeSTCoords</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
||||
@@ -155,6 +155,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_fixes.readTCOnClose, "EmuCore/GS", "UserHacks_ReadTCOnClose", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_fixes.estimateTextureRegion, "EmuCore/GS", "UserHacks_EstimateTextureRegion", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_fixes.drawBuffering, "EmuCore/GS", "UserHacks_DrawBuffering", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_fixes.rewriteLargeSTCoords, "EmuCore/GS", "UserHacks_RewriteLargeSTCoords", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_fixes.gpuPaletteConversion, "EmuCore/GS", "paltex", false);
|
||||
connect(m_fixes.cpuSpriteRenderBW, &QComboBox::currentIndexChanged, this,
|
||||
&GraphicsSettingsWidget::onCPUSpriteRenderBWChanged);
|
||||
@@ -636,6 +637,9 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
|
||||
|
||||
dialog()->registerWidgetHelp(m_fixes.drawBuffering, tr("Draw Buffering"), tr("Unchecked"),
|
||||
tr("Attempts to reduce draw calls in games which do heavy context switching for blending purposes."));
|
||||
|
||||
dialog()->registerWidgetHelp(m_fixes.rewriteLargeSTCoords, tr("Rewrite Large ST"), tr("Unchecked"),
|
||||
tr("Rewrite large ST coordinates and clamp the values (mainly for Ridge Racer V and Destruction Derby Arena)."));
|
||||
}
|
||||
|
||||
// Upscaling Fixes tab
|
||||
|
||||
+2039
-1924
File diff suppressed because it is too large
Load Diff
+7
-4
@@ -468,7 +468,7 @@ u32 cdvdGetElfCRC(const std::string& path)
|
||||
return elfo.GetCRC();
|
||||
}
|
||||
|
||||
static CDVDDiscType GetPS2ElfName(IsoReader& isor, std::string* name, std::string* version, Error* error)
|
||||
static CDVDDiscType GetPS2ElfName(IsoReader& isor, std::string* name, std::string* version, std::string* vmode, Error* error)
|
||||
{
|
||||
CDVDDiscType retype = CDVDDiscType::Other;
|
||||
name->clear();
|
||||
@@ -510,6 +510,7 @@ static CDVDDiscType GetPS2ElfName(IsoReader& isor, std::string* name, std::strin
|
||||
else if (key == "VMODE")
|
||||
{
|
||||
DevCon.WriteLn(Color_Blue, fmt::format("(SYSTEM.CNF) Disc region type = {}", value));
|
||||
*vmode = value;
|
||||
}
|
||||
else if (key == "VER")
|
||||
{
|
||||
@@ -574,15 +575,15 @@ static std::string ExecutablePathToSerial(const std::string& path)
|
||||
return serial;
|
||||
}
|
||||
|
||||
void cdvdGetDiscInfo(std::string* out_serial, std::string* out_elf_path, std::string* out_version, u32* out_crc,
|
||||
void cdvdGetDiscInfo(std::string* out_serial, std::string* out_elf_path, std::string* out_version, std::string* out_region, u32* out_crc,
|
||||
CDVDDiscType* out_disc_type)
|
||||
{
|
||||
Error error;
|
||||
IsoReader isor;
|
||||
|
||||
std::string elfpath, version;
|
||||
std::string elfpath, version, vmode;
|
||||
CDVDDiscType disc_type = CDVDDiscType::Other;
|
||||
if (!isor.Open(&error) || (disc_type = GetPS2ElfName(isor, &elfpath, &version, &error)) == CDVDDiscType::Other)
|
||||
if (!isor.Open(&error) || (disc_type = GetPS2ElfName(isor, &elfpath, &version, &vmode, &error)) == CDVDDiscType::Other)
|
||||
Console.Error(fmt::format("Failed to get ELF name: {}", error.GetDescription()));
|
||||
|
||||
// Don't bother parsing it if we don't need the CRC.
|
||||
@@ -616,6 +617,8 @@ void cdvdGetDiscInfo(std::string* out_serial, std::string* out_elf_path, std::st
|
||||
*out_version = std::move(version);
|
||||
if (out_disc_type)
|
||||
*out_disc_type = disc_type;
|
||||
if (out_region)
|
||||
*out_region = vmode;
|
||||
}
|
||||
|
||||
void cdvdReadKey(u8, u16, u32 arg2, u8* key)
|
||||
|
||||
+1
-1
@@ -179,7 +179,7 @@ extern void cdvdNewDiskCB();
|
||||
extern u8 cdvdRead(u8 key);
|
||||
extern void cdvdWrite(u8 key, u8 rt);
|
||||
|
||||
extern void cdvdGetDiscInfo(std::string* out_serial, std::string* out_elf_path, std::string* out_version, u32* out_crc,
|
||||
extern void cdvdGetDiscInfo(std::string* out_serial, std::string* out_elf_path, std::string* out_version, std::string* out_region, u32* out_crc,
|
||||
CDVDDiscType* out_disc_type);
|
||||
extern u32 cdvdGetElfCRC(const std::string& path);
|
||||
extern bool cdvdLoadElf(ElfObject* elfo, const std::string_view elfpath, bool isPSXElf, Error* error);
|
||||
|
||||
@@ -1263,7 +1263,7 @@ function(setup_main_executable target)
|
||||
if("${file}" MATCHES "^\\.") # Don't copy macOS garbage (mainly Finder's .DS_Store files) into application
|
||||
continue()
|
||||
endif()
|
||||
if (NOT WIN32 AND "${path}" MATCHES "/dx11/") # Don't include unneccessary stuff
|
||||
if (NOT WIN32 AND "${path}" MATCHES "/dx11/") # Don't include unnecessary stuff
|
||||
continue()
|
||||
endif()
|
||||
if (NOT BUNDLE_EMOJI_FONT AND "${path}" MATCHES "fonts/Twemoji")
|
||||
|
||||
@@ -766,6 +766,7 @@ struct Pcsx2Config
|
||||
DisableFramebufferFetch : 1,
|
||||
DisableVertexShaderExpand : 1,
|
||||
SkipDuplicateFrames : 1,
|
||||
AdvancedFrameDisplay : 1,
|
||||
OsdShowSpeed : 1,
|
||||
OsdShowFPS : 1,
|
||||
OsdShowVPS : 1,
|
||||
@@ -811,6 +812,7 @@ struct Pcsx2Config
|
||||
UserHacks_NativePaletteDraw : 1,
|
||||
UserHacks_EstimateTextureRegion : 1,
|
||||
UserHacks_DrawBuffering : 1,
|
||||
UserHacks_RewriteLargeSTCoords : 1,
|
||||
FXAA : 1,
|
||||
ShadeBoost : 1,
|
||||
DumpGSData : 1,
|
||||
@@ -824,6 +826,7 @@ struct Pcsx2Config
|
||||
SaveDrawStats : 1,
|
||||
SaveFrameStats : 1,
|
||||
SaveHWConfig : 1,
|
||||
DumpReplayUseFrameRange : 1,
|
||||
DumpReplaceableTextures : 1,
|
||||
DumpReplaceableMipmaps : 1,
|
||||
DumpTexturesWithFMVActive : 1,
|
||||
@@ -912,6 +915,10 @@ struct Pcsx2Config
|
||||
int SaveFrameStart = 0;
|
||||
int SaveFrameCount = -1;
|
||||
int SaveFrameBy = 1;
|
||||
int DumpReplayLoopCount = 0;
|
||||
int DumpReplayFrameStart = 0;
|
||||
int DumpReplayFrameEnd = 0;
|
||||
u32 SavedMetricsCaptureSeconds = 10;
|
||||
|
||||
s8 ExclusiveFullscreenControl = -1;
|
||||
GSScreenshotSize ScreenshotSize = GSScreenshotSize::WindowResolution;
|
||||
|
||||
+17
-6
@@ -215,7 +215,7 @@ static void vSyncInfoCalc(vSyncTimingInfo* info, double framesPerSecond, u32 sca
|
||||
// Dynasty Warriors 3 Xtreme Legends - fake save corruption when loading save
|
||||
// Jak II - random speedups
|
||||
// Shadow of Rome - FMV audio issues
|
||||
const bool ntsc_hblank = gsVideoMode != GS_VideoMode::PAL && gsVideoMode != GS_VideoMode::DVD_PAL;
|
||||
const bool ntsc_hblank = gsVideoMode != GS_VideoMode::PAL && gsVideoMode != GS_VideoMode::DVD_PAL && (gsVideoMode != GS_VideoMode::Uninitialized || framesPerSecond != (Pcsx2Config::GSOptions::DEFAULT_FRAME_RATE_PAL / 2));
|
||||
const u64 HalfFrame = Frame / 2;
|
||||
const float extra_scanlines = static_cast<float>(IsProgressiveVideoMode()) * (ntsc_hblank ? 0.5f : 1.5f);
|
||||
const u64 Blank = Scanline * ((ntsc_hblank ? 22.5f : 24.5f) + extra_scanlines);
|
||||
@@ -307,10 +307,12 @@ double GetVerticalFrequency()
|
||||
// https://web.archive.org/web/20120629231826fw_/http://ntsc-tv.com/index.html
|
||||
// https://web.archive.org/web/20200831051302/https://www.hdretrovision.com/240p/
|
||||
|
||||
std::string cur_region = VMManager::Internal::GetCurrentRegion();
|
||||
|
||||
switch (gsVideoMode)
|
||||
{
|
||||
case GS_VideoMode::Uninitialized: // SetGsCrt hasn't executed yet, give some temporary values.
|
||||
return 60.00;
|
||||
return (cur_region == "PAL") ? Pcsx2Config::GSOptions::DEFAULT_FRAME_RATE_PAL : Pcsx2Config::GSOptions::DEFAULT_FRAME_RATE_NTSC;
|
||||
case GS_VideoMode::PAL:
|
||||
case GS_VideoMode::DVD_PAL:
|
||||
return (IsProgressiveVideoMode() == false) ? EmuConfig.GS.FrameratePAL : EmuConfig.GS.FrameratePAL - 0.24f;
|
||||
@@ -352,9 +354,9 @@ void UpdateVSyncRate(bool force)
|
||||
{
|
||||
case GS_VideoMode::Uninitialized: // SYSCALL instruction hasn't executed yet, give some temporary values.
|
||||
if (gsIsInterlaced)
|
||||
total_scanlines = SCANLINES_TOTAL_NTSC_I;
|
||||
total_scanlines = (vertical_frequency == Pcsx2Config::GSOptions::DEFAULT_FRAME_RATE_PAL) ? SCANLINES_TOTAL_PAL_I : SCANLINES_TOTAL_NTSC_I;
|
||||
else
|
||||
total_scanlines = SCANLINES_TOTAL_NTSC_NI;
|
||||
total_scanlines = (vertical_frequency == Pcsx2Config::GSOptions::DEFAULT_FRAME_RATE_PAL) ? SCANLINES_TOTAL_PAL_NI : SCANLINES_TOTAL_NTSC_NI;
|
||||
break;
|
||||
case GS_VideoMode::PAL:
|
||||
case GS_VideoMode::DVD_PAL:
|
||||
@@ -492,9 +494,12 @@ static __fi void VSyncStart(u64 sCycle)
|
||||
|
||||
// Don't bother throttling if we're going to pause.
|
||||
if (!VMManager::Internal::IsExecutionInterrupted())
|
||||
VMManager::Internal::Throttle();
|
||||
VMManager::Internal::Throttle(true);
|
||||
|
||||
gsPostVsyncStart(); // MUST be after framelimit; doing so before causes funk with frame times!
|
||||
if (!EmuConfig.GS.AdvancedFrameDisplay)
|
||||
{
|
||||
gsPostVsyncStart(); // MUST be after framelimit; doing so before causes funk with frame times!
|
||||
}
|
||||
|
||||
// Poll input after MTGS frame push, just in case it has to stall to catch up.
|
||||
VMManager::Internal::PollInputOnCPUThread();
|
||||
@@ -564,6 +569,12 @@ static __fi void GSVSync()
|
||||
static __fi void VSyncEnd(u64 sCycle)
|
||||
{
|
||||
EECNT_LOG(" ================ EE COUNTER VSYNC END (frame: %d) ================", g_FrameCount);
|
||||
VMManager::Internal::Throttle(false);
|
||||
|
||||
if (EmuConfig.GS.AdvancedFrameDisplay)
|
||||
{
|
||||
gsPostVsyncStart();
|
||||
}
|
||||
|
||||
g_FrameCount++;
|
||||
if (!GSSMODE1reg.SINT)
|
||||
|
||||
@@ -174,7 +174,8 @@ The clamp modes are also numerically based.
|
||||
* cpuSpriteRenderBW [Value between `0` to `10`] {Disabled, 1 (64), 2 (128), 3 (192), 4 (256), 5 (320), 6 (384), 7 (448), 8 (512), 9 (576), 10 (640)} Default: Off (`0`)
|
||||
* cpuSpriteRenderLevel [`0` or `1` or `2`] {Sprites only, Sprites/Triangles, Blended Sprites/Triangles} Default: Off unless cpuSpriteRenderBW has value other than Off then it is 'Sprites only' (`0`)
|
||||
* estimateTextureRegion [`0` or `1`] {Off, On} Default: Off (`0`)
|
||||
* drawBuffering [`0` or `1`] {Off, On} Default: Off (`0`)
|
||||
* drawBuffering [`0` or `1`] {Off, On} Default: Off (`0`)
|
||||
* rewriteLargeSTCoords [`0` or `1`] {Off, On} Default: Off (`0`)
|
||||
* getSkipCount {`GSC` with suffix } {None unless specific game GSC} Default: Disabled (`0`) unless valid variable name (ex. GSC_PolyphonyDigitalGames, GSC_UrbanReign, ...)
|
||||
* gpuPaletteConversion [`0` or `1`] {Off, On} Default: Off (`0`)
|
||||
* gpuTargetCLUT [`0` or `1` or `2`] {Disabled, Enabled (Exact Match), Enabled (Check Inside Target)} Default: Disabled (`0`)
|
||||
|
||||
@@ -204,7 +204,12 @@
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
},
|
||||
"drawBuffering": {
|
||||
"drawBuffering": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
},
|
||||
"rewriteLargeSTCoords": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "GS/GSPerfMon.h"
|
||||
#include "GS/GSUtil.h"
|
||||
#include "GS/MultiISA.h"
|
||||
#include "GS/GSPerfMon.h"
|
||||
#include "Host.h"
|
||||
#include "Input/InputManager.h"
|
||||
#include "MTGS.h"
|
||||
@@ -491,6 +492,23 @@ void GSStopGSDump()
|
||||
g_gs_renderer->StopGSDump();
|
||||
}
|
||||
|
||||
void GSStartSavingMetrics(u32 seconds)
|
||||
{
|
||||
if (g_gs_renderer)
|
||||
g_gs_renderer->StartSavingMetrics(seconds);
|
||||
}
|
||||
|
||||
void GSDumpSavedMetrics()
|
||||
{
|
||||
if (g_gs_renderer)
|
||||
g_gs_renderer->DumpSavedMetrics();
|
||||
}
|
||||
|
||||
bool GSIsSavingMetrics()
|
||||
{
|
||||
return g_gs_renderer && g_gs_renderer->IsSavingMetrics();
|
||||
}
|
||||
|
||||
bool GSBeginCapture(std::string filename)
|
||||
{
|
||||
if (g_gs_renderer)
|
||||
@@ -565,6 +583,11 @@ void GSSetVSyncMode(GSVSyncMode mode, bool allow_present_throttle)
|
||||
g_gs_device->SetVSyncMode(mode, allow_present_throttle);
|
||||
}
|
||||
|
||||
void GSResetStats()
|
||||
{
|
||||
g_perfmon.Reset();
|
||||
}
|
||||
|
||||
bool GSWantsExclusiveFullscreen()
|
||||
{
|
||||
if (!g_gs_device || !g_gs_device->SupportsExclusiveFullscreen())
|
||||
@@ -1226,6 +1249,24 @@ BEGIN_HOTKEY_LIST(g_gs_hotkeys){"Screenshot", TRANSLATE_NOOP("Hotkeys", "Graphic
|
||||
GSStopGSDump();
|
||||
});
|
||||
}},
|
||||
{"GSStartSavingMetricsVariableFrames", TRANSLATE_NOOP("Hotkeys", "Graphics"),
|
||||
TRANSLATE_NOOP("Hotkeys", "Start Saving Performance Metrics (Press & Hold)"),
|
||||
[](s32 pressed) {
|
||||
MTGS::RunOnGSThread([pressed]() {
|
||||
if (pressed > 0)
|
||||
GSStartSavingMetrics(UINT32_MAX);
|
||||
else
|
||||
GSDumpSavedMetrics();
|
||||
});
|
||||
}},
|
||||
{"GSStartSavingMetricsFixedFrames", TRANSLATE_NOOP("Hotkeys", "Graphics"),
|
||||
TRANSLATE_NOOP("Hotkeys", "Start Saving Performance Metrics (Capture Timer)"),
|
||||
[](s32 pressed) {
|
||||
MTGS::RunOnGSThread([pressed]() {
|
||||
if (pressed > 0 && !GSIsSavingMetrics())
|
||||
GSStartSavingMetrics(GSConfig.SavedMetricsCaptureSeconds);
|
||||
});
|
||||
}},
|
||||
{"ToggleSoftwareRendering", TRANSLATE_NOOP("Hotkeys", "Graphics"),
|
||||
TRANSLATE_NOOP("Hotkeys", "Toggle Software Rendering"),
|
||||
[](s32 pressed) {
|
||||
|
||||
@@ -76,6 +76,9 @@ std::string GSGetBaseSnapshotFilename();
|
||||
std::string GSGetBaseVideoFilename();
|
||||
void GSQueueSnapshot(const std::string& path, u32 gsdump_frames = 0);
|
||||
void GSStopGSDump();
|
||||
void GSStartSavingMetrics(float time);
|
||||
void GSDumpSavedMetrics();
|
||||
bool GSIsSavingMetrics();
|
||||
bool GSBeginCapture(std::string filename);
|
||||
void GSEndCapture();
|
||||
void GSPresentCurrentFrame();
|
||||
@@ -86,6 +89,7 @@ bool GSHasDisplayWindow();
|
||||
void GSResizeDisplayWindow(u32 width, u32 height, float scale);
|
||||
void GSUpdateDisplayWindow();
|
||||
void GSSetVSyncMode(GSVSyncMode mode, bool allow_present_throttle);
|
||||
void GSResetStats();
|
||||
|
||||
GSRendererType GSGetCurrentRenderer();
|
||||
bool GSIsHardwareRenderer();
|
||||
|
||||
+159
-2
@@ -105,7 +105,6 @@ GSState::GSState()
|
||||
s_n = 0;
|
||||
s_transfer_n = 0;
|
||||
|
||||
|
||||
memset(&m_v, 0, sizeof(m_v));
|
||||
memset(m_mem.m_vm8, 0, m_mem.m_vmsize);
|
||||
|
||||
@@ -2504,6 +2503,11 @@ u32 GSState::CalcMask(int exp, int max_exp)
|
||||
return (1 << std::min(amount, 23)) - 1;
|
||||
}
|
||||
|
||||
void GSState::IncDraw()
|
||||
{
|
||||
s_n++;
|
||||
}
|
||||
|
||||
void GSState::FlushPrim()
|
||||
{
|
||||
if (m_index->tail > 0)
|
||||
@@ -2526,7 +2530,7 @@ void GSState::FlushPrim()
|
||||
GSVertex buff[2];
|
||||
GSVertexBuff& vtx_buff = *m_vertex;
|
||||
GSIndexBuff& idx_buff = *m_index;
|
||||
s_n++;
|
||||
IncDraw();
|
||||
|
||||
const u32 head = vtx_buff.head;
|
||||
const u32 tail = vtx_buff.tail;
|
||||
@@ -6838,6 +6842,159 @@ GIFRegTEX0 GSState::GetTex0Layer(u32 lod)
|
||||
return TEX0;
|
||||
}
|
||||
|
||||
// Fix large ST coorindates that may cause graphical glitches.
|
||||
template <u32 primclass>
|
||||
void GSState::RewriteVerticesIfLargeSTImpl(const GSVector4& large_val, bool check_clamp_mode)
|
||||
{
|
||||
// Need to be texture mapping with ST and not have so many vertices that rewritten indices will overflow.
|
||||
if (PRIM->TME && PRIM->FST == 0)
|
||||
{
|
||||
const float tw = static_cast<float>(1 << m_context->TEX0.TW);
|
||||
const float th = static_cast<float>(1 << m_context->TEX0.TH);
|
||||
const GSVector4 tsize = GSVector4(tw, th, 1.0f, 1.0f);
|
||||
|
||||
// Only rewrite big/small S or T when the clamping mode is CLAMP or REGION_CLAMP (if requested).
|
||||
const GIFRegCLAMP& clamp = m_context->CLAMP;
|
||||
const GSVector4 clamp_mask =
|
||||
check_clamp_mode ?
|
||||
GSVector4::cast(GSVector4i(
|
||||
(clamp.WMS == CLAMP_CLAMP || clamp.WMS == CLAMP_REGION_CLAMP) ? 0xFFFFFFFF : 0,
|
||||
(clamp.WMT == CLAMP_CLAMP || clamp.WMT == CLAMP_REGION_CLAMP) ? 0xFFFFFFFF : 0,
|
||||
0,
|
||||
0)) :
|
||||
GSVector4::cast(GSVector4i::cxpr(0xFFFFFFFF));
|
||||
|
||||
const GSVector4 tex_bbox = m_vt.m_min.t.xyxy(m_vt.m_max.t) / tsize.xyxy();
|
||||
const bool large_st = ((tex_bbox.abs() >= large_val) & clamp_mask).mask() || m_vt.nan.value;
|
||||
|
||||
if (large_st)
|
||||
{
|
||||
GL_PUSH("Large ST detected, rewriting vertices.");
|
||||
if (m_index->tail > UINT16_MAX)
|
||||
{
|
||||
GL_INS("Too many vertices to rewrite safely, exiting.");
|
||||
DevCon.Warning("Large ST detected but too many vertices to rewrite safely.");
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr int n = GSUtil::GetClassVertexCount(primclass);
|
||||
|
||||
// Make sure the copy buffer is large enough.
|
||||
while (m_max_vertex_count < m_index->tail)
|
||||
GrowVertexBuffer();
|
||||
|
||||
GSVertex* RESTRICT vertex = m_vertex->buff;
|
||||
GSVertex* RESTRICT vertex_copy = m_vertex->buff_copy;
|
||||
u16* RESTRICT index = m_index->buff;
|
||||
const int count = static_cast<int>(m_index->tail);
|
||||
|
||||
for (int i = 0; i < count; i += n)
|
||||
{
|
||||
GSVector4 stcq[n];
|
||||
|
||||
// Load STQ for this primitive.
|
||||
for (int j = 0; j < n; j++)
|
||||
stcq[j] = GSVector4::cast(GSVector4i(vertex[index[i + j]].m[0]));
|
||||
|
||||
// Perform Q division and see which values need to be rewritten.
|
||||
GSVector4 uv[n];
|
||||
GSVector4 small{}, big{}, nan{};
|
||||
for (int j = 0; j < n; j++)
|
||||
{
|
||||
// For sprites always use Q of second vertex.
|
||||
const GSVector4 q = primclass == GS_SPRITE_CLASS ? stcq[1].wwww() : stcq[j].wwww();
|
||||
uv[j] = (stcq[j] / q).xyzw(GSVector4::zero());
|
||||
small |= (uv[j] <= -large_val);
|
||||
big |= (uv[j] >= large_val);
|
||||
nan |= (uv[j] != uv[j]);
|
||||
}
|
||||
|
||||
// Get the new values for fields that will be rewritten.
|
||||
// The follows rules are used:
|
||||
// 1. If there are small values but not big or nans, make all vertices small.
|
||||
// 2. If there are big values but not small or nans, make all vertices big.
|
||||
// 3. If there are both big and small values, or nans, make all vertices zero.
|
||||
GSVector4 uv_new = GSVector4::zero();
|
||||
uv_new = uv_new.blend32(-large_val, small);
|
||||
uv_new = uv_new.blend32(large_val, big);
|
||||
uv_new = uv_new.blend32(GSVector4::zero(), (small & big) | nan);
|
||||
|
||||
const GSVector4 rewrite = (((small | big) & clamp_mask) | nan).xyxy(GSVector4::zero());
|
||||
|
||||
// If both S and T are rewritten, no point in keeping Q. Just set it to 1.0f;
|
||||
if ((rewrite.mask() & 3) == 3)
|
||||
{
|
||||
for (int j = 0; j < n; j++)
|
||||
stcq[j] = stcq[j].template insert32<0, 3>(GSVector4::m_one);
|
||||
}
|
||||
|
||||
// Rewrite the fields that require it and write to the copy buffer.
|
||||
for (int j = 0; j < n; j++)
|
||||
{
|
||||
// For sprites always use Q of second vertex.
|
||||
const GSVector4 q = (primclass == GS_SPRITE_CLASS) ? stcq[1].wwww() : stcq[j].wwww();
|
||||
stcq[j] = stcq[j].blend32(uv_new * q, rewrite);
|
||||
|
||||
vertex_copy[i + j].m[0] = GSVector4i::cast(stcq[j]);
|
||||
vertex_copy[i + j].m[1] = vertex[index[i + j]].m[1];
|
||||
index[i + j] = i + j;
|
||||
}
|
||||
}
|
||||
|
||||
// Swap the buffers and fix the counts.
|
||||
std::swap(m_vertex->buff, m_vertex->buff_copy);
|
||||
m_vertex->head = m_vertex->next = m_vertex->tail = m_index->tail;
|
||||
|
||||
// Recalculate ST min/max/eq in the vertex trace.
|
||||
GSVector4 tmin = GSVector4::cxpr(FLT_MAX);
|
||||
GSVector4 tmax = GSVector4::cxpr(-FLT_MAX);
|
||||
for (int i = 0; i < count; i += n)
|
||||
{
|
||||
for (int j = 0; j < n; j++)
|
||||
{
|
||||
GSVector4 stcq = GSVector4::cast(GSVector4i(m_vertex->buff[i + j].m[0]));
|
||||
const float q = (primclass == GS_SPRITE_CLASS) ? m_vertex->buff[i + 1].RGBAQ.Q : stcq.w;
|
||||
stcq = (stcq / q).xyzw(stcq);
|
||||
|
||||
tmin = tmin.min(stcq);
|
||||
tmax = tmax.max(stcq);
|
||||
}
|
||||
}
|
||||
m_vt.m_min.t = tmin.xyww() * tsize;
|
||||
m_vt.m_max.t = tmax.xyww() * tsize;
|
||||
m_vt.m_eq.stq = (m_vt.m_min.t == m_vt.m_max.t).mask();
|
||||
|
||||
// Dump vertices if needed.
|
||||
if (GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()) && GSConfig.SaveInfo)
|
||||
{
|
||||
DumpVertices(GetDrawDumpPath("%05d_vertices_st_rewrite.txt", s_n));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSState::RewriteVerticesIfLargeST(const GSVector4& large_val, bool check_clamp_mode)
|
||||
{
|
||||
switch (m_vt.m_primclass)
|
||||
{
|
||||
case GS_POINT_CLASS:
|
||||
RewriteVerticesIfLargeSTImpl<GS_POINT_CLASS>(large_val, check_clamp_mode);
|
||||
break;
|
||||
case GS_LINE_CLASS:
|
||||
RewriteVerticesIfLargeSTImpl<GS_LINE_CLASS>(large_val, check_clamp_mode);
|
||||
break;
|
||||
case GS_SPRITE_CLASS:
|
||||
RewriteVerticesIfLargeSTImpl<GS_SPRITE_CLASS>(large_val, check_clamp_mode);
|
||||
break;
|
||||
case GS_TRIANGLE_CLASS:
|
||||
RewriteVerticesIfLargeSTImpl<GS_TRIANGLE_CLASS>(large_val, check_clamp_mode);
|
||||
break;
|
||||
default:
|
||||
pxFail("Invalid primclass"); // Impossible
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// GSTransferBuffer
|
||||
|
||||
GSState::GSTransferBuffer::GSTransferBuffer()
|
||||
|
||||
+8
-3
@@ -318,9 +318,11 @@ public:
|
||||
static u64 s_last_transfer_draw_n;
|
||||
static u64 s_transfer_n;
|
||||
|
||||
GSPerfMon m_perfmon_frame; // Track stat across a frame.
|
||||
GSPerfMon m_perfmon_draw; // Track stat across a draw.
|
||||
|
||||
GSPerfMon m_perfmon_frame; // Track stats across a frame.
|
||||
GSPerfMon m_perfmon_draw; // Track stats across a draw.
|
||||
|
||||
void IncDraw();
|
||||
|
||||
static constexpr u32 STATE_VERSION = 9;
|
||||
|
||||
#define PRIM_REG_MASK 0x7FF
|
||||
@@ -541,6 +543,9 @@ public:
|
||||
bool SpriteDrawWithoutGaps();
|
||||
void CalculatePrimitiveCoversWithoutGaps();
|
||||
GIFRegTEX0 GetTex0Layer(u32 lod);
|
||||
template <u32 primclass>
|
||||
void RewriteVerticesIfLargeSTImpl(const GSVector4& large_val, bool check_clamp_mode);
|
||||
void RewriteVerticesIfLargeST(const GSVector4& large_val, bool check_clamp_mode);
|
||||
};
|
||||
|
||||
// We put this in the header because of Multi-ISA.
|
||||
|
||||
@@ -49,6 +49,7 @@ const char* ShaderEntryPoint(ShaderConvert value)
|
||||
case ShaderConvert::RGB5A1_TO_DEPTH16: return "ps_convert_rgb5a1_depth16";
|
||||
case ShaderConvert::DEPTH32_TO_DEPTH24: return "ps_convert_depth32_depth24";
|
||||
case ShaderConvert::DEPTH_COPY: return "ps_depth_copy";
|
||||
case ShaderConvert::PRIMID_TO_RGBA8: return "ps_convert_primid_rgba8";
|
||||
case ShaderConvert::DOWNSAMPLE_COPY: return "ps_downsample_copy";
|
||||
case ShaderConvert::RGBA_TO_8I: return "ps_convert_rgba_8i";
|
||||
case ShaderConvert::RGB5A1_TO_8I: return "ps_convert_rgb5a1_8i";
|
||||
@@ -109,6 +110,7 @@ const char* ShaderConvertName(ShaderConvert shader)
|
||||
ENTRY(RGBA8_TO_DEPTH16);
|
||||
ENTRY(RGB5A1_TO_DEPTH16);
|
||||
ENTRY(DEPTH32_TO_DEPTH24);
|
||||
ENTRY(PRIMID_TO_RGBA8);
|
||||
ENTRY(DOWNSAMPLE_COPY);
|
||||
ENTRY(RGBA_TO_8I);
|
||||
ENTRY(RGB5A1_TO_8I);
|
||||
|
||||
@@ -59,6 +59,7 @@ enum class ShaderConvert
|
||||
RGBA8_TO_DEPTH16,
|
||||
RGB5A1_TO_DEPTH16,
|
||||
DEPTH32_TO_DEPTH24,
|
||||
PRIMID_TO_RGBA8,
|
||||
DOWNSAMPLE_COPY,
|
||||
RGBA_TO_8I,
|
||||
RGB5A1_TO_8I,
|
||||
@@ -122,6 +123,7 @@ static inline constexpr bool HasColorOutput(ShaderConvert shader)
|
||||
case ShaderConvert::DEPTH32_TO_RGBA8:
|
||||
case ShaderConvert::DEPTH32_TO_RGB8:
|
||||
case ShaderConvert::DEPTH16_TO_RGB5A1:
|
||||
case ShaderConvert::PRIMID_TO_RGBA8:
|
||||
case ShaderConvert::DOWNSAMPLE_COPY:
|
||||
case ShaderConvert::RGBA_TO_8I:
|
||||
case ShaderConvert::RGB5A1_TO_8I:
|
||||
@@ -162,6 +164,7 @@ static inline constexpr bool HasFloat32Input(ShaderConvert shader)
|
||||
case ShaderConvert::DEPTH32_TO_RGB8:
|
||||
case ShaderConvert::DEPTH16_TO_RGB5A1:
|
||||
case ShaderConvert::DEPTH32_TO_DEPTH24:
|
||||
case ShaderConvert::PRIMID_TO_RGBA8:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -462,7 +465,7 @@ static inline ShaderConvertSelector GetConvertShader(GSTexture::Format src, GSTe
|
||||
switch (dst)
|
||||
{
|
||||
case GSTexture::Format::Color:
|
||||
pxAssert(src_bpp == 32 && dst_bpp == 32);
|
||||
pxAssert(src_bpp == dst_bpp);
|
||||
shader = ShaderConvert::COPY; // bpp is handled by mask
|
||||
break;
|
||||
case GSTexture::Format::DepthColor:
|
||||
@@ -533,6 +536,10 @@ static inline ShaderConvertSelector GetConvertShader(GSTexture::Format src, GSTe
|
||||
pxAssert(false);
|
||||
}
|
||||
break;
|
||||
case GSTexture::Format::PrimID:
|
||||
pxAssert(dst == GSTexture::Format::Color);
|
||||
shader = ShaderConvert::PRIMID_TO_RGBA8;
|
||||
break;
|
||||
default:
|
||||
pxAssert(false);
|
||||
break;
|
||||
|
||||
@@ -150,7 +150,7 @@ bool GSRenderer::Merge(int field)
|
||||
}
|
||||
}
|
||||
|
||||
s_n++;
|
||||
IncDraw();
|
||||
|
||||
GSVector4 src_gs_read[2] = {};
|
||||
GSVector4 dst[3] = {};
|
||||
@@ -524,6 +524,9 @@ bool GSRenderer::BeginPresentFrame(bool frame_skip)
|
||||
{
|
||||
Host::BeginPresentFrame();
|
||||
|
||||
if (GSDumpReplayer::IsReplayingDump())
|
||||
GSDumpReplayer::UpdateGSStats();
|
||||
|
||||
const GSDevice::PresentResult res = g_gs_device->BeginPresent(frame_skip);
|
||||
if (res == GSDevice::PresentResult::FrameSkipped)
|
||||
{
|
||||
@@ -805,6 +808,10 @@ void GSRenderer::VSync(u32 field, bool registers_written, bool idle_frame)
|
||||
}
|
||||
}
|
||||
|
||||
// metrics
|
||||
if (m_saving_metrics && !PerformanceMetrics::IsSavingMetrics())
|
||||
DumpSavedMetrics();
|
||||
|
||||
// capture
|
||||
if (GSCapture::IsCapturingVideo())
|
||||
{
|
||||
@@ -953,6 +960,29 @@ void GSRenderer::StopGSDump()
|
||||
m_dump_frames = 0;
|
||||
}
|
||||
|
||||
void GSRenderer::StartSavingMetrics(u32 seconds)
|
||||
{
|
||||
m_saving_metrics = true;
|
||||
PerformanceMetrics::StartSavingMetrics(seconds);
|
||||
Host::AddKeyedOSDMessage("GSMetrics",
|
||||
fmt::format(TRANSLATE_FS("GS", "Started saving performance metrics{}"),
|
||||
(0 < seconds && seconds < UINT32_MAX) ? fmt::format(" ({} seconds)", seconds) : ""),
|
||||
Host::OSD_INFO_DURATION);
|
||||
}
|
||||
|
||||
void GSRenderer::DumpSavedMetrics()
|
||||
{
|
||||
m_saving_metrics = false;
|
||||
PerformanceMetrics::DumpSavedMetrics();
|
||||
Host::AddKeyedOSDMessage("GSMetrics", fmt::format(TRANSLATE_FS("GS", "Logging saved performance metrics")),
|
||||
Host::OSD_INFO_DURATION);
|
||||
}
|
||||
|
||||
bool GSRenderer::IsSavingMetrics()
|
||||
{
|
||||
return m_saving_metrics;
|
||||
}
|
||||
|
||||
void GSRenderer::PresentCurrentFrame()
|
||||
{
|
||||
if (BeginPresentFrame(false))
|
||||
|
||||
@@ -19,6 +19,7 @@ private:
|
||||
std::string m_snapshot;
|
||||
u32 m_dump_frames = 0;
|
||||
u32 m_skipped_duplicate_frames = 0;
|
||||
bool m_saving_metrics = false;
|
||||
|
||||
// Tracking draw counters for idle frame detection.
|
||||
u64 m_last_draw_n = 0;
|
||||
@@ -56,6 +57,9 @@ public:
|
||||
|
||||
void QueueSnapshot(const std::string& path, const u32 gsdump_frames);
|
||||
void StopGSDump();
|
||||
void StartSavingMetrics(u32 seconds);
|
||||
void DumpSavedMetrics();
|
||||
bool IsSavingMetrics();
|
||||
void PresentCurrentFrame();
|
||||
bool BeginCapture(std::string filename, const GSVector2i& size = GSVector2i(0, 0));
|
||||
void EndCapture();
|
||||
|
||||
@@ -63,4 +63,15 @@ enum class PS_ROV_DEPTH : uint32_t
|
||||
READ_ONLY = 2,
|
||||
};
|
||||
|
||||
#if defined(__METAL_VERSION__)
|
||||
#define CONSTANT constant
|
||||
#else
|
||||
#define CONSTANT
|
||||
#endif
|
||||
|
||||
static constexpr CONSTANT int PRIMID_MAX = (1 << 24) - 1;
|
||||
static constexpr CONSTANT int PRIMID_MIN = -1;
|
||||
|
||||
#undef CONSTANT
|
||||
|
||||
} // namespace GSShader
|
||||
|
||||
@@ -44,7 +44,7 @@ bool GSTexture::Save(const std::string& fn)
|
||||
{
|
||||
// Depth textures need special treatment - we have a stencil component.
|
||||
// Just re-use the existing conversion shader instead.
|
||||
if (m_format == Format::DepthStencil || m_format == Format::DepthColor)
|
||||
if (m_format == Format::DepthStencil || m_format == Format::DepthColor || m_format == Format::PrimID)
|
||||
{
|
||||
GSTexture* temp = g_gs_device->CreateRenderTarget(GetWidth(), GetHeight(), Format::Color, false);
|
||||
if (!temp)
|
||||
|
||||
@@ -249,6 +249,8 @@ bool GSDevice11::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
|
||||
ShaderMacro sm_ps;
|
||||
sm_ps.AddMacro("PIXEL_SHADER", 1);
|
||||
sm_ps.AddMacro("PRIMID_MAX", GSShader::PRIMID_MAX);
|
||||
sm_ps.AddMacro("PRIMID_MIN", GSShader::PRIMID_MIN);
|
||||
sm_ps.AddMacro("HAS_BILN", static_cast<int>(shader.Biln()));
|
||||
sm_ps.AddMacro("HAS_STENCIL_OUTPUT", static_cast<int>(shader.StencilOutput()));
|
||||
sm_ps.AddMacro("HAS_INTEGER_OUTPUT", static_cast<int>(shader.IntegerOutputBpp() != 0));
|
||||
@@ -582,6 +584,8 @@ bool GSDevice11::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
const std::string entry_point_macro = WrapEntryPointMacro(entry_point);
|
||||
ShaderMacro sm_ps;
|
||||
sm_ps.AddMacro("PIXEL_SHADER", 1);
|
||||
sm_ps.AddMacro("PRIMID_MAX", GSShader::PRIMID_MAX);
|
||||
sm_ps.AddMacro("PRIMID_MIN", GSShader::PRIMID_MIN);
|
||||
sm_ps.AddMacro(entry_point_macro.c_str(), 1);
|
||||
m_date.primid_init_ps[i] = m_shader_cache.GetPixelShader(m_dev.get(), *convert_hlsl, sm_ps.GetPtr(), entry_point.c_str());
|
||||
if (!m_date.primid_init_ps[i])
|
||||
|
||||
@@ -289,16 +289,12 @@ bool GSDevice12::CreateDevice(u32& vendor_id)
|
||||
|
||||
// Create the actual device.
|
||||
// Intel Haswell DX12 support is specific:
|
||||
// Newerest drivers have dx12 support disabled so the last driver to support dx12 is 15.40.42.5063.
|
||||
// Newer drivers have dx12 support disabled so the last driver to support dx12 is 15.40.42.5063.
|
||||
// Shader cache must be also disabled, and make sure Debug Device option is disabled as well.
|
||||
// Let's enable it on dev/debug for testing purposes so we don't have to change this all the time.
|
||||
// Let's enable it for testing purposes so we don't have to change this all the time, and
|
||||
// might be handy for the tweakers that want to run dx12.
|
||||
// TODO: Find out the status of Broadwell.
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
hr = D3D12CreateDevice(m_adapter.get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device));
|
||||
#else
|
||||
const bool isIntel = (vendor_id == 0x163C || vendor_id == 0x8086 || vendor_id == 0x8087);
|
||||
hr = D3D12CreateDevice(m_adapter.get(), isIntel ? D3D_FEATURE_LEVEL_12_0 : D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device));
|
||||
#endif
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
@@ -488,36 +484,8 @@ void GSDevice12::MoveToNextCommandList()
|
||||
if (res.sampler_allocator.ShouldReset())
|
||||
res.sampler_allocator.Reset();
|
||||
|
||||
if (res.has_timestamp_query)
|
||||
{
|
||||
// readback timestamp from the last time this cmdlist was used.
|
||||
// we don't need to worry about disjoint in dx12, the frequency is reliable within a single cmdlist.
|
||||
const u32 offset = (m_current_command_list * (sizeof(u64) * NUM_TIMESTAMP_QUERIES_PER_CMDLIST));
|
||||
const D3D12_RANGE read_range = {offset, offset + (sizeof(u64) * NUM_TIMESTAMP_QUERIES_PER_CMDLIST)};
|
||||
void* map;
|
||||
HRESULT hr = m_timestamp_query_buffer->Map(0, &read_range, &map);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
u64 timestamps[2];
|
||||
std::memcpy(timestamps, static_cast<const u8*>(map) + offset, sizeof(timestamps));
|
||||
m_accumulated_gpu_time +=
|
||||
static_cast<float>(static_cast<double>(timestamps[1] - timestamps[0]) / m_timestamp_frequency);
|
||||
|
||||
const D3D12_RANGE write_range = {};
|
||||
m_timestamp_query_buffer->Unmap(0, &write_range);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Warning("D3D12: Map() for timestamp query failed: %08X", hr);
|
||||
}
|
||||
}
|
||||
|
||||
res.has_timestamp_query = m_gpu_timing_enabled;
|
||||
if (m_gpu_timing_enabled)
|
||||
{
|
||||
res.command_lists[1].list4->EndQuery(m_timestamp_query_heap.get(), D3D12_QUERY_TYPE_TIMESTAMP,
|
||||
m_current_command_list * NUM_TIMESTAMP_QUERIES_PER_CMDLIST);
|
||||
}
|
||||
ReadGPUTiming();
|
||||
StartGPUTiming();
|
||||
|
||||
if (res.pipeline_statistics_query == QueryState::Ready)
|
||||
{
|
||||
@@ -587,15 +555,7 @@ bool GSDevice12::ExecuteCommandList(WaitType wait_for_completion)
|
||||
m_vertex_constant_buffer.FlushMemory();
|
||||
m_pixel_constant_buffer.FlushMemory();
|
||||
|
||||
if (res.has_timestamp_query)
|
||||
{
|
||||
// write the timestamp back at the end of the cmdlist
|
||||
res.command_lists[1].list4->EndQuery(m_timestamp_query_heap.get(), D3D12_QUERY_TYPE_TIMESTAMP,
|
||||
(m_current_command_list * NUM_TIMESTAMP_QUERIES_PER_CMDLIST) + 1);
|
||||
res.command_lists[1].list4->ResolveQueryData(m_timestamp_query_heap.get(), D3D12_QUERY_TYPE_TIMESTAMP,
|
||||
m_current_command_list * NUM_TIMESTAMP_QUERIES_PER_CMDLIST, NUM_TIMESTAMP_QUERIES_PER_CMDLIST,
|
||||
m_timestamp_query_buffer.get(), m_current_command_list * (sizeof(u64) * NUM_TIMESTAMP_QUERIES_PER_CMDLIST));
|
||||
}
|
||||
EndGPUTiming();
|
||||
|
||||
if ((res.pipeline_statistics_query == QueryState::Querying) || (res.pipeline_statistics_query == QueryState::Ready))
|
||||
{
|
||||
@@ -857,6 +817,64 @@ bool GSDevice12::SetGPUPipelineStatisticsEnabled(bool enabled)
|
||||
return true;
|
||||
}
|
||||
|
||||
void GSDevice12::StartGPUTiming()
|
||||
{
|
||||
if (m_gpu_timing_enabled)
|
||||
{
|
||||
CommandListResources& res = m_command_lists[m_current_command_list];
|
||||
res.command_lists[1].list4->EndQuery(m_timestamp_query_heap.get(), D3D12_QUERY_TYPE_TIMESTAMP,
|
||||
m_current_command_list * NUM_TIMESTAMP_QUERIES_PER_CMDLIST);
|
||||
res.timestamp_query_state = QueryState::Querying;
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice12::EndGPUTiming()
|
||||
{
|
||||
CommandListResources& res = m_command_lists[m_current_command_list];
|
||||
if (res.timestamp_query_state == QueryState::Querying)
|
||||
{
|
||||
// write the timestamp back at the end of the cmdlist
|
||||
if (InRenderPass())
|
||||
EndRenderPass(); // Can't end query in a render pass
|
||||
res.command_lists[1].list4->EndQuery(m_timestamp_query_heap.get(), D3D12_QUERY_TYPE_TIMESTAMP,
|
||||
(m_current_command_list * NUM_TIMESTAMP_QUERIES_PER_CMDLIST) + 1);
|
||||
res.command_lists[1].list4->ResolveQueryData(m_timestamp_query_heap.get(), D3D12_QUERY_TYPE_TIMESTAMP,
|
||||
m_current_command_list * NUM_TIMESTAMP_QUERIES_PER_CMDLIST, NUM_TIMESTAMP_QUERIES_PER_CMDLIST,
|
||||
m_timestamp_query_buffer.get(), m_current_command_list * (sizeof(u64) * NUM_TIMESTAMP_QUERIES_PER_CMDLIST));
|
||||
res.timestamp_query_state = QueryState::Ready;
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice12::ReadGPUTiming()
|
||||
{
|
||||
CommandListResources& res = m_command_lists[m_current_command_list];
|
||||
if (res.timestamp_query_state == QueryState::Ready)
|
||||
{
|
||||
// readback timestamp from the last time this cmdlist was used.
|
||||
// we don't need to worry about disjoint in dx12, the frequency is reliable within a single cmdlist.
|
||||
const u32 offset = (m_current_command_list * (sizeof(u64) * NUM_TIMESTAMP_QUERIES_PER_CMDLIST));
|
||||
const D3D12_RANGE read_range = { offset, offset + (sizeof(u64) * NUM_TIMESTAMP_QUERIES_PER_CMDLIST) };
|
||||
void* map;
|
||||
HRESULT hr = m_timestamp_query_buffer->Map(0, &read_range, &map);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
u64 timestamps[2];
|
||||
std::memcpy(timestamps, static_cast<const u8*>(map) + offset, sizeof(timestamps));
|
||||
m_accumulated_gpu_time +=
|
||||
static_cast<float>(static_cast<double>(timestamps[1] - timestamps[0]) / m_timestamp_frequency);
|
||||
|
||||
const D3D12_RANGE write_range = {};
|
||||
m_timestamp_query_buffer->Unmap(0, &write_range);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Warning("D3D12: Map() for timestamp query failed: %08X", hr);
|
||||
}
|
||||
|
||||
res.timestamp_query_state = QueryState::None;
|
||||
}
|
||||
}
|
||||
|
||||
bool GSDevice12::AllocatePreinitializedGPUBuffer(u32 size, ID3D12Resource** gpu_buffer,
|
||||
D3D12MA::Allocation** gpu_allocation, const std::function<void(void*)>& fill_callback)
|
||||
{
|
||||
@@ -2877,6 +2895,8 @@ bool GSDevice12::CompileConvertPipelines()
|
||||
|
||||
ShaderMacro sm;
|
||||
sm.AddMacro("PIXEL_SHADER", 1);
|
||||
sm.AddMacro("PRIMID_MAX", GSShader::PRIMID_MAX);
|
||||
sm.AddMacro("PRIMID_MIN", GSShader::PRIMID_MIN);
|
||||
sm.AddMacro("HAS_BILN", static_cast<int>(shader.Biln()));
|
||||
sm.AddMacro("HAS_STENCIL_OUTPUT", static_cast<int>(shader.StencilOutput()));
|
||||
sm.AddMacro("HAS_INTEGER_OUTPUT", static_cast<int>(shader.IntegerOutputBpp() != 0));
|
||||
@@ -2930,6 +2950,8 @@ bool GSDevice12::CompileConvertPipelines()
|
||||
|
||||
ShaderMacro sm;
|
||||
sm.AddMacro("PIXEL_SHADER", "1");
|
||||
sm.AddMacro("PRIMID_MAX", GSShader::PRIMID_MAX);
|
||||
sm.AddMacro("PRIMID_MIN", GSShader::PRIMID_MIN);
|
||||
sm.AddMacro(entry_point_macro.c_str(), "1");
|
||||
|
||||
ComPtr<ID3DBlob> ps(m_shader_cache.GetPixelShader(*source, sm.GetPtr(), entry_point.c_str()));
|
||||
|
||||
@@ -191,7 +191,6 @@ public:
|
||||
void UploadIndices(D3D12StreamBuffer& buffer, const void* index, size_t count);
|
||||
|
||||
private:
|
||||
// For pipeline statistics
|
||||
enum class QueryState
|
||||
{
|
||||
None,
|
||||
@@ -209,7 +208,7 @@ private:
|
||||
std::vector<std::pair<D3D12DescriptorHeapManager&, u32>> pending_descriptors;
|
||||
u64 ready_fence_value = 0;
|
||||
bool init_command_list_used = false;
|
||||
bool has_timestamp_query = false;
|
||||
QueryState timestamp_query_state = QueryState::None;
|
||||
QueryState pipeline_statistics_query = QueryState::None;
|
||||
};
|
||||
|
||||
@@ -524,6 +523,9 @@ public:
|
||||
void EndPresent() override;
|
||||
|
||||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
void StartGPUTiming();
|
||||
void EndGPUTiming();
|
||||
void ReadGPUTiming();
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
|
||||
bool SetGPUPipelineStatisticsEnabled(bool enabled) override;
|
||||
|
||||
@@ -607,20 +607,6 @@ bool GSHwHack::GSC_TalesOfLegendia(GSRendererHW& r, int& skip)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSHwHack::GSC_UltramanFightingEvolution(GSRendererHW& r, int& skip)
|
||||
{
|
||||
if (skip == 0)
|
||||
{
|
||||
if (!s_nativeres && RTME && RFBP == 0x2a00 && RFPSM == PSMZ24 && RTBP0 == 0x1c00 && RTPSM == PSMZ24)
|
||||
{
|
||||
// Don't enable hack on native res if crc is below aggressive.
|
||||
skip = 5; // blur
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSHwHack::GSC_TalesofSymphonia(GSRendererHW& r, int& skip)
|
||||
{
|
||||
if (skip == 0)
|
||||
@@ -1468,9 +1454,6 @@ const GSHwHack::Entry<GSRendererHW::GSC_Ptr> GSHwHack::s_get_skip_count_function
|
||||
|
||||
// Depth Issue
|
||||
CRC_F(GSC_BurnoutGames),
|
||||
|
||||
// Upscaling hacks
|
||||
CRC_F(GSC_UltramanFightingEvolution),
|
||||
};
|
||||
|
||||
const GSHwHack::Entry<GSRendererHW::OI_Ptr> GSHwHack::s_before_draw_functions[] = {
|
||||
|
||||
@@ -18,7 +18,6 @@ public:
|
||||
static bool GSC_BlackAndBurnoutSky(GSRendererHW& r, int& skip);
|
||||
static bool GSC_MidnightClub3(GSRendererHW& r, int& skip);
|
||||
static bool GSC_TalesOfLegendia(GSRendererHW& r, int& skip);
|
||||
static bool GSC_UltramanFightingEvolution(GSRendererHW& r, int& skip);
|
||||
static bool GSC_TalesofSymphonia(GSRendererHW& r, int& skip);
|
||||
static bool GSC_UrbanReign(GSRendererHW& r, int& skip);
|
||||
static bool GSC_BlueTongueGames(GSRendererHW& r, int& skip);
|
||||
|
||||
@@ -2901,6 +2901,15 @@ void GSRendererHW::Draw()
|
||||
|
||||
// First pass texture shuffle detection using context/vertices.
|
||||
DetectTextureShuffle();
|
||||
|
||||
// Ridge Racer V and Destruction Derby Arena have large ST coordinates in reflection map draws that cause
|
||||
// speckled artifacts on cars. Detect and rewrite such vertices here.
|
||||
if (GSConfig.UserHacks_RewriteLargeSTCoords)
|
||||
{
|
||||
// The threshold is chosen to be low enough to fix the artifacts in Ridge Racer V and Destruction Derby Arena
|
||||
// while not breaking anything.
|
||||
RewriteVerticesIfLargeST(GSVector4::cxpr(16.0f), false);
|
||||
}
|
||||
|
||||
// When the format is 24bit (Z or C), DATE ceases to function.
|
||||
// It was believed that in 24bit mode all pixels pass because alpha doesn't exist
|
||||
@@ -3526,13 +3535,14 @@ void GSRendererHW::Draw()
|
||||
const u32 color_mask = (m_vt.m_max.c > GSVector4i::zero()).mask();
|
||||
const bool texture_function_color = m_cached_ctx.TEX0.TFX == TFX_DECAL || (color_mask & 0xFFF) || (m_cached_ctx.TEX0.TFX > TFX_DECAL && (color_mask & 0xF000));
|
||||
const bool texture_function_alpha = m_cached_ctx.TEX0.TFX != TFX_MODULATE || (color_mask & 0xF000);
|
||||
const bool req_color = (is_possible_channel_shuffle && channel_shuffle_targets != ChannelFetch_ALPHA) || (!is_possible_channel_shuffle && ((texture_function_color && (!PRIM->ABE || GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp < 16 || (NeedsBlending() && IsUsingCsInBlend())) && (possible_shuffle || (m_cached_ctx.FRAME.FBMSK & (fm_mask & 0x00FFFFFF)) != (fm_mask & 0x00FFFFFF))) || need_aem_color));
|
||||
const bool alpha_used = (GSUtil::GetChannelMask(m_context->TEX0.PSM) == 0x8 || (m_context->TEX0.TCC && texture_function_alpha)) && ((NeedsBlending() && IsUsingAsInBlend()) || (m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST > ATST_ALWAYS) || (possible_shuffle || (m_cached_ctx.FRAME.FBMSK & (fm_mask & 0xFF000000)) != (fm_mask & 0xFF000000)));
|
||||
const bool req_alpha = (is_possible_channel_shuffle && channel_shuffle_targets == ChannelFetch_ALPHA) || (!is_possible_channel_shuffle && (GSUtil::GetChannelMask(m_context->TEX0.PSM) & 0x8) && alpha_used);
|
||||
const bool color_used = (is_possible_channel_shuffle && channel_shuffle_targets != ChannelFetch_ALPHA) || (!is_possible_channel_shuffle && ((texture_function_color && (!PRIM->ABE || (NeedsBlending() && IsUsingCsInBlend())) && ((m_cached_ctx.FRAME.FBMSK & (fm_mask & 0x00FFFFFF)) != (fm_mask & 0x00FFFFFF))) || need_aem_color));
|
||||
const bool alpha_used = (is_possible_channel_shuffle && channel_shuffle_targets == ChannelFetch_ALPHA) || (!is_possible_channel_shuffle && (m_context->TEX0.TCC && texture_function_alpha) && ((NeedsBlending() && IsUsingAsInBlend()) || (m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST > ATST_ALWAYS) || (m_cached_ctx.FRAME.FBMSK & (fm_mask & 0xFF000000)) != (fm_mask & 0xFF000000)));
|
||||
const bool req_color = (GSUtil::GetChannelMask(m_context->TEX0.PSM) & 0x7) && color_used;
|
||||
const bool req_alpha = (GSUtil::GetChannelMask(m_context->TEX0.PSM) == 0x8 && (color_used || alpha_used)) || ((GSUtil::GetChannelMask(m_context->TEX0.PSM) & 0x8) && alpha_used);
|
||||
|
||||
// TODO: Be able to send an alpha of 1.0 (blended with vertex alpha maybe?) so we can avoid sending the texture, since we don't always need it.
|
||||
// Example games: Evolution Snowboarding, Final Fantasy Dirge of Cerberus, Red Dead Revolver, Stuntman, Tony Hawk's Underground 2, Ultimate Spider-Man.
|
||||
if (!req_color && !alpha_used)
|
||||
if (!req_color && !req_alpha)
|
||||
{
|
||||
m_process_texture = false;
|
||||
possible_shuffle = false;
|
||||
@@ -7689,26 +7699,17 @@ void GSRendererHW::ConfigureROV(bool color_rov, bool depth_rov)
|
||||
if (color_rov)
|
||||
{
|
||||
// FbMask setup
|
||||
if (m_conf.colormask.wrgba != 0)
|
||||
if (m_conf.colormask.wrgba != 0 && m_conf.colormask.wrgba != 0xF)
|
||||
{
|
||||
if (!m_conf.ps.fbmask)
|
||||
m_conf.cb_ps.FbMask = GSVector4i::zero();
|
||||
const GSVector4i fbmask = GSVector4i(m_conf.colormask.wr ? 0 : 0xFF, m_conf.colormask.wg ? 0 : 0xFF,
|
||||
m_conf.colormask.wb ? 0 : 0xFF, m_conf.colormask.wa ? 0 : 0xFF);
|
||||
if (!m_conf.ps.fbmask)
|
||||
{
|
||||
// Don't enable FB mask emulation, just use the mask for ROV.
|
||||
m_conf.cb_ps.FbMask = fbmask;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_conf.cb_ps.FbMask |= fbmask;
|
||||
}
|
||||
m_conf.ps.fbmask = true;
|
||||
m_conf.cb_ps.FbMask |= fbmask;
|
||||
GL_INS("ROV: FbMask={R=%x, G=%x, B=%x, A=%x}",
|
||||
m_conf.cb_ps.FbMask.r, m_conf.cb_ps.FbMask.g, m_conf.cb_ps.FbMask.b, m_conf.cb_ps.FbMask.a);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_conf.ps.no_color = true;
|
||||
}
|
||||
|
||||
// Blend setup
|
||||
if (m_conf.IsBlending())
|
||||
|
||||
@@ -1735,8 +1735,8 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
match = false;
|
||||
|
||||
// Situations where font has been uploaded to the alpha channel and they use a different buffer width, this can't currently be translated correctly.
|
||||
GSLocalMemory::psm_t req_psm = GSLocalMemory::m_psm[psm];
|
||||
if (!possible_shuffle && req_psm.trbpp <= 8 && req_psm.bpp == 32 && t->m_TEX0.TBW != bw && (bw * 64) != t->m_valid.z && r.w > req_psm.pgs.y)
|
||||
const GSLocalMemory::psm_t req_psm = GSLocalMemory::m_psm[psm];
|
||||
if (!possible_shuffle && req_psm.trbpp <= 8 && req_psm.bpp == 32 && t->m_TEX0.TBW != bw && static_cast<int>(bw * 64) != t->m_valid.z && r.w > req_psm.pgs.y)
|
||||
match = false;
|
||||
|
||||
// Different swizzle, different width, and dirty, so probably not what we want.
|
||||
|
||||
@@ -112,22 +112,22 @@ fragment void ps_datm0(float4 p [[position]], DirectReadTextureIn<float> tex)
|
||||
|
||||
fragment float4 ps_primid_init_datm1(float4 p [[position]], DirectReadTextureIn<float> tex)
|
||||
{
|
||||
return tex.read(p).a < (127.5f / 255.f) ? -1 : FLT_MAX;
|
||||
return tex.read(p).a < (127.5f / 255.f) ? GSShader::PRIMID_MIN : GSShader::PRIMID_MAX;
|
||||
}
|
||||
|
||||
fragment float4 ps_primid_init_datm0(float4 p [[position]], DirectReadTextureIn<float> tex)
|
||||
{
|
||||
return tex.read(p).a > (127.5f / 255.f) ? -1 : FLT_MAX;
|
||||
return tex.read(p).a > (127.5f / 255.f) ? GSShader::PRIMID_MIN : GSShader::PRIMID_MAX;
|
||||
}
|
||||
|
||||
fragment float4 ps_primid_rta_init_datm1(float4 p [[position]], DirectReadTextureIn<float> tex)
|
||||
{
|
||||
return tex.read(p).a < (254.5f / 255.f) ? -1 : FLT_MAX;
|
||||
return tex.read(p).a < (254.5f / 255.f) ? GSShader::PRIMID_MIN : GSShader::PRIMID_MAX;
|
||||
}
|
||||
|
||||
fragment float4 ps_primid_rta_init_datm0(float4 p [[position]], DirectReadTextureIn<float> tex)
|
||||
{
|
||||
return tex.read(p).a > (254.5f / 255.f) ? -1 : FLT_MAX;
|
||||
return tex.read(p).a > (254.5f / 255.f) ? GSShader::PRIMID_MIN : GSShader::PRIMID_MAX;
|
||||
}
|
||||
|
||||
fragment float4 ps_rta_correction(ConvertShaderData data [[stage_in]], ConvertPSRes res)
|
||||
@@ -175,11 +175,6 @@ fragment float4 ps_convert_depth16_rgb5a1(ConvertShaderData data [[stage_in]], C
|
||||
return convert_depth16_rgba8(res.sample(data.t)) / 255.f;
|
||||
}
|
||||
|
||||
fragment float ps_convert_float32_depth_to_color(ConvertShaderData data [[stage_in]], ConvertPSDepthRes res)
|
||||
{
|
||||
return res.sample(data.t);
|
||||
}
|
||||
|
||||
fragment float4 ps_downsample_copy(ConvertShaderData data [[stage_in]],
|
||||
texture2d<float> texture [[texture(GSMTLTextureIndexNonHW)]],
|
||||
constant GSMTLDownsamplePSUniform& uniform [[buffer(GSMTLBufferIndexUniforms)]])
|
||||
@@ -273,6 +268,16 @@ struct ConvertToDepthRes
|
||||
}
|
||||
};
|
||||
|
||||
static float4 primid_to_rgba8(float p)
|
||||
{
|
||||
return float4(as_type<uchar4>(p)) / 255.f;
|
||||
}
|
||||
|
||||
fragment float4 ps_convert_primid_rgba8(ConvertShaderData data [[stage_in]], ConvertPSDepthOrColorRes res)
|
||||
{
|
||||
return primid_to_rgba8(res.sample(data.t));
|
||||
}
|
||||
|
||||
fragment DepthOrColorOut ps_depth_copy(ConvertShaderData data [[stage_in]], ConvertPSDepthOrColorRes res)
|
||||
{
|
||||
return res.sample(data.t);
|
||||
|
||||
@@ -1304,8 +1304,12 @@ struct PSMain
|
||||
{
|
||||
if (PS_FBMASK)
|
||||
{
|
||||
float multi = PS_COLCLIP_HW ? 65535.0 : 255.5;
|
||||
C = float4((uint4(int4(C)) & (cb.fbmask ^ 0xff)) | (uint4(current_color * float4(multi, multi, multi, 255)) & cb.fbmask));
|
||||
float multi_rgb = PS_COLCLIP_HW ? 65535.0 : 255.5;
|
||||
float multi_a = PS_RTA_CORRECTION ? 128.0 : 255.0;
|
||||
float4 RT = current_color;
|
||||
RT.rgb = RT.rgb * multi_rgb;
|
||||
RT.a = round(RT.a * multi_a);
|
||||
C = float4((uint4(int4(C)) & (cb.fbmask ^ 0xff)) | (uint4(RT) & cb.fbmask));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1769,7 +1773,7 @@ fragment MainPSOut ps_main(
|
||||
main.current_depth = ds_tex.read(coord).x;
|
||||
}
|
||||
|
||||
if (NEEDS_RT || (PS_ROV_COLOR && any(cb.fbmask == 0xff)))
|
||||
if (NEEDS_RT)
|
||||
{
|
||||
if (PS_ROV_COLOR)
|
||||
{
|
||||
@@ -1797,8 +1801,6 @@ fragment MainPSOut ps_main(
|
||||
ds_rov.write(out.depth, coord);
|
||||
if (PS_ROV_COLOR && !main.color_discarded)
|
||||
{
|
||||
if (!PS_FBMASK)
|
||||
out.c0 = select(out.c0, main.current_color, cb.fbmask == 0xff);
|
||||
if (ROV_NEEDS_R32)
|
||||
rt_u32.write(pack_float_to_unorm4x8(out.c0), coord);
|
||||
else
|
||||
|
||||
@@ -432,6 +432,8 @@ bool GSDeviceOGL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
const char* name = shader.EntryPoint();
|
||||
|
||||
std::string macro;
|
||||
macro += fmt::format("#define PRIMID_MAX {}\n", GSShader::PRIMID_MAX);
|
||||
macro += fmt::format("#define PRIMID_MIN {}\n", GSShader::PRIMID_MIN);
|
||||
macro += fmt::format("#define HAS_BILN {}\n", static_cast<int>(shader.Biln()));
|
||||
macro += fmt::format("#define HAS_STENCIL_OUTPUT {}\n", static_cast<int>(shader.StencilOutput()));
|
||||
macro += fmt::format("#define HAS_INTEGER_OUTPUT {}\n", static_cast<int>(shader.IntegerOutputBpp() != 0));
|
||||
@@ -609,9 +611,13 @@ bool GSDeviceOGL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
|
||||
for (size_t i = 0; i < std::size(m_date.primid_ps); i++)
|
||||
{
|
||||
std::string macro;
|
||||
macro += fmt::format("#define PRIMID_MAX {}\n", GSShader::PRIMID_MAX);
|
||||
macro += fmt::format("#define PRIMID_MIN {}\n", GSShader::PRIMID_MIN);
|
||||
|
||||
const std::string ps(GetShaderSource(
|
||||
fmt::format("ps_primid_image_init_{}", i),
|
||||
GL_FRAGMENT_SHADER, *convert_glsl));
|
||||
GL_FRAGMENT_SHADER, *convert_glsl, macro));
|
||||
m_shader_cache.GetProgram(&m_date.primid_ps[i], m_convert.vs, ps);
|
||||
m_date.primid_ps[i].SetFormattedName("PrimID Destination Alpha Init %d", i);
|
||||
}
|
||||
|
||||
@@ -287,125 +287,6 @@ void ConvertVertexBuffer(const GSDrawingContext* RESTRICT ctx, GSVertexSW* RESTR
|
||||
}
|
||||
}
|
||||
|
||||
// Fix ST coordinates that would overflow the rasterizer fixed point format by rewriting the vertices.
|
||||
template <u32 primclass>
|
||||
void GSRendererSW::RewriteVerticesIfSTOverflow()
|
||||
{
|
||||
if (PRIM->TME && PRIM->FST == 0)
|
||||
{
|
||||
const GSVector4 tsize = GSVector4(
|
||||
static_cast<float>(1 << m_context->TEX0.TW),
|
||||
static_cast<float>(1 << m_context->TEX0.TH),
|
||||
1.0f,
|
||||
1.0f);
|
||||
|
||||
// SW rasterizer stores UV in 1.15.16 format so clamp to +/- (2^15 - 2) (-2 so bilinear doesn't overflow).
|
||||
// Do the division by texture size here to avoid divisions for each vertex.
|
||||
const GSVector4 OVERFLOW_VAL = GSVector4::cxpr(static_cast<float>((1 << 15) - 2)) / tsize;
|
||||
|
||||
// Only rewrite big/small S or T when the clamping mode is CLAMP or REGION_CLAMP.
|
||||
const GSVector4i clamp_mode = GSVector4i(
|
||||
(m_context->CLAMP.WMS == CLAMP_CLAMP || m_context->CLAMP.WMS == CLAMP_REGION_CLAMP) ? 0xFFFFFFFF : 0,
|
||||
(m_context->CLAMP.WMT == CLAMP_CLAMP || m_context->CLAMP.WMT == CLAMP_REGION_CLAMP) ? 0xFFFFFFFF : 0,
|
||||
0,
|
||||
0);
|
||||
|
||||
const bool st_overflow =
|
||||
((GSVector4i::cast(m_vt.m_min.t <= -OVERFLOW_VAL * tsize) & clamp_mode).mask() & 3) ||
|
||||
((GSVector4i::cast(m_vt.m_max.t >= OVERFLOW_VAL * tsize) & clamp_mode).mask() & 3) ||
|
||||
m_vt.nan.value;
|
||||
|
||||
if (st_overflow)
|
||||
{
|
||||
constexpr int n = GSUtil::GetClassVertexCount(primclass);
|
||||
|
||||
// Make sure the copy buffer is large enough.
|
||||
while (m_max_vertex_count < m_index->tail)
|
||||
GrowVertexBuffer();
|
||||
|
||||
GSVertex* RESTRICT vertex = m_vertex->buff;
|
||||
GSVertex* RESTRICT vertex_copy = m_vertex->buff_copy;
|
||||
u16* RESTRICT index = m_index->buff;
|
||||
|
||||
for (int i = 0; i < static_cast<int>(m_index->tail); i += n)
|
||||
{
|
||||
GSVector4 stcq[n];
|
||||
|
||||
// Load STQ for this primitive.
|
||||
for (int j = 0; j < n; j++)
|
||||
stcq[j] = GSVector4::cast(GSVector4i(vertex[index[i + j]].m[0]));
|
||||
|
||||
// Perform Q division and see which values need to be rewritten.
|
||||
GSVector4 uv[n];
|
||||
GSVector4i small{}, big{}, nan{};
|
||||
for (int j = 0; j < n; j++)
|
||||
{
|
||||
// For sprites always use Q of second vertex.
|
||||
const GSVector4 q = primclass == GS_SPRITE_CLASS ? stcq[1].wwww() : stcq[j].wwww();
|
||||
uv[j] = (stcq[j] / q).xyzw(GSVector4::zero());
|
||||
small |= GSVector4i::cast(uv[j] <= -OVERFLOW_VAL);
|
||||
big |= GSVector4i::cast(uv[j] >= OVERFLOW_VAL);
|
||||
nan |= GSVector4i::cast(uv[j] != uv[j]);
|
||||
}
|
||||
|
||||
// Get the new values for fields that will be rewritten.
|
||||
// The follows rules are used:
|
||||
// 1. If there are small values but not big or nans, make all vertices small.
|
||||
// 2. If there are big values but not small or nans, make all vertices big.
|
||||
// 3. If there are both big and small values, or nans, make all vertices zero.
|
||||
GSVector4 uv_new = GSVector4::zero();
|
||||
uv_new = uv_new.blend32(-OVERFLOW_VAL, GSVector4::cast(small));
|
||||
uv_new = uv_new.blend32(OVERFLOW_VAL, GSVector4::cast(big));
|
||||
uv_new = uv_new.blend32(GSVector4::zero(), GSVector4::cast((small & big) | nan));
|
||||
|
||||
const GSVector4i rewrite = (((small | big) & clamp_mode) | nan).upl64(GSVector4i::zero());
|
||||
|
||||
// If both S and T are rewritten, no point in keeping Q. Just set it to 1.0f;
|
||||
if ((GSVector4::cast(rewrite).mask() & 3) == 3)
|
||||
{
|
||||
for (int j = 0; j < n; j++)
|
||||
stcq[j] = stcq[j].template insert32<0, 3>(GSVector4::m_one);
|
||||
}
|
||||
|
||||
// Rewrite the fields that require it and write to the copy buffer.
|
||||
for (int j = 0; j < n; j++)
|
||||
{
|
||||
// For sprites always use Q of second vertex.
|
||||
const GSVector4 q = (primclass == GS_SPRITE_CLASS) ? stcq[1].wwww() : stcq[j].wwww();
|
||||
stcq[j] = stcq[j].blend32(uv_new * q, GSVector4::cast(rewrite));
|
||||
|
||||
vertex_copy[i + j].m[0] = GSVector4i::cast(stcq[j]);
|
||||
vertex_copy[i + j].m[1] = vertex[index[i + j]].m[1];
|
||||
index[i + j] = i + j;
|
||||
}
|
||||
}
|
||||
|
||||
// Swap the buffers and fix the counts.
|
||||
std::swap(m_vertex->buff, m_vertex->buff_copy);
|
||||
m_vertex->head = m_vertex->next = m_vertex->tail = m_index->tail;
|
||||
|
||||
// Recalculate ST min/max/eq in the vertex trace.
|
||||
GSVector4 tmin = GSVector4::cxpr(FLT_MAX);
|
||||
GSVector4 tmax = GSVector4::cxpr(-FLT_MAX);
|
||||
for (int i = 0; i < static_cast<int>(m_index->tail); i += n)
|
||||
{
|
||||
for (int j = 0; j < n; j++)
|
||||
{
|
||||
GSVector4 stcq = GSVector4::cast(GSVector4i(m_vertex->buff[i + j].m[0]));
|
||||
const float Q = (primclass == GS_SPRITE_CLASS) ? stcq.w : m_vertex->buff[i + 1].RGBAQ.Q;
|
||||
stcq = (stcq / Q).xyzw(stcq);
|
||||
|
||||
tmin = tmin.min(stcq);
|
||||
tmax = tmax.max(stcq);
|
||||
}
|
||||
}
|
||||
m_vt.m_min.t = tmin.xyww() * tsize;
|
||||
m_vt.m_max.t = tmax.xyww() * tsize;
|
||||
m_vt.m_eq.stq = (m_vt.m_min.t == m_vt.m_max.t).mask();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSVertexSWInitStatic()
|
||||
{
|
||||
#define InitCVB4(P, T, F, Q) GSVertexSW::s_cvb[P][T][F][Q] = ConvertVertexBuffer<P, T, F, Q>;
|
||||
@@ -427,24 +308,25 @@ MULTI_ISA_UNSHARED_END
|
||||
void GSRendererSW::Draw()
|
||||
{
|
||||
const GSDrawingContext* context = m_context;
|
||||
|
||||
switch (m_vt.m_primclass)
|
||||
if (!GSConfig.UserHacks_RewriteLargeSTCoords)
|
||||
{
|
||||
case GS_POINT_CLASS:
|
||||
RewriteVerticesIfSTOverflow<GS_POINT_CLASS>();
|
||||
break;
|
||||
case GS_LINE_CLASS:
|
||||
RewriteVerticesIfSTOverflow<GS_LINE_CLASS>();
|
||||
break;
|
||||
case GS_TRIANGLE_CLASS:
|
||||
RewriteVerticesIfSTOverflow<GS_TRIANGLE_CLASS>();
|
||||
break;
|
||||
case GS_SPRITE_CLASS:
|
||||
RewriteVerticesIfSTOverflow<GS_SPRITE_CLASS>();
|
||||
break;
|
||||
default:
|
||||
pxFailRel("Unknown primitive class.");
|
||||
break;
|
||||
// SW rasterizer stores UV in 1.15.16 format so clamp to +/- (2^15 - 2) (-2 so bilinear doesn't overflow).
|
||||
// Also only do this for CLAMP and CLAMP_REGION modes to reduce the performance impact.
|
||||
const GSVector4 tsize = GSVector4(
|
||||
static_cast<float>(1 << m_context->TEX0.TW),
|
||||
static_cast<float>(1 << m_context->TEX0.TH),
|
||||
1.0f,
|
||||
1.0f);
|
||||
|
||||
// Large value is given in terms of normalized ST / Q coordinates.
|
||||
const GSVector4 large_val = GSVector4::cxpr(static_cast<float>((1 << 15) - 2)) / tsize;
|
||||
RewriteVerticesIfLargeST(large_val, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// More sensitive as the rewrite threshold is lower and we do it for all clamp mode.
|
||||
// The performance cost will also be higher.
|
||||
RewriteVerticesIfLargeST(GSVector4::cxpr(16.0f), false);
|
||||
}
|
||||
|
||||
auto data = m_vertex_heap.make_shared<SharedData>().cast<GSRasterizerData>();
|
||||
|
||||
@@ -1153,6 +1153,77 @@ bool GSDeviceVK::SetGPUPipelineStatisticsEnabled(bool enabled)
|
||||
return (enabled == m_gpu_pipeline_statistics_enabled);
|
||||
}
|
||||
|
||||
void GSDeviceVK::StartGPUTiming(u32 index)
|
||||
{
|
||||
if (m_gpu_timing_enabled || m_spin_timer)
|
||||
{
|
||||
FrameResources& resources = m_frame_resources[index];
|
||||
vkCmdResetQueryPool(resources.command_buffers[1], m_timestamp_query_pool, index * 2, 2);
|
||||
vkCmdWriteTimestamp(
|
||||
resources.command_buffers[1], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, m_timestamp_query_pool, index * 2);
|
||||
resources.timestamp_query_state = QueryState::Querying;
|
||||
}
|
||||
}
|
||||
|
||||
void GSDeviceVK::EndGPUTiming(u32 index)
|
||||
{
|
||||
FrameResources& resources = m_frame_resources[index];
|
||||
|
||||
const bool wants_timestamp = m_gpu_timing_enabled || m_spin_timer;
|
||||
|
||||
if (wants_timestamp && resources.timestamp_query_state == QueryState::Querying)
|
||||
{
|
||||
vkCmdWriteTimestamp(m_current_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, m_timestamp_query_pool,
|
||||
m_current_frame * 2 + 1);
|
||||
resources.timestamp_query_state = QueryState::Ready;
|
||||
}
|
||||
}
|
||||
|
||||
void GSDeviceVK::ReadGPUTiming(u32 index)
|
||||
{
|
||||
FrameResources& resources = m_frame_resources[index];
|
||||
|
||||
const bool wants_timestamps = m_gpu_timing_enabled || resources.spin_id >= 0;
|
||||
|
||||
if (wants_timestamps && resources.timestamp_query_state == QueryState::Ready)
|
||||
{
|
||||
std::array<u64, 2> timestamps;
|
||||
const VkResult res =
|
||||
vkGetQueryPoolResults(m_device, m_timestamp_query_pool, index * 2, static_cast<u32>(timestamps.size()),
|
||||
sizeof(u64) * timestamps.size(), timestamps.data(), sizeof(u64), VK_QUERY_RESULT_64_BIT);
|
||||
if (res == VK_SUCCESS)
|
||||
{
|
||||
// if we didn't write the timestamp at the start of the cmdbuffer (just enabled timing), the first TS will be zero
|
||||
if (timestamps[0] > 0 && m_gpu_timing_enabled)
|
||||
{
|
||||
const double ns_diff =
|
||||
(timestamps[1] - timestamps[0]) * static_cast<double>(m_device_properties.limits.timestampPeriod);
|
||||
m_accumulated_gpu_time += ns_diff / 1000000.0;
|
||||
}
|
||||
if (resources.spin_id >= 0)
|
||||
{
|
||||
if (m_optional_extensions.vk_ext_calibrated_timestamps && timestamps[1] > 0)
|
||||
{
|
||||
const u64 end = timestamps[1] * m_spin_timestamp_scale + m_spin_timestamp_offset;
|
||||
m_spin_manager.DrawCompleted(resources.spin_id, resources.submit_timestamp, end);
|
||||
}
|
||||
else if (!m_optional_extensions.vk_ext_calibrated_timestamps && timestamps[0] > 0)
|
||||
{
|
||||
const u64 begin = timestamps[0] * m_spin_timestamp_scale;
|
||||
const u64 end = timestamps[1] * m_spin_timestamp_scale;
|
||||
m_spin_manager.DrawCompleted(resources.spin_id, begin, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkGetQueryPoolResults failed: ");
|
||||
}
|
||||
|
||||
resources.timestamp_query_state = QueryState::None;
|
||||
}
|
||||
}
|
||||
|
||||
void GSDeviceVK::ScanForCommandBufferCompletion()
|
||||
{
|
||||
for (u32 check_index = (m_current_frame + 1) % NUM_COMMAND_BUFFERS; check_index != m_current_frame;
|
||||
@@ -1222,12 +1293,7 @@ void GSDeviceVK::SubmitCommandBuffer(VKSwapChain* present_swap_chain)
|
||||
}
|
||||
}
|
||||
|
||||
bool wants_timestamp = m_gpu_timing_enabled || m_spin_timer;
|
||||
if (wants_timestamp && resources.timestamp_written)
|
||||
{
|
||||
vkCmdWriteTimestamp(m_current_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, m_timestamp_query_pool,
|
||||
m_current_frame * 2 + 1);
|
||||
}
|
||||
EndGPUTiming(m_current_frame);
|
||||
|
||||
if (resources.pipeline_statistics_query == QueryState::Querying)
|
||||
{
|
||||
@@ -1363,43 +1429,7 @@ void GSDeviceVK::CommandBufferCompleted(u32 index)
|
||||
it();
|
||||
resources.cleanup_resources.clear();
|
||||
|
||||
bool wants_timestamps = m_gpu_timing_enabled || resources.spin_id >= 0;
|
||||
|
||||
if (wants_timestamps && resources.timestamp_written)
|
||||
{
|
||||
std::array<u64, 2> timestamps;
|
||||
VkResult res =
|
||||
vkGetQueryPoolResults(m_device, m_timestamp_query_pool, index * 2, static_cast<u32>(timestamps.size()),
|
||||
sizeof(u64) * timestamps.size(), timestamps.data(), sizeof(u64), VK_QUERY_RESULT_64_BIT);
|
||||
if (res == VK_SUCCESS)
|
||||
{
|
||||
// if we didn't write the timestamp at the start of the cmdbuffer (just enabled timing), the first TS will be zero
|
||||
if (timestamps[0] > 0 && m_gpu_timing_enabled)
|
||||
{
|
||||
const double ns_diff =
|
||||
(timestamps[1] - timestamps[0]) * static_cast<double>(m_device_properties.limits.timestampPeriod);
|
||||
m_accumulated_gpu_time += ns_diff / 1000000.0;
|
||||
}
|
||||
if (resources.spin_id >= 0)
|
||||
{
|
||||
if (m_optional_extensions.vk_ext_calibrated_timestamps && timestamps[1] > 0)
|
||||
{
|
||||
u64 end = timestamps[1] * m_spin_timestamp_scale + m_spin_timestamp_offset;
|
||||
m_spin_manager.DrawCompleted(resources.spin_id, resources.submit_timestamp, end);
|
||||
}
|
||||
else if (!m_optional_extensions.vk_ext_calibrated_timestamps && timestamps[0] > 0)
|
||||
{
|
||||
u64 begin = timestamps[0] * m_spin_timestamp_scale;
|
||||
u64 end = timestamps[1] * m_spin_timestamp_scale;
|
||||
m_spin_manager.DrawCompleted(resources.spin_id, begin, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkGetQueryPoolResults failed: ");
|
||||
}
|
||||
}
|
||||
ReadGPUTiming(index);
|
||||
}
|
||||
|
||||
void GSDeviceVK::MoveToNextCommandBuffer()
|
||||
@@ -1434,13 +1464,7 @@ void GSDeviceVK::ActivateCommandBuffer(u32 index)
|
||||
if (res != VK_SUCCESS)
|
||||
LOG_VULKAN_ERROR(res, "vkBeginCommandBuffer failed: ");
|
||||
|
||||
bool wants_timestamp = m_gpu_timing_enabled || m_spin_timer;
|
||||
if (wants_timestamp)
|
||||
{
|
||||
vkCmdResetQueryPool(resources.command_buffers[1], m_timestamp_query_pool, index * 2, 2);
|
||||
vkCmdWriteTimestamp(
|
||||
resources.command_buffers[1], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, m_timestamp_query_pool, index * 2);
|
||||
}
|
||||
StartGPUTiming(index);
|
||||
|
||||
if (resources.pipeline_statistics_query == QueryState::Ready)
|
||||
{
|
||||
@@ -1471,7 +1495,6 @@ void GSDeviceVK::ActivateCommandBuffer(u32 index)
|
||||
|
||||
resources.fence_counter = m_next_fence_counter++;
|
||||
resources.init_buffer_used = false;
|
||||
resources.timestamp_written = wants_timestamp;
|
||||
|
||||
m_current_frame = index;
|
||||
m_current_command_buffer = resources.command_buffers[1];
|
||||
@@ -4200,6 +4223,8 @@ bool GSDeviceVK::CompileConvertPipelines()
|
||||
gpb.SetColorWriteMask(0, shader.Mask());
|
||||
|
||||
std::string macro;
|
||||
macro += fmt::format("#define PRIMID_MAX {}\n", GSShader::PRIMID_MAX);
|
||||
macro += fmt::format("#define PRIMID_MIN {}\n", GSShader::PRIMID_MIN);
|
||||
macro += fmt::format("#define HAS_BILN {}\n", static_cast<int>(shader.Biln()));
|
||||
macro += fmt::format("#define HAS_STENCIL_OUTPUT {}\n", static_cast<int>(shader.StencilOutput()));
|
||||
macro += fmt::format("#define HAS_INTEGER_OUTPUT {}\n", static_cast<int>(shader.IntegerOutputBpp() != 0));
|
||||
@@ -4267,9 +4292,14 @@ bool GSDeviceVK::CompileConvertPipelines()
|
||||
|
||||
for (u32 datm = 0; datm < 4; datm++)
|
||||
{
|
||||
std::string macro;
|
||||
macro += fmt::format("#define PRIMID_MAX {}\n", GSShader::PRIMID_MAX);
|
||||
macro += fmt::format("#define PRIMID_MIN {}\n", GSShader::PRIMID_MIN);
|
||||
|
||||
const std::string source_with_header = macro + *source;
|
||||
|
||||
const std::string entry_point(StringUtil::StdStringFromFormat("ps_primid_image_init_%d", datm));
|
||||
VkShaderModule ps =
|
||||
GetUtilityFragmentShader(*source, entry_point.c_str());
|
||||
VkShaderModule ps = GetUtilityFragmentShader(source_with_header, entry_point.c_str());
|
||||
if (ps == VK_NULL_HANDLE)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -209,7 +209,6 @@ private:
|
||||
void CalibrateSpinTimestamp();
|
||||
u64 GetCPUTimestamp();
|
||||
|
||||
// For pipeline statistics
|
||||
enum class QueryState
|
||||
{
|
||||
None,
|
||||
@@ -228,7 +227,7 @@ private:
|
||||
u32 submit_timestamp = 0;
|
||||
bool init_buffer_used = false;
|
||||
bool needs_fence_wait = false;
|
||||
bool timestamp_written = false;
|
||||
QueryState timestamp_query_state = QueryState::None;
|
||||
QueryState pipeline_statistics_query = QueryState::None;
|
||||
|
||||
std::vector<std::function<void()>> cleanup_resources;
|
||||
@@ -575,6 +574,9 @@ public:
|
||||
bool IsPresenting() const;
|
||||
|
||||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
void StartGPUTiming(u32 index);
|
||||
void EndGPUTiming(u32 index);
|
||||
void ReadGPUTiming(u32 index);
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
|
||||
bool SetGPUPipelineStatisticsEnabled(bool enabled) override;
|
||||
|
||||
@@ -104,9 +104,9 @@ std::unique_ptr<GSTextureVK> GSTextureVK::Create(Usage usage, Format format, int
|
||||
|
||||
if (format == Format::UNorm8)
|
||||
{
|
||||
// for r8 textures, swizzle it across all 4 components. the shaders depend on it being in alpha.. why?
|
||||
// UNorm8 wants value in alpha, not red.
|
||||
static constexpr const VkComponentMapping r8_swizzle = {
|
||||
VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R };
|
||||
VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_R };
|
||||
vci.components = r8_swizzle;
|
||||
}
|
||||
|
||||
|
||||
+164
-11
@@ -1,6 +1,8 @@
|
||||
// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "PerformanceMetrics.h"
|
||||
#include "GS/GSPerfMon.h"
|
||||
#include "GS.h"
|
||||
#include "GS/GSLzma.h"
|
||||
#include "GSDumpReplayer.h"
|
||||
@@ -27,6 +29,7 @@
|
||||
#include "common/Timer.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <cinttypes>
|
||||
|
||||
static void GSDumpReplayerCpuReserve();
|
||||
static void GSDumpReplayerCpuShutdown();
|
||||
@@ -46,6 +49,19 @@ static bool s_needs_state_loaded = false;
|
||||
static u64 s_frame_ticks = 0;
|
||||
static u64 s_next_frame_time = 0;
|
||||
static bool s_is_dump_runner = false;
|
||||
static bool s_dump_perf_metrics = true;
|
||||
|
||||
static bool s_use_frame_range = false;
|
||||
static bool s_init_frame_range = false;
|
||||
static u32 s_frame_start = 0;
|
||||
static u32 s_frame_end = 0;
|
||||
static u32 s_frame_start_packet = 0;
|
||||
static u32 s_frame_end_packet = 0;
|
||||
|
||||
static GSPerfMon s_total_gs_stats;
|
||||
static GSPerfMon s_last_g_perfmon;
|
||||
static u64 s_total_frames = 0;
|
||||
static u64 s_total_drawn_frames = 0;
|
||||
|
||||
R5900cpu GSDumpReplayerCpu = {
|
||||
GSDumpReplayerCpuReserve,
|
||||
@@ -70,9 +86,10 @@ bool GSDumpReplayer::IsRunner()
|
||||
return s_is_dump_runner;
|
||||
}
|
||||
|
||||
void GSDumpReplayer::SetIsDumpRunner(bool is_runner)
|
||||
void GSDumpReplayer::SetIsDumpRunner(bool is_runner, bool dump_perf)
|
||||
{
|
||||
s_is_dump_runner = is_runner;
|
||||
s_dump_perf_metrics = dump_perf;
|
||||
}
|
||||
|
||||
void GSDumpReplayer::SetLoopCount(s32 loop_count)
|
||||
@@ -85,6 +102,13 @@ int GSDumpReplayer::GetLoopCount()
|
||||
return s_dump_loop_count;
|
||||
}
|
||||
|
||||
void GSDumpReplayer::SetFrameRange(bool use, u32 start, u32 end)
|
||||
{
|
||||
s_use_frame_range = use;
|
||||
s_frame_start = start;
|
||||
s_frame_end = end;
|
||||
}
|
||||
|
||||
bool GSDumpReplayer::Initialize(const char* filename, Error* error)
|
||||
{
|
||||
Common::Timer timer;
|
||||
@@ -145,6 +169,8 @@ void GSDumpReplayer::Shutdown()
|
||||
{
|
||||
Console.WriteLn("(GSDumpReplayer) Shutting down.");
|
||||
|
||||
DumpStats();
|
||||
|
||||
Cpu = nullptr;
|
||||
psxCpu = nullptr;
|
||||
CpuVU0 = nullptr;
|
||||
@@ -196,6 +222,13 @@ void GSDumpReplayerCpuReset()
|
||||
s_needs_state_loaded = true;
|
||||
s_current_packet = 0;
|
||||
s_dump_frame_number = 0;
|
||||
s_total_gs_stats.Reset();
|
||||
s_last_g_perfmon.Reset();
|
||||
s_init_frame_range = false;
|
||||
s_frame_start_packet = 0;
|
||||
s_frame_end_packet = 0;
|
||||
s_total_frames = 0;
|
||||
s_total_drawn_frames = 0;
|
||||
}
|
||||
|
||||
static void GSDumpReplayerLoadInitialState()
|
||||
@@ -256,17 +289,10 @@ static void GSDumpReplayerFrameLimit()
|
||||
s_next_frame_time = std::max(now, s_next_frame_time + s_frame_ticks);
|
||||
}
|
||||
|
||||
void GSDumpReplayerCpuStep()
|
||||
void AdvanceNextLoop()
|
||||
{
|
||||
if (s_needs_state_loaded)
|
||||
{
|
||||
GSDumpReplayerLoadInitialState();
|
||||
s_needs_state_loaded = false;
|
||||
}
|
||||
|
||||
const GSDumpFile::GSData& packet = s_dump_file->GetPackets()[s_current_packet];
|
||||
s_current_packet = (s_current_packet + 1) % static_cast<u32>(s_dump_file->GetPackets().size());
|
||||
if (s_current_packet == 0)
|
||||
const bool end_of_dump = (s_current_packet == static_cast<u32>(s_dump_file->GetPackets().size()));
|
||||
if (end_of_dump || (s_init_frame_range && s_current_packet > s_frame_end_packet))
|
||||
{
|
||||
s_dump_frame_number = 0;
|
||||
if (s_dump_loop_count > 0)
|
||||
@@ -277,6 +303,55 @@ void GSDumpReplayerCpuStep()
|
||||
s_dump_running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateFrameRangePacketsOnVSync()
|
||||
{
|
||||
if (s_use_frame_range && !s_init_frame_range)
|
||||
{
|
||||
if (s_dump_frame_number == s_frame_start)
|
||||
{
|
||||
// +1 since the current packet is the previous frame VSync packet.
|
||||
s_frame_start_packet = s_current_packet + 1;
|
||||
}
|
||||
else if (s_dump_frame_number >= s_frame_end && s_frame_end > s_frame_start)
|
||||
{
|
||||
// Current packet is the VSync packet of the last frame we want to loop over.
|
||||
s_frame_end_packet = s_current_packet;
|
||||
s_init_frame_range = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CheckFrameRange()
|
||||
{
|
||||
if (s_init_frame_range)
|
||||
{
|
||||
if (s_current_packet > s_frame_end_packet || s_current_packet < s_frame_start_packet)
|
||||
{
|
||||
s_dump_frame_number = s_frame_start;
|
||||
s_current_packet = s_frame_start_packet;
|
||||
}
|
||||
}
|
||||
else if (s_current_packet == static_cast<u32>(s_dump_file->GetPackets().size()))
|
||||
{
|
||||
// This will run if the frame range goes past the end of the dump.
|
||||
s_frame_end_packet = s_current_packet;
|
||||
s_init_frame_range = true;
|
||||
}
|
||||
}
|
||||
|
||||
void GSDumpReplayerCpuStep()
|
||||
{
|
||||
if (s_needs_state_loaded)
|
||||
{
|
||||
GSDumpReplayerLoadInitialState();
|
||||
s_needs_state_loaded = false;
|
||||
PerformanceMetrics::StartSavingMetrics(UINT32_MAX);
|
||||
}
|
||||
|
||||
// Get the next packet.
|
||||
const GSDumpFile::GSData& packet = s_dump_file->GetPackets()[s_current_packet];
|
||||
|
||||
switch (packet.id)
|
||||
{
|
||||
@@ -323,6 +398,7 @@ void GSDumpReplayerCpuStep()
|
||||
if (VMManager::Internal::IsExecutionInterrupted())
|
||||
GSDumpReplayerExitExecution();
|
||||
Host::PumpMessagesOnCPUThread();
|
||||
UpdateFrameRangePacketsOnVSync();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -343,6 +419,18 @@ void GSDumpReplayerCpuStep()
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Increment the packet counter.
|
||||
s_current_packet++;
|
||||
|
||||
// Increment the loop counter.
|
||||
AdvanceNextLoop();
|
||||
|
||||
// Adjust packet index based on the frame range we're replaying.
|
||||
CheckFrameRange();
|
||||
|
||||
// Loop packet index.
|
||||
s_current_packet %= static_cast<u32>(s_dump_file->GetPackets().size());
|
||||
}
|
||||
|
||||
void GSDumpReplayerCpuExecute()
|
||||
@@ -404,3 +492,68 @@ void GSDumpReplayer::RenderUI()
|
||||
|
||||
#undef DRAW_LINE
|
||||
}
|
||||
|
||||
static void UpdateSingleGSStat(GSPerfMon::counter_t counter)
|
||||
{
|
||||
const double curr = g_perfmon.GetCounter(counter);
|
||||
const double last = s_last_g_perfmon.GetCounter(counter);
|
||||
// GSPerfMon resets every 30 frames to zero.
|
||||
s_total_gs_stats.Put(counter, curr < last ? curr : (curr - last));
|
||||
};
|
||||
|
||||
void GSDumpReplayer::UpdateGSStats()
|
||||
{
|
||||
// Called on GS thread.
|
||||
if (GSIsHardwareRenderer())
|
||||
{
|
||||
const double last_draws = s_total_gs_stats.GetCounter(GSPerfMon::Draw);
|
||||
const double last_uploads = s_total_gs_stats.GetCounter(GSPerfMon::TextureUploads);
|
||||
|
||||
UpdateSingleGSStat(GSPerfMon::Draw);
|
||||
UpdateSingleGSStat(GSPerfMon::DrawCalls);
|
||||
UpdateSingleGSStat(GSPerfMon::RenderPasses);
|
||||
UpdateSingleGSStat(GSPerfMon::Barriers);
|
||||
UpdateSingleGSStat(GSPerfMon::TextureCopies);
|
||||
UpdateSingleGSStat(GSPerfMon::TextureUploads);
|
||||
UpdateSingleGSStat(GSPerfMon::Readbacks);
|
||||
UpdateSingleGSStat(GSPerfMon::TextureCopiesROV);
|
||||
UpdateSingleGSStat(GSPerfMon::DrawCallsROV);
|
||||
UpdateSingleGSStat(GSPerfMon::BarriersROV);
|
||||
|
||||
s_last_g_perfmon = g_perfmon;
|
||||
|
||||
const bool idle_frame = s_total_frames > 0 &&
|
||||
s_total_gs_stats.GetCounter(GSPerfMon::Draw) == last_draws &&
|
||||
s_total_gs_stats.GetCounter(GSPerfMon::TextureUploads) == last_uploads;
|
||||
|
||||
if (!idle_frame)
|
||||
s_total_drawn_frames++;
|
||||
|
||||
s_total_frames++;
|
||||
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
}
|
||||
}
|
||||
|
||||
static void DumpStatAndAvg(const char* format, double stat)
|
||||
{
|
||||
Console.WriteLn(format, static_cast<u64>(stat), static_cast<u64>(std::ceil(stat / static_cast<double>(s_total_drawn_frames))));
|
||||
}
|
||||
|
||||
void GSDumpReplayer::DumpStats()
|
||||
{
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
Console.WriteLnFmt("======= HW STATISTICS FOR {} ({}) FRAMES ========", s_total_frames, s_total_drawn_frames);
|
||||
DumpStatAndAvg("@HWSTAT@ Draw Calls: %" PRIu64 " (avg %" PRIu64 ")", s_total_gs_stats.GetCounter(GSPerfMon::DrawCalls));
|
||||
DumpStatAndAvg("@HWSTAT@ Render Passes: %" PRIu64 " (avg %" PRIu64 ")", s_total_gs_stats.GetCounter(GSPerfMon::RenderPasses));
|
||||
DumpStatAndAvg("@HWSTAT@ Barriers: %" PRIu64 " (avg %" PRIu64 ")", s_total_gs_stats.GetCounter(GSPerfMon::Barriers));
|
||||
DumpStatAndAvg("@HWSTAT@ Copies: %" PRIu64 " (avg %" PRIu64 ")", s_total_gs_stats.GetCounter(GSPerfMon::TextureCopies));
|
||||
DumpStatAndAvg("@HWSTAT@ Uploads: %" PRIu64 " (avg %" PRIu64 ")", s_total_gs_stats.GetCounter(GSPerfMon::TextureUploads));
|
||||
DumpStatAndAvg("@HWSTAT@ Readbacks: %" PRIu64 " (avg %" PRIu64 ")", s_total_gs_stats.GetCounter(GSPerfMon::Readbacks));
|
||||
DumpStatAndAvg("@HWSTAT@ Copies (ROV): %" PRIu64 " (avg %" PRIu64 ")", s_total_gs_stats.GetCounter(GSPerfMon::TextureCopiesROV));
|
||||
DumpStatAndAvg("@HWSTAT@ Draws Calls (ROV): %" PRIu64 " (avg %" PRIu64 ")", s_total_gs_stats.GetCounter(GSPerfMon::DrawCallsROV));
|
||||
DumpStatAndAvg("@HWSTAT@ Barriers (ROV): %" PRIu64 " (avg %" PRIu64 ")", s_total_gs_stats.GetCounter(GSPerfMon::BarriersROV));
|
||||
if (s_dump_perf_metrics)
|
||||
PerformanceMetrics::DumpSavedMetrics();
|
||||
Console.WriteLnFmt("============================================");
|
||||
}
|
||||
@@ -16,7 +16,8 @@ namespace GSDumpReplayer
|
||||
void SetLoopCount(s32 loop_count = 0);
|
||||
int GetLoopCount();
|
||||
bool IsRunner();
|
||||
void SetIsDumpRunner(bool is_runner);
|
||||
void SetIsDumpRunner(bool is_runner, bool dump_perf = true);
|
||||
void SetFrameRange(bool use, u32 start, u32 end);
|
||||
|
||||
bool Initialize(const char* filename, Error* error = nullptr);
|
||||
bool ChangeDump(const char* filename);
|
||||
@@ -28,4 +29,8 @@ namespace GSDumpReplayer
|
||||
u32 GetFrameNumber();
|
||||
|
||||
void RenderUI();
|
||||
|
||||
void UpdateGSStats();
|
||||
|
||||
void DumpStats();
|
||||
} // namespace GSDumpReplayer
|
||||
|
||||
@@ -376,6 +376,7 @@ static const char* s_gs_hw_fix_names[] = {
|
||||
"nativePaletteDraw",
|
||||
"estimateTextureRegion",
|
||||
"drawBuffering",
|
||||
"rewriteLargeSTCoords",
|
||||
"PCRTCOffsets",
|
||||
"PCRTCOverscan",
|
||||
"trilinearFiltering",
|
||||
@@ -622,6 +623,9 @@ bool GameDatabaseSchema::GameEntry::configMatchesHWFix(const Pcsx2Config::GSOpti
|
||||
|
||||
case GSHWFixId::DrawBuffering:
|
||||
return (static_cast<int>(config.UserHacks_DrawBuffering) == value);
|
||||
|
||||
case GSHWFixId::RewriteLargeSTCoords:
|
||||
return (static_cast<int>(config.UserHacks_RewriteLargeSTCoords) == value);
|
||||
|
||||
case GSHWFixId::PCRTCOffsets:
|
||||
return (static_cast<int>(config.PCRTCOffsets) == value);
|
||||
@@ -793,6 +797,10 @@ void GameDatabaseSchema::GameEntry::applyGSHardwareFixes(Pcsx2Config::GSOptions&
|
||||
config.UserHacks_DrawBuffering = (value > 0);
|
||||
break;
|
||||
|
||||
case GSHWFixId::RewriteLargeSTCoords:
|
||||
config.UserHacks_RewriteLargeSTCoords = (value > 0);
|
||||
break;
|
||||
|
||||
case GSHWFixId::PCRTCOffsets:
|
||||
config.PCRTCOffsets = (value > 0);
|
||||
break;
|
||||
|
||||
@@ -61,6 +61,7 @@ namespace GameDatabaseSchema
|
||||
NativePaletteDraw,
|
||||
EstimateTextureRegion,
|
||||
DrawBuffering,
|
||||
RewriteLargeSTCoords,
|
||||
PCRTCOffsets,
|
||||
PCRTCOverscan,
|
||||
|
||||
|
||||
+1
-1
@@ -267,7 +267,7 @@ bool GameList::GetIsoSerialAndCRC(const std::string& path, s32* disc_type, std::
|
||||
|
||||
// TODO: we could include the version in the game list?
|
||||
*disc_type = DoCDVDdetectDiskType();
|
||||
cdvdGetDiscInfo(serial, nullptr, nullptr, crc, nullptr);
|
||||
cdvdGetDiscInfo(serial, nullptr, nullptr, nullptr, crc, nullptr);
|
||||
DoCDVDclose();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2658,6 +2658,13 @@ void FullscreenUI::DrawEmulationSettingsPage()
|
||||
SetSettingsChanged(bsi);
|
||||
}
|
||||
|
||||
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_ANGLES_RIGHT, "Advanced Frame Display"),
|
||||
FSUI_CSTR("Displays the newest frame immediately at the beginning of the "
|
||||
"frame raster time, instead of at the end. Can reduce perceived "
|
||||
"input lag, but may cause problems with some games, such as "
|
||||
"Soulcalibur II and Baldur's Gate Dark Alliance II. "),
|
||||
"EmuCore/GS", "AdvancedFrameDisplay", false);
|
||||
|
||||
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROWS_SPIN, "Vertical Sync (VSync)"), FSUI_CSTR("Synchronizes frame presentation with host refresh."),
|
||||
"EmuCore/GS", "VsyncEnable", false);
|
||||
|
||||
@@ -3236,6 +3243,9 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad
|
||||
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_CROP, "Estimate Texture Region"),
|
||||
FSUI_CSTR("Attempts to reduce the texture size when games do not set it themselves (e.g. Snowblind games)."), "EmuCore/GS",
|
||||
"UserHacks_EstimateTextureRegion", false, manual_hw_fixes);
|
||||
DrawToggleSetting(bsi, FSUI_CSTR("Rewrite Large ST"),
|
||||
FSUI_CSTR("Rewrite large ST coordinates and clamp the values."), "EmuCore/GS",
|
||||
"UserHacks_RewriteLargeSTCoords", false, manual_hw_fixes);
|
||||
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_PALETTE, "GPU Palette Conversion"),
|
||||
FSUI_CSTR("When enabled GPU converts colormap-textures, otherwise the CPU will. It is a trade-off between GPU and CPU."),
|
||||
"EmuCore/GS", "paltex", false, manual_hw_fixes);
|
||||
@@ -5960,6 +5970,7 @@ TRANSLATE_NOOP("FullscreenUI", "Second of the minute (0-59).");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Frame Pacing / Latency Control");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Sets the number of frames which can be queued.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Synchronize EE and GS threads after each frame. Lowest input latency, but increases system requirements.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Displays the newest frame immediately at the beginning of the frame raster time, instead of at the end. Can reduce perceived input lag, but may cause problems with some games, such as Soulcalibur II and Baldur's Gate Dark Alliance II. ");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Synchronizes frame presentation with host refresh.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Speeds up emulation so that the guest refresh rate matches the host.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Disables PCSX2's internal frame timing, and uses host vsync instead.");
|
||||
@@ -6014,6 +6025,8 @@ TRANSLATE_NOOP("FullscreenUI", "Removes texture cache entries when there is any
|
||||
TRANSLATE_NOOP("FullscreenUI", "Allows the texture cache to reuse as an input texture the inner portion of a previous framebuffer.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Flushes all targets in the texture cache back to local memory when shutting down.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Attempts to reduce the texture size when games do not set it themselves (e.g. Snowblind games).");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Rewrite Large ST");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Rewrite large ST coordinates and clamp the values.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "When enabled GPU converts colormap-textures, otherwise the CPU will. It is a trade-off between GPU and CPU.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Attempts to reduce draw calls in games which do heavy context switching for blending purposes.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Truncate 32-bit depth values to 24 bits. Helps games struggling with Z-fighting.");
|
||||
@@ -6582,6 +6595,7 @@ TRANSLATE_NOOP("FullscreenUI", "Minute");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Second");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Maximum Frame Latency");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Optimal Frame Pacing");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Advanced Frame Display");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Vertical Sync (VSync)");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Sync to Host Refresh Rate");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Use Host VSync Timing");
|
||||
|
||||
@@ -928,6 +928,8 @@ __ri void ImGuiManager::DrawSettingsOverlay(float scale, float margin, float spa
|
||||
APPEND("MTVU ");
|
||||
if (EmuConfig.GS.VsyncEnable)
|
||||
APPEND("VSYNC ");
|
||||
if (EmuConfig.GS.AdvancedFrameDisplay)
|
||||
APPEND("AFD ");
|
||||
|
||||
APPEND("EER={} EEC={} VUR={} VUC={} VQS={} ", static_cast<unsigned>(EmuConfig.Cpu.FPUFPCR.GetRoundMode()),
|
||||
EmuConfig.Cpu.Recompiler.GetEEClampMode(), static_cast<unsigned>(EmuConfig.Cpu.VU0FPCR.GetRoundMode()),
|
||||
@@ -1021,6 +1023,8 @@ __ri void ImGuiManager::DrawSettingsOverlay(float scale, float margin, float spa
|
||||
APPEND("ETR ");
|
||||
if (GSConfig.UserHacks_DrawBuffering)
|
||||
APPEND("DRWB ");
|
||||
if (GSConfig.UserHacks_RewriteLargeSTCoords)
|
||||
APPEND("RWST ");
|
||||
if (GSConfig.HWSpinGPUForReadbacks)
|
||||
APPEND("RBSG ");
|
||||
if (GSConfig.HWSpinCPUForReadbacks)
|
||||
|
||||
@@ -1048,6 +1048,13 @@ void MTGS::SetRunIdle(bool enabled)
|
||||
s_run_idle_flag.store(enabled, std::memory_order_release);
|
||||
}
|
||||
|
||||
void MTGS::ResetStats()
|
||||
{
|
||||
RunOnGSThread([]() {
|
||||
GSResetStats();
|
||||
});
|
||||
}
|
||||
|
||||
// Used in MTVU mode... MTVU will later complete a real packet
|
||||
void Gif_AddGSPacketMTVU(GS_Packet& gsPack, GIF_PATH path)
|
||||
{
|
||||
|
||||
@@ -78,6 +78,7 @@ namespace MTGS
|
||||
bool SaveMemorySnapshot(u32 window_width, u32 window_height, bool apply_aspect, bool crop_borders,
|
||||
u32* width, u32* height, std::vector<u32>* pixels);
|
||||
void SetRunIdle(bool enabled);
|
||||
void ResetStats();
|
||||
|
||||
// Size of the ringbuffer as a power of 2 -- size is a multiple of simd128s.
|
||||
// (actual size is 1<<m_RingBufferSizeFactor simd vectors [128-bit values])
|
||||
|
||||
@@ -723,6 +723,7 @@ Pcsx2Config::GSOptions::GSOptions()
|
||||
DisableFramebufferFetch = false;
|
||||
DisableVertexShaderExpand = false;
|
||||
SkipDuplicateFrames = true;
|
||||
AdvancedFrameDisplay = false;
|
||||
OsdMessagesPos = OsdOverlayPos::TopLeft;
|
||||
OsdPerformancePos = OsdOverlayPos::TopRight;
|
||||
OsdShowSpeed = false;
|
||||
@@ -875,6 +876,10 @@ bool Pcsx2Config::GSOptions::OptionsAreEqual(const GSOptions& right) const
|
||||
OpEqu(SaveFrameStart) &&
|
||||
OpEqu(SaveFrameCount) &&
|
||||
OpEqu(SaveFrameBy) &&
|
||||
OpEqu(DumpReplayLoopCount) &&
|
||||
OpEqu(DumpReplayFrameStart) &&
|
||||
OpEqu(DumpReplayFrameEnd) &&
|
||||
OpEqu(SavedMetricsCaptureSeconds) &&
|
||||
|
||||
OpEqu(ExclusiveFullscreenControl) &&
|
||||
OpEqu(ScreenshotSize) &&
|
||||
@@ -961,6 +966,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
|
||||
SettingsWrapBitBool(DisableFramebufferFetch);
|
||||
SettingsWrapBitBool(DisableVertexShaderExpand);
|
||||
SettingsWrapBitBool(SkipDuplicateFrames);
|
||||
SettingsWrapBitBool(AdvancedFrameDisplay);
|
||||
SettingsWrapBitBool(OsdShowSpeed);
|
||||
SettingsWrapBitBool(OsdShowFPS);
|
||||
SettingsWrapBitBool(OsdShowVPS);
|
||||
@@ -1005,6 +1011,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
|
||||
SettingsWrapIntEnumEx(UserHacks_Limit24BitDepth, "UserHacks_Limit24BitDepth");
|
||||
SettingsWrapBitBoolEx(UserHacks_EstimateTextureRegion, "UserHacks_EstimateTextureRegion");
|
||||
SettingsWrapBitBoolEx(UserHacks_DrawBuffering, "UserHacks_DrawBuffering");
|
||||
SettingsWrapBitBoolEx(UserHacks_RewriteLargeSTCoords, "UserHacks_RewriteLargeSTCoords");
|
||||
SettingsWrapBitBoolEx(FXAA, "fxaa");
|
||||
SettingsWrapBitBool(ShadeBoost);
|
||||
SettingsWrapBitBoolEx(DumpGSData, "DumpGSData");
|
||||
@@ -1018,6 +1025,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
|
||||
SettingsWrapBitBoolEx(SaveDrawStats, "SaveDrawStats");
|
||||
SettingsWrapBitBoolEx(SaveFrameStats, "SaveFrameStats");
|
||||
SettingsWrapBitBoolEx(SaveHWConfig, "SaveHWConfig");
|
||||
SettingsWrapBitBoolEx(DumpReplayUseFrameRange, "DumpReplayUseFrameRange");
|
||||
SettingsWrapBitBool(DumpReplaceableTextures);
|
||||
SettingsWrapBitBool(DumpReplaceableMipmaps);
|
||||
SettingsWrapBitBool(DumpTexturesWithFMVActive);
|
||||
@@ -1092,6 +1100,10 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
|
||||
SettingsWrapBitfieldEx(SaveFrameStart, "SaveFrameStart");
|
||||
SettingsWrapBitfieldEx(SaveFrameCount, "SaveFrameCount");
|
||||
SettingsWrapBitfieldEx(SaveFrameBy, "SaveFrameBy");
|
||||
SettingsWrapBitfieldEx(DumpReplayLoopCount, "DumpReplayLoopCount");
|
||||
SettingsWrapBitfieldEx(DumpReplayFrameStart, "DumpReplayFrameStart");
|
||||
SettingsWrapBitfieldEx(DumpReplayFrameEnd, "DumpReplayFrameEnd");
|
||||
SettingsWrapBitfieldEx(SavedMetricsCaptureSeconds, "SavedMetricsCaptureSeconds");
|
||||
|
||||
SettingsWrapEntryEx(CaptureContainer, "CaptureContainer");
|
||||
SettingsWrapEntryEx(VideoCaptureCodec, "VideoCaptureCodec");
|
||||
@@ -1145,6 +1157,7 @@ void Pcsx2Config::GSOptions::MaskUserHacks()
|
||||
UserHacks_Limit24BitDepth = GSLimit24BitDepth::Disabled;
|
||||
UserHacks_EstimateTextureRegion = false;
|
||||
UserHacks_DrawBuffering = false;
|
||||
UserHacks_RewriteLargeSTCoords = false;
|
||||
UserHacks_TCOffsetX = 0;
|
||||
UserHacks_TCOffsetY = 0;
|
||||
UserHacks_CPUSpriteRenderBW = 0;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
#include "common/Timer.h"
|
||||
#include "common/Threading.h"
|
||||
@@ -75,6 +76,10 @@ static double s_average_gpu_ps_invocations = 0.0;
|
||||
static u64 s_accumulated_gpu_vs_invocations = 0;
|
||||
static u64 s_accumulated_gpu_ps_invocations = 0;
|
||||
|
||||
static PerformanceMetrics::SavedMetrics s_saved_metrics;
|
||||
static PerformanceMetrics::SavedMetrics s_saved_metrics_std;
|
||||
static float s_saved_metrics_remaining_seconds = 0.0f;
|
||||
|
||||
void PerformanceMetrics::Clear()
|
||||
{
|
||||
Reset();
|
||||
@@ -85,6 +90,8 @@ void PerformanceMetrics::Clear()
|
||||
s_average_frame_time = 0.0f;
|
||||
s_maximum_frame_time = 0.0f;
|
||||
s_internal_fps_method = PerformanceMetrics::InternalFPSMethod::None;
|
||||
s_average_gpu_vs_invocations = 0.0;
|
||||
s_average_gpu_ps_invocations = 0.0;
|
||||
|
||||
s_cpu_thread_usage = 0.0f;
|
||||
s_cpu_thread_time = 0.0f;
|
||||
@@ -102,6 +109,10 @@ void PerformanceMetrics::Clear()
|
||||
|
||||
s_frame_time_history.fill(0.0f);
|
||||
s_frame_time_history_pos = 0;
|
||||
|
||||
s_saved_metrics = {};
|
||||
s_saved_metrics_std = {};
|
||||
s_saved_metrics_remaining_seconds = 0.0f;
|
||||
}
|
||||
|
||||
void PerformanceMetrics::Reset()
|
||||
@@ -113,6 +124,8 @@ void PerformanceMetrics::Reset()
|
||||
s_minimum_frame_time_accumulator = 0.0f;
|
||||
s_average_frame_time_accumulator = 0.0f;
|
||||
s_maximum_frame_time_accumulator = 0.0f;
|
||||
s_accumulated_gpu_vs_invocations = 0;
|
||||
s_accumulated_gpu_ps_invocations = 0;
|
||||
|
||||
s_accumulated_gpu_time = 0.0f;
|
||||
s_presents_since_last_update = 0;
|
||||
@@ -130,6 +143,17 @@ void PerformanceMetrics::Reset()
|
||||
stat.last_cpu_time = stat.handle.GetCPUTime();
|
||||
}
|
||||
|
||||
static double GetCPUTimeToPCTFactor(u64 ticks_delta)
|
||||
{
|
||||
return 100.0 * static_cast<double>(GetTickFrequency()) /
|
||||
(static_cast<double>(ticks_delta) * static_cast<double>(Threading::GetThreadTicksPerSecond()));
|
||||
}
|
||||
|
||||
static double GetCPUTimeToMSFactor(u64 frames)
|
||||
{
|
||||
return 1000.0 / static_cast<double>(Threading::GetThreadTicksPerSecond()) / static_cast<double>(frames);
|
||||
}
|
||||
|
||||
void PerformanceMetrics::Update(bool gs_register_write, bool fb_blit, bool is_skipping_present)
|
||||
{
|
||||
if (!is_skipping_present)
|
||||
@@ -191,11 +215,8 @@ void PerformanceMetrics::Update(bool gs_register_write, bool fb_blit, bool is_sk
|
||||
const u64 ticks_delta = ticks - s_last_ticks;
|
||||
s_last_ticks = ticks;
|
||||
|
||||
const double pct_divider =
|
||||
100.0 * (1.0 / ((static_cast<double>(ticks_delta) * static_cast<double>(Threading::GetThreadTicksPerSecond())) /
|
||||
static_cast<double>(GetTickFrequency())));
|
||||
const double time_divider = 1000.0 * (1.0 / static_cast<double>(Threading::GetThreadTicksPerSecond())) *
|
||||
(1.0 / static_cast<double>(s_frames_since_last_update));
|
||||
const double pct_divider = GetCPUTimeToPCTFactor(ticks_delta);
|
||||
const double time_divider = GetCPUTimeToMSFactor(s_frames_since_last_update);
|
||||
|
||||
const u64 cpu_time = s_cpu_thread_handle.GetCPUTime();
|
||||
const u64 gs_time = MTGS::GetThreadHandle().GetCPUTime();
|
||||
@@ -229,6 +250,32 @@ void PerformanceMetrics::Update(bool gs_register_write, bool fb_blit, bool is_sk
|
||||
thread.time = static_cast<double>(delta) * time_divider;
|
||||
}
|
||||
|
||||
if (s_saved_metrics_remaining_seconds > 0.0f)
|
||||
{
|
||||
auto UpdateSavedMetrics = [&](PerformanceMetrics::SavedMetrics& metrics, bool square) {
|
||||
auto Transform = [square](float f) { return square ? f * f : f; };
|
||||
|
||||
metrics.num_samples += 1.0f;
|
||||
metrics.frames += static_cast<float>(s_frames_since_last_update);
|
||||
metrics.time += time;
|
||||
metrics.fps += Transform(s_fps);
|
||||
metrics.internal_fps += Transform(s_internal_fps);
|
||||
metrics.cpu_thread_usage += Transform(s_cpu_thread_usage);
|
||||
metrics.cpu_thread_time += Transform(s_cpu_thread_time);
|
||||
metrics.gs_thread_usage += Transform(s_gs_thread_usage);
|
||||
metrics.gs_thread_time += Transform(s_gs_thread_time);
|
||||
metrics.gpu_time += Transform(s_average_gpu_time);;
|
||||
metrics.gpu_usage += Transform(s_gpu_usage);
|
||||
};
|
||||
|
||||
UpdateSavedMetrics(s_saved_metrics, false);
|
||||
UpdateSavedMetrics(s_saved_metrics_std, true);
|
||||
|
||||
s_saved_metrics_remaining_seconds -= std::min(s_saved_metrics_remaining_seconds, time);
|
||||
|
||||
std::atomic_thread_fence(std::memory_order_release); // results might be read on another thread
|
||||
}
|
||||
|
||||
s_frames_since_last_update = 0;
|
||||
s_unskipped_frames_since_last_update = 0;
|
||||
s_presents_since_last_update = 0;
|
||||
@@ -391,3 +438,62 @@ u32 PerformanceMetrics::GetFrameTimeHistoryPos()
|
||||
{
|
||||
return s_frame_time_history_pos;
|
||||
}
|
||||
|
||||
void PerformanceMetrics::StartSavingMetrics(u32 seconds)
|
||||
{
|
||||
s_saved_metrics_remaining_seconds = static_cast<float>(seconds);
|
||||
s_saved_metrics = {};
|
||||
s_saved_metrics_std = {};
|
||||
}
|
||||
|
||||
bool PerformanceMetrics::IsSavingMetrics()
|
||||
{
|
||||
return s_saved_metrics_remaining_seconds > 0.0f;
|
||||
}
|
||||
|
||||
void PerformanceMetrics::DumpSavedMetrics()
|
||||
{
|
||||
s_saved_metrics_remaining_seconds = 0.0f;
|
||||
|
||||
SavedMetrics metrics = std::exchange(s_saved_metrics, SavedMetrics{});
|
||||
SavedMetrics metrics_std = std::exchange(s_saved_metrics_std, SavedMetrics{});
|
||||
|
||||
const float num_samples = metrics.num_samples;
|
||||
|
||||
if (num_samples > 0.0f)
|
||||
{
|
||||
const auto Square = [](float f) { return f * f; };
|
||||
const auto Average = [num_samples](float f) { return f / num_samples; };
|
||||
|
||||
metrics.fps = Average(metrics.fps);
|
||||
metrics.internal_fps = Average(metrics.internal_fps);
|
||||
metrics.cpu_thread_usage = Average(metrics.cpu_thread_usage);
|
||||
metrics.cpu_thread_time = Average(metrics.cpu_thread_time);
|
||||
metrics.gs_thread_usage = Average(metrics.gs_thread_usage);
|
||||
metrics.gs_thread_time = Average(metrics.gs_thread_time);
|
||||
metrics.gpu_time = Average(metrics.gpu_time);
|
||||
metrics.gpu_usage = Average(metrics.gpu_usage);
|
||||
|
||||
metrics_std.fps = std::sqrt((Average(metrics_std.fps) - Square(metrics.fps)));
|
||||
metrics_std.internal_fps = std::sqrt((Average(metrics_std.internal_fps) - Square(metrics.internal_fps)));
|
||||
metrics_std.cpu_thread_usage = std::sqrt((Average(metrics_std.cpu_thread_usage) - Square(metrics.cpu_thread_usage)));
|
||||
metrics_std.cpu_thread_time = std::sqrt((Average(metrics_std.cpu_thread_time) - Square(metrics.cpu_thread_time)));
|
||||
metrics_std.gs_thread_usage = std::sqrt((Average(metrics_std.gs_thread_usage) - Square(metrics.gs_thread_usage)));
|
||||
metrics_std.gs_thread_time = std::sqrt((Average(metrics_std.gs_thread_time) - Square(metrics.gs_thread_time)));
|
||||
metrics_std.gpu_time = std::sqrt((Average(metrics_std.gpu_time) - Square(metrics.gpu_time)));
|
||||
metrics_std.gpu_usage = std::sqrt((Average(metrics_std.gpu_usage) - Square(metrics.gpu_usage)));
|
||||
|
||||
Console.WriteLnFmt("@HWSTAT@ Frames: {} ({} samples)", metrics.frames, metrics.num_samples);
|
||||
Console.WriteLnFmt("@HWSTAT@ Time: {:.3f} sec", metrics.time);
|
||||
Console.WriteLnFmt("@HWSTAT@ FPS: {:.3f} ± {:.3f} ({:.3f} ± {:.3f} internal)", metrics.fps, metrics_std.fps, metrics.internal_fps, metrics_std.internal_fps);
|
||||
Console.WriteLnFmt("@HWSTAT@ Minimum Frame Time: {:.3f} ms ({:.3f} FPS)", GetMinimumFrameTime(), 1000.0f / GetMinimumFrameTime());
|
||||
Console.WriteLnFmt("@HWSTAT@ Average Frame Time: {:.3f} ms ({:.3f} FPS)", GetAverageFrameTime(), 1000.0f / GetAverageFrameTime());
|
||||
Console.WriteLnFmt("@HWSTAT@ Maximum Frame Time: {:.3f} ms ({:.3f} FPS)", GetMaximumFrameTime(), 1000.0f / GetMaximumFrameTime());
|
||||
Console.WriteLnFmt("@HWSTAT@ Average CPU Thread Usage: {:.3f} ± {:.3f} %", metrics.cpu_thread_usage, metrics_std.cpu_thread_usage);
|
||||
Console.WriteLnFmt("@HWSTAT@ Average GS Thread Usage: {:.3f} ± {:.3f} %", metrics.gs_thread_usage, metrics_std.gs_thread_usage);
|
||||
Console.WriteLnFmt("@HWSTAT@ Average GPU Usage: {:.3f} ± {:.3f} %", metrics.gpu_usage, metrics_std.gpu_usage);
|
||||
Console.WriteLnFmt("@HWSTAT@ Average CPU Thread Time: {:.3f} ± {:.3f} ms", metrics.cpu_thread_time, metrics_std.cpu_thread_time);
|
||||
Console.WriteLnFmt("@HWSTAT@ Average GS Thread Time: {:.3f} ± {:.3f} ms", metrics.gs_thread_time, metrics_std.gs_thread_time);
|
||||
Console.WriteLnFmt("@HWSTAT@ Average GPU Time: {:.3f} ± {:.3f} ms", metrics.gpu_time, metrics_std.gpu_time);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,4 +62,23 @@ namespace PerformanceMetrics
|
||||
|
||||
const FrameTimeHistory& GetFrameTimeHistory();
|
||||
u32 GetFrameTimeHistoryPos();
|
||||
|
||||
struct SavedMetrics
|
||||
{
|
||||
float num_samples;
|
||||
float frames;
|
||||
float time;
|
||||
float fps;
|
||||
float internal_fps;
|
||||
float cpu_thread_usage;
|
||||
float cpu_thread_time;
|
||||
float gs_thread_usage;
|
||||
float gs_thread_time;
|
||||
float gpu_time;
|
||||
float gpu_usage;
|
||||
};
|
||||
|
||||
void StartSavingMetrics(u32 seconds);
|
||||
bool IsSavingMetrics();
|
||||
void DumpSavedMetrics();
|
||||
} // namespace PerformanceMetrics
|
||||
|
||||
+1
-1
@@ -679,7 +679,7 @@ void eeloadHook()
|
||||
{
|
||||
CDVDDiscType disc_type;
|
||||
std::string disc_elf;
|
||||
cdvdGetDiscInfo(nullptr, &disc_elf, nullptr, nullptr, &disc_type);
|
||||
cdvdGetDiscInfo(nullptr, &disc_elf, nullptr, nullptr, nullptr, &disc_type);
|
||||
if (disc_type == CDVDDiscType::PS2Disc)
|
||||
{
|
||||
// only allow fast boot for PS2 games
|
||||
|
||||
@@ -23,8 +23,6 @@ bool SaveStateBase::InputRecordingFreeze()
|
||||
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "Counters.h"
|
||||
#include "SaveState.h"
|
||||
#include "VMManager.h"
|
||||
#include "Host.h"
|
||||
#include "ImGui/ImGuiOverlays.h"
|
||||
@@ -32,7 +30,7 @@ bool SaveStateBase::InputRecordingFreeze()
|
||||
#include "GameDatabase.h"
|
||||
#include "fmt/format.h"
|
||||
#include "GS.h"
|
||||
#include "Host.h"
|
||||
#include "SIO/Pad/Pad.h"
|
||||
|
||||
InputRecording g_InputRecording;
|
||||
|
||||
@@ -139,6 +137,7 @@ void InputRecording::closeActiveFile()
|
||||
if (m_file.close())
|
||||
{
|
||||
m_is_active = false;
|
||||
Pad::ResetAllControllerInputs();
|
||||
InputRec::log(TRANSLATE_STR("InputRecording", "Input recording stopped"), Host::OSD_ERROR_DURATION);
|
||||
MTGS::PresentCurrentFrame();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "InputRecording.h"
|
||||
#include "InputRecordingControls.h"
|
||||
#include "Utilities/InputRecordingLogger.h"
|
||||
#include "SIO/Pad/Pad.h"
|
||||
|
||||
#include "Host.h"
|
||||
#include "MTGS.h"
|
||||
@@ -29,6 +30,7 @@ void InputRecordingControls::setRecordMode(bool waitForFrameToEnd)
|
||||
if (!waitForFrameToEnd || VMManager::GetState() == VMState::Paused)
|
||||
{
|
||||
m_state = Mode::Recording;
|
||||
Pad::ResetAllControllerInputs();
|
||||
InputRec::log(TRANSLATE("InputRecordingControls","Record Mode Enabled"), Host::OSD_INFO_DURATION);
|
||||
MTGS::PresentCurrentFrame();
|
||||
}
|
||||
@@ -36,6 +38,7 @@ void InputRecordingControls::setRecordMode(bool waitForFrameToEnd)
|
||||
{
|
||||
m_controlQueue.push([&]() {
|
||||
m_state = Mode::Recording;
|
||||
Pad::ResetAllControllerInputs();
|
||||
InputRec::log(TRANSLATE("InputRecordingControls","Record Mode Enabled"), Host::OSD_INFO_DURATION);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -232,6 +232,8 @@ void Pad::SetDefaultHotkeyConfig(SettingsInterface& si)
|
||||
si.SetStringValue("Hotkeys", "GSDumpMultiFrame", "Keyboard/Control & Keyboard/Shift & Keyboard/F8");
|
||||
si.SetStringValue("Hotkeys", "Screenshot", "Keyboard/F8");
|
||||
si.SetStringValue("Hotkeys", "GSDumpSingleFrame", "Keyboard/Shift & Keyboard/F8");
|
||||
si.SetStringValue("Hotkeys", "GSStartSavingMetricsVariableFrames", "Keyboard/F10");
|
||||
si.SetStringValue("Hotkeys", "GSStartSavingMetricsFixedFrames", "Keyboard/Control & Keyboard/F10");
|
||||
si.SetStringValue("Hotkeys", "ToggleSoftwareRendering", "Keyboard/F9");
|
||||
// si.SetStringValue("Hotkeys", "ToggleTextureDumping", "Keyboard"); TBD
|
||||
// si.SetStringValue("Hotkeys", "ToggleTextureReplacements", "Keyboard"); TBD
|
||||
@@ -554,6 +556,32 @@ void Pad::SetControllerState(u32 controller, u32 bind, float value)
|
||||
s_controllers[controller]->Set(bind, value);
|
||||
}
|
||||
|
||||
void Pad::ResetControllerInputs(u32 controller)
|
||||
{
|
||||
if (controller >= NUM_CONTROLLER_PORTS || !HasConnectedPad(controller))
|
||||
return;
|
||||
|
||||
for (InputBindingInfo binding : s_controllers[controller]->GetInfo().bindings)
|
||||
{
|
||||
switch (binding.bind_type)
|
||||
{
|
||||
case InputBindingInfo::Type::Button:
|
||||
case InputBindingInfo::Type::Axis:
|
||||
case InputBindingInfo::Type::HalfAxis:
|
||||
s_controllers[controller]->Set(binding.bind_index, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Pad::ResetAllControllerInputs()
|
||||
{
|
||||
for (u32 port = 0; port < NUM_CONTROLLER_PORTS; port++)
|
||||
ResetControllerInputs(port);
|
||||
}
|
||||
|
||||
bool Pad::Freeze(StateWrapper& sw)
|
||||
{
|
||||
if (sw.IsReading())
|
||||
|
||||
@@ -66,6 +66,10 @@ namespace Pad
|
||||
// Sets the specified bind on a controller to the specified pressure (normalized to 0..1).
|
||||
void SetControllerState(u32 controller, u32 bind, float value);
|
||||
|
||||
// Resets all input binds on a controller to their default state.
|
||||
void ResetControllerInputs(u32 controller);
|
||||
void ResetAllControllerInputs();
|
||||
|
||||
bool Freeze(StateWrapper& sw);
|
||||
|
||||
// Sets the state of the specified macro button.
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
|
||||
/// Version number for GS and other shaders. Increment whenever any of the contents of the
|
||||
/// shaders change, to invalidate the cache.
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 110; // Last changed in PR 14897
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 113; // Last changed in PR 14743
|
||||
|
||||
+28
-5
@@ -171,6 +171,7 @@ static std::string s_disc_version;
|
||||
static std::string s_title;
|
||||
static std::string s_title_en_search;
|
||||
static std::string s_title_en_replace;
|
||||
static std::string s_cur_region;
|
||||
static u32 s_disc_crc;
|
||||
static u32 s_current_crc;
|
||||
static u32 s_elf_entry_point = 0xFFFFFFFFu;
|
||||
@@ -665,7 +666,12 @@ void VMManager::LoadCoreSettings(SettingsInterface& si)
|
||||
|
||||
// Force MTVU off when playing back GS dumps, it doesn't get used.
|
||||
if (GSDumpReplayer::IsReplayingDump())
|
||||
{
|
||||
EmuConfig.Speedhacks.vuThread = false;
|
||||
GSDumpReplayer::SetFrameRange(EmuConfig.GS.DumpReplayUseFrameRange,
|
||||
EmuConfig.GS.DumpReplayFrameStart, EmuConfig.GS.DumpReplayFrameEnd);
|
||||
GSDumpReplayer::SetLoopCount(EmuConfig.GS.DumpReplayLoopCount);
|
||||
}
|
||||
}
|
||||
|
||||
void VMManager::LoadInputBindings(SettingsInterface& si, std::unique_lock<std::mutex>& lock)
|
||||
@@ -1051,11 +1057,12 @@ void VMManager::UpdateDiscDetails(bool booting)
|
||||
s_disc_crc = GSDumpReplayer::GetDumpCRC();
|
||||
s_disc_elf = {};
|
||||
s_disc_version = {};
|
||||
s_cur_region = "NTSC";
|
||||
serial_is_valid = !s_disc_serial.empty();
|
||||
}
|
||||
else if (CDVDsys_GetSourceType() != CDVD_SourceType::NoDisc)
|
||||
{
|
||||
cdvdGetDiscInfo(&s_disc_serial, &s_disc_elf, &s_disc_version, &s_disc_crc, nullptr);
|
||||
cdvdGetDiscInfo(&s_disc_serial, &s_disc_elf, &s_disc_version, &s_cur_region, &s_disc_crc, nullptr);
|
||||
serial_is_valid = !s_disc_serial.empty();
|
||||
}
|
||||
else if (!s_elf_override.empty())
|
||||
@@ -1063,12 +1070,14 @@ void VMManager::UpdateDiscDetails(bool booting)
|
||||
s_disc_serial = Path::GetFileTitle(s_elf_override);
|
||||
s_disc_version = {};
|
||||
s_disc_crc = 0; // set below
|
||||
s_cur_region = "NTSC";
|
||||
}
|
||||
else
|
||||
{
|
||||
s_disc_serial = BiosSerial;
|
||||
s_disc_version = {};
|
||||
s_disc_crc = 0;
|
||||
s_cur_region = (BiosZone == "Europe") ? "PAL" : "NTSC";
|
||||
title = fmt::format(TRANSLATE_FS("VMManager", "PS2 BIOS ({})"), BiosZone);
|
||||
}
|
||||
|
||||
@@ -1645,6 +1654,7 @@ VMBootResult VMManager::Initialize(const VMBootParameters& boot_params, Error* e
|
||||
}
|
||||
|
||||
PerformanceMetrics::Clear();
|
||||
MTGS::ResetStats();
|
||||
return VMBootResult::StartupSuccess;
|
||||
}
|
||||
|
||||
@@ -2268,14 +2278,14 @@ void VMManager::ResetFrameLimiter()
|
||||
s_limiter_frame_start = GetCPUTicks();
|
||||
}
|
||||
|
||||
void VMManager::Internal::Throttle()
|
||||
void VMManager::Internal::Throttle(bool vsync_start)
|
||||
{
|
||||
if (s_target_speed == 0.0f || s_use_vsync_for_timing)
|
||||
return;
|
||||
|
||||
const u64 uExpectedEnd =
|
||||
s_limiter_frame_start +
|
||||
s_limiter_ticks_per_frame; // Compute when we would expect this frame to end, assuming everything goes perfectly perfect.
|
||||
(vsync_start ? (s_limiter_ticks_per_frame * 0.9) : s_limiter_ticks_per_frame); // Compute when we would expect this frame to end, assuming everything goes perfectly perfect.
|
||||
const u64 iEnd = GetCPUTicks(); // The current tick we actually stopped on.
|
||||
const s64 sDeltaTime = iEnd - uExpectedEnd; // The diff between when we stopped and when we expected to.
|
||||
|
||||
@@ -2304,8 +2314,11 @@ void VMManager::Internal::Throttle()
|
||||
{
|
||||
}
|
||||
|
||||
// Finally, set our next frame start to when this one ends
|
||||
s_limiter_frame_start = uExpectedEnd;
|
||||
if (!vsync_start)
|
||||
{
|
||||
// Finally, set our next frame start to when this one ends
|
||||
s_limiter_frame_start = uExpectedEnd;
|
||||
}
|
||||
}
|
||||
|
||||
void VMManager::Internal::FrameRateChanged()
|
||||
@@ -2818,6 +2831,11 @@ bool VMManager::Internal::IsFastBootInProgress()
|
||||
return s_fast_boot_requested && !HasBootedELF();
|
||||
}
|
||||
|
||||
std::string VMManager::Internal::GetCurrentRegion()
|
||||
{
|
||||
return s_cur_region;
|
||||
}
|
||||
|
||||
void VMManager::Internal::DisableFastBoot()
|
||||
{
|
||||
if (!s_fast_boot_requested)
|
||||
@@ -3270,6 +3288,11 @@ void VMManager::WarnAboutUnsafeSettings()
|
||||
append(ICON_FA_CIRCLE_EXCLAMATION,
|
||||
TRANSLATE_SV("VMManager", "Draw Buffering is enabled, this may result in graphical errors."));
|
||||
}
|
||||
if (EmuConfig.GS.UserHacks_RewriteLargeSTCoords)
|
||||
{
|
||||
append(ICON_FA_CIRCLE_EXCLAMATION,
|
||||
TRANSLATE_SV("VMManager", "Rewrite large ST is enabled, this may reduce performance."));
|
||||
}
|
||||
if (EmuConfig.GS.DumpReplaceableTextures)
|
||||
{
|
||||
append(ICON_FA_CIRCLE_EXCLAMATION,
|
||||
|
||||
+4
-1
@@ -306,6 +306,9 @@ namespace VMManager
|
||||
/// Returns true if fast booting is active (requested but ELF not started).
|
||||
bool IsFastBootInProgress();
|
||||
|
||||
// Returns the current disc/BIOS region, if set.
|
||||
std::string GetCurrentRegion();
|
||||
|
||||
/// Disables fast boot if it was requested, and found to be incompatible.
|
||||
void DisableFastBoot();
|
||||
|
||||
@@ -319,7 +322,7 @@ namespace VMManager
|
||||
void FrameRateChanged();
|
||||
|
||||
/// Throttles execution, or limits the frame rate.
|
||||
void Throttle();
|
||||
void Throttle(bool vsync_start);
|
||||
|
||||
/// Resets/clears all execution/code caches.
|
||||
void ClearCPUExecutionCaches();
|
||||
|
||||
+2
-1
@@ -237,7 +237,8 @@ public:
|
||||
// if we're using the flag hack, ignore the mac flags going in to the new block too if an exact match wasn't requested.
|
||||
if (mVUsFlagHack)
|
||||
{
|
||||
if ((ref.quick & ~0x0C04) != (quick64 & ~0x0C04)) continue;
|
||||
if ((ref.quick & ~0x3002) != (quick64 & ~0x3002))
|
||||
continue;
|
||||
}
|
||||
else if (ref.quick != quick64) continue;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user