Compare commits

...
78 Commits
Author SHA1 Message Date
lightningterror 746c5b603f GS: Try to fix -Wreorder warning. 2021-12-28 10:09:08 +01:00
qurious-pixel d0de8d22fe MISC: codacy fixes 2021-12-28 08:54:17 +00:00
qurious-pixel 231b8e9481 reference the app-variables.sh apprun-hook file 2021-12-28 08:54:17 +00:00
qurious-pixel f9f36700bb Update AppRun 2021-12-28 08:54:17 +00:00
qurious-pixel ba9fced3db Create app-variables.sh 2021-12-28 08:54:17 +00:00
Connor McLaughlin c192ecf6b7 GSDumpDialog: Cache length instead of querying every packet
Length() internally calls fseek() to end, ftell(), and fseek() back
again (really slow).

Shaves several seconds off loading large gs dumps.
2021-12-28 07:43:28 +00:00
Connor McLaughlin 6ee029e14b PAD: Add platform independent implementation 2021-12-28 05:22:45 +00:00
Connor McLaughlin 935f880fa7 USB: Fix compilation of USBNull on Windows 2021-12-28 05:22:45 +00:00
Connor McLaughlin 47d046c5fe DEV9: Prepare for Qt 2021-12-28 05:22:45 +00:00
Connor McLaughlin 4305e17cbe SPU2: Prepare for Qt (add Host wrapper) 2021-12-28 05:22:45 +00:00
Connor McLaughlin c5c4cdd0b4 PINE: Disable for Qt (for now) 2021-12-28 05:22:45 +00:00
Connor McLaughlin 252562db90 Misc: #ifdef out last bits of wx-dependent code 2021-12-28 05:22:45 +00:00
Connor McLaughlin a898682f3e Host: Add layered settings interface for per-game settings 2021-12-28 05:22:45 +00:00
Connor McLaughlin 7829094668 3rdparty: Add simpleini 2021-12-28 05:22:45 +00:00
Connor McLaughlin 042c23a545 Config: Add folder initializers 2021-12-28 05:22:45 +00:00
Connor McLaughlin af2b9e3a4c Config: Add SPU2 options to global struct 2021-12-28 05:22:45 +00:00
Connor McLaughlin b3b7c55b9a Host: Add ReportErrorAsync() and formatted variant 2021-12-28 05:22:45 +00:00
Connor McLaughlin 1859ede325 GameDatabase: Use resource abstraction to read yaml 2021-12-28 05:22:45 +00:00
Connor McLaughlin 2c32c374fb GameDatabase: Don't include rapidyaml in header
Name clashes with Qt.
2021-12-28 05:22:45 +00:00
Connor McLaughlin 65d22406a3 SettingsWrapper: Fix enums being stored as ints 2021-12-28 05:22:45 +00:00
Connor McLaughlin 92689a60ae Common/StringUtil: Add whitespace strip methods 2021-12-28 05:22:45 +00:00
Connor McLaughlin 1a598ccf0d Common/StringUtil: Add wide string conversion for non-windows 2021-12-28 05:22:45 +00:00
Italo Di Renzo e50feb74fd Add "Clear missing files" option to recent ISO list (#4975)
* GUI: Add "Clear missing files" option to Recent ISO list

* GUI: Show list of files to remove in confirmation dialog.
2021-12-27 20:50:04 -08:00
arcum42 af067a8c84 Default to a native build. Remove --clean-plugins. (#5132) 2021-12-27 20:31:27 -08:00
tellowkrinkle 61a196bc3d GS: Move afix check to high blend level 2021-12-27 20:18:47 -06:00
lightningterror 6a431daffc GS-hw: Extend Blend mix to work when alpha is higher than 1.
Clamp the alpha(As/Af) to 1 in the shader, it is already clamped to 1 in hw blend unit.
It should allow to better render the effects, still not fully accurate but it's closer to what we want.
Hopefully it helps D3D11 more.
2021-12-27 20:22:41 +01:00
Mrlinkwii 1aad3e6cc8 GameDB: add VU clamping to "Ultimate Spider-Man" and fixes to other games 2021-12-27 18:02:16 +00:00
refractionpcsx2 c8d42e32ed GameDB: Properly use vuRoundMode child node 2021-12-27 03:47:52 +00:00
refractionpcsx2 514cc6edb8 IPU: Unbreak previous change with IDEC sync
Testing in Production y'all
2021-12-26 23:44:50 +00:00
lightningterror 208d3ffa7b GS-hw: Fix pabe regression from renderers merge.
Only OpenGL should disable accumulation and blend mix to allow reading the framebuffer next.

Also pabe will only be accurate with non recursive blend on d3d11 only so enable it for it only.
2021-12-26 19:12:28 +01:00
refractionpcsx2 25dd92f8c0 IPU: Modify IDEC sync position.
Previously broke the Onimusha patch, sorry
2021-12-26 14:56:52 +00:00
Connor McLaughlin 3f81b7e56d GL/ShaderCache: Time various shader compilation tasks 2021-12-26 13:21:51 +00:00
Connor McLaughlin 99b7333991 GS/OpenGL: Add option to disable shader cache 2021-12-26 13:21:51 +00:00
Connor McLaughlin a2ae4ba441 GS/OpenGL: Get rid of interface blocks for convert shaders 2021-12-26 13:21:51 +00:00
Connor McLaughlin 4e1b2792c9 GS/OpenGL: Move some uniform buffers to program uniforms 2021-12-26 13:21:51 +00:00
Connor McLaughlin 55695bb5bc GS/OpenGL: Use ShaderCache 2021-12-26 13:21:51 +00:00
Connor McLaughlin 6e064da536 GS/OpenGL: Use programs instead of separate pipelines 2021-12-26 13:21:51 +00:00
Connor McLaughlin 69ff12645c Common: Add GL/ShaderCache 2021-12-26 13:21:51 +00:00
Connor McLaughlin efb93d22d9 Common: Add GL Program wrapper class 2021-12-26 13:21:51 +00:00
Connor McLaughlin cdb0068dcc Common: Add MD5Digest 2021-12-26 13:21:51 +00:00
Connor McLaughlin b0a0d714c4 Common: Add HashCombine.h 2021-12-26 13:21:51 +00:00
refractionpcsx2 7e36ee243c GameDB: Fix Round/Clamp nodes 2021-12-26 11:58:27 +00:00
Sergeanur 21bc56a8ba GS: Simulate scan mask 2021-12-26 11:51:25 +00:00
refractionpcsx2 e920c0fe3e VS: Fix filters 2021-12-26 10:37:43 +00:00
refractionpcsx2 31992fb398 GameDB: Fix loading patches for some games 2021-12-26 08:43:06 +00:00
refractionpcsx2 dc65599fae GameDB: Remove no longer required patches 2021-12-26 04:48:49 +00:00
refractionpcsx2 eb9dc7b70d IPU: BDEC/IDEC wait for IPU0 to drain before proceeding 2021-12-26 04:48:49 +00:00
refractionpcsx2 06bf2502a6 IPU: Tidy up and fix up toIPU DMA, remove some hacks 2021-12-26 04:48:49 +00:00
refractionpcsx2 242655bac9 IPU: Tidy up some DMA and FIFO behaviour 2021-12-26 04:48:49 +00:00
refractionpcsx2 8335b3ee77 IPU: Only fill IPU with required data, no more. 2021-12-26 04:48:49 +00:00
refractionpcsx2 a0c8ad9511 Savestate: Bump version 2021-12-26 04:48:49 +00:00
refractionpcsx2 d775a9364b IPU: Set DMA to only transfer on request (or reset) 2021-12-26 04:48:49 +00:00
Ty Lamontagne 1695124472 Linux / Windows CMake Builds: Change output executable to lowercase
No reason to be uppercase.
2021-12-25 15:11:17 +00:00
Tyler Wilding 70145eb150 macos: add undef to fix macOS builds 2021-12-25 15:11:01 +00:00
Tyler Wilding dacd7d94d9 memcard: fix saving and loading handling on new yaml lib 2021-12-25 15:11:01 +00:00
Tyler Wilding 85bd8555c0 common: add some file-path helpers to Path ns 2021-12-25 15:11:01 +00:00
Tyler Wilding 6920b4e366 gamedb: handle yaml parsing errors properly 2021-12-25 15:11:01 +00:00
Tyler Wilding bda3835cb1 memcard: migrate folder memory cards to rapidyaml 2021-12-25 15:11:01 +00:00
Tyler Wilding 83e5aa6137 gamedb: migrate GameDB implementation to rapidyaml 2021-12-25 15:11:01 +00:00
Tyler Wilding 4719e52c6e fs-api: extend host API to allow retrieval of a resource file path 2021-12-25 15:11:01 +00:00
Tyler Wilding e313eadcd2 common: pull our string functions into common 2021-12-25 15:11:01 +00:00
Tyler Wilding be952e40ba vs: update project configuration to include rapidyaml 2021-12-25 15:11:01 +00:00
Tyler Wilding 4d4b24f8b0 cmake: support rapidyaml 2021-12-25 15:11:01 +00:00
Tyler Wilding 9533fa25c3 deps: remove yaml-cpp and add rapidyaml 2021-12-25 15:11:01 +00:00
lightningterror 013c9072b9 GS-hw: Move the blend mix alpha check after sw blending selection.
Optimization.
2021-12-25 14:52:07 +01:00
lightningterror bf8dc05fac GS: Redo GetAlphaMinMax.
Cleaner this way, also fix recent regression on Full Blend with alpha max.
2021-12-25 14:52:07 +01:00
Connor McLaughlin f4b38662fa GS/Null: Move methods to cpp file 2021-12-24 11:01:00 +00:00
Connor McLaughlin ea41cce5ef GS: Add missing override specifier to a few files 2021-12-24 11:01:00 +00:00
TellowKrinkle 013c292ffb GS: Fix looping over pages of textures with massive strides 2021-12-23 19:10:19 -06:00
refractionpcsx2 cb18f11133 GS: Added auto Mipmap support in hardware for Jurassic Park 2021-12-23 08:25:52 +00:00
TellowKrinkle ea25f49c65 Common: Fix GetWorkingDirectory on unix 2021-12-23 07:49:14 +00:00
Connor McLaughlin 5d15d5958e GS: Only copy draw area for colclip/DATE 2021-12-22 11:41:57 +01:00
Connor McLaughlin efed92b15c GS/OpenGL: Move scaling factor to shader constant 2021-12-22 11:41:57 +01:00
Connor McLaughlin 7d39d02e98 GSDeviceOGL: Don't set scissor unconditionally 2021-12-22 11:41:57 +01:00
Connor McLaughlin e006442e4f GSRendererNew: Remove another constant buffer copy 2021-12-22 11:41:57 +01:00
Connor McLaughlin 212848e931 GSDevice: Force inline accessor methods
Don't want to make debug builds slower.
2021-12-22 11:41:57 +01:00
Connor McLaughlin 732de53d1b GS: Get rid of second constant buffer for alpha pass 2021-12-22 11:41:57 +01:00
Connor McLaughlin 08c00eed1e GS: Unify constant buffers between renderers 2021-12-22 11:41:57 +01:00
163 changed files with 10500 additions and 2553 deletions
-8
View File
@@ -1,14 +1,6 @@
#!/bin/bash
export LD_LIBRARY_PATH="$APPDIR/usr/lib:$LD_LIBRARY_PATH"
BINARY_NAME=$(basename "$ARGV0")
if [[ ! -e "$PWD/$BINARY_NAME.config" ]]; then
mkdir "$PWD/$BINARY_NAME.config"
fi
export XDG_CONFIG_HOME="$PWD/$BINARY_NAME.config"
ln -sf $APPDIR/usr/bin/app /tmp/PCSX2
mkdir -p $HOME/.local/share/icons/hicolor/scalable/apps && cp $APPDIR/PCSX2.png $HOME/.local/share/icons/hicolor/scalable/apps
$APPDIR/AppRun-patched
@@ -0,0 +1,10 @@
#!/bin/bash
export LD_LIBRARY_PATH="$APPDIR/usr/lib:$LD_LIBRARY_PATH"
export BINARY_NAME=$(basename "$ARGV0")
if [[ ! -e "$PWD/$BINARY_NAME.config" ]]; then
mkdir "$PWD/$BINARY_NAME.config"
fi
export XDG_CONFIG_HOME="$PWD/$BINARY_NAME.config"
mkdir -p "$HOME"/.local/share/icons/hicolor/scalable/apps && cp "$APPDIR"/PCSX2.png "$HOME"/.local/share/icons/hicolor/scalable/apps
+5 -2
View File
@@ -25,8 +25,8 @@ sudo cp /usr/local/bin/patchelf /tmp/squashfs-root/usr/bin/patchelf
cd "$GITHUB_WORKSPACE"
mkdir -p squashfs-root/usr/bin
ls -al "$BUILDBIN"
cp -P "$BUILDBIN"/PCSX2 "$GITHUB_WORKSPACE"/squashfs-root/usr/bin/
patchelf --set-rpath /tmp/PCSX2 "$GITHUB_WORKSPACE"/squashfs-root/usr/bin/PCSX2
cp -P "$BUILDBIN"/pcsx2 "$GITHUB_WORKSPACE"/squashfs-root/usr/bin/
patchelf --set-rpath /tmp/PCSX2 "$GITHUB_WORKSPACE"/squashfs-root/usr/bin/pcsx2
cp ./pcsx2/gui/Resources/AppIcon64.png ./squashfs-root/PCSX2.png
cp ./linux_various/PCSX2.desktop.in ./squashfs-root/PCSX2.desktop
sed -i -e 's|Categories=@PCSX2_MENU_CATEGORIES@|Categories=Game;Emulator;|g' ./squashfs-root/PCSX2.desktop
@@ -48,12 +48,15 @@ chmod a+x ./squashfs-root/AppRun-patched
chmod a+x ./squashfs-root/usr/optional/exec.so
echo "$name" > "$GITHUB_WORKSPACE"/squashfs-root/version.txt
mkdir -p "$GITHUB_WORKSPACE"/squashfs-root/usr/bin/app
mkdir -p "$GITHUB_WORKSPACE"/squashfs-root/apprun-hooks
cp -r "$GITHUB_WORKSPACE"/bin/Langs "$GITHUB_WORKSPACE"/squashfs-root/usr/bin/
cp -r "$GITHUB_WORKSPACE"/bin/resources "$GITHUB_WORKSPACE"/squashfs-root/usr/bin/app/
cp "$GITHUB_WORKSPACE"/bin/docs/{Configuration_Guide.pdf,PCSX2_FAQ.pdf} "$GITHUB_WORKSPACE"/squashfs-root/usr/bin/app
cp /usr/lib/$LIBARCH/libthai.so.0 "$GITHUB_WORKSPACE"/squashfs-root/usr/lib/
cp --dereference /usr/lib/"$LIBARCH"/libstdc++.so.6 "$GITHUB_WORKSPACE"/squashfs-root/usr/optional/libstdc++/libstdc++.so.6
cp --dereference /lib/"$LIBARCH"/libgcc_s.so.1 "$GITHUB_WORKSPACE"/squashfs-root/usr/optional/libgcc_s/libgcc_s.so.1
chmod +x .github/workflows/scripts/linux/app-variables.sh
cp .github/workflows/scripts/linux/app-variables.sh "$GITHUB_WORKSPACE"/squashfs-root/apprun-hooks
export UPD_INFO="gh-releases-zsync|PCSX2|pcsx2|latest|$name.AppImage.zsync"
export OUTPUT="$name.AppImage"
/tmp/squashfs-root/AppRun --appdir="$GITHUB_WORKSPACE"/squashfs-root/ --plugin gtk -d "$GITHUB_WORKSPACE"/squashfs-root/PCSX2.desktop -i "$GITHUB_WORKSPACE"/squashfs-root/PCSX2.png --output appimage
+1 -1
View File
@@ -121,7 +121,7 @@ jobs:
Release) SIMD="SSE4";;
*AVX2) SIMD="AVX2";;
CMake) SIMD="CMake"
cp build/pcsx2/PCSX2* bin/ ;;
cp build/pcsx2/pcsx2* bin/ ;;
*) SIMD="UNKNOWN";;
esac
if [ ${{ github.event_name }} == "pull_request" ]; then
+1 -2
View File
@@ -73,10 +73,9 @@ oprofile_data/
/bin/**/*.ilk
/bin/**/*.lib
/bin/**/*.pdb
/bin/PCSX2
/bin/pcsx2
/bin/PCSX2-linux.sh
/bin/*ReplayLoader
/bin/PCSX2-linux.sh
/bin/GS*.txt
/bin/bios
/bin/cache
+4 -3
View File
@@ -7,9 +7,6 @@
[submodule "3rdparty/fmt/fmt"]
path = 3rdparty/fmt/fmt
url = https://github.com/fmtlib/fmt.git
[submodule "3rdparty/yaml-cpp/yaml-cpp"]
path = 3rdparty/yaml-cpp/yaml-cpp
url = https://github.com/jbeder/yaml-cpp.git
[submodule "3rdparty/libchdr/libchdr"]
path = 3rdparty/libchdr/libchdr
url = https://github.com/rtissera/libchdr.git
@@ -20,3 +17,7 @@
[submodule "3rdparty/cubeb/cubeb"]
path = 3rdparty/cubeb/cubeb
url = https://github.com/mozilla/cubeb.git
[submodule "3rdparty/rapidyaml/rapidyaml"]
path = 3rdparty/rapidyaml/rapidyaml
url = https://github.com/biojppm/rapidyaml.git
branch = master
+143
View File
@@ -0,0 +1,143 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(SolutionDir)common\vsprops\BaseProjectConfig.props" />
<Import Project="$(SolutionDir)common\vsprops\WinSDK.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{DE9653B6-17DD-356A-9EE0-28A731772587}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization Condition="$(Configuration.Contains(Release))">true</WholeProgramOptimization>
<UseDebugLibraries Condition="$(Configuration.Contains(Debug))">true</UseDebugLibraries>
<UseDebugLibraries Condition="!$(Configuration.Contains(Debug))">false</UseDebugLibraries>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="PropertySheets">
<Import Project="..\DefaultProjectRootDir.props" />
<Import Project="..\3rdparty.props" />
<Import Condition="$(Configuration.Contains(Debug))" Project="..\..\common\vsprops\CodeGen_Debug.props" />
<Import Condition="$(Configuration.Contains(Devel))" Project="..\..\common\vsprops\CodeGen_Devel.props" />
<Import Condition="$(Configuration.Contains(Release))" Project="..\..\common\vsprops\CodeGen_Release.props" />
<Import Condition="!$(Configuration.Contains(Release))" Project="..\..\common\vsprops\IncrementalLinking.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>TurnOffAllWarnings</WarningLevel>
<AdditionalIncludeDirectories>$(ProjectDir)/rapidyaml/src;$(ProjectDir)/rapidyaml/ext/c4core/src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="$(Configuration.Contains(Debug))">
<ClCompile>
<PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;_WINDOWS</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="!$(Configuration.Contains(Debug))">
<ClCompile>
<PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;_WINDOWS;NDEBUG</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="rapidyaml\src\ryml.hpp" />
<ClInclude Include="rapidyaml\src\ryml_std.hpp" />
<ClInclude Include="rapidyaml\src\c4\yml\detail\checks.hpp" />
<ClInclude Include="rapidyaml\src\c4\yml\detail\parser_dbg.hpp" />
<ClInclude Include="rapidyaml\src\c4\yml\detail\stack.hpp" />
<ClInclude Include="rapidyaml\src\c4\yml\common.hpp" />
<ClCompile Include="rapidyaml\src\c4\yml\common.cpp" />
<ClInclude Include="rapidyaml\src\c4\yml\emit.def.hpp" />
<ClInclude Include="rapidyaml\src\c4\yml\emit.hpp" />
<ClInclude Include="rapidyaml\src\c4\yml\export.hpp" />
<ClInclude Include="rapidyaml\src\c4\yml\node.hpp" />
<ClCompile Include="rapidyaml\src\c4\yml\node.cpp" />
<ClInclude Include="rapidyaml\src\c4\yml\parse.hpp" />
<ClCompile Include="rapidyaml\src\c4\yml\parse.cpp" />
<ClInclude Include="rapidyaml\src\c4\yml\preprocess.hpp" />
<ClCompile Include="rapidyaml\src\c4\yml\preprocess.cpp" />
<ClInclude Include="rapidyaml\src\c4\yml\std\map.hpp" />
<ClInclude Include="rapidyaml\src\c4\yml\std\std.hpp" />
<ClInclude Include="rapidyaml\src\c4\yml\std\string.hpp" />
<ClInclude Include="rapidyaml\src\c4\yml\std\vector.hpp" />
<ClInclude Include="rapidyaml\src\c4\yml\tree.hpp" />
<ClCompile Include="rapidyaml\src\c4\yml\tree.cpp" />
<ClInclude Include="rapidyaml\src\c4\yml\writer.hpp" />
<ClInclude Include="rapidyaml\src\c4\yml\yml.hpp" />
<Natvis Include="rapidyaml\src\ryml.natvis">
</Natvis>
<ClInclude Include="rapidyaml\ext\c4core\src\c4\allocator.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\base64.hpp" />
<ClCompile Include="rapidyaml\ext\c4core\src\c4\base64.cpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\blob.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\bitmask.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\charconv.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\c4_pop.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\c4_push.hpp" />
<ClCompile Include="rapidyaml\ext\c4core\src\c4\char_traits.cpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\char_traits.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\common.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\compiler.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\config.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\cpu.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ctor_dtor.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\enum.hpp" />
<ClCompile Include="rapidyaml\ext\c4core\src\c4\error.cpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\error.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\export.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\format.hpp" />
<ClCompile Include="rapidyaml\ext\c4core\src\c4\format.cpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\hash.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\language.hpp" />
<ClCompile Include="rapidyaml\ext\c4core\src\c4\language.cpp" />
<ClCompile Include="rapidyaml\ext\c4core\src\c4\memory_resource.cpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\memory_resource.hpp" />
<ClCompile Include="rapidyaml\ext\c4core\src\c4\memory_util.cpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\memory_util.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\platform.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\preprocessor.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\restrict.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\span.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\std\std.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\std\string.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\std\tuple.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\std\vector.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\substr.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\substr_fwd.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\szconv.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\time.hpp" />
<ClCompile Include="rapidyaml\ext\c4core\src\c4\time.cpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\type_name.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\types.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\unrestrict.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\windows.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\windows_pop.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\windows_push.hpp" />
<Natvis Include="rapidyaml\ext\c4core\src\c4\c4core.natvis">
</Natvis>
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\debugbreak\debugbreak.h" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\rng\rng.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\sg14\inplace_function.h" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\fast_float.hpp" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\fast_float\include\fast_float\ascii_number.h" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\fast_float\include\fast_float\bigint.h" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\fast_float\include\fast_float\decimal_to_binary.h" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\fast_float\include\fast_float\digit_comparison.h" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\fast_float\include\fast_float\fast_float.h" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\fast_float\include\fast_float\fast_table.h" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\fast_float\include\fast_float\float_common.h" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\fast_float\include\fast_float\parse_number.h" />
<ClInclude Include="rapidyaml\ext\c4core\src\c4\ext\fast_float\include\fast_float\simple_decimal_conversion.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+9
View File
@@ -0,0 +1,9 @@
set(SRCS
include/ConvertUTF.h
include/SimpleIni.h
src/ConvertUTF.c
)
add_library(simpleini ${SRCS})
target_include_directories(simpleini PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/src")
target_include_directories(simpleini INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include")
+20
View File
@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2006-2013 Brodie Thiesfield
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+149
View File
@@ -0,0 +1,149 @@
/*
* Copyright 2001-2004 Unicode, Inc.
*
* Disclaimer
*
* This source code is provided as is by Unicode, Inc. No claims are
* made as to fitness for any particular purpose. No warranties of any
* kind are expressed or implied. The recipient agrees to determine
* applicability of information provided. If this file has been
* purchased on magnetic or optical media from Unicode, Inc., the
* sole remedy for any claim will be exchange of defective media
* within 90 days of receipt.
*
* Limitations on Rights to Redistribute This Code
*
* Unicode, Inc. hereby grants the right to freely use the information
* supplied in this file in the creation of products supporting the
* Unicode Standard, and to make copies of this file in any form
* for internal or external distribution as long as this notice
* remains attached.
*/
/* ---------------------------------------------------------------------
Conversions between UTF32, UTF-16, and UTF-8. Header file.
Several funtions are included here, forming a complete set of
conversions between the three formats. UTF-7 is not included
here, but is handled in a separate source file.
Each of these routines takes pointers to input buffers and output
buffers. The input buffers are const.
Each routine converts the text between *sourceStart and sourceEnd,
putting the result into the buffer between *targetStart and
targetEnd. Note: the end pointers are *after* the last item: e.g.
*(sourceEnd - 1) is the last item.
The return result indicates whether the conversion was successful,
and if not, whether the problem was in the source or target buffers.
(Only the first encountered problem is indicated.)
After the conversion, *sourceStart and *targetStart are both
updated to point to the end of last text successfully converted in
the respective buffers.
Input parameters:
sourceStart - pointer to a pointer to the source buffer.
The contents of this are modified on return so that
it points at the next thing to be converted.
targetStart - similarly, pointer to pointer to the target buffer.
sourceEnd, targetEnd - respectively pointers to the ends of the
two buffers, for overflow checking only.
These conversion functions take a ConversionFlags argument. When this
flag is set to strict, both irregular sequences and isolated surrogates
will cause an error. When the flag is set to lenient, both irregular
sequences and isolated surrogates are converted.
Whether the flag is strict or lenient, all illegal sequences will cause
an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
must check for illegal sequences.
When the flag is set to lenient, characters over 0x10FFFF are converted
to the replacement character; otherwise (when the flag is set to strict)
they constitute an error.
Output parameters:
The value "sourceIllegal" is returned from some routines if the input
sequence is malformed. When "sourceIllegal" is returned, the source
value will point to the illegal value that caused the problem. E.g.,
in UTF-8 when a sequence is malformed, it points to the start of the
malformed sequence.
Author: Mark E. Davis, 1994.
Rev History: Rick McGowan, fixes & updates May 2001.
Fixes & updates, Sept 2001.
------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------
The following 4 definitions are compiler-specific.
The C standard does not guarantee that wchar_t has at least
16 bits, so wchar_t is no less portable than unsigned short!
All should be unsigned values to avoid sign extension during
bit mask & shift operations.
------------------------------------------------------------------------ */
typedef unsigned int UTF32; /* at least 32 bits */
typedef unsigned short UTF16; /* at least 16 bits */
typedef unsigned char UTF8; /* typically 8 bits */
typedef unsigned char Boolean; /* 0 or 1 */
/* Some fundamental constants */
#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
#define UNI_MAX_BMP (UTF32)0x0000FFFF
#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
typedef enum {
conversionOK, /* conversion successful */
sourceExhausted, /* partial character in source, but hit end */
targetExhausted, /* insuff. room in target for conversion */
sourceIllegal /* source sequence is illegal/malformed */
} ConversionResult;
typedef enum {
strictConversion = 0,
lenientConversion
} ConversionFlags;
/* This is for C++ and does no harm in C */
#ifdef __cplusplus
extern "C" {
#endif
ConversionResult ConvertUTF8toUTF16 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF16toUTF8 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF8toUTF32 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF32toUTF8 (
const UTF32** sourceStart, const UTF32* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF16toUTF32 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF32toUTF16 (
const UTF32** sourceStart, const UTF32* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
#ifdef __cplusplus
}
#endif
/* --------------------------------------------------------------------- */
File diff suppressed because it is too large Load Diff
+47
View File
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(SolutionDir)common\vsprops\BaseProjectConfig.props" />
<Import Project="$(SolutionDir)common\vsprops\WinSDK.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization Condition="$(Configuration.Contains(Release))">true</WholeProgramOptimization>
<UseDebugLibraries Condition="$(Configuration.Contains(Debug))">true</UseDebugLibraries>
<UseDebugLibraries Condition="!$(Configuration.Contains(Debug))">false</UseDebugLibraries>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="PropertySheets">
<Import Project="..\DefaultProjectRootDir.props" />
<Import Project="..\3rdparty.props" />
<Import Condition="$(Configuration.Contains(Debug))" Project="..\..\common\vsprops\CodeGen_Debug.props" />
<Import Condition="$(Configuration.Contains(Devel))" Project="..\..\common\vsprops\CodeGen_Devel.props" />
<Import Condition="$(Configuration.Contains(Release))" Project="..\..\common\vsprops\CodeGen_Release.props" />
<Import Condition="!$(Configuration.Contains(Release))" Project="..\..\common\vsprops\IncrementalLinking.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>TurnOffAllWarnings</WarningLevel>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="src\ConvertUTF.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\ConvertUTF.h" />
<ClInclude Include="include\SimpleIni.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="src\ConvertUTF.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\SimpleIni.h" />
<ClInclude Include="include\ConvertUTF.h" />
</ItemGroup>
</Project>
+539
View File
@@ -0,0 +1,539 @@
/*
* Copyright 2001-2004 Unicode, Inc.
*
* Disclaimer
*
* This source code is provided as is by Unicode, Inc. No claims are
* made as to fitness for any particular purpose. No warranties of any
* kind are expressed or implied. The recipient agrees to determine
* applicability of information provided. If this file has been
* purchased on magnetic or optical media from Unicode, Inc., the
* sole remedy for any claim will be exchange of defective media
* within 90 days of receipt.
*
* Limitations on Rights to Redistribute This Code
*
* Unicode, Inc. hereby grants the right to freely use the information
* supplied in this file in the creation of products supporting the
* Unicode Standard, and to make copies of this file in any form
* for internal or external distribution as long as this notice
* remains attached.
*/
/* ---------------------------------------------------------------------
Conversions between UTF32, UTF-16, and UTF-8. Source code file.
Author: Mark E. Davis, 1994.
Rev History: Rick McGowan, fixes & updates May 2001.
Sept 2001: fixed const & error conditions per
mods suggested by S. Parent & A. Lillich.
June 2002: Tim Dodd added detection and handling of incomplete
source sequences, enhanced error detection, added casts
to eliminate compiler warnings.
July 2003: slight mods to back out aggressive FFFE detection.
Jan 2004: updated switches in from-UTF8 conversions.
Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
See the header file "ConvertUTF.h" for complete documentation.
------------------------------------------------------------------------ */
#include "ConvertUTF.h"
#ifdef CVTUTF_DEBUG
#include <stdio.h>
#endif
static const int halfShift = 10; /* used for shifting by 10 bits */
static const UTF32 halfBase = 0x0010000UL;
static const UTF32 halfMask = 0x3FFUL;
#define UNI_SUR_HIGH_START (UTF32)0xD800
#define UNI_SUR_HIGH_END (UTF32)0xDBFF
#define UNI_SUR_LOW_START (UTF32)0xDC00
#define UNI_SUR_LOW_END (UTF32)0xDFFF
#define false 0
#define true 1
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF32toUTF16 (
const UTF32** sourceStart, const UTF32* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF32* source = *sourceStart;
UTF16* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch;
if (target >= targetEnd) {
result = targetExhausted; break;
}
ch = *source++;
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
/* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
if (flags == strictConversion) {
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
*target++ = (UTF16)ch; /* normal case */
}
} else if (ch > UNI_MAX_LEGAL_UTF32) {
if (flags == strictConversion) {
result = sourceIllegal;
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
/* target is a character in range 0xFFFF - 0x10FFFF. */
if (target + 1 >= targetEnd) {
--source; /* Back up source pointer! */
result = targetExhausted; break;
}
ch -= halfBase;
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
}
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF16toUTF32 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF16* source = *sourceStart;
UTF32* target = *targetStart;
UTF32 ch, ch2;
while (source < sourceEnd) {
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
ch = *source++;
/* If we have a surrogate pair, convert to UTF32 first. */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
/* If the 16 bits following the high surrogate are in the source buffer... */
if (source < sourceEnd) {
ch2 = *source;
/* If it's a low surrogate, convert to UTF32. */
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
++source;
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
} else { /* We don't have the 16 bits following the high surrogate. */
--source; /* return to the high surrogate */
result = sourceExhausted;
break;
}
} else if (flags == strictConversion) {
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
if (target >= targetEnd) {
source = oldSource; /* Back up source pointer! */
result = targetExhausted; break;
}
*target++ = ch;
}
*sourceStart = source;
*targetStart = target;
#ifdef CVTUTF_DEBUG
if (result == sourceIllegal) {
fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
fflush(stderr);
}
#endif
return result;
}
/* --------------------------------------------------------------------- */
/*
* Index into the table below with the first byte of a UTF-8 sequence to
* get the number of trailing bytes that are supposed to follow it.
* Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
* left as-is for anyone who may want to do such conversion, which was
* allowed in earlier algorithms.
*/
static const char trailingBytesForUTF8[256] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
};
/*
* Magic values subtracted from a buffer value during UTF8 conversion.
* This table contains as many values as there might be trailing bytes
* in a UTF-8 sequence.
*/
static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
0x03C82080UL, 0xFA082080UL, 0x82082080UL };
/*
* Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
* into the first byte, depending on how many bytes follow. There are
* as many entries in this table as there are UTF-8 sequence types.
* (I.e., one byte sequence, two byte... etc.). Remember that sequencs
* for *legal* UTF-8 will be 4 or fewer bytes total.
*/
static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
/* --------------------------------------------------------------------- */
/* The interface converts a whole buffer to avoid function-call overhead.
* Constants have been gathered. Loops & conditionals have been removed as
* much as possible for efficiency, in favor of drop-through switches.
* (See "Note A" at the bottom of the file for equivalent code.)
* If your compiler supports it, the "isLegalUTF8" call can be turned
* into an inline function.
*/
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF16toUTF8 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF16* source = *sourceStart;
UTF8* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch;
unsigned short bytesToWrite = 0;
const UTF32 byteMask = 0xBF;
const UTF32 byteMark = 0x80;
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
ch = *source++;
/* If we have a surrogate pair, convert to UTF32 first. */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
/* If the 16 bits following the high surrogate are in the source buffer... */
if (source < sourceEnd) {
UTF32 ch2 = *source;
/* If it's a low surrogate, convert to UTF32. */
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
++source;
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
} else { /* We don't have the 16 bits following the high surrogate. */
--source; /* return to the high surrogate */
result = sourceExhausted;
break;
}
} else if (flags == strictConversion) {
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
/* Figure out how many bytes the result will require */
if (ch < (UTF32)0x80) { bytesToWrite = 1;
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
} else if (ch < (UTF32)0x110000) { bytesToWrite = 4;
} else { bytesToWrite = 3;
ch = UNI_REPLACEMENT_CHAR;
}
target += bytesToWrite;
if (target > targetEnd) {
source = oldSource; /* Back up source pointer! */
target -= bytesToWrite; result = targetExhausted; break;
}
switch (bytesToWrite) { /* note: everything falls through. */
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
}
target += bytesToWrite;
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
/*
* Utility routine to tell whether a sequence of bytes is legal UTF-8.
* This must be called with the length pre-determined by the first byte.
* If not calling this from ConvertUTF8to*, then the length can be set by:
* length = trailingBytesForUTF8[*source]+1;
* and the sequence is illegal right away if there aren't that many bytes
* available.
* If presented with a length > 4, this returns false. The Unicode
* definition of UTF-8 goes up to 4-byte sequences.
*/
static Boolean isLegalUTF8(const UTF8 *source, int length) {
UTF8 a;
const UTF8 *srcptr = source+length;
switch (length) {
default: return false;
/* Everything else falls through when "true"... */
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
case 2: if ((a = (*--srcptr)) > 0xBF) return false;
switch (*source) {
/* no fall-through in this inner switch */
case 0xE0: if (a < 0xA0) return false; break;
case 0xED: if (a > 0x9F) return false; break;
case 0xF0: if (a < 0x90) return false; break;
case 0xF4: if (a > 0x8F) return false; break;
default: if (a < 0x80) return false;
}
case 1: if (*source >= 0x80 && *source < 0xC2) return false;
}
if (*source > 0xF4) return false;
return true;
}
/* --------------------------------------------------------------------- */
/*
* Exported function to return whether a UTF-8 sequence is legal or not.
* This is not used here; it's just exported.
*/
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
int length = trailingBytesForUTF8[*source]+1;
if (source+length > sourceEnd) {
return false;
}
return isLegalUTF8(source, length);
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF8toUTF16 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF8* source = *sourceStart;
UTF16* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch = 0;
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
if (source + extraBytesToRead >= sourceEnd) {
result = sourceExhausted; break;
}
/* Do this check whether lenient or strict */
if (! isLegalUTF8(source, extraBytesToRead+1)) {
result = sourceIllegal;
break;
}
/*
* The cases all fall through. See "Note A" below.
*/
switch (extraBytesToRead) {
case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
case 3: ch += *source++; ch <<= 6;
case 2: ch += *source++; ch <<= 6;
case 1: ch += *source++; ch <<= 6;
case 0: ch += *source++;
}
ch -= offsetsFromUTF8[extraBytesToRead];
if (target >= targetEnd) {
source -= (extraBytesToRead+1); /* Back up source pointer! */
result = targetExhausted; break;
}
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
if (flags == strictConversion) {
source -= (extraBytesToRead+1); /* return to the illegal value itself */
result = sourceIllegal;
break;
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
*target++ = (UTF16)ch; /* normal case */
}
} else if (ch > UNI_MAX_UTF16) {
if (flags == strictConversion) {
result = sourceIllegal;
source -= (extraBytesToRead+1); /* return to the start */
break; /* Bail out; shouldn't continue */
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
/* target is a character in range 0xFFFF - 0x10FFFF. */
if (target + 1 >= targetEnd) {
source -= (extraBytesToRead+1); /* Back up source pointer! */
result = targetExhausted; break;
}
ch -= halfBase;
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
}
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF32toUTF8 (
const UTF32** sourceStart, const UTF32* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF32* source = *sourceStart;
UTF8* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch;
unsigned short bytesToWrite = 0;
const UTF32 byteMask = 0xBF;
const UTF32 byteMark = 0x80;
ch = *source++;
if (flags == strictConversion ) {
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
/*
* Figure out how many bytes the result will require. Turn any
* illegally large UTF32 things (> Plane 17) into replacement chars.
*/
if (ch < (UTF32)0x80) { bytesToWrite = 1;
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
} else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4;
} else { bytesToWrite = 3;
ch = UNI_REPLACEMENT_CHAR;
result = sourceIllegal;
}
target += bytesToWrite;
if (target > targetEnd) {
--source; /* Back up source pointer! */
target -= bytesToWrite; result = targetExhausted; break;
}
switch (bytesToWrite) { /* note: everything falls through. */
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
}
target += bytesToWrite;
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF8toUTF32 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF8* source = *sourceStart;
UTF32* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch = 0;
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
if (source + extraBytesToRead >= sourceEnd) {
result = sourceExhausted; break;
}
/* Do this check whether lenient or strict */
if (! isLegalUTF8(source, extraBytesToRead+1)) {
result = sourceIllegal;
break;
}
/*
* The cases all fall through. See "Note A" below.
*/
switch (extraBytesToRead) {
case 5: ch += *source++; ch <<= 6;
case 4: ch += *source++; ch <<= 6;
case 3: ch += *source++; ch <<= 6;
case 2: ch += *source++; ch <<= 6;
case 1: ch += *source++; ch <<= 6;
case 0: ch += *source++;
}
ch -= offsetsFromUTF8[extraBytesToRead];
if (target >= targetEnd) {
source -= (extraBytesToRead+1); /* Back up the source pointer! */
result = targetExhausted; break;
}
if (ch <= UNI_MAX_LEGAL_UTF32) {
/*
* UTF-16 surrogate values are illegal in UTF-32, and anything
* over Plane 17 (> 0x10FFFF) is illegal.
*/
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
if (flags == strictConversion) {
source -= (extraBytesToRead+1); /* return to the illegal value itself */
result = sourceIllegal;
break;
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
*target++ = ch;
}
} else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
result = sourceIllegal;
*target++ = UNI_REPLACEMENT_CHAR;
}
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* ---------------------------------------------------------------------
Note A.
The fall-through switches in UTF-8 reading code save a
temp variable, some decrements & conditionals. The switches
are equivalent to the following loop:
{
int tmpBytesToRead = extraBytesToRead+1;
do {
ch += *source++;
--tmpBytesToRead;
if (tmpBytesToRead) ch <<= 6;
} while (tmpBytesToRead > 0);
}
In UTF-8 writing code, the switches on "bytesToWrite" are
similarly unrolled loops.
--------------------------------------------------------------------- */
-75
View File
@@ -1,75 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(SolutionDir)common\vsprops\BaseProjectConfig.props" />
<Import Project="$(SolutionDir)common\vsprops\WinSDK.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{48329442-E41B-4A1F-8364-36EEE1B71343}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization Condition="$(Configuration.Contains(Release))">true</WholeProgramOptimization>
<UseDebugLibraries Condition="$(Configuration.Contains(Debug))">true</UseDebugLibraries>
<UseDebugLibraries Condition="!$(Configuration.Contains(Debug))">false</UseDebugLibraries>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="PropertySheets">
<Import Project="..\DefaultProjectRootDir.props" />
<Import Project="..\3rdparty.props" />
<Import Condition="$(Configuration.Contains(Debug))" Project="..\..\common\vsprops\CodeGen_Debug.props" />
<Import Condition="$(Configuration.Contains(Devel))" Project="..\..\common\vsprops\CodeGen_Devel.props" />
<Import Condition="$(Configuration.Contains(Release))" Project="..\..\common\vsprops\CodeGen_Release.props" />
<Import Condition="!$(Configuration.Contains(Release))" Project="..\..\common\vsprops\IncrementalLinking.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>TurnOffAllWarnings</WarningLevel>
<AdditionalIncludeDirectories>$(ProjectDir)/yaml-cpp/include/;$(ProjectDir)/yaml-cpp/src/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="yaml-cpp\src\contrib\graphbuilder.cpp" />
<ClCompile Include="yaml-cpp\src\contrib\graphbuilderadapter.cpp" />
<ClCompile Include="yaml-cpp\src\binary.cpp" />
<ClCompile Include="yaml-cpp\src\convert.cpp" />
<ClCompile Include="yaml-cpp\src\depthguard.cpp" />
<ClCompile Include="yaml-cpp\src\directives.cpp" />
<ClCompile Include="yaml-cpp\src\emit.cpp" />
<ClCompile Include="yaml-cpp\src\emitfromevents.cpp" />
<ClCompile Include="yaml-cpp\src\emitter.cpp" />
<ClCompile Include="yaml-cpp\src\emitterstate.cpp" />
<ClCompile Include="yaml-cpp\src\emitterutils.cpp" />
<ClCompile Include="yaml-cpp\src\exceptions.cpp" />
<ClCompile Include="yaml-cpp\src\exp.cpp" />
<ClCompile Include="yaml-cpp\src\memory.cpp" />
<ClCompile Include="yaml-cpp\src\node.cpp" />
<ClCompile Include="yaml-cpp\src\node_data.cpp" />
<ClCompile Include="yaml-cpp\src\nodebuilder.cpp" />
<ClCompile Include="yaml-cpp\src\nodeevents.cpp" />
<ClCompile Include="yaml-cpp\src\null.cpp" />
<ClCompile Include="yaml-cpp\src\ostream_wrapper.cpp" />
<ClCompile Include="yaml-cpp\src\parse.cpp" />
<ClCompile Include="yaml-cpp\src\parser.cpp" />
<ClCompile Include="yaml-cpp\src\regex_yaml.cpp" />
<ClCompile Include="yaml-cpp\src\scanner.cpp" />
<ClCompile Include="yaml-cpp\src\scanscalar.cpp" />
<ClCompile Include="yaml-cpp\src\scantag.cpp" />
<ClCompile Include="yaml-cpp\src\scantoken.cpp" />
<ClCompile Include="yaml-cpp\src\simplekey.cpp" />
<ClCompile Include="yaml-cpp\src\singledocparser.cpp" />
<ClCompile Include="yaml-cpp\src\stream.cpp" />
<ClCompile Include="yaml-cpp\src\tag.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>
+54 -28
View File
@@ -1,4 +1,4 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31606.5
@@ -48,8 +48,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "3rdparty\fmt\fmt.vcx
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsamplerate", "3rdparty\libsamplerate\libsamplerate.vcxproj", "{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yaml", "3rdparty\yaml-cpp\yaml.vcxproj", "{48329442-E41B-4A1F-8364-36EEE1B71343}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libchdr", "3rdparty\libchdr\libchdr.vcxproj", "{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jpgd", "3rdparty\jpgd\jpgd.vcxproj", "{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63}"
@@ -58,8 +56,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "common\common.vcx
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glad", "3rdparty\glad\glad.vcxproj", "{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ryml", "3rdparty\rapidyaml\ryml.vcxproj", "{DE9653B6-17DD-356A-9EE0-28A731772587}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cubeb", "3rdparty\cubeb\cubeb.vcxproj", "{BF74C473-DC04-44B3-92E8-4145F4E77342}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simpleini", "3rdparty\simpleini\simpleini.vcxproj", "{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug AVX2|Win32 = Debug AVX2|Win32
@@ -460,30 +461,6 @@ Global
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release|Win32.Build.0 = Release|Win32
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release|x64.ActiveCfg = Release|x64
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F}.Release|x64.Build.0 = Release|x64
{48329442-E41B-4A1F-8364-36EEE1B71343}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{48329442-E41B-4A1F-8364-36EEE1B71343}.Debug AVX2|Win32.Build.0 = Debug|Win32
{48329442-E41B-4A1F-8364-36EEE1B71343}.Debug AVX2|x64.ActiveCfg = Debug|x64
{48329442-E41B-4A1F-8364-36EEE1B71343}.Debug AVX2|x64.Build.0 = Debug|x64
{48329442-E41B-4A1F-8364-36EEE1B71343}.Debug|Win32.ActiveCfg = Debug|Win32
{48329442-E41B-4A1F-8364-36EEE1B71343}.Debug|Win32.Build.0 = Debug|Win32
{48329442-E41B-4A1F-8364-36EEE1B71343}.Debug|x64.ActiveCfg = Debug|x64
{48329442-E41B-4A1F-8364-36EEE1B71343}.Debug|x64.Build.0 = Debug|x64
{48329442-E41B-4A1F-8364-36EEE1B71343}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{48329442-E41B-4A1F-8364-36EEE1B71343}.Devel AVX2|Win32.Build.0 = Devel|Win32
{48329442-E41B-4A1F-8364-36EEE1B71343}.Devel AVX2|x64.ActiveCfg = Devel|x64
{48329442-E41B-4A1F-8364-36EEE1B71343}.Devel AVX2|x64.Build.0 = Devel|x64
{48329442-E41B-4A1F-8364-36EEE1B71343}.Devel|Win32.ActiveCfg = Devel|Win32
{48329442-E41B-4A1F-8364-36EEE1B71343}.Devel|Win32.Build.0 = Devel|Win32
{48329442-E41B-4A1F-8364-36EEE1B71343}.Devel|x64.ActiveCfg = Devel|x64
{48329442-E41B-4A1F-8364-36EEE1B71343}.Devel|x64.Build.0 = Devel|x64
{48329442-E41B-4A1F-8364-36EEE1B71343}.Release AVX2|Win32.ActiveCfg = Release|Win32
{48329442-E41B-4A1F-8364-36EEE1B71343}.Release AVX2|Win32.Build.0 = Release|Win32
{48329442-E41B-4A1F-8364-36EEE1B71343}.Release AVX2|x64.ActiveCfg = Release|x64
{48329442-E41B-4A1F-8364-36EEE1B71343}.Release AVX2|x64.Build.0 = Release|x64
{48329442-E41B-4A1F-8364-36EEE1B71343}.Release|Win32.ActiveCfg = Release|Win32
{48329442-E41B-4A1F-8364-36EEE1B71343}.Release|Win32.Build.0 = Release|Win32
{48329442-E41B-4A1F-8364-36EEE1B71343}.Release|x64.ActiveCfg = Release|x64
{48329442-E41B-4A1F-8364-36EEE1B71343}.Release|x64.Build.0 = Release|x64
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug AVX2|Win32.Build.0 = Debug|Win32
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}.Debug AVX2|x64.ActiveCfg = Debug|x64
@@ -580,6 +557,30 @@ Global
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release|Win32.Build.0 = Release|Win32
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release|x64.ActiveCfg = Release|x64
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}.Release|x64.Build.0 = Release|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug AVX2|Win32.Build.0 = Debug|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug AVX2|x64.ActiveCfg = Debug|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug AVX2|x64.Build.0 = Debug|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug|Win32.ActiveCfg = Debug|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug|Win32.Build.0 = Debug|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug|x64.ActiveCfg = Debug|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Debug|x64.Build.0 = Debug|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel AVX2|Win32.Build.0 = Devel|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel AVX2|x64.ActiveCfg = Devel|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel AVX2|x64.Build.0 = Devel|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel|Win32.ActiveCfg = Devel|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel|Win32.Build.0 = Devel|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel|x64.ActiveCfg = Devel|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Devel|x64.Build.0 = Devel|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release AVX2|Win32.ActiveCfg = Release|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release AVX2|Win32.Build.0 = Release|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release AVX2|x64.ActiveCfg = Release|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release AVX2|x64.Build.0 = Release|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release|Win32.ActiveCfg = Release|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release|Win32.Build.0 = Release|Win32
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release|x64.ActiveCfg = Release|x64
{DE9653B6-17DD-356A-9EE0-28A731772587}.Release|x64.Build.0 = Release|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug AVX2|Win32.Build.0 = Debug|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Debug AVX2|x64.ActiveCfg = Debug|x64
@@ -604,6 +605,30 @@ Global
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release|Win32.Build.0 = Release|Win32
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release|x64.ActiveCfg = Release|x64
{BF74C473-DC04-44B3-92E8-4145F4E77342}.Release|x64.Build.0 = Release|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug AVX2|Win32.ActiveCfg = Debug|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug AVX2|Win32.Build.0 = Debug|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug AVX2|x64.ActiveCfg = Debug|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug AVX2|x64.Build.0 = Debug|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug|Win32.ActiveCfg = Debug|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug|Win32.Build.0 = Debug|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug|x64.ActiveCfg = Debug|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug|x64.Build.0 = Debug|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel AVX2|Win32.ActiveCfg = Devel|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel AVX2|Win32.Build.0 = Devel|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel AVX2|x64.ActiveCfg = Devel|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel AVX2|x64.Build.0 = Devel|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel|Win32.ActiveCfg = Devel|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel|Win32.Build.0 = Devel|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel|x64.ActiveCfg = Devel|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Devel|x64.Build.0 = Devel|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release AVX2|Win32.ActiveCfg = Release|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release AVX2|Win32.Build.0 = Release|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release AVX2|x64.ActiveCfg = Release|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release AVX2|x64.Build.0 = Release|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release|Win32.ActiveCfg = Release|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release|Win32.Build.0 = Release|Win32
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release|x64.ActiveCfg = Release|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -624,11 +649,12 @@ Global
{12728250-16EC-4DC6-94D7-E21DD88947F8} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{449AD25E-424A-4714-BABC-68706CDCC33B} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{48329442-E41B-4A1F-8364-36EEE1B71343} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{ED2F21FD-0A36-4A8F-9B90-E7D92A2ACB63} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{DE9653B6-17DD-356A-9EE0-28A731772587} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{BF74C473-DC04-44B3-92E8-4145F4E77342} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0BC474EA-3628-45D3-9DBC-E22D0B7E0F77}
+59 -65
View File
@@ -1957,6 +1957,8 @@ SCES-50000:
name: "Ridge Racer V"
region: "PAL-M5"
compat: 5
clampModes:
vuClampMode: 2 # Fixes texture rendering in the intro.
SCES-50001:
name: "Tekken Tag Tournament"
region: "PAL-M5"
@@ -2054,6 +2056,8 @@ SCES-50354:
clampModes:
eeClampMode: 3 # Objects appear in wrong places without it.
vuClampMode: 2 # Fixes water reflection.
gameFixes:
- EETimingHack # Fixes flickering graphics.
SCES-50360:
name: "Twisted Metal - Black"
region: "PAL-M5"
@@ -2226,14 +2230,6 @@ SCES-50878:
name: "Tekken 4"
region: "PAL-M5"
compat: 5
patches:
default:
content: |-
// CRC 2251E14D, F48F994A
comment=patches by Shadow Lady
// IPU BUSY! fix...
patch=0,EE,00292424,word,24200001
patch=0,EE,00292624,word,00000000
SCES-50885:
name: "Ape Escape 2"
region: "PAL-E"
@@ -4337,12 +4333,6 @@ SCPS-15050:
name: "Flipnic"
region: "NTSC-J"
compat: 5
patches:
25433CBD:
content: |-
comment=Patch by Prafull
//Fixes hang in some stages due to ipu issues
patch=1,EE,0011c000,word,000000000
SCPS-15051:
name: "MLB 2003"
region: "NTSC-J"
@@ -5246,13 +5236,6 @@ SCPS-56006:
name: "Tekken 4"
region: "NTSC-K"
compat: 5
patches:
35B4028B:
content: |-
comment=Patches by Shadow Lady
// IPU BUSY! fix...
patch=0,EE,00290b24,word,24200001
patch=0,EE,00290d24,word,00000000
SCPS-56008:
name: "Fatal Frame"
region: "NTSC-K"
@@ -7111,6 +7094,8 @@ SLED-50478:
SLED-50488:
name: "Spy Hunter [Demo]"
region: "PAL-E"
gameFixes:
- VIF1StallHack # Fixes loading hang.
SLED-50884:
name: "TimeSplitters 2 [Demo]"
region: "PAL-E"
@@ -7204,6 +7189,11 @@ SLED-53953:
region: "PAL-E"
gameFixes:
- GIFFIFOHack # Fixes flag corruptions.
SLED-53983:
name: "Fight Night Round 3 [Demo]"
region: "PAL"
gameFixes:
- GIFFIFOHack # Fixes flag corruption.
SLED-54035:
name: "Play the Best Demos from Atari [Demo]"
region: "PAL-M5"
@@ -7880,15 +7870,14 @@ SLES-50267:
2547FF67:
content: |-
author=Nachbrenner
// Skip PSX2_Mpeg_PlayFile__FPc.
patch=0,EE,00107a00,word,03e00008
patch=0,EE,00107a04,word,24020001
// Skip SuperSync__Fi.
patch=0,EE,00100eb0,word,03e00008
patch=0,EE,00100eb4,word,24020001
SLES-50268:
name: "Spy Hunter"
region: "PAL-M5"
gameFixes:
- VIF1StallHack # Fixes loading hang.
SLES-50273:
name: "Legion - The Legend of Excalibur"
region: "PAL-M5"
@@ -9413,12 +9402,6 @@ SLES-51101:
name: "Eggo Mania"
region: "PAL-M3"
compat: 5
patches:
30b27954:
content: |-
comment=Patches by Nachbrenner
// Skip IPU synchronisation.
patch=0,EE,00111100,word,00000000
SLES-51107:
name: "Hitman 2 - Silent Assassin"
region: "PAL-I"
@@ -13820,9 +13803,13 @@ SLES-53390:
name: "Ultimate Spider-Man"
region: "PAL-E"
compat: 5
clampModes:
vuClampMode: 0 # Fixes Spider-Man's eye texture colour.
SLES-53391:
name: "Ultimate Spider-Man"
region: "PAL-M5"
clampModes:
vuClampMode: 0 # Fixes Spider-Man's eye texture colour.
SLES-53393:
name: "Spartan Total Warrior"
region: "PAL-M5"
@@ -14253,7 +14240,7 @@ SLES-53541:
name: "Tiger Woods PGA Tour 06"
region: "PAL-M4"
clampModes:
vuClampMode: 2 # Fix black textures on characters.
vuClampMode: 3 # Fix black textures on characters.
gameFixes:
- SkipMPEGHack # Fixes hang after EA intro (IPU).
SLES-53542:
@@ -14542,6 +14529,8 @@ SLES-53668:
SLES-53672:
name: "Ultimate Spider-Man [Limited]"
region: "PAL-E"
clampModes:
vuClampMode: 0 # Fixes Fixes Spider-Man's eye texture colour.
SLES-53676:
name: "WWE SmackDown! vs. RAW 2006"
region: "PAL-E"
@@ -15206,6 +15195,8 @@ SLES-53979:
SLES-53982:
name: "Fight Night Round 3"
region: "PAL-E-F"
gameFixes:
- GIFFIFOHack # Fixes flag corruption.
SLES-53984:
name: "Ice Age 2 - The Meltdown"
region: "PAL-M6"
@@ -17195,6 +17186,8 @@ SLES-54898:
SLES-54899:
name: "EyeToy - Bob the Builder"
region: "PAL-M5"
clampModes:
vuClampMode: 3 # Fixes black screen.
SLES-54900:
name: "EyeToy - Bob the Builder"
region: "PAL-E-I"
@@ -19765,6 +19758,8 @@ SLPM-60107:
SLPM-60109:
name: "Ridge Racer V [Trial]"
region: "NTSC-J"
clampModes:
vuClampMode: 2 # Fixes texture rendering in the intro.
SLPM-60172:
name: "Itadaki Street 3 - Okuman Chouja ni Shiteageru"
region: "NTSC-J"
@@ -21174,6 +21169,12 @@ SLPM-62552:
name: "Super Shanghai 2005"
region: "NTSC-J"
compat: 5
patches:
default:
content: |-
// Sets CD Read command to blocking to prevent CDVD Reset collision on boot
comment=patch by kr_ps2
patch=1,IOP,000760B0,word,24040001
SLPM-62553:
name: "Sega Ages 2500 Series Vol.17 - Phantasy Star Generation 2"
region: "NTSC-J"
@@ -22153,6 +22154,8 @@ SLPM-65089:
SLPM-65090:
name: "Spy Hunter"
region: "NTSC-J"
gameFixes:
- VIF1StallHack # Fixes loading hang.
SLPM-65091:
name: "Harukanaru Toki no Naka de 2 [Limited Edition]"
region: "NTSC-J"
@@ -25449,7 +25452,7 @@ SLPM-66191:
name: "Tiger Woods PGA Tour 06"
region: "NTSC-J"
clampModes:
vuClampMode: 2 # Fixes black textures on characters.
vuClampMode: 3 # Fixes black textures on characters.
gameFixes:
- SkipMPEGHack # Fixes hang after EA intro (IPU).
SLPM-66192:
@@ -26135,6 +26138,11 @@ SLPM-66401:
SLPM-66402:
name: "Taito Memories Vol.1 [Taito The Best]"
region: "NTSC-J"
SLPM-66404:
name: "Ultimate Spider-Man"
region: "NTSC-J"
clampModes:
vuClampMode: 0 # Fixes Spider-Man's eye texture colour.
SLPM-66405:
name: "Rajirugi - Precious"
region: "NTSC-J"
@@ -28415,6 +28423,8 @@ SLPS-20001:
name: "Ridge Racer V"
region: "NTSC-J"
compat: 5
clampModes:
vuClampMode: 2 # Fixes texture rendering in the intro.
SLPS-20002:
name: "Doukyu Billiards"
region: "NTSC-J"
@@ -29594,6 +29604,8 @@ SLPS-25033:
clampModes:
eeClampMode: 3 # Objects appear in wrong places without it.
vuClampMode: 2 # Fixes water reflection.
gameFixes:
- EETimingHack # Fixes flickering graphics.
SLPS-25034:
name: "Flower, Sun and Rain"
region: "NTSC-J"
@@ -29798,14 +29810,6 @@ SLPS-25100:
name: "Tekken 4"
region: "NTSC-J"
compat: 5
patches:
default:
content: |-
// CRC 26173F9A, 7c359c94
comment=Patches by Shadow Lady
// IPU BUSY! fix...
patch=0,EE,00291764,word,24200001
patch=0,EE,00291964,word,00000000
SLPS-25102:
name: "Project Arms"
region: "NTSC-J"
@@ -32908,6 +32912,8 @@ SLPS-73404:
clampModes:
eeClampMode: 3 # Objects appear in wrong places without it.
vuClampMode: 2 # Fixes water reflection.
gameFixes:
- EETimingHack # Fixes flickering graphics.
SLPS-73405:
name: "Zero [PlayStation 2 The Best]"
region: "NTSC-J"
@@ -33006,6 +33012,8 @@ SLUS-20002:
name: "Ridge Racer V"
region: "NTSC-U"
compat: 5
clampModes:
vuClampMode: 2 # Fixes texture rendering in the intro.
SLUS-20003:
name: "Portal Runner"
region: "NTSC-U"
@@ -33420,9 +33428,6 @@ SLUS-20141:
116154AD:
content: |-
author=Nachbrenner
// Skip PSX2_Mpeg_PlayFile__FPc.
patch=0,EE,00107a00,word,03e00008
patch=0,EE,00107a04,word,24020001
// Skip SuperSync__Fi.
patch=0,EE,00100eb0,word,03e00008
patch=0,EE,00100eb4,word,24020001
@@ -33466,6 +33471,8 @@ SLUS-20151:
clampModes:
eeClampMode: 3 # Objects appear in wrong places without it.
vuClampMode: 2 # Fixes water reflection.
gameFixes:
- EETimingHack # Fixes flickering graphics.
SLUS-20152:
name: "Ace Combat 4 - Shattered Skies"
region: "NTSC-U"
@@ -34188,13 +34195,6 @@ SLUS-20328:
name: "Tekken 4"
region: "NTSC-U"
compat: 5
patches:
833FE0A4:
content: |-
comment=Patches by Shadow Lady
// IPU BUSY! fix...
patch=0,EE,002917e4,word,24200001
patch=0,EE,002919e4,word,00000000
SLUS-20329:
name: "Pro Race Driver"
region: "NTSC-U"
@@ -36142,14 +36142,6 @@ SLUS-20793:
name: "Gladiator - Sword of Vengeance"
region: "NTSC-U"
compat: 5
patches:
C5DAD771:
content: |-
author=Prafull
// Fix hang before menu screen
// The patch causes few artifacts in FMV
// Skips part of IPU
patch=1,EE,00286674,word,00000000
SLUS-20794:
name: "ESPN - Major League Baseball"
region: "NTSC-U"
@@ -36436,6 +36428,8 @@ SLUS-20870:
name: "Ultimate Spider-Man"
region: "NTSC-U"
compat: 5
clampModes:
vuClampMode: 0 # Fixes wrong texture colour.
SLUS-20871:
name: "Naval Ops - Commander"
region: "NTSC-U"
@@ -37730,12 +37724,6 @@ SLUS-21157:
name: "Flipnic - Ultimate Pinball"
region: "NTSC-U"
compat: 5
patches:
EADDB48E:
content: |-
comment=Patch by Prafull
// Fixes ufo shootdown mission hang
patch=1,EE,0011c310,word,00000000
SLUS-21158:
name: "Rugby 2005"
region: "NTSC-U"
@@ -38253,7 +38241,7 @@ SLUS-21264:
region: "NTSC-U"
compat: 5
clampModes:
vuClampMode: 2 # Fix black textures on characters.
vuClampMode: 3 # Fix black textures on characters.
gameFixes:
- SkipMPEGHack # Fixes hang after EA intro (IPU).
SLUS-21265:
@@ -38351,6 +38339,8 @@ SLUS-21284:
SLUS-21285:
name: "Ultimate Spider-Man [Limited Edition]"
region: "NTSC-U"
clampModes:
vuClampMode: 0 # Fixes Spider-Man's eyes texture.
SLUS-21286:
name: "WWE SmackDown! vs. RAW 2006"
region: "NTSC-U"
@@ -38826,6 +38816,8 @@ SLUS-21383:
name: "Fight Night - Round 3"
region: "NTSC-U"
compat: 5
gameFixes:
- GIFFIFOHack # Fixes flag corruption.
SLUS-21384:
name: "Cabela's Alaskan Adventures"
region: "NTSC-U"
@@ -41142,6 +41134,8 @@ SLUS-28004:
clampModes:
eeClampMode: 3 # Objects appear in wrong places without it.
vuClampMode: 2 # Fixes water reflection.
gameFixes:
- EETimingHack # Fixes flickering graphics.
SLUS-28006:
name: "Burnout [Trade Demo]"
region: "NTSC-U"
+6 -25
View File
@@ -12,30 +12,15 @@
[GLOBALS|FUNCTIONS]
------------------------------------------------------------------------------*/
#if (FXAA_GLSL_130 == 1)
in SHADER
{
vec4 p;
vec2 t;
vec4 c;
} PSin;
in vec2 PSin_t;
layout(location = 0) out vec4 SV_Target0;
layout(std140, binding = 14) uniform cb14
{
vec2 _xyFrame;
vec4 _rcpFrame;
};
#elif (SHADER_MODEL >= 0x400)
Texture2D Texture : register(t0);
SamplerState TextureSampler : register(s0);
cbuffer cb0
{
float4 _rcpFrame : register(c0);
};
struct VS_INPUT
{
float4 p : POSITION;
@@ -131,11 +116,6 @@ float RGBLuminance(float3 color)
return dot(color.rgb, lumCoeff);
}
#if (FXAA_GLSL_130 == 0)
#define PixelSize float2(_rcpFrame.x, _rcpFrame.y)
#endif
float3 RGBGammaToLinear(float3 color, float gamma)
{
color = FxaaSat(color);
@@ -502,6 +482,7 @@ float4 FxaaPass(float4 FxaaColor : COLOR0, float2 uv0 : TEXCOORD0)
tex.tex = Texture;
tex.smpl = TextureSampler;
float2 PixelSize;
Texture.GetDimensions(PixelSize.x, PixelSize.y);
FxaaColor = FxaaPixelShader(uv0, tex, 1.0/PixelSize.xy, FxaaSubpixMax, FxaaEdgeThreshold, FxaaEdgeThresholdMin);
@@ -520,9 +501,9 @@ float4 FxaaPass(float4 FxaaColor : COLOR0, float2 uv0 : TEXCOORD0)
void ps_main()
{
vec4 color = texture(TextureSampler, PSin.t);
color = PreGammaPass(color, PSin.t);
color = FxaaPass(color, PSin.t);
vec4 color = texture(TextureSampler, PSin_t);
color = PreGammaPass(color, PSin_t);
color = FxaaPass(color, PSin_t);
SV_Target0 = color;
}
+34 -24
View File
@@ -47,9 +47,11 @@
#define PS_BLEND_B 0
#define PS_BLEND_C 0
#define PS_BLEND_D 0
#define PS_ALPHA_CLAMP 0
#define PS_PABE 0
#define PS_DITHER 0
#define PS_ZCLAMP 0
#define PS_SCANMSK 0
#endif
#define SW_BLEND (PS_BLEND_A || PS_BLEND_B || PS_BLEND_D)
@@ -99,37 +101,33 @@ SamplerState PaletteSampler : register(s1);
cbuffer cb0
{
float4 VertexScale;
float4 VertexOffset;
float4 Texture_Scale_Offset;
float2 VertexScale;
float2 VertexOffset;
float2 TextureScale;
float2 TextureOffset;
float2 PointSize;
uint MaxDepth;
uint3 pad_cb0;
uint pad_cb0;
};
cbuffer cb1
{
float3 FogColor;
float AREF;
float4 HalfTexel;
float4 WH;
float4 MinMax;
float2 MinF;
float2 TA;
uint4 MskFix;
int4 ChannelShuffle;
uint4 FbMask;
float4 TC_OffsetHack;
float Af;
float MaxDepthPS;
float Af;
uint4 MskFix;
uint4 FbMask;
float4 HalfTexel;
float4 MinMax;
int4 ChannelShuffle;
float2 TC_OffsetHack;
float2 pad_cb1;
float4x4 DitherMatrix;
};
cbuffer cb2
{
float2 PointSize;
};
float4 sample_c(float2 uv)
{
if (PS_POINT_SAMPLER)
@@ -707,9 +705,13 @@ void ps_blend(inout float4 Color, float As, float2 pos_xy)
float3 A = (PS_BLEND_A == 0) ? Cs : ((PS_BLEND_A == 1) ? Cd : (float3)0.0f);
float3 B = (PS_BLEND_B == 0) ? Cs : ((PS_BLEND_B == 1) ? Cd : (float3)0.0f);
float3 C = (PS_BLEND_C == 0) ? As : ((PS_BLEND_C == 1) ? Ad : Af);
float C = (PS_BLEND_C == 0) ? As : ((PS_BLEND_C == 1) ? Ad : Af);
float3 D = (PS_BLEND_D == 0) ? Cs : ((PS_BLEND_D == 1) ? Cd : (float3)0.0f);
// As/Af clamp alpha for Blend mix
if (PS_ALPHA_CLAMP)
C = min(C, (float)1.0f);
Color.rgb = (PS_BLEND_A == PS_BLEND_B) ? D : trunc(((A - B) * C) + D);
// PABE
@@ -724,6 +726,13 @@ PS_OUTPUT ps_main(PS_INPUT input)
PS_OUTPUT output;
if (PS_SCANMSK & 2)
{
// fail depth test on prohibited lines
if ((int(input.p.y) & 1) == (PS_SCANMSK & 1))
discard;
}
if (PS_SHUFFLE)
{
uint4 denorm_c = uint4(C);
@@ -801,17 +810,18 @@ VS_OUTPUT vs_main(VS_INPUT input)
// input granularity is 1/16 pixel, anything smaller than that won't step drawing up/left by one pixel
// example: 133.0625 (133 + 1/16) should start from line 134, ceil(133.0625 - 0.05) still above 133
float4 p = float4(input.p, input.z, 0) - float4(0.05f, 0.05f, 0, 0);
output.p = float4(input.p, input.z, 1.0f) - float4(0.05f, 0.05f, 0, 0);
output.p = p * VertexScale - VertexOffset;
output.p.xy = output.p.xy * float2(VertexScale.x, -VertexScale.y) - float2(VertexOffset.x, -VertexOffset.y);
output.p.z *= exp2(-32.0f); // integer->float depth
if(VS_TME)
{
float2 uv = input.uv - Texture_Scale_Offset.zw;
float2 st = input.st - Texture_Scale_Offset.zw;
float2 uv = input.uv - TextureOffset;
float2 st = input.st - TextureOffset;
// Integer nomalized
output.ti.xy = uv * Texture_Scale_Offset.xy;
output.ti.xy = uv * TextureScale;
if (VS_FST)
{
@@ -821,7 +831,7 @@ VS_OUTPUT vs_main(VS_INPUT input)
else
{
// float for post-processing in some games
output.ti.zw = st / Texture_Scale_Offset.xy;
output.ti.zw = st / TextureScale;
}
// Float coords
output.t.xy = st;
@@ -44,20 +44,8 @@ out gl_PerVertex {
// Performance note, some drivers (nouveau) will validate all Constant Buffers
// even if only one was updated.
#ifdef FRAGMENT_SHADER
layout(std140, binding = 15) uniform cb15
{
ivec4 ScalingFactor;
ivec4 ChannelShuffle;
int EMODA;
int EMODC;
ivec2 pad_cb15;
};
#endif
#if defined(VERTEX_SHADER) || defined(GEOMETRY_SHADER)
layout(std140, binding = 20) uniform cb20
layout(std140, binding = 1) uniform cb20
{
vec2 VertexScale;
vec2 VertexOffset;
@@ -72,7 +60,7 @@ layout(std140, binding = 20) uniform cb20
#endif
#if defined(VERTEX_SHADER) || defined(FRAGMENT_SHADER)
layout(std140, binding = 21) uniform cb21
layout(std140, binding = 0) uniform cb21
{
vec3 FogColor;
float AREF;
@@ -91,8 +79,10 @@ layout(std140, binding = 21) uniform cb21
vec4 MinMax;
vec2 pad_cb21;
ivec4 ChannelShuffle;
vec2 TC_OffsetHack;
vec2 pad_cb21;
mat4 DitherMatrix;
};
+21 -25
View File
@@ -15,18 +15,15 @@ layout(location = 7) in vec4 COLOR;
// smooth, the default, means to do perspective-correct interpolation.
//
// The centroid qualifier only matters when multisampling. If this qualifier is not present, then the value is interpolated to the pixel's center, anywhere in the pixel, or to one of the pixel's samples. This sample may lie outside of the actual primitive being rendered, since a primitive can cover only part of a pixel's area. The centroid qualifier is used to prevent this; the interpolation point must fall within both the pixel's area and the primitive's area.
out SHADER
{
vec4 p;
vec2 t;
vec4 c;
} VSout;
out vec4 PSin_p;
out vec2 PSin_t;
out vec4 PSin_c;
void vs_main()
{
VSout.p = vec4(POSITION, 0.5f, 1.0f);
VSout.t = TEXCOORD0;
VSout.c = COLOR;
PSin_p = vec4(POSITION, 0.5f, 1.0f);
PSin_t = TEXCOORD0;
PSin_c = COLOR;
gl_Position = vec4(POSITION, 0.5f, 1.0f); // NOTE I don't know if it is possible to merge POSITION_OUT and gl_Position
}
@@ -34,12 +31,9 @@ void vs_main()
#ifdef FRAGMENT_SHADER
in SHADER
{
vec4 p;
vec2 t;
vec4 c;
} PSin;
in vec4 PSin_p;
in vec2 PSin_t;
in vec4 PSin_c;
// Give a different name so I remember there is a special case!
#if defined(ps_convert_rgba8_16bits) || defined(ps_convert_float32_32bits)
@@ -50,7 +44,7 @@ layout(location = 0) out vec4 SV_Target0;
vec4 sample_c()
{
return texture(TextureSampler, PSin.t);
return texture(TextureSampler, PSin_t);
}
vec4 ps_crt(uint i)
@@ -226,9 +220,9 @@ void ps_convert_rgba_8i()
int txN = tb.x | (int(gl_FragCoord.x) & 7);
int txH = tb.x | ((int(gl_FragCoord.x) + 4) & 7);
txN *= ScalingFactor.x;
txH *= ScalingFactor.x;
ty *= ScalingFactor.y;
txN *= PS_SCALE_FACTOR;
txH *= PS_SCALE_FACTOR;
ty *= PS_SCALE_FACTOR;
// TODO investigate texture gather
vec4 cN = texelFetch(TextureSampler, ivec2(txN, ty), 0);
@@ -281,7 +275,7 @@ void ps_convert_rgba_8i()
#ifdef ps_osd
void ps_osd()
{
SV_Target0 = PSin.c * vec4(1.0, 1.0, 1.0, sample_c().r);
SV_Target0 = PSin_c * vec4(1.0, 1.0, 1.0, sample_c().r);
}
#endif
@@ -349,11 +343,11 @@ void ps_filter_complex()
vec2 texdim = vec2(textureSize(TextureSampler, 0));
vec4 c;
if (dFdy(PSin.t.y) * PSin.t.y > 0.5f) {
if (dFdy(PSin_t.y) * PSin_t.y > 0.5f) {
c = sample_c();
} else {
float factor = (0.9f - 0.4f * cos(2.0f * PI * PSin.t.y * texdim.y));
c = factor * texture(TextureSampler, vec2(PSin.t.x, (floor(PSin.t.y * texdim.y) + 0.5f) / texdim.y));
float factor = (0.9f - 0.4f * cos(2.0f * PI * PSin_t.y * texdim.y));
c = factor * texture(TextureSampler, vec2(PSin_t.x, (floor(PSin_t.y * texdim.y) + 0.5f) / texdim.y));
}
SV_Target0 = c;
@@ -388,6 +382,8 @@ void ps_mod256()
#endif
#ifdef ps_yuv
uniform ivec2 EMOD;
void ps_yuv()
{
vec4 i = sample_c();
@@ -404,7 +400,7 @@ void ps_yuv()
float Cr = float(0xE0)/255.0f * yuv.y + float(0x80)/255.0f;
float Cb = float(0xE0)/255.0f * yuv.z + float(0x80)/255.0f;
switch(EMODA) {
switch(EMOD.x) {
case 0:
o.a = i.a;
break;
@@ -419,7 +415,7 @@ void ps_yuv()
break;
}
switch(EMODC) {
switch(EMOD.y) {
case 0:
o.rgb = i.rgb;
break;
+14 -20
View File
@@ -1,57 +1,51 @@
//#version 420 // Keep it for editor detection
in SHADER
{
vec4 p;
vec2 t;
vec4 c;
} PSin;
#ifdef FRAGMENT_SHADER
layout(std140, binding = 11) uniform cb11
{
vec2 ZrH;
float hH;
};
in vec4 PSin_p;
in vec2 PSin_t;
in vec4 PSin_c;
uniform vec2 ZrH;
uniform float hH;
layout(location = 0) out vec4 SV_Target0;
// TODO ensure that clip (discard) is < 0 and not <= 0 ???
void ps_main0()
{
if (fract(PSin.t.y * hH) - 0.5 < 0.0)
if (fract(PSin_t.y * hH) - 0.5 < 0.0)
discard;
// I'm not sure it impact us but be safe to lookup texture before conditional if
// see: http://www.opengl.org/wiki/GLSL_Sampler#Non-uniform_flow_control
vec4 c = texture(TextureSampler, PSin.t);
vec4 c = texture(TextureSampler, PSin_t);
SV_Target0 = c;
}
void ps_main1()
{
if (0.5 - fract(PSin.t.y * hH) < 0.0)
if (0.5 - fract(PSin_t.y * hH) < 0.0)
discard;
// I'm not sure it impact us but be safe to lookup texture before conditional if
// see: http://www.opengl.org/wiki/GLSL_Sampler#Non-uniform_flow_control
vec4 c = texture(TextureSampler, PSin.t);
vec4 c = texture(TextureSampler, PSin_t);
SV_Target0 = c;
}
void ps_main2()
{
vec4 c0 = texture(TextureSampler, PSin.t - ZrH);
vec4 c1 = texture(TextureSampler, PSin.t);
vec4 c2 = texture(TextureSampler, PSin.t + ZrH);
vec4 c0 = texture(TextureSampler, PSin_t - ZrH);
vec4 c1 = texture(TextureSampler, PSin_t);
vec4 c2 = texture(TextureSampler, PSin_t + ZrH);
SV_Target0 = (c0 + c1 * 2.0f + c2) / 4.0f;
}
void ps_main3()
{
SV_Target0 = texture(TextureSampler, PSin.t);
SV_Target0 = texture(TextureSampler, PSin_t);
}
#endif
+7 -13
View File
@@ -1,24 +1,18 @@
//#version 420 // Keep it for editor detection
in SHADER
{
vec4 p;
vec2 t;
vec4 c;
} PSin;
#ifdef FRAGMENT_SHADER
layout(std140, binding = 10) uniform cb10
{
vec4 BGColor;
};
in vec4 PSin_p;
in vec2 PSin_t;
in vec4 PSin_c;
uniform vec4 BGColor;
layout(location = 0) out vec4 SV_Target0;
void ps_main0()
{
vec4 c = texture(TextureSampler, PSin.t);
vec4 c = texture(TextureSampler, PSin_t);
// Note: clamping will be done by fixed unit
c.a *= 2.0f;
SV_Target0 = c;
@@ -26,7 +20,7 @@ void ps_main0()
void ps_main1()
{
vec4 c = texture(TextureSampler, PSin.t);
vec4 c = texture(TextureSampler, PSin_t);
c.a = BGColor.a;
SV_Target0 = c;
}
+4 -7
View File
@@ -11,12 +11,9 @@
#ifdef FRAGMENT_SHADER
in SHADER
{
vec4 p;
vec2 t;
vec4 c;
} PSin;
in vec4 PSin_p;
in vec2 PSin_t;
in vec4 PSin_c;
layout(location = 0) out vec4 SV_Target0;
@@ -48,7 +45,7 @@ vec4 ContrastSaturationBrightness(vec4 color)
void ps_main()
{
vec4 c = texture(TextureSampler, PSin.t);
vec4 c = texture(TextureSampler, PSin_t);
SV_Target0 = ContrastSaturationBrightness(c);
}
+12 -2
View File
@@ -282,7 +282,7 @@ ivec2 clamp_wrap_uv_depth(ivec2 uv)
vec4 sample_depth(vec2 st)
{
vec2 uv_f = vec2(clamp_wrap_uv_depth(ivec2(st))) * vec2(ScalingFactor.xy) * vec2(1.0f/16.0f);
vec2 uv_f = vec2(clamp_wrap_uv_depth(ivec2(st))) * vec2(float(PS_SCALE_FACTOR)) * vec2(1.0f/16.0f);
ivec2 uv = ivec2(uv_f);
vec4 t = vec4(0.0f);
@@ -619,7 +619,7 @@ void ps_dither(inout vec3 C)
#if PS_DITHER == 2
ivec2 fpos = ivec2(gl_FragCoord.xy);
#else
ivec2 fpos = ivec2(gl_FragCoord.xy / ScalingFactor.x);
ivec2 fpos = ivec2(gl_FragCoord.xy / float(PS_SCALE_FACTOR));
#endif
C += DitherMatrix[fpos.y&3][fpos.x&3];
#endif
@@ -702,6 +702,11 @@ void ps_blend(inout vec4 Color, float As)
vec3 D = vec3(0.0f);
#endif
// As/Af clamp alpha for Blend mix
#if PS_ALPHA_CLAMP
C = min(C, float(1.0f));
#endif
#if PS_BLEND_A == PS_BLEND_B
Color.rgb = D;
#else
@@ -718,6 +723,11 @@ void ps_blend(inout vec4 Color, float As)
void ps_main()
{
#if PS_SCANMSK & 2
// fail depth test on prohibited lines
if ((int(gl_FragCoord.y) & 1) == (PS_SCANMSK & 1))
discard;
#endif
#if ((PS_DATE & 3) == 1 || (PS_DATE & 3) == 2)
#if PS_WRITE_RG == 1
+6 -13
View File
@@ -40,20 +40,13 @@
#define saturate(x) clamp(x, 0.0, 1.0)
#define SamplerState sampler2D
in SHADER
{
vec4 p;
vec2 t;
vec4 c;
} PSin;
in vec4 PSin_p;
in vec2 PSin_t;
layout(location = 0) out vec4 SV_Target0;
layout(std140, binding = 14) uniform cb14
{
vec2 _xyFrame;
vec4 _rcpFrame;
};
uniform vec2 _xyFrame;
uniform vec4 _rcpFrame;
#else
@@ -2415,8 +2408,8 @@ PS_OUTPUT ps_main(VS_OUTPUT input)
#endif
{
#if GLSL == 1
float2 texcoord = PSin.t;
float4 position = PSin.p;
float2 texcoord = PSin_t;
float4 position = PSin_p;
float4 color = texture(TextureSampler, texcoord);
#else
PS_OUTPUT output;
+7 -11
View File
@@ -164,8 +164,8 @@ cleanBuild=0
useClang=0
useIcc=0
# 0 => no, 1 => yes, 2 => force yes
useCross=2
# 0 => no, 1 => yes
useCross=0
CoverityBuild=0
cppcheck=0
@@ -183,7 +183,6 @@ set_make
for ARG in "$@"; do
case "$ARG" in
--clean ) cleanBuild=1 ;;
--clean-plugins ) cleanBuild=2 ;;
--clang-tidy ) flags="$flags -DCMAKE_EXPORT_COMPILE_COMMANDS=ON"; clangTidy=1 ; useClang=1;;
--ftime-trace ) flags="$flags -DTIMETRACE=TRUE"; useClang=1;;
--clang ) useClang=1 ;;
@@ -220,20 +219,19 @@ for ARG in "$@"; do
echo "--release : Build PCSX2 as a Release build."
echo
echo "--clean : Do a clean build."
echo "--clean-plugins : Do a clean build of plugins, but not of pcsx2."
echo "--no-simd : Only allow sse2"
echo
echo "** Developer option **"
echo "--cross-multilib: Build a 32bit PCSX2 on a 64bit machine using multilib."
echo "--no-cross-multilib: Build a native version of PCSX2 (default)"
echo
echo "** Distribution Compatibilities **"
echo "--sdl12 : Build with SDL1.2 (requires if wx is linked against SDL1.2)"
echo "--no-portaudio : Skip portaudio for SPU2."
echo "--use-system-yaml : Use the system version of yaml-cpp, if available."
echo "--use-system-yaml : Use system rapidyaml library"
echo
echo "** Expert Developer option **"
echo "--gtk2 : use GTK 2 instead of GTK 3"
echo "--no-cross-multilib: Build a native PCSX2 (nonfunctional recompiler)"
echo "--no-trans : Don't regenerate mo files when building."
echo "--clang : Build with Clang/llvm"
echo "--intel : Build with ICC (Intel compiler)"
@@ -257,16 +255,14 @@ if [ "$cleanBuild" -eq 1 ]; then
echo "Doing a clean build."
# allow to keep build as a symlink (for example to a ramdisk)
rm -fr "$build"/*
elif [ "$cleanBuild" -eq 2 ]; then
echo "Doing a clean build on the plugins, but not pcsx2."
rm -fr "$build"/plugins/*
fi
if [ "$useCross" -eq 2 ] && [ "$(getconf LONG_BIT 2> /dev/null)" != 32 ]; then
echo "Forcing cross compilation."
if [ "$useCross" -eq 1 ]; then
echo "Cross compiling."
flags="$flags $i386_flag"
elif [ "$useCross" -ne 1 ]; then
useCross=0
echo "Compiling natively."
fi
switch_wxconfig
+9 -13
View File
@@ -229,26 +229,21 @@ else()
endif()
if(USE_SYSTEM_YAML)
find_package(yaml-cpp "0.6.3" QUIET)
if(NOT yaml-cpp_FOUND)
message(STATUS "No system yaml-cpp was found")
find_package(ryml REQUIRED)
if(NOT ryml_FOUND)
message(STATUS "No system rapidyaml was found, using the submodule in the 3rdparty directory")
set(USE_SYSTEM_YAML OFF)
else()
message(STATUS "Found yaml-cpp: ${yaml-cpp_VERSION}")
message(STATUS "Note that the latest release of yaml-cpp is very outdated, and the bundled submodule in the repo has over a year of bug fixes and as such is preferred.")
message(STATUS "Found rapidyaml: ${rapidyaml_VERSION}")
endif()
endif()
if(NOT USE_SYSTEM_YAML)
if(EXISTS "${CMAKE_SOURCE_DIR}/3rdparty/yaml-cpp/yaml-cpp/CMakeLists.txt")
message(STATUS "Using bundled yaml-cpp")
add_subdirectory(3rdparty/yaml-cpp/yaml-cpp EXCLUDE_FROM_ALL)
if (NOT MSVC)
# Remove once https://github.com/jbeder/yaml-cpp/pull/815 is merged
target_compile_options(yaml-cpp PRIVATE -Wno-shadow)
endif()
if(EXISTS "${CMAKE_SOURCE_DIR}/3rdparty/rapidyaml/rapidyaml/CMakeLists.txt")
message(STATUS "Using bundled rapidyaml")
add_subdirectory(3rdparty/rapidyaml/rapidyaml EXCLUDE_FROM_ALL)
else()
message(FATAL_ERROR "No bundled yaml-cpp was found")
message(FATAL_ERROR "No bundled rapidyaml was found")
endif()
endif()
@@ -264,6 +259,7 @@ else()
endif()
add_subdirectory(3rdparty/glad EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/simpleini EXCLUDE_FROM_ALL)
if(CUBEB_API)
add_subdirectory(3rdparty/cubeb EXCLUDE_FROM_ALL)
+7
View File
@@ -19,11 +19,14 @@ target_sources(common PRIVATE
FastFormatString.cpp
FastJmp.cpp
GL/Context.cpp
GL/Program.cpp
GL/ShaderCache.cpp
GL/StreamBuffer.cpp
FileSystem.cpp
IniInterface.cpp
Mutex.cpp
Misc.cpp
MD5Digest.cpp
PathUtils.cpp
PrecompiledHeader.cpp
Perf.cpp
@@ -75,9 +78,13 @@ target_sources(common PRIVATE
FileSystem.h
General.h
GL/Context.h
GL/Program.h
GL/ShaderCache.h
GL/StreamBuffer.h
HashCombine.h
MemcpyFast.h
MemsetFast.inl
MD5Digest.h
Path.h
PageFaultSource.h
PrecompiledHeader.h
+1
View File
@@ -1557,6 +1557,7 @@ std::string FileSystem::GetWorkingDirectory()
buffer.resize(buffer.size() * 2);
}
buffer.resize(std::strlen(buffer.c_str())); // Remove excess nulls
return buffer;
}
+655
View File
@@ -0,0 +1,655 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/PrecompiledHeader.h"
#include "common/GL/Program.h"
#include "common/Assertions.h"
#include "common/Console.h"
#include "common/StringUtil.h"
#include <array>
#include <fstream>
namespace GL
{
GLuint Program::s_last_program_id = 0;
static GLuint s_next_bad_shader_id = 1;
Program::Program() = default;
Program::Program(Program&& prog)
{
m_program_id = prog.m_program_id;
prog.m_program_id = 0;
m_vertex_shader_id = prog.m_vertex_shader_id;
prog.m_vertex_shader_id = 0;
m_fragment_shader_id = prog.m_fragment_shader_id;
prog.m_fragment_shader_id = 0;
m_uniform_locations = std::move(prog.m_uniform_locations);
}
Program::~Program()
{
Destroy();
}
GLuint Program::CompileShader(GLenum type, const std::string_view source)
{
GLuint id = glCreateShader(type);
std::array<const GLchar*, 1> sources = {{source.data()}};
std::array<GLint, 1> source_lengths = {{static_cast<GLint>(source.size())}};
glShaderSource(id, static_cast<GLsizei>(sources.size()), sources.data(), source_lengths.data());
glCompileShader(id);
GLint status = GL_FALSE;
glGetShaderiv(id, GL_COMPILE_STATUS, &status);
GLint info_log_length = 0;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &info_log_length);
if (status == GL_FALSE || info_log_length > 0)
{
std::string info_log;
info_log.resize(info_log_length + 1);
glGetShaderInfoLog(id, info_log_length, &info_log_length, &info_log[0]);
if (status == GL_TRUE)
{
Console.Warning("Shader compiled with warnings:\n%s", info_log.c_str());
}
else
{
Console.Error("Shader failed to compile:\n%s", info_log.c_str());
std::ofstream ofs(StringUtil::StdStringFromFormat("bad_shader_%u.txt", s_next_bad_shader_id++).c_str(),
std::ofstream::out | std::ofstream::binary);
if (ofs.is_open())
{
ofs.write(sources[0], source_lengths[0]);
ofs << "\n\nCompile failed, info log:\n";
ofs << info_log;
ofs.close();
}
glDeleteShader(id);
return 0;
}
}
return id;
}
void Program::ResetLastProgram()
{
s_last_program_id = 0;
}
bool Program::Compile(const std::string_view vertex_shader, const std::string_view geometry_shader,
const std::string_view fragment_shader)
{
GLuint vertex_shader_id = 0;
if (!vertex_shader.empty())
{
vertex_shader_id = CompileShader(GL_VERTEX_SHADER, vertex_shader);
if (vertex_shader_id == 0)
return false;
}
GLuint geometry_shader_id = 0;
if (!geometry_shader.empty())
{
geometry_shader_id = CompileShader(GL_GEOMETRY_SHADER, geometry_shader);
if (geometry_shader_id == 0)
return false;
}
GLuint fragment_shader_id = 0;
if (!fragment_shader.empty())
{
fragment_shader_id = CompileShader(GL_FRAGMENT_SHADER, fragment_shader);
if (fragment_shader_id == 0)
{
glDeleteShader(vertex_shader_id);
return false;
}
}
m_program_id = glCreateProgram();
if (vertex_shader_id != 0)
glAttachShader(m_program_id, vertex_shader_id);
if (geometry_shader_id != 0)
glAttachShader(m_program_id, geometry_shader_id);
if (fragment_shader_id != 0)
glAttachShader(m_program_id, fragment_shader_id);
return true;
}
bool Program::CreateFromBinary(const void* data, u32 data_length, u32 data_format)
{
GLuint prog = glCreateProgram();
glProgramBinary(prog, static_cast<GLenum>(data_format), data, data_length);
GLint link_status;
glGetProgramiv(prog, GL_LINK_STATUS, &link_status);
if (link_status != GL_TRUE)
{
Console.Error("Failed to create GL program from binary: status %d", link_status);
glDeleteProgram(prog);
return false;
}
m_program_id = prog;
return true;
}
bool Program::GetBinary(std::vector<u8>* out_data, u32* out_data_format)
{
GLint binary_size = 0;
glGetProgramiv(m_program_id, GL_PROGRAM_BINARY_LENGTH, &binary_size);
if (binary_size == 0)
{
Console.Warning("glGetProgramiv(GL_PROGRAM_BINARY_LENGTH) returned 0");
return false;
}
GLenum format = 0;
out_data->resize(static_cast<size_t>(binary_size));
glGetProgramBinary(m_program_id, binary_size, &binary_size, &format, out_data->data());
if (binary_size == 0)
{
Console.Warning("glGetProgramBinary() failed");
return false;
}
else if (static_cast<size_t>(binary_size) != out_data->size())
{
Console.Warning("Size changed from %zu to %d after glGetProgramBinary()", out_data->size(), binary_size);
out_data->resize(static_cast<size_t>(binary_size));
}
*out_data_format = static_cast<u32>(format);
DevCon.WriteLn("Program binary retrieved, %zu bytes, format %u", out_data->size(), *out_data_format);
return true;
}
void Program::SetBinaryRetrievableHint()
{
glProgramParameteri(m_program_id, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
}
void Program::BindAttribute(GLuint index, const char* name)
{
glBindAttribLocation(m_program_id, index, name);
}
void Program::BindDefaultAttributes()
{
BindAttribute(0, "a_position");
BindAttribute(1, "a_texcoord");
BindAttribute(2, "a_color");
}
void Program::BindFragData(GLuint index /*= 0*/, const char* name /*= "o_col0"*/)
{
glBindFragDataLocation(m_program_id, index, name);
}
void Program::BindFragDataIndexed(GLuint color_number /*= 0*/, const char* name /*= "o_col0"*/)
{
if (GLAD_GL_VERSION_3_3 || GLAD_GL_ARB_blend_func_extended)
{
glBindFragDataLocationIndexed(m_program_id, color_number, 0, name);
return;
}
else if (GLAD_GL_EXT_blend_func_extended)
{
glBindFragDataLocationIndexedEXT(m_program_id, color_number, 0, name);
return;
}
Console.Error("BindFragDataIndexed() called without ARB or EXT extension, we'll probably crash.");
glBindFragDataLocationIndexed(m_program_id, color_number, 0, name);
}
bool Program::Link()
{
glLinkProgram(m_program_id);
if (m_vertex_shader_id != 0)
glDeleteShader(m_vertex_shader_id);
m_vertex_shader_id = 0;
if (m_fragment_shader_id != 0)
glDeleteShader(m_fragment_shader_id);
m_fragment_shader_id = 0;
GLint status = GL_FALSE;
glGetProgramiv(m_program_id, GL_LINK_STATUS, &status);
GLint info_log_length = 0;
glGetProgramiv(m_program_id, GL_INFO_LOG_LENGTH, &info_log_length);
if (status == GL_FALSE || info_log_length > 0)
{
std::string info_log;
info_log.resize(info_log_length + 1);
glGetProgramInfoLog(m_program_id, info_log_length, &info_log_length, &info_log[0]);
if (status == GL_TRUE)
{
Console.Error("Program linked with warnings:\n%s", info_log.c_str());
}
else
{
Console.Error("Program failed to link:\n%s", info_log.c_str());
glDeleteProgram(m_program_id);
m_program_id = 0;
return false;
}
}
return true;
}
void Program::Bind() const
{
if (s_last_program_id == m_program_id)
return;
glUseProgram(m_program_id);
s_last_program_id = m_program_id;
}
void Program::Destroy()
{
if (m_vertex_shader_id != 0)
{
glDeleteShader(m_vertex_shader_id);
m_vertex_shader_id = 0;
}
if (m_fragment_shader_id != 0)
{
glDeleteShader(m_fragment_shader_id);
m_fragment_shader_id = 0;
}
if (m_program_id != 0)
{
glDeleteProgram(m_program_id);
m_program_id = 0;
}
m_uniform_locations.clear();
}
int Program::RegisterUniform(const char* name)
{
int id = static_cast<int>(m_uniform_locations.size());
m_uniform_locations.push_back(glGetUniformLocation(m_program_id, name));
return id;
}
void Program::Uniform1ui(int index, u32 x) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform1ui(location, x);
}
void Program::Uniform2ui(int index, u32 x, u32 y) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform2ui(location, x, y);
}
void Program::Uniform3ui(int index, u32 x, u32 y, u32 z) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform3ui(location, x, y, z);
}
void Program::Uniform4ui(int index, u32 x, u32 y, u32 z, u32 w) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform4ui(location, x, y, z, w);
}
void Program::Uniform1i(int index, s32 x) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform1i(location, x);
}
void Program::Uniform2i(int index, s32 x, s32 y) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform2i(location, x, y);
}
void Program::Uniform3i(int index, s32 x, s32 y, s32 z) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform3i(location, x, y, z);
}
void Program::Uniform4i(int index, s32 x, s32 y, s32 z, s32 w) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform4i(location, x, y, z, w);
}
void Program::Uniform1f(int index, float x) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform1f(location, x);
}
void Program::Uniform2f(int index, float x, float y) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform2f(location, x, y);
}
void Program::Uniform3f(int index, float x, float y, float z) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform3f(location, x, y, z);
}
void Program::Uniform4f(int index, float x, float y, float z, float w) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform4f(location, x, y, z, w);
}
void Program::Uniform2uiv(int index, const u32* v) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform2uiv(location, 1, v);
}
void Program::Uniform3uiv(int index, const u32* v) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform3uiv(location, 1, v);
}
void Program::Uniform4uiv(int index, const u32* v) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform4uiv(location, 1, v);
}
void Program::Uniform2iv(int index, const s32* v) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform2iv(location, 1, v);
}
void Program::Uniform3iv(int index, const s32* v) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform3iv(location, 1, v);
}
void Program::Uniform4iv(int index, const s32* v) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform4iv(location, 1, v);
}
void Program::Uniform2fv(int index, const float* v) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform2fv(location, 1, v);
}
void Program::Uniform3fv(int index, const float* v) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform3fv(location, 1, v);
}
void Program::Uniform4fv(int index, const float* v) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform4fv(location, 1, v);
}
void Program::Uniform1ui(const char* name, u32 x) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform1ui(location, x);
}
void Program::Uniform2ui(const char* name, u32 x, u32 y) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform2ui(location, x, y);
}
void Program::Uniform3ui(const char* name, u32 x, u32 y, u32 z) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform3ui(location, x, y, z);
}
void Program::Uniform4ui(const char* name, u32 x, u32 y, u32 z, u32 w) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform4ui(location, x, y, z, w);
}
void Program::Uniform1i(const char* name, s32 x) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform1i(location, x);
}
void Program::Uniform2i(const char* name, s32 x, s32 y) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform2i(location, x, y);
}
void Program::Uniform3i(const char* name, s32 x, s32 y, s32 z) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform3i(location, x, y, z);
}
void Program::Uniform4i(const char* name, s32 x, s32 y, s32 z, s32 w) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform4i(location, x, y, z, w);
}
void Program::Uniform1f(const char* name, float x) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform1f(location, x);
}
void Program::Uniform2f(const char* name, float x, float y) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform2f(location, x, y);
}
void Program::Uniform3f(const char* name, float x, float y, float z) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform3f(location, x, y, z);
}
void Program::Uniform4f(const char* name, float x, float y, float z, float w) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform4f(location, x, y, z, w);
}
void Program::Uniform2uiv(const char* name, const u32* v) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform2uiv(location, 1, v);
}
void Program::Uniform3uiv(const char* name, const u32* v) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform3uiv(location, 1, v);
}
void Program::Uniform4uiv(const char* name, const u32* v) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform4uiv(location, 1, v);
}
void Program::Uniform2iv(const char* name, const s32* v) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform2iv(location, 1, v);
}
void Program::Uniform3iv(const char* name, const s32* v) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform3iv(location, 1, v);
}
void Program::Uniform4iv(const char* name, const s32* v) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform4iv(location, 1, v);
}
void Program::Uniform2fv(const char* name, const float* v) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform2fv(location, 1, v);
}
void Program::Uniform3fv(const char* name, const float* v) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform3fv(location, 1, v);
}
void Program::Uniform4fv(const char* name, const float* v) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform4fv(location, 1, v);
}
void Program::BindUniformBlock(const char* name, u32 index)
{
const GLint location = glGetUniformBlockIndex(m_program_id, name);
if (location >= 0)
glUniformBlockBinding(m_program_id, location, index);
}
void Program::SetName(const std::string_view& name)
{
if (name.empty())
return;
#ifdef _DEBUG
glObjectLabel(GL_PROGRAM, m_program_id, name.length(), name.data());
#endif
}
void Program::SetFormattedName(const char* format, ...)
{
va_list ap;
va_start(ap, format);
std::string n = StringUtil::StdStringFromFormatV(format, ap);
va_end(ap);
SetName(n);
}
Program& Program::operator=(Program&& prog)
{
Destroy();
m_program_id = prog.m_program_id;
prog.m_program_id = 0;
m_vertex_shader_id = prog.m_vertex_shader_id;
prog.m_vertex_shader_id = 0;
m_fragment_shader_id = prog.m_fragment_shader_id;
prog.m_fragment_shader_id = 0;
m_uniform_locations = std::move(prog.m_uniform_locations);
return *this;
}
} // namespace GL
+122
View File
@@ -0,0 +1,122 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../Pcsx2Defs.h"
#include "glad.h"
#include <string_view>
#include <vector>
namespace GL
{
class Program
{
public:
Program();
Program(const Program&) = delete;
Program(Program&& prog);
~Program();
static GLuint CompileShader(GLenum type, const std::string_view source);
static void ResetLastProgram();
bool IsValid() const { return m_program_id != 0; }
bool Compile(const std::string_view vertex_shader, const std::string_view geometry_shader,
const std::string_view fragment_shader);
bool CreateFromBinary(const void* data, u32 data_length, u32 data_format);
bool GetBinary(std::vector<u8>* out_data, u32* out_data_format);
void SetBinaryRetrievableHint();
void BindAttribute(GLuint index, const char* name);
void BindDefaultAttributes();
void BindFragData(GLuint index = 0, const char* name = "o_col0");
void BindFragDataIndexed(GLuint color_number = 0, const char* name = "o_col0");
bool Link();
void Bind() const;
void Destroy();
int RegisterUniform(const char* name);
void Uniform1ui(int index, u32 x) const;
void Uniform2ui(int index, u32 x, u32 y) const;
void Uniform3ui(int index, u32 x, u32 y, u32 z) const;
void Uniform4ui(int index, u32 x, u32 y, u32 z, u32 w) const;
void Uniform1i(int index, s32 x) const;
void Uniform2i(int index, s32 x, s32 y) const;
void Uniform3i(int index, s32 x, s32 y, s32 z) const;
void Uniform4i(int index, s32 x, s32 y, s32 z, s32 w) const;
void Uniform1f(int index, float x) const;
void Uniform2f(int index, float x, float y) const;
void Uniform3f(int index, float x, float y, float z) const;
void Uniform4f(int index, float x, float y, float z, float w) const;
void Uniform2uiv(int index, const u32* v) const;
void Uniform3uiv(int index, const u32* v) const;
void Uniform4uiv(int index, const u32* v) const;
void Uniform2iv(int index, const s32* v) const;
void Uniform3iv(int index, const s32* v) const;
void Uniform4iv(int index, const s32* v) const;
void Uniform2fv(int index, const float* v) const;
void Uniform3fv(int index, const float* v) const;
void Uniform4fv(int index, const float* v) const;
void Uniform1ui(const char* name, u32 x) const;
void Uniform2ui(const char* name, u32 x, u32 y) const;
void Uniform3ui(const char* name, u32 x, u32 y, u32 z) const;
void Uniform4ui(const char* name, u32 x, u32 y, u32 z, u32 w) const;
void Uniform1i(const char* name, s32 x) const;
void Uniform2i(const char* name, s32 x, s32 y) const;
void Uniform3i(const char* name, s32 x, s32 y, s32 z) const;
void Uniform4i(const char* name, s32 x, s32 y, s32 z, s32 w) const;
void Uniform1f(const char* name, float x) const;
void Uniform2f(const char* name, float x, float y) const;
void Uniform3f(const char* name, float x, float y, float z) const;
void Uniform4f(const char* name, float x, float y, float z, float w) const;
void Uniform2uiv(const char* name, const u32* v) const;
void Uniform3uiv(const char* name, const u32* v) const;
void Uniform4uiv(const char* name, const u32* v) const;
void Uniform2iv(const char* name, const s32* v) const;
void Uniform3iv(const char* name, const s32* v) const;
void Uniform4iv(const char* name, const s32* v) const;
void Uniform2fv(const char* name, const float* v) const;
void Uniform3fv(const char* name, const float* v) const;
void Uniform4fv(const char* name, const float* v) const;
void BindUniformBlock(const char* name, u32 index);
void SetName(const std::string_view& name);
void SetFormattedName(const char* format, ...);
Program& operator=(const Program&) = delete;
Program& operator=(Program&& prog);
__fi bool operator==(const Program& rhs) const { return m_program_id == rhs.m_program_id; }
__fi bool operator!=(const Program& rhs) const { return m_program_id != rhs.m_program_id; }
private:
static u32 s_last_program_id;
GLuint m_program_id = 0;
GLuint m_vertex_shader_id = 0;
GLuint m_fragment_shader_id = 0;
std::vector<GLint> m_uniform_locations;
};
} // namespace GL
+443
View File
@@ -0,0 +1,443 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/GL/ShaderCache.h"
#include "common/FileSystem.h"
#include "common/Console.h"
#include "common/MD5Digest.h"
#include "common/StringUtil.h"
#include "common/Timer.h"
namespace GL
{
#pragma pack(push, 1)
struct CacheIndexEntry
{
u64 vertex_source_hash_low;
u64 vertex_source_hash_high;
u32 vertex_source_length;
u64 geometry_source_hash_low;
u64 geometry_source_hash_high;
u32 geometry_source_length;
u64 fragment_source_hash_low;
u64 fragment_source_hash_high;
u32 fragment_source_length;
u32 file_offset;
u32 blob_size;
u32 blob_format;
};
#pragma pack(pop)
ShaderCache::ShaderCache() = default;
ShaderCache::~ShaderCache()
{
Close();
}
bool ShaderCache::CacheIndexKey::operator==(const CacheIndexKey& key) const
{
return (
vertex_source_hash_low == key.vertex_source_hash_low && vertex_source_hash_high == key.vertex_source_hash_high &&
vertex_source_length == key.vertex_source_length && geometry_source_hash_low == key.geometry_source_hash_low &&
geometry_source_hash_high == key.geometry_source_hash_high &&
geometry_source_length == key.geometry_source_length && fragment_source_hash_low == key.fragment_source_hash_low &&
fragment_source_hash_high == key.fragment_source_hash_high && fragment_source_length == key.fragment_source_length);
}
bool ShaderCache::CacheIndexKey::operator!=(const CacheIndexKey& key) const
{
return (
vertex_source_hash_low != key.vertex_source_hash_low || vertex_source_hash_high != key.vertex_source_hash_high ||
vertex_source_length != key.vertex_source_length || geometry_source_hash_low != key.geometry_source_hash_low ||
geometry_source_hash_high != key.geometry_source_hash_high ||
geometry_source_length != key.geometry_source_length || fragment_source_hash_low != key.fragment_source_hash_low ||
fragment_source_hash_high != key.fragment_source_hash_high || fragment_source_length != key.fragment_source_length);
}
bool ShaderCache::Open(bool is_gles, std::string_view base_path, u32 version)
{
m_base_path = base_path;
m_version = version;
m_program_binary_supported = is_gles || GLAD_GL_ARB_get_program_binary;
if (m_program_binary_supported)
{
// check that there's at least one format and the extension isn't being "faked"
GLint num_formats = 0;
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &num_formats);
Console.WriteLn("%u program binary formats supported by driver", num_formats);
m_program_binary_supported = (num_formats > 0);
}
if (!m_program_binary_supported)
{
Console.Warning("Your GL driver does not support program binaries. Hopefully it has a built-in cache.");
return true;
}
if (!base_path.empty())
{
const std::string index_filename = GetIndexFileName();
const std::string blob_filename = GetBlobFileName();
if (ReadExisting(index_filename, blob_filename))
return true;
return CreateNew(index_filename, blob_filename);
}
return true;
}
bool ShaderCache::CreateNew(const std::string& index_filename, const std::string& blob_filename)
{
if (FileSystem::FileExists(index_filename.c_str()))
{
Console.Warning("Removing existing index file '%s'", index_filename.c_str());
FileSystem::DeleteFilePath(index_filename.c_str());
}
if (FileSystem::FileExists(blob_filename.c_str()))
{
Console.Warning("Removing existing blob file '%s'", blob_filename.c_str());
FileSystem::DeleteFilePath(blob_filename.c_str());
}
m_index_file = FileSystem::OpenCFile(index_filename.c_str(), "wb");
if (!m_index_file)
{
Console.Error("Failed to open index file '%s' for writing", index_filename.c_str());
return false;
}
const u32 index_version = FILE_VERSION;
if (std::fwrite(&index_version, sizeof(index_version), 1, m_index_file) != 1 ||
std::fwrite(&m_version, sizeof(m_version), 1, m_index_file) != 1)
{
Console.Error("Failed to write version to index file '%s'", index_filename.c_str());
std::fclose(m_index_file);
m_index_file = nullptr;
FileSystem::DeleteFilePath(index_filename.c_str());
return false;
}
m_blob_file = FileSystem::OpenCFile(blob_filename.c_str(), "w+b");
if (!m_blob_file)
{
Console.Error("Failed to open blob file '%s' for writing", blob_filename.c_str());
std::fclose(m_index_file);
m_index_file = nullptr;
FileSystem::DeleteFilePath(index_filename.c_str());
return false;
}
return true;
}
bool ShaderCache::ReadExisting(const std::string& index_filename, const std::string& blob_filename)
{
m_index_file = FileSystem::OpenCFile(index_filename.c_str(), "r+b");
if (!m_index_file)
{
// special case here: when there's a sharing violation (i.e. two instances running),
// we don't want to blow away the cache. so just continue without a cache.
if (errno == EACCES)
{
Console.WriteLn("Failed to open shader cache index with EACCES, are you running two instances?");
return true;
}
return false;
}
u32 file_version = 0;
u32 data_version = 0;
if (std::fread(&file_version, sizeof(file_version), 1, m_index_file) != 1 || file_version != FILE_VERSION ||
std::fread(&data_version, sizeof(data_version), 1, m_index_file) != 1 || data_version != m_version)
{
Console.Error("Bad file/data version in '%s'", index_filename.c_str());
std::fclose(m_index_file);
m_index_file = nullptr;
return false;
}
m_blob_file = FileSystem::OpenCFile(blob_filename.c_str(), "a+b");
if (!m_blob_file)
{
Console.Error("Blob file '%s' is missing", blob_filename.c_str());
std::fclose(m_index_file);
m_index_file = nullptr;
return false;
}
std::fseek(m_blob_file, 0, SEEK_END);
const u32 blob_file_size = static_cast<u32>(std::ftell(m_blob_file));
for (;;)
{
CacheIndexEntry entry;
if (std::fread(&entry, sizeof(entry), 1, m_index_file) != 1 ||
(entry.file_offset + entry.blob_size) > blob_file_size)
{
if (std::feof(m_index_file))
break;
Console.Error("Failed to read entry from '%s', corrupt file?", index_filename.c_str());
m_index.clear();
std::fclose(m_blob_file);
m_blob_file = nullptr;
std::fclose(m_index_file);
m_index_file = nullptr;
return false;
}
const CacheIndexKey key{
entry.vertex_source_hash_low, entry.vertex_source_hash_high, entry.vertex_source_length,
entry.geometry_source_hash_low, entry.geometry_source_hash_high, entry.geometry_source_length,
entry.fragment_source_hash_low, entry.fragment_source_hash_high, entry.fragment_source_length};
const CacheIndexData data{entry.file_offset, entry.blob_size, entry.blob_format};
m_index.emplace(key, data);
}
Console.WriteLn("Read %zu entries from '%s'", m_index.size(), index_filename.c_str());
return true;
}
void ShaderCache::Close()
{
m_index.clear();
if (m_index_file)
std::fclose(m_index_file);
if (m_blob_file)
std::fclose(m_blob_file);
}
bool ShaderCache::Recreate()
{
Close();
const std::string index_filename = GetIndexFileName();
const std::string blob_filename = GetBlobFileName();
return CreateNew(index_filename, blob_filename);
}
ShaderCache::CacheIndexKey ShaderCache::GetCacheKey(const std::string_view& vertex_shader,
const std::string_view& geometry_shader,
const std::string_view& fragment_shader)
{
union ShaderHash
{
struct
{
u64 low;
u64 high;
};
u8 bytes[16];
};
ShaderHash vertex_hash = {};
ShaderHash geometry_hash = {};
ShaderHash fragment_hash = {};
MD5Digest digest;
if (!vertex_shader.empty())
{
digest.Update(vertex_shader.data(), static_cast<u32>(vertex_shader.length()));
digest.Final(vertex_hash.bytes);
}
if (!geometry_shader.empty())
{
digest.Reset();
digest.Update(geometry_shader.data(), static_cast<u32>(geometry_shader.length()));
digest.Final(geometry_hash.bytes);
}
if (!fragment_shader.empty())
{
digest.Reset();
digest.Update(fragment_shader.data(), static_cast<u32>(fragment_shader.length()));
digest.Final(fragment_hash.bytes);
}
return CacheIndexKey{vertex_hash.low, vertex_hash.high, static_cast<u32>(vertex_shader.length()),
geometry_hash.low, geometry_hash.high, static_cast<u32>(geometry_shader.length()),
fragment_hash.low, fragment_hash.high, static_cast<u32>(fragment_shader.length())};
}
std::string ShaderCache::GetIndexFileName() const
{
return StringUtil::StdStringFromFormat("%s/gl_programs.idx", m_base_path.c_str());
}
std::string ShaderCache::GetBlobFileName() const
{
return StringUtil::StdStringFromFormat("%s/gl_programs.bin", m_base_path.c_str());
}
std::optional<Program> ShaderCache::GetProgram(const std::string_view vertex_shader,
const std::string_view geometry_shader,
const std::string_view fragment_shader, const PreLinkCallback& callback)
{
if (!m_program_binary_supported || !m_blob_file)
{
#ifdef PCSX2_DEVBUILD
Common::Timer timer;
#endif
std::optional<Program> res = CompileProgram(vertex_shader, geometry_shader, fragment_shader, callback, false);
#ifdef PCSX2_DEVBUILD
Console.WriteLn("Time to compile shader without caching: %.2fms", timer.GetTimeMilliseconds());
#endif
return res;
}
const auto key = GetCacheKey(vertex_shader, geometry_shader, fragment_shader);
auto iter = m_index.find(key);
if (iter == m_index.end())
return CompileAndAddProgram(key, vertex_shader, geometry_shader, fragment_shader, callback);
std::vector<u8> data(iter->second.blob_size);
if (std::fseek(m_blob_file, iter->second.file_offset, SEEK_SET) != 0 ||
std::fread(data.data(), 1, iter->second.blob_size, m_blob_file) != iter->second.blob_size)
{
Console.Error("Read blob from file failed");
return {};
}
#ifdef PCSX2_DEVBUILD
Common::Timer timer;
#endif
Program prog;
if (prog.CreateFromBinary(data.data(), static_cast<u32>(data.size()), iter->second.blob_format))
{
#ifdef PCSX2_DEVBUILD
Console.WriteLn("Time to create program from binary: %.2fms", timer.GetTimeMilliseconds());
#endif
return std::optional<Program>(std::move(prog));
}
Console.Warning(
"Failed to create program from binary, this may be due to a driver or GPU Change. Recreating cache.");
if (!Recreate())
return CompileProgram(vertex_shader, geometry_shader, fragment_shader, callback, false);
else
return CompileAndAddProgram(key, vertex_shader, geometry_shader, fragment_shader, callback);
}
bool ShaderCache::GetProgram(Program* out_program, const std::string_view vertex_shader,
const std::string_view geometry_shader, const std::string_view fragment_shader,
const PreLinkCallback& callback /* = */)
{
auto prog = GetProgram(vertex_shader, geometry_shader, fragment_shader, callback);
if (!prog)
return false;
*out_program = std::move(*prog);
return true;
}
std::optional<Program> ShaderCache::CompileProgram(const std::string_view& vertex_shader,
const std::string_view& geometry_shader,
const std::string_view& fragment_shader,
const PreLinkCallback& callback, bool set_retrievable)
{
Program prog;
if (!prog.Compile(vertex_shader, geometry_shader, fragment_shader))
return std::nullopt;
if (callback)
callback(prog);
if (set_retrievable)
prog.SetBinaryRetrievableHint();
if (!prog.Link())
return std::nullopt;
return std::optional<Program>(std::move(prog));
}
std::optional<Program> ShaderCache::CompileAndAddProgram(const CacheIndexKey& key,
const std::string_view& vertex_shader,
const std::string_view& geometry_shader,
const std::string_view& fragment_shader,
const PreLinkCallback& callback)
{
#ifdef PCSX2_DEVBUILD
Common::Timer timer;
#endif
std::optional<Program> prog = CompileProgram(vertex_shader, geometry_shader, fragment_shader, callback, true);
if (!prog)
return std::nullopt;
#ifdef PCSX2_DEVBUILD
const float compile_time = timer.GetTimeMilliseconds();
timer.Reset();
#endif
std::vector<u8> prog_data;
u32 prog_format = 0;
if (!prog->GetBinary(&prog_data, &prog_format))
return std::nullopt;
#ifdef PCSX2_DEVBUILD
const float binary_time = timer.GetTimeMilliseconds();
timer.Reset();
#endif
if (!m_blob_file || std::fseek(m_blob_file, 0, SEEK_END) != 0)
return prog;
CacheIndexData data;
data.file_offset = static_cast<u32>(std::ftell(m_blob_file));
data.blob_size = static_cast<u32>(prog_data.size());
data.blob_format = prog_format;
CacheIndexEntry entry = {};
entry.vertex_source_hash_low = key.vertex_source_hash_low;
entry.vertex_source_hash_high = key.vertex_source_hash_high;
entry.vertex_source_length = key.vertex_source_length;
entry.geometry_source_hash_low = key.geometry_source_hash_low;
entry.geometry_source_hash_high = key.geometry_source_hash_high;
entry.geometry_source_length = key.geometry_source_length;
entry.fragment_source_hash_low = key.fragment_source_hash_low;
entry.fragment_source_hash_high = key.fragment_source_hash_high;
entry.fragment_source_length = key.fragment_source_length;
entry.file_offset = data.file_offset;
entry.blob_size = data.blob_size;
entry.blob_format = data.blob_format;
if (std::fwrite(prog_data.data(), 1, entry.blob_size, m_blob_file) != entry.blob_size ||
std::fflush(m_blob_file) != 0 || std::fwrite(&entry, sizeof(entry), 1, m_index_file) != 1 ||
std::fflush(m_index_file) != 0)
{
Console.Error("Failed to write shader blob to file");
return prog;
}
#ifdef PCSX2_DEVBUILD
const float write_time = timer.GetTimeMilliseconds();
Console.WriteLn("Compiled and cached shader: Compile: %.2fms, Binary: %.2fms, Write: %.2fms", compile_time, binary_time, write_time);
#endif
m_index.emplace(key, data);
return prog;
}
} // namespace GL
+112
View File
@@ -0,0 +1,112 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include "common/HashCombine.h"
#include "common/GL/Program.h"
#include <cstdio>
#include <functional>
#include <optional>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>
namespace GL
{
class ShaderCache
{
public:
using PreLinkCallback = std::function<void(Program&)>;
ShaderCache();
~ShaderCache();
bool Open(bool is_gles, std::string_view base_path, u32 version);
std::optional<Program> GetProgram(const std::string_view vertex_shader, const std::string_view geometry_shader,
const std::string_view fragment_shader, const PreLinkCallback& callback = {});
bool GetProgram(Program* out_program, const std::string_view vertex_shader, const std::string_view geometry_shader,
const std::string_view fragment_shader, const PreLinkCallback& callback = {});
private:
static constexpr u32 FILE_VERSION = 1;
struct CacheIndexKey
{
u64 vertex_source_hash_low;
u64 vertex_source_hash_high;
u32 vertex_source_length;
u64 geometry_source_hash_low;
u64 geometry_source_hash_high;
u32 geometry_source_length;
u64 fragment_source_hash_low;
u64 fragment_source_hash_high;
u32 fragment_source_length;
bool operator==(const CacheIndexKey& key) const;
bool operator!=(const CacheIndexKey& key) const;
};
struct CacheIndexEntryHasher
{
std::size_t operator()(const CacheIndexKey& e) const noexcept
{
std::size_t h = 0;
HashCombine(h,
e.vertex_source_hash_low, e.vertex_source_hash_high, e.vertex_source_length,
e.geometry_source_hash_low, e.geometry_source_hash_high, e.geometry_source_length,
e.fragment_source_hash_low, e.fragment_source_hash_high, e.fragment_source_length);
return h;
}
};
struct CacheIndexData
{
u32 file_offset;
u32 blob_size;
u32 blob_format;
};
using CacheIndex = std::unordered_map<CacheIndexKey, CacheIndexData, CacheIndexEntryHasher>;
static CacheIndexKey GetCacheKey(const std::string_view& vertex_shader, const std::string_view& geometry_shader,
const std::string_view& fragment_shader);
std::string GetIndexFileName() const;
std::string GetBlobFileName() const;
bool CreateNew(const std::string& index_filename, const std::string& blob_filename);
bool ReadExisting(const std::string& index_filename, const std::string& blob_filename);
void Close();
bool Recreate();
std::optional<Program> CompileProgram(const std::string_view& vertex_shader, const std::string_view& geometry_shader,
const std::string_view& fragment_shader, const PreLinkCallback& callback,
bool set_retrievable);
std::optional<Program> CompileAndAddProgram(const CacheIndexKey& key, const std::string_view& vertex_shader,
const std::string_view& geometry_shader,
const std::string_view& fragment_shader, const PreLinkCallback& callback);
std::string m_base_path;
std::FILE* m_index_file = nullptr;
std::FILE* m_blob_file = nullptr;
CacheIndex m_index;
u32 m_version = 0;
bool m_program_binary_supported = false;
};
} // namespace GL
+26
View File
@@ -0,0 +1,26 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <functional>
#include <utility>
template <typename T, typename... Rest>
static inline void HashCombine(std::size_t& seed, const T& v, Rest&&... rest)
{
seed ^= std::hash<T>{}(v) + 0x9e3779b9u + (seed << 6) + (seed >> 2);
(HashCombine(seed, std::forward<Rest>(rest)), ...);
}
+222
View File
@@ -0,0 +1,222 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "MD5Digest.h"
#include <cstring>
// mostly based on this implementation (public domain): http://www.fourmilab.ch/md5/
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x)
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
static void MD5Transform(u32 buf[4], u32 in[16])
{
u32 a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
MD5Digest::MD5Digest()
{
Reset();
}
void MD5Digest::Reset()
{
buf[0] = 0x67452301;
buf[1] = 0xefcdab89;
buf[2] = 0x98badcfe;
buf[3] = 0x10325476;
bits[0] = 0;
bits[1] = 0;
std::memset(in, 0, sizeof(in));
}
void MD5Digest::Update(const void* pData, u32 cbData)
{
u32 t;
const u8* pByteData = reinterpret_cast<const u8*>(pData);
/* Update bitcount */
t = this->bits[0];
if ((this->bits[0] = t + ((u32)cbData << 3)) < t)
this->bits[1]++; /* Carry from low to high */
this->bits[1] += cbData >> 29;
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
/* Handle any leading odd-sized chunks */
if (t)
{
u8* p = (u8*)this->in + t;
t = 64 - t;
if (cbData < t)
{
std::memcpy(p, pByteData, cbData);
return;
}
std::memcpy(p, pByteData, t);
MD5Transform(this->buf, (u32*)this->in);
pByteData += t;
cbData -= t;
}
/* Process data in 64-byte chunks */
while (cbData >= 64)
{
std::memcpy(this->in, pByteData, 64);
MD5Transform(this->buf, (u32*)this->in);
pByteData += 64;
cbData -= 64;
}
/* Handle any remaining bytes of data. */
std::memcpy(this->in, pByteData, cbData);
}
void MD5Digest::Final(u8 Digest[16])
{
u32 count;
u8* p;
/* Compute number of bytes mod 64 */
count = (this->bits[0] >> 3) & 0x3F;
/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
p = this->in + count;
*p++ = 0x80;
/* Bytes of padding needed to make 64 bytes */
count = 64 - 1 - count;
/* Pad out to 56 mod 64 */
if (count < 8)
{
/* Two lots of padding: Pad the first block to 64 bytes */
std::memset(p, 0, count);
MD5Transform(this->buf, (u32*)this->in);
/* Now fill the next block with 56 bytes */
std::memset(this->in, 0, 56);
}
else
{
/* Pad block to 56 bytes */
std::memset(p, 0, count - 8);
}
/* Append length in bits and transform */
((u32*)this->in)[14] = this->bits[0];
((u32*)this->in)[15] = this->bits[1];
MD5Transform(this->buf, (u32*)this->in);
std::memcpy(Digest, this->buf, 16);
}
+32
View File
@@ -0,0 +1,32 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "Pcsx2Types.h"
class MD5Digest
{
public:
MD5Digest();
void Update(const void* pData, u32 cbData);
void Final(u8 Digest[16]);
void Reset();
private:
u32 buf[4];
u32 bits[2];
u8 in[64];
};
+5
View File
@@ -18,6 +18,10 @@
#include <wx/filename.h>
#include "common/StringHelpers.h"
#include "ghc/filesystem.h"
namespace fs = ghc::filesystem;
#define g_MaxPath 255 // 255 is safer with antiquated Win32 ASCII APIs.
// --------------------------------------------------------------------------------------
@@ -233,4 +237,5 @@ namespace Path
extern wxString GetDirectory(const wxString& src);
extern wxString GetFilenameWithoutExt(const wxString& src);
extern wxString GetRootDirectory(const wxString& src);
extern fs::path FromWxString(const wxString& path);
} // namespace Path
+9 -1
View File
@@ -195,7 +195,6 @@ wxString Path::GetDirectory(const wxString& src)
return wxFileName(src).GetPath();
}
// returns the base/root directory of the given path.
// Example /this/that/something.txt -> dest == "/"
wxString Path::GetRootDirectory(const wxString& src)
@@ -206,3 +205,12 @@ wxString Path::GetRootDirectory(const wxString& src)
else
return wxString(src.begin(), src.begin() + pos);
}
fs::path Path::FromWxString(const wxString& path)
{
#ifdef _WIN32
return fs::path(path.ToStdWstring());
#else
return fs::path(path.ToStdString());
#endif
}
+2 -11
View File
@@ -166,15 +166,6 @@ int SettingsSaveWrapper::EntryBitfield(const char* section, const char* var, int
void SettingsSaveWrapper::_EnumEntry(const char* section, const char* var, int& value, const char* const* enumArray, int defvalue)
{
const int cnt = _calcEnumLength(enumArray);
if (value >= cnt)
{
Console.Warning("(SaveSettings) An illegal enumerated index was detected when saving '%s'", var);
Console.Indent().Warning(
"Illegal Value: %d\n"
"Using Default: %d (%s)\n",
value, defvalue, enumArray[defvalue]);
value = defvalue;
}
m_si.SetIntValue(section, var, value);
const int index = (value < 0 || value >= cnt) ? defvalue : value;
m_si.SetStringValue(section, var, enumArray[index]);
}
+79 -4
View File
@@ -19,6 +19,7 @@
#include <codecvt>
#include <cstdio>
#include <sstream>
#include <algorithm>
#ifdef _WIN32
#include "RedtapeWindows.h"
@@ -206,7 +207,49 @@ namespace StringUtil
return ss.str();
}
#ifdef _WIN32
std::string toLower(const std::string_view& input)
{
std::string newStr;
std::transform(input.begin(), input.end(), std::back_inserter(newStr),
[](unsigned char c) { return std::tolower(c); });
return newStr;
}
bool compareNoCase(const std::string_view& str1, const std::string_view& str2)
{
if (str1.length() != str2.length())
{
return false;
}
return Strncasecmp(str1.data(), str2.data(), str1.length()) == 0;
}
std::vector<std::string> splitOnNewLine(const std::string& str)
{
std::vector<std::string> lines;
std::istringstream stream(str);
std::string line;
while (std::getline(stream, line))
{
lines.push_back(line);
}
return lines;
}
std::string_view StripWhitespace(const std::string_view& str)
{
std::string_view::size_type start = 0;
while (start < str.size() && std::isspace(str[start]))
start++;
if (start == str.size())
return {};
std::string_view::size_type end = str.size() - 1;
while (end > start && std::isspace(str[end]))
end--;
return str.substr(start, end - start + 1);
}
std::wstring UTF8StringToWideString(const std::string_view& str)
{
@@ -219,6 +262,7 @@ namespace StringUtil
bool UTF8StringToWideString(std::wstring& dest, const std::string_view& str)
{
#ifdef _WIN32
int wlen = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.length()), nullptr, 0);
if (wlen < 0)
return false;
@@ -228,19 +272,36 @@ namespace StringUtil
return false;
return true;
#else
// This depends on wxString, which isn't great. But hopefully we won't need any wide strings outside
// of windows once wx is gone anyway.
if (str.empty())
{
dest.clear();
return true;
}
const wxString wxstr(wxString::FromUTF8(str.data(), str.length()));
if (wxstr.IsEmpty())
return false;
dest = wxstr.ToStdWstring();
return true;
#endif
}
std::string WideStringToUTF8String(const std::wstring_view& str)
{
std::string ret;
if (!WideStringToUTF8String(ret, str))
return {};
ret.clear();
return ret;
}
bool WideStringToUTF8String(std::string& dest, const std::wstring_view& str)
{
#ifdef _WIN32
int mblen = WideCharToMultiByte(CP_UTF8, 0, str.data(), static_cast<int>(str.length()), nullptr, 0, nullptr, nullptr);
if (mblen < 0)
return false;
@@ -253,8 +314,22 @@ namespace StringUtil
}
return true;
}
#else
// This depends on wxString, which isn't great. But hopefully we won't need any wide strings outside
// of windows once wx is gone anyway.
if (str.empty())
{
dest.clear();
return true;
}
const wxString wxstr(str.data(), str.data() + str.length());
if (wxstr.IsEmpty())
return false;
const auto buf = wxstr.ToUTF8();
dest.assign(buf.data(), buf.length());
return true;
#endif
}
} // namespace StringUtil
+7 -5
View File
@@ -153,6 +153,9 @@ namespace StringUtil
return (str.length() >= suffix_length && str.compare(str.length() - suffix_length, suffix_length, suffix) == 0);
}
/// Strip whitespace from the start/end of the string.
std::string_view StripWhitespace(const std::string_view& str);
/// Strided memcpy/memcmp.
static inline void StrideMemCpy(void* dst, std::size_t dst_stride, const void* src, std::size_t src_stride,
std::size_t copy_size, std::size_t count)
@@ -184,6 +187,10 @@ namespace StringUtil
return 0;
}
std::string toLower(const std::string_view& str);
bool compareNoCase(const std::string_view& str1, const std::string_view& str2);
std::vector<std::string> splitOnNewLine(const std::string& str);
/// Converts a wxString to a UTF-8 std::string.
static std::string wxStringToUTF8String(const wxString& str)
{
@@ -203,8 +210,6 @@ namespace StringUtil
return wxString::FromUTF8(str.data(), str.length());
}
#ifdef _WIN32
/// Converts the specified UTF-8 string to a wide string.
std::wstring UTF8StringToWideString(const std::string_view& str);
bool UTF8StringToWideString(std::wstring& dest, const std::string_view& str);
@@ -212,7 +217,4 @@ namespace StringUtil
/// Converts the specified wide string to a UTF-8 string.
std::string WideStringToUTF8String(const std::wstring_view& str);
bool WideStringToUTF8String(std::string& dest, const std::wstring_view& str);
#endif
} // namespace StringUtil
+7
View File
@@ -51,9 +51,12 @@
</ClCompile>
<ClCompile Include="GL\Context.cpp" />
<ClCompile Include="GL\ContextWGL.cpp" />
<ClCompile Include="GL\Program.cpp" />
<ClCompile Include="GL\ShaderCache.cpp" />
<ClCompile Include="GL\StreamBuffer.cpp" />
<ClCompile Include="FileSystem.cpp" />
<ClCompile Include="IniInterface.cpp" />
<ClCompile Include="MD5Digest.cpp" />
<ClCompile Include="ProgressCallback.cpp" />
<ClCompile Include="pxStreams.cpp" />
<ClCompile Include="pxTranslate.cpp" />
@@ -110,8 +113,12 @@
<ClInclude Include="FastJmp.h" />
<ClInclude Include="GL\Context.h" />
<ClInclude Include="GL\ContextWGL.h" />
<ClInclude Include="GL\Program.h" />
<ClInclude Include="GL\ShaderCache.h" />
<ClInclude Include="GL\StreamBuffer.h" />
<ClInclude Include="FileSystem.h" />
<ClInclude Include="HashCombine.h" />
<ClInclude Include="MD5Digest.h" />
<ClInclude Include="ProgressCallback.h" />
<ClInclude Include="ScopedGuard.h" />
<ClInclude Include="StringUtil.h" />
+22 -1
View File
@@ -142,6 +142,15 @@
<ClCompile Include="ProgressCallback.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MD5Digest.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GL\Program.cpp">
<Filter>Source Files\GL</Filter>
</ClCompile>
<ClCompile Include="GL\ShaderCache.cpp">
<Filter>Source Files\GL</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="AlignedMalloc.h">
@@ -330,6 +339,18 @@
<ClInclude Include="ScopedGuard.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="HashCombine.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MD5Digest.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GL\Program.h">
<Filter>Header Files\GL</Filter>
</ClInclude>
<ClInclude Include="GL\ShaderCache.h">
<Filter>Header Files\GL</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Source Files">
@@ -355,4 +376,4 @@
<Filter>Source Files</Filter>
</MASM>
</ItemGroup>
</Project>
</Project>
+4
View File
@@ -22,6 +22,10 @@
#define ATTR_DEP
#endif
#ifdef FSCALE
# undef FSCALE // Defined in a macOS header
#endif
//------------------------------------------------------------------
// legacy jump/align functions
//------------------------------------------------------------------
+1 -1
View File
@@ -6,7 +6,7 @@
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\;$(SolutionDir)3rdparty\soundtouch\soundtouch\;$(SolutionDir)3rdparty\yaml-cpp\yaml-cpp\include\;$(SolutionDir)3rdparty\fmt\fmt\include\;$(SolutionDir)3rdparty\libchdr\libchdr\include;$(SolutionDir)3rdparty\wil\include;$(SolutionDir)3rdparty\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\;$(SolutionDir)3rdparty\soundtouch\soundtouch\;$(SolutionDir)3rdparty\rapidyaml\rapidyaml\src;$(SolutionDir)3rdparty\rapidyaml\rapidyaml\ext\c4core\src;$(SolutionDir)3rdparty\fmt\fmt\include\;$(SolutionDir)3rdparty\libchdr\libchdr\include;$(SolutionDir)3rdparty\wil\include;$(SolutionDir)3rdparty\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIL_SUPPRESS_EXCEPTIONS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
+1 -1
View File
@@ -43,7 +43,7 @@ fi
DIR=`dirname $current_script`
MY_LD_LIBRARY_PATH=$LD_LIBRARY_PATH
if [ ! -x "$DIR/PCSX2" ]
if [ ! -x "$DIR/pcsx2" ]
then
echo "Error PCSX2 not found in $DIR"
echo "Maybe the script was directly 'called'"
+1 -1
View File
@@ -9,7 +9,7 @@ GenericName[zh_CN]=PlayStation 2 模拟器
Comment=Sony PlayStation 2 emulator
Comment[ru]=Эмулятор Sony PlayStation 2
Comment[zh_CN]=索尼 PlayStation 2 模拟器
Exec=env GDK_BACKEND=x11 MESA_NO_ERROR=1 PCSX2
Exec=env GDK_BACKEND=x11 MESA_NO_ERROR=1 pcsx2
Icon=PCSX2
Keywords=game;emulator;
Categories=@PCSX2_MENU_CATEGORIES@
+20
View File
@@ -35,6 +35,12 @@
#include "Recording/InputRecording.h"
#endif
#ifndef PCSX2_CORE
#include "System/SysThreads.h"
#else
#include "VMManager.h"
#endif
// This typically reflects the Sony-assigned serial code for the Disc, if one exists.
// (examples: SLUS-2113, etc).
// If the disc is homebrew then it probably won't have a valid serial; in which case
@@ -492,8 +498,18 @@ void cdvdReloadElfInfo(wxString elfoverride)
}
catch (Exception::FileNotFound& e)
{
#ifdef PCSX2_CORE
Console.Error("Failed to load ELF info");
LastELF.clear();
DiscSerial.clear();
ElfCRC = 0;
ElfEntry = 0;
ElfTextRange = {};
return;
#else
pxFail("Not in my back yard!");
Cpu->ThrowException(e);
#endif
}
}
@@ -2146,7 +2162,11 @@ static void cdvdWrite16(u8 rt) // SCOMMAND
case 0x0F: // sceCdPowerOff (0:1)- Call74 from Xcdvdman
Console.WriteLn(Color_StrongBlack, "sceCdPowerOff called. Resetting VM.");
#ifndef PCSX2_CORE
GetCoreThread().Reset();
#else
VMManager::Reset();
#endif
break;
case 0x12: // sceCdReadILinkId (0:9)
+4
View File
@@ -173,9 +173,13 @@ static void TestTemplate(const wxDirName &base, const wxString &fname, bool canE
static std::string iso2indexname(const std::string& isoname)
{
#ifndef PCSX2_CORE
//testTemplate(isoname);
wxDirName appRoot = // TODO: have only one of this in PCSX2. Right now have few...
(wxDirName)(wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath());
#else
const wxDirName& appRoot = EmuFolders::DataRoot;
#endif
//TestTemplate(appRoot, isoname, false);
return StringUtil::wxStringToUTF8String(ApplyTemplate(L"gzip index", appRoot, EmuConfig.GzipIsoIndexTemplate, isoname, false));
}
+9 -5
View File
@@ -629,7 +629,6 @@ set(pcsx2GSSources
GS/Renderers/OpenGL/GLLoader.cpp
GS/Renderers/OpenGL/GLState.cpp
GS/Renderers/OpenGL/GSDeviceOGL.cpp
GS/Renderers/OpenGL/GSShaderOGL.cpp
GS/Renderers/OpenGL/GSTextureOGL.cpp
GS/Window/GSSetting.cpp
GS/Window/GSwxDialog.cpp
@@ -699,7 +698,6 @@ set(pcsx2GSHeaders
GS/Renderers/OpenGL/GLLoader.h
GS/Renderers/OpenGL/GLState.h
GS/Renderers/OpenGL/GSDeviceOGL.h
GS/Renderers/OpenGL/GSShaderOGL.h
GS/Renderers/OpenGL/GSTextureOGL.h
GS/Renderers/OpenGL/GSUniformBufferOGL.h
GS/Window/GSCaptureDlg.h
@@ -1369,7 +1367,7 @@ target_link_libraries(PCSX2_FLAGS INTERFACE
common
glad
fmt::fmt
yaml-cpp
ryml
chdr-static
wxWidgets::all
ZLIB::ZLIB
@@ -1483,6 +1481,12 @@ foreach(path IN LISTS RESOURCE_FILES)
pcsx2_resource(${path} ${CMAKE_SOURCE_DIR}/bin/resources/)
endforeach()
if (NOT APPLE)
set_target_properties(PCSX2 PROPERTIES
OUTPUT_NAME pcsx2
)
endif()
if (APPLE)
# MacOS defaults to having a maximum protection of the __DATA segment of rw (non-executable)
# We have a bunch of page-sized arrays in bss that we use for jit
@@ -1522,9 +1526,9 @@ endif()
if(NOT DISABLE_SETCAP)
if(PACKAGE_MODE)
install(CODE "execute_process(COMMAND /bin/bash -c \"echo 'Enabling networking capability on Linux...';set -x; [ -f '${CMAKE_INSTALL_FULL_BINDIR}/PCSX2' ] && sudo setcap 'CAP_NET_RAW+eip CAP_NET_ADMIN+eip' '${CMAKE_INSTALL_FULL_BINDIR}/PCSX2'; set +x\")")
install(CODE "execute_process(COMMAND /bin/bash -c \"echo 'Enabling networking capability on Linux...';set -x; [ -f '${CMAKE_INSTALL_FULL_BINDIR}/pcsx2' ] && sudo setcap 'CAP_NET_RAW+eip CAP_NET_ADMIN+eip' '${CMAKE_INSTALL_FULL_BINDIR}/pcsx2'; set +x\")")
else()
install(CODE "execute_process(COMMAND /bin/bash -c \"echo 'Enabling networking capability on Linux...';set -x; [ -f '${CMAKE_SOURCE_DIR}/bin/PCSX2' ] && sudo setcap 'CAP_NET_RAW+eip CAP_NET_ADMIN+eip' '${CMAKE_SOURCE_DIR}/bin/PCSX2'; set +x\")")
install(CODE "execute_process(COMMAND /bin/bash -c \"echo 'Enabling networking capability on Linux...';set -x; [ -f '${CMAKE_SOURCE_DIR}/bin/pcsx2' ] && sudo setcap 'CAP_NET_RAW+eip CAP_NET_ADMIN+eip' '${CMAKE_SOURCE_DIR}/bin/pcsx2'; set +x\")")
endif()
endif()
+87
View File
@@ -378,6 +378,82 @@ struct Pcsx2Config
}
};
struct SPU2Options
{
enum class InterpolationMode
{
Nearest,
Linear,
Cubic,
Hermite,
CatmullRom,
Gaussian
};
enum class SynchronizationMode
{
TimeStretch,
ASync,
NoSync,
};
BITFIELD32()
bool
AdvancedVolumeControl : 1;
BITFIELD_END
InterpolationMode Interpolation = InterpolationMode::Gaussian;
SynchronizationMode SynchMode = SynchronizationMode::TimeStretch;
s32 FinalVolume = 100;
s32 Latency{100};
s32 SpeakerConfiguration{0};
double VolumeAdjustC{ 0.0f };
double VolumeAdjustFL{ 0.0f };
double VolumeAdjustFR{ 0.0f };
double VolumeAdjustBL{ 0.0f };
double VolumeAdjustBR{ 0.0f };
double VolumeAdjustSL{ 0.0f };
double VolumeAdjustSR{ 0.0f };
double VolumeAdjustLFE{ 0.0f };
std::string OutputModule;
SPU2Options();
void LoadSave(SettingsWrapper& wrap);
bool operator==(const SPU2Options& right) const
{
return OpEqu(bitset) &&
OpEqu(Interpolation) &&
OpEqu(SynchMode) &&
OpEqu(FinalVolume) &&
OpEqu(Latency) &&
OpEqu(SpeakerConfiguration) &&
OpEqu(VolumeAdjustC) &&
OpEqu(VolumeAdjustFL) &&
OpEqu(VolumeAdjustFR) &&
OpEqu(VolumeAdjustBL) &&
OpEqu(VolumeAdjustBR) &&
OpEqu(VolumeAdjustSL) &&
OpEqu(VolumeAdjustSR) &&
OpEqu(VolumeAdjustLFE) &&
OpEqu(OutputModule);
}
bool operator!=(const SPU2Options& right) const
{
return !this->operator==(right);
}
};
// ------------------------------------------------------------------------
// NOTE: The GUI's GameFixes panel is dependent on the order of bits in this structure.
struct GamefixOptions
@@ -576,6 +652,7 @@ struct Pcsx2Config
ProfilerOptions Profiler;
DebugOptions Debugger;
FramerateOptions Framerate;
SPU2Options SPU2;
TraceLogFilters Trace;
@@ -618,6 +695,8 @@ extern Pcsx2Config EmuConfig;
namespace EmuFolders
{
extern wxDirName AppRoot;
extern wxDirName DataRoot;
extern wxDirName Settings;
extern wxDirName Bios;
extern wxDirName Snapshots;
@@ -629,6 +708,14 @@ namespace EmuFolders
extern wxDirName CheatsWS;
extern wxDirName Resources;
extern wxDirName Cache;
extern wxDirName Covers;
extern wxDirName GameSettings;
// Assumes that AppRoot and DataRoot have been initialized.
void SetDefaults();
bool EnsureFoldersExist();
void LoadConfig(SettingsInterface& si);
void Save(SettingsInterface& si);
} // namespace EmuFolders
/////////////////////////////////////////////////////////////////////////////////////////
+8
View File
@@ -20,6 +20,7 @@
void HddCreate::Start()
{
#ifndef PCSX2_CORE
//This can be called from the EE Core thread
//ensure that UI creation/deletaion is done on main thread
if (!wxIsMainThread())
@@ -33,6 +34,7 @@ void HddCreate::Start()
//This creates a modeless dialog
progressDialog = new wxProgressDialog(_("Creating HDD file"), _("Creating HDD file"), neededSize, nullptr, wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_CAN_ABORT | wxPD_ELAPSED_TIME | wxPD_REMAINING_TIME);
#endif
fileThread = std::thread(&HddCreate::WriteImage, this, filePath, neededSize);
@@ -47,8 +49,10 @@ void HddCreate::Start()
{
msg.Printf(_("%i / %i MiB"), written.load(), neededSize);
#ifndef PCSX2_CORE
if (!progressDialog->Update(currentSize, msg))
canceled.store(true);
#endif
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
@@ -57,11 +61,15 @@ void HddCreate::Start()
if (errored.load())
{
#ifndef PCSX2_CORE
wxMessageDialog dialog(nullptr, _("Failed to create HDD file"), _("Info"), wxOK);
dialog.ShowModal();
#endif
}
#ifndef PCSX2_CORE
delete progressDialog;
#endif
//Signal calling thread to resume
{
std::lock_guard ioSignallock(completedMutex);
+4
View File
@@ -15,7 +15,9 @@
#pragma once
#ifndef PCSX2_CORE
#include <wx/progdlg.h>
#endif
#include <string>
#include <thread>
@@ -33,7 +35,9 @@ public:
std::atomic_bool errored{false};
private:
#ifndef PCSX2_CORE
wxProgressDialog* progressDialog;
#endif
std::atomic_int written{0};
std::thread fileThread;
+1 -1
View File
@@ -16,7 +16,7 @@
#include "PrecompiledHeader.h"
#ifdef _WIN32
//#include <winsock2.h>
#include "common/RedtapeWindows.h"
#include <Winioctl.h>
#include <windows.h>
#else
+12 -1
View File
@@ -19,9 +19,12 @@
#include <wx/fileconf.h>
#include "DEV9.h"
#include "gui/AppConfig.h"
#include "common/IniInterface.h"
#ifndef PCSX2_CORE
#include "gui/AppConfig.h"
#endif
#ifdef _WIN32
#include "ws2tcpip.h"
#elif defined(__POSIX__)
@@ -34,7 +37,11 @@
void SaveDnsHosts()
{
#ifndef PCSX2_CORE
std::unique_ptr<wxFileConfig> hini(OpenFileConfig(EmuFolders::Settings.Combine(wxString("DEV9Hosts.ini")).GetFullPath()));
#else
std::unique_ptr<wxFileConfig> hini(new wxFileConfig(wxEmptyString, wxEmptyString, EmuFolders::Settings.Combine(wxString("DEV9Hosts.ini")).GetFullPath(), wxEmptyString, wxCONFIG_USE_RELATIVE_PATH));
#endif
IniSaver ini((wxConfigBase*)hini.get());
for (size_t i = 0; i < config.EthHosts.size(); i++)
@@ -77,7 +84,11 @@ void LoadDnsHosts()
return;
}
#ifndef PCSX2_CORE
std::unique_ptr<wxFileConfig> hini(OpenFileConfig(iniPath.GetFullPath()));
#else
std::unique_ptr<wxFileConfig> hini(new wxFileConfig(wxEmptyString, wxEmptyString, iniPath.GetFullPath(), wxEmptyString, wxCONFIG_USE_RELATIVE_PATH));
#endif
IniLoader ini((wxConfigBase*)hini.get());
int i = 0;
+2
View File
@@ -15,6 +15,8 @@
#include "PrecompiledHeader.h"
#include "common/RedtapeWindows.h"
#include <stdio.h>
#include <windows.h>
#include <winsock2.h>
+1 -2
View File
@@ -16,9 +16,8 @@
#include "PrecompiledHeader.h"
#ifdef _WIN32
//#include <winsock2.h>
#include "common/RedtapeWindows.h"
#include <Winioctl.h>
#include <windows.h>
#endif
#include <stdlib.h>
#include <string.h>
+5
View File
@@ -408,8 +408,10 @@ const std::vector<BreakPoint> CBreakPoints::GetBreakpoints()
}
// including them earlier causes some ambiguities
#ifndef PCSX2_CORE
#include "gui/App.h"
#include "gui/Debugger/DisassemblyDialog.h"
#endif
void CBreakPoints::Update(BreakPointCpu cpu, u32 addr)
{
@@ -427,7 +429,10 @@ void CBreakPoints::Update(BreakPointCpu cpu, u32 addr)
if (resume)
r5900Debug.resumeCpu();
#ifndef PCSX2_CORE
auto disassembly_window = wxGetApp().GetDisassemblyPtr();
if (disassembly_window) // make sure that valid pointer is recieved to prevent potential NULL dereference.
disassembly_window->update();
#endif
}
+12
View File
@@ -167,26 +167,38 @@ private:
bool DebugInterface::isAlive()
{
#ifndef PCSX2_CORE
return GetCoreThread().IsOpen() && g_FrameCount > 0;
#else
return false;
#endif
}
bool DebugInterface::isCpuPaused()
{
#ifndef PCSX2_CORE
return GetCoreThread().IsPaused();
#else
return false;
#endif
}
void DebugInterface::pauseCpu()
{
#ifndef PCSX2_CORE
SysCoreThread& core = GetCoreThread();
if (!core.IsPaused())
core.Pause({}, true);
#endif
}
void DebugInterface::resumeCpu()
{
#ifndef PCSX2_CORE
SysCoreThread& core = GetCoreThread();
if (core.IsPaused())
core.Resume();
#endif
}
+5
View File
@@ -20,7 +20,10 @@
#include "GS.h" // for sending game crc to mtgs
#include "Elfheader.h"
#include "DebugTools/SymbolMap.h"
#ifndef PCSX2_CORE
#include "gui/AppCoreThread.h"
#endif
u32 ElfCRC;
u32 ElfEntry;
@@ -353,7 +356,9 @@ int GetPS2ElfName( wxString& name )
else if( parts.lvalue == L"VER" )
{
Console.WriteLn( Color_Blue, L"(SYSTEM.CNF) Software version = " + parts.rvalue );
#ifndef PCSX2_CORE
GameInfo::gameVersion = parts.rvalue;
#endif
}
}
+242
View File
@@ -0,0 +1,242 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "INISettingsInterface.h"
#include "common/FileSystem.h"
#include "common/Console.h"
#include "common/StringUtil.h"
#include <algorithm>
#include <iterator>
INISettingsInterface::INISettingsInterface(std::string filename)
: m_filename(std::move(filename))
, m_ini(true, true)
{
}
INISettingsInterface::~INISettingsInterface()
{
if (m_dirty)
Save();
}
bool INISettingsInterface::Load()
{
SI_Error err = SI_FAIL;
auto fp = FileSystem::OpenManagedCFile(m_filename.c_str(), "rb");
if (fp)
err = m_ini.LoadFile(fp.get());
return (err == SI_OK);
}
bool INISettingsInterface::Save()
{
SI_Error err = SI_FAIL;
std::FILE* fp = FileSystem::OpenCFile(m_filename.c_str(), "wb");
if (fp)
{
err = m_ini.SaveFile(fp, false);
std::fclose(fp);
}
if (err != SI_OK)
{
Console.Warning("Failed to save settings to '%s'.", m_filename.c_str());
return false;
}
m_dirty = false;
return true;
}
void INISettingsInterface::Clear()
{
m_ini.Reset();
}
bool INISettingsInterface::GetIntValue(const char* section, const char* key, int* value) const
{
const char* str_value = m_ini.GetValue(section, key);
if (!str_value)
return false;
std::optional<int> parsed_value = StringUtil::FromChars<int>(str_value, 10);
if (!parsed_value.has_value())
return false;
*value = parsed_value.value();
return true;
}
bool INISettingsInterface::GetUIntValue(const char* section, const char* key, uint* value) const
{
const char* str_value = m_ini.GetValue(section, key);
if (!str_value)
return false;
std::optional<uint> parsed_value = StringUtil::FromChars<uint>(str_value, 10);
if (!parsed_value.has_value())
return false;
*value = parsed_value.value();
return true;
}
bool INISettingsInterface::GetFloatValue(const char* section, const char* key, float* value) const
{
const char* str_value = m_ini.GetValue(section, key);
if (!str_value)
return false;
std::optional<float> parsed_value = StringUtil::FromChars<float>(str_value);
if (!parsed_value.has_value())
return false;
*value = parsed_value.value();
return true;
}
bool INISettingsInterface::GetDoubleValue(const char* section, const char* key, double* value) const
{
const char* str_value = m_ini.GetValue(section, key);
if (!str_value)
return false;
std::optional<double> parsed_value = StringUtil::FromChars<double>(str_value);
if (!parsed_value.has_value())
return false;
*value = parsed_value.value();
return true;
}
bool INISettingsInterface::GetBoolValue(const char* section, const char* key, bool* value) const
{
const char* str_value = m_ini.GetValue(section, key);
if (!str_value)
return false;
std::optional<bool> parsed_value = StringUtil::FromChars<bool>(str_value);
if (!parsed_value.has_value())
return false;
*value = parsed_value.value();
return true;
}
bool INISettingsInterface::GetStringValue(const char* section, const char* key, std::string* value) const
{
const char* str_value = m_ini.GetValue(section, key);
if (!str_value)
return false;
value->assign(str_value);
return true;
}
void INISettingsInterface::SetIntValue(const char* section, const char* key, int value)
{
m_dirty = true;
m_ini.SetLongValue(section, key, static_cast<long>(value), nullptr, false, true);
}
void INISettingsInterface::SetUIntValue(const char* section, const char* key, uint value)
{
m_dirty = true;
m_ini.SetLongValue(section, key, static_cast<long>(value), nullptr, false, true);
}
void INISettingsInterface::SetFloatValue(const char* section, const char* key, float value)
{
m_dirty = true;
m_ini.SetDoubleValue(section, key, static_cast<double>(value), nullptr, true);
}
void INISettingsInterface::SetDoubleValue(const char* section, const char* key, double value)
{
m_dirty = true;
m_ini.SetDoubleValue(section, key, value, nullptr, true);
}
void INISettingsInterface::SetBoolValue(const char* section, const char* key, bool value)
{
m_dirty = true;
m_ini.SetBoolValue(section, key, value, nullptr, true);
}
void INISettingsInterface::SetStringValue(const char* section, const char* key, const char* value)
{
m_dirty = true;
m_ini.SetValue(section, key, value, nullptr, true);
}
void INISettingsInterface::DeleteValue(const char* section, const char* key)
{
m_dirty = true;
m_ini.Delete(section, key);
}
void INISettingsInterface::ClearSection(const char* section)
{
m_dirty = true;
m_ini.Delete(section, nullptr);
m_ini.SetValue(section, nullptr, nullptr);
}
std::vector<std::string> INISettingsInterface::GetStringList(const char* section, const char* key)
{
std::list<CSimpleIniA::Entry> entries;
if (!m_ini.GetAllValues(section, key, entries))
return {};
std::vector<std::string> ret;
ret.reserve(entries.size());
for (const CSimpleIniA::Entry& entry : entries)
ret.emplace_back(entry.pItem);
return ret;
}
void INISettingsInterface::SetStringList(const char* section, const char* key, const std::vector<std::string>& items)
{
m_dirty = true;
m_ini.Delete(section, key);
for (const std::string& sv : items)
m_ini.SetValue(section, key, sv.c_str(), nullptr, false);
}
bool INISettingsInterface::RemoveFromStringList(const char* section, const char* key, const char* item)
{
m_dirty = true;
return m_ini.DeleteValue(section, key, item, true);
}
bool INISettingsInterface::AddToStringList(const char* section, const char* key, const char* item)
{
std::list<CSimpleIniA::Entry> entries;
if (m_ini.GetAllValues(section, key, entries) &&
std::find_if(entries.begin(), entries.end(),
[item](const CSimpleIniA::Entry& e) { return (std::strcmp(e.pItem, item) == 0); }) != entries.end())
{
return false;
}
m_dirty = true;
m_ini.SetValue(section, key, item, nullptr, false);
return true;
}
+71
View File
@@ -0,0 +1,71 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/SettingsInterface.h"
// being a pain here...
#ifdef _WIN32
#include "common/RedtapeWindows.h"
#endif
#include "SimpleIni.h"
class INISettingsInterface final : public SettingsInterface
{
public:
INISettingsInterface(std::string filename);
~INISettingsInterface() override;
const std::string& GetFileName() const { return m_filename; }
bool Load();
bool Save() override;
void Clear() override;
bool GetIntValue(const char* section, const char* key, int* value) const override;
bool GetUIntValue(const char* section, const char* key, uint* value) const override;
bool GetFloatValue(const char* section, const char* key, float* value) const override;
bool GetDoubleValue(const char* section, const char* key, double* value) const override;
bool GetBoolValue(const char* section, const char* key, bool* value) const override;
bool GetStringValue(const char* section, const char* key, std::string* value) const override;
void SetIntValue(const char* section, const char* key, int value) override;
void SetUIntValue(const char* section, const char* key, uint value) override;
void SetFloatValue(const char* section, const char* key, float value) override;
void SetDoubleValue(const char* section, const char* key, double value) override;
void SetBoolValue(const char* section, const char* key, bool value) override;
void SetStringValue(const char* section, const char* key, const char* value) override;
void DeleteValue(const char* section, const char* key) override;
void ClearSection(const char* section) override;
std::vector<std::string> GetStringList(const char* section, const char* key) override;
void SetStringList(const char* section, const char* key, const std::vector<std::string>& items) override;
bool RemoveFromStringList(const char* section, const char* key, const char* item) override;
bool AddToStringList(const char* section, const char* key, const char* item) override;
// default parameter overloads
using SettingsInterface::GetBoolValue;
using SettingsInterface::GetDoubleValue;
using SettingsInterface::GetFloatValue;
using SettingsInterface::GetIntValue;
using SettingsInterface::GetStringValue;
using SettingsInterface::GetUIntValue;
private:
std::string m_filename;
CSimpleIniA m_ini;
bool m_dirty = false;
};
+192
View File
@@ -0,0 +1,192 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "LayeredSettingsInterface.h"
#include "common/Assertions.h"
LayeredSettingsInterface::LayeredSettingsInterface() = default;
LayeredSettingsInterface::~LayeredSettingsInterface() = default;
bool LayeredSettingsInterface::Save()
{
pxFailRel("Attempting to save layered settings interface");
return false;
}
void LayeredSettingsInterface::Clear()
{
pxFailRel("Attempting to clear layered settings interface");
}
bool LayeredSettingsInterface::GetIntValue(const char* section, const char* key, int* value) const
{
for (u32 layer = FIRST_LAYER; layer <= LAST_LAYER; layer++)
{
if (SettingsInterface* sif = m_layers[layer]; sif != nullptr)
{
if (sif->GetIntValue(section, key, value))
return true;
}
}
return false;
}
bool LayeredSettingsInterface::GetUIntValue(const char* section, const char* key, uint* value) const
{
for (u32 layer = FIRST_LAYER; layer <= LAST_LAYER; layer++)
{
if (SettingsInterface* sif = m_layers[layer]; sif != nullptr)
{
if (sif->GetUIntValue(section, key, value))
return true;
}
}
return false;
}
bool LayeredSettingsInterface::GetFloatValue(const char* section, const char* key, float* value) const
{
for (u32 layer = FIRST_LAYER; layer <= LAST_LAYER; layer++)
{
if (SettingsInterface* sif = m_layers[layer]; sif != nullptr)
{
if (sif->GetFloatValue(section, key, value))
return true;
}
}
return false;
}
bool LayeredSettingsInterface::GetDoubleValue(const char* section, const char* key, double* value) const
{
for (u32 layer = FIRST_LAYER; layer <= LAST_LAYER; layer++)
{
if (SettingsInterface* sif = m_layers[layer]; sif != nullptr)
{
if (sif->GetDoubleValue(section, key, value))
return true;
}
}
return false;
}
bool LayeredSettingsInterface::GetBoolValue(const char* section, const char* key, bool* value) const
{
for (u32 layer = FIRST_LAYER; layer <= LAST_LAYER; layer++)
{
if (SettingsInterface* sif = m_layers[layer]; sif != nullptr)
{
if (sif->GetBoolValue(section, key, value))
return true;
}
}
return false;
}
bool LayeredSettingsInterface::GetStringValue(const char* section, const char* key, std::string* value) const
{
for (u32 layer = FIRST_LAYER; layer <= LAST_LAYER; layer++)
{
if (SettingsInterface* sif = m_layers[layer]; sif != nullptr)
{
if (sif->GetStringValue(section, key, value))
return true;
}
}
return false;
}
void LayeredSettingsInterface::SetIntValue(const char* section, const char* key, int value)
{
pxFailRel("Attempt to call SetIntValue() on layered settings interface");
}
void LayeredSettingsInterface::SetUIntValue(const char* section, const char* key, uint value)
{
pxFailRel("Attempt to call SetUIntValue() on layered settings interface");
}
void LayeredSettingsInterface::SetFloatValue(const char* section, const char* key, float value)
{
pxFailRel("Attempt to call SetFloatValue() on layered settings interface");
}
void LayeredSettingsInterface::SetDoubleValue(const char* section, const char* key, double value)
{
pxFailRel("Attempt to call SetDoubleValue() on layered settings interface");
}
void LayeredSettingsInterface::SetBoolValue(const char* section, const char* key, bool value)
{
pxFailRel("Attempt to call SetBoolValue() on layered settings interface");
}
void LayeredSettingsInterface::SetStringValue(const char* section, const char* key, const char* value)
{
pxFailRel("Attempt to call SetStringValue() on layered settings interface");
}
void LayeredSettingsInterface::DeleteValue(const char* section, const char* key)
{
pxFailRel("Attempt to call DeleteValue() on layered settings interface");
}
void LayeredSettingsInterface::ClearSection(const char* section)
{
pxFailRel("Attempt to call ClearSection() on layered settings interface");
}
std::vector<std::string> LayeredSettingsInterface::GetStringList(const char* section, const char* key)
{
std::vector<std::string> ret;
for (u32 layer = FIRST_LAYER; layer <= LAST_LAYER; layer++)
{
if (SettingsInterface* sif = m_layers[layer]; sif != nullptr)
{
ret = sif->GetStringList(section, key);
if (!ret.empty())
break;
}
}
return ret;
}
void LayeredSettingsInterface::SetStringList(const char* section, const char* key, const std::vector<std::string>& items)
{
pxFailRel("Attempt to call SetStringList() on layered settings interface");
}
bool LayeredSettingsInterface::RemoveFromStringList(const char* section, const char* key, const char* item)
{
pxFailRel("Attempt to call RemoveFromStringList() on layered settings interface");
return false;
}
bool LayeredSettingsInterface::AddToStringList(const char* section, const char* key, const char* item)
{
pxFailRel("Attempt to call AddToStringList() on layered settings interface");
return true;
}
+75
View File
@@ -0,0 +1,75 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/SettingsInterface.h"
#include <array>
class LayeredSettingsInterface final : public SettingsInterface
{
public:
enum Layer : u32
{
LAYER_CMDLINE,
LAYER_GAME,
LAYER_BASE,
NUM_LAYERS
};
LayeredSettingsInterface();
~LayeredSettingsInterface() override;
SettingsInterface* GetLayer(Layer layer) const { return m_layers[layer]; }
void SetLayer(Layer layer, SettingsInterface* sif) { m_layers[layer] = sif; }
bool Save() override;
void Clear() override;
bool GetIntValue(const char* section, const char* key, int* value) const override;
bool GetUIntValue(const char* section, const char* key, uint* value) const override;
bool GetFloatValue(const char* section, const char* key, float* value) const override;
bool GetDoubleValue(const char* section, const char* key, double* value) const override;
bool GetBoolValue(const char* section, const char* key, bool* value) const override;
bool GetStringValue(const char* section, const char* key, std::string* value) const override;
void SetIntValue(const char* section, const char* key, int value) override;
void SetUIntValue(const char* section, const char* key, uint value) override;
void SetFloatValue(const char* section, const char* key, float value) override;
void SetDoubleValue(const char* section, const char* key, double value) override;
void SetBoolValue(const char* section, const char* key, bool value) override;
void SetStringValue(const char* section, const char* key, const char* value) override;
void DeleteValue(const char* section, const char* key) override;
void ClearSection(const char* section) override;
std::vector<std::string> GetStringList(const char* section, const char* key) override;
void SetStringList(const char* section, const char* key, const std::vector<std::string>& items) override;
bool RemoveFromStringList(const char* section, const char* key, const char* item) override;
bool AddToStringList(const char* section, const char* key, const char* item) override;
// default parameter overloads
using SettingsInterface::GetBoolValue;
using SettingsInterface::GetDoubleValue;
using SettingsInterface::GetFloatValue;
using SettingsInterface::GetIntValue;
using SettingsInterface::GetStringValue;
using SettingsInterface::GetUIntValue;
private:
static constexpr Layer FIRST_LAYER = LAYER_CMDLINE;
static constexpr Layer LAST_LAYER = LAYER_BASE;
std::array<SettingsInterface*, NUM_LAYERS> m_layers{};
};
+1 -9
View File
@@ -252,14 +252,6 @@ int _GSopen(const WindowInfo& wi, const char* title, GSRendererType renderer, in
return -1;
}
if (renderer == GSRendererType::OGL_HW && theApp.GetConfigI("debug_glsl_shader") == 2)
{
printf("GS: test OpenGL shader. Please wait...\n\n");
static_cast<GSDeviceOGL*>(s_gs->m_dev)->SelfShaderTest();
printf("\nGS: test OpenGL shader done. It will now exit\n");
return -1;
}
return 0;
}
@@ -1121,9 +1113,9 @@ void GSApp::Init()
m_default_configuration["CaptureWidth"] = "640";
m_default_configuration["crc_hack_level"] = std::to_string(static_cast<s8>(CRCHackLevel::Automatic));
m_default_configuration["CrcHacksExclusions"] = "";
m_default_configuration["debug_glsl_shader"] = "0";
m_default_configuration["debug_opengl"] = "0";
m_default_configuration["disable_hw_gl_draw"] = "0";
m_default_configuration["disable_shader_cache"] = "0";
m_default_configuration["dithering_ps2"] = "2";
m_default_configuration["dump"] = "0";
m_default_configuration["extrathreads"] = "2";
+2
View File
@@ -447,6 +447,8 @@ const CRC::Game CRC::m_games[] =
{0x51E417AA, HarryPotterATPOA, EU, 0},
{0x4C01B1B0, HarryPotterOOTP, US, 0}, // Order Of The Phoenix
{0x01A9BF0E, HarryPotterOOTP, EU, 0},
{0x960FFA6A, JurassicPark, EU, 0},
{0xA99B8FE7, JurassicPark, US, 0},
{0x230CB71D, SoulReaver2, US, 0},
{0x1771BFE4, SoulReaver2, US, 0},
{0x6F991F52, SoulReaver2, JP, 0},
+1
View File
@@ -74,6 +74,7 @@ public:
Jak2,
Jak3,
JakX,
JurassicPark,
KazokuKeikakuKokoroNoKizuna,
KnightsOfTheTemple2,
Kunoichi,
+2
View File
@@ -1819,6 +1819,8 @@ GSOffset::PageLooper GSOffset::pageLooperForRect(const GSVector4i& rect) const
out.yCnt = botPg - topPg;
out.firstRowPgXStart = out.midRowPgXStart = out.lastRowPgXStart = rect.left >> m_pageShiftX;
out.firstRowPgXEnd = out.midRowPgXEnd = out.lastRowPgXEnd = ((rect.right + m_pageMask.x) >> m_pageShiftX) + !aligned;
out.slowPath = static_cast<u32>(out.yCnt * out.yInc + out.midRowPgXEnd - out.midRowPgXStart) > MAX_PAGES;
// Page-aligned bp is easy, all tiles touch their lower page but not the upper
if (aligned)
return out;
+54 -17
View File
@@ -310,6 +310,7 @@ public:
int bp; ///< Page offset of y=top x=0
int yInc; ///< Amount to add to bp when increasing y by one page
int yCnt; ///< Number of pages the rect covers in the y direction
bool slowPath; ///< True if the texture is big enough to wrap around GS memory and overlap itself
friend class GSOffset;
@@ -320,30 +321,66 @@ public:
void loopPagesWithBreak(Fn&& fn) const
{
int lineBP = bp;
int nextMin = 0;
int startOff = firstRowPgXStart;
int endOff = firstRowPgXEnd;
int yCnt = this->yCnt;
for (int y = 0; y < yCnt; y++)
{
int start = std::max(nextMin, lineBP + startOff);
int end = lineBP + endOff;
nextMin = end;
lineBP += yInc;
for (int pos = start; pos < end; pos++)
if (!fn(pos % MAX_PAGES))
return;
if (y < yCnt - 1)
if (unlikely(slowPath))
{
u32 touched[MAX_PAGES / 32] = {};
for (int y = 0; y < yCnt; y++)
{
startOff = midRowPgXStart;
endOff = midRowPgXEnd;
u32 start = lineBP + startOff;
u32 end = lineBP + endOff;
lineBP += yInc;
for (u32 pos = start; pos < end; pos++)
{
u32 page = pos % MAX_PAGES;
u32 idx = page / 32;
u32 mask = 1 << (page % 32);
if (touched[idx] & mask)
continue;
if (!fn(page))
return;
touched[idx] |= mask;
}
if (y < yCnt - 1)
{
startOff = midRowPgXStart;
endOff = midRowPgXEnd;
}
else
{
startOff = lastRowPgXStart;
endOff = lastRowPgXEnd;
}
}
else
}
else
{
u32 nextMin = 0;
for (int y = 0; y < yCnt; y++)
{
startOff = lastRowPgXStart;
endOff = lastRowPgXEnd;
u32 start = std::max<u32>(nextMin, lineBP + startOff);
u32 end = lineBP + endOff;
nextMin = end;
lineBP += yInc;
for (u32 pos = start; pos < end; pos++)
if (!fn(pos % MAX_PAGES))
return;
if (y < yCnt - 1)
{
startOff = midRowPgXStart;
endOff = midRowPgXEnd;
}
else
{
startOff = lastRowPgXStart;
endOff = lastRowPgXEnd;
}
}
}
}
+11 -10
View File
@@ -29,6 +29,7 @@ GSState::GSState()
, m_skip(0)
, m_skip_offset(0)
, m_q(1.0f)
, m_scanmask_used(false)
, m_vt(this)
, m_regs(NULL)
, m_crc(0)
@@ -219,6 +220,8 @@ void GSState::Reset()
m_vertex.tail = 0;
m_vertex.next = 0;
m_index.tail = 0;
m_scanmask_used = false;
}
void GSState::ResetHandlers()
@@ -1098,6 +1101,8 @@ void GSState::GIFRegHandlerSCANMSK(const GIFReg* RESTRICT r)
Flush();
m_env.SCANMSK = (GSVector4i)r->SCANMSK;
if (m_env.SCANMSK.MSK & 2)
m_scanmask_used = true;
}
template <int i>
@@ -2736,7 +2741,7 @@ void GSState::GetTextureMinMax(GSVector4i& r, const GIFRegTEX0& TEX0, const GIFR
r = vr;
}
void GSState::GetAlphaMinMax()
void GSState::CalcAlphaMinMax()
{
if (m_vt.m_alpha.valid)
return;
@@ -2841,12 +2846,10 @@ bool GSState::TryAlphaTest(u32& fm, u32& zm)
}
else
{
GetAlphaMinMax();
const int amin = GetAlphaMinMax().min;
const int amax = GetAlphaMinMax().max;
int amin = m_vt.m_alpha.min;
int amax = m_vt.m_alpha.max;
int aref = m_context->TEST.AREF;
const int aref = m_context->TEST.AREF;
switch (m_context->TEST.ATST)
{
@@ -2951,10 +2954,8 @@ bool GSState::IsOpaque()
{
if (context->ALPHA.C == 0)
{
GetAlphaMinMax();
amin = m_vt.m_alpha.min;
amax = m_vt.m_alpha.max;
amin = GetAlphaMinMax().min;
amax = GetAlphaMinMax().max;
}
else if (context->ALPHA.C == 1)
{
+11 -2
View File
@@ -139,6 +139,9 @@ class GSState : public GSAlignedClass<32>
} m_tr;
private:
void CalcAlphaMinMax();
protected:
bool IsBadFrame();
void SetupCrcHack();
@@ -159,6 +162,8 @@ protected:
GSVector4i m_ofxy;
bool tex_flushed;
bool m_scanmask_used;
struct
{
GSVertex* buff;
@@ -186,9 +191,13 @@ protected:
// following functions need m_vt to be initialized
GSVertexTrace m_vt;
GSVertexTrace::VertexAlpha& GetAlphaMinMax()
{
if (!m_vt.m_alpha.valid)
CalcAlphaMinMax();
return m_vt.m_alpha;
}
void GetTextureMinMax(GSVector4i& r, const GIFRegTEX0& TEX0, const GIFRegCLAMP& CLAMP, bool linear);
void GetAlphaMinMax();
bool TryAlphaTest(u32& fm, u32& zm);
bool IsOpaque();
bool IsMipMapDraw();
-5
View File
@@ -299,11 +299,6 @@ void GSDevice::StretchRect(GSTexture* sTex, GSTexture* dTex, const GSVector4& dR
StretchRect(sTex, GSVector4(0, 0, 1, 1), dTex, dRect, shader, linear);
}
GSTexture* GSDevice::GetCurrent()
{
return m_current;
}
void GSDevice::Merge(GSTexture* sTex[3], GSVector4* sRect, GSVector4* dRect, const GSVector2i& fs, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c)
{
// KH:COM crashes at startup when booting *through the bios* due to m_merge being NULL.
+60 -91
View File
@@ -97,15 +97,6 @@ public:
ExternalFXConstantBuffer() { memset(this, 0, sizeof(*this)); }
};
class FXAAConstantBuffer
{
public:
GSVector4 rcpFrame;
GSVector4 rcpFrameOpt;
FXAAConstantBuffer() { memset(this, 0, sizeof(*this)); }
};
class ShadeBoostConstantBuffer
{
public:
@@ -135,7 +126,7 @@ struct HWBlend
u16 flags, op, src, dst;
};
struct GSHWDrawConfig
struct alignas(16) GSHWDrawConfig
{
enum class Topology: u8
{
@@ -222,14 +213,15 @@ struct GSHWDrawConfig
// *** Word 2
// Blend and Colclip
u32 blend_a : 2;
u32 blend_b : 2;
u32 blend_c : 2;
u32 blend_d : 2;
u32 clr1 : 1; // useful?
u32 hdr : 1;
u32 colclip : 1;
u32 pabe : 1;
u32 blend_a : 2;
u32 blend_b : 2;
u32 blend_c : 2;
u32 blend_d : 2;
u32 clr1 : 1; // useful?
u32 hdr : 1;
u32 colclip : 1;
u32 alpha_clamp : 1;
u32 pabe : 1;
// Others ways to fetch the texture
u32 channel : 3;
@@ -250,7 +242,10 @@ struct GSHWDrawConfig
u32 point_sampler : 1;
u32 invalid_tex0 : 1; // Lupin the 3rd
u32 _free2 : 6;
// Scan mask
u32 scanmsk : 2;
u32 _free2 : 3;
};
u64 key;
@@ -337,108 +332,81 @@ struct GSHWDrawConfig
GSVector2 texture_offset;
GSVector2 point_size;
GSVector2i max_depth;
VSConstantBuffer()
__fi VSConstantBuffer()
{
memset(this, 0, sizeof(*this));
}
VSConstantBuffer(const VSConstantBuffer& other)
__fi VSConstantBuffer(const VSConstantBuffer& other)
{
memcpy(this, &other, sizeof(*this));
}
VSConstantBuffer& operator=(const VSConstantBuffer& other)
__fi VSConstantBuffer& operator=(const VSConstantBuffer& other)
{
new (this) VSConstantBuffer(other);
return *this;
}
bool operator==(const VSConstantBuffer& other) const
__fi bool operator==(const VSConstantBuffer& other) const
{
return BitEqual(*this, other);
}
bool operator!=(const VSConstantBuffer& other) const
__fi bool operator!=(const VSConstantBuffer& other) const
{
return !(*this == other);
}
__fi bool Update(const VSConstantBuffer& other)
{
if (*this == other)
return false;
memcpy(this, &other, sizeof(*this));
return true;
}
};
struct alignas(16) PSConstantBuffer
{
union
{
struct
{
u8 fog_color[3];
u8 aref;
};
u32 fog_color_aref;
};
union
{
struct
{
u8 r, g, b, a;
} fbmask;
u32 fbmask_int;
};
u32 max_depth;
union
{
struct
{
u8 ta0;
u8 ta1;
u8 _pad;
u8 alpha_fix;
};
u32 ta_af;
};
union
{
struct
{
u8 blue_mask;
u8 blue_shift;
u8 green_mask;
u8 green_shift;
} channel_shuffle;
u32 channel_shuffle_int;
};
union
{
struct
{
u16 umsk;
u16 vmsk;
u16 ufix;
u16 vfix;
};
u64 uv_msk_fix;
};
GIFRegDIMX dither_matrix;
GSVector2 tc_offset;
GSVector4 texture_size; // xy → PS2 size, wz → emulator size
GSVector4 FogColor_AREF;
GSVector4 WH;
GSVector4 TA_MaxDepth_Af;
GSVector4i MskFix;
GSVector4i FbMask;
GSVector4 half_texel;
GSVector4 uv_min_max;
PSConstantBuffer()
GSVector4 HalfTexel;
GSVector4 MinMax;
GSVector4i ChannelShuffle;
GSVector2 TCOffsetHack;
float pad1[2];
GSVector4 DitherMatrix[4];
__fi PSConstantBuffer()
{
memset(this, 0, sizeof(*this));
}
PSConstantBuffer(const PSConstantBuffer& other)
__fi PSConstantBuffer(const PSConstantBuffer& other)
{
memcpy(this, &other, sizeof(*this));
}
PSConstantBuffer& operator=(const PSConstantBuffer& other)
__fi PSConstantBuffer& operator=(const PSConstantBuffer& other)
{
new (this) PSConstantBuffer(other);
return *this;
}
bool operator==(const PSConstantBuffer& other) const
__fi bool operator==(const PSConstantBuffer& other) const
{
return BitEqual(*this, other);
}
bool operator!=(const PSConstantBuffer& other) const
__fi bool operator!=(const PSConstantBuffer& other) const
{
return !(*this == other);
}
__fi bool Update(const PSConstantBuffer& other)
{
if (*this == other)
return false;
memcpy(this, &other, sizeof(*this));
return true;
}
};
struct BlendState
{
@@ -486,6 +454,7 @@ struct GSHWDrawConfig
u32 indices_per_prim; ///< Number of indices that make up one primitive
const std::vector<size_t>* drawlist; ///< For reducing barriers on sprites
GSVector4i scissor; ///< Scissor rect
GSVector4i drawarea; ///< Area in the framebuffer which will be modified.
Topology topology; ///< Draw topology
GSSelector gs;
@@ -503,17 +472,17 @@ struct GSHWDrawConfig
DestinationAlphaMode destination_alpha;
bool datm;
VSConstantBuffer cb_vs;
PSConstantBuffer cb_ps;
struct AlphaSecondPass
{
bool enable;
ColorMaskSelector colormask;
DepthStencilSelector depth;
PSSelector ps;
PSConstantBuffer cb_ps;
float ps_aref;
} alpha_second_pass;
VSConstantBuffer cb_vs;
PSConstantBuffer cb_ps;
};
class GSDevice : public GSAlignedClass<32>
@@ -643,8 +612,8 @@ public:
virtual void RenderHW(GSHWDrawConfig& config) {}
FeatureSupport Features() { return m_features; }
GSTexture* GetCurrent();
__fi FeatureSupport Features() const { return m_features; }
__fi GSTexture* GetCurrent() const { return m_current; }
void Merge(GSTexture* sTex[3], GSVector4* sRect, GSVector4* dRect, const GSVector2i& fs, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c);
void Interlace(const GSVector2i& ds, int field, int mode, float yoffset);
+3 -1
View File
@@ -220,7 +220,9 @@ bool GSRenderer::Merge(int field)
off.x = tex[i]->GetScale().x * frame_diff.x;
}
if (display_diff.y >= 4) // Shouldn't this be >= 2?
if (m_scanmask_used && display_diff.y == 1) // Scanmask effect wouldn't look correct if we scale the offset
off.y = display_diff.y;
else if (display_diff.y >= 4) // Shouldn't this be >= 2?
{
off.y = tex[i]->GetScale().y * display_diff.y;
+19 -81
View File
@@ -351,16 +351,6 @@ bool GSDevice11::Create(const WindowInfo& wi)
m_dev->CreateBuffer(&bd, nullptr, m_shaderfx.cb.put());
// Fxaa
memset(&bd, 0, sizeof(bd));
bd.ByteWidth = sizeof(FXAAConstantBuffer);
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
m_dev->CreateBuffer(&bd, nullptr, m_fxaa.cb.put());
//
memset(&rd, 0, sizeof(rd));
@@ -954,9 +944,7 @@ void GSDevice11::DoFXAA(GSTexture* sTex, GSTexture* dTex)
const GSVector4 sRect(0, 0, 1, 1);
const GSVector4 dRect(0, 0, s.x, s.y);
FXAAConstantBuffer cb;
if (m_fxaa.ps == nullptr)
if (!m_fxaa_ps)
{
try
{
@@ -964,7 +952,7 @@ void GSDevice11::DoFXAA(GSTexture* sTex, GSTexture* dTex)
if (shader.has_value())
{
ShaderMacro sm(m_shader.model);
CreateShader(*shader, "fxaa.fx", nullptr, "ps_main", sm.GetPtr(), m_fxaa.ps.put());
CreateShader(*shader, "fxaa.fx", nullptr, "ps_main", sm.GetPtr(), m_fxaa_ps.put());
}
}
catch (GSRecoverableError)
@@ -973,12 +961,7 @@ void GSDevice11::DoFXAA(GSTexture* sTex, GSTexture* dTex)
}
}
cb.rcpFrame = GSVector4(1.0f / s.x, 1.0f / s.y, 0.0f, 0.0f);
cb.rcpFrameOpt = GSVector4::zero();
m_ctx->UpdateSubresource(m_fxaa.cb.get(), 0, nullptr, &cb, 0, 0);
StretchRect(sTex, sRect, dTex, dRect, m_fxaa.ps.get(), m_fxaa.cb.get(), true);
StretchRect(sTex, sRect, dTex, dRect, m_fxaa_ps.get(), nullptr, true);
//sTex->Save("c:\\temp1\\1.bmp");
//dTex->Save("c:\\temp1\\2.bmp");
@@ -1477,53 +1460,6 @@ void GSDevice11::CompileShader(const std::string& source, const char* fn, ID3DIn
throw GSRecoverableError();
}
static GSDevice11::VSConstantBuffer convertCB(const GSHWDrawConfig::VSConstantBuffer& cb)
{
GSDevice11::VSConstantBuffer out;
out.VertexScale = GSVector4(cb.vertex_scale.x, -cb.vertex_scale.y, ldexpf(1, -32), 0.0f);
out.VertexOffset = GSVector4(cb.vertex_offset.x, -cb.vertex_offset.y, 0.0f, -1.0f);
out.Texture_Scale_Offset = GSVector4::loadl(&cb.texture_scale).upld(GSVector4::loadl(&cb.texture_offset));
out.MaxDepth = cb.max_depth;
return out;
}
static GSDevice11::GSConstantBuffer convertCBGS(const GSHWDrawConfig::VSConstantBuffer& cb)
{
GSDevice11::GSConstantBuffer out;
out.PointSize = cb.point_size;
return out;
}
static GSDevice11::PSConstantBuffer convertCB(const GSHWDrawConfig::PSConstantBuffer& cb, int atst)
{
GSDevice11::PSConstantBuffer out;
out.FogColor_AREF = GSVector4(GSVector4i::load(cb.fog_color_aref).u8to32());
if (atst == 1 || atst == 2) // Greater / Less alpha
out.FogColor_AREF.w -= 0.1f;
out.HalfTexel = cb.half_texel;
out.WH = cb.texture_size;
out.MinMax = cb.uv_min_max;
const GSVector4 ta_af(GSVector4i::load(cb.ta_af).u8to32());
out.MinF_TA = (GSVector4(out.MskFix) + 0.5f).xyxy(ta_af) / out.WH.xyxy(GSVector4(255, 255));
out.MskFix = GSVector4i::loadl(&cb.uv_msk_fix).u16to32();
out.ChannelShuffle = GSVector4i::load(cb.channel_shuffle_int).u8to32();
out.FbMask = GSVector4i::load(cb.fbmask_int).u8to32();
out.TC_OffsetHack = GSVector4(cb.tc_offset.x, cb.tc_offset.y).xyxy();
out.Af_MaxDepth = GSVector4(ta_af.a / 128.f, cb.max_depth * ldexpf(1, -32));
GSVector4i dither = GSVector4i::loadl(&cb.dither_matrix).u8to16();
const GSVector4i ditherLow = dither.sll16(13).sra16(13);
const GSVector4i ditherHi = dither.sll16(9).sra16(5);
dither = ditherLow.blend8(ditherHi, GSVector4i(0xFF00FF00));
out.DitherMatrix[0] = GSVector4(dither.xxxx().i8to32());
out.DitherMatrix[1] = GSVector4(dither.yyyy().i8to32());
out.DitherMatrix[2] = GSVector4(dither.zzzz().i8to32());
out.DitherMatrix[3] = GSVector4(dither.wwww().i8to32());
return out;
}
static GSDevice11::OMBlendSelector convertSel(GSHWDrawConfig::ColorMaskSelector cm, GSHWDrawConfig::BlendState blend)
{
GSDevice11::OMBlendSelector out;
@@ -1561,7 +1497,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
if (config.destination_alpha != GSHWDrawConfig::DestinationAlphaMode::Off)
{
const GSVector4 src = GSVector4(config.scissor) / GSVector4(config.ds->GetSize()).xyxy();
const GSVector4 src = GSVector4(config.drawarea) / GSVector4(config.ds->GetSize()).xyxy();
const GSVector4 dst = src * 2.0f - 1.0f;
GSVertexPT1 vertices[] =
@@ -1579,10 +1515,10 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
if (config.ps.hdr)
{
const GSVector2i size = config.rt->GetSize();
const GSVector4 dRect(config.scissor);
const GSVector4 dRect(config.drawarea);
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
hdr_rt = CreateRenderTarget(size.x, size.y, GSTexture::Format::FloatColor);
hdr_rt->CommitRegion(GSVector2i(config.scissor.z, config.scissor.w));
hdr_rt->CommitRegion(GSVector2i(config.drawarea.z, config.drawarea.w));
// Warning: StretchRect must be called before BeginScene otherwise
// vertices will be overwritten. Trust me you don't want to do that.
StretchRect(config.rt, sRect, hdr_rt, dRect, ShaderConvert::COPY, false);
@@ -1618,14 +1554,10 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
PSSetShaderResource(3, config.rt);
}
const VSConstantBuffer cb_vs = convertCB(config.cb_vs);
const GSConstantBuffer cb_gs = convertCBGS(config.cb_vs);
PSConstantBuffer cb_ps = convertCB(config.cb_ps, config.ps.atst);
SetupOM(config.depth, convertSel(config.colormask, config.blend), config.blend.factor);
SetupVS(config.vs, &cb_vs);
SetupGS(config.gs, &cb_gs);
SetupPS(config.ps, &cb_ps, config.sampler);
SetupVS(config.vs, &config.cb_vs);
SetupGS(config.gs);
SetupPS(config.ps, &config.cb_ps, config.sampler);
OMSetRenderTargets(hdr_rt ? hdr_rt : config.rt, config.ds, &config.scissor);
@@ -1634,11 +1566,17 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
if (config.alpha_second_pass.enable)
{
preprocessSel(config.alpha_second_pass.ps);
if (config.cb_ps != config.alpha_second_pass.cb_ps)
if (config.cb_ps.FogColor_AREF.a != config.alpha_second_pass.ps_aref)
{
cb_ps = convertCB(config.alpha_second_pass.cb_ps, config.alpha_second_pass.ps.atst);
config.cb_ps.FogColor_AREF.a = config.alpha_second_pass.ps_aref;
SetupPS(config.alpha_second_pass.ps, &config.cb_ps, config.sampler);
}
SetupPS(config.alpha_second_pass.ps, &cb_ps, config.sampler);
else
{
// ps cbuffer hasn't changed, so don't bother checking
SetupPS(config.alpha_second_pass.ps, nullptr, config.sampler);
}
SetupOM(config.alpha_second_pass.depth, convertSel(config.alpha_second_pass.colormask, config.blend), config.blend.factor);
DrawIndexedPrimitive();
@@ -1649,7 +1587,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
if (hdr_rt)
{
const GSVector2i size = config.rt->GetSize();
const GSVector4 dRect(config.scissor);
const GSVector4 dRect(config.drawarea);
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
StretchRect(hdr_rt, sRect, config.rt, dRect, ShaderConvert::MOD_256, false);
Recycle(hdr_rt);
+7 -129
View File
@@ -31,129 +31,13 @@ struct GSVertexShader11
class GSDevice11 final : public GSDevice
{
public:
#pragma pack(push, 1)
struct alignas(32) VSConstantBuffer
{
GSVector4 VertexScale;
GSVector4 VertexOffset;
GSVector4 Texture_Scale_Offset;
GSVector2i MaxDepth;
GSVector2i pad_vscb;
VSConstantBuffer()
{
VertexScale = GSVector4::zero();
VertexOffset = GSVector4::zero();
Texture_Scale_Offset = GSVector4::zero();
MaxDepth = GSVector2i(0);
pad_vscb = GSVector2i(0);
}
__forceinline bool Update(const VSConstantBuffer* cb)
{
GSVector4i* a = (GSVector4i*)this;
GSVector4i* b = (GSVector4i*)cb;
if (!((a[0] == b[0]) & (a[1] == b[1]) & (a[2] == b[2]) & (a[3] == b[3])).alltrue())
{
a[0] = b[0];
a[1] = b[1];
a[2] = b[2];
a[3] = b[3];
return true;
}
return false;
}
};
struct alignas(32) PSConstantBuffer
{
GSVector4 FogColor_AREF;
GSVector4 HalfTexel;
GSVector4 WH;
GSVector4 MinMax;
GSVector4 MinF_TA;
GSVector4i MskFix;
GSVector4i ChannelShuffle;
GSVector4i FbMask;
GSVector4 TC_OffsetHack;
GSVector4 Af_MaxDepth;
GSVector4 DitherMatrix[4];
PSConstantBuffer()
{
FogColor_AREF = GSVector4::zero();
HalfTexel = GSVector4::zero();
WH = GSVector4::zero();
MinMax = GSVector4::zero();
MinF_TA = GSVector4::zero();
MskFix = GSVector4i::zero();
ChannelShuffle = GSVector4i::zero();
FbMask = GSVector4i::zero();
Af_MaxDepth = GSVector4::zero();
DitherMatrix[0] = GSVector4::zero();
DitherMatrix[1] = GSVector4::zero();
DitherMatrix[2] = GSVector4::zero();
DitherMatrix[3] = GSVector4::zero();
}
__forceinline bool Update(const PSConstantBuffer* cb)
{
GSVector4i* a = (GSVector4i*)this;
GSVector4i* b = (GSVector4i*)cb;
if (!((a[0] == b[0]) /*& (a[1] == b1)*/ & (a[2] == b[2]) & (a[3] == b[3]) & (a[4] == b[4]) & (a[5] == b[5]) &
(a[6] == b[6]) & (a[7] == b[7]) & (a[9] == b[9]) & // if WH matches HalfTexel does too
(a[10] == b[10]) & (a[11] == b[11]) & (a[12] == b[12]) & (a[13] == b[13])).alltrue())
{
a[0] = b[0];
a[1] = b[1];
a[2] = b[2];
a[3] = b[3];
a[4] = b[4];
a[5] = b[5];
a[6] = b[6];
a[7] = b[7];
a[9] = b[9];
a[10] = b[10];
a[11] = b[11];
a[12] = b[12];
a[13] = b[13];
return true;
}
return false;
}
};
struct alignas(32) GSConstantBuffer
{
GSVector2 PointSize;
GSConstantBuffer()
{
PointSize = GSVector2(0);
}
__forceinline bool Update(const GSConstantBuffer* cb)
{
return true;
}
};
using VSSelector = GSHWDrawConfig::VSSelector;
using GSSelector = GSHWDrawConfig::GSSelector;
using PSSelector = GSHWDrawConfig::PSSelector;
using PSSamplerSelector = GSHWDrawConfig::SamplerSelector;
using OMDepthStencilSelector = GSHWDrawConfig::DepthStencilSelector;
#pragma pack(push, 1)
struct OMBlendSelector
{
union
@@ -309,11 +193,7 @@ private:
wil::com_ptr_nothrow<ID3D11Buffer> cb;
} m_shaderfx;
struct
{
wil::com_ptr_nothrow<ID3D11PixelShader> ps;
wil::com_ptr_nothrow<ID3D11Buffer> cb;
} m_fxaa;
wil::com_ptr_nothrow<ID3D11PixelShader> m_fxaa_ps;
struct
{
@@ -332,7 +212,6 @@ private:
std::unordered_map<u32, GSVertexShader11> m_vs;
wil::com_ptr_nothrow<ID3D11Buffer> m_vs_cb;
std::unordered_map<u32, wil::com_ptr_nothrow<ID3D11GeometryShader>> m_gs;
wil::com_ptr_nothrow<ID3D11Buffer> m_gs_cb;
std::unordered_map<u64, wil::com_ptr_nothrow<ID3D11PixelShader>> m_ps;
wil::com_ptr_nothrow<ID3D11Buffer> m_ps_cb;
std::unordered_map<u32, wil::com_ptr_nothrow<ID3D11SamplerState>> m_ps_ss;
@@ -340,9 +219,8 @@ private:
std::unordered_map<u32, wil::com_ptr_nothrow<ID3D11DepthStencilState>> m_om_dss;
std::unordered_map<u32, wil::com_ptr_nothrow<ID3D11BlendState>> m_om_bs;
VSConstantBuffer m_vs_cb_cache;
GSConstantBuffer m_gs_cb_cache;
PSConstantBuffer m_ps_cb_cache;
GSHWDrawConfig::VSConstantBuffer m_vs_cb_cache;
GSHWDrawConfig::PSConstantBuffer m_ps_cb_cache;
std::unique_ptr<GSTexture> m_font;
std::unique_ptr<GSTexture11> m_download_tex;
@@ -415,9 +293,9 @@ public:
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor = NULL);
bool CreateTextureFX();
void SetupVS(VSSelector sel, const VSConstantBuffer* cb);
void SetupGS(GSSelector sel, const GSConstantBuffer* cb);
void SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel);
void SetupVS(VSSelector sel, const GSHWDrawConfig::VSConstantBuffer* cb);
void SetupGS(GSSelector sel);
void SetupPS(PSSelector sel, const GSHWDrawConfig::PSConstantBuffer* cb, PSSamplerSelector ssel);
void SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, u8 afix);
void RenderHW(GSHWDrawConfig& config) final;
+12 -29
View File
@@ -26,7 +26,7 @@ bool GSDevice11::CreateTextureFX()
memset(&bd, 0, sizeof(bd));
bd.ByteWidth = sizeof(VSConstantBuffer);
bd.ByteWidth = sizeof(GSHWDrawConfig::VSConstantBuffer);
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
@@ -37,18 +37,7 @@ bool GSDevice11::CreateTextureFX()
memset(&bd, 0, sizeof(bd));
bd.ByteWidth = sizeof(GSConstantBuffer);
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
hr = m_dev->CreateBuffer(&bd, nullptr, m_gs_cb.put());
if (FAILED(hr))
return false;
memset(&bd, 0, sizeof(bd));
bd.ByteWidth = sizeof(PSConstantBuffer);
bd.ByteWidth = sizeof(GSHWDrawConfig::PSConstantBuffer);
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
@@ -78,20 +67,18 @@ bool GSDevice11::CreateTextureFX()
// create layout
VSSelector sel;
VSConstantBuffer cb;
GSHWDrawConfig::VSConstantBuffer cb;
SetupVS(sel, &cb);
GSConstantBuffer gcb;
SetupGS(GSSelector(1), &gcb);
SetupGS(GSSelector(1));
//
return true;
}
void GSDevice11::SetupVS(VSSelector sel, const VSConstantBuffer* cb)
void GSDevice11::SetupVS(VSSelector sel, const GSHWDrawConfig::VSConstantBuffer* cb)
{
auto i = std::as_const(m_vs).find(sel.key);
@@ -119,7 +106,7 @@ void GSDevice11::SetupVS(VSSelector sel, const VSConstantBuffer* cb)
i = m_vs.try_emplace(sel.key, std::move(vs)).first;
}
if (m_vs_cb_cache.Update(cb))
if (m_vs_cb_cache.Update(*cb))
{
m_ctx->UpdateSubresource(m_vs_cb.get(), 0, NULL, cb, 0, 0);
}
@@ -129,7 +116,7 @@ void GSDevice11::SetupVS(VSSelector sel, const VSConstantBuffer* cb)
IASetInputLayout(i->second.il.get());
}
void GSDevice11::SetupGS(GSSelector sel, const GSConstantBuffer* cb)
void GSDevice11::SetupGS(GSSelector sel)
{
wil::com_ptr_nothrow<ID3D11GeometryShader> gs;
@@ -157,16 +144,10 @@ void GSDevice11::SetupGS(GSSelector sel, const GSConstantBuffer* cb)
}
}
if (m_gs_cb_cache.Update(cb))
{
m_ctx->UpdateSubresource(m_gs_cb.get(), 0, NULL, cb, 0, 0);
}
GSSetShader(gs.get(), m_gs_cb.get());
GSSetShader(gs.get(), m_vs_cb.get());
}
void GSDevice11::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel)
void GSDevice11::SetupPS(PSSelector sel, const GSHWDrawConfig::PSConstantBuffer* cb, PSSamplerSelector ssel)
{
auto i = std::as_const(m_ps).find(sel.key);
@@ -205,9 +186,11 @@ void GSDevice11::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSe
sm.AddMacro("PS_BLEND_B", sel.blend_b);
sm.AddMacro("PS_BLEND_C", sel.blend_c);
sm.AddMacro("PS_BLEND_D", sel.blend_d);
sm.AddMacro("PS_ALPHA_CLAMP", sel.alpha_clamp);
sm.AddMacro("PS_PABE", sel.pabe);
sm.AddMacro("PS_DITHER", sel.dither);
sm.AddMacro("PS_ZCLAMP", sel.zclamp);
sm.AddMacro("PS_SCANMSK", sel.scanmsk);
wil::com_ptr_nothrow<ID3D11PixelShader> ps;
CreateShader(m_tfx_source, "tfx.fx", nullptr, "ps_main", sm.GetPtr(), ps.put());
@@ -215,7 +198,7 @@ void GSDevice11::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSe
i = m_ps.try_emplace(sel.key, std::move(ps)).first;
}
if (m_ps_cb_cache.Update(cb))
if (cb && m_ps_cb_cache.Update(*cb))
{
m_ctx->UpdateSubresource(m_ps_cb.get(), 0, NULL, cb, 0, 0);
}
+1
View File
@@ -218,6 +218,7 @@ void GSRendererHW::SetGameCRC(u32 crc, int options)
case CRC::ICO:
case CRC::Jak1:
case CRC::Jak3:
case CRC::JurassicPark:
case CRC::LegacyOfKainDefiance:
case CRC::NicktoonsUnite:
case CRC::Persona3:
+82 -75
View File
@@ -165,7 +165,7 @@ void GSRendererNew::EmulateZbuffer()
}
else if (!m_context->ZBUF.ZMSK)
{
m_conf.cb_ps.max_depth = max_z;
m_conf.cb_ps.TA_MaxDepth_Af.z = static_cast<float>(max_z) * 0x1p-32f;
m_conf.ps.zclamp = 1;
}
}
@@ -282,10 +282,10 @@ void GSRendererNew::EmulateTextureShuffleAndFbmask()
if (m_conf.ps.fbmask && enable_fbmask_emulation)
{
m_conf.cb_ps.fbmask.r = rg_mask;
m_conf.cb_ps.fbmask.g = rg_mask;
m_conf.cb_ps.fbmask.b = ba_mask;
m_conf.cb_ps.fbmask.a = ba_mask;
m_conf.cb_ps.FbMask.r = rg_mask;
m_conf.cb_ps.FbMask.g = rg_mask;
m_conf.cb_ps.FbMask.b = ba_mask;
m_conf.cb_ps.FbMask.a = ba_mask;
// No blending so hit unsafe path.
if (!PRIM->ABE || !m_dev->Features().texture_barrier)
@@ -318,7 +318,7 @@ void GSRendererNew::EmulateTextureShuffleAndFbmask()
if (m_conf.ps.fbmask)
{
m_conf.cb_ps.fbmask_int = m_context->FRAME.FBMSK;
m_conf.cb_ps.FbMask = fbmask_v.u8to32();
// Only alpha is special here, I think we can take a very unsafe shortcut
// Alpha isn't blended on the GS but directly copyied into the RT.
//
@@ -456,10 +456,7 @@ void GSRendererNew::EmulateChannelShuffle(GSTexture** rt, const GSTextureCache::
const int green_shift = 8 - blue_shift;
GL_INS("Green/Blue channel (%d, %d)", blue_shift, green_shift);
m_conf.cb_ps.channel_shuffle.blue_mask = blue_mask;
m_conf.cb_ps.channel_shuffle.blue_shift = blue_shift;
m_conf.cb_ps.channel_shuffle.green_mask = green_mask;
m_conf.cb_ps.channel_shuffle.green_shift = green_shift;
m_conf.cb_ps.ChannelShuffle = GSVector4i(blue_mask, blue_shift, green_mask, green_shift);
m_conf.ps.channel = ChannelFetch_GXBY;
m_context->FRAME.FBMSK = 0x00FFFFFF;
}
@@ -544,11 +541,6 @@ void GSRendererNew::EmulateBlending(bool& DATE_GL42, bool& DATE_GL45)
const bool blend_mix2 = !!(blend_flag & BLEND_MIX2);
const bool blend_mix3 = !!(blend_flag & BLEND_MIX3);
bool blend_mix = (blend_mix1 || blend_mix2 || blend_mix3);
// Checking alpha mix is costly, isolate it as an optimization.
if (!m_vt.m_alpha.valid && blend_mix && (ALPHA.C == 0))
GetAlphaMinMax();
// Do not enable if As > 128 or F > 128, hw blend clamps to 1
blend_mix &= !((ALPHA.C == 0 && m_vt.m_alpha.max > 128) || (ALPHA.C == 2 && ALPHA.FIX > 128u));
// SW Blend is (nearly) free. Let's use it.
const bool impossible_or_free_blend = (blend_flag & BLEND_A_MAX) // Impossible blending
@@ -568,10 +560,10 @@ void GSRendererNew::EmulateBlending(bool& DATE_GL42, bool& DATE_GL45)
sw_blending |= true;
[[fallthrough]];
case AccBlendLevel::Full:
sw_blending |= (ALPHA.A != ALPHA.B) && ((ALPHA.C == 0 && m_vt.m_alpha.max > 128) || (ALPHA.C == 2 && ALPHA.FIX > 128u));
sw_blending |= ALPHA.A != ALPHA.B && ALPHA.C == 0 && GetAlphaMinMax().max > 128;
[[fallthrough]];
case AccBlendLevel::High:
sw_blending |= (ALPHA.C == 1);
sw_blending |= ALPHA.C == 1 || (ALPHA.A != ALPHA.B && ALPHA.C == 2 && ALPHA.FIX > 128u);
[[fallthrough]];
case AccBlendLevel::Medium:
// Initial idea was to enable accurate blending for sprite rendering to handle
@@ -649,9 +641,17 @@ void GSRendererNew::EmulateBlending(bool& DATE_GL42, bool& DATE_GL45)
if (sw_blending)
{
GL_INS("PABE mode ENABLED");
m_conf.ps.pabe = 1;
accumulation_blend = false;
blend_mix = false;
if (m_dev->Features().texture_barrier)
{
// Disable hw/sw blend and do pure sw blend with reading the framebuffer.
accumulation_blend = false;
blend_mix = false;
m_conf.ps.pabe = 1;
}
else
{
m_conf.ps.pabe = blend_non_recursive;
}
}
else if (ALPHA.A == 0 && ALPHA.B == 1 && ALPHA.C == 0 && ALPHA.D == 1)
{
@@ -707,6 +707,7 @@ void GSRendererNew::EmulateBlending(bool& DATE_GL42, bool& DATE_GL45)
else if (blend_mix)
{
m_conf.blend = {blend_index, ALPHA.FIX, ALPHA.C == 2, false, true};
m_conf.ps.alpha_clamp = 1;
if (blend_mix1)
{
@@ -741,7 +742,7 @@ void GSRendererNew::EmulateBlending(bool& DATE_GL42, bool& DATE_GL45)
// Require the fix alpha vlaue
if (ALPHA.C == 2)
m_conf.cb_ps.alpha_fix = ALPHA.FIX;
m_conf.cb_ps.TA_MaxDepth_Af.a = static_cast<float>(ALPHA.FIX) / 128.0f;
}
else
{
@@ -822,8 +823,10 @@ void GSRendererNew::EmulateTextureSampler(const GSTextureCache::Source* tex)
}
// Shuffle is a 16 bits format, so aem is always required
m_conf.cb_ps.ta0 = m_env.TEXA.TA0;
m_conf.cb_ps.ta1 = m_env.TEXA.TA1;
GSVector4 ta(m_env.TEXA & GSVector4i::x000000ff());
ta /= 255.0f;
m_conf.cb_ps.TA_MaxDepth_Af.x = ta.x;
m_conf.cb_ps.TA_MaxDepth_Af.y = ta.y;
// The purpose of texture shuffle is to move color channel. Extra interpolation is likely a bad idea.
bilinear &= m_vt.IsLinear();
@@ -843,8 +846,10 @@ void GSRendererNew::EmulateTextureSampler(const GSTextureCache::Source* tex)
// Don't upload AEM if format is 32 bits
if (cpsm.fmt)
{
m_conf.cb_ps.ta0 = m_env.TEXA.TA0;
m_conf.cb_ps.ta1 = m_env.TEXA.TA1;
GSVector4 ta(m_env.TEXA & GSVector4i::x000000ff());
ta /= 255.0f;
m_conf.cb_ps.TA_MaxDepth_Af.x = ta.x;
m_conf.cb_ps.TA_MaxDepth_Af.y = ta.y;
}
// Select the index format
@@ -926,23 +931,20 @@ void GSRendererNew::EmulateTextureSampler(const GSTextureCache::Source* tex)
m_conf.ps.fst = !!PRIM->FST;
m_conf.cb_ps.texture_size = WH;
m_conf.cb_ps.half_texel = GSVector4(-0.5f, 0.5f).xxyy() / WH.zwzw();
m_conf.cb_ps.WH = WH;
m_conf.cb_ps.HalfTexel = GSVector4(-0.5f, 0.5f).xxyy() / WH.zwzw();
if (complex_wms_wmt)
{
m_conf.cb_ps.umsk = m_context->CLAMP.MINU;
m_conf.cb_ps.vmsk = m_context->CLAMP.MINV;
m_conf.cb_ps.ufix = m_context->CLAMP.MAXU;
m_conf.cb_ps.vfix = m_context->CLAMP.MAXV;
m_conf.cb_ps.uv_min_max = GSVector4(GSVector4i::loadl(&m_conf.cb_ps.uv_msk_fix).u16to32()) / WH.xyxy();
m_conf.cb_ps.MskFix = GSVector4i(m_context->CLAMP.MINU, m_context->CLAMP.MINV, m_context->CLAMP.MAXU, m_context->CLAMP.MAXV);;
m_conf.cb_ps.MinMax = GSVector4(m_conf.cb_ps.MskFix) / WH.xyxy();
}
else if (trilinear_manual)
{
// Reuse uv_min_max for mipmap parameter to avoid an extension of the UBO
m_conf.cb_ps.uv_min_max.x = (float)m_context->TEX1.K / 16.0f;
m_conf.cb_ps.uv_min_max.y = float(1 << m_context->TEX1.L);
m_conf.cb_ps.uv_min_max.z = float(m_lod.x); // Offset because first layer is m_lod, dunno if we can do better
m_conf.cb_ps.uv_min_max.w = float(m_lod.y);
m_conf.cb_ps.MinMax.x = (float)m_context->TEX1.K / 16.0f;
m_conf.cb_ps.MinMax.y = float(1 << m_context->TEX1.L);
m_conf.cb_ps.MinMax.z = float(m_lod.x); // Offset because first layer is m_lod, dunno if we can do better
m_conf.cb_ps.MinMax.w = float(m_lod.y);
}
else if (trilinear_auto)
{
@@ -952,16 +954,16 @@ void GSRendererNew::EmulateTextureSampler(const GSTextureCache::Source* tex)
// TC Offset Hack
m_conf.ps.tcoffsethack = m_userhacks_tcoffset;
GSVector4 tc_oh_ts = GSVector4(1 / 16.0f, 1 / 16.0f, m_userhacks_tcoffset_x, m_userhacks_tcoffset_y) / WH.xyxy();
m_conf.cb_ps.TCOffsetHack = GSVector2(tc_oh_ts.z, tc_oh_ts.w);
m_conf.cb_vs.texture_scale = GSVector2(tc_oh_ts.x, tc_oh_ts.y);
m_conf.cb_ps.tc_offset = GSVector2(tc_oh_ts.z, tc_oh_ts.w);
// Must be done after all coordinates math
if (m_context->HasFixedTEX0() && !PRIM->FST)
{
m_conf.ps.invalid_tex0 = 1;
// Use invalid size to denormalize ST coordinate
m_conf.cb_ps.texture_size.x = (float)(1 << m_context->stack.TEX0.TW);
m_conf.cb_ps.texture_size.y = (float)(1 << m_context->stack.TEX0.TH);
m_conf.cb_ps.WH.x = (float)(1 << m_context->stack.TEX0.TW);
m_conf.cb_ps.WH.y = (float)(1 << m_context->stack.TEX0.TH);
// We can't handle m_target with invalid_tex0 atm due to upscaling
ASSERT(!tex->m_target);
@@ -1101,7 +1103,7 @@ GSRendererNew::PRIM_OVERLAP GSRendererNew::PrimitiveOverlap()
return overlap;
}
void GSRendererNew::EmulateATST(GSHWDrawConfig::PSConstantBuffer& cb, GSHWDrawConfig::PSSelector& ps, bool pass_2)
void GSRendererNew::EmulateATST(float& AREF, GSHWDrawConfig::PSSelector& ps, bool pass_2)
{
static const u32 inverted_atst[] = {ATST_ALWAYS, ATST_NEVER, ATST_GEQUAL, ATST_GREATER, ATST_NOTEQUAL, ATST_LESS, ATST_LEQUAL, ATST_EQUAL};
@@ -1115,27 +1117,27 @@ void GSRendererNew::EmulateATST(GSHWDrawConfig::PSConstantBuffer& cb, GSHWDrawCo
switch (atst)
{
case ATST_LESS:
cb.aref = m_context->TEST.AREF;
AREF = static_cast<float>(m_context->TEST.AREF) - 0.1f;
ps.atst = 1;
break;
case ATST_LEQUAL:
cb.aref = m_context->TEST.AREF + 1;
AREF = static_cast<float>(m_context->TEST.AREF) - 0.1f + 1.0f;
ps.atst = 1;
break;
case ATST_GEQUAL:
cb.aref = m_context->TEST.AREF;
AREF = static_cast<float>(m_context->TEST.AREF) - 0.1f;
ps.atst = 2;
break;
case ATST_GREATER:
cb.aref = m_context->TEST.AREF + 1;
AREF = static_cast<float>(m_context->TEST.AREF) - 0.1f + 1.0f;
ps.atst = 2;
break;
case ATST_EQUAL:
cb.aref = m_context->TEST.AREF;
AREF = static_cast<float>(m_context->TEST.AREF);
ps.atst = 3;
break;
case ATST_NOTEQUAL:
cb.aref = m_context->TEST.AREF;
AREF = static_cast<float>(m_context->TEST.AREF);
ps.atst = 4;
break;
case ATST_NEVER: // Draw won't be done so no need to implement it in shader
@@ -1148,11 +1150,9 @@ void GSRendererNew::EmulateATST(GSHWDrawConfig::PSConstantBuffer& cb, GSHWDrawCo
void GSRendererNew::ResetStates()
{
GSHWDrawConfig::VSConstantBuffer vs_tmp = m_conf.cb_vs;
GSHWDrawConfig::PSConstantBuffer ps_tmp = m_conf.cb_ps;
memset(&m_conf, 0, sizeof(m_conf));
m_conf.cb_vs = vs_tmp;
m_conf.cb_ps = ps_tmp;
// We don't want to zero out the constant buffers, since fields used by the current draw could result in redundant uploads.
// This memset should be pretty efficient - the struct is 16 byte aligned, as is the cb_vs offset.
memset(&m_conf, 0, reinterpret_cast<const char*>(&m_conf.cb_vs) - reinterpret_cast<const char*>(&m_conf));
}
void GSRendererNew::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* tex)
@@ -1181,6 +1181,7 @@ void GSRendererNew::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour
ResetStates();
m_conf.cb_vs.texture_offset = GSVector2(0, 0);
m_conf.ps.scanmsk = m_env.SCANMSK.MSK;
ASSERT(m_dev != NULL);
@@ -1241,24 +1242,23 @@ void GSRendererNew::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour
// Performance note: check alpha range with GetAlphaMinMax()
// Note: all my dump are already above 120fps, but it seems to reduce GPU load
// with big upscaling
GetAlphaMinMax();
if (m_context->TEST.DATM && m_vt.m_alpha.max < 128)
if (m_context->TEST.DATM && GetAlphaMinMax().max < 128)
{
// Only first pixel (write 0) will pass (alpha is 1)
GL_PERF("DATE: Fast with alpha %d-%d", m_vt.m_alpha.min, m_vt.m_alpha.max);
GL_PERF("DATE: Fast with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max);
DATE_one = true;
}
else if (!m_context->TEST.DATM && m_vt.m_alpha.min >= 128)
else if (!m_context->TEST.DATM && GetAlphaMinMax().min >= 128)
{
// Only first pixel (write 1) will pass (alpha is 0)
GL_PERF("DATE: Fast with alpha %d-%d", m_vt.m_alpha.min, m_vt.m_alpha.max);
GL_PERF("DATE: Fast with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max);
DATE_one = true;
}
else if ((m_vt.m_primclass == GS_SPRITE_CLASS && m_drawlist.size() < 50) || (m_index.tail < 100))
{
// texture barrier will split the draw call into n draw call. It is very efficient for
// few primitive draws. Otherwise it sucks.
GL_PERF("DATE: Slow with alpha %d-%d", m_vt.m_alpha.min, m_vt.m_alpha.max);
GL_PERF("DATE: Slow with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max);
if (m_dev->Features().texture_barrier)
{
m_conf.require_full_barrier = true;
@@ -1268,7 +1268,7 @@ void GSRendererNew::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour
else if (m_accurate_date)
{
// Note: Fast level (DATE_one) was removed as it's less accurate.
GL_PERF("DATE: Full AD with alpha %d-%d", m_vt.m_alpha.min, m_vt.m_alpha.max);
GL_PERF("DATE: Full AD with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max);
if (m_dev->Features().image_load_store)
{
DATE_GL42 = true;
@@ -1308,6 +1308,9 @@ void GSRendererNew::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour
m_conf.blend = {}; // No blending please
}
if (m_conf.ps.scanmsk & 2)
DATE_GL42 = false; // to have discard in the shader work correctly
if (m_conf.ps.dfmt == 1)
{
// Disable writing of the alpha channel
@@ -1395,16 +1398,19 @@ void GSRendererNew::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour
GL_DBG("DITHERING mode ENABLED (%d)", m_dithering);
m_conf.ps.dither = m_dithering;
m_conf.cb_ps.dither_matrix.U64 = m_env.DIMX.U64 & 0x7777777777777777ull;
m_conf.cb_ps.DitherMatrix[0] = GSVector4(m_env.DIMX.DM00, m_env.DIMX.DM01, m_env.DIMX.DM02, m_env.DIMX.DM03);
m_conf.cb_ps.DitherMatrix[1] = GSVector4(m_env.DIMX.DM10, m_env.DIMX.DM11, m_env.DIMX.DM12, m_env.DIMX.DM13);
m_conf.cb_ps.DitherMatrix[2] = GSVector4(m_env.DIMX.DM20, m_env.DIMX.DM21, m_env.DIMX.DM22, m_env.DIMX.DM23);
m_conf.cb_ps.DitherMatrix[3] = GSVector4(m_env.DIMX.DM30, m_env.DIMX.DM31, m_env.DIMX.DM32, m_env.DIMX.DM33);
}
if (PRIM->FGE)
{
m_conf.ps.fog = 1;
m_conf.cb_ps.fog_color[0] = m_env.FOGCOL.FCR;
m_conf.cb_ps.fog_color[1] = m_env.FOGCOL.FCG;
m_conf.cb_ps.fog_color[2] = m_env.FOGCOL.FCB;
const GSVector4 fc = GSVector4::rgba32(m_env.FOGCOL.U32[0]);
// Blend AREF to avoid to load a random value for alpha (dirty cache)
m_conf.cb_ps.FogColor_AREF = fc.blend32<8>(m_conf.cb_ps.FogColor_AREF);
}
// Warning must be done after EmulateZbuffer
@@ -1440,7 +1446,12 @@ void GSRendererNew::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour
}
else
{
EmulateATST(m_conf.cb_ps, m_conf.ps, false);
float aref = m_conf.cb_ps.FogColor_AREF.a;
EmulateATST(aref, m_conf.ps, false);
// avoid redundant cbuffer updates
m_conf.cb_ps.FogColor_AREF.a = aref;
m_conf.alpha_second_pass.ps_aref = aref;
}
if (tex)
@@ -1490,23 +1501,22 @@ void GSRendererNew::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour
const GSVector4& hacked_scissor = m_channel_shuffle ? GSVector4(0, 0, 1024, 1024) : m_context->scissor.in;
const GSVector4i scissor = GSVector4i(GSVector4(rtscale).xyxy() * hacked_scissor).rintersect(GSVector4i(rtsize).zwxy());
const GSVector4i commitRect = ComputeBoundingBox(rtscale, rtsize);
m_conf.scissor = (DATE && !DATE_GL45) ? scissor.rintersect(commitRect) : scissor;
m_conf.drawarea = scissor.rintersect(ComputeBoundingBox(rtscale, rtsize));
m_conf.scissor = (DATE && !DATE_GL45) ? m_conf.drawarea : scissor;
SetupIA(sx, sy);
if (rt)
rt->CommitRegion(GSVector2i(commitRect.z, commitRect.w));
rt->CommitRegion(GSVector2i(m_conf.drawarea.z, m_conf.drawarea.w));
if (ds)
ds->CommitRegion(GSVector2i(commitRect.z, commitRect.w));
ds->CommitRegion(GSVector2i(m_conf.drawarea.z, m_conf.drawarea.w));
m_conf.alpha_second_pass.enable = ate_second_pass;
if (ate_second_pass)
{
ASSERT(!m_env.PABE.PABE);
memcpy(&m_conf.alpha_second_pass.cb_ps, &m_conf.cb_ps, sizeof(m_conf.cb_ps));
memcpy(&m_conf.alpha_second_pass.ps, &m_conf.ps, sizeof(m_conf.ps));
memcpy(&m_conf.alpha_second_pass.colormask, &m_conf.colormask, sizeof(m_conf.colormask));
memcpy(&m_conf.alpha_second_pass.depth, &m_conf.depth, sizeof(m_conf.depth));
@@ -1515,13 +1525,13 @@ void GSRendererNew::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour
{
// Enable ATE as first pass to update the depth
// of pixels that passed the alpha test
EmulateATST(m_conf.alpha_second_pass.cb_ps, m_conf.alpha_second_pass.ps, false);
EmulateATST(m_conf.alpha_second_pass.ps_aref, m_conf.alpha_second_pass.ps, false);
}
else
{
// second pass will process the pixels that failed
// the alpha test
EmulateATST(m_conf.alpha_second_pass.cb_ps, m_conf.alpha_second_pass.ps, true);
EmulateATST(m_conf.alpha_second_pass.ps_aref, m_conf.alpha_second_pass.ps, true);
}
@@ -1574,10 +1584,10 @@ void GSRendererNew::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour
return;
// RenderHW always renders first pass, replace first pass with second
memcpy(&m_conf.cb_ps, &m_conf.alpha_second_pass.cb_ps, sizeof(m_conf.cb_ps));
memcpy(&m_conf.ps, &m_conf.alpha_second_pass.ps, sizeof(m_conf.ps));
memcpy(&m_conf.colormask, &m_conf.alpha_second_pass.colormask, sizeof(m_conf.colormask));
memcpy(&m_conf.depth, &m_conf.alpha_second_pass.depth, sizeof(m_conf.depth));
m_conf.cb_ps.FogColor_AREF.a = m_conf.alpha_second_pass.ps_aref;
m_conf.alpha_second_pass.enable = false;
}
@@ -1587,10 +1597,7 @@ void GSRendererNew::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour
m_conf.require_one_barrier = true;
}
if (m_conf.require_full_barrier && m_vt.m_primclass == GS_SPRITE_CLASS)
{
m_conf.drawlist = &m_drawlist;
}
m_conf.drawlist = (m_conf.require_full_barrier && m_vt.m_primclass == GS_SPRITE_CLASS) ? &m_drawlist : nullptr;
m_conf.rt = rt;
m_conf.ds = ds;
+1 -1
View File
@@ -43,7 +43,7 @@ private:
inline void EmulateBlending(bool& DATE_GL42, bool& DATE_GL45);
inline void EmulateTextureSampler(const GSTextureCache::Source* tex);
inline void EmulateZbuffer();
inline void EmulateATST(GSHWDrawConfig::PSConstantBuffer& cb, GSHWDrawConfig::PSSelector& ps, bool pass_2);
inline void EmulateATST(float& AREF, GSHWDrawConfig::PSSelector& ps, bool pass_2);
public:
GSRendererNew();
@@ -15,3 +15,14 @@
#include "PrecompiledHeader.h"
#include "GSRendererNull.h"
GSRendererNull::GSRendererNull() = default;
void GSRendererNull::Draw()
{
}
GSTexture* GSRendererNull::GetOutput(int i, int& y_offset)
{
return nullptr;
}
+5 -23
View File
@@ -17,30 +17,12 @@
#include "GS/Renderers/Common/GSRenderer.h"
class GSRendererNull : public GSRenderer
class GSRendererNull final : public GSRenderer
{
class GSVertexTraceNull : public GSVertexTrace
{
public:
GSVertexTraceNull(const GSState* state)
: GSVertexTrace(state)
{
}
};
public:
GSRendererNull();
protected:
void Draw()
{
}
GSTexture* GetOutput(int i, int& y_offset)
{
return NULL;
}
public:
GSRendererNull()
: GSRenderer()
{
}
void Draw() override;
GSTexture* GetOutput(int i, int& y_offset) override;
};
+5 -5
View File
@@ -17,7 +17,7 @@
#include "GS/Renderers/Common/GSTexture.h"
class GSTextureNull : public GSTexture
class GSTextureNull final : public GSTexture
{
struct
{
@@ -33,8 +33,8 @@ public:
Type GetType() const { return m_desc.type; }
Format GetFormat() const { return m_desc.format; }
bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) { return true; }
bool Map(GSMap& m, const GSVector4i* r = NULL, int layer = 0) { return false; }
void Unmap() {}
bool Save(const std::string& fn) { return false; }
bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) override { return true; }
bool Map(GSMap& m, const GSVector4i* r = NULL, int layer = 0) override { return false; }
void Unmap() override {}
bool Save(const std::string& fn) override { return false; }
};
-3
View File
@@ -145,7 +145,6 @@ namespace GLLoader
bool vendor_id_intel = false;
bool mesa_driver = false;
bool in_replayer = false;
bool buggy_sso_dual_src = false;
bool found_geometry_shader = true; // we require GL3.3 so geometry must be supported by default
bool found_GL_ARB_clear_texture = false;
@@ -213,8 +212,6 @@ namespace GLLoader
// On linux assumes the free driver if it isn't nvidia or amd pro driver
mesa_driver = !vendor_id_nvidia && !vendor_id_amd;
#endif
// As of 2019 SSO is still broken on intel (Kaby Lake confirmed).
buggy_sso_dual_src = vendor_id_intel || vendor_id_amd;
if (theApp.GetConfigI("override_geometry_shader") != -1)
{
-1
View File
@@ -36,7 +36,6 @@ namespace GLLoader
extern bool vendor_id_nvidia;
extern bool vendor_id_intel;
extern bool mesa_driver;
extern bool buggy_sso_dual_src;
extern bool in_replayer;
// GL
-12
View File
@@ -44,12 +44,6 @@ namespace GLState
GLuint tex_unit[8];
GLuint64 tex_handle[8];
GLuint ps;
GLuint gs;
GLuint vs;
GLuint program;
GLuint pipeline;
s64 available_vram;
void Clear()
@@ -80,12 +74,6 @@ namespace GLState
std::fill(std::begin(tex_unit), std::end(tex_unit), 0);
std::fill(std::begin(tex_handle), std::end(tex_handle), 0);
ps = 0;
gs = 0;
vs = 0;
program = 0;
pipeline = 0;
// Set a max vram limit for texture allocation
// (256MB are reserved for PBO/IBO/VBO/UBO buffers)
available_vram = (4096u - 256u) * 1024u * 1024u;
-6
View File
@@ -46,12 +46,6 @@ namespace GLState
extern GLuint tex_unit[8]; // shader input texture
extern GLuint64 tex_handle[8]; // shader input texture
extern GLuint ps;
extern GLuint gs;
extern GLuint vs;
extern GLuint program;
extern GLuint pipeline;
extern s64 available_vram;
extern void Clear();
File diff suppressed because it is too large Load Diff
+44 -135
View File
@@ -17,10 +17,12 @@
#include "common/GL/Context.h"
#include "common/GL/StreamBuffer.h"
#include "common/GL/Program.h"
#include "common/GL/ShaderCache.h"
#include "common/HashCombine.h"
#include "GS/Renderers/Common/GSDevice.h"
#include "GSTextureOGL.h"
#include "GSUniformBufferOGL.h"
#include "GSShaderOGL.h"
#include "GLState.h"
#include "GS/GS.h"
@@ -123,41 +125,6 @@ public:
class GSDeviceOGL final : public GSDevice
{
public:
struct alignas(32) VSConstantBuffer
{
GSVector4 Vertex_Scale_Offset;
GSVector4 Texture_Scale_Offset;
GSVector2 PointSize;
GSVector2i MaxDepth;
VSConstantBuffer()
{
Vertex_Scale_Offset = GSVector4::zero();
Texture_Scale_Offset = GSVector4::zero();
PointSize = GSVector2(0);
MaxDepth = GSVector2i(0);
}
__forceinline bool Update(const VSConstantBuffer* cb)
{
GSVector4i* a = (GSVector4i*)this;
GSVector4i* b = (GSVector4i*)cb;
if (!((a[0] == b[0]) & (a[1] == b[1]) & (a[2] == b[2])).alltrue())
{
a[0] = b[0];
a[1] = b[1];
a[2] = b[2];
return true;
}
return false;
}
};
struct VSSelector
{
union
@@ -211,87 +178,41 @@ public:
}
};
struct alignas(32) PSConstantBuffer
{
GSVector4 FogColor_AREF;
GSVector4 WH;
GSVector4 TA_MaxDepth_Af;
GSVector4i MskFix;
GSVector4i FbMask;
GSVector4 HalfTexel;
GSVector4 MinMax;
GSVector4 TC_OH;
GSVector4 DitherMatrix[4];
PSConstantBuffer()
{
FogColor_AREF = GSVector4::zero();
HalfTexel = GSVector4::zero();
WH = GSVector4::zero();
TA_MaxDepth_Af = GSVector4::zero();
MinMax = GSVector4::zero();
MskFix = GSVector4i::zero();
TC_OH = GSVector4::zero();
FbMask = GSVector4i::zero();
DitherMatrix[0] = GSVector4::zero();
DitherMatrix[1] = GSVector4::zero();
DitherMatrix[2] = GSVector4::zero();
DitherMatrix[3] = GSVector4::zero();
}
__forceinline bool Update(const PSConstantBuffer* cb)
{
GSVector4i* a = (GSVector4i*)this;
GSVector4i* b = (GSVector4i*)cb;
// if WH matches both HalfTexel and TC_OH_TS do too
if (!((a[0] == b[0]) & (a[1] == b[1]) & (a[2] == b[2]) & (a[3] == b[3]) & (a[4] == b[4]) & (a[6] == b[6])
& (a[8] == b[8]) & (a[9] == b[9]) & (a[10] == b[10]) & (a[11] == b[11])).alltrue())
{
// Note previous check uses SSE already, a plain copy will be faster than any memcpy
a[0] = b[0];
a[1] = b[1];
a[2] = b[2];
a[3] = b[3];
a[4] = b[4];
a[5] = b[5];
a[6] = b[6];
a[8] = b[8];
a[9] = b[9];
a[10] = b[10];
a[11] = b[11];
return true;
}
return false;
}
};
using PSSelector = GSHWDrawConfig::PSSelector;
using PSSamplerSelector = GSHWDrawConfig::SamplerSelector;
using OMDepthStencilSelector = GSHWDrawConfig::DepthStencilSelector;
using OMColorMaskSelector = GSHWDrawConfig::ColorMaskSelector;
struct alignas(32) MiscConstantBuffer
struct ProgramSelector
{
GSVector4i ScalingFactor;
GSVector4i ChannelShuffle;
GSVector4i EMOD_AC;
VSSelector vs;
GSSelector gs;
PSSelector ps;
MiscConstantBuffer() { memset(this, 0, sizeof(*this)); }
__fi bool operator==(const ProgramSelector& p) const { return vs.key == p.vs.key && gs.key == p.gs.key && ps.key == p.ps.key; }
__fi bool operator!=(const ProgramSelector& p) const { return vs.key != p.vs.key || gs.key != p.gs.key || ps.key != p.ps.key; }
};
struct ProgramSelectorHash
{
__fi std::size_t operator()(const ProgramSelector& p) const noexcept
{
std::size_t h = 0;
HashCombine(h, p.vs.key, p.gs.key, p.ps.key);
return h;
}
};
static int m_shader_inst;
static int m_shader_reg;
private:
// Increment this constant whenever shaders change, to invalidate user's program binary cache.
static constexpr u32 SHADER_VERSION = 1;
std::unique_ptr<GL::Context> m_gl_context;
int m_mipmap;
int m_upscale_multiplier;
TriFiltering m_filter;
static bool m_debug_gl_call;
@@ -318,38 +239,35 @@ private:
struct
{
GLuint ps[2]; // program object
GSUniformBufferOGL* cb; // uniform buffer object
GL::Program ps[2]; // program object
} m_merge_obj;
struct
{
GLuint ps[4]; // program object
GSUniformBufferOGL* cb; // uniform buffer object
GL::Program ps[4]; // program object
} m_interlace;
struct
{
GLuint vs; // program object
GLuint ps[(int)ShaderConvert::Count]; // program object
std::string vs;
GL::Program ps[static_cast<int>(ShaderConvert::Count)]; // program object
GLuint ln; // sampler object
GLuint pt; // sampler object
GSDepthStencilOGL* dss;
GSDepthStencilOGL* dss_write;
GSUniformBufferOGL* cb;
} m_convert;
struct
{
GLuint ps;
GSUniformBufferOGL* cb;
GL::Program ps;
} m_fxaa;
#ifndef PCSX2_CORE
struct
{
GLuint ps;
GSUniformBufferOGL* cb;
GL::Program ps;
} m_shaderfx;
#endif
struct
{
@@ -359,7 +277,7 @@ private:
struct
{
GLuint ps;
GL::Program ps;
} m_shadeboost;
struct
@@ -370,18 +288,15 @@ private:
GLuint timer() { return timer_query[last_query]; }
} m_profiler;
GLuint m_vs[1 << 1];
GLuint m_gs[1 << 3];
GLuint m_ps_ss[1 << 7];
GSDepthStencilOGL* m_om_dss[1 << 5];
std::unordered_map<u64, GLuint> m_ps;
GLuint m_apitrace;
std::unordered_map<ProgramSelector, GL::Program, ProgramSelectorHash> m_programs;
GL::ShaderCache m_shader_cache;
GLuint m_palette_ss;
VSConstantBuffer m_vs_cb_cache;
PSConstantBuffer m_ps_cb_cache;
MiscConstantBuffer m_misc_cb_cache;
GSHWDrawConfig::VSConstantBuffer m_vs_cb_cache;
GSHWDrawConfig::PSConstantBuffer m_ps_cb_cache;
std::unique_ptr<GSTexture> m_font;
AlignedBuffer<u8, 32> m_download_buffer;
@@ -404,8 +319,6 @@ private:
void DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect, const GSVector2i& ds);
public:
GSShaderOGL* m_shader;
GSDeviceOGL();
virtual ~GSDeviceOGL();
@@ -439,9 +352,9 @@ public:
void BlitRect(GSTexture* sTex, const GSVector4i& r, const GSVector2i& dsize, bool at_origin, bool linear);
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderConvert shader = ShaderConvert::COPY, bool linear = true) final;
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, GLuint ps, bool linear = true);
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, const GL::Program& ps, bool linear = true);
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, bool red, bool green, bool blue, bool alpha) final;
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, GLuint ps, int bs, OMColorMaskSelector cms, bool linear = true);
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, const GL::Program& ps, int bs, OMColorMaskSelector cms, bool linear = true);
void RenderHW(GSHWDrawConfig& config) final;
void SendHWDraw(const GSHWDrawConfig& config);
@@ -465,19 +378,15 @@ public:
bool HasDepthSparse() final { return GLLoader::found_compatible_sparse_depth; }
bool CreateTextureFX();
GLuint CompileVS(VSSelector sel);
GLuint CompileGS(GSSelector sel);
GLuint CompilePS(PSSelector sel);
std::string GetShaderSource(const std::string_view& entry, GLenum type, const std::string_view& common_header, const std::string_view& glsl_h_code, const std::string_view& macro_sel);
std::string GenGlslHeader(const std::string_view& entry, GLenum type, const std::string_view& macro);
std::string GetVSSource(VSSelector sel);
std::string GetGSSource(GSSelector sel);
std::string GetPSSource(PSSelector sel);
GLuint CreateSampler(PSSamplerSelector sel);
GSDepthStencilOGL* CreateDepthStencil(OMDepthStencilSelector dssel);
void SelfShaderTestPrint(const std::string& test, int& nb_shader);
void SelfShaderTestRun(const std::string& dir, const std::string& file, const PSSelector& sel, int& nb_shader);
void SelfShaderTest();
void SetupPipeline(const VSSelector& vsel, const GSSelector& gsel, const PSSelector& psel);
void SetupCB(const VSConstantBuffer* vs_cb, const PSConstantBuffer* ps_cb);
void SetupCBMisc(const GSVector4i& channel);
void SetupPipeline(const ProgramSelector& psel);
void SetupSampler(PSSamplerSelector ssel);
void SetupOM(OMDepthStencilSelector dssel);
GLuint GetSamplerID(PSSamplerSelector ssel);
-404
View File
@@ -1,404 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "GSShaderOGL.h"
#include "GLState.h"
#include "GS/GS.h"
GSShaderOGL::GSShaderOGL(bool debug)
: m_pipeline(0)
, m_debug_shader(debug)
{
// Create a default pipeline
m_pipeline = LinkPipeline("HW pipe", 0, 0, 0);
BindPipeline(m_pipeline);
}
GSShaderOGL::~GSShaderOGL()
{
printf("Delete %zu Shaders, %zu Programs, %zu Pipelines\n",
m_shad_to_delete.size(), m_prog_to_delete.size(), m_pipe_to_delete.size());
for (auto s : m_shad_to_delete)
glDeleteShader(s);
for (auto p : m_prog_to_delete)
glDeleteProgram(p);
glDeleteProgramPipelines(m_pipe_to_delete.size(), &m_pipe_to_delete[0]);
}
GLuint GSShaderOGL::LinkPipeline(const std::string& pretty_print, GLuint vs, GLuint gs, GLuint ps)
{
GLuint p;
glCreateProgramPipelines(1, &p);
glUseProgramStages(p, GL_VERTEX_SHADER_BIT, vs);
glUseProgramStages(p, GL_GEOMETRY_SHADER_BIT, gs);
glUseProgramStages(p, GL_FRAGMENT_SHADER_BIT, ps);
glObjectLabel(GL_PROGRAM_PIPELINE, p, pretty_print.size(), pretty_print.c_str());
m_pipe_to_delete.push_back(p);
return p;
}
GLuint GSShaderOGL::LinkProgram(GLuint vs, GLuint gs, GLuint ps)
{
u32 hash = ((vs ^ gs) << 24) ^ ps;
auto it = m_program.find(hash);
if (it != m_program.end())
return it->second;
GLuint p = glCreateProgram();
if (vs) glAttachShader(p, vs);
if (ps) glAttachShader(p, ps);
if (gs) glAttachShader(p, gs);
glLinkProgram(p);
ValidateProgram(p);
m_prog_to_delete.push_back(p);
m_program[hash] = p;
return p;
}
void GSShaderOGL::BindProgram(GLuint vs, GLuint gs, GLuint ps)
{
GLuint p = LinkProgram(vs, gs, ps);
if (GLState::program != p)
{
GLState::program = p;
glUseProgram(p);
}
}
void GSShaderOGL::BindProgram(GLuint p)
{
if (GLState::program != p)
{
GLState::program = p;
glUseProgram(p);
}
}
void GSShaderOGL::BindPipeline(GLuint vs, GLuint gs, GLuint ps)
{
BindPipeline(m_pipeline);
if (GLState::vs != vs)
{
GLState::vs = vs;
glUseProgramStages(m_pipeline, GL_VERTEX_SHADER_BIT, vs);
}
if (GLState::gs != gs)
{
GLState::gs = gs;
glUseProgramStages(m_pipeline, GL_GEOMETRY_SHADER_BIT, gs);
}
#ifdef _DEBUG
// In debug always sets the program. It allow to replace the program in apitrace easily.
if (true)
#else
if (GLState::ps != ps)
#endif
{
GLState::ps = ps;
glUseProgramStages(m_pipeline, GL_FRAGMENT_SHADER_BIT, ps);
}
}
void GSShaderOGL::BindPipeline(GLuint pipe)
{
if (GLState::pipeline != pipe)
{
GLState::pipeline = pipe;
glBindProgramPipeline(pipe);
}
if (GLState::program)
{
GLState::program = 0;
glUseProgram(0);
}
}
bool GSShaderOGL::ValidateShader(GLuint s)
{
if (!m_debug_shader)
return true;
GLint status = 0;
glGetShaderiv(s, GL_COMPILE_STATUS, &status);
if (status)
return true;
GLint log_length = 0;
glGetShaderiv(s, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 0)
{
char* log = new char[log_length];
glGetShaderInfoLog(s, log_length, NULL, log);
fprintf(stderr, "%s", log);
delete[] log;
}
fprintf(stderr, "\n");
return false;
}
bool GSShaderOGL::ValidateProgram(GLuint p)
{
if (!m_debug_shader)
return true;
GLint status = 0;
glGetProgramiv(p, GL_LINK_STATUS, &status);
if (status)
return true;
GLint log_length = 0;
glGetProgramiv(p, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 0)
{
char* log = new char[log_length];
glGetProgramInfoLog(p, log_length, NULL, log);
fprintf(stderr, "%s", log);
delete[] log;
}
fprintf(stderr, "\n");
return false;
}
bool GSShaderOGL::ValidatePipeline(GLuint p)
{
if (!m_debug_shader)
return true;
// FIXME: might be mandatory to validate the pipeline
glValidateProgramPipeline(p);
GLint status = 0;
glGetProgramPipelineiv(p, GL_VALIDATE_STATUS, &status);
if (status)
return true;
GLint log_length = 0;
glGetProgramPipelineiv(p, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 0)
{
char* log = new char[log_length];
glGetProgramPipelineInfoLog(p, log_length, NULL, log);
fprintf(stderr, "%s", log);
delete[] log;
}
fprintf(stderr, "\n");
return false;
}
std::string GSShaderOGL::GenGlslHeader(const std::string& entry, GLenum type, const std::string& macro)
{
std::string header;
header = "#version 330 core\n";
// Need GL version 420
header += "#extension GL_ARB_shading_language_420pack: require\n";
// Need GL version 410
header += "#extension GL_ARB_separate_shader_objects: require\n";
if (GLLoader::found_GL_ARB_shader_image_load_store)
{
// Need GL version 420
header += "#extension GL_ARB_shader_image_load_store: require\n";
}
else
{
header += "#define DISABLE_GL42_image\n";
}
if (GLLoader::vendor_id_amd || GLLoader::vendor_id_intel)
header += "#define BROKEN_DRIVER as_usual\n";
// Stupid GL implementation (can't use GL_ES)
// AMD/nvidia define it to 0
// intel window don't define it
// intel linux refuse to define it
header += "#define pGL_ES 0\n";
// Allow to puts several shader in 1 files
switch (type)
{
case GL_VERTEX_SHADER:
header += "#define VERTEX_SHADER 1\n";
break;
case GL_GEOMETRY_SHADER:
header += "#define GEOMETRY_SHADER 1\n";
break;
case GL_FRAGMENT_SHADER:
header += "#define FRAGMENT_SHADER 1\n";
break;
default:
ASSERT(0);
}
// Select the entry point ie the main function
header += format("#define %s main\n", entry.c_str());
header += macro;
return header;
}
GLuint GSShaderOGL::Compile(const char* glsl_file, const std::string& entry, GLenum type, const std::string& common_header, const char* glsl_h_code, const std::string& macro_sel /* = "" */)
{
ASSERT(glsl_h_code != NULL);
GLuint program = 0;
// Note it is better to separate header and source file to have the good line number
// in the glsl compiler report
const int shader_nb = 3;
const char* sources[shader_nb];
std::string header = GenGlslHeader(entry, type, macro_sel);
sources[0] = header.c_str();
sources[1] = common_header.c_str();
sources[2] = glsl_h_code;
program = glCreateShaderProgramv(type, shader_nb, sources);
bool status = ValidateProgram(program);
if (!status)
{
// print extra info
fprintf(stderr, "%s (entry %s, prog %d) :", glsl_file, entry.c_str(), program);
fprintf(stderr, "\n%s", macro_sel.c_str());
fprintf(stderr, "\n");
}
m_prog_to_delete.push_back(program);
return program;
}
// Same as above but for not-separated build
GLuint GSShaderOGL::CompileShader(const char* glsl_file, const std::string& entry, GLenum type, const std::string& common_header, const char* glsl_h_code, const std::string& macro_sel /* = "" */)
{
ASSERT(glsl_h_code != NULL);
GLuint shader = 0;
// Note it is better to separate header and source file to have the good line number
// in the glsl compiler report
const int shader_nb = 3;
const char* sources[shader_nb];
std::string header = GenGlslHeader(entry, type, macro_sel);
sources[0] = header.c_str();
sources[1] = common_header.data();
sources[2] = glsl_h_code;
shader = glCreateShader(type);
glShaderSource(shader, shader_nb, sources, NULL);
glCompileShader(shader);
bool status = ValidateShader(shader);
if (!status)
{
// print extra info
fprintf(stderr, "%s (entry %s, prog %d) :", glsl_file, entry.c_str(), shader);
fprintf(stderr, "\n%s", macro_sel.c_str());
fprintf(stderr, "\n");
}
m_shad_to_delete.push_back(shader);
return shader;
}
// This function will get the binary program. Normally it must be used a caching
// solution but Nvidia also incorporates the ASM dump. Asm is nice because it allow
// to have an overview of the program performance based on the instruction number
// Note: initially I was using cg offline compiler but it doesn't support latest
// GLSL improvement (unfortunately).
int GSShaderOGL::DumpAsm(const std::string& file, GLuint p)
{
if (!GLLoader::vendor_id_nvidia)
return 0;
GLint binaryLength;
glGetProgramiv(p, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
char* binary = new char[binaryLength + 4];
GLenum binaryFormat;
glGetProgramBinary(p, binaryLength, NULL, &binaryFormat, binary);
FILE* outfile = fopen(file.c_str(), "w");
ASSERT(outfile);
// Search the magic number "!!"
int asm_ = 0;
while (asm_ < binaryLength && (binary[asm_] != '!' || binary[asm_ + 1] != '!'))
{
asm_ += 1;
}
int instructions = -1;
if (asm_ < binaryLength)
{
// Now print asm as text
char* asm_txt = strtok(&binary[asm_], "\n");
while (asm_txt != NULL && (strncmp(asm_txt, "END", 3) || !strncmp(asm_txt, "ENDIF", 5)))
{
if (!strncmp(asm_txt, "OUT", 3) || !strncmp(asm_txt, "TEMP", 4) || !strncmp(asm_txt, "LONG", 4))
{
instructions = 0;
}
else if (instructions >= 0)
{
if (instructions == 0)
fprintf(outfile, "\n");
instructions++;
}
fprintf(outfile, "%s\n", asm_txt);
asm_txt = strtok(NULL, "\n");
}
fprintf(outfile, "\nFound %d instructions\n", instructions);
}
fclose(outfile);
if (instructions < 0)
{
// RAW dump in case of error
fprintf(stderr, "Error: failed to find the number of instructions!\n");
outfile = fopen(file.c_str(), "wb");
fwrite(binary, binaryLength, 1, outfile);
fclose(outfile);
ASSERT(0);
}
delete[] binary;
return instructions;
}
-55
View File
@@ -1,55 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "GS/GSGL.h"
#include <unordered_map>
class GSShaderOGL
{
GLuint m_pipeline;
std::unordered_map<u32, GLuint> m_program;
const bool m_debug_shader;
std::vector<GLuint> m_shad_to_delete;
std::vector<GLuint> m_prog_to_delete;
std::vector<GLuint> m_pipe_to_delete;
bool ValidateShader(GLuint s);
bool ValidateProgram(GLuint p);
bool ValidatePipeline(GLuint p);
std::string GenGlslHeader(const std::string& entry, GLenum type, const std::string& macro);
public:
GSShaderOGL(bool debug);
~GSShaderOGL();
void BindPipeline(GLuint vs, GLuint gs, GLuint ps);
void BindPipeline(GLuint pipe);
GLuint Compile(const char* glsl_file, const std::string& entry, GLenum type, const std::string& common_header, const char* glsl_h_code, const std::string& macro_sel = "");
GLuint LinkPipeline(const std::string& pretty_print, GLuint vs, GLuint gs, GLuint ps);
// Same as above but for not separated build
void BindProgram(GLuint vs, GLuint gs, GLuint ps);
void BindProgram(GLuint p);
GLuint CompileShader(const char* glsl_file, const std::string& entry, GLenum type, const std::string& common_header, const char* glsl_h_code, const std::string& macro_sel = "");
GLuint LinkProgram(GLuint vs, GLuint gs, GLuint ps);
int DumpAsm(const std::string& file, GLuint p);
};
+1 -1
View File
@@ -83,5 +83,5 @@ public:
void CommitPages(const GSVector2i& region, bool commit) final;
u32 GetMemUsage();
u32 GetMemUsage() final;
};
+5 -1
View File
@@ -40,6 +40,7 @@ GSRasterizer::GSRasterizer(IDrawScanline* ds, int id, int threads, GSPerfMon* pe
, m_ds(ds)
, m_id(id)
, m_threads(threads)
, m_scanmsk_value(0)
{
memset(&m_pixels, 0, sizeof(m_pixels));
m_primcount = 0;
@@ -158,6 +159,7 @@ void GSRasterizer::Draw(GSRasterizerData* data)
m_scissor = data->scissor;
m_fscissor_x = GSVector4(data->scissor).xzxz();
m_fscissor_y = GSVector4(data->scissor).ywyw();
m_scanmsk_value = data->scanmsk_value;
switch (data->primclass)
{
@@ -834,7 +836,7 @@ void GSRasterizer::DrawSprite(const GSVertexSW* vertex, const u32* index)
GSVertexSW scan = v[0];
if (m_ds->IsSolidRect())
if ((m_scanmsk_value & 2) == 0 && m_ds->IsSolidRect())
{
if (m_threads == 1)
{
@@ -1158,6 +1160,7 @@ void GSRasterizer::Flush(const GSVertexSW* vertex, const u32* index, const GSVer
void GSRasterizer::DrawScanline(int pixels, int left, int top, const GSVertexSW& scan)
{
if ((m_scanmsk_value & 2) && (m_scanmsk_value & 1) == (top & 1)) return;
m_pixels.actual += pixels;
m_pixels.total += ((left + pixels + (PIXELS_PER_LOOP - 1)) & ~(PIXELS_PER_LOOP - 1)) - (left & ~(PIXELS_PER_LOOP - 1));
//m_pixels.total += ((left + pixels + (PIXELS_PER_LOOP - 1)) & ~(PIXELS_PER_LOOP - 1)) - left;
@@ -1169,6 +1172,7 @@ void GSRasterizer::DrawScanline(int pixels, int left, int top, const GSVertexSW&
void GSRasterizer::DrawEdge(int pixels, int left, int top, const GSVertexSW& scan)
{
if ((m_scanmsk_value & 2) && (m_scanmsk_value & 1) == (top & 1)) return;
m_pixels.actual += 1;
m_pixels.total += PIXELS_PER_LOOP - 1;
+3
View File
@@ -39,6 +39,7 @@ public:
u64 start;
int pixels;
int counter;
u8 scanmsk_value;
GSRasterizerData()
: scissor(GSVector4i::zero())
@@ -52,6 +53,7 @@ public:
, frame(0)
, start(0)
, pixels(0)
, scanmsk_value(0)
{
counter = s_counter++;
}
@@ -132,6 +134,7 @@ protected:
int m_threads;
int m_thread_height;
u8* m_scanline;
u8 m_scanmsk_value;
GSVector4i m_scissor;
GSVector4 m_fscissor_x;
GSVector4 m_fscissor_y;
+1
View File
@@ -344,6 +344,7 @@ void GSRendererSW::Draw()
sd->vertex_count = m_vertex.next;
sd->index = (u32*)(sd->buff + sizeof(GSVertexSW) * ((m_vertex.next + 1) & ~1));
sd->index_count = m_index.tail;
sd->scanmsk_value = m_env.SCANMSK.MSK;
// skip per pixel division if q is constant.
// Optimize the division by 1 with a nop. It also means that GS_SPRITE_CLASS must be processed when !m_vt.m_eq.q.
+5 -5
View File
@@ -27,10 +27,10 @@ class GSTextureSW final : public GSTexture
public:
GSTextureSW(Type type, int width, int height);
virtual ~GSTextureSW();
~GSTextureSW() override;
bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0);
bool Map(GSMap& m, const GSVector4i* r = NULL, int layer = 0);
void Unmap();
bool Save(const std::string& fn);
bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) override;
bool Map(GSMap& m, const GSVector4i* r = NULL, int layer = 0) override;
void Unmap() override;
bool Save(const std::string& fn) override;
};
+1 -1
View File
@@ -558,7 +558,7 @@ DebugTab::DebugTab(wxWindow* parent)
{
PaddedBoxSizer<wxStaticBoxSizer> debug_box(wxVERTICAL, this, "Debug");
auto* debug_check_box = new wxWrapSizer(wxHORIZONTAL);
m_ui.addCheckBox(debug_check_box, "GLSL compilation", "debug_glsl_shader");
m_ui.addCheckBox(debug_check_box, "Disable Shader Cache", "disable_shader_cache");
m_ui.addCheckBox(debug_check_box, "Print GL error", "debug_opengl");
#ifdef _WIN32
m_ui.addCheckBox(debug_check_box, "D3D Debug Layer", "debug_d3d");

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