mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-08-22 13:53:10 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
746c5b603f | ||
|
|
d0de8d22fe | ||
|
|
231b8e9481 | ||
|
|
f9f36700bb | ||
|
|
ba9fced3db | ||
|
|
c192ecf6b7 | ||
|
|
6ee029e14b | ||
|
|
935f880fa7 | ||
|
|
47d046c5fe | ||
|
|
4305e17cbe | ||
|
|
c5c4cdd0b4 | ||
|
|
252562db90 | ||
|
|
a898682f3e | ||
|
|
7829094668 | ||
|
|
042c23a545 | ||
|
|
af2b9e3a4c | ||
|
|
b3b7c55b9a | ||
|
|
1859ede325 | ||
|
|
2c32c374fb | ||
|
|
65d22406a3 | ||
|
|
92689a60ae | ||
|
|
1a598ccf0d | ||
|
|
e50feb74fd | ||
|
|
af067a8c84 | ||
|
|
61a196bc3d | ||
|
|
6a431daffc | ||
|
|
1aad3e6cc8 | ||
|
|
c8d42e32ed | ||
|
|
514cc6edb8 | ||
|
|
208d3ffa7b | ||
|
|
25dd92f8c0 | ||
|
|
3f81b7e56d | ||
|
|
99b7333991 | ||
|
|
a2ae4ba441 | ||
|
|
4e1b2792c9 | ||
|
|
55695bb5bc | ||
|
|
6e064da536 | ||
|
|
69ff12645c | ||
|
|
efb93d22d9 | ||
|
|
cdb0068dcc | ||
|
|
b0a0d714c4 | ||
|
|
7e36ee243c | ||
|
|
21bc56a8ba | ||
|
|
e920c0fe3e | ||
|
|
31992fb398 | ||
|
|
dc65599fae | ||
|
|
eb9dc7b70d | ||
|
|
06bf2502a6 | ||
|
|
242655bac9 | ||
|
|
8335b3ee77 | ||
|
|
a0c8ad9511 | ||
|
|
d775a9364b | ||
|
|
1695124472 | ||
|
|
70145eb150 | ||
|
|
dacd7d94d9 | ||
|
|
85bd8555c0 | ||
|
|
6920b4e366 | ||
|
|
bda3835cb1 | ||
|
|
83e5aa6137 | ||
|
|
4719e52c6e | ||
|
|
e313eadcd2 | ||
|
|
be952e40ba | ||
|
|
4d4b24f8b0 | ||
|
|
9533fa25c3 | ||
|
|
013c9072b9 | ||
|
|
bf8dc05fac | ||
|
|
f4b38662fa | ||
|
|
ea41cce5ef | ||
|
|
013c292ffb | ||
|
|
cb18f11133 | ||
|
|
ea25f49c65 | ||
|
|
5d15d5958e | ||
|
|
efed92b15c | ||
|
|
7d39d02e98 | ||
|
|
e006442e4f | ||
|
|
212848e931 | ||
|
|
732de53d1b | ||
|
|
08c00eed1e |
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
+1
Submodule 3rdparty/rapidyaml/rapidyaml added at 8c70f1e98c
Vendored
+143
@@ -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>
|
||||
Vendored
+9
@@ -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")
|
||||
Vendored
+20
@@ -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
@@ -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
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
+3447
File diff suppressed because it is too large
Load Diff
Vendored
+47
@@ -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
@@ -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>
|
||||
Vendored
+539
@@ -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.
|
||||
|
||||
--------------------------------------------------------------------- */
|
||||
Vendored
-1
Submodule 3rdparty/yaml-cpp/yaml-cpp deleted from 98acc5a887
Vendored
-75
@@ -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
@@ -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}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)), ...);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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];
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
#define ATTR_DEP
|
||||
#endif
|
||||
|
||||
#ifdef FSCALE
|
||||
# undef FSCALE // Defined in a macOS header
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// legacy jump/align functions
|
||||
//------------------------------------------------------------------
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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'"
|
||||
|
||||
@@ -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@
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -16,7 +16,7 @@
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
//#include <winsock2.h>
|
||||
#include "common/RedtapeWindows.h"
|
||||
#include <Winioctl.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "common/RedtapeWindows.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
|
||||
+1
-2
@@ -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>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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";
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -74,6 +74,7 @@ public:
|
||||
Jak2,
|
||||
Jak3,
|
||||
JakX,
|
||||
JurassicPark,
|
||||
KazokuKeikakuKokoroNoKizuna,
|
||||
KnightsOfTheTemple2,
|
||||
Kunoichi,
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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; }
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -83,5 +83,5 @@ public:
|
||||
|
||||
void CommitPages(const GSVector2i& region, bool commit) final;
|
||||
|
||||
u32 GetMemUsage();
|
||||
u32 GetMemUsage() final;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user